@opengeni/db 0.3.0 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/environment-crypto.ts","../src/event-payload-sanitizer.ts","../src/codex-token-resolver.ts"],"sourcesContent":["import type {\n AccessContext,\n AccessGrant,\n ApiKey,\n BillingBalance,\n CapabilityCatalogItem,\n CapabilityInstallation,\n CapabilityInstallationStatus,\n CapabilityKind,\n CapabilityPack,\n CapabilitySource,\n FileAsset,\n FileStatus,\n FileUploadStatus,\n ManagedAccount,\n Permission,\n PackInstallation,\n PackInstallationStatus,\n ResourceRef,\n SandboxBackend,\n SandboxOs,\n ScheduledTask,\n ScheduledTaskAgentConfig,\n ScheduledTaskOverlapPolicy,\n ScheduledTaskRun,\n ScheduledTaskRunMode,\n ScheduledTaskRunStatus,\n ScheduledTaskScheduleSpec,\n ScheduledTaskStatus,\n ScheduledTaskTriggerType,\n Session,\n SessionEvent,\n SessionEventType,\n SessionGoal,\n SessionGoalCreatedBy,\n SessionGoalStatus,\n SessionMcpServerMetadata,\n SessionStatus,\n SessionTurn,\n SessionTurnSource,\n SessionTurnStatus,\n SocialConnection,\n SocialConnectionStatus,\n SocialPost,\n SocialProvider,\n ToolRef,\n ReasoningEffort,\n UsageEvent,\n Workspace,\n WorkspaceEnvironment,\n WorkspaceEnvironmentVariableMetadata,\n WorkspaceMember,\n WorkspaceRegisteredPack,\n} from \"@opengeni/contracts\";\nimport { reasoningEffortForMetadata, CLEARED_RUN_STATE_BLOB } from \"@opengeni/contracts\";\nimport { environmentsEncryptionKeyBytes, type Settings } from \"@opengeni/config\";\nimport { isCodexBilledModel } from \"@opengeni/codex\";\n// Re-exported so consumers get the whole codex-billed detection surface (the pure\n// prefix test + the credential-aware predicates below) from a single import.\nexport { isCodexBilledModel } from \"@opengeni/codex\";\nimport { and, asc, desc, eq, gt, gte, inArray, lt, ne, sql, type SQL } from \"drizzle-orm\";\nimport type { PgDatabase } from \"drizzle-orm/pg-core\";\nimport { drizzle } from \"drizzle-orm/postgres-js\";\nimport postgres from \"postgres\";\nimport { decryptEnvironmentValue } from \"./environment-crypto\";\nimport { sanitizeEventPayload } from \"./event-payload-sanitizer\";\nimport * as schema from \"./schema\";\n\nexport { sql as dbSql } from \"drizzle-orm\";\nexport { decryptEnvironmentValue, encryptEnvironmentValue } from \"./environment-crypto\";\nexport { sanitizeEventPayload, sanitizeEventString } from \"./event-payload-sanitizer\";\n// Re-exported so external consumers can `import { migrate } from \"@opengeni/db\"`.\n// The `@opengeni/db/migrate` subpath stays available too (internal callers + the\n// db:migrate script use it). Re-exporting does NOT run migrate.ts's\n// `import.meta.main` block — that only fires when migrate.ts is the entry.\nexport { migrate, runMigrations } from \"./migrate\";\n// Step I SDK entry points for the embedded topology: a host drives migration +\n// role provisioning over an explicit admin connection + target schema. Importing\n// these does NOT run the modules' `import.meta.main` CLI blocks.\nexport { provisionRoles, type ProvisionResult, type ProvisionRolesOptions } from \"./provision-roles\";\n\n// §7.7 driver widening (Step I). `Database` is the structural, cross-driver\n// query-layer port: every helper in this file accepts `db: Database` and uses\n// only the methods present on drizzle's base `PgDatabase` (select/insert/update/\n// delete/transaction/execute). Widening from the concrete\n// `PostgresJsDatabase<typeof schema>` to `PgDatabase<any, typeof schema>` is a\n// pure TYPE change — no runtime behavior changes — that lets an embedded host\n// inject ANY drizzle pg driver handle (node-postgres, neon-http, etc.) bound to\n// OpenGeni's schema, not just the postgres-js handle `createDb` builds. The\n// `any` for the query-result HKT is deliberate: it keeps `db.execute(sql\\`…\\`)`\n// callable across drivers whose raw-result shapes differ (postgres-js returns a\n// row array; node-postgres returns `{ rows }`). The three raw `db.execute(…)`\n// reads that index a row array (`getManagedUserByEmail` here is the only\n// host-facing one — see `userLookup`) stay postgres-js-shaped for standalone;\n// `userLookup` is the injection seam for hosts on a different driver.\n// `PostgresJsDatabase<typeof schema>` is assignable to this, so standalone is\n// unaffected.\nexport type Database = PgDatabase<any, typeof schema>;\n\nexport type DbClient = {\n db: Database;\n close: () => Promise<void>;\n};\n\nexport type RlsContext = {\n accountId: string;\n workspaceId?: string | null;\n};\n\n/**\n * RLS posture for the connection OpenGeni's query layer runs over (Step I, §7.7).\n *\n * - `\"force\"` (DEFAULT — today's standalone behavior, byte-for-byte): OpenGeni\n * connects as a NON-OWNER role (`opengeni_app`) and every table carries\n * `FORCE ROW LEVEL SECURITY`, so the workspace/account GUCs set by\n * `setRlsContext` are the ONLY thing that admits rows — even the table owner\n * is subject to RLS. This is the Fork-A isolation guarantee.\n * - `\"scoped\"` (embedded Fork-B opt-in): the host runs OpenGeni's queries over a\n * role that OWNS the dedicated schema (RLS need not be forced for that role),\n * relying on the host's own tenant boundary. OpenGeni STILL emits the\n * `set_config('opengeni.account_id'/'workspace_id', …)` GUCs defensively on\n * every scoped query, so the application query path is byte-identical between\n * the two strategies and the app code is RLS-mode-agnostic. The strategy is a\n * declared posture (consumed by `provisionRoles` and as a documented\n * invariant), NOT a query-path branch — there is deliberately no `if\n * (strategy === …)` anywhere in the helpers below. Picking `\"scoped\"` does not\n * relax any GUC; it only changes which DB role the host provisions/connects as\n * and asserts that the host accepts owning the isolation boundary.\n */\nexport type RlsStrategy = \"force\" | \"scoped\";\n\n/**\n * Resolve a host-IdP/Better-Auth user *identifier* by email. Injected via\n * `createDb({ userLookup })` (Step I). UNSET → today's raw parameterized select\n * against Better Auth's `auth_users` table (see `getManagedUserByEmail`), which\n * relies on the postgres-js array-shaped `db.execute` result. An embedded host\n * whose identity lives elsewhere (a different IdP table, a different driver, or\n * a non-`auth_users` user store) injects this closure so OpenGeni never touches\n * `auth_users` directly. Returns the user id, or null when no such user exists.\n */\nexport type UserLookup = (db: Database, email: string) => Promise<string | null>;\n\nexport type CreateDbOptions = {\n /**\n * The Postgres `search_path` for this connection (Step I, §7.8 runtime half).\n * UNSET → today's behavior: NO `search_path` startup parameter is sent, so the\n * server default applies (`public` for standalone, where every table + the\n * `vector` extension + `gen_random_uuid()` live). For an embedded dedicated\n * schema, pass e.g. `\"opengeni,opengeni_private,public\"` — postgres-js sends\n * it as a per-session startup parameter (the supported, query-param-free way;\n * URL `?search_path=` is IGNORED by postgres-js). Keep `public` LAST so the\n * `vector` type and `gen_random_uuid()` (which live in `public` on the\n * pgvector image) still resolve — the SPIKE-1 live footgun.\n */\n searchPath?: string;\n /** RLS posture; defaults to `\"force\"` (today's standalone). */\n rlsStrategy?: RlsStrategy;\n /** Host-provided user-by-email resolver; unset → today's raw `auth_users` query. */\n userLookup?: UserLookup;\n /** postgres-js pool size; defaults to today's `10`. */\n max?: number;\n};\n\n/**\n * The active RLS strategy + userLookup for an injected `Database`, recorded in a\n * side WeakMap so helpers (and `getManagedUserByEmail`) can consult the host's\n * binding without changing every call signature. A handle with no recorded\n * config (e.g. one built outside `createDb`, or in a test) falls back to the\n * standalone defaults: `rlsStrategy: \"force\"`, raw `auth_users` lookup.\n */\ntype DbBinding = { rlsStrategy: RlsStrategy; userLookup?: UserLookup };\nconst dbBindings = new WeakMap<object, DbBinding>();\n\n/** The strategy bound to a handle (or the `\"force\"` default). */\nexport function rlsStrategyFor(db: Database): RlsStrategy {\n return dbBindings.get(db as unknown as object)?.rlsStrategy ?? \"force\";\n}\n\n/**\n * Run a raw SQL query and read its rows as a typed array.\n *\n * Why this exists: the Step I driver widening (`Database = PgDatabase<any, …>`)\n * deliberately sets the query-result HKT to `any` so `db.execute(…)` is callable\n * across drivers whose raw-result shapes differ (postgres-js → row array;\n * node-postgres → `{ rows }`). A side effect is that `db.execute<T>(…)` now\n * resolves to `any`, erasing the per-row element type at the call site. OpenGeni's\n * OWN internal raw queries (sandbox-lease reaping, warm-meter reads, group\n * session-id lists) ALWAYS run over the postgres-js handle `createDb` builds,\n * whose `.execute` returns an array of rows — so this helper re-applies that\n * array-of-`T` typing in ONE documented place instead of scattering casts. It is\n * NOT a cross-driver abstraction: a host on a non-array driver must override the\n * specific helper (today only `userLookup`), not call internal raw queries.\n */\nasync function rawRows<T extends Record<string, unknown>>(\n executor: Pick<Database, \"execute\">,\n query: SQL,\n): Promise<T[]> {\n const result = await executor.execute<T>(query);\n return result as unknown as T[];\n}\n\nexport function createDb(databaseUrl: string, options: CreateDbOptions = {}): DbClient {\n // `prepare: false` is REQUIRED for Azure Database for PostgreSQL Flexible\n // Server's transaction-pooling PgBouncer: postgres-js's default named prepared\n // statements (`s_N`) are bound to one backend, but a transaction pooler hands\n // each transaction a different backend, so a later `execute` intermittently\n // throws `prepared statement \"s_N\" does not exist`. Every RLS read in this\n // module (set_config + SELECT inside one db.transaction) rides on this pool, so\n // the failure surfaces as a \"worked, then didn't\" credential/permission read.\n // idle_timeout + max_lifetime recycle connections so a pooler-recycled backend\n // is never reused indefinitely; application_name aids server-side diagnostics.\n const client = postgres(databaseUrl, {\n max: options.max ?? 10,\n prepare: false,\n idle_timeout: 30,\n max_lifetime: 1800,\n // `connection` carries per-session Postgres STARTUP parameters. `application_name`\n // (always) aids server-side diagnostics; `search_path` (embedded only) is the\n // supported, query-param-free way to scope a connection to a dedicated schema —\n // postgres-js IGNORES a URL `?search_path=`. Unset searchPath → omit it so the\n // server default (`public`) is unchanged for standalone.\n connection: {\n application_name: \"opengeni\",\n ...(options.searchPath ? { search_path: options.searchPath } : {}),\n },\n });\n const db = drizzle(client, { schema });\n dbBindings.set(db as unknown as object, {\n rlsStrategy: options.rlsStrategy ?? \"force\",\n ...(options.userLookup ? { userLookup: options.userLookup } : {}),\n });\n return {\n db,\n close: async () => {\n await client.end();\n },\n };\n}\n\n/**\n * Register a host's `rlsStrategy`/`userLookup` against an externally-constructed\n * `Database` handle (e.g. one the embedded host built from its own driver and\n * injected, rather than via `createDb`). Lets the same WeakMap-backed lookups\n * work for injected handles. Standalone never calls this (it uses `createDb`).\n */\nexport function registerDbBinding(db: Database, binding: { rlsStrategy?: RlsStrategy; userLookup?: UserLookup }): void {\n dbBindings.set(db as unknown as object, {\n rlsStrategy: binding.rlsStrategy ?? \"force\",\n ...(binding.userLookup ? { userLookup: binding.userLookup } : {}),\n });\n}\n\nexport async function setRlsContext(db: Database, context: RlsContext): Promise<void> {\n // Fail loud on an empty/blank account id: a \"\" account would set an RLS GUC\n // that matches no tenant row, silently returning zero rows from every scoped\n // read (a phantom \"not found\" / \"no active subscription\"). An RLS context with\n // no account is always a bug at the call site, never a valid query scope.\n if (typeof context.accountId !== \"string\" || context.accountId.trim() === \"\") {\n throw new Error(\"setRlsContext: a non-empty accountId is required to establish an RLS context\");\n }\n await db.execute(sql`select set_config('opengeni.account_id', ${context.accountId}, true)`);\n await db.execute(sql`select set_config('opengeni.workspace_id', ${context.workspaceId ?? \"\"}, true)`);\n}\n\nexport async function withRlsContext<T>(\n db: Database,\n context: RlsContext,\n fn: (db: Database) => Promise<T>,\n): Promise<T> {\n return await db.transaction(async (tx) => {\n const scoped = tx as unknown as Database;\n await setRlsContext(scoped, context);\n // Defense-in-depth: read the LOCAL GUC back on THIS backend BEFORE running\n // the scoped query. The set_config and this read share one db.transaction,\n // which a transaction pooler pins to a single backend — so a mismatch here\n // means the context was genuinely lost (a torn transaction / pooler backend\n // swap), not normal operation. Without this guard such an event runs the\n // scoped read with an empty account_id and returns zero RLS-visible rows,\n // manufacturing a phantom \"no active subscription\" from a credential that is\n // in fact active. Convert that silent false into a loud, root-cause-bearing\n // error so the caller can retry rather than permanently mis-decide.\n const applied = await tx.execute<{ account_id: string | null }>(\n sql`select current_setting('opengeni.account_id', true) as account_id`,\n );\n const appliedAccountId = applied[0]?.account_id ?? \"\";\n if (appliedAccountId !== context.accountId) {\n throw new Error(\n `RLS context not applied on the active backend: expected account ${context.accountId}, got \"${appliedAccountId}\"`,\n );\n }\n return await fn(scoped);\n });\n}\n\nexport async function rlsContextForWorkspace(db: Database, workspaceId: string): Promise<RlsContext> {\n const [row] = await db.select({ accountId: schema.workspaces.accountId })\n .from(schema.workspaces)\n .where(eq(schema.workspaces.id, workspaceId))\n .limit(1);\n if (!row) {\n throw new Error(`Workspace not found: ${workspaceId}`);\n }\n return { accountId: row.accountId, workspaceId };\n}\n\nexport async function withWorkspaceRls<T>(\n db: Database,\n workspaceId: string,\n fn: (db: Database) => Promise<T>,\n): Promise<T> {\n return await withRlsContext(db, await rlsContextForWorkspace(db, workspaceId), fn);\n}\n\nexport async function withWorkspaceUsageLock<T>(\n db: Database,\n workspaceId: string,\n fn: (db: Database) => Promise<T>,\n): Promise<T> {\n const context = await rlsContextForWorkspace(db, workspaceId);\n return await withRlsContext(db, context, async (scopedDb) => {\n await scopedDb.execute(sql`select pg_advisory_xact_lock(hashtext(${`usage:${workspaceId}`}))`);\n return await fn(scopedDb);\n });\n}\n\nexport async function withAccountRls<T>(\n db: Database,\n accountId: string,\n fn: (db: Database) => Promise<T>,\n): Promise<T> {\n return await withRlsContext(db, { accountId, workspaceId: null }, fn);\n}\n\nexport const allWorkspacePermissions: Permission[] = [\n \"workspace:read\",\n \"workspace:admin\",\n \"members:manage\",\n \"sessions:create\",\n \"sessions:read\",\n \"sessions:control\",\n \"files:upload\",\n \"files:read\",\n \"documents:manage\",\n \"documents:search\",\n \"scheduled_tasks:manage\",\n \"scheduled_tasks:run\",\n \"github:manage\",\n \"github:use\",\n \"api_keys:manage\",\n \"environments:manage\",\n \"environments:use\",\n \"mcp_servers:attach\",\n \"goals:manage\",\n \"enrollments:read\",\n \"enrollments:manage\",\n];\n\nexport const allAccountPermissions: Permission[] = [\n \"account:read\",\n \"account:admin\",\n \"members:manage\",\n \"workspace:create\",\n \"billing:read\",\n \"billing:manage\",\n \"api_keys:manage\",\n];\n\nexport type BootstrapWorkspaceInput = {\n accountExternalSource: string;\n accountExternalId: string;\n accountName: string;\n workspaceExternalSource: string;\n workspaceExternalId: string;\n workspaceName: string;\n subjectId: string;\n subjectLabel?: string;\n accountPermissions?: Permission[];\n workspacePermissions?: Permission[];\n};\n\nexport async function bootstrapWorkspace(db: Database, input: BootstrapWorkspaceInput): Promise<AccessContext> {\n return await db.transaction(async (tx) => {\n const [account] = await tx.insert(schema.managedAccounts).values({\n name: input.accountName,\n externalSource: input.accountExternalSource,\n externalId: input.accountExternalId,\n }).onConflictDoUpdate({\n target: [schema.managedAccounts.externalSource, schema.managedAccounts.externalId],\n set: {\n name: input.accountName,\n updatedAt: new Date(),\n },\n }).returning();\n if (!account) {\n throw new Error(\"Failed to bootstrap account\");\n }\n const [workspace] = await tx.insert(schema.workspaces).values({\n accountId: account.id,\n name: input.workspaceName,\n externalSource: input.workspaceExternalSource,\n externalId: input.workspaceExternalId,\n }).onConflictDoUpdate({\n target: [schema.workspaces.externalSource, schema.workspaces.externalId],\n set: {\n name: input.workspaceName,\n updatedAt: new Date(),\n },\n }).returning();\n if (!workspace) {\n throw new Error(\"Failed to bootstrap workspace\");\n }\n const workspacePermissions = input.workspacePermissions ?? allWorkspacePermissions;\n await tx.insert(schema.workspaceMemberships).values({\n accountId: account.id,\n workspaceId: workspace.id,\n subjectId: input.subjectId,\n subjectLabel: input.subjectLabel ?? null,\n role: \"owner\",\n permissions: workspacePermissions,\n }).onConflictDoUpdate({\n target: [schema.workspaceMemberships.subjectId, schema.workspaceMemberships.workspaceId],\n set: {\n subjectLabel: input.subjectLabel ?? null,\n role: \"owner\",\n permissions: workspacePermissions,\n updatedAt: new Date(),\n },\n });\n return {\n mode: input.accountExternalSource === \"opengeni:local\" ? \"local\" : \"configured\",\n subjectId: input.subjectId,\n ...(input.subjectLabel ? { subjectLabel: input.subjectLabel } : {}),\n accountGrants: [{\n accountId: account.id,\n subjectId: input.subjectId,\n ...(input.subjectLabel ? { subjectLabel: input.subjectLabel } : {}),\n role: \"owner\",\n permissions: input.accountPermissions ?? allAccountPermissions,\n }],\n workspaceGrants: [{\n workspaceId: workspace.id,\n accountId: account.id,\n subjectId: input.subjectId,\n ...(input.subjectLabel ? { subjectLabel: input.subjectLabel } : {}),\n permissions: workspacePermissions,\n }],\n defaultAccountId: account.id,\n defaultWorkspaceId: workspace.id,\n };\n });\n}\n\nexport async function ensureManagedAccessForUser(db: Database, input: {\n userId: string;\n email: string;\n name: string;\n}): Promise<AccessContext> {\n const subjectId = `user:${input.userId}`;\n const subjectLabel = input.email || input.name;\n return await db.transaction(async (tx) => {\n const [account] = await tx.insert(schema.managedAccounts).values({\n name: input.name || input.email,\n externalSource: \"better-auth:user\",\n externalId: input.userId,\n }).onConflictDoUpdate({\n target: [schema.managedAccounts.externalSource, schema.managedAccounts.externalId],\n set: {\n name: input.name || input.email,\n updatedAt: new Date(),\n },\n }).returning();\n if (!account) {\n throw new Error(\"Failed to ensure managed account\");\n }\n const [defaultWorkspace] = await tx.insert(schema.workspaces).values({\n accountId: account.id,\n name: \"Default workspace\",\n slug: \"default\",\n externalSource: \"better-auth:user\",\n externalId: `${input.userId}:default`,\n }).onConflictDoUpdate({\n target: [schema.workspaces.externalSource, schema.workspaces.externalId],\n set: {\n name: \"Default workspace\",\n updatedAt: new Date(),\n },\n }).returning();\n if (!defaultWorkspace) {\n throw new Error(\"Failed to ensure default workspace\");\n }\n await tx.insert(schema.workspaceMemberships).values({\n accountId: account.id,\n workspaceId: defaultWorkspace.id,\n subjectId,\n subjectLabel,\n role: \"owner\",\n permissions: allWorkspacePermissions,\n }).onConflictDoUpdate({\n target: [schema.workspaceMemberships.subjectId, schema.workspaceMemberships.workspaceId],\n set: {\n subjectLabel,\n role: \"owner\",\n permissions: allWorkspacePermissions,\n updatedAt: new Date(),\n },\n });\n const memberships = await tx.select({\n membership: schema.workspaceMemberships,\n workspace: schema.workspaces,\n }).from(schema.workspaceMemberships)\n .innerJoin(schema.workspaces, eq(schema.workspaceMemberships.workspaceId, schema.workspaces.id))\n .where(eq(schema.workspaceMemberships.subjectId, subjectId))\n .orderBy(desc(schema.workspaces.createdAt));\n return {\n mode: \"managed\",\n subjectId,\n subjectLabel,\n accountGrants: [{\n accountId: account.id,\n subjectId,\n subjectLabel,\n role: \"owner\",\n permissions: allAccountPermissions,\n }],\n workspaceGrants: memberships.map((row) => ({\n workspaceId: row.workspace.id,\n accountId: row.workspace.accountId,\n subjectId,\n subjectLabel,\n permissions: row.membership.permissions as Permission[],\n })),\n defaultAccountId: account.id,\n defaultWorkspaceId: defaultWorkspace.id,\n };\n });\n}\n\nexport async function getWorkspace(db: Database, workspaceId: string): Promise<Workspace | null> {\n const [row] = await db.select().from(schema.workspaces).where(eq(schema.workspaces.id, workspaceId)).limit(1);\n return row ? mapWorkspace(row) : null;\n}\n\nexport async function getManagedAccount(db: Database, accountId: string): Promise<ManagedAccount | null> {\n const [row] = await db.select().from(schema.managedAccounts).where(eq(schema.managedAccounts.id, accountId)).limit(1);\n return row ? mapAccount(row) : null;\n}\n\nexport async function requireWorkspace(db: Database, workspaceId: string): Promise<Workspace> {\n const workspace = await getWorkspace(db, workspaceId);\n if (!workspace) {\n throw new Error(`Workspace not found: ${workspaceId}`);\n }\n return workspace;\n}\n\nexport async function listWorkspacesForSubject(db: Database, subjectId: string, limit = 100): Promise<Workspace[]> {\n const rows = await db.select({ workspace: schema.workspaces }).from(schema.workspaceMemberships)\n .innerJoin(schema.workspaces, eq(schema.workspaceMemberships.workspaceId, schema.workspaces.id))\n .where(eq(schema.workspaceMemberships.subjectId, subjectId))\n .orderBy(desc(schema.workspaces.createdAt))\n .limit(limit);\n return rows.map((row) => mapWorkspace(row.workspace));\n}\n\nexport async function countWorkspacesForAccount(db: Database, accountId: string): Promise<number> {\n const [{ count } = { count: 0 }] = await db.select({\n count: sql<number>`count(*)::int`,\n }).from(schema.workspaces).where(eq(schema.workspaces.accountId, accountId));\n return Number(count);\n}\n\nexport async function createWorkspace(db: Database, input: {\n accountId: string;\n name: string;\n slug?: string | null;\n externalSource?: string | null;\n externalId?: string | null;\n agentInstructions?: string | null;\n}): Promise<Workspace> {\n const [row] = await db.insert(schema.workspaces).values({\n accountId: input.accountId,\n name: input.name,\n slug: input.slug ?? null,\n externalSource: input.externalSource ?? null,\n externalId: input.externalId ?? null,\n agentInstructions: input.agentInstructions ?? null,\n }).returning();\n if (!row) {\n throw new Error(\"Failed to create workspace\");\n }\n return mapWorkspace(row);\n}\n\nexport async function grantWorkspaceAccess(db: Database, input: {\n accountId: string;\n workspaceId: string;\n subjectId: string;\n subjectLabel?: string;\n role?: string;\n permissions: Permission[];\n}): Promise<void> {\n await db.insert(schema.workspaceMemberships).values({\n accountId: input.accountId,\n workspaceId: input.workspaceId,\n subjectId: input.subjectId,\n subjectLabel: input.subjectLabel ?? null,\n role: input.role ?? \"member\",\n permissions: input.permissions,\n }).onConflictDoUpdate({\n target: [schema.workspaceMemberships.subjectId, schema.workspaceMemberships.workspaceId],\n set: {\n subjectLabel: input.subjectLabel ?? null,\n role: input.role ?? \"member\",\n permissions: input.permissions,\n updatedAt: new Date(),\n },\n });\n}\n\nexport async function updateWorkspace(db: Database, workspaceId: string, input: {\n name?: string;\n slug?: string | null;\n agentInstructions?: string | null;\n}): Promise<Workspace> {\n const [row] = await db.update(schema.workspaces).set({\n ...(input.name !== undefined ? { name: input.name } : {}),\n ...(input.slug !== undefined ? { slug: input.slug } : {}),\n ...(input.agentInstructions !== undefined ? { agentInstructions: input.agentInstructions } : {}),\n updatedAt: new Date(),\n }).where(eq(schema.workspaces.id, workspaceId)).returning();\n if (!row) {\n throw new Error(`Workspace not found: ${workspaceId}`);\n }\n return mapWorkspace(row);\n}\n\nexport async function getWorkspaceGrant(db: Database, subjectId: string, workspaceId: string): Promise<AccessGrant | null> {\n const [row] = await db.select({\n membership: schema.workspaceMemberships,\n workspace: schema.workspaces,\n }).from(schema.workspaceMemberships)\n .innerJoin(schema.workspaces, eq(schema.workspaceMemberships.workspaceId, schema.workspaces.id))\n .where(and(eq(schema.workspaceMemberships.subjectId, subjectId), eq(schema.workspaceMemberships.workspaceId, workspaceId)))\n .limit(1);\n return row ? {\n workspaceId: row.workspace.id,\n accountId: row.workspace.accountId,\n subjectId: row.membership.subjectId,\n ...(row.membership.subjectLabel ? { subjectLabel: row.membership.subjectLabel } : {}),\n permissions: row.membership.permissions as Permission[],\n } : null;\n}\n\nexport async function listWorkspaceMembers(db: Database, workspaceId: string): Promise<WorkspaceMember[]> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const rows = await scopedDb.select().from(schema.workspaceMemberships)\n .where(eq(schema.workspaceMemberships.workspaceId, workspaceId))\n .orderBy(asc(schema.workspaceMemberships.createdAt));\n return rows.map(mapWorkspaceMember);\n });\n}\n\nexport async function removeWorkspaceMember(db: Database, workspaceId: string, subjectId: string): Promise<boolean> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const rows = await scopedDb.delete(schema.workspaceMemberships)\n .where(and(eq(schema.workspaceMemberships.workspaceId, workspaceId), eq(schema.workspaceMemberships.subjectId, subjectId)))\n .returning({ id: schema.workspaceMemberships.id });\n return rows.length > 0;\n });\n}\n\n/**\n * Resolve a managed user email to its user id.\n *\n * STANDALONE (default, unchanged): the `auth_users` table is owned by Better\n * Auth and is NOT in the Drizzle schema, so this runs the raw parameterized\n * select below — matching emails case-insensitively, returning the id or null.\n *\n * EMBEDDED (Step I `userLookup` port): when the handle was built via\n * `createDb({ userLookup })` (or registered with `registerDbBinding`), this\n * delegates to the host's resolver instead — so a host whose identity lives in\n * a different IdP/table/driver never forces OpenGeni to touch `auth_users`. The\n * raw query also assumes the postgres-js array-shaped `db.execute` result; the\n * port is the cross-driver escape hatch for that too.\n *\n * Used to add an already-registered user to a workspace; email invites for\n * unknown users are deferred.\n */\nexport async function getManagedUserByEmail(db: Database, email: string): Promise<string | null> {\n const binding = dbBindings.get(db as unknown as object);\n if (binding?.userLookup) {\n return await binding.userLookup(db, email);\n }\n const rows = await db.execute(sql<{ id: string }>`\n select id from auth_users where lower(email) = lower(${email}) limit 1\n `);\n return ((rows as unknown as Array<{ id?: string }>)[0]?.id) ?? null;\n}\n\nexport async function deleteWorkspace(db: Database, workspaceId: string): Promise<void> {\n await db.delete(schema.workspaces).where(eq(schema.workspaces.id, workspaceId));\n}\n\nexport async function createApiKey(db: Database, input: {\n accountId: string;\n workspaceId?: string | null;\n name: string;\n prefix: string;\n keyHash: string;\n permissions: Permission[];\n expiresAt?: Date | null;\n}): Promise<ApiKey> {\n return await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId ?? null }, async (scopedDb) => {\n const [row] = await scopedDb.insert(schema.apiKeys).values({\n accountId: input.accountId,\n workspaceId: input.workspaceId ?? null,\n name: input.name,\n prefix: input.prefix,\n keyHash: input.keyHash,\n permissions: input.permissions,\n expiresAt: input.expiresAt ?? null,\n }).returning();\n if (!row) {\n throw new Error(\"Failed to create API key\");\n }\n return mapApiKey(row);\n });\n}\n\nexport async function listApiKeys(db: Database, workspaceId: string): Promise<ApiKey[]> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const rows = await scopedDb.select().from(schema.apiKeys)\n .where(eq(schema.apiKeys.workspaceId, workspaceId))\n .orderBy(desc(schema.apiKeys.createdAt));\n return rows.map(mapApiKey);\n });\n}\n\nexport async function countActiveApiKeysForWorkspace(db: Database, workspaceId: string): Promise<number> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const [{ count } = { count: 0 }] = await scopedDb.select({\n count: sql<number>`count(*)::int`,\n }).from(schema.apiKeys)\n .where(and(eq(schema.apiKeys.workspaceId, workspaceId), sql`${schema.apiKeys.revokedAt} is null`, sql`(${schema.apiKeys.expiresAt} is null or ${schema.apiKeys.expiresAt} > now())`));\n return Number(count);\n });\n}\n\nexport async function revokeApiKey(db: Database, workspaceId: string, apiKeyId: string): Promise<ApiKey> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const [row] = await scopedDb.update(schema.apiKeys).set({\n revokedAt: new Date(),\n updatedAt: new Date(),\n }).where(and(eq(schema.apiKeys.workspaceId, workspaceId), eq(schema.apiKeys.id, apiKeyId))).returning();\n if (!row) {\n throw new Error(`API key not found: ${apiKeyId}`);\n }\n return mapApiKey(row);\n });\n}\n\nexport async function findActiveApiKeyByHash(db: Database, keyHash: string): Promise<ApiKey | null> {\n return await db.transaction(async (tx) => {\n await tx.execute(sql`select set_config('opengeni.api_key_hash', ${keyHash}, true)`);\n const [row] = await tx.select().from(schema.apiKeys)\n .where(and(eq(schema.apiKeys.keyHash, keyHash), sql`${schema.apiKeys.revokedAt} is null`, sql`(${schema.apiKeys.expiresAt} is null or ${schema.apiKeys.expiresAt} > now())`))\n .limit(1);\n if (!row) {\n return null;\n }\n const now = new Date();\n await tx.update(schema.apiKeys).set({ lastUsedAt: now, updatedAt: now }).where(eq(schema.apiKeys.id, row.id));\n return mapApiKey({ ...row, lastUsedAt: now });\n });\n}\n\nexport type GitHubInstallation = {\n id: string;\n accountId: string;\n workspaceId: string;\n installationId: number;\n accountLogin: string | null;\n accountType: string | null;\n createdAt: string;\n updatedAt: string;\n};\n\nexport async function upsertGitHubInstallation(db: Database, input: {\n accountId: string;\n workspaceId: string;\n installationId: number;\n accountLogin?: string | null;\n accountType?: string | null;\n}): Promise<GitHubInstallation> {\n return await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId }, async (scopedDb) => {\n const [row] = await scopedDb.insert(schema.githubInstallations).values({\n accountId: input.accountId,\n workspaceId: input.workspaceId,\n installationId: input.installationId,\n accountLogin: input.accountLogin ?? null,\n accountType: input.accountType ?? null,\n }).onConflictDoUpdate({\n target: [schema.githubInstallations.workspaceId, schema.githubInstallations.installationId],\n set: {\n accountId: input.accountId,\n accountLogin: input.accountLogin ?? null,\n accountType: input.accountType ?? null,\n updatedAt: new Date(),\n },\n }).returning();\n if (!row) {\n throw new Error(\"Failed to upsert GitHub installation\");\n }\n return mapGitHubInstallation(row);\n });\n}\n\nexport async function listGitHubInstallationsForWorkspace(db: Database, workspaceId: string): Promise<GitHubInstallation[]> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const rows = await scopedDb.select().from(schema.githubInstallations)\n .where(eq(schema.githubInstallations.workspaceId, workspaceId))\n .orderBy(desc(schema.githubInstallations.updatedAt));\n return rows.map(mapGitHubInstallation);\n });\n}\n\nexport async function listGitHubInstallationIdsForWorkspace(db: Database, workspaceId: string): Promise<number[]> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const rows = await scopedDb.select({ installationId: schema.githubInstallations.installationId })\n .from(schema.githubInstallations)\n .where(eq(schema.githubInstallations.workspaceId, workspaceId))\n .orderBy(desc(schema.githubInstallations.updatedAt));\n return rows.map((row) => row.installationId);\n });\n}\n\nexport async function recordUsageEvent(db: Database, input: {\n accountId: string;\n workspaceId: string;\n subjectId?: string | null;\n eventType: string;\n quantity: number;\n unit: string;\n sourceResourceType?: string | null;\n sourceResourceId?: string | null;\n idempotencyKey: string;\n occurredAt?: Date;\n}): Promise<UsageEvent> {\n return await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId }, async (scopedDb) => {\n const [row] = await scopedDb.insert(schema.usageEvents).values({\n accountId: input.accountId,\n workspaceId: input.workspaceId,\n subjectId: input.subjectId ?? null,\n eventType: input.eventType,\n quantity: input.quantity,\n unit: input.unit,\n sourceResourceType: input.sourceResourceType ?? null,\n sourceResourceId: input.sourceResourceId ?? null,\n idempotencyKey: input.idempotencyKey,\n occurredAt: input.occurredAt ?? new Date(),\n }).onConflictDoNothing({ target: schema.usageEvents.idempotencyKey }).returning();\n if (row) {\n return mapUsageEvent(row);\n }\n const [existing] = await scopedDb.select().from(schema.usageEvents).where(eq(schema.usageEvents.idempotencyKey, input.idempotencyKey)).limit(1);\n if (!existing) {\n throw new Error(\"Failed to record usage event\");\n }\n return mapUsageEvent(existing);\n });\n}\n\nexport async function listUsageEvents(db: Database, input: {\n accountId: string;\n workspaceId?: string;\n limit?: number;\n}): Promise<UsageEvent[]> {\n return await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId ?? null }, async (scopedDb) => {\n const rows = await scopedDb.select().from(schema.usageEvents)\n .where(input.workspaceId\n ? and(eq(schema.usageEvents.accountId, input.accountId), eq(schema.usageEvents.workspaceId, input.workspaceId))\n : eq(schema.usageEvents.accountId, input.accountId))\n .orderBy(desc(schema.usageEvents.occurredAt), desc(schema.usageEvents.recordedAt))\n .limit(input.limit ?? 100);\n return rows.map(mapUsageEvent);\n });\n}\n\nexport async function sumUsageQuantity(db: Database, input: {\n accountId?: string;\n workspaceId?: string;\n eventType: string;\n since?: Date;\n}): Promise<number> {\n const context = input.workspaceId\n ? await rlsContextForWorkspace(db, input.workspaceId)\n : input.accountId\n ? { accountId: input.accountId, workspaceId: null }\n : null;\n if (!context) {\n throw new Error(\"Usage quantity queries require accountId or workspaceId\");\n }\n return await withRlsContext(db, context, async (scopedDb) => {\n const clauses = [\n eq(schema.usageEvents.eventType, input.eventType),\n ...(input.accountId ? [eq(schema.usageEvents.accountId, input.accountId)] : []),\n ...(input.workspaceId ? [eq(schema.usageEvents.workspaceId, input.workspaceId)] : []),\n ...(input.since ? [gt(schema.usageEvents.occurredAt, input.since)] : []),\n ];\n const [{ total } = { total: 0 }] = await scopedDb.select({\n total: sql<number>`coalesce(sum(${schema.usageEvents.quantity}), 0)`,\n }).from(schema.usageEvents).where(and(...clauses));\n return Number(total);\n });\n}\n\nexport async function applyCreditLedgerEntry(db: Database, input: {\n accountId: string;\n workspaceId?: string | null;\n type: string;\n amountMicros: number;\n sourceType?: string | null;\n sourceId?: string | null;\n idempotencyKey: string;\n metadata?: Record<string, unknown>;\n occurredAt?: Date;\n}): Promise<BillingBalance> {\n return await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId ?? null }, async (scopedDb) => {\n await scopedDb.insert(schema.creditLedgerEntries).values({\n accountId: input.accountId,\n workspaceId: input.workspaceId ?? null,\n type: input.type,\n amountMicros: input.amountMicros,\n sourceType: input.sourceType ?? null,\n sourceId: input.sourceId ?? null,\n idempotencyKey: input.idempotencyKey,\n metadata: input.metadata ?? {},\n occurredAt: input.occurredAt ?? new Date(),\n }).onConflictDoNothing({ target: schema.creditLedgerEntries.idempotencyKey });\n return await getBillingBalance(scopedDb, input.accountId);\n });\n}\n\nexport async function applyCreditDebitUpToBalance(db: Database, input: {\n accountId: string;\n workspaceId?: string | null;\n type: string;\n requestedAmountMicros: number;\n sourceType?: string | null;\n sourceId?: string | null;\n idempotencyKey: string;\n metadata?: Record<string, unknown>;\n occurredAt?: Date;\n}): Promise<{ balance: BillingBalance; debitedMicros: number }> {\n if (input.requestedAmountMicros <= 0) {\n return { balance: await getBillingBalance(db, input.accountId), debitedMicros: 0 };\n }\n return await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId ?? null }, async (scopedDb) => {\n await scopedDb.execute(sql`select pg_advisory_xact_lock(hashtext(${input.accountId}))`);\n const before = await getBillingBalance(scopedDb, input.accountId);\n const debitedMicros = Math.min(input.requestedAmountMicros, Math.max(0, before.balanceMicros));\n if (debitedMicros > 0) {\n await scopedDb.insert(schema.creditLedgerEntries).values({\n accountId: input.accountId,\n workspaceId: input.workspaceId ?? null,\n type: input.type,\n amountMicros: -debitedMicros,\n sourceType: input.sourceType ?? null,\n sourceId: input.sourceId ?? null,\n idempotencyKey: input.idempotencyKey,\n metadata: {\n ...input.metadata,\n requestedAmountMicros: input.requestedAmountMicros,\n debitedMicros,\n },\n occurredAt: input.occurredAt ?? new Date(),\n }).onConflictDoNothing({ target: schema.creditLedgerEntries.idempotencyKey });\n }\n return { balance: await getBillingBalance(scopedDb, input.accountId), debitedMicros };\n });\n}\n\nexport async function hasCreditLedgerEntry(db: Database, accountId: string, idempotencyKey: string): Promise<boolean> {\n return await withAccountRls(db, accountId, async (scopedDb) => {\n const [row] = await scopedDb.select({ id: schema.creditLedgerEntries.id })\n .from(schema.creditLedgerEntries)\n .where(and(eq(schema.creditLedgerEntries.accountId, accountId), eq(schema.creditLedgerEntries.idempotencyKey, idempotencyKey)))\n .limit(1);\n return Boolean(row);\n });\n}\n\nexport async function getBillingCustomer(db: Database, accountId: string, provider = \"stripe\"): Promise<{\n accountId: string;\n provider: string;\n providerCustomerId: string;\n email: string | null;\n} | null> {\n return await withAccountRls(db, accountId, async (scopedDb) => {\n const [row] = await scopedDb.select().from(schema.billingCustomers)\n .where(and(eq(schema.billingCustomers.accountId, accountId), eq(schema.billingCustomers.provider, provider)))\n .limit(1);\n return row ? {\n accountId: row.accountId,\n provider: row.provider,\n providerCustomerId: row.providerCustomerId,\n email: row.email,\n } : null;\n });\n}\n\nexport async function upsertBillingCustomer(db: Database, input: {\n accountId: string;\n provider?: string;\n providerCustomerId: string;\n email?: string | null;\n}): Promise<void> {\n await withAccountRls(db, input.accountId, async (scopedDb) => {\n await scopedDb.insert(schema.billingCustomers).values({\n accountId: input.accountId,\n provider: input.provider ?? \"stripe\",\n providerCustomerId: input.providerCustomerId,\n email: input.email ?? null,\n }).onConflictDoUpdate({\n target: [schema.billingCustomers.accountId, schema.billingCustomers.provider],\n set: {\n providerCustomerId: input.providerCustomerId,\n email: input.email ?? null,\n updatedAt: new Date(),\n },\n });\n });\n}\n\nexport async function recordStripeWebhookEvent(db: Database, input: {\n id: string;\n type: string;\n livemode: boolean;\n payload: unknown;\n}): Promise<boolean> {\n const [row] = await db.insert(schema.stripeWebhookEvents).values({\n id: input.id,\n type: input.type,\n livemode: String(input.livemode),\n payload: input.payload,\n }).onConflictDoNothing({ target: schema.stripeWebhookEvents.id }).returning({ id: schema.stripeWebhookEvents.id });\n return Boolean(row);\n}\n\nexport async function isStripeWebhookProcessed(db: Database, id: string): Promise<boolean> {\n const [row] = await db.select({ processedAt: schema.stripeWebhookEvents.processedAt })\n .from(schema.stripeWebhookEvents)\n .where(eq(schema.stripeWebhookEvents.id, id))\n .limit(1);\n return Boolean(row?.processedAt);\n}\n\nexport async function markStripeWebhookProcessed(db: Database, id: string): Promise<void> {\n await db.update(schema.stripeWebhookEvents).set({ processedAt: new Date() }).where(eq(schema.stripeWebhookEvents.id, id));\n}\n\nexport async function getBillingBalance(db: Database, accountId: string): Promise<BillingBalance> {\n return await withAccountRls(db, accountId, async (scopedDb) => {\n const [{ balance } = { balance: 0 }] = await scopedDb.select({\n balance: sql<number>`coalesce(sum(${schema.creditLedgerEntries.amountMicros}), 0)`,\n }).from(schema.creditLedgerEntries).where(eq(schema.creditLedgerEntries.accountId, accountId));\n return {\n accountId,\n balanceMicros: Number(balance),\n currency: \"usd\",\n updatedAt: new Date().toISOString(),\n };\n });\n}\n\nexport async function countScheduledTasksForWorkspace(db: Database, workspaceId: string): Promise<number> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const [{ count } = { count: 0 }] = await scopedDb.select({\n count: sql<number>`count(*)::int`,\n }).from(schema.scheduledTasks).where(eq(schema.scheduledTasks.workspaceId, workspaceId));\n return Number(count);\n });\n}\n\nexport type AppendEventInput = {\n type: SessionEventType;\n payload?: unknown;\n clientEventId?: string;\n turnId?: string | null;\n producerId?: string;\n producerSeq?: number;\n occurredAt?: Date;\n};\n\nexport type CreateScheduledTaskInput = {\n id?: string;\n accountId: string;\n workspaceId: string;\n name: string;\n status: ScheduledTaskStatus;\n schedule: ScheduledTaskScheduleSpec;\n temporalScheduleId: string;\n runMode: ScheduledTaskRunMode;\n overlapPolicy: ScheduledTaskOverlapPolicy;\n agentConfig: ScheduledTaskAgentConfig;\n environmentId?: string | null;\n metadata: Record<string, unknown>;\n};\n\nexport type UpdateScheduledTaskInput = Partial<{\n name: string;\n status: ScheduledTaskStatus;\n schedule: ScheduledTaskScheduleSpec;\n runMode: ScheduledTaskRunMode;\n overlapPolicy: ScheduledTaskOverlapPolicy;\n agentConfig: ScheduledTaskAgentConfig;\n reusableSessionId: string | null;\n environmentId: string | null;\n metadata: Record<string, unknown>;\n}>;\n\nexport type CreatePackInstallationInput = {\n accountId: string;\n workspaceId: string;\n packId: string;\n metadata?: Record<string, unknown>;\n};\n\nexport type RegisterWorkspacePackInput = {\n accountId: string;\n workspaceId: string;\n pack: CapabilityPack;\n};\n\nexport type CreateSocialConnectionInput = {\n accountId: string;\n workspaceId: string;\n provider: SocialProvider;\n accountHandle: string;\n accountName?: string | null;\n externalAccountId?: string | null;\n status: SocialConnectionStatus;\n scopes?: string[];\n credentialRef?: string | null;\n tokenMetadata?: Record<string, unknown>;\n metadata?: Record<string, unknown>;\n};\n\nexport type CreateSocialPostInput = {\n accountId: string;\n workspaceId: string;\n connectionId: string;\n externalPostId?: string | null;\n url?: string | null;\n authorHandle?: string | null;\n text: string;\n publishedAt: Date;\n metrics?: Record<string, number>;\n raw?: Record<string, unknown>;\n};\n\nexport type CreateCapabilityCatalogItemInput = {\n accountId: string;\n workspaceId: string;\n id: string;\n kind: Exclude<CapabilityKind, \"pack\">;\n source: CapabilitySource;\n name: string;\n description?: string | null;\n category?: string;\n tags?: string[];\n homepageUrl?: string | null;\n endpointUrl?: string | null;\n installUrl?: string | null;\n authModel?: string | null;\n metadata?: Record<string, unknown>;\n};\n\nexport type EnableCapabilityInstallationInput = {\n accountId: string;\n workspaceId: string;\n capabilityId: string;\n kind: CapabilityKind;\n config?: Record<string, unknown>;\n metadata?: Record<string, unknown>;\n};\n\nexport type EnabledMcpCapabilityServer = {\n capabilityId: string;\n id: string;\n name: string;\n url: string;\n allowedTools?: string[];\n timeoutMs?: number;\n cacheToolsList?: boolean;\n /**\n * Credential request headers stored encrypted at enable time\n * (AES-256-GCM under the workspace-environments key). Decrypted only at\n * the runtime boundary that builds the MCP client; never exposed by the\n * capability API surface.\n */\n headersEncrypted?: Record<string, string>;\n};\n\nexport type CreateSessionMcpServerInput = {\n id: string;\n name?: string | null;\n url: string;\n allowedTools?: string[] | null;\n timeoutMs?: number | null;\n cacheToolsList?: boolean | null;\n headersEncrypted?: Record<string, string>;\n};\n\nexport type UpdateSessionMcpServerCredentialsInput = {\n id: string;\n headersEncrypted: Record<string, string>;\n};\n\nexport type UpdateSessionMcpServerCredentialsResult = {\n servers: SessionMcpServerMetadata[];\n missingIds: string[];\n};\n\nexport type SessionMcpServerForRun = SessionMcpServerMetadata & {\n allowedTools?: string[];\n timeoutMs?: number;\n cacheToolsList?: boolean;\n headers: Record<string, string>;\n};\n\nexport type EnqueueSessionTurnInput = {\n accountId: string;\n workspaceId: string;\n sessionId: string;\n triggerEventId: string;\n temporalWorkflowId: string;\n source: SessionTurnSource;\n prompt: string;\n resources: ResourceRef[];\n tools: ToolRef[];\n model: string;\n reasoningEffort: ReasoningEffort;\n sandboxBackend: SandboxBackend;\n metadata: Record<string, unknown>;\n};\n\nexport type UpdateQueuedSessionTurnInput = Partial<{\n prompt: string;\n resources: ResourceRef[];\n tools: ToolRef[];\n model: string;\n reasoningEffort: ReasoningEffort;\n sandboxBackend: SandboxBackend;\n metadata: Record<string, unknown>;\n}>;\n\nexport async function createFileUpload(db: Database, input: {\n accountId: string;\n workspaceId: string;\n fileId: string;\n filename: string;\n safeFilename: string;\n contentType: string;\n sizeBytes: number;\n sha256?: string | null;\n bucket: string;\n objectKey: string;\n expiresAt: Date;\n}): Promise<{ file: FileAsset; uploadId: string; expiresAt: string }> {\n return await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId }, async (scopedDb) => await scopedDb.transaction(async (tx) => {\n const [fileRow] = await tx.insert(schema.files).values({\n id: input.fileId,\n accountId: input.accountId,\n workspaceId: input.workspaceId,\n filename: input.filename,\n safeFilename: input.safeFilename,\n contentType: input.contentType,\n sizeBytes: input.sizeBytes,\n sha256: input.sha256 ?? null,\n bucket: input.bucket,\n objectKey: input.objectKey,\n status: \"pending_upload\",\n }).returning();\n if (!fileRow) {\n throw new Error(\"Failed to create file\");\n }\n const [uploadRow] = await tx.insert(schema.fileUploads).values({\n accountId: input.accountId,\n workspaceId: input.workspaceId,\n fileId: fileRow.id,\n status: \"pending\",\n expiresAt: input.expiresAt,\n }).returning({ id: schema.fileUploads.id, expiresAt: schema.fileUploads.expiresAt });\n if (!uploadRow) {\n throw new Error(\"Failed to create file upload\");\n }\n return {\n file: mapFile(fileRow),\n uploadId: uploadRow.id,\n expiresAt: uploadRow.expiresAt.toISOString(),\n };\n }));\n}\n\nexport async function getFile(db: Database, workspaceId: string, fileId: string): Promise<FileAsset | null> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const [row] = await scopedDb.select().from(schema.files).where(and(eq(schema.files.workspaceId, workspaceId), eq(schema.files.id, fileId))).limit(1);\n return row ? mapFile(row) : null;\n });\n}\n\nexport async function requireFile(db: Database, workspaceId: string, fileId: string): Promise<FileAsset> {\n const file = await getFile(db, workspaceId, fileId);\n if (!file) {\n throw new Error(`File not found: ${fileId}`);\n }\n return file;\n}\n\nexport async function getFileUpload(db: Database, workspaceId: string, uploadId: string): Promise<{ id: string; status: FileUploadStatus; expiresAt: Date; file: FileAsset } | null> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const [row] = await scopedDb.select({\n id: schema.fileUploads.id,\n status: schema.fileUploads.status,\n expiresAt: schema.fileUploads.expiresAt,\n file: schema.files,\n }).from(schema.fileUploads)\n .innerJoin(schema.files, eq(schema.fileUploads.fileId, schema.files.id))\n .where(and(eq(schema.fileUploads.workspaceId, workspaceId), eq(schema.fileUploads.id, uploadId)))\n .limit(1);\n return row ? {\n id: row.id,\n status: row.status as FileUploadStatus,\n expiresAt: row.expiresAt,\n file: mapFile(row.file),\n } : null;\n });\n}\n\nexport async function completeFileUpload(db: Database, workspaceId: string, uploadId: string): Promise<FileAsset> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => await scopedDb.transaction(async (tx) => {\n const [uploadRow] = await tx.select().from(schema.fileUploads).where(and(eq(schema.fileUploads.workspaceId, workspaceId), eq(schema.fileUploads.id, uploadId))).for(\"update\").limit(1);\n if (!uploadRow) {\n throw new Error(`File upload not found: ${uploadId}`);\n }\n const [fileRow] = await tx.select().from(schema.files).where(and(eq(schema.files.workspaceId, workspaceId), eq(schema.files.id, uploadRow.fileId))).for(\"update\").limit(1);\n if (!fileRow) {\n throw new Error(`File not found for upload: ${uploadId}`);\n }\n const now = new Date();\n const [updatedFile] = await tx.update(schema.files).set({\n status: \"ready\",\n updatedAt: now,\n }).where(and(eq(schema.files.workspaceId, workspaceId), eq(schema.files.id, fileRow.id))).returning();\n await tx.update(schema.fileUploads).set({\n status: \"completed\",\n completedAt: now,\n updatedAt: now,\n }).where(and(eq(schema.fileUploads.workspaceId, workspaceId), eq(schema.fileUploads.id, uploadId)));\n if (!updatedFile) {\n throw new Error(\"Failed to complete file upload\");\n }\n return mapFile(updatedFile);\n }));\n}\n\nexport async function markFileUploadFailed(db: Database, workspaceId: string, uploadId: string, fileId: string): Promise<void> {\n const now = new Date();\n await withWorkspaceRls(db, workspaceId, async (scopedDb) => await scopedDb.transaction(async (tx) => {\n await tx.update(schema.fileUploads).set({ status: \"failed\", updatedAt: now }).where(and(eq(schema.fileUploads.workspaceId, workspaceId), eq(schema.fileUploads.id, uploadId)));\n await tx.update(schema.files).set({ status: \"failed\", updatedAt: now }).where(and(eq(schema.files.workspaceId, workspaceId), eq(schema.files.id, fileId)));\n }));\n}\n\nexport async function enablePackInstallation(db: Database, input: CreatePackInstallationInput): Promise<PackInstallation> {\n return await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId }, async (scopedDb) => {\n const now = new Date();\n const existing = await getPackInstallation(scopedDb, input.workspaceId, input.packId);\n if (existing) {\n const [row] = await scopedDb.update(schema.packInstallations).set({\n status: \"active\",\n metadata: input.metadata ?? existing.metadata,\n enabledAt: now,\n updatedAt: now,\n }).where(and(eq(schema.packInstallations.workspaceId, input.workspaceId), eq(schema.packInstallations.packId, input.packId))).returning();\n if (!row) {\n throw new Error(`Pack installation not found: ${input.packId}`);\n }\n return mapPackInstallation(row);\n }\n const [row] = await scopedDb.insert(schema.packInstallations).values({\n accountId: input.accountId,\n workspaceId: input.workspaceId,\n packId: input.packId,\n status: \"active\",\n metadata: input.metadata ?? {},\n }).returning();\n if (!row) {\n throw new Error(\"Failed to enable pack installation\");\n }\n return mapPackInstallation(row);\n });\n}\n\nexport async function listPackInstallations(db: Database, workspaceId: string): Promise<PackInstallation[]> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const rows = await scopedDb.select().from(schema.packInstallations)\n .where(eq(schema.packInstallations.workspaceId, workspaceId))\n .orderBy(desc(schema.packInstallations.updatedAt));\n return rows.map(mapPackInstallation);\n });\n}\n\nexport async function getPackInstallation(db: Database, workspaceId: string, packId: string): Promise<PackInstallation | null> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const [row] = await scopedDb.select().from(schema.packInstallations)\n .where(and(eq(schema.packInstallations.workspaceId, workspaceId), eq(schema.packInstallations.packId, packId)))\n .limit(1);\n return row ? mapPackInstallation(row) : null;\n });\n}\n\nexport async function updatePackInstallationStatus(db: Database, workspaceId: string, packId: string, status: PackInstallationStatus): Promise<PackInstallation> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const [row] = await scopedDb.update(schema.packInstallations).set({\n status,\n updatedAt: new Date(),\n }).where(and(eq(schema.packInstallations.workspaceId, workspaceId), eq(schema.packInstallations.packId, packId))).returning();\n if (!row) {\n throw new Error(`Pack installation not found: ${packId}`);\n }\n return mapPackInstallation(row);\n });\n}\n\nexport async function registerWorkspacePack(db: Database, input: RegisterWorkspacePackInput): Promise<{ pack: WorkspaceRegisteredPack; created: boolean }> {\n return await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId }, async (scopedDb) => {\n const now = new Date();\n const [row] = await scopedDb.insert(schema.workspacePacks).values({\n accountId: input.accountId,\n workspaceId: input.workspaceId,\n packId: input.pack.id,\n manifest: input.pack as unknown as Record<string, unknown>,\n })\n .onConflictDoUpdate({\n target: [schema.workspacePacks.workspaceId, schema.workspacePacks.packId],\n set: {\n manifest: input.pack as unknown as Record<string, unknown>,\n updatedAt: now,\n },\n })\n .returning();\n if (!row) {\n throw new Error(\"Failed to register workspace pack\");\n }\n return { pack: mapWorkspacePack(row), created: row.createdAt.getTime() === row.updatedAt.getTime() };\n });\n}\n\nexport async function listWorkspacePacks(db: Database, workspaceId: string): Promise<WorkspaceRegisteredPack[]> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const rows = await scopedDb.select().from(schema.workspacePacks)\n .where(eq(schema.workspacePacks.workspaceId, workspaceId))\n .orderBy(asc(schema.workspacePacks.packId));\n return rows.map(mapWorkspacePack);\n });\n}\n\nexport async function getWorkspacePack(db: Database, workspaceId: string, packId: string): Promise<WorkspaceRegisteredPack | null> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const [row] = await scopedDb.select().from(schema.workspacePacks)\n .where(and(eq(schema.workspacePacks.workspaceId, workspaceId), eq(schema.workspacePacks.packId, packId)))\n .limit(1);\n return row ? mapWorkspacePack(row) : null;\n });\n}\n\nexport async function deleteWorkspacePack(db: Database, workspaceId: string, packId: string): Promise<boolean> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const rows = await scopedDb.delete(schema.workspacePacks)\n .where(and(eq(schema.workspacePacks.workspaceId, workspaceId), eq(schema.workspacePacks.packId, packId)))\n .returning({ id: schema.workspacePacks.id });\n return rows.length > 0;\n });\n}\n\nexport async function upsertCapabilityCatalogItem(db: Database, input: CreateCapabilityCatalogItemInput): Promise<CapabilityCatalogItem> {\n return await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId }, async (scopedDb) => {\n const now = new Date();\n const values = {\n id: input.id,\n accountId: input.accountId,\n workspaceId: input.workspaceId,\n kind: input.kind,\n source: input.source,\n name: input.name,\n description: input.description ?? null,\n category: input.category ?? \"custom\",\n tags: input.tags ?? [],\n homepageUrl: input.homepageUrl ?? null,\n endpointUrl: input.endpointUrl ?? null,\n installUrl: input.installUrl ?? null,\n authModel: input.authModel ?? null,\n metadata: input.metadata ?? {},\n updatedAt: now,\n };\n const updateValues = {\n kind: values.kind,\n source: values.source,\n name: values.name,\n description: values.description,\n category: values.category,\n tags: values.tags,\n homepageUrl: values.homepageUrl,\n endpointUrl: values.endpointUrl,\n installUrl: values.installUrl,\n authModel: values.authModel,\n metadata: values.metadata,\n updatedAt: values.updatedAt,\n };\n const [row] = await scopedDb.insert(schema.capabilityCatalogItems).values(values)\n .onConflictDoUpdate({\n target: [schema.capabilityCatalogItems.workspaceId, schema.capabilityCatalogItems.id],\n set: updateValues,\n })\n .returning();\n if (!row) {\n throw new Error(\"Failed to upsert capability catalog item\");\n }\n return mapCapabilityCatalogItem(row);\n });\n}\n\nexport async function listCapabilityCatalogItems(db: Database, workspaceId: string): Promise<CapabilityCatalogItem[]> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const rows = await scopedDb.select().from(schema.capabilityCatalogItems)\n .where(eq(schema.capabilityCatalogItems.workspaceId, workspaceId))\n .orderBy(asc(schema.capabilityCatalogItems.kind), asc(schema.capabilityCatalogItems.name));\n return rows.map(mapCapabilityCatalogItem);\n });\n}\n\nexport async function getCapabilityCatalogItem(db: Database, workspaceId: string, capabilityId: string): Promise<CapabilityCatalogItem | null> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const [row] = await scopedDb.select().from(schema.capabilityCatalogItems)\n .where(and(eq(schema.capabilityCatalogItems.workspaceId, workspaceId), eq(schema.capabilityCatalogItems.id, capabilityId)))\n .limit(1);\n return row ? mapCapabilityCatalogItem(row) : null;\n });\n}\n\nexport async function enableCapabilityInstallation(db: Database, input: EnableCapabilityInstallationInput): Promise<CapabilityInstallation> {\n return await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId }, async (scopedDb) => {\n const now = new Date();\n // Read the raw row (not the redacted mapping) so an omitted config\n // preserves stored credential-header ciphertext instead of the redaction.\n const [existing] = await scopedDb.select().from(schema.capabilityInstallations)\n .where(and(eq(schema.capabilityInstallations.workspaceId, input.workspaceId), eq(schema.capabilityInstallations.capabilityId, input.capabilityId)))\n .limit(1);\n if (existing) {\n const [row] = await scopedDb.update(schema.capabilityInstallations).set({\n kind: input.kind,\n status: \"active\",\n config: input.config ?? existing.config,\n metadata: input.metadata ?? existing.metadata,\n enabledAt: now,\n updatedAt: now,\n }).where(and(eq(schema.capabilityInstallations.workspaceId, input.workspaceId), eq(schema.capabilityInstallations.capabilityId, input.capabilityId))).returning();\n if (!row) {\n throw new Error(`Capability installation not found: ${input.capabilityId}`);\n }\n return mapCapabilityInstallation(row);\n }\n const [row] = await scopedDb.insert(schema.capabilityInstallations).values({\n accountId: input.accountId,\n workspaceId: input.workspaceId,\n capabilityId: input.capabilityId,\n kind: input.kind,\n status: \"active\",\n config: input.config ?? {},\n metadata: input.metadata ?? {},\n }).returning();\n if (!row) {\n throw new Error(\"Failed to enable capability installation\");\n }\n return mapCapabilityInstallation(row);\n });\n}\n\nexport async function disableCapabilityInstallation(db: Database, workspaceId: string, capabilityId: string): Promise<CapabilityInstallation> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const [row] = await scopedDb.update(schema.capabilityInstallations).set({\n status: \"disabled\",\n updatedAt: new Date(),\n }).where(and(eq(schema.capabilityInstallations.workspaceId, workspaceId), eq(schema.capabilityInstallations.capabilityId, capabilityId))).returning();\n if (!row) {\n throw new Error(`Capability installation not found: ${capabilityId}`);\n }\n return mapCapabilityInstallation(row);\n });\n}\n\nexport async function listCapabilityInstallations(db: Database, workspaceId: string): Promise<CapabilityInstallation[]> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const rows = await scopedDb.select().from(schema.capabilityInstallations)\n .where(eq(schema.capabilityInstallations.workspaceId, workspaceId))\n .orderBy(desc(schema.capabilityInstallations.updatedAt));\n return rows.map(mapCapabilityInstallation);\n });\n}\n\nexport async function getCapabilityInstallation(db: Database, workspaceId: string, capabilityId: string): Promise<CapabilityInstallation | null> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const [row] = await scopedDb.select().from(schema.capabilityInstallations)\n .where(and(eq(schema.capabilityInstallations.workspaceId, workspaceId), eq(schema.capabilityInstallations.capabilityId, capabilityId)))\n .limit(1);\n return row ? mapCapabilityInstallation(row) : null;\n });\n}\n\nexport async function listEnabledMcpCapabilityServers(db: Database, workspaceId: string): Promise<EnabledMcpCapabilityServer[]> {\n const rows = await withWorkspaceRls(db, workspaceId, async (scopedDb) => await scopedDb.select({\n item: schema.capabilityCatalogItems,\n installation: schema.capabilityInstallations,\n }).from(schema.capabilityInstallations)\n .innerJoin(schema.capabilityCatalogItems, and(\n eq(schema.capabilityInstallations.workspaceId, schema.capabilityCatalogItems.workspaceId),\n eq(schema.capabilityInstallations.capabilityId, schema.capabilityCatalogItems.id),\n ))\n .where(and(\n eq(schema.capabilityInstallations.workspaceId, workspaceId),\n eq(schema.capabilityInstallations.kind, \"mcp\"),\n eq(schema.capabilityInstallations.status, \"active\"),\n ))\n .orderBy(asc(schema.capabilityCatalogItems.name)));\n\n return rows.flatMap(({ item, installation }) => {\n if (!item.endpointUrl || !mcpConnectivityOk(installation.metadata)) {\n return [];\n }\n const headersEncrypted = encryptedHeadersConfig(installation.config.headersEncrypted);\n if (item.authModel && !headersEncrypted) {\n // Credential-gated MCPs are runnable only when credential headers were\n // stored at enable time.\n return [];\n }\n const metadata = item.metadata;\n const config = installation.config;\n const allowedTools = stringArrayConfig(config.allowedTools ?? metadata.allowedTools);\n const timeoutMs = positiveIntegerConfig(config.timeoutMs ?? metadata.timeoutMs);\n const cacheToolsList = booleanConfig(config.cacheToolsList ?? metadata.cacheToolsList);\n return [{\n capabilityId: item.id,\n id: mcpServerIdForCapability(item.id, metadata),\n name: item.name,\n url: item.endpointUrl,\n ...(allowedTools ? { allowedTools } : {}),\n ...(timeoutMs ? { timeoutMs } : {}),\n ...(cacheToolsList !== undefined ? { cacheToolsList } : {}),\n ...(headersEncrypted ? { headersEncrypted } : {}),\n }];\n });\n}\n\n/**\n * Decrypts an enabled capability MCP's stored credential headers. Returns\n * null when the server has none, and \"unavailable\" when headers exist but\n * cannot be recovered (missing key or failed decryption) — in which case the\n * server must be skipped rather than connected without credentials.\n */\nexport function decryptedCapabilityHeaders(\n server: EnabledMcpCapabilityServer,\n encryptionKey: Uint8Array | null,\n): Record<string, string> | null | \"unavailable\" {\n if (!server.headersEncrypted || Object.keys(server.headersEncrypted).length === 0) {\n return null;\n }\n if (!encryptionKey) {\n return \"unavailable\";\n }\n try {\n return Object.fromEntries(Object.entries(server.headersEncrypted).map(([name, value]) => [name, decryptEnvironmentValue(encryptionKey, value)]));\n } catch {\n return \"unavailable\";\n }\n}\n\n/**\n * Returns the encrypted credential-header map stored on a capability\n * installation, or null when none is stored. This is the only read path for\n * the ciphertext besides listEnabledMcpCapabilityServers; the generic\n * installation mapping redacts it to header names.\n */\nexport async function getStoredCapabilityHeaderCiphertext(db: Database, workspaceId: string, capabilityId: string): Promise<Record<string, string> | null> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const [row] = await scopedDb.select({ config: schema.capabilityInstallations.config }).from(schema.capabilityInstallations)\n .where(and(eq(schema.capabilityInstallations.workspaceId, workspaceId), eq(schema.capabilityInstallations.capabilityId, capabilityId)))\n .limit(1);\n return row ? encryptedHeadersConfig(row.config.headersEncrypted) ?? null : null;\n });\n}\n\nexport function mcpServerIdForCapability(capabilityId: string, metadata: Record<string, unknown> = {}): string {\n const explicit = typeof metadata.mcpServerId === \"string\" ? metadata.mcpServerId.trim() : \"\";\n if (/^[A-Za-z0-9_-]+$/.test(explicit)) {\n return explicit;\n }\n const body = capabilityId\n .replace(/^[^:]+:/, \"\")\n .toLowerCase()\n .replace(/[^a-z0-9_-]+/g, \"-\")\n .replace(/^-+|-+$/g, \"\")\n .slice(0, 44) || \"mcp\";\n return `cap-${body}-${shortHash(capabilityId)}`;\n}\n\nexport async function createSocialConnection(db: Database, input: CreateSocialConnectionInput): Promise<SocialConnection> {\n return await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId }, async (scopedDb) => {\n const [row] = await scopedDb.insert(schema.socialConnections).values({\n accountId: input.accountId,\n workspaceId: input.workspaceId,\n provider: input.provider,\n accountHandle: input.accountHandle,\n accountName: input.accountName ?? null,\n externalAccountId: input.externalAccountId ?? null,\n status: input.status,\n scopes: input.scopes ?? [],\n credentialRef: input.credentialRef ?? null,\n tokenMetadata: input.tokenMetadata ?? {},\n metadata: input.metadata ?? {},\n }).returning();\n if (!row) {\n throw new Error(\"Failed to create social connection\");\n }\n return mapSocialConnection(row);\n });\n}\n\nexport async function listSocialConnections(db: Database, workspaceId: string, limit = 100): Promise<SocialConnection[]> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const rows = await scopedDb.select().from(schema.socialConnections)\n .where(eq(schema.socialConnections.workspaceId, workspaceId))\n .orderBy(desc(schema.socialConnections.createdAt))\n .limit(limit);\n return rows.map(mapSocialConnection);\n });\n}\n\nexport async function getSocialConnection(db: Database, workspaceId: string, connectionId: string): Promise<SocialConnection | null> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const [row] = await scopedDb.select().from(schema.socialConnections)\n .where(and(eq(schema.socialConnections.workspaceId, workspaceId), eq(schema.socialConnections.id, connectionId)))\n .limit(1);\n return row ? mapSocialConnection(row) : null;\n });\n}\n\nexport async function requireSocialConnection(db: Database, workspaceId: string, connectionId: string): Promise<SocialConnection> {\n const connection = await getSocialConnection(db, workspaceId, connectionId);\n if (!connection) {\n throw new Error(`Social connection not found: ${connectionId}`);\n }\n return connection;\n}\n\nexport async function createSocialPost(db: Database, input: CreateSocialPostInput): Promise<SocialPost> {\n return await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId }, async (scopedDb) => {\n const connection = await requireSocialConnection(scopedDb, input.workspaceId, input.connectionId);\n const [row] = await scopedDb.insert(schema.socialPosts).values({\n accountId: input.accountId,\n workspaceId: input.workspaceId,\n connectionId: input.connectionId,\n provider: connection.provider,\n externalPostId: input.externalPostId ?? null,\n url: input.url ?? null,\n authorHandle: input.authorHandle ?? connection.accountHandle,\n text: input.text,\n publishedAt: input.publishedAt,\n metrics: input.metrics ?? {},\n raw: input.raw ?? {},\n }).returning();\n if (!row) {\n throw new Error(\"Failed to create social post\");\n }\n return mapSocialPost(row);\n });\n}\n\nexport async function listSocialPosts(db: Database, options: {\n workspaceId: string;\n connectionIds?: string[];\n since?: Date;\n limit?: number;\n}): Promise<SocialPost[]> {\n const conditions: SQL[] = [eq(schema.socialPosts.workspaceId, options.workspaceId)];\n if (options.connectionIds?.length) {\n conditions.push(inArray(schema.socialPosts.connectionId, options.connectionIds));\n }\n if (options.since) {\n conditions.push(gte(schema.socialPosts.publishedAt, options.since));\n }\n const limit = options.limit ?? 100;\n return await withWorkspaceRls(db, options.workspaceId, async (scopedDb) => {\n const rows = await scopedDb.select().from(schema.socialPosts)\n .where(and(...conditions))\n .orderBy(desc(schema.socialPosts.publishedAt))\n .limit(limit);\n return rows.map(mapSocialPost);\n });\n}\n\nexport async function createScheduledTask(db: Database, input: CreateScheduledTaskInput): Promise<ScheduledTask> {\n return await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId }, async (scopedDb) => {\n const [row] = await scopedDb.insert(schema.scheduledTasks).values(input).returning();\n if (!row) {\n throw new Error(\"Failed to create scheduled task\");\n }\n return mapScheduledTask(row);\n });\n}\n\nexport async function updateScheduledTask(db: Database, workspaceId: string, taskId: string, input: UpdateScheduledTaskInput): Promise<ScheduledTask> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const [row] = await scopedDb.update(schema.scheduledTasks).set({\n ...(input.name !== undefined ? { name: input.name } : {}),\n ...(input.status !== undefined ? { status: input.status } : {}),\n ...(input.schedule !== undefined ? { schedule: input.schedule } : {}),\n ...(input.runMode !== undefined ? { runMode: input.runMode } : {}),\n ...(input.overlapPolicy !== undefined ? { overlapPolicy: input.overlapPolicy } : {}),\n ...(input.agentConfig !== undefined ? { agentConfig: input.agentConfig } : {}),\n ...(input.reusableSessionId !== undefined ? { reusableSessionId: input.reusableSessionId } : {}),\n ...(input.environmentId !== undefined ? { environmentId: input.environmentId } : {}),\n ...(input.metadata !== undefined ? { metadata: input.metadata } : {}),\n updatedAt: new Date(),\n }).where(and(eq(schema.scheduledTasks.workspaceId, workspaceId), eq(schema.scheduledTasks.id, taskId))).returning();\n if (!row) {\n throw new Error(`Scheduled task not found: ${taskId}`);\n }\n return mapScheduledTask(row);\n });\n}\n\nexport async function getScheduledTask(db: Database, workspaceId: string, taskId: string): Promise<ScheduledTask | null> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const [row] = await scopedDb.select().from(schema.scheduledTasks).where(and(eq(schema.scheduledTasks.workspaceId, workspaceId), eq(schema.scheduledTasks.id, taskId))).limit(1);\n return row ? mapScheduledTask(row) : null;\n });\n}\n\nexport async function requireScheduledTask(db: Database, workspaceId: string, taskId: string): Promise<ScheduledTask> {\n const task = await getScheduledTask(db, workspaceId, taskId);\n if (!task) {\n throw new Error(`Scheduled task not found: ${taskId}`);\n }\n return task;\n}\n\nexport async function listScheduledTasks(db: Database, workspaceId: string, limit = 100): Promise<ScheduledTask[]> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const rows = await scopedDb.select().from(schema.scheduledTasks)\n .where(eq(schema.scheduledTasks.workspaceId, workspaceId))\n .orderBy(desc(schema.scheduledTasks.createdAt))\n .limit(limit);\n return rows.map(mapScheduledTask);\n });\n}\n\nexport async function deleteScheduledTask(db: Database, workspaceId: string, taskId: string): Promise<void> {\n await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n await scopedDb.delete(schema.scheduledTasks).where(and(eq(schema.scheduledTasks.workspaceId, workspaceId), eq(schema.scheduledTasks.id, taskId)));\n });\n}\n\nexport async function createScheduledTaskRun(db: Database, input: {\n workspaceId: string;\n taskId: string;\n triggerType: ScheduledTaskTriggerType;\n scheduledAt?: Date | null;\n firedAt?: Date;\n}): Promise<ScheduledTaskRun> {\n return await withWorkspaceRls(db, input.workspaceId, async (scopedDb) => {\n const [taskRow] = await scopedDb.select().from(schema.scheduledTasks)\n .where(and(eq(schema.scheduledTasks.workspaceId, input.workspaceId), eq(schema.scheduledTasks.id, input.taskId)))\n .limit(1);\n if (!taskRow) {\n throw new Error(`Scheduled task not found: ${input.taskId}`);\n }\n const [row] = await scopedDb.insert(schema.scheduledTaskRuns).values({\n accountId: taskRow.accountId,\n workspaceId: taskRow.workspaceId,\n taskId: input.taskId,\n triggerType: input.triggerType,\n scheduledAt: input.scheduledAt ?? null,\n firedAt: input.firedAt ?? new Date(),\n status: \"queued\",\n }).returning();\n if (!row) {\n throw new Error(\"Failed to create scheduled task run\");\n }\n return mapScheduledTaskRun(row);\n });\n}\n\nexport async function updateScheduledTaskRun(db: Database, workspaceId: string, runId: string, input: Partial<{\n status: ScheduledTaskRunStatus;\n sessionId: string | null;\n triggerEventId: string | null;\n error: string | null;\n}>): Promise<ScheduledTaskRun> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const [row] = await scopedDb.update(schema.scheduledTaskRuns).set({\n ...(input.status !== undefined ? { status: input.status } : {}),\n ...(input.sessionId !== undefined ? { sessionId: input.sessionId } : {}),\n ...(input.triggerEventId !== undefined ? { triggerEventId: input.triggerEventId } : {}),\n ...(input.error !== undefined ? { error: input.error } : {}),\n updatedAt: new Date(),\n }).where(and(eq(schema.scheduledTaskRuns.workspaceId, workspaceId), eq(schema.scheduledTaskRuns.id, runId))).returning();\n if (!row) {\n throw new Error(`Scheduled task run not found: ${runId}`);\n }\n return mapScheduledTaskRun(row);\n });\n}\n\nexport async function listScheduledTaskRuns(db: Database, workspaceId: string, taskId: string, limit = 100): Promise<ScheduledTaskRun[]> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const rows = await scopedDb.select().from(schema.scheduledTaskRuns)\n .where(and(eq(schema.scheduledTaskRuns.workspaceId, workspaceId), eq(schema.scheduledTaskRuns.taskId, taskId)))\n .orderBy(desc(schema.scheduledTaskRuns.createdAt))\n .limit(limit);\n return rows.map(mapScheduledTaskRun);\n });\n}\n\nexport async function createWorkspaceEnvironment(db: Database, input: {\n accountId: string;\n workspaceId: string;\n name: string;\n description?: string | null;\n variables?: Array<{ name: string; valueEncrypted: string }>;\n}): Promise<WorkspaceEnvironment> {\n // withRlsContext wraps the callback in one transaction, so the environment\n // row and all initial variables commit or roll back together.\n return await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId }, async (scopedDb) => {\n const [row] = await scopedDb.insert(schema.workspaceEnvironments).values({\n accountId: input.accountId,\n workspaceId: input.workspaceId,\n name: input.name,\n description: input.description ?? null,\n }).returning();\n if (!row) {\n throw new Error(\"Failed to create workspace environment\");\n }\n const variables = input.variables ?? [];\n if (variables.length === 0) {\n return mapWorkspaceEnvironment(row, []);\n }\n const inserted = await scopedDb.insert(schema.workspaceEnvironmentVariables).values(variables.map((variable) => ({\n accountId: input.accountId,\n workspaceId: input.workspaceId,\n environmentId: row.id,\n name: variable.name,\n valueEncrypted: variable.valueEncrypted,\n }))).returning({\n name: schema.workspaceEnvironmentVariables.name,\n version: schema.workspaceEnvironmentVariables.version,\n createdAt: schema.workspaceEnvironmentVariables.createdAt,\n updatedAt: schema.workspaceEnvironmentVariables.updatedAt,\n });\n return mapWorkspaceEnvironment(row, inserted\n .map(mapWorkspaceEnvironmentVariableMetadata)\n .sort((a, b) => a.name.localeCompare(b.name)));\n });\n}\n\nexport async function listWorkspaceEnvironments(db: Database, workspaceId: string): Promise<WorkspaceEnvironment[]> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const rows = await scopedDb.select().from(schema.workspaceEnvironments)\n .where(eq(schema.workspaceEnvironments.workspaceId, workspaceId))\n .orderBy(asc(schema.workspaceEnvironments.createdAt));\n const variableRows = await scopedDb.select({\n environmentId: schema.workspaceEnvironmentVariables.environmentId,\n name: schema.workspaceEnvironmentVariables.name,\n version: schema.workspaceEnvironmentVariables.version,\n createdAt: schema.workspaceEnvironmentVariables.createdAt,\n updatedAt: schema.workspaceEnvironmentVariables.updatedAt,\n }).from(schema.workspaceEnvironmentVariables)\n .where(eq(schema.workspaceEnvironmentVariables.workspaceId, workspaceId))\n .orderBy(asc(schema.workspaceEnvironmentVariables.name));\n const grouped = new Map<string, WorkspaceEnvironmentVariableMetadata[]>();\n for (const variable of variableRows) {\n const list = grouped.get(variable.environmentId) ?? [];\n list.push(mapWorkspaceEnvironmentVariableMetadata(variable));\n grouped.set(variable.environmentId, list);\n }\n return rows.map((row) => mapWorkspaceEnvironment(row, grouped.get(row.id) ?? []));\n });\n}\n\nexport async function getWorkspaceEnvironment(db: Database, workspaceId: string, environmentId: string): Promise<WorkspaceEnvironment | null> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const [row] = await scopedDb.select().from(schema.workspaceEnvironments)\n .where(and(eq(schema.workspaceEnvironments.workspaceId, workspaceId), eq(schema.workspaceEnvironments.id, environmentId)))\n .limit(1);\n if (!row) {\n return null;\n }\n return mapWorkspaceEnvironment(row, await listEnvironmentVariableMetadata(scopedDb, workspaceId, environmentId));\n });\n}\n\nexport async function getWorkspaceEnvironmentByName(db: Database, workspaceId: string, name: string): Promise<WorkspaceEnvironment | null> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const [row] = await scopedDb.select().from(schema.workspaceEnvironments)\n .where(and(eq(schema.workspaceEnvironments.workspaceId, workspaceId), eq(schema.workspaceEnvironments.name, name)))\n .limit(1);\n if (!row) {\n return null;\n }\n return mapWorkspaceEnvironment(row, await listEnvironmentVariableMetadata(scopedDb, workspaceId, row.id));\n });\n}\n\nexport async function updateWorkspaceEnvironment(db: Database, workspaceId: string, environmentId: string, input: {\n name?: string;\n description?: string | null;\n}): Promise<WorkspaceEnvironment> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const [row] = await scopedDb.update(schema.workspaceEnvironments).set({\n ...(input.name !== undefined ? { name: input.name } : {}),\n ...(input.description !== undefined ? { description: input.description } : {}),\n updatedAt: new Date(),\n }).where(and(eq(schema.workspaceEnvironments.workspaceId, workspaceId), eq(schema.workspaceEnvironments.id, environmentId))).returning();\n if (!row) {\n throw new Error(`Workspace environment not found: ${environmentId}`);\n }\n return mapWorkspaceEnvironment(row, await listEnvironmentVariableMetadata(scopedDb, workspaceId, environmentId));\n });\n}\n\nexport async function deleteWorkspaceEnvironment(db: Database, workspaceId: string, environmentId: string): Promise<boolean> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const rows = await scopedDb.delete(schema.workspaceEnvironments)\n .where(and(eq(schema.workspaceEnvironments.workspaceId, workspaceId), eq(schema.workspaceEnvironments.id, environmentId)))\n .returning({ id: schema.workspaceEnvironments.id });\n return rows.length > 0;\n });\n}\n\nexport async function countWorkspaceEnvironments(db: Database, workspaceId: string): Promise<number> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const [{ count } = { count: 0 }] = await scopedDb.select({\n count: sql<number>`count(*)::int`,\n }).from(schema.workspaceEnvironments).where(eq(schema.workspaceEnvironments.workspaceId, workspaceId));\n return Number(count);\n });\n}\n\nexport async function countScheduledTasksUsingEnvironment(db: Database, workspaceId: string, environmentId: string): Promise<number> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const [{ count } = { count: 0 }] = await scopedDb.select({\n count: sql<number>`count(*)::int`,\n }).from(schema.scheduledTasks)\n .where(and(eq(schema.scheduledTasks.workspaceId, workspaceId), eq(schema.scheduledTasks.environmentId, environmentId)));\n return Number(count);\n });\n}\n\nexport async function countActiveSessionsUsingEnvironment(db: Database, workspaceId: string, environmentId: string): Promise<number> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const [{ count } = { count: 0 }] = await scopedDb.select({\n count: sql<number>`count(*)::int`,\n }).from(schema.sessions)\n .where(and(\n eq(schema.sessions.workspaceId, workspaceId),\n eq(schema.sessions.environmentId, environmentId),\n inArray(schema.sessions.status, [\"queued\", \"running\", \"requires_action\"]),\n ));\n return Number(count);\n });\n}\n\nexport async function setWorkspaceEnvironmentVariable(db: Database, input: {\n accountId: string;\n workspaceId: string;\n environmentId: string;\n name: string;\n valueEncrypted: string;\n}): Promise<WorkspaceEnvironmentVariableMetadata> {\n return await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId }, async (scopedDb) => {\n const now = new Date();\n const [row] = await scopedDb.insert(schema.workspaceEnvironmentVariables).values({\n accountId: input.accountId,\n workspaceId: input.workspaceId,\n environmentId: input.environmentId,\n name: input.name,\n valueEncrypted: input.valueEncrypted,\n }).onConflictDoUpdate({\n target: [\n schema.workspaceEnvironmentVariables.workspaceId,\n schema.workspaceEnvironmentVariables.environmentId,\n schema.workspaceEnvironmentVariables.name,\n ],\n set: {\n valueEncrypted: input.valueEncrypted,\n version: sql`${schema.workspaceEnvironmentVariables.version} + 1`,\n updatedAt: now,\n },\n }).returning({\n name: schema.workspaceEnvironmentVariables.name,\n version: schema.workspaceEnvironmentVariables.version,\n createdAt: schema.workspaceEnvironmentVariables.createdAt,\n updatedAt: schema.workspaceEnvironmentVariables.updatedAt,\n });\n if (!row) {\n throw new Error(\"Failed to set workspace environment variable\");\n }\n await scopedDb.update(schema.workspaceEnvironments).set({ updatedAt: now })\n .where(and(eq(schema.workspaceEnvironments.workspaceId, input.workspaceId), eq(schema.workspaceEnvironments.id, input.environmentId)));\n return mapWorkspaceEnvironmentVariableMetadata(row);\n });\n}\n\nexport async function deleteWorkspaceEnvironmentVariable(db: Database, workspaceId: string, environmentId: string, name: string): Promise<boolean> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const rows = await scopedDb.delete(schema.workspaceEnvironmentVariables)\n .where(and(\n eq(schema.workspaceEnvironmentVariables.workspaceId, workspaceId),\n eq(schema.workspaceEnvironmentVariables.environmentId, environmentId),\n eq(schema.workspaceEnvironmentVariables.name, name),\n ))\n .returning({ id: schema.workspaceEnvironmentVariables.id });\n if (rows.length > 0) {\n await scopedDb.update(schema.workspaceEnvironments).set({ updatedAt: new Date() })\n .where(and(eq(schema.workspaceEnvironments.workspaceId, workspaceId), eq(schema.workspaceEnvironments.id, environmentId)));\n }\n return rows.length > 0;\n });\n}\n\n/**\n * The ONLY helper that selects value_encrypted. Used exclusively by the worker\n * activity that materializes a sandbox for a run whose session carries an\n * environment attachment. Do not call from API routes: values are write-only.\n */\nexport async function getWorkspaceEnvironmentValuesForRun(db: Database, workspaceId: string, environmentId: string): Promise<{\n environment: { id: string; name: string; description: string | null };\n values: Record<string, string>;\n} | null> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const [environment] = await scopedDb.select({\n id: schema.workspaceEnvironments.id,\n name: schema.workspaceEnvironments.name,\n description: schema.workspaceEnvironments.description,\n }).from(schema.workspaceEnvironments)\n .where(and(eq(schema.workspaceEnvironments.workspaceId, workspaceId), eq(schema.workspaceEnvironments.id, environmentId)))\n .limit(1);\n if (!environment) {\n return null;\n }\n const rows = await scopedDb.select({\n name: schema.workspaceEnvironmentVariables.name,\n valueEncrypted: schema.workspaceEnvironmentVariables.valueEncrypted,\n }).from(schema.workspaceEnvironmentVariables)\n .where(and(\n eq(schema.workspaceEnvironmentVariables.workspaceId, workspaceId),\n eq(schema.workspaceEnvironmentVariables.environmentId, environmentId),\n ));\n return {\n environment: { id: environment.id, name: environment.name, description: environment.description },\n values: Object.fromEntries(rows.map((row) => [row.name, row.valueEncrypted])),\n };\n });\n}\n\nexport type WorkspaceEnvironmentForRun = {\n id: string;\n name: string;\n description: string | null;\n values: Record<string, string>;\n};\n\n/**\n * Load and decrypt the workspace environment attached to a run's session. SHARED\n * by the worker TURN path (apps/worker agent-turn) AND the API-direct ATTACH paths\n * (viewer / Channel-A / desktop / terminal) so a box first warmed by an attach is\n * created with the SAME decrypted workspace-environment values the turn declares —\n * the box-manifest env must match the agent-manifest env or the SDK's\n * `validateNoEnvironmentDelta` throws when the agent injects its manifest into the\n * resumed non-owned box.\n *\n * `environmentId === null` is the unattached path: zero DB work and behavior\n * byte-identical to deployments without this feature. Attached runs fail closed: a\n * missing key or a deleted environment throws (names/ids only in messages) instead\n * of silently running without the secrets the run expects.\n */\nexport async function loadWorkspaceEnvironmentForRun(\n db: Database,\n settings: Settings,\n workspaceId: string,\n environmentId: string | null,\n): Promise<WorkspaceEnvironmentForRun | null> {\n if (!environmentId) {\n return null;\n }\n const key = environmentsEncryptionKeyBytes(settings);\n if (!key) {\n throw new Error(\"workspace environment attached but OPENGENI_ENVIRONMENTS_ENCRYPTION_KEY is not configured\");\n }\n const stored = await getWorkspaceEnvironmentValuesForRun(db, workspaceId, environmentId);\n if (!stored) {\n throw new Error(`workspace environment not found: ${environmentId}`);\n }\n const values: Record<string, string> = {};\n for (const [name, encrypted] of Object.entries(stored.values)) {\n try {\n values[name] = decryptEnvironmentValue(key, encrypted);\n } catch (error) {\n const reason = error instanceof Error ? error.message : String(error);\n throw new Error(`failed to decrypt workspace environment variable ${name}: ${reason}`);\n }\n }\n return {\n id: stored.environment.id,\n name: stored.environment.name,\n description: stored.environment.description,\n values,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Codex (ChatGPT) subscription credentials\n//\n// One row per workspace. Secret tokens live inside `credential_encrypted` (v1\n// AES-256-GCM, same envelope as workspace env vars). The caller pre-encrypts the\n// JSON bundle {access_token, refresh_token, id_token} — the db layer never sees\n// plaintext token JSON on the write path. `loadCodexCredentialForRun` is the\n// ONLY decrypt-read accessor and must never be called from an API route;\n// `getCodexCredentialStatus` returns metadata only (never the secret column).\n// ---------------------------------------------------------------------------\n\nexport type CodexCredentialTokens = { accessToken: string; refreshToken: string; idToken: string };\n\nexport type CodexCredentialForRun = {\n id: string; // row id — for compare-and-set writes (P1-c)\n version: number; // optimistic-concurrency version loaded with this snapshot\n workspaceId: string;\n tokens: CodexCredentialTokens; // decrypted — never logged, never returned by a route\n chatgptAccountId: string | null;\n scopes: string | null;\n planType: string | null;\n isFedramp: boolean;\n expiresAt: Date | null;\n lastRefreshAt: Date | null;\n status: string;\n lastError: string | null;\n};\n\n/**\n * Login / rotation write (multi-account P1). Caller passes the PRE-encrypted\n * credential blob. Keyed on the composite partial index (workspace, chatgpt\n * account): re-connecting the SAME ChatGPT account updates that row in place\n * (re-asserts account_id, bumps version); connecting a NEW account inserts a new\n * row. Returns the row id + whether it was newly inserted. The route — not this\n * accessor — auto-activates a brand-new first account and ensures the\n * rotation-settings row exists.\n */\nexport async function upsertCodexSubscriptionCredential(db: Database, input: {\n accountId: string;\n workspaceId: string;\n credentialEncrypted: string; // v1 envelope of JSON {access_token, refresh_token, id_token}\n chatgptAccountId: string | null;\n scopes: string | null;\n planType: string | null;\n isFedramp: boolean;\n expiresAt: Date | null;\n lastRefreshAt: Date | null;\n accountEmail?: string | null;\n label?: string | null;\n}): Promise<{ id: string; isNew: boolean }> {\n return await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId }, async (scopedDb) => {\n const now = new Date();\n const [row] = await scopedDb.insert(schema.codexSubscriptionCredentials).values({\n accountId: input.accountId,\n workspaceId: input.workspaceId,\n credentialEncrypted: input.credentialEncrypted,\n chatgptAccountId: input.chatgptAccountId,\n scopes: input.scopes,\n planType: input.planType,\n isFedramp: input.isFedramp,\n expiresAt: input.expiresAt,\n lastRefreshAt: input.lastRefreshAt,\n accountEmail: input.accountEmail ?? null,\n label: input.label ?? null,\n status: \"active\",\n lastError: null,\n }).onConflictDoUpdate({\n // The unique index is PARTIAL (WHERE chatgpt_account_id IS NOT NULL), so the\n // conflict target MUST repeat that predicate via targetWhere, else postgres\n // raises \"no unique or exclusion constraint matching the ON CONFLICT\".\n target: [schema.codexSubscriptionCredentials.workspaceId, schema.codexSubscriptionCredentials.chatgptAccountId],\n targetWhere: sql`chatgpt_account_id is not null`,\n set: {\n // account_id MUST be re-asserted on conflict. Omitting it leaves a stale\n // account_id on a row whose owning account changed (e.g. a reconnect\n // under a different grant), which makes the row RLS-INVISIBLE to every\n // subsequent scoped read — a permanent phantom \"no active subscription\".\n accountId: input.accountId,\n credentialEncrypted: input.credentialEncrypted,\n scopes: input.scopes,\n planType: input.planType,\n isFedramp: input.isFedramp,\n expiresAt: input.expiresAt,\n lastRefreshAt: input.lastRefreshAt,\n // Refresh the derived email; keep an existing user-chosen label (only seed\n // it when still null) so a re-connect never clobbers a rename.\n accountEmail: input.accountEmail ?? null,\n label: sql`coalesce(${schema.codexSubscriptionCredentials.label}, ${input.label ?? null})`,\n status: \"active\",\n lastError: null,\n version: sql`${schema.codexSubscriptionCredentials.version} + 1`,\n updatedAt: now,\n },\n }).returning({\n id: schema.codexSubscriptionCredentials.id,\n createdAt: schema.codexSubscriptionCredentials.createdAt,\n updatedAt: schema.codexSubscriptionCredentials.updatedAt,\n });\n // The upsert always returns exactly one row (insert or update).\n if (!row) {\n throw new Error(\"upsertCodexSubscriptionCredential returned no row\");\n }\n // A fresh INSERT leaves created_at === updated_at (both the same per-txn db\n // now()). A conflict UPDATE stamps updated_at to our JS `now` while created_at\n // keeps the original (older) value, so the two diverge. This distinguishes\n // insert from update without a second read.\n const isNew = row.createdAt.getTime() === row.updatedAt.getTime();\n return { id: row.id, isNew };\n });\n}\n\n/**\n * The ONLY decrypt-read accessor. Fails closed. Never call from an API route that\n * returns the result.\n *\n * The run's account is the resolved pin-or-active credential id, not LIMIT 1: the\n * caller (worker) resolves the effective credential id and passes it here so a\n * pinned session loads its SPECIFIC account. RLS still constrains the row to the\n * workspace; an unknown/disconnected id returns null → the caller treats it as\n * \"needs relogin / re-pick\".\n */\nexport async function loadCodexCredentialForRun(\n db: Database,\n settings: Settings,\n workspaceId: string,\n credentialId: string,\n): Promise<CodexCredentialForRun | null> {\n const key = environmentsEncryptionKeyBytes(settings);\n if (!key) {\n throw new Error(\"codex credential present but OPENGENI_ENVIRONMENTS_ENCRYPTION_KEY is not configured\");\n }\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const [row] = await scopedDb.select().from(schema.codexSubscriptionCredentials)\n .where(and(\n eq(schema.codexSubscriptionCredentials.id, credentialId),\n eq(schema.codexSubscriptionCredentials.workspaceId, workspaceId),\n )).limit(1);\n if (!row) {\n return null;\n }\n let tokens: CodexCredentialTokens;\n try {\n // The stored blob uses OpenAI's snake_case token field names; map to the\n // camelCase internal shape. Callers (route + worker) write snake_case.\n const parsed = JSON.parse(decryptEnvironmentValue(key, row.credentialEncrypted)) as {\n access_token: string;\n refresh_token: string;\n id_token: string;\n };\n tokens = { accessToken: parsed.access_token, refreshToken: parsed.refresh_token, idToken: parsed.id_token };\n } catch (error) {\n const reason = error instanceof Error ? error.message : String(error);\n throw new Error(`failed to decrypt codex credential for workspace ${workspaceId}: ${reason}`);\n }\n return {\n id: row.id,\n version: row.version,\n workspaceId,\n tokens,\n chatgptAccountId: row.chatgptAccountId,\n scopes: row.scopes,\n planType: row.planType,\n isFedramp: row.isFedramp,\n expiresAt: row.expiresAt,\n lastRefreshAt: row.lastRefreshAt,\n status: row.status,\n lastError: row.lastError,\n };\n });\n}\n\n/**\n * Persist rotated tokens after a successful refresh. Caller pre-encrypts.\n *\n * COMPARE-AND-SET (P1-c): the write is guarded by the (id, version) the resolver\n * loaded. If a disconnect→reconnect replaced/rotated the row between the load and\n * this write, the guard matches 0 rows and we DO NOT clobber the freshly\n * reconnected credential with tokens from the now-defunct family. Returns true\n * iff the guarded row was updated; false means \"credential changed under me —\n * the rotation is moot, drop it.\"\n */\nexport async function recordCodexTokenRefresh(db: Database, input: {\n id: string;\n version: number;\n workspaceId: string;\n credentialEncrypted: string;\n expiresAt: Date | null;\n lastRefreshAt: Date;\n}): Promise<boolean> {\n return await withWorkspaceRls(db, input.workspaceId, async (scopedDb) => {\n const updated = await scopedDb.update(schema.codexSubscriptionCredentials).set({\n credentialEncrypted: input.credentialEncrypted,\n expiresAt: input.expiresAt,\n lastRefreshAt: input.lastRefreshAt,\n status: \"active\",\n lastError: null,\n version: sql`${schema.codexSubscriptionCredentials.version} + 1`,\n updatedAt: new Date(),\n }).where(and(\n eq(schema.codexSubscriptionCredentials.id, input.id),\n eq(schema.codexSubscriptionCredentials.version, input.version),\n )).returning({ id: schema.codexSubscriptionCredentials.id });\n return updated.length > 0;\n });\n}\n\n/**\n * Surface a permanent or transient failure on a SPECIFIC credential row.\n *\n * COMPARE-AND-SET (P1-c): the status is stamped only if the row STILL matches the\n * (id, version) the resolver loaded. This stops a refresh that began before a\n * disconnect→reconnect (or a manual account switch) from stamping `needs_relogin`\n * on the brand-new, good credential — with N accounts per workspace a\n * workspace-wide write would be flat-out wrong (it would scribble on every\n * account). Returns true iff the guarded row was updated.\n */\nexport async function setCodexCredentialStatus(\n db: Database,\n workspaceId: string,\n status: \"active\" | \"needs_relogin\" | \"error\",\n lastError: string | null,\n target: { id: string; version: number },\n): Promise<boolean> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const updated = await scopedDb.update(schema.codexSubscriptionCredentials)\n .set({ status, lastError, updatedAt: new Date() })\n .where(and(\n eq(schema.codexSubscriptionCredentials.id, target.id),\n eq(schema.codexSubscriptionCredentials.version, target.version),\n ))\n .returning({ id: schema.codexSubscriptionCredentials.id });\n return updated.length > 0;\n });\n}\n\n/**\n * Metadata-only read for API routes, repointed to the per-workspace ACTIVE\n * credential. NEVER selects credential_encrypted.\n *\n * Reads codex_rotation_settings.active_credential_id and joins the credential by\n * id (deterministic). If the pointer is NULL but credentials exist (the\n * mid-disconnect window), it falls back to the most-recently-connected row and\n * lazily repairs the pointer so the next read is deterministic. The returned\n * `credentialId` is the active row's id (null when no credential exists at all).\n */\nexport async function getCodexCredentialStatus(db: Database, workspaceId: string): Promise<{\n connected: boolean;\n credentialId: string | null;\n chatgptAccountId: string | null;\n scopes: string | null;\n planType: string | null;\n status: string;\n expiresAt: Date | null;\n lastRefreshAt: Date | null;\n lastError: string | null;\n} | null> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const cols = {\n id: schema.codexSubscriptionCredentials.id,\n chatgptAccountId: schema.codexSubscriptionCredentials.chatgptAccountId,\n scopes: schema.codexSubscriptionCredentials.scopes,\n planType: schema.codexSubscriptionCredentials.planType,\n status: schema.codexSubscriptionCredentials.status,\n expiresAt: schema.codexSubscriptionCredentials.expiresAt,\n lastRefreshAt: schema.codexSubscriptionCredentials.lastRefreshAt,\n lastError: schema.codexSubscriptionCredentials.lastError,\n } as const;\n const [settingsRow] = await scopedDb.select({ activeCredentialId: schema.codexRotationSettings.activeCredentialId })\n .from(schema.codexRotationSettings)\n .where(eq(schema.codexRotationSettings.workspaceId, workspaceId)).limit(1);\n\n let row: { id: string; chatgptAccountId: string | null; scopes: string | null; planType: string | null; status: string; expiresAt: Date | null; lastRefreshAt: Date | null; lastError: string | null } | undefined;\n if (settingsRow?.activeCredentialId) {\n [row] = await scopedDb.select(cols).from(schema.codexSubscriptionCredentials)\n .where(and(\n eq(schema.codexSubscriptionCredentials.id, settingsRow.activeCredentialId),\n eq(schema.codexSubscriptionCredentials.workspaceId, workspaceId),\n )).limit(1);\n }\n if (!row) {\n // No active pointer (or it dangles): fall back to the most-recently-connected\n // credential and lazily repair the pointer so the active account is stable.\n [row] = await scopedDb.select(cols).from(schema.codexSubscriptionCredentials)\n .where(eq(schema.codexSubscriptionCredentials.workspaceId, workspaceId))\n .orderBy(desc(schema.codexSubscriptionCredentials.createdAt)).limit(1);\n if (row && settingsRow && settingsRow.activeCredentialId !== row.id) {\n await scopedDb.update(schema.codexRotationSettings)\n .set({ activeCredentialId: row.id, updatedAt: new Date() })\n .where(eq(schema.codexRotationSettings.workspaceId, workspaceId));\n }\n }\n if (!row) {\n return null;\n }\n const { id, ...rest } = row;\n return { connected: rest.status === \"active\", credentialId: id, ...rest };\n });\n}\n\n/**\n * Single source of truth for \"this workspace has an ACTIVE ChatGPT/Codex\n * subscription connected AND the feature is enabled for this deployment.\"\n *\n * This is the SAME condition `settingsWithCodexCredential` (worker) uses to\n * decide whether to inject the synthetic codex-subscription provider, so billing\n * and provider-injection cannot drift. Metadata-only read (never the secret).\n */\nexport async function workspaceCodexSubscriptionActive(\n db: Database,\n settings: Pick<Settings, \"codexSubscriptionEnabled\">,\n workspaceId: string,\n): Promise<boolean> {\n if (!settings.codexSubscriptionEnabled) {\n return false;\n }\n // Bounded re-read. A TRANSIENT read failure (a pooled-connection blip or a\n // lost RLS GUC — now thrown loud by withRlsContext's read-back guard rather\n // than silently returning zero rows) must never permanently decide a\n // genuinely-active subscription is disconnected, which would throw the\n // fail-loud CodexSubscriptionUnavailableError at model resolution and fail the\n // turn. Retry only on a THROWN error (the transient signature); a cleanly\n // returned status — a row (any status) or a confirmed absent row (null) — is\n // authoritative and resolves immediately, so the common no-subscription turn\n // pays no extra latency.\n let lastError: unknown;\n for (let attempt = 0; attempt < CODEX_ACTIVE_READ_ATTEMPTS; attempt++) {\n try {\n const status = await getCodexCredentialStatus(db, workspaceId);\n return status?.status === \"active\";\n } catch (error) {\n lastError = error;\n if (attempt < CODEX_ACTIVE_READ_ATTEMPTS - 1) {\n await new Promise((resolve) => setTimeout(resolve, CODEX_ACTIVE_READ_RETRY_MS * (attempt + 1)));\n }\n }\n }\n // Every attempt threw: this is a real, persistent read outage, not a one-off\n // blip. Surface the underlying error (truthful + retryable) instead of\n // silently denying an active subscription.\n console.error(\n `workspaceCodexSubscriptionActive: credential read failed for workspace ${workspaceId} after ${CODEX_ACTIVE_READ_ATTEMPTS} attempts`,\n lastError,\n );\n throw lastError instanceof Error ? lastError : new Error(String(lastError));\n}\n\n// Bounded re-read tuning for the codex active-credential check. A handful of\n// attempts with a short linear backoff rides out a transient pooler/RLS blip\n// without materially delaying a genuine outage's failure.\nconst CODEX_ACTIVE_READ_ATTEMPTS = 3;\nconst CODEX_ACTIVE_READ_RETRY_MS = 50;\n\n/**\n * CANONICAL \"is this a Codex-billed turn?\" predicate.\n *\n * True iff: the turn's model is a `codex/<slug>` id (`isCodexBilledModel`) AND\n * the deployment flag is on AND the workspace has an ACTIVE credential. A true\n * result means the turn is paid by the USER's ChatGPT/Codex plan and MUST consume\n * ZERO OpenGeni credits: callers skip the credit-balance / model-cost / token\n * gates and skip OpenGeni pricing + credit debit.\n *\n * The prefix ALONE never returns true: an unconnected user typing `codex/...`\n * gets the normal gates (and the worker fails the turn for a missing credential),\n * so there is no free/uncapped-run bypass.\n */\nexport async function isCodexBilledTurn(input: {\n db: Database;\n settings: Pick<Settings, \"codexSubscriptionEnabled\">;\n workspaceId: string;\n model: string | null | undefined;\n /**\n * Precomputed `workspaceCodexSubscriptionActive` result (P2-b). When the caller\n * already resolved the active flag for provider injection, pass it here so the\n * billed-turn predicate and the routing overlay read the credential ONCE and\n * cannot disagree across a concurrent disconnect/reconnect — a drift that would\n * either wrongly debit OpenGeni credits for a ChatGPT-paid turn or the inverse.\n */\n active?: boolean;\n}): Promise<boolean> {\n if (!isCodexBilledModel(input.model)) {\n return false; // cheap; no db hit on the common path\n }\n if (input.active !== undefined) {\n return input.active;\n }\n return workspaceCodexSubscriptionActive(input.db, input.settings, input.workspaceId);\n}\n\n// ---------------------------------------------------------------------------\n// Multi-account (P1) metadata accessors. All metadata-only — NEVER decrypt.\n// ---------------------------------------------------------------------------\n\nexport type CodexAccountStatus = {\n id: string;\n chatgptAccountId: string | null;\n label: string | null;\n accountEmail: string | null;\n planType: string | null;\n status: string; // active | needs_relogin | error\n isActive: boolean;\n expiresAt: Date | null;\n lastRefreshAt: Date | null;\n lastError: string | null;\n // P2 cached usage (plaintext metadata; rides along on this metadata-only read\n // with ZERO provider calls and ZERO decrypts). null until the first refresh.\n primaryUsedPercent: number | null;\n primaryResetAt: Date | null;\n secondaryUsedPercent: number | null;\n secondaryResetAt: Date | null;\n usageCheckedAt: Date | null;\n // P3 rotation cooldown: when set and in the future, this account is cooling-down\n // (rotated-off after a usage cap) and the engine skips it. null ⇒ not cooling.\n exhaustedUntil: Date | null;\n // P4 connector-aware rotation: the ORIGINAL-dotted connector namespaces this\n // account exposes via codex_apps (github/gmail/linear/…). null ⇒ never probed\n // (the ranker treats it as unknown: never credited as covering, never excluded).\n connectorNamespaces: string[] | null;\n connectorsCheckedAt: Date | null;\n};\n\n/**\n * Metadata-only list of every connected Codex account in the workspace, for the\n * accounts UI + the worker's selection resolver. NEVER decrypts. `isActive` marks\n * the workspace active pointer. Ordered by created_at ASC (stable list order).\n */\nexport async function listCodexAccountStatuses(db: Database, workspaceId: string): Promise<CodexAccountStatus[]> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const [settingsRow] = await scopedDb.select({ activeCredentialId: schema.codexRotationSettings.activeCredentialId })\n .from(schema.codexRotationSettings)\n .where(eq(schema.codexRotationSettings.workspaceId, workspaceId)).limit(1);\n const activeId = settingsRow?.activeCredentialId ?? null;\n const rows = await scopedDb.select({\n id: schema.codexSubscriptionCredentials.id,\n chatgptAccountId: schema.codexSubscriptionCredentials.chatgptAccountId,\n label: schema.codexSubscriptionCredentials.label,\n accountEmail: schema.codexSubscriptionCredentials.accountEmail,\n planType: schema.codexSubscriptionCredentials.planType,\n status: schema.codexSubscriptionCredentials.status,\n expiresAt: schema.codexSubscriptionCredentials.expiresAt,\n lastRefreshAt: schema.codexSubscriptionCredentials.lastRefreshAt,\n lastError: schema.codexSubscriptionCredentials.lastError,\n // P2 cached usage columns — metadata-only, ride along on this read.\n primaryUsedPercent: schema.codexSubscriptionCredentials.primaryUsedPercent,\n primaryResetAt: schema.codexSubscriptionCredentials.primaryResetAt,\n secondaryUsedPercent: schema.codexSubscriptionCredentials.secondaryUsedPercent,\n secondaryResetAt: schema.codexSubscriptionCredentials.secondaryResetAt,\n usageCheckedAt: schema.codexSubscriptionCredentials.usageCheckedAt,\n exhaustedUntil: schema.codexSubscriptionCredentials.exhaustedUntil,\n // P4 connector-set cache — metadata-only, rides along on this read.\n connectorNamespaces: schema.codexSubscriptionCredentials.connectorNamespaces,\n connectorsCheckedAt: schema.codexSubscriptionCredentials.connectorsCheckedAt,\n }).from(schema.codexSubscriptionCredentials)\n .where(eq(schema.codexSubscriptionCredentials.workspaceId, workspaceId))\n .orderBy(asc(schema.codexSubscriptionCredentials.createdAt));\n return rows.map((row) => ({ ...row, isActive: row.id === activeId }));\n });\n}\n\n/** The P2 usage-cache snapshot written by the refreshing usage wrapper. */\nexport type CodexAccountUsageSnapshot = {\n primaryUsedPercent: number | null;\n primaryResetAt: Date | null;\n secondaryUsedPercent: number | null;\n secondaryResetAt: Date | null;\n checkedAt: Date;\n};\n\n/**\n * Cache-write for P2 quota bars: persist the five plaintext usage columns on a\n * SPECIFIC credential row. NEVER touches credential_encrypted. RLS-scoped, guarded\n * by (id, workspace_id) so it can only write a row the workspace owns. Returns true\n * iff a row was updated (false ⇒ the credential was disconnected under us — the\n * snapshot is moot, drop it). This is the only writer of the usage_checked_at TTL\n * clock that `listCodexAccountStatuses` reads back.\n */\nexport async function recordCodexAccountUsage(\n db: Database,\n workspaceId: string,\n credentialId: string,\n snapshot: CodexAccountUsageSnapshot,\n): Promise<boolean> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const updated = await scopedDb.update(schema.codexSubscriptionCredentials)\n .set({\n primaryUsedPercent: snapshot.primaryUsedPercent,\n primaryResetAt: snapshot.primaryResetAt,\n secondaryUsedPercent: snapshot.secondaryUsedPercent,\n secondaryResetAt: snapshot.secondaryResetAt,\n usageCheckedAt: snapshot.checkedAt,\n // NB: no `version` bump and no `updatedAt` touch — usage is non-credential\n // metadata and must NOT race the (id, version) refresh CAS in\n // recordCodexTokenRefresh / setCodexCredentialStatus.\n })\n .where(and(\n eq(schema.codexSubscriptionCredentials.id, credentialId),\n eq(schema.codexSubscriptionCredentials.workspaceId, workspaceId),\n ))\n .returning({ id: schema.codexSubscriptionCredentials.id });\n return updated.length > 0;\n });\n}\n\nexport type CodexRotationSettings = {\n activeCredentialId: string | null;\n rotationEnabled: boolean; // P1: always false\n rotationStrategy: string; // P1: 'most_remaining' (unused)\n};\n\n/** The per-workspace rotation/active-pointer row (null when none exists yet). */\nexport async function getCodexRotationSettings(db: Database, workspaceId: string): Promise<CodexRotationSettings | null> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const [row] = await scopedDb.select({\n activeCredentialId: schema.codexRotationSettings.activeCredentialId,\n rotationEnabled: schema.codexRotationSettings.rotationEnabled,\n rotationStrategy: schema.codexRotationSettings.rotationStrategy,\n }).from(schema.codexRotationSettings)\n .where(eq(schema.codexRotationSettings.workspaceId, workspaceId)).limit(1);\n return row ?? null;\n });\n}\n\n/** Idempotently ensure the per-workspace rotation-settings row exists. */\nexport async function ensureCodexRotationSettings(db: Database, accountId: string, workspaceId: string): Promise<void> {\n await withRlsContext(db, { accountId, workspaceId }, async (scopedDb) => {\n await scopedDb.insert(schema.codexRotationSettings)\n .values({ accountId, workspaceId })\n .onConflictDoNothing({ target: [schema.codexRotationSettings.workspaceId] });\n });\n}\n\n/**\n * THE manual-switch primitive (workspace scope). Validates the credential id\n * belongs to the workspace, then one-cell UPDATEs active_credential_id. Returns\n * false if the id is unknown (so the route can 404).\n */\nexport async function setActiveCodexCredential(db: Database, workspaceId: string, credentialId: string): Promise<boolean> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const [cred] = await scopedDb.select({ id: schema.codexSubscriptionCredentials.id })\n .from(schema.codexSubscriptionCredentials)\n .where(and(\n eq(schema.codexSubscriptionCredentials.id, credentialId),\n eq(schema.codexSubscriptionCredentials.workspaceId, workspaceId),\n )).limit(1);\n if (!cred) {\n return false;\n }\n const updated = await scopedDb.update(schema.codexRotationSettings)\n .set({ activeCredentialId: credentialId, updatedAt: new Date() })\n .where(eq(schema.codexRotationSettings.workspaceId, workspaceId))\n .returning({ id: schema.codexRotationSettings.id });\n return updated.length > 0;\n });\n}\n\n/**\n * P3 rotation cooldown writer: stamp `exhausted_until` on a SPECIFIC credential row so the\n * rotation engine treats it as cooling-down (capped) until `until`. Pass `until = null` to\n * clear the cooldown. Modeled EXACTLY on recordCodexAccountUsage: RLS-scoped, guarded by\n * (id, workspace_id), and — critically — NO `version` bump and NO `updatedAt` touch, so it can\n * never race the (id, version) token-refresh CAS in recordCodexTokenRefresh / setCodexCredentialStatus.\n * Returns true iff a row was updated (false ⇒ the credential was disconnected under us).\n */\nexport async function setCodexCredentialExhausted(\n db: Database,\n workspaceId: string,\n credentialId: string,\n until: Date | null,\n): Promise<boolean> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const updated = await scopedDb.update(schema.codexSubscriptionCredentials)\n .set({ exhaustedUntil: until })\n .where(and(\n eq(schema.codexSubscriptionCredentials.id, credentialId),\n eq(schema.codexSubscriptionCredentials.workspaceId, workspaceId),\n ))\n .returning({ id: schema.codexSubscriptionCredentials.id });\n return updated.length > 0;\n });\n}\n\n/**\n * P3 reactive-rotation boundedness (Finding 1b): the number of CONSECUTIVE rotated\n * 429-failover turns since the session last had a SUCCESSFUL turn. Counts\n * `turn.failed` events carrying the `rotated` marker that occurred AFTER the most\n * recent `turn.completed` event (the natural reset anchor — any successful turn\n * moves the anchor past every prior failover, so the streak resets to 0). The\n * reactive 429 catch consults this to bound its otherwise-0-delay re-dispatch:\n * once the streak exceeds ~(connected accounts + margin) the path degrades to a\n * fixed positive idle instead of another hot re-dispatch (invariant 4: NO THRASH),\n * covering the double-fault where a cooldown write did not persist AND the 429\n * carried no usage headers. Derived from persisted events so it is correct across\n * the Temporal re-dispatch (each failover is a NEW turn, but its event survives).\n */\nexport async function countConsecutiveReactiveRotations(\n db: Database,\n workspaceId: string,\n sessionId: string,\n): Promise<number> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const [lastOk] = await scopedDb.select({ sequence: schema.sessionEvents.sequence })\n .from(schema.sessionEvents)\n .where(and(\n eq(schema.sessionEvents.workspaceId, workspaceId),\n eq(schema.sessionEvents.sessionId, sessionId),\n eq(schema.sessionEvents.type, \"turn.completed\"),\n ))\n .orderBy(desc(schema.sessionEvents.sequence))\n .limit(1);\n const conditions = [\n eq(schema.sessionEvents.workspaceId, workspaceId),\n eq(schema.sessionEvents.sessionId, sessionId),\n eq(schema.sessionEvents.type, \"turn.failed\"),\n sql`${schema.sessionEvents.payload} ->> 'rotated' = 'true'`,\n ];\n if (lastOk) {\n conditions.push(sql`${schema.sessionEvents.sequence} > ${lastOk.sequence}`);\n }\n const [{ rotated } = { rotated: 0 }] = await scopedDb.select({\n rotated: sql<number>`count(*)::int`,\n }).from(schema.sessionEvents).where(and(...conditions));\n return Number(rotated);\n });\n}\n\n/**\n * P4 connector-set cache writer: persist the set of ORIGINAL-dotted connector\n * namespaces a SPECIFIC credential exposes via codex_apps (+ the freshness clock).\n * Modeled byte-for-byte on recordCodexAccountUsage / setCodexCredentialExhausted:\n * RLS-scoped, guarded by (id, workspace_id), and — critically — NO `version` bump and\n * NO `updatedAt` touch, so it can never race the (id, version) token-refresh CAS.\n *\n * The CALLER must only invoke this with a NON-EMPTY set: codex_apps connects\n * best-effort (a transient failure yields an empty tools/list), and overwriting a\n * known non-empty set with [] would falsely \"drop\" coverage on a flaky turn. A\n * genuinely connector-less account stays null (the ranker treats null as unknown).\n * Returns true iff a row was updated (false ⇒ the credential was disconnected under us).\n */\nexport async function recordCodexAccountConnectors(\n db: Database,\n workspaceId: string,\n credentialId: string,\n namespaces: string[],\n): Promise<boolean> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const updated = await scopedDb.update(schema.codexSubscriptionCredentials)\n .set({\n connectorNamespaces: namespaces,\n connectorsCheckedAt: new Date(),\n // NB: no `version` bump and no `updatedAt` touch — connector set is non-credential\n // metadata and must NOT race the (id, version) refresh CAS (same discipline as\n // recordCodexAccountUsage / setCodexCredentialExhausted).\n })\n .where(and(\n eq(schema.codexSubscriptionCredentials.id, credentialId),\n eq(schema.codexSubscriptionCredentials.workspaceId, workspaceId),\n ))\n .returning({ id: schema.codexSubscriptionCredentials.id });\n return updated.length > 0;\n });\n}\n\n/** The supported rotation strategies (P3). */\nexport const CODEX_ROTATION_STRATEGIES = [\"most_remaining\", \"round_robin\", \"drain_then_next\"] as const;\nexport type CodexRotationStrategy = (typeof CODEX_ROTATION_STRATEGIES)[number];\n\n/**\n * P3 rotation-settings write path: one-cell UPDATE of `rotation_enabled` and/or\n * `rotation_strategy` on the per-workspace row. Validates the strategy enum (rejects unknown).\n * Guarded by workspaceId; ensureCodexRotationSettings guarantees the row exists. Returns the\n * effective settings after the patch (null when no row exists yet — caller should ensure first).\n */\nexport async function updateCodexRotationSettings(\n db: Database,\n workspaceId: string,\n patch: { rotationEnabled?: boolean; rotationStrategy?: CodexRotationStrategy },\n): Promise<CodexRotationSettings | null> {\n if (patch.rotationStrategy !== undefined && !CODEX_ROTATION_STRATEGIES.includes(patch.rotationStrategy)) {\n throw new Error(`invalid codex rotation strategy: ${patch.rotationStrategy}`);\n }\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const set: Record<string, unknown> = { updatedAt: new Date() };\n if (patch.rotationEnabled !== undefined) {\n set.rotationEnabled = patch.rotationEnabled;\n }\n if (patch.rotationStrategy !== undefined) {\n set.rotationStrategy = patch.rotationStrategy;\n }\n const [row] = await scopedDb.update(schema.codexRotationSettings)\n .set(set)\n .where(eq(schema.codexRotationSettings.workspaceId, workspaceId))\n .returning({\n activeCredentialId: schema.codexRotationSettings.activeCredentialId,\n rotationEnabled: schema.codexRotationSettings.rotationEnabled,\n rotationStrategy: schema.codexRotationSettings.rotationStrategy,\n });\n return row ?? null;\n });\n}\n\n/** P1 rename (label only); P3 widens to rotation fields. */\nexport async function renameCodexAccount(db: Database, workspaceId: string, credentialId: string, label: string | null): Promise<boolean> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const updated = await scopedDb.update(schema.codexSubscriptionCredentials)\n .set({ label, updatedAt: new Date() })\n .where(and(\n eq(schema.codexSubscriptionCredentials.id, credentialId),\n eq(schema.codexSubscriptionCredentials.workspaceId, workspaceId),\n ))\n .returning({ id: schema.codexSubscriptionCredentials.id });\n return updated.length > 0;\n });\n}\n\nexport type SessionCodexState = {\n pinnedCredentialId: string | null;\n lastCredentialId: string | null;\n};\n\n/** The session's pin + last-ran-on Codex account (drives the worker resolver + indicator). */\nexport async function getSessionCodexState(db: Database, workspaceId: string, sessionId: string): Promise<SessionCodexState | null> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const [row] = await scopedDb.select({\n pinnedCredentialId: schema.sessions.codexPinnedCredentialId,\n lastCredentialId: schema.sessions.codexLastCredentialId,\n }).from(schema.sessions)\n .where(and(eq(schema.sessions.workspaceId, workspaceId), eq(schema.sessions.id, sessionId))).limit(1);\n return row ?? null;\n });\n}\n\n/**\n * Per-session pin (manual override). pinnedCredentialId === null clears the pin\n * (follow the workspace active). Validates the id belongs to the workspace when\n * non-null. Returns false if the session is unknown or the id is invalid.\n */\nexport async function setSessionCodexPin(\n db: Database, workspaceId: string, sessionId: string, pinnedCredentialId: string | null,\n): Promise<boolean> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n if (pinnedCredentialId !== null) {\n const [cred] = await scopedDb.select({ id: schema.codexSubscriptionCredentials.id })\n .from(schema.codexSubscriptionCredentials)\n .where(and(\n eq(schema.codexSubscriptionCredentials.id, pinnedCredentialId),\n eq(schema.codexSubscriptionCredentials.workspaceId, workspaceId),\n )).limit(1);\n if (!cred) {\n return false;\n }\n }\n const updated = await scopedDb.update(schema.sessions)\n .set({ codexPinnedCredentialId: pinnedCredentialId, updatedAt: new Date() })\n .where(and(eq(schema.sessions.workspaceId, workspaceId), eq(schema.sessions.id, sessionId)))\n .returning({ id: schema.sessions.id });\n return updated.length > 0;\n });\n}\n\n/** Written by the worker at the turn boundary; drives the in-session indicator. */\nexport async function recordSessionActiveCodexCredential(\n db: Database, workspaceId: string, sessionId: string, credentialId: string,\n): Promise<void> {\n await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n await scopedDb.update(schema.sessions)\n .set({ codexLastCredentialId: credentialId, updatedAt: new Date() })\n .where(and(eq(schema.sessions.workspaceId, workspaceId), eq(schema.sessions.id, sessionId)));\n });\n}\n\n/**\n * Disconnect ONE account. DELETE WHERE id = credentialId AND workspace_id. If it\n * was the active pointer, the FK ON DELETE SET NULL clears it; this fn then\n * re-picks the most-recently-connected remaining account as active, atomically in\n * the same RLS txn. Returns whether a row was removed + the new active id.\n */\nexport async function disconnectCodexAccount(\n db: Database, workspaceId: string, credentialId: string,\n): Promise<{ removed: boolean; newActiveCredentialId: string | null }> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const removedRows = await scopedDb.delete(schema.codexSubscriptionCredentials)\n .where(and(\n eq(schema.codexSubscriptionCredentials.id, credentialId),\n eq(schema.codexSubscriptionCredentials.workspaceId, workspaceId),\n ))\n .returning({ id: schema.codexSubscriptionCredentials.id });\n // The FK SET NULL already cleared the pointer if we deleted the active row.\n const [settingsRow] = await scopedDb.select({ activeCredentialId: schema.codexRotationSettings.activeCredentialId })\n .from(schema.codexRotationSettings)\n .where(eq(schema.codexRotationSettings.workspaceId, workspaceId)).limit(1);\n if (removedRows.length === 0) {\n return { removed: false, newActiveCredentialId: settingsRow?.activeCredentialId ?? null };\n }\n let newActive = settingsRow?.activeCredentialId ?? null;\n if (newActive === null) {\n const [next] = await scopedDb.select({ id: schema.codexSubscriptionCredentials.id })\n .from(schema.codexSubscriptionCredentials)\n .where(eq(schema.codexSubscriptionCredentials.workspaceId, workspaceId))\n .orderBy(desc(schema.codexSubscriptionCredentials.createdAt)).limit(1);\n newActive = next?.id ?? null;\n if (settingsRow) {\n await scopedDb.update(schema.codexRotationSettings)\n .set({ activeCredentialId: newActive, updatedAt: new Date() })\n .where(eq(schema.codexRotationSettings.workspaceId, workspaceId));\n }\n }\n return { removed: true, newActiveCredentialId: newActive };\n });\n}\n\n/** Legacy \"disconnect all\" (old workspace-wide behavior). Returns rows removed. */\nexport async function disconnectAllCodexAccounts(db: Database, workspaceId: string): Promise<number> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const rows = await scopedDb.delete(schema.codexSubscriptionCredentials)\n .where(eq(schema.codexSubscriptionCredentials.workspaceId, workspaceId))\n .returning({ id: schema.codexSubscriptionCredentials.id });\n return rows.length;\n });\n}\n\nexport async function recordAuditEvent(db: Database, input: {\n accountId: string;\n workspaceId?: string | null;\n subjectId?: string | null;\n action: string;\n targetType?: string | null;\n targetId?: string | null;\n metadata?: Record<string, unknown>;\n}): Promise<void> {\n // audit_events has a FORCED RLS policy keyed on the account/workspace GUCs,\n // so the insert must run inside an RLS context.\n await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId ?? null }, async (scopedDb) => {\n await scopedDb.insert(schema.auditEvents).values({\n accountId: input.accountId,\n workspaceId: input.workspaceId ?? null,\n subjectId: input.subjectId ?? null,\n action: input.action,\n targetType: input.targetType ?? null,\n targetId: input.targetId ?? null,\n metadata: input.metadata ?? {},\n });\n });\n}\n\nasync function listEnvironmentVariableMetadata(db: Database, workspaceId: string, environmentId: string): Promise<WorkspaceEnvironmentVariableMetadata[]> {\n const rows = await db.select({\n name: schema.workspaceEnvironmentVariables.name,\n version: schema.workspaceEnvironmentVariables.version,\n createdAt: schema.workspaceEnvironmentVariables.createdAt,\n updatedAt: schema.workspaceEnvironmentVariables.updatedAt,\n }).from(schema.workspaceEnvironmentVariables)\n .where(and(\n eq(schema.workspaceEnvironmentVariables.workspaceId, workspaceId),\n eq(schema.workspaceEnvironmentVariables.environmentId, environmentId),\n ))\n .orderBy(asc(schema.workspaceEnvironmentVariables.name));\n return rows.map(mapWorkspaceEnvironmentVariableMetadata);\n}\n\nfunction mapWorkspaceEnvironment(row: typeof schema.workspaceEnvironments.$inferSelect, variables: WorkspaceEnvironmentVariableMetadata[]): WorkspaceEnvironment {\n return {\n id: row.id,\n accountId: row.accountId,\n workspaceId: row.workspaceId,\n name: row.name,\n description: row.description,\n variables,\n createdAt: row.createdAt.toISOString(),\n updatedAt: row.updatedAt.toISOString(),\n };\n}\n\nfunction mapWorkspaceEnvironmentVariableMetadata(row: {\n name: string;\n version: number;\n createdAt: Date;\n updatedAt: Date;\n}): WorkspaceEnvironmentVariableMetadata {\n return {\n name: row.name,\n version: row.version,\n createdAt: row.createdAt.toISOString(),\n updatedAt: row.updatedAt.toISOString(),\n };\n}\n\nfunction mapSessionMcpServerMetadata(row: typeof schema.sessionMcpServers.$inferSelect): SessionMcpServerMetadata {\n return {\n id: row.serverId,\n name: row.name ?? null,\n url: row.url,\n headerNames: Object.keys(row.headersEncrypted ?? {}).sort(),\n credentialVersion: Number(row.credentialVersion),\n };\n}\n\nasync function sessionMcpServerMetadataForSessions(\n db: Database,\n workspaceId: string,\n sessionIds: string[],\n): Promise<Map<string, SessionMcpServerMetadata[]>> {\n const grouped = new Map<string, SessionMcpServerMetadata[]>();\n if (sessionIds.length === 0) {\n return grouped;\n }\n const rows = await db.select().from(schema.sessionMcpServers)\n .where(and(\n eq(schema.sessionMcpServers.workspaceId, workspaceId),\n inArray(schema.sessionMcpServers.sessionId, sessionIds),\n ))\n .orderBy(asc(schema.sessionMcpServers.createdAt), asc(schema.sessionMcpServers.serverId));\n for (const row of rows) {\n const list = grouped.get(row.sessionId) ?? [];\n list.push(mapSessionMcpServerMetadata(row));\n grouped.set(row.sessionId, list);\n }\n return grouped;\n}\n\nasync function insertSessionMcpServers(db: Database, input: {\n accountId: string;\n workspaceId: string;\n sessionId: string;\n servers: CreateSessionMcpServerInput[];\n}): Promise<SessionMcpServerMetadata[]> {\n if (input.servers.length === 0) {\n return [];\n }\n const rows = await db.insert(schema.sessionMcpServers).values(input.servers.map((server) => ({\n accountId: input.accountId,\n workspaceId: input.workspaceId,\n sessionId: input.sessionId,\n serverId: server.id,\n name: server.name ?? null,\n url: server.url,\n allowedTools: server.allowedTools ?? null,\n timeoutMs: server.timeoutMs ?? null,\n cacheToolsList: server.cacheToolsList ?? false,\n headersEncrypted: server.headersEncrypted ?? {},\n }))).returning();\n return rows.map(mapSessionMcpServerMetadata);\n}\n\nexport async function createSessionMcpServers(db: Database, input: {\n accountId: string;\n workspaceId: string;\n sessionId: string;\n servers: CreateSessionMcpServerInput[];\n}): Promise<SessionMcpServerMetadata[]> {\n return await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId }, async (scopedDb) =>\n await insertSessionMcpServers(scopedDb, input)\n );\n}\n\nexport async function listSessionMcpServerMetadata(db: Database, workspaceId: string, sessionId: string): Promise<SessionMcpServerMetadata[]> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const grouped = await sessionMcpServerMetadataForSessions(scopedDb, workspaceId, [sessionId]);\n return grouped.get(sessionId) ?? [];\n });\n}\n\nexport async function updateSessionMcpServerCredentials(db: Database, input: {\n workspaceId: string;\n sessionId: string;\n updates: UpdateSessionMcpServerCredentialsInput[];\n}): Promise<UpdateSessionMcpServerCredentialsResult> {\n return await withWorkspaceRls(db, input.workspaceId, async (scopedDb) => await scopedDb.transaction(async (tx) =>\n await updateSessionMcpServerCredentialsInTransaction(tx, input)\n ));\n}\n\nasync function updateSessionMcpServerCredentialsInTransaction(\n tx: Pick<Database, \"update\">,\n input: {\n workspaceId: string;\n sessionId: string;\n updates: UpdateSessionMcpServerCredentialsInput[];\n },\n): Promise<UpdateSessionMcpServerCredentialsResult> {\n const servers: SessionMcpServerMetadata[] = [];\n const missingIds: string[] = [];\n for (const update of input.updates) {\n const [row] = await tx.update(schema.sessionMcpServers)\n .set({\n headersEncrypted: update.headersEncrypted,\n credentialVersion: sql`${schema.sessionMcpServers.credentialVersion} + 1`,\n updatedAt: new Date(),\n })\n .where(and(\n eq(schema.sessionMcpServers.workspaceId, input.workspaceId),\n eq(schema.sessionMcpServers.sessionId, input.sessionId),\n eq(schema.sessionMcpServers.serverId, update.id),\n ))\n .returning();\n if (!row) {\n missingIds.push(update.id);\n } else {\n servers.push(mapSessionMcpServerMetadata(row));\n }\n }\n return { servers, missingIds };\n}\n\nexport async function listSessionMcpServersForRun(\n db: Database,\n workspaceId: string,\n sessionId: string,\n encryptionKey: Uint8Array,\n): Promise<SessionMcpServerForRun[]> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const rows = await scopedDb.select().from(schema.sessionMcpServers)\n .where(and(\n eq(schema.sessionMcpServers.workspaceId, workspaceId),\n eq(schema.sessionMcpServers.sessionId, sessionId),\n ))\n .orderBy(asc(schema.sessionMcpServers.createdAt), asc(schema.sessionMcpServers.serverId));\n return rows.map((row) => {\n let headers: Record<string, string>;\n try {\n headers = Object.fromEntries(Object.entries(row.headersEncrypted ?? {})\n .map(([name, stored]) => [name, decryptEnvironmentValue(encryptionKey, stored)]));\n } catch {\n throw new Error(\"session MCP server credential decryption failed\");\n }\n return {\n ...mapSessionMcpServerMetadata(row),\n ...(row.allowedTools ? { allowedTools: row.allowedTools } : {}),\n ...(row.timeoutMs ? { timeoutMs: row.timeoutMs } : {}),\n ...(row.cacheToolsList ? { cacheToolsList: row.cacheToolsList } : {}),\n headers,\n };\n });\n });\n}\n\nexport async function createSession(db: Database, input: {\n accountId: string;\n workspaceId: string;\n initialMessage: string;\n resources: ResourceRef[];\n tools?: ToolRef[];\n metadata: Record<string, unknown>;\n model: string;\n sandboxBackend: SandboxBackend;\n environmentId?: string | null;\n firstPartyMcpPermissions?: Permission[] | null;\n parentSessionId?: string | null;\n createIdempotencyKey?: string | null;\n // The shared-sandbox group to join. Omit (or null) for a singleton group:\n // the new row's own id is used (group === session), today's 1:1 behavior. A\n // shared spawn passes the parent's sandboxGroupId so both run in ONE box.\n sandboxGroupId?: string | null;\n sandboxOs?: SandboxOs;\n mcpServers?: CreateSessionMcpServerInput[];\n}): Promise<Session> {\n // Generate the id up front so the same uuid can seed sandbox_group_id for a\n // singleton group (sandbox_group_id cannot SQL-default to id).\n const id = crypto.randomUUID();\n return await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId }, async (scopedDb) => {\n const [row] = await scopedDb.insert(schema.sessions).values({\n id,\n accountId: input.accountId,\n workspaceId: input.workspaceId,\n initialMessage: input.initialMessage,\n resources: input.resources,\n tools: input.tools ?? [],\n metadata: input.metadata,\n model: input.model,\n sandboxBackend: input.sandboxBackend,\n sandboxOs: input.sandboxOs ?? \"linux\",\n sandboxGroupId: input.sandboxGroupId ?? id,\n environmentId: input.environmentId ?? null,\n firstPartyMcpPermissions: input.firstPartyMcpPermissions ?? null,\n parentSessionId: input.parentSessionId ?? null,\n createIdempotencyKey: input.createIdempotencyKey ?? null,\n status: \"queued\",\n }).returning();\n if (!row) {\n throw new Error(\"Failed to create session\");\n }\n const mcpServers = await insertSessionMcpServers(scopedDb, {\n accountId: input.accountId,\n workspaceId: input.workspaceId,\n sessionId: row.id,\n servers: input.mcpServers ?? [],\n });\n return mapSession(row, mcpServers);\n });\n}\n\n/**\n * Inserts a session under a workspace-scoped CREATE idempotency key, collapsing\n * a concurrent race on the same key to a single row. On the unique-violation\n * the conflicting insert does nothing (`onConflictDoNothing` on the partial\n * unique index) and the now-existing winning row is fetched and returned, so\n * two near-simultaneous creates with the same key yield ONE session and both\n * callers see the same id. `created` distinguishes the winner (true: this call\n * inserted and must run the rest of the start flow) from the loser/dup (false:\n * the row already existed and must be returned as-is).\n */\nexport async function createSessionWithIdempotencyKey(db: Database, input: {\n accountId: string;\n workspaceId: string;\n initialMessage: string;\n resources: ResourceRef[];\n tools?: ToolRef[];\n metadata: Record<string, unknown>;\n model: string;\n sandboxBackend: SandboxBackend;\n environmentId?: string | null;\n firstPartyMcpPermissions?: Permission[] | null;\n parentSessionId?: string | null;\n createIdempotencyKey: string;\n // The shared-sandbox group to join. Omit (or null) for a singleton group\n // (group === the new row's own id); a shared spawn passes the parent's group.\n sandboxGroupId?: string | null;\n sandboxOs?: SandboxOs;\n mcpServers?: CreateSessionMcpServerInput[];\n}): Promise<{ session: Session; created: boolean }> {\n // Generate the id up front so the same uuid can seed sandbox_group_id for a\n // singleton group (sandbox_group_id cannot SQL-default to id).\n const id = crypto.randomUUID();\n return await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId }, async (scopedDb) => {\n const [inserted] = await scopedDb.insert(schema.sessions).values({\n id,\n accountId: input.accountId,\n workspaceId: input.workspaceId,\n initialMessage: input.initialMessage,\n resources: input.resources,\n tools: input.tools ?? [],\n metadata: input.metadata,\n model: input.model,\n sandboxBackend: input.sandboxBackend,\n sandboxOs: input.sandboxOs ?? \"linux\",\n sandboxGroupId: input.sandboxGroupId ?? id,\n environmentId: input.environmentId ?? null,\n firstPartyMcpPermissions: input.firstPartyMcpPermissions ?? null,\n parentSessionId: input.parentSessionId ?? null,\n createIdempotencyKey: input.createIdempotencyKey,\n status: \"queued\",\n }).onConflictDoNothing({\n target: [schema.sessions.workspaceId, schema.sessions.createIdempotencyKey],\n where: sql`${schema.sessions.createIdempotencyKey} is not null`,\n }).returning();\n if (inserted) {\n const mcpServers = await insertSessionMcpServers(scopedDb, {\n accountId: input.accountId,\n workspaceId: input.workspaceId,\n sessionId: inserted.id,\n servers: input.mcpServers ?? [],\n });\n return { session: mapSession(inserted, mcpServers), created: true };\n }\n const [existing] = await scopedDb.select().from(schema.sessions).where(and(\n eq(schema.sessions.workspaceId, input.workspaceId),\n eq(schema.sessions.createIdempotencyKey, input.createIdempotencyKey),\n )).limit(1);\n if (!existing) {\n // No row inserted and none found: the conflict target did not actually\n // collide (should never happen for a present key) — surface it rather\n // than silently returning a phantom.\n throw new Error(\"Failed to create session under idempotency key\");\n }\n const grouped = await sessionMcpServerMetadataForSessions(scopedDb, input.workspaceId, [existing.id]);\n return { session: mapSession(existing, grouped.get(existing.id) ?? []), created: false };\n });\n}\n\nexport async function getSessionByCreateIdempotencyKey(db: Database, workspaceId: string, createIdempotencyKey: string): Promise<Session | null> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const [row] = await scopedDb.select().from(schema.sessions).where(and(\n eq(schema.sessions.workspaceId, workspaceId),\n eq(schema.sessions.createIdempotencyKey, createIdempotencyKey),\n )).limit(1);\n if (!row) return null;\n const grouped = await sessionMcpServerMetadataForSessions(scopedDb, workspaceId, [row.id]);\n return mapSession(row, grouped.get(row.id) ?? []);\n });\n}\n\nexport async function getSession(db: Database, workspaceId: string, sessionId: string): Promise<Session | null> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const [row] = await scopedDb.select().from(schema.sessions).where(and(eq(schema.sessions.workspaceId, workspaceId), eq(schema.sessions.id, sessionId))).limit(1);\n if (!row) return null;\n const grouped = await sessionMcpServerMetadataForSessions(scopedDb, workspaceId, [row.id]);\n return mapSession(row, grouped.get(row.id) ?? []);\n });\n}\n\n/**\n * Resolve ANY session that belongs to a shared-sandbox group (addendum 05 §D.3,\n * stress (e)). Used by the create-session `sandbox:{groupId}` join path to (1)\n * prove the group exists and (2) inherit its box's (backend, os).\n *\n * `workspaceId` is a MANDATORY access boundary, NOT optional: the group uuid is\n * caller-supplied, so the workspace filter (inside RLS) is what forbids a\n * cross-workspace join — a foreign group returns null → the caller 404s. The\n * group uuid itself is never an authorization boundary. Returns the first member\n * session (any one suffices to read the shared box's backend/os); null when the\n * group has no session in this workspace.\n */\nexport async function getAnySessionInGroup(db: Database, workspaceId: string, sandboxGroupId: string): Promise<Session | null> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const [row] = await scopedDb.select().from(schema.sessions)\n .where(and(eq(schema.sessions.workspaceId, workspaceId), eq(schema.sessions.sandboxGroupId, sandboxGroupId)))\n .limit(1);\n return row ? mapSession(row) : null;\n });\n}\n\n/**\n * The DISTINCT environmentIds across a group's member sessions (workspace-\n * scoped; null = no environment attached). The env-aware create check compares\n * a joiner against EVERY member — an arbitrary single member (getAnySessionInGroup)\n * makes the compatibility verdict nondeterministic for legacy env-blind groups\n * whose members carry mixed environmentIds.\n */\nexport async function listDistinctEnvironmentIdsInGroup(db: Database, workspaceId: string, sandboxGroupId: string): Promise<Array<string | null>> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const rows = await scopedDb.selectDistinct({ environmentId: schema.sessions.environmentId }).from(schema.sessions)\n .where(and(eq(schema.sessions.workspaceId, workspaceId), eq(schema.sessions.sandboxGroupId, sandboxGroupId)));\n return rows.map((r) => r.environmentId ?? null);\n });\n}\n\nexport async function listSessions(db: Database, workspaceId: string, limit = 50): Promise<Session[]> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const rows = await scopedDb.select().from(schema.sessions)\n .where(eq(schema.sessions.workspaceId, workspaceId))\n .orderBy(desc(schema.sessions.createdAt), desc(schema.sessions.id))\n .limit(limit);\n const grouped = await sessionMcpServerMetadataForSessions(scopedDb, workspaceId, rows.map((row) => row.id));\n return rows.map((row) => mapSession(row, grouped.get(row.id) ?? []));\n });\n}\n\n/**\n * Count sessions still attached to a live Temporal workflow: queued, running,\n * or awaiting an approval (requires_action). idle has no running execution and\n * failed/cancelled are terminal, so neither blocks a workspace delete. The\n * delete path uses this to refuse (409) while a session could still be running\n * in Temporal, since there is no clean session-terminate to call first.\n */\nexport async function countActiveSessionsForWorkspace(db: Database, workspaceId: string): Promise<number> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const [{ count } = { count: 0 }] = await scopedDb.select({\n count: sql<number>`count(*)::int`,\n }).from(schema.sessions)\n .where(and(\n eq(schema.sessions.workspaceId, workspaceId),\n inArray(schema.sessions.status, [\"queued\", \"running\", \"requires_action\"]),\n ));\n return Number(count);\n });\n}\n\nexport async function requireSession(db: Database, workspaceId: string, sessionId: string): Promise<Session> {\n const session = await getSession(db, workspaceId, sessionId);\n if (!session) {\n throw new Error(`Session not found: ${sessionId}`);\n }\n return session;\n}\n\nexport type ListSessionEventsOptions = {\n after?: number;\n before?: number;\n limit?: number;\n};\n\nconst POSTGRES_INT_MAX = 2_147_483_647;\n\nexport async function listSessionEvents(db: Database, workspaceId: string, sessionId: string): Promise<SessionEvent[]>;\nexport async function listSessionEvents(db: Database, workspaceId: string, sessionId: string, after: number, limit?: number): Promise<SessionEvent[]>;\nexport async function listSessionEvents(db: Database, workspaceId: string, sessionId: string, options: ListSessionEventsOptions): Promise<SessionEvent[]>;\nexport async function listSessionEvents(\n db: Database,\n workspaceId: string,\n sessionId: string,\n afterOrOptions: number | ListSessionEventsOptions = 0,\n legacyLimit = 500,\n): Promise<SessionEvent[]> {\n const options = typeof afterOrOptions === \"number\"\n ? { after: afterOrOptions, limit: legacyLimit }\n : afterOrOptions;\n const after = normalizeEventSequence(options.after, 0);\n const limit = normalizeEventLimit(options.limit, 500);\n const hasBefore = options.before !== undefined && Number.isFinite(options.before);\n const before = hasBefore ? Math.floor(options.before as number) : undefined;\n\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const filters: SQL[] = [\n eq(schema.sessionEvents.workspaceId, workspaceId),\n eq(schema.sessionEvents.sessionId, sessionId),\n gt(schema.sessionEvents.sequence, after),\n ];\n if (before !== undefined && before <= POSTGRES_INT_MAX) {\n filters.push(lt(schema.sessionEvents.sequence, before));\n }\n const rows = await scopedDb.select().from(schema.sessionEvents)\n .where(and(...filters))\n .orderBy(hasBefore ? desc(schema.sessionEvents.sequence) : asc(schema.sessionEvents.sequence))\n .limit(limit);\n return (hasBefore ? rows.reverse() : rows).map(mapEvent);\n });\n}\n\nfunction normalizeEventSequence(value: number | undefined, fallback: number): number {\n if (value === undefined || !Number.isFinite(value)) {\n return fallback;\n }\n return Math.floor(value);\n}\n\nfunction normalizeEventLimit(value: number | undefined, fallback: number): number {\n if (value === undefined || !Number.isFinite(value)) {\n return fallback;\n }\n return Math.max(0, Math.floor(value));\n}\n\nexport async function getSessionEvent(db: Database, workspaceId: string, eventId: string): Promise<SessionEvent | null> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const [row] = await scopedDb.select().from(schema.sessionEvents).where(and(eq(schema.sessionEvents.workspaceId, workspaceId), eq(schema.sessionEvents.id, eventId))).limit(1);\n return row ? mapEvent(row) : null;\n });\n}\n\nexport async function getLatestRunState(db: Database, workspaceId: string, sessionId: string): Promise<{\n id: string;\n serializedRunState: string;\n pendingApprovals: unknown[];\n // The codex account that froze this state (pin > workspace-active), or null\n // when frozen on the non-codex path / before the column existed. The replay\n // path compares it to the resuming turn's codex account to decide whether the\n // blob's account-bound reasoning must be neutralized before being replayed.\n frozenCodexCredentialId: string | null;\n} | null> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const [row] = await scopedDb.select().from(schema.agentRunStates)\n .where(and(eq(schema.agentRunStates.workspaceId, workspaceId), eq(schema.agentRunStates.sessionId, sessionId)))\n .orderBy(desc(schema.agentRunStates.createdAt))\n .limit(1);\n return row ? {\n id: row.id,\n serializedRunState: row.serializedRunState,\n pendingApprovals: row.pendingApprovals,\n frozenCodexCredentialId: row.frozenCodexCredentialId ?? null,\n } : null;\n });\n}\n\n/**\n * Append conversation items (verbatim SDK AgentInputItems) to the session's\n * history. Idempotent on (workspace, session, position): concurrent or\n * repeated writers (streaming writes + turn-end reconciliation) converge\n * instead of duplicating.\n */\nexport async function appendSessionHistoryItems(db: Database, input: {\n accountId: string;\n workspaceId: string;\n sessionId: string;\n turnId?: string | null;\n // The codex account that produced these items (the turn's resolved credential\n // id), or null/undefined on the non-codex path. Stored verbatim so the read\n // path can strip cross-account reasoning.encrypted_content blobs per turn.\n producerCodexCredentialId?: string | null;\n items: Array<{ position: number; item: Record<string, unknown> }>;\n}): Promise<void> {\n if (input.items.length === 0) {\n return;\n }\n await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId }, async (scopedDb) => {\n await scopedDb.insert(schema.sessionHistoryItems).values(input.items.map((entry) => ({\n accountId: input.accountId,\n workspaceId: input.workspaceId,\n sessionId: input.sessionId,\n turnId: input.turnId ?? null,\n producerCodexCredentialId: input.producerCodexCredentialId ?? null,\n position: entry.position,\n item: sanitizeEventPayload(entry.item),\n }))).onConflictDoNothing({\n target: [schema.sessionHistoryItems.workspaceId, schema.sessionHistoryItems.sessionId, schema.sessionHistoryItems.position],\n });\n });\n}\n\nexport async function getSessionHistoryItems(db: Database, workspaceId: string, sessionId: string): Promise<Array<{ position: number; item: Record<string, unknown> }>> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const rows = await scopedDb.select({\n position: schema.sessionHistoryItems.position,\n item: schema.sessionHistoryItems.item,\n }).from(schema.sessionHistoryItems)\n .where(and(eq(schema.sessionHistoryItems.workspaceId, workspaceId), eq(schema.sessionHistoryItems.sessionId, sessionId)))\n .orderBy(schema.sessionHistoryItems.position);\n return rows;\n });\n}\n\n/**\n * The LIVE conversation-truth read path: only active rows, position-ordered.\n * After a client-side context compaction this returns [retained user messages,\n * active summary]; with no compaction yet it equals\n * getSessionHistoryItems. The model-facing read path uses this so superseded\n * (summarized-away) prefix rows are excluded while the full transcript stays in\n * the table as an audit trail.\n */\nexport async function getActiveSessionHistoryItems(db: Database, workspaceId: string, sessionId: string): Promise<Array<{ position: number; item: Record<string, unknown>; producerCodexCredentialId: string | null }>> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const rows = await scopedDb.select({\n position: schema.sessionHistoryItems.position,\n item: schema.sessionHistoryItems.item,\n producerCodexCredentialId: schema.sessionHistoryItems.producerCodexCredentialId,\n }).from(schema.sessionHistoryItems)\n .where(and(\n eq(schema.sessionHistoryItems.workspaceId, workspaceId),\n eq(schema.sessionHistoryItems.sessionId, sessionId),\n eq(schema.sessionHistoryItems.active, true),\n ))\n .orderBy(schema.sessionHistoryItems.position);\n return rows;\n });\n}\n\n/**\n * Count of ACTIVE (live, model-facing) history rows for a session. This is the\n * length of the history the next turn is seeded from — the dual-write slice\n * index — which after a compaction is far smaller than the total persisted-row\n * count (countSessionHistoryItems still includes the superseded prefix).\n */\nexport async function countActiveSessionHistoryItems(db: Database, workspaceId: string, sessionId: string): Promise<number> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const [row] = await scopedDb.select({\n count: sql<number>`count(*)`,\n }).from(schema.sessionHistoryItems)\n .where(and(\n eq(schema.sessionHistoryItems.workspaceId, workspaceId),\n eq(schema.sessionHistoryItems.sessionId, sessionId),\n eq(schema.sessionHistoryItems.active, true),\n ));\n return Number(row?.count ?? 0);\n });\n}\n\n/**\n * Result-item types and the CALL type that settles each. Kept byte-for-byte in\n * sync with the runtime sanitizer's RESULT_TYPE_BY_CALL_TYPE and the repair\n * migration (0014). The repair, the read-path sanitizer, and this spec all share\n * one definition of a tool-call pair.\n */\nconst REPAIR_CALL_TYPE_BY_RESULT_TYPE: Record<string, string> = {\n function_call_result: \"function_call\",\n computer_call_result: \"computer_call\",\n shell_call_output: \"shell_call\",\n apply_patch_call_output: \"apply_patch_call\",\n};\n\nfunction repairCallIdOf(item: unknown): string | undefined {\n if (!item || typeof item !== \"object\") {\n return undefined;\n }\n const record = item as { callId?: unknown; call_id?: unknown };\n if (typeof record.callId === \"string\") {\n return record.callId;\n }\n if (typeof record.call_id === \"string\") {\n return record.call_id;\n }\n return undefined;\n}\n\nfunction repairItemType(item: unknown): string | undefined {\n if (!item || typeof item !== \"object\") {\n return undefined;\n }\n const type = (item as { type?: unknown }).type;\n return typeof type === \"string\" ? type : undefined;\n}\n\n/**\n * Pure TypeScript SPEC for the one-time orphan repair (migration 0014),\n * mirroring its SQL WHERE clause so the deletion rule is unit-testable without a\n * database. Given the ACTIVE history rows of a single session in position order,\n * returns the indices of the orphaned tool-call RESULT rows the repair deletes.\n *\n * An orphan is a result-type row (function_call_result / computer_call_result /\n * shell_call_output / apply_patch_call_output) with no matching CALL of the\n * paired type, same correlation id (camelCase `callId` OR snake_case `call_id`),\n * at a STRICTLY EARLIER position in the same session. This is exactly the\n * session-bricking row the Responses API 400s on (\"No tool call found for\n * function call output\").\n *\n * DANGLING CALLS (a call with no result yet) are intentionally NOT returned: a\n * call awaiting a not-yet-settled result is valid, not corruption. Only unpaired\n * results are removed.\n *\n * EXISTENCE, not consumption: like the migration's `NOT EXISTS (... earlier\n * call ...)`, a result is kept whenever ANY earlier matching call exists. A\n * second result that re-uses a call_id already settled earlier is therefore NOT\n * flagged here (a matching call still exists before it) — this conservative\n * choice matches the SQL exactly and never deletes a row whose call is present;\n * the read-path sanitizer (which consumes calls one-for-one) still drops such a\n * rare duplicate in-memory, so the model request stays valid regardless.\n *\n * Callers pass rows already ordered by position. The earlier-position test is\n * by array order (the SQL orders by the numeric position column, which the read\n * path also orders by), so identical inputs yield identical decisions.\n */\nexport function orphanedResultRowIndicesForRepair(\n activeRowsInPositionOrder: ReadonlyArray<{ item: Record<string, unknown> }>,\n): number[] {\n // call_ids of CALLs seen so far, per matching result type. A result is an\n // orphan unless a call of its paired type with the same id appeared earlier.\n const seenCallIdsByResultType = new Map<string, Set<string>>();\n // Pre-index every call type to the result type(s) it can settle.\n const resultTypeByCallType: Record<string, string> = {};\n for (const [resultType, callType] of Object.entries(REPAIR_CALL_TYPE_BY_RESULT_TYPE)) {\n resultTypeByCallType[callType] = resultType;\n }\n const orphanIndices: number[] = [];\n activeRowsInPositionOrder.forEach((row, index) => {\n const type = repairItemType(row.item);\n const callId = repairCallIdOf(row.item);\n if (!type || !callId) {\n return;\n }\n const settlesResultType = resultTypeByCallType[type];\n if (settlesResultType) {\n // This row is a CALL: record its id so a later matching result is paired.\n const seen = seenCallIdsByResultType.get(settlesResultType) ?? new Set<string>();\n seen.add(callId);\n seenCallIdsByResultType.set(settlesResultType, seen);\n return;\n }\n if (REPAIR_CALL_TYPE_BY_RESULT_TYPE[type]) {\n // This row is a RESULT: orphan unless an earlier matching call was seen.\n const seen = seenCallIdsByResultType.get(type);\n if (!seen || !seen.has(callId)) {\n orphanIndices.push(index);\n }\n }\n });\n return orphanIndices;\n}\n\n/**\n * Apply a client-side context compaction as an atomic, audit-preserving write:\n *\n * - supersede (set active=false) every active row whose position lies in\n * [0, boundaryPosition) — i.e. the summarized prefix — EXCLUDING the tail.\n * Rows are never deleted.\n * - insert ONE active synthetic summary row at `summaryPosition` (a FRACTIONAL\n * position — boundaryPosition - 0.5 — that sorts immediately before the kept\n * tail and collides with NO existing row, so no real prefix row is ever\n * overwritten). Idempotent on position: a retry that finds the summary row\n * already there does not duplicate it (it only re-activates the existing\n * summary row at that fractional position) and — crucially — never mutates\n * the real row at boundaryPosition - 1.\n *\n * The caller computes the boundary from the orphan-safe planner so no tool-call\n * pair straddles the cut. `summaryPosition` must be < boundaryPosition (between\n * the last superseded prefix row and the kept tail), guaranteeing it sorts\n * before the tail. Because positions are whole numbers and summaries are\n * half-steps, the summary's fractional position can never equal a real row.\n */\nexport async function applyContextCompaction(db: Database, input: {\n accountId: string;\n workspaceId: string;\n sessionId: string;\n turnId?: string | null;\n /** Active prefix rows with position < boundaryPosition get superseded. */\n boundaryPosition: number;\n /** Position for the new summary row. Old boundary mode uses a fractional half-step before the kept tail. */\n summaryPosition: number;\n /**\n * Optional replacement rows inserted after superseding the old active set.\n * Used by Codex-parity client compaction to rebuild active history as retained\n * user messages plus one summary. These rows are synthetic replay rows, so\n * they intentionally do not inherit the current compaction turn id.\n */\n replacementItems?: Array<{ position: number; item: Record<string, unknown> }>;\n summaryItem: Record<string, unknown>;\n}): Promise<void> {\n await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId }, async (scopedDb) => {\n await scopedDb.transaction(async (tx) => {\n await tx.update(schema.sessionHistoryItems)\n .set({ active: false })\n .where(and(\n eq(schema.sessionHistoryItems.workspaceId, input.workspaceId),\n eq(schema.sessionHistoryItems.sessionId, input.sessionId),\n eq(schema.sessionHistoryItems.active, true),\n lt(schema.sessionHistoryItems.position, input.boundaryPosition),\n ));\n if (input.replacementItems && input.replacementItems.length > 0) {\n await tx.insert(schema.sessionHistoryItems).values(input.replacementItems.map((entry) => ({\n accountId: input.accountId,\n workspaceId: input.workspaceId,\n sessionId: input.sessionId,\n turnId: null,\n position: entry.position,\n item: sanitizeEventPayload(entry.item),\n active: true,\n }))).onConflictDoUpdate({\n target: [schema.sessionHistoryItems.workspaceId, schema.sessionHistoryItems.sessionId, schema.sessionHistoryItems.position],\n set: { active: true },\n });\n }\n // Insert the summary at its FRACTIONAL position. The supersede step above\n // also sets active=false for any rows with position < boundaryPosition —\n // which on a RETRY includes the summary itself (it sits below the\n // boundary). The conflict target here is that fractional position, which\n // can ONLY ever collide with a prior summary row (real rows are whole\n // numbers), so onConflictDoUpdate set:{active:true} is safe: it merely\n // re-activates the existing summary, keeping the retry idempotent WITHOUT\n // mutating its item/turnId and — crucially — WITHOUT ever touching the\n // real row at boundaryPosition - 1 (the old integer placement overwrote\n // it). The summary carries the current turnId so per-turn counts stay\n // correct.\n await tx.insert(schema.sessionHistoryItems).values({\n accountId: input.accountId,\n workspaceId: input.workspaceId,\n sessionId: input.sessionId,\n turnId: input.turnId ?? null,\n position: input.summaryPosition,\n item: sanitizeEventPayload(input.summaryItem),\n active: true,\n }).onConflictDoUpdate({\n target: [schema.sessionHistoryItems.workspaceId, schema.sessionHistoryItems.sessionId, schema.sessionHistoryItems.position],\n set: { active: true },\n });\n });\n });\n}\n\n/**\n * The next free WHOLE-NUMBER history position for a session: one past the\n * largest existing position (active or superseded), floored so the synthetic\n * summary's fractional half-step never shifts the count. The dual-write\n * watermark uses this to append new rows at fresh absolute positions, decoupled\n * from the in-memory history length (which, after a compaction, is far shorter\n * than the total persisted-row count and so cannot serve as the next position).\n */\nexport async function nextSessionHistoryPosition(db: Database, workspaceId: string, sessionId: string): Promise<number> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const [row] = await scopedDb.select({\n maxPosition: sql<number | null>`max(${schema.sessionHistoryItems.position})`,\n }).from(schema.sessionHistoryItems)\n .where(and(eq(schema.sessionHistoryItems.workspaceId, workspaceId), eq(schema.sessionHistoryItems.sessionId, sessionId)));\n const max = row?.maxPosition;\n return max === null || max === undefined ? 0 : Math.floor(Number(max)) + 1;\n });\n}\n\n/**\n * Record the actual input-token count of the most recent turn's final model\n * call, for the next turn's pre-read compaction trigger.\n */\nexport async function setSessionLastInputTokens(db: Database, workspaceId: string, sessionId: string, lastInputTokens: number): Promise<void> {\n await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n await scopedDb.update(schema.sessions)\n .set({ lastInputTokens, updatedAt: new Date() })\n .where(and(eq(schema.sessions.workspaceId, workspaceId), eq(schema.sessions.id, sessionId)));\n });\n}\n\n/**\n * The neutral marker written by clearSessionContext as the sole active history\n * row. It keeps getActiveSessionHistoryItems().length > 0 so the items read\n * path (run-input.ts messageInput) stays selected and never falls through to\n * the getLatestRunState blob — that fallback is the resurrection vector a clear\n * must defeat. A plain user message is a valid, sanitizer-clean item.\n */\nexport function clearedContextMarkerItem(): Record<string, unknown> {\n return { type: \"message\", role: \"user\", content: \"[context cleared]\" };\n}\n\n/**\n * The sentinel serializedRunState written by clearSessionContext, re-exported\n * from @opengeni/contracts so the writer (here) and the readers (run-input /\n * runtime) share one definition. It is audit-honest (carries no prior\n * conversation) and is NOT a real Agents-SDK run state — it has no\n * `$schemaVersion`/history, so `RunState.fromString` throws on it.\n *\n * Both run-state read paths therefore guard against it explicitly via\n * {@link isClearedRunStateBlob}:\n * - the message path (run-input messageInput) honors it in BOTH items and\n * run_state history modes — in items mode the boundary marker keeps the\n * active read non-empty so the blob is never reached, and in run_state mode\n * the sentinel is recognized and treated as a fresh empty start;\n * - the approval path is additionally refused by the API for mid-turn /\n * requires_action sessions, so it never sees the sentinel.\n * Stored so getLatestRunState (the run_state-source read path) reflects the\n * clear instead of resurrecting the pre-clear blob.\n */\nexport const CLEARED_RUN_STATE = CLEARED_RUN_STATE_BLOB;\n\nexport type ClearSessionContextResult = {\n /** Active history rows superseded (active=true -> false). */\n supersededItems: number;\n /** Position of the inserted neutral boundary marker. */\n markerPosition: number;\n /** stateVersion of the fresh cleared run-state row. */\n runStateVersion: number;\n};\n\n/**\n * Clear a session's conversation context in ONE transaction, audit-preserving\n * and idempotent. Defeats the RunState-fallback resurrection on BOTH model read\n * paths:\n *\n * (a) supersede every active session_history_items row (active=true -> false).\n * Nothing is deleted — the full transcript stays as an audit trail, same\n * pattern as applyContextCompaction.\n * (b) insert ONE active neutral boundary marker at max(position)+1 so the\n * active read path returns length 1 (not 0) and run-input.ts stays on the\n * items route, away from the getLatestRunState blob (the bug).\n * (c) insert a fresh agent_run_states row (stateVersion = max+1) with an empty\n * cleared blob and pendingApprovals:[], so getLatestRunState (approval /\n * run_state-source read path) also reflects the clear.\n *\n * Also resets last_input_tokens to 0 so the next turn's compaction trigger\n * starts fresh against the now-short context.\n *\n * Idempotent: a re-run supersedes the (now sole, already-marker) active row,\n * inserts another marker at the next position, and another cleared run-state.\n * The post-conditions (one active marker row, latest run-state cleared) hold.\n */\nexport async function clearSessionContext(db: Database, input: {\n accountId: string;\n workspaceId: string;\n sessionId: string;\n}): Promise<ClearSessionContextResult> {\n return await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId }, async (scopedDb) => {\n return await scopedDb.transaction(async (tx) => {\n const supersededRows = await tx.update(schema.sessionHistoryItems)\n .set({ active: false })\n .where(and(\n eq(schema.sessionHistoryItems.workspaceId, input.workspaceId),\n eq(schema.sessionHistoryItems.sessionId, input.sessionId),\n eq(schema.sessionHistoryItems.active, true),\n ))\n .returning({ id: schema.sessionHistoryItems.id });\n\n const [{ maxPosition } = { maxPosition: -1 }] = await tx.select({\n maxPosition: sql<number>`coalesce(max(${schema.sessionHistoryItems.position}), -1)`,\n }).from(schema.sessionHistoryItems)\n .where(and(\n eq(schema.sessionHistoryItems.workspaceId, input.workspaceId),\n eq(schema.sessionHistoryItems.sessionId, input.sessionId),\n ));\n const markerPosition = Number(maxPosition) + 1;\n await tx.insert(schema.sessionHistoryItems).values({\n accountId: input.accountId,\n workspaceId: input.workspaceId,\n sessionId: input.sessionId,\n turnId: null,\n position: markerPosition,\n item: sanitizeEventPayload(clearedContextMarkerItem()),\n active: true,\n }).onConflictDoNothing({\n target: [schema.sessionHistoryItems.workspaceId, schema.sessionHistoryItems.sessionId, schema.sessionHistoryItems.position],\n });\n\n const [{ maxVersion } = { maxVersion: 0 }] = await tx.select({\n maxVersion: sql<number>`coalesce(max(${schema.agentRunStates.stateVersion}), 0)`,\n }).from(schema.agentRunStates)\n .where(and(\n eq(schema.agentRunStates.workspaceId, input.workspaceId),\n eq(schema.agentRunStates.sessionId, input.sessionId),\n ));\n const runStateVersion = Number(maxVersion) + 1;\n await tx.insert(schema.agentRunStates).values({\n accountId: input.accountId,\n workspaceId: input.workspaceId,\n sessionId: input.sessionId,\n turnId: null,\n stateVersion: runStateVersion,\n serializedRunState: CLEARED_RUN_STATE,\n pendingApprovals: [],\n });\n\n await tx.update(schema.sessions)\n .set({ lastInputTokens: 0, updatedAt: new Date() })\n .where(and(eq(schema.sessions.workspaceId, input.workspaceId), eq(schema.sessions.id, input.sessionId)));\n\n return { supersededItems: supersededRows.length, markerPosition, runStateVersion };\n });\n });\n}\n\nexport async function countSessionHistoryItems(db: Database, workspaceId: string, sessionId: string): Promise<number> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const [row] = await scopedDb.select({\n count: sql<number>`count(*)`,\n }).from(schema.sessionHistoryItems)\n .where(and(eq(schema.sessionHistoryItems.workspaceId, workspaceId), eq(schema.sessionHistoryItems.sessionId, sessionId)));\n return Number(row?.count ?? 0);\n });\n}\n\n/**\n * Set the operator /compact request flag. The worker honors it before the next\n * turn (forced client-side compaction) and clears it. Idempotent: repeated\n * requests collapse to one pending compaction.\n */\nexport async function requestSessionCompaction(db: Database, workspaceId: string, sessionId: string): Promise<void> {\n await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n await scopedDb.update(schema.sessions)\n .set({ compactRequested: true, updatedAt: new Date() })\n .where(and(eq(schema.sessions.workspaceId, workspaceId), eq(schema.sessions.id, sessionId)));\n });\n}\n\n/**\n * Atomically consume the /compact request flag: clear it and report whether it\n * was set. The worker calls this pre-turn; only the call that observed `true`\n * runs the forced compaction, so concurrent turns can't double-compact.\n */\nexport async function consumeSessionCompactionRequest(db: Database, workspaceId: string, sessionId: string): Promise<boolean> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const cleared = await scopedDb.update(schema.sessions)\n .set({ compactRequested: false, updatedAt: new Date() })\n .where(and(\n eq(schema.sessions.workspaceId, workspaceId),\n eq(schema.sessions.id, sessionId),\n eq(schema.sessions.compactRequested, true),\n ))\n .returning({ id: schema.sessions.id });\n return cleared.length > 0;\n });\n}\n\n/**\n * Number of conversation-truth items a specific turn persisted. The\n * worker-death requeue path uses this to decide whether the re-dispatched\n * turn must enter through a resume notice (its partial progress is already\n * part of conversation truth, so replaying the original trigger would hand\n * the model duplicate input) or can replay its original trigger cleanly.\n */\nexport async function countTurnSessionHistoryItems(db: Database, workspaceId: string, turnId: string): Promise<number> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const [row] = await scopedDb.select({\n count: sql<number>`count(*)`,\n }).from(schema.sessionHistoryItems)\n .where(and(eq(schema.sessionHistoryItems.workspaceId, workspaceId), eq(schema.sessionHistoryItems.turnId, turnId)));\n return Number(row?.count ?? 0);\n });\n}\n\n/**\n * Persist the session's sandbox recovery descriptor (the small versioned\n * envelope used to reattach / snapshot-restore / rebuild the sandbox),\n * decoupled from the RunState blob.\n */\nexport async function upsertSandboxSessionEnvelope(db: Database, input: {\n accountId: string;\n workspaceId: string;\n sessionId: string;\n envelope: Record<string, unknown>;\n}): Promise<void> {\n await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId }, async (scopedDb) => {\n await scopedDb.insert(schema.sandboxSessionEnvelopes).values({\n accountId: input.accountId,\n workspaceId: input.workspaceId,\n sessionId: input.sessionId,\n envelope: input.envelope,\n }).onConflictDoUpdate({\n target: [schema.sandboxSessionEnvelopes.workspaceId, schema.sandboxSessionEnvelopes.sessionId],\n set: { envelope: input.envelope, updatedAt: new Date() },\n });\n });\n}\n\nexport async function getSandboxSessionEnvelope(db: Database, workspaceId: string, sessionId: string): Promise<Record<string, unknown> | null> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const [row] = await scopedDb.select({ envelope: schema.sandboxSessionEnvelopes.envelope })\n .from(schema.sandboxSessionEnvelopes)\n .where(and(eq(schema.sandboxSessionEnvelopes.workspaceId, workspaceId), eq(schema.sandboxSessionEnvelopes.sessionId, sessionId)))\n .limit(1);\n return row?.envelope ?? null;\n });\n}\n\n// ============================================================================\n// Session recordings — the durable index for the \"agent films itself proving\n// the fix\" loop (P4.3). One row per recording; insert at start, update at\n// finalize (available with the storage_key) or failure. Read-side feeds the\n// list route + the signed-URL replay route (storage_key is the source of truth).\n// ============================================================================\n\nexport type SessionRecordingState = (typeof schema.sessionRecordingStateValues)[number];\nexport type SessionRecordingMode = (typeof schema.sessionRecordingModeValues)[number];\nexport type SessionRecordingCodec = (typeof schema.sessionRecordingCodecValues)[number];\n\nexport type SessionRecordingRow = {\n id: string;\n workspaceId: string;\n sessionId: string;\n turnId: string | null;\n state: SessionRecordingState;\n mode: SessionRecordingMode;\n codec: SessionRecordingCodec;\n storageKey: string | null;\n sizeBytes: number | null;\n durationSeconds: number | null;\n width: number;\n height: number;\n reason: string | null;\n createdAt: Date;\n finalizedAt: Date | null;\n};\n\nfunction mapRecording(row: typeof schema.sessionRecordings.$inferSelect): SessionRecordingRow {\n return {\n id: row.id,\n workspaceId: row.workspaceId,\n sessionId: row.sessionId,\n turnId: row.turnId,\n state: row.state,\n mode: row.mode,\n codec: row.codec,\n storageKey: row.storageKey,\n sizeBytes: row.sizeBytes === null || row.sizeBytes === undefined ? null : Number(row.sizeBytes),\n durationSeconds: row.durationSeconds === null || row.durationSeconds === undefined ? null : Number(row.durationSeconds),\n width: row.width,\n height: row.height,\n reason: row.reason,\n createdAt: row.createdAt,\n finalizedAt: row.finalizedAt,\n };\n}\n\nexport async function insertRecording(db: Database, input: {\n id: string;\n accountId: string;\n workspaceId: string;\n sessionId: string;\n turnId?: string | null;\n mode: SessionRecordingMode;\n codec: SessionRecordingCodec;\n width: number;\n height: number;\n reason?: string | null;\n}): Promise<SessionRecordingRow> {\n return await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId }, async (scopedDb) => {\n const [row] = await scopedDb.insert(schema.sessionRecordings).values({\n id: input.id,\n accountId: input.accountId,\n workspaceId: input.workspaceId,\n sessionId: input.sessionId,\n turnId: input.turnId ?? null,\n state: \"recording\",\n mode: input.mode,\n codec: input.codec,\n width: input.width,\n height: input.height,\n reason: input.reason ?? null,\n }).returning();\n return mapRecording(row!);\n });\n}\n\nexport async function updateRecording(db: Database, input: {\n accountId: string;\n workspaceId: string;\n recordingId: string;\n state: SessionRecordingState;\n storageKey?: string | null;\n sizeBytes?: number | null;\n durationSeconds?: number | null;\n reason?: string | null;\n finalized?: boolean;\n}): Promise<SessionRecordingRow | null> {\n return await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId }, async (scopedDb) => {\n const set: Partial<typeof schema.sessionRecordings.$inferInsert> = { state: input.state };\n if (input.storageKey !== undefined) set.storageKey = input.storageKey;\n if (input.sizeBytes !== undefined) set.sizeBytes = input.sizeBytes;\n if (input.durationSeconds !== undefined) set.durationSeconds = input.durationSeconds;\n if (input.reason !== undefined) set.reason = input.reason;\n if (input.finalized || input.state === \"available\" || input.state === \"failed\") {\n set.finalizedAt = new Date();\n }\n const [row] = await scopedDb.update(schema.sessionRecordings)\n .set(set)\n .where(and(\n eq(schema.sessionRecordings.workspaceId, input.workspaceId),\n eq(schema.sessionRecordings.id, input.recordingId),\n ))\n .returning();\n return row ? mapRecording(row) : null;\n });\n}\n\n/**\n * Hard-delete a recording row. Used to DISCARD an on-turn recording that captured\n * NO computer-use activity (a plain text turn): the row was inserted at\n * `beginRecording` (state \"recording\") but the turn never drove the desktop, so it\n * is removed entirely rather than surfaced as a phantom recording or a failure. No\n * other table FK-references session_recordings, so the delete is self-contained.\n */\nexport async function deleteRecording(db: Database, input: {\n accountId: string;\n workspaceId: string;\n recordingId: string;\n}): Promise<void> {\n await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId }, async (scopedDb) => {\n await scopedDb.delete(schema.sessionRecordings)\n .where(and(\n eq(schema.sessionRecordings.workspaceId, input.workspaceId),\n eq(schema.sessionRecordings.id, input.recordingId),\n ));\n });\n}\n\nexport async function getRecording(db: Database, workspaceId: string, recordingId: string): Promise<SessionRecordingRow | null> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const [row] = await scopedDb.select().from(schema.sessionRecordings)\n .where(and(\n eq(schema.sessionRecordings.workspaceId, workspaceId),\n eq(schema.sessionRecordings.id, recordingId),\n ))\n .limit(1);\n return row ? mapRecording(row) : null;\n });\n}\n\nexport async function listRecordings(db: Database, workspaceId: string, sessionId: string): Promise<SessionRecordingRow[]> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const rows = await scopedDb.select().from(schema.sessionRecordings)\n .where(and(\n eq(schema.sessionRecordings.workspaceId, workspaceId),\n eq(schema.sessionRecordings.sessionId, sessionId),\n ))\n .orderBy(desc(schema.sessionRecordings.createdAt));\n return rows.map(mapRecording);\n });\n}\n\n// ============================================================================\n// Channel-A interactive PTY sessions (P4.4) — the ptyId <-> exec-session-id map.\n// The ONLY new persistent state Channel A needs; FS/Git reads persist nothing.\n// ============================================================================\n\nexport type SandboxPtySessionRow = {\n id: string;\n accountId: string;\n workspaceId: string;\n sessionId: string;\n execSessionId: number | null;\n leaseEpoch: number;\n cols: number;\n rows: number;\n shell: string;\n cwd: string;\n status: \"open\" | \"closed\";\n openedBy: string;\n lastInputAt: string;\n createdAt: string;\n closedAt: string | null;\n};\n\nfunction mapPtySession(row: typeof schema.sandboxPtySessions.$inferSelect): SandboxPtySessionRow {\n return {\n id: row.id,\n accountId: row.accountId,\n workspaceId: row.workspaceId,\n sessionId: row.sessionId,\n execSessionId: row.execSessionId ?? null,\n leaseEpoch: row.leaseEpoch,\n cols: row.cols,\n rows: row.rows,\n shell: row.shell,\n cwd: row.cwd,\n status: row.status as \"open\" | \"closed\",\n openedBy: row.openedBy,\n lastInputAt: row.lastInputAt.toISOString(),\n createdAt: row.createdAt.toISOString(),\n closedAt: row.closedAt ? row.closedAt.toISOString() : null,\n };\n}\n\nexport async function insertPtySession(db: Database, input: {\n id: string;\n accountId: string;\n workspaceId: string;\n sessionId: string;\n execSessionId?: number | null;\n leaseEpoch: number;\n cols: number;\n rows: number;\n shell: string;\n cwd: string;\n openedBy: string;\n}): Promise<SandboxPtySessionRow> {\n return await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId }, async (scopedDb) => {\n const [row] = await scopedDb.insert(schema.sandboxPtySessions).values({\n id: input.id,\n accountId: input.accountId,\n workspaceId: input.workspaceId,\n sessionId: input.sessionId,\n execSessionId: input.execSessionId ?? null,\n leaseEpoch: input.leaseEpoch,\n cols: input.cols,\n rows: input.rows,\n shell: input.shell,\n cwd: input.cwd,\n status: \"open\",\n openedBy: input.openedBy,\n }).returning();\n return mapPtySession(row!);\n });\n}\n\n/** Read an OPEN PTY row by ptyId. Returns null when absent or already closed. */\nexport async function getOpenPtySession(db: Database, workspaceId: string, ptyId: string): Promise<SandboxPtySessionRow | null> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const [row] = await scopedDb.select().from(schema.sandboxPtySessions)\n .where(and(\n eq(schema.sandboxPtySessions.workspaceId, workspaceId),\n eq(schema.sandboxPtySessions.id, ptyId),\n eq(schema.sandboxPtySessions.status, \"open\"),\n ))\n .limit(1);\n return row ? mapPtySession(row) : null;\n });\n}\n\n/** Stamp the SDK exec-session id (known only after the open exec yields a still-\n * running process) + refresh the input-activity TTL. */\nexport async function updatePtySessionActivity(db: Database, input: {\n accountId: string;\n workspaceId: string;\n ptyId: string;\n execSessionId?: number | null;\n cols?: number;\n rows?: number;\n}): Promise<SandboxPtySessionRow | null> {\n return await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId }, async (scopedDb) => {\n const set: Partial<typeof schema.sandboxPtySessions.$inferInsert> = { lastInputAt: new Date() };\n if (input.execSessionId !== undefined) set.execSessionId = input.execSessionId;\n if (input.cols !== undefined) set.cols = input.cols;\n if (input.rows !== undefined) set.rows = input.rows;\n const [row] = await scopedDb.update(schema.sandboxPtySessions)\n .set(set)\n .where(and(\n eq(schema.sandboxPtySessions.workspaceId, input.workspaceId),\n eq(schema.sandboxPtySessions.id, input.ptyId),\n eq(schema.sandboxPtySessions.status, \"open\"),\n ))\n .returning();\n return row ? mapPtySession(row) : null;\n });\n}\n\n/** Mark a PTY closed (idempotent — a double close on a closed row is a no-op). */\nexport async function closePtySession(db: Database, input: {\n accountId: string;\n workspaceId: string;\n ptyId: string;\n}): Promise<SandboxPtySessionRow | null> {\n return await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId }, async (scopedDb) => {\n const [row] = await scopedDb.update(schema.sandboxPtySessions)\n .set({ status: \"closed\", closedAt: new Date() })\n .where(and(\n eq(schema.sandboxPtySessions.workspaceId, input.workspaceId),\n eq(schema.sandboxPtySessions.id, input.ptyId),\n ))\n .returning();\n return row ? mapPtySession(row) : null;\n });\n}\n\n/** List a session's OPEN PTYs (reattach + reap). */\nexport async function listOpenPtySessions(db: Database, workspaceId: string, sessionId: string): Promise<SandboxPtySessionRow[]> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const rows = await scopedDb.select().from(schema.sandboxPtySessions)\n .where(and(\n eq(schema.sandboxPtySessions.workspaceId, workspaceId),\n eq(schema.sandboxPtySessions.sessionId, sessionId),\n eq(schema.sandboxPtySessions.status, \"open\"),\n ))\n .orderBy(desc(schema.sandboxPtySessions.createdAt));\n return rows.map(mapPtySession);\n });\n}\n\n// ============================================================================\n// Sandbox singleton lease — the SOLE enforcer of one-box-per-group (P1.1).\n//\n// Group-keyed (workspace_id, sandbox_group_id) from the start. The sole\n// double-spawn guard is the UNIQUE (workspace_id, sandbox_group_id) index +\n// plain SELECT … FOR UPDATE (block, NOT skip-locked) + the cold->warming CAS\n// inside that row lock. lease_epoch is integer (returns a JS number) but every\n// read is Number()-coerced defensively. Mirrors the claimNextQueuedTurn\n// withWorkspaceRls/withRlsContext -> scopedDb.transaction -> tx.execute(sql<T>``)\n// pattern (the row type goes on the sql tag, not on .execute).\n// ============================================================================\n\nexport type SandboxLeaseLiveness = \"cold\" | \"warming\" | \"warm\" | \"draining\";\nexport type LeaseHolderKind = \"turn\" | \"viewer\";\n\n// The snake_case raw shape returned by the raw sql`` lease queries. lease_epoch\n// comes back as a number for an integer column, but we type it number|string\n// and Number()-coerce so the same code is correct regardless of column type.\n// Typed with an index signature so it satisfies db.execute<TRow extends\n// Record<string, unknown>>.\ntype LeaseRow = {\n id: string;\n account_id: string;\n workspace_id: string;\n sandbox_group_id: string;\n liveness: SandboxLeaseLiveness;\n refcount: number;\n turn_holders: number;\n viewer_holders: number;\n instance_id: string | null;\n backend: string;\n os: string;\n image: string | null;\n data_plane_url: string | null;\n terminal_data_plane_url: string | null;\n lease_epoch: number | string;\n resume_backend_id: string | null;\n resume_state: Record<string, unknown> | null;\n last_meter_at: Date | string | null;\n last_meter_tick: number;\n expires_at: Date | string;\n} & Record<string, unknown>;\n\nexport interface LeaseSnapshot {\n id: string;\n sandboxGroupId: string;\n liveness: SandboxLeaseLiveness;\n refcount: number;\n turnHolders: number;\n viewerHolders: number;\n instanceId: string | null;\n backend: string;\n os: string;\n // The container image the group box runs (Modal image ref / docker image). Null\n // for a legacy/cold row (image unknown). Shared state: all the box's sessions run\n // this image; a resume resolving a different image conflicts (B3).\n image: string | null;\n dataPlaneUrl: string | null;\n // The cached ttyd pty-ws tunnel URL (7681), separate from dataPlaneUrl (the\n // 6080 desktop tunnel). Null until mintTerminalStream resolves + records it.\n terminalDataPlaneUrl: string | null;\n leaseEpoch: number;\n resumeBackendId: string | null;\n resumeState: Record<string, unknown> | null;\n expiresAt: Date;\n}\n\nexport interface AcquireLeaseInput {\n accountId: string;\n workspaceId: string;\n // The group's identity (sessions.sandbox_group_id; == session id for a\n // singleton group). The lease is per-group, not per-session.\n sandboxGroupId: string;\n kind: LeaseHolderKind;\n holderId: string; // session_turns.id (turn) | viewer connection id (viewer)\n subjectId?: string | null; // the attributing session within the group\n backend: string; // sessions.sandbox_backend\n os?: string; // default 'linux'\n // The container image this run resolves (Modal image ref / docker image). Stamped on\n // the cold-create + folded onto a warming/CAS; a warm/draining/warming box already\n // running a DIFFERENT image is a shared-state conflict (B3): a SOLO holder forces the\n // box to recreate on this image, N-holders throw SandboxImageConflictError. Omitted\n // (null/undefined) -> image is not enforced (legacy/cold rows, selfhosted).\n image?: string | null;\n leaseTtlMs: number; // refresh window for expires_at (turn-heartbeat cadence)\n // Optional epoch fence for a re-establishing turn holder: when set, the\n // turn-arrival increment is gated on lease_epoch == expectedEpoch (split-brain).\n expectedEpoch?: number;\n}\n\nexport type AcquireLeaseResult =\n // Caller WON the cold->warming CAS: it is the spawner (any pool worker). Must\n // resume-by-id from resume_state, expose the stream port, then call\n // commitWarmingToWarm. No owner process is started.\n | { role: \"spawner\"; lease: LeaseSnapshot }\n // Box live or being built by someone else: attach (and, for warming, wait).\n | { role: \"attached\"; lease: LeaseSnapshot }\n // Re-armed a draining lease back to warm (box never torn down).\n | { role: \"rearmed\"; lease: LeaseSnapshot }\n // Epoch fence rejected the turn-arrival increment: a newer epoch exists (a\n // later turn re-established the box). Caller must back off and re-read; NEVER\n // create().\n | { role: \"fenced\"; lease: LeaseSnapshot };\n\n// Thrown by callers that treat a fenced/superseded epoch as an error path.\nexport class SandboxLeaseSupersededError extends Error {\n constructor(public readonly sandboxGroupId: string, public readonly leaseEpoch: number) {\n super(`Sandbox lease superseded for group ${sandboxGroupId} (epoch ${leaseEpoch})`);\n this.name = \"SandboxLeaseSupersededError\";\n }\n}\n\n// IMAGE IS SHARED STATE (B3): thrown when a resume resolves an image DIFFERENT from\n// the one the live shared box was created with AND other holders are still on the box.\n// A shared box is ONE filesystem; recreating it on a new image would yank the running\n// filesystem out from under the OTHER sessions, so we refuse. The turn activity surfaces\n// this as an actionable error: spawn with sandbox:'new' or align the pack image. A SOLO\n// holder never hits this — acquireLease recreates the box on the new image instead.\nexport class SandboxImageConflictError extends Error {\n constructor(\n public readonly sandboxGroupId: string,\n public readonly currentImage: string,\n public readonly requestedImage: string,\n ) {\n super(\n `Sandbox group ${sandboxGroupId} runs image ${currentImage}; this run resolves image ${requestedImage}. `\n + `A shared box requires one image — spawn with sandbox:'new' for an isolated box or align the pack image.`,\n );\n this.name = \"SandboxImageConflictError\";\n }\n}\n\nfunction mapLeaseRow(row: LeaseRow): LeaseSnapshot {\n return {\n id: row.id,\n sandboxGroupId: row.sandbox_group_id,\n liveness: row.liveness,\n refcount: Number(row.refcount),\n turnHolders: Number(row.turn_holders),\n viewerHolders: Number(row.viewer_holders),\n instanceId: row.instance_id,\n backend: row.backend,\n os: row.os,\n image: row.image ?? null,\n dataPlaneUrl: row.data_plane_url,\n terminalDataPlaneUrl: row.terminal_data_plane_url ?? null,\n // Defensive coercion: integer returns a number, but coerce regardless so the\n // fence comparison stays exact even if the column type ever drifts to int8.\n leaseEpoch: Number(row.lease_epoch),\n resumeBackendId: row.resume_backend_id,\n resumeState: row.resume_state,\n expiresAt: row.expires_at instanceof Date ? row.expires_at : new Date(row.expires_at),\n };\n}\n\n// Recompute refcount/split-counts from the holder rows (holders are the source\n// of truth), refresh expires_at, optionally set liveness. Returns the updated row.\nasync function recomputeAndStampLease(\n tx: Database,\n leaseId: string,\n leaseTtlMs: number,\n setLiveness: SandboxLeaseLiveness | null,\n): Promise<LeaseRow> {\n const counts = await tx.execute<{ total: number; turns: number; viewers: number }>(sql`\n select count(*)::int as total,\n count(*) filter (where kind = 'turn')::int as turns,\n count(*) filter (where kind = 'viewer')::int as viewers\n from sandbox_lease_holders where lease_id = ${leaseId}\n `);\n const c = counts[0]!;\n const updated = await tx.execute<LeaseRow>(sql`\n update sandbox_leases set\n refcount = ${c.total},\n turn_holders = ${c.turns},\n viewer_holders = ${c.viewers},\n expires_at = now() + (${String(leaseTtlMs)} || ' milliseconds')::interval,\n ${setLiveness ? sql`liveness = ${setLiveness},` : sql``}\n updated_at = now()\n where id = ${leaseId}\n returning *\n `);\n return updated[0]!;\n}\n\n// Idempotent acquire: the unique (lease, kind, holder) index makes a retried or\n// duplicate acquire a no-op heartbeat refresh, never a double-count.\nasync function upsertLeaseHolder(\n tx: Database, leaseId: string, accountId: string, workspaceId: string,\n kind: LeaseHolderKind, holderId: string, subjectId: string | null,\n): Promise<void> {\n await tx.execute(sql`\n insert into sandbox_lease_holders\n (account_id, workspace_id, lease_id, kind, holder_id, subject_id, last_heartbeat_at)\n values (${accountId}, ${workspaceId}, ${leaseId}, ${kind}, ${holderId}, ${subjectId}, now())\n on conflict (lease_id, kind, holder_id)\n do update set last_heartbeat_at = now()\n `);\n}\n\n// §4.1 — the get-or-create critical section. ONE transaction:\n// insert-or-nothing -> SELECT … FOR UPDATE (block, not skip) -> branch -> bump.\n// The single most load-bearing function: the sole double-spawn guard.\nexport async function acquireLease(db: Database, input: AcquireLeaseInput): Promise<AcquireLeaseResult> {\n const { accountId, workspaceId, sandboxGroupId, kind, holderId, backend } = input;\n const os = input.os ?? \"linux\";\n const subjectId = input.subjectId ?? null;\n return await withRlsContext(db, { accountId, workspaceId }, async (scopedDb) =>\n await scopedDb.transaction(async (txRaw) => {\n const tx = txRaw as unknown as Database;\n const image = input.image ?? null;\n // (1) Materialize the singleton row if absent. ON CONFLICT DO NOTHING + the\n // unique index = idempotent under a race; concurrent inserts collapse to\n // one row. expires_at seeded so a never-warmed cold row has a valid TTL. The\n // image (B3) is stamped on the cold-create so a fresh box records the image it\n // will be built on; a conflict on an EXISTING live box is handled below.\n await tx.execute(sql`\n insert into sandbox_leases\n (account_id, workspace_id, sandbox_group_id, liveness, backend, os, image, expires_at)\n values\n (${accountId}, ${workspaceId}, ${sandboxGroupId}, 'cold', ${backend}, ${os}, ${image},\n now() + (${String(input.leaseTtlMs)} || ' milliseconds')::interval)\n on conflict (workspace_id, sandbox_group_id) do nothing\n `);\n\n // (2) Serialize ALL concurrent arrivals on this group's row. Plain FOR\n // UPDATE (block, do NOT skip) — unlike claimNextQueuedTurn's SKIP LOCKED,\n // because we WANT the loser to block then attach, not skip and lose.\n const rows = await tx.execute<LeaseRow>(sql`\n select * from sandbox_leases\n where workspace_id = ${workspaceId} and sandbox_group_id = ${sandboxGroupId}\n for update\n `);\n const row = rows[0];\n if (!row) throw new Error(`Lease row vanished post-insert: ${sandboxGroupId}`);\n\n let liveness = row.liveness;\n\n // -- IMAGE IS SHARED STATE (B3): a LIVE box (warm/draining/warming) already runs\n // a specific image. If this run resolves a DIFFERENT image (both sides known),\n // the shared filesystem cannot serve both. Under the held row lock we count the\n // OTHER holders (holders that are not this exact (kind, holderId) — an idempotent\n // retry of our own holder does not count as a rival):\n // - SOLO (no other holders): RECREATE. Reset the box to cold and re-stamp the\n // NEW image, then fall through to the cold branch below, which CASes us in as\n // the spawner. The spawner cold-creates a fresh box on the new image (the\n // archive replay in establishSandboxSessionFromEnvelope hydrates /workspace).\n // - OTHER holders present: REFUSE. Throw SandboxImageConflictError — recreating\n // would yank the running filesystem out from under the other sessions.\n // Only enforced when BOTH images are known; a cold row / a legacy null-image box /\n // an unset input image never conflicts (the selfhosted path passes no image).\n if (liveness !== \"cold\" && image !== null && row.image !== null && row.image !== image) {\n const others = await tx.execute<{ n: number }>(sql`\n select count(*)::int as n from sandbox_lease_holders\n where lease_id = ${row.id} and not (kind = ${kind} and holder_id = ${holderId})\n `);\n const otherHolders = Number(others[0]?.n ?? 0);\n if (otherHolders > 0) {\n throw new SandboxImageConflictError(sandboxGroupId, row.image, image);\n }\n // SOLO recreate: reset to cold + re-stamp the new image. Clear the live-box\n // fields so no stale instance/tunnel survives the image roll (symmetric with\n // failWarmingToCold). resume_state is nulled — a solo image change is an\n // intentional fresh box (a divergent image cannot replay the old box's live\n // state); the session envelope/archive still drives /workspace hydration on the\n // cold re-create. Fall through to the cold branch, which CASes us in as spawner.\n await tx.execute(sql`\n update sandbox_leases set\n liveness = 'cold', image = ${image}, instance_id = null,\n data_plane_url = null, terminal_data_plane_url = null,\n resume_backend_id = null, resume_state = null, updated_at = now()\n where id = ${row.id}\n `);\n liveness = \"cold\";\n }\n\n // -- draining: late arrival re-arms (D1). Box still alive (grace open).\n if (liveness === \"draining\") {\n await upsertLeaseHolder(tx, row.id, accountId, workspaceId, kind, holderId, subjectId);\n const updated = await recomputeAndStampLease(tx, row.id, input.leaseTtlMs, \"warm\");\n return { role: \"rearmed\" as const, lease: mapLeaseRow(updated) };\n }\n\n // -- cold: WIN the cold->warming CAS (C1). Exactly one winner under the\n // held row lock; concurrent arrivals serialize behind us and see warming.\n // The image (B3) is (re-)stamped on the CAS so the box the spawner cold-creates\n // records the image it runs — for a fresh cold row or a solo-recreate above.\n if (liveness === \"cold\") {\n const casRows = await tx.execute<{ id: string }>(sql`\n update sandbox_leases set\n liveness = 'warming',\n ${image !== null ? sql`image = ${image},` : sql``}\n updated_at = now()\n where id = ${row.id} and liveness = 'cold'\n returning id\n `);\n await upsertLeaseHolder(tx, row.id, accountId, workspaceId, kind, holderId, subjectId);\n const updated = await recomputeAndStampLease(tx, row.id, input.leaseTtlMs, null);\n // casRows.length === 0 cannot happen under the held row lock (defensive):\n // a lost CAS means a sibling flipped it first, so we attach.\n const role = casRows.length === 0 ? \"attached\" as const : \"spawner\" as const;\n return { role, lease: mapLeaseRow(updated) };\n }\n\n // -- warm: epoch fence for re-establishing turn holders (split-brain). A\n // turn arriving with expectedEpoch must match the live row epoch; a stale\n // re-dispatched turn is fenced out -> back off, NEVER create(). Number()-\n // coerced so an int8 drift cannot make the compare always-true.\n if (liveness === \"warm\" && kind === \"turn\" && input.expectedEpoch !== undefined\n && Number(row.lease_epoch) !== input.expectedEpoch) {\n return { role: \"fenced\" as const, lease: mapLeaseRow(row) };\n }\n\n // -- warm / warming: attach (A2 / A1). refcount++ ONLY; never touch\n // liveness. The spawner exclusively owns warming->warm.\n await upsertLeaseHolder(tx, row.id, accountId, workspaceId, kind, holderId, subjectId);\n const updated = await recomputeAndStampLease(tx, row.id, input.leaseTtlMs, null);\n return { role: \"attached\" as const, lease: mapLeaseRow(updated) };\n }),\n );\n}\n\n// §4.2 — the ONLY lease_epoch++ site. CAS on (warming AND lease_epoch=expected).\n// Folds the group box-envelope (resume_backend_id/resume_state) onto the lease.\nexport async function commitWarmingToWarm(db: Database, input: {\n accountId: string; workspaceId: string; sandboxGroupId: string;\n expectedEpoch: number; // the epoch the spawner observed at cold->warming\n instanceId: string;\n dataPlaneUrl?: string | null; // event-driven resolveExposedPort result, any worker\n resumeBackendId?: string | null;\n resumeState?: Record<string, unknown> | null;\n leaseTtlMs: number;\n}): Promise<{ committed: boolean; lease: LeaseSnapshot | null }> {\n return await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId },\n async (scopedDb) => {\n // resume_state is jsonb: the raw postgres driver does NOT auto-stringify a\n // plain object bound for a jsonb column, so serialize to a JSON string and\n // cast ::jsonb (null stays a real SQL null). Binding the object directly\n // throws \"string argument must be of type string\" on the wire.\n const resumeStateJson = input.resumeState == null ? null : JSON.stringify(input.resumeState);\n const rows = await scopedDb.execute<LeaseRow>(sql`\n update sandbox_leases set\n liveness = 'warm',\n instance_id = ${input.instanceId},\n data_plane_url = ${input.dataPlaneUrl ?? null},\n -- A box re-key (epoch++) invalidates the prior epoch's ttyd tunnel; the\n -- terminal URL is re-resolved + re-recorded lazily by mintTerminalStream\n -- on the next attach. Clear it here so a stale URL never survives a roll.\n terminal_data_plane_url = null,\n resume_backend_id = ${input.resumeBackendId ?? null},\n resume_state = ${resumeStateJson}::jsonb,\n lease_epoch = lease_epoch + 1,\n expires_at = now() + (${String(input.leaseTtlMs)} || ' milliseconds')::interval,\n updated_at = now()\n where workspace_id = ${input.workspaceId} and sandbox_group_id = ${input.sandboxGroupId}\n and liveness = 'warming' and lease_epoch = ${input.expectedEpoch}\n returning *\n `);\n // CAS miss = a reaper already reset this warming row to cold (the spawner\n // was too slow), or another spawner re-established and bumped the epoch.\n // The spawner MUST drop its in-memory handle and re-acquire — NEVER force\n // warm, NEVER provider-delete the box (it rides the provider idle-timeout).\n if (rows.length === 0) return { committed: false, lease: null };\n return { committed: true, lease: mapLeaseRow(rows[0]!) };\n });\n}\n\n// §4.3 — caught spawn failure: warming -> cold (W3). Holders are intentionally\n// left intact — the arrival that triggered the spawn still wants a box, so the\n// next acquireLease re-CAS cold->warming.\n//\n// ARCHIVE PRESERVATION (sandbox-file-persistence): when the cold lease that was\n// selected for re-warm carried a persisted /workspace archive on its resume_state\n// (an archive-only envelope `{ backendId, sessionState: { workspaceArchive } }`\n// placed there by a prior drain), the spawn failed BEFORE commitWarmingToWarm,\n// so the LIVE box envelope was never folded onto resume_state. The warming row\n// still holds the ORIGINAL archive-only envelope. Nulling resume_state here would\n// destroy the snapshot the NEXT re-warm must replay — the same file-persistence\n// bug confirmDrainCold guards against. So we PRESERVE a minimal archive-only\n// envelope across this failure rollback (same shape confirmDrainCold keeps) and\n// retain resume_backend_id. No archive on the warming row (a never-persisted cold\n// start) -> resume_state is nulled as before.\nexport async function failWarmingToCold(db: Database, input: {\n accountId: string; workspaceId: string; sandboxGroupId: string; expectedEpoch: number;\n}): Promise<void> {\n await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId },\n async (scopedDb) => {\n await scopedDb.execute(sql`\n update sandbox_leases set\n liveness = 'cold', instance_id = null,\n data_plane_url = null, terminal_data_plane_url = null, updated_at = now(),\n resume_state = case\n when (resume_state #>> '{sessionState,workspaceArchive}') is not null\n then jsonb_build_object(\n 'backendId', coalesce(resume_state ->> 'backendId', to_jsonb(resume_backend_id) #>> '{}'),\n 'sessionState', jsonb_build_object(\n 'workspaceArchive', resume_state #> '{sessionState,workspaceArchive}'))\n else null\n end,\n resume_backend_id = case\n when (resume_state #>> '{sessionState,workspaceArchive}') is not null\n then resume_backend_id\n else null\n end\n where workspace_id = ${input.workspaceId} and sandbox_group_id = ${input.sandboxGroupId}\n and liveness = 'warming' and lease_epoch = ${input.expectedEpoch}\n `);\n });\n}\n\n// §4.4 — idempotent delete-my-row (+ opportunistic warm->draining guarded\n// refcount=0 AND turn_holders=0, so a paying turn is never drained).\nexport async function releaseLeaseHolder(db: Database, input: {\n accountId: string; workspaceId: string; sandboxGroupId: string;\n kind: LeaseHolderKind; holderId: string; idleGraceMs: number;\n}): Promise<{ liveness: SandboxLeaseLiveness; refcount: number } | null> {\n return await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId },\n async (scopedDb) => await scopedDb.transaction(async (txRaw) => {\n const tx = txRaw as unknown as Database;\n const rows = await tx.execute<LeaseRow>(sql`\n select * from sandbox_leases\n where workspace_id = ${input.workspaceId} and sandbox_group_id = ${input.sandboxGroupId}\n for update\n `);\n const row = rows[0];\n if (!row) return null; // already cold-and-reaped; release is an idempotent no-op\n\n // Idempotent: deleting an already-gone holder affects 0 rows, fine.\n await tx.execute(sql`\n delete from sandbox_lease_holders\n where lease_id = ${row.id} and kind = ${input.kind} and holder_id = ${input.holderId}\n `);\n\n const counts = await tx.execute<{ total: number; turns: number; viewers: number }>(sql`\n select count(*)::int as total,\n count(*) filter (where kind = 'turn')::int as turns,\n count(*) filter (where kind = 'viewer')::int as viewers\n from sandbox_lease_holders where lease_id = ${row.id}\n `);\n const c = counts[0]!;\n\n // warm + dropped to 0 (AND no turn holders) -> draining, stamp grace deadline.\n // Release during warming decrements only, NEVER touches liveness (the\n // spawner owns warming->warm and re-checks refcount after committing).\n const enterDraining = row.liveness === \"warm\" && c.total === 0 && c.turns === 0;\n const updated = await tx.execute<LeaseRow>(sql`\n update sandbox_leases set\n refcount = ${c.total}, turn_holders = ${c.turns}, viewer_holders = ${c.viewers},\n ${enterDraining\n ? sql`liveness = 'draining', expires_at = now() + (${String(input.idleGraceMs)} || ' milliseconds')::interval,`\n : sql``}\n updated_at = now()\n where id = ${row.id}\n returning *\n `);\n return { liveness: updated[0]!.liveness, refcount: Number(c.total) };\n }));\n}\n\n// §4.5 — heartbeat. EPOCH-FENCED (the C1b fix — the real split-brain bug, on the\n// HEARTBEAT path): a stale (superseded) owner's lease refresh is rejected so it\n// self-evicts. Also liveness-guarded to warm/warming (C2) so a heartbeat can't\n// wedge a draining lease forever by pushing its grace deadline.\nexport async function heartbeatLeaseHolder(db: Database, input: {\n accountId: string; workspaceId: string; sandboxGroupId: string;\n kind: LeaseHolderKind; holderId: string; leaseTtlMs: number; expectedEpoch: number;\n}): Promise<boolean> {\n return await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId },\n async (scopedDb) => await scopedDb.transaction(async (txRaw) => {\n const tx = txRaw as unknown as Database;\n const updated = await tx.execute<{ id: string }>(sql`\n update sandbox_lease_holders set last_heartbeat_at = now()\n where lease_id = (select id from sandbox_leases\n where workspace_id = ${input.workspaceId} and sandbox_group_id = ${input.sandboxGroupId})\n and kind = ${input.kind} and holder_id = ${input.holderId}\n returning id\n `);\n if (updated.length === 0) return false; // holder was reaped — caller re-acquires\n // Epoch-fenced, liveness-guarded lease TTL refresh: only a live-epoch\n // warm/warming lease is refreshed. A stale-epoch (split-brain) or draining\n // lease returns 0 rows -> false -> the stale holder drops its handle.\n const leaseRows = await tx.execute<{ id: string }>(sql`\n update sandbox_leases set\n expires_at = now() + (${String(input.leaseTtlMs)} || ' milliseconds')::interval,\n updated_at = now()\n where workspace_id = ${input.workspaceId} and sandbox_group_id = ${input.sandboxGroupId}\n and lease_epoch = ${input.expectedEpoch}\n and liveness in ('warm','warming')\n returning id\n `);\n return leaseRows.length > 0;\n }));\n}\n\n// §4.6 — the reaper. DB-SIDE ONLY (no provider call — the provider stop() is\n// P1.3's runtime concern). Three actions in one pass: TTL-reap stale viewer\n// holders, recompute refcounts + warm->draining, reset warming-death to cold;\n// returns the drainable (workspaceId, sandboxGroupId) rows the caller terminates.\n//\n// This is the PER-WORKSPACE entry point (RLS-scoped). The cross-workspace global\n// sweep is the SECURITY-DEFINER opengeni_private.reap_sandbox_leases() fn —\n// reapStaleLeaseHoldersGlobal below.\nexport interface ReapDrainable {\n workspaceId: string;\n sandboxGroupId: string;\n instanceId: string | null;\n leaseEpoch: number;\n}\n\nexport async function reapStaleLeaseHolders(db: Database, input: {\n workspaceId: string;\n viewerHolderTtlMs: number; // delete viewer rows older than this\n idleGraceMs: number; // drain-grace horizon (matches releaseLeaseHolder)\n}): Promise<{ reapedViewers: number; warmingReset: number; drained: ReapDrainable[] }> {\n return await withWorkspaceRls(db, input.workspaceId, async (scopedDb) =>\n await scopedDb.transaction(async (txRaw) => {\n const tx = txRaw as unknown as Database;\n // (a) Reap stale VIEWER holders (turn holders are TTL-exempt — never reaped).\n const reaped = await tx.execute<{ lease_id: string }>(sql`\n delete from sandbox_lease_holders\n where workspace_id = ${input.workspaceId} and kind = 'viewer'\n and last_heartbeat_at < now() - (${String(input.viewerHolderTtlMs)} || ' milliseconds')::interval\n returning lease_id\n `);\n\n // (b) Recompute refcounts for every lease in the workspace; warm leases\n // that hit 0 (AND turn_holders=0) enter draining with a fresh grace\n // deadline (idleGraceMs — the SAME horizon releaseLeaseHolder stamps).\n await tx.execute(sql`\n update sandbox_leases L set\n refcount = c.total,\n turn_holders = c.turns,\n viewer_holders = c.viewers,\n liveness = case when L.liveness = 'warm' and c.total = 0 and c.turns = 0\n then 'draining' else L.liveness end,\n expires_at = case when L.liveness = 'warm' and c.total = 0 and c.turns = 0\n then now() + (${String(input.idleGraceMs)} || ' milliseconds')::interval\n else L.expires_at end,\n updated_at = now()\n from (\n select L2.id,\n (select count(*) from sandbox_lease_holders h where h.lease_id = L2.id)::int as total,\n (select count(*) from sandbox_lease_holders h where h.lease_id = L2.id and h.kind = 'turn')::int as turns,\n (select count(*) from sandbox_lease_holders h where h.lease_id = L2.id and h.kind = 'viewer')::int as viewers\n from sandbox_leases L2 where L2.workspace_id = ${input.workspaceId}\n ) c\n where L.id = c.id and L.workspace_id = ${input.workspaceId}\n `);\n\n // (c) WARMING-death: a 'warming' row whose LEASE TTL lapsed = an uncaught\n // spawner death. Reset to cold so a queued turn can re-acquire and re-spawn.\n const warmingReset = await tx.execute<{ id: string }>(sql`\n update sandbox_leases set\n liveness = 'cold', instance_id = null,\n resume_backend_id = null, resume_state = null,\n data_plane_url = null, terminal_data_plane_url = null, updated_at = now()\n where workspace_id = ${input.workspaceId}\n and liveness = 'warming' and expires_at < now()\n returning id\n `);\n\n // (d) DRAINING-grace elapsed: surface leases whose grace is up AND still\n // idle, with instance_id + epoch, so the caller can issue the provider\n // stop() then confirmDrainCold. DB-only: no provider call here.\n const drainable = await rawRows<{ sandbox_group_id: string; instance_id: string | null; lease_epoch: number | string }>(tx, sql`\n select sandbox_group_id, instance_id, lease_epoch from sandbox_leases\n where workspace_id = ${input.workspaceId}\n and liveness = 'draining' and expires_at < now() and refcount = 0\n `);\n\n return {\n reapedViewers: reaped.length,\n warmingReset: warmingReset.length,\n drained: drainable.map((r) => ({\n workspaceId: input.workspaceId,\n sandboxGroupId: r.sandbox_group_id,\n instanceId: r.instance_id,\n leaseEpoch: Number(r.lease_epoch),\n })),\n };\n }));\n}\n\n// §4.6 (global) — the cross-workspace reaper sweep (OD-3). Calls the\n// SECURITY-DEFINER opengeni_private.reap_sandbox_leases() fn so the global\n// reaper Temporal Schedule (P1.3) sees stale rows across ALL workspaces in ONE\n// pass, bypassing per-workspace FORCE RLS. DB-only — returns the drainable rows;\n// the provider stop() is the caller's concern. No RLS GUC is set (the DEFINER fn\n// is the sanctioned cross-workspace read).\nexport async function reapStaleLeaseHoldersGlobal(db: Database, input: {\n viewerHolderTtlMs: number;\n idleGraceMs: number;\n}): Promise<ReapDrainable[]> {\n const rows = await rawRows<{ workspace_id: string; sandbox_group_id: string; instance_id: string | null; lease_epoch: number | string }>(db, sql`\n select workspace_id, sandbox_group_id, instance_id, lease_epoch\n from opengeni_private.reap_sandbox_leases(${input.viewerHolderTtlMs}, ${input.idleGraceMs})\n `);\n return rows.map((r) => ({\n workspaceId: r.workspace_id,\n sandboxGroupId: r.sandbox_group_id,\n instanceId: r.instance_id,\n leaseEpoch: Number(r.lease_epoch),\n }));\n}\n\n// §2.2 (global) — the warm-meter read for the REAPER tick (P2.1). Returns one row\n// per WARM viewer-only group (turn-held boxes are metered by the turn heartbeat,\n// so they are EXCLUDED here — no double-meter). Cross-workspace via the\n// SECURITY-DEFINER list fn (FORCE RLS would hide other workspaces from the scoped\n// connection). DB-only read; the worker accrues per row via accrueWarmSeconds.\nexport interface MeterableWarmLease {\n accountId: string;\n workspaceId: string;\n sandboxGroupId: string;\n leaseEpoch: number;\n backend: string;\n}\n\nexport async function listMeterableWarmLeases(db: Database): Promise<MeterableWarmLease[]> {\n const rows = await rawRows<{ account_id: string; workspace_id: string; sandbox_group_id: string; lease_epoch: number | string; backend: string }>(db, sql`\n select account_id, workspace_id, sandbox_group_id, lease_epoch, backend\n from opengeni_private.list_meterable_warm_leases()\n `);\n return rows.map((r) => ({\n accountId: r.account_id,\n workspaceId: r.workspace_id,\n sandboxGroupId: r.sandbox_group_id,\n leaseEpoch: Number(r.lease_epoch),\n backend: r.backend,\n }));\n}\n\n// §4.7 — explicit re-arm seam (D1). acquireLease already re-arms a draining\n// lease inline; this is the standalone version for callers that learn a holder\n// is wanted during the grace window without going through acquireLease first.\nexport async function reArmDrainingLease(db: Database, input: {\n accountId: string; workspaceId: string; sandboxGroupId: string; leaseTtlMs: number;\n}): Promise<{ rearmed: boolean }> {\n return await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId },\n async (scopedDb) => {\n const rows = await scopedDb.execute<{ id: string }>(sql`\n update sandbox_leases set\n liveness = 'warm',\n expires_at = now() + (${String(input.leaseTtlMs)} || ' milliseconds')::interval,\n updated_at = now()\n where workspace_id = ${input.workspaceId} and sandbox_group_id = ${input.sandboxGroupId}\n and liveness = 'draining'\n returning id\n `);\n return { rearmed: rows.length > 0 };\n });\n}\n\n// §4.8 — the reaper's final teardown commit (D3). Called AFTER the caller issued\n// the provider stop() on instance_id. CAS-guarded (draining AND refcount=0 AND\n// lease_epoch=expected) so a late re-arm (D1) or a newer epoch that snuck in\n// during teardown wins — wentCold:false means the box is still wanted and must\n// NOT have been stopped (the caller checks this CAS before stop(), or re-reads).\nexport async function confirmDrainCold(db: Database, input: {\n accountId: string; workspaceId: string; sandboxGroupId: string; expectedEpoch: number;\n}): Promise<{ wentCold: boolean }> {\n return await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId },\n async (scopedDb) => {\n // draining->cold: the box is terminated, so EVERY live-box field is cleared\n // (instance_id / data-plane URLs). resume_state, however, is NOT blindly\n // nulled — if the reaper PERSISTED a /workspace snapshot onto it\n // (persistDrainSnapshot folds the archive at resume_state.sessionState.\n // workspaceArchive BEFORE this CAS, in the SAME sweep), nulling it here would\n // immediately destroy the snapshot the next cold-restore must replay — the\n // file-persistence bug. So we PRESERVE a MINIMAL archive-only envelope\n // `{ backendId, sessionState: { workspaceArchive } }` (dropping the dead box's\n // providerState/sandboxId — the box is gone, resume-by-id would only fail) and\n // KEEP resume_backend_id so cold-restore knows which client to hydrate with.\n // No archive (a non-persisted drain, or a 'none'/tar config that stored none)\n // -> resume_state is nulled as before. The archive then rides the COLD lease's\n // resume_state until the next spawner reads + hydrates it; it is re-superseded\n // (GC'd) on the next drain and finally cleared on workspace teardown.\n const rows = await scopedDb.execute<{ id: string }>(sql`\n update sandbox_leases set\n liveness = 'cold', instance_id = null,\n data_plane_url = null, terminal_data_plane_url = null, updated_at = now(),\n resume_state = case\n when (resume_state #>> '{sessionState,workspaceArchive}') is not null\n then jsonb_build_object(\n 'backendId', coalesce(resume_state ->> 'backendId', to_jsonb(resume_backend_id) #>> '{}'),\n 'sessionState', jsonb_build_object(\n 'workspaceArchive', resume_state #> '{sessionState,workspaceArchive}'))\n else null\n end,\n resume_backend_id = case\n when (resume_state #>> '{sessionState,workspaceArchive}') is not null\n then resume_backend_id\n else null\n end\n where workspace_id = ${input.workspaceId} and sandbox_group_id = ${input.sandboxGroupId}\n and liveness = 'draining' and refcount = 0 and lease_epoch = ${input.expectedEpoch}\n returning id\n `);\n return { wentCold: rows.length > 0 };\n });\n}\n\n// §4.8b — persist the /workspace snapshot archive onto the lease BEFORE the\n// reaper terminates a drained box (sandbox-file-persistence). The reaper, after\n// resuming the live box and capturing `session.persistWorkspace()` (a base64\n// snapshot-ref / tar archive), CAS-folds it onto the lease's resume_state under\n// the SAME epoch fence confirmDrainCold uses (draining AND refcount=0 AND\n// lease_epoch=expected). Folding it into resume_state.sessionState.workspaceArchive\n// means a later cold-restore (establishSandboxSessionFromEnvelope) reads it back\n// off the same envelope it already deserializes, and confirmDrainCold's\n// `resume_state = null` clears it on teardown for free (delete-on-teardown).\n//\n// When workspaceArchive is null this function acts as a PURE CAS-GATE: it checks\n// (draining AND refcount=0 AND epoch=expected) under a FOR UPDATE lock and returns\n// wrote:true/false WITHOUT writing anything. This allows the reaper to guard a\n// terminate that produced no archive (a backend with no persistWorkspace) against\n// the re-arm race: a re-arm during the snapshot window sets refcount>0 / liveness!=\n// draining, so wrote:false → the reaper MUST NOT delete the box.\n//\n// Returns `{ wrote, priorArchive }`:\n// - wrote:false -> the CAS missed (re-armed / newer epoch / vanished); the\n// caller must NOT terminate (the box is wanted again). No GC.\n// - priorArchive -> the archive THIS lease carried before (if any), so the\n// caller can best-effort delete the superseded provider\n// snapshot (keep-latest-per-lease GC). null on the first\n// persist for this box or when workspaceArchive is null.\n// The fence is the split-brain guard: a stale-epoch reaper writes ZERO rows and\n// is told not to terminate.\nexport async function persistDrainSnapshot(db: Database, input: {\n accountId: string; workspaceId: string; sandboxGroupId: string;\n expectedEpoch: number;\n /** base64 of the provider snapshot-ref / tar archive from persistWorkspace().\n * Pass null to CAS-check without writing (for backends with no persistWorkspace). */\n workspaceArchive: string | null;\n}): Promise<{ wrote: boolean; priorArchive: string | null }> {\n // withRlsContext already runs `fn` inside ONE transaction with the RLS GUCs set,\n // so the SELECT...FOR UPDATE + UPDATE below are atomic (one snapshot, one lock)\n // WITHOUT an extra nested savepoint — nesting a second transaction here under\n // the RLS-scoped connection wedges the postgres-js client (\"Failed query\").\n return await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId },\n async (scopedDb) => {\n // (1) Lock + read the PRIOR archive under the CAS guard (draining AND\n // refcount=0 AND lease_epoch=expected). A miss (re-armed / newer epoch /\n // vanished) returns no row → wrote:false, the caller must NOT terminate.\n const guard = await scopedDb.execute<{ prior_archive: string | null }>(sql`\n select resume_state #>> '{sessionState,workspaceArchive}' as prior_archive\n from sandbox_leases\n where workspace_id = ${input.workspaceId} and sandbox_group_id = ${input.sandboxGroupId}\n and liveness = 'draining' and refcount = 0 and lease_epoch = ${input.expectedEpoch}\n for update\n `);\n if (guard.length === 0) {\n return { wrote: false, priorArchive: null };\n }\n const priorArchive = guard[0]!.prior_archive ?? null;\n // null workspaceArchive = pure CAS-check (re-arm guard for no-archive backends).\n // The FOR UPDATE lock above is the only synchronization needed; no write.\n if (input.workspaceArchive === null) {\n return { wrote: true, priorArchive: null };\n }\n // (2) Merge the NEW archive into resume_state.sessionState.workspaceArchive.\n // jsonb_set's create_missing does NOT create intermediate objects, so a\n // direct set of '{sessionState,workspaceArchive}' is a silent no-op when\n // `sessionState` is absent (a null resume_state, or a legacy flat envelope).\n // Instead: rebuild `sessionState` as (existing sessionState OR '{}') merged\n // (||) with `{workspaceArchive: <b64>}` — this CREATES sessionState if absent\n // AND preserves its existing siblings (providerState/manifest/exposedPorts).\n // The archive is bound as a jsonb string scalar (to_jsonb(text)). Re-asserting\n // the CAS guard keeps the write atomic with the FOR UPDATE lock above.\n await scopedDb.execute(sql`\n update sandbox_leases set\n resume_state = jsonb_set(\n -- Defensive: only treat resume_state / its sessionState as an object\n -- when it actually IS one; a null/scalar (legacy or malformed envelope)\n -- starts from '{}' so jsonb_set never throws \"cannot set path in scalar\".\n case when jsonb_typeof(resume_state) = 'object' then resume_state else '{}'::jsonb end,\n '{sessionState}',\n (case when jsonb_typeof(resume_state -> 'sessionState') = 'object'\n then resume_state -> 'sessionState' else '{}'::jsonb end)\n || jsonb_build_object('workspaceArchive', to_jsonb(${input.workspaceArchive}::text)),\n true\n ),\n updated_at = now()\n where workspace_id = ${input.workspaceId} and sandbox_group_id = ${input.sandboxGroupId}\n and liveness = 'draining' and refcount = 0 and lease_epoch = ${input.expectedEpoch}\n `);\n return { wrote: true, priorArchive };\n });\n}\n\n// §4.9 — non-locking snapshot for the API handshake & health.\nexport async function readLease(db: Database, workspaceId: string, sandboxGroupId: string): Promise<LeaseSnapshot | null> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const rows = await scopedDb.execute<LeaseRow>(sql`\n select * from sandbox_leases\n where workspace_id = ${workspaceId} and sandbox_group_id = ${sandboxGroupId}\n limit 1\n `);\n return rows[0] ? mapLeaseRow(rows[0]) : null;\n });\n}\n\n// P4.2 — record the (re-)resolved desktop data-plane URL on an ALREADY-WARM\n// lease, EPOCH-FENCED. commitWarmingToWarm records the URL at cold→warming→warm\n// (the spawn path); this is the WARM-path counterpart used when a viewer mints\n// the URL against a box that some other holder already brought up, and on\n// rollover-rotation (re-resolve under the current epoch). The fence is the\n// split-brain guard: a stale-epoch writer (a box re-established under a newer\n// epoch) updates ZERO rows and the caller backs off. Returns the updated\n// snapshot, or null on a fence miss (epoch advanced / lease vanished).\nexport async function recordLeaseDataPlaneUrl(db: Database, input: {\n accountId: string;\n workspaceId: string;\n sandboxGroupId: string;\n expectedEpoch: number;\n dataPlaneUrl: string | null;\n}): Promise<LeaseSnapshot | null> {\n return await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId },\n async (scopedDb) => {\n const rows = await scopedDb.execute<LeaseRow>(sql`\n update sandbox_leases set\n data_plane_url = ${input.dataPlaneUrl ?? null},\n updated_at = now()\n where workspace_id = ${input.workspaceId} and sandbox_group_id = ${input.sandboxGroupId}\n and lease_epoch = ${input.expectedEpoch}\n and liveness in ('warm', 'draining')\n returning *\n `);\n return rows[0] ? mapLeaseRow(rows[0]) : null;\n });\n}\n\n// P5.t — record the (re-)resolved ttyd terminal data-plane URL (7681) on an\n// ALREADY-WARM lease, EPOCH-FENCED. The exact terminal twin of\n// recordLeaseDataPlaneUrl: the REAL PTY rides a SEPARATE provider tunnel from the\n// desktop noVNC, so its URL is cached in its own column. mintTerminalStream calls\n// this after resolving the 7681 tunnel; the fast-path then re-mints only a fresh\n// token against the cached URL. The fence is the split-brain guard (a stale-epoch\n// writer updates ZERO rows). Returns the updated snapshot, or null on a fence\n// miss (epoch advanced / lease vanished).\nexport async function recordLeaseTerminalDataPlaneUrl(db: Database, input: {\n accountId: string;\n workspaceId: string;\n sandboxGroupId: string;\n expectedEpoch: number;\n terminalDataPlaneUrl: string | null;\n}): Promise<LeaseSnapshot | null> {\n return await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId },\n async (scopedDb) => {\n const rows = await scopedDb.execute<LeaseRow>(sql`\n update sandbox_leases set\n terminal_data_plane_url = ${input.terminalDataPlaneUrl ?? null},\n updated_at = now()\n where workspace_id = ${input.workspaceId} and sandbox_group_id = ${input.sandboxGroupId}\n and lease_epoch = ${input.expectedEpoch}\n and liveness in ('warm', 'draining')\n returning *\n `);\n return rows[0] ? mapLeaseRow(rows[0]) : null;\n });\n}\n\n// ============================================================================\n// Bring-your-own-compute (M2): first-class swappable sandboxes + enrollment +\n// per-machine metrics + the per-session epoch-fenced active-sandbox pointer\n// (migration 0024 / dossier §10.3 + §10.7 + §23). All workspace-scoped behind\n// the same RLS the lease DAOs use.\n// ============================================================================\n\nexport type SandboxKind = (typeof schema.sandboxKindValues)[number];\nexport type EnrollmentExposure = (typeof schema.enrollmentExposureValues)[number];\nexport type EnrollmentStatus = (typeof schema.enrollmentStatusValues)[number];\nexport type EnrollmentOs = (typeof schema.enrollmentOsValues)[number];\n\nexport type EnrollmentRecord = {\n id: string;\n accountId: string;\n workspaceId: string;\n pubkey: string;\n exposure: EnrollmentExposure;\n hasDisplay: boolean;\n allowScreenControl: boolean;\n status: EnrollmentStatus;\n os: EnrollmentOs;\n arch: string;\n lastSeenAt: string | null;\n createdAt: string;\n revokedAt: string | null;\n updatedAt: string;\n};\n\nfunction mapEnrollment(row: typeof schema.enrollments.$inferSelect): EnrollmentRecord {\n return {\n id: row.id,\n accountId: row.accountId,\n workspaceId: row.workspaceId,\n pubkey: row.pubkey,\n exposure: row.exposure as EnrollmentExposure,\n hasDisplay: row.hasDisplay,\n allowScreenControl: row.allowScreenControl,\n status: row.status as EnrollmentStatus,\n os: row.os as EnrollmentOs,\n arch: row.arch,\n lastSeenAt: row.lastSeenAt ? row.lastSeenAt.toISOString() : null,\n createdAt: row.createdAt.toISOString(),\n revokedAt: row.revokedAt ? row.revokedAt.toISOString() : null,\n updatedAt: row.updatedAt.toISOString(),\n };\n}\n\nexport type SandboxRecord = {\n id: string;\n accountId: string;\n workspaceId: string;\n kind: SandboxKind;\n name: string;\n enrollmentId: string | null;\n createdAt: string;\n updatedAt: string;\n};\n\nfunction mapSandbox(row: typeof schema.sandboxes.$inferSelect): SandboxRecord {\n return {\n id: row.id,\n accountId: row.accountId,\n workspaceId: row.workspaceId,\n kind: row.kind as SandboxKind,\n name: row.name,\n enrollmentId: row.enrollmentId ?? null,\n createdAt: row.createdAt.toISOString(),\n updatedAt: row.updatedAt.toISOString(),\n };\n}\n\n// ---- enrollments ----------------------------------------------------------\n\n// Register (or idempotently re-register) a machine. A re-enroll of the SAME\n// (workspace, pubkey) is an UPSERT — it refreshes the consent/OS fields and, if\n// the machine was previously revoked, re-activates it (status->active, revoked_at\n// cleared) — never a duplicate machine row. The agent's ed25519 pubkey is the\n// machine identity; the unique (workspace, pubkey) index is the conflict target.\nexport async function createEnrollment(db: Database, input: {\n accountId: string;\n workspaceId: string;\n pubkey: string;\n exposure?: EnrollmentExposure;\n hasDisplay?: boolean;\n allowScreenControl?: boolean;\n os?: EnrollmentOs;\n arch?: string;\n}): Promise<EnrollmentRecord> {\n return await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId }, async (scopedDb) => {\n const [row] = await scopedDb.insert(schema.enrollments).values({\n accountId: input.accountId,\n workspaceId: input.workspaceId,\n pubkey: input.pubkey,\n exposure: input.exposure ?? \"whole-machine\",\n hasDisplay: input.hasDisplay ?? false,\n allowScreenControl: input.allowScreenControl ?? false,\n os: input.os ?? \"linux\",\n arch: input.arch ?? \"x86_64\",\n status: \"active\",\n }).onConflictDoUpdate({\n target: [schema.enrollments.workspaceId, schema.enrollments.pubkey],\n set: {\n exposure: input.exposure ?? \"whole-machine\",\n hasDisplay: input.hasDisplay ?? false,\n allowScreenControl: input.allowScreenControl ?? false,\n os: input.os ?? \"linux\",\n arch: input.arch ?? \"x86_64\",\n // A re-enroll re-activates a previously revoked machine.\n status: \"active\",\n revokedAt: null,\n updatedAt: new Date(),\n },\n }).returning();\n if (!row) {\n throw new Error(\"Failed to create enrollment\");\n }\n return mapEnrollment(row);\n });\n}\n\nexport async function getEnrollment(db: Database, workspaceId: string, enrollmentId: string): Promise<EnrollmentRecord | null> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const [row] = await scopedDb.select().from(schema.enrollments)\n .where(and(eq(schema.enrollments.workspaceId, workspaceId), eq(schema.enrollments.id, enrollmentId)))\n .limit(1);\n return row ? mapEnrollment(row) : null;\n });\n}\n\n// List a workspace's enrollments, newest first. `status` filters the lifecycle\n// (omit for all; 'active' for the Machines dashboard's live list).\nexport async function listEnrollments(db: Database, workspaceId: string, options: { status?: EnrollmentStatus } = {}): Promise<EnrollmentRecord[]> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const where = options.status\n ? and(eq(schema.enrollments.workspaceId, workspaceId), eq(schema.enrollments.status, options.status))\n : eq(schema.enrollments.workspaceId, workspaceId);\n const rows = await scopedDb.select().from(schema.enrollments)\n .where(where)\n .orderBy(desc(schema.enrollments.createdAt));\n return rows.map(mapEnrollment);\n });\n}\n\n// Revoke a machine (uninstall --purge / dashboard revoke). Idempotent: an already\n// -revoked row is a no-op (revoked:false). status->revoked, revoked_at stamped.\nexport async function revokeEnrollment(db: Database, input: {\n accountId: string; workspaceId: string; enrollmentId: string;\n}): Promise<{ revoked: boolean }> {\n return await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId }, async (scopedDb) => {\n const rows = await scopedDb.update(schema.enrollments)\n .set({ status: \"revoked\", revokedAt: new Date(), updatedAt: new Date() })\n .where(and(\n eq(schema.enrollments.workspaceId, input.workspaceId),\n eq(schema.enrollments.id, input.enrollmentId),\n eq(schema.enrollments.status, \"active\"),\n ))\n .returning({ id: schema.enrollments.id });\n return { revoked: rows.length > 0 };\n });\n}\n\n// Heartbeat liveness cursor: the agent reports it is alive. last_seen_at is read\n// by the online/reconnecting/offline derivation in the Machines surface.\nexport async function touchEnrollmentLastSeen(db: Database, input: {\n accountId: string; workspaceId: string; enrollmentId: string;\n}): Promise<void> {\n await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId }, async (scopedDb) => {\n await scopedDb.update(schema.enrollments)\n .set({ lastSeenAt: new Date(), updatedAt: new Date() })\n .where(and(\n eq(schema.enrollments.workspaceId, input.workspaceId),\n eq(schema.enrollments.id, input.enrollmentId),\n ));\n });\n}\n\n// Live display cursor: the agent's connect Hello reports whether a display is\n// present RIGHT NOW (a desktop framebuffer probes). Unlike `has_display` set once\n// at enroll time from the enroll-offer snapshot, this tracks REALITY across the\n// machine's life — a Mac that later grants Screen Recording, or a Linux box whose\n// Xvfb starts after enrollment, flips false→true on its next Hello (and a display\n// that goes away flips true→false). CHANGE-GUARDED at the SQL layer (the `ne`\n// predicate): a Hello that reports the same value the row already holds updates\n// zero rows, so a steady state never churns a write. Returns whether a row was\n// actually changed. Best-effort — the caller swallows failures so a display\n// refresh never breaks the agent's connect.\nexport async function setEnrollmentHasDisplay(db: Database, input: {\n accountId: string; workspaceId: string; enrollmentId: string; hasDisplay: boolean;\n}): Promise<{ updated: boolean }> {\n return await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId }, async (scopedDb) => {\n const rows = await scopedDb.update(schema.enrollments)\n .set({ hasDisplay: input.hasDisplay, updatedAt: new Date() })\n .where(and(\n eq(schema.enrollments.workspaceId, input.workspaceId),\n eq(schema.enrollments.id, input.enrollmentId),\n // Only write on a CHANGE — an unchanged display must not churn a write on\n // every reconnect Hello.\n ne(schema.enrollments.hasDisplay, input.hasDisplay),\n ))\n .returning({ id: schema.enrollments.id });\n return { updated: rows.length > 0 };\n });\n}\n\n// ---- device-flow enrollment requests (M5, migration 0025) -----------------\n//\n// The OAuth 2.0 device-authorization (RFC 8628) PENDING request: one short-TTL,\n// single-use row per in-flight enrollment. The agent starts a flow (gets a\n// device_code + user_code), the user approves it (LOUD consent capture +\n// createEnrollment + createSandbox), and the agent polls the device_code for the\n// resulting EnrollmentCredentials. Dossier §10.2 + §18.\n\nexport type DeviceEnrollmentStatus = (typeof schema.deviceEnrollmentStatusValues)[number];\n\nexport type DeviceEnrollmentRequestRecord = {\n id: string;\n deviceCode: string;\n userCode: string;\n accountId: string;\n workspaceId: string;\n pubkey: string;\n os: EnrollmentOs;\n arch: string;\n machineName: string | null;\n requestedExposure: EnrollmentExposure;\n canOfferDisplay: boolean;\n requestsScreenControl: boolean;\n status: DeviceEnrollmentStatus;\n approvedBySubjectId: string | null;\n approvedBySubjectLabel: string | null;\n allowScreenControl: boolean;\n approvedAt: string | null;\n enrollmentId: string | null;\n sandboxId: string | null;\n expiresAt: string;\n createdAt: string;\n updatedAt: string;\n};\n\nfunction mapDeviceEnrollmentRequest(row: typeof schema.deviceEnrollmentRequests.$inferSelect): DeviceEnrollmentRequestRecord {\n return {\n id: row.id,\n deviceCode: row.deviceCode,\n userCode: row.userCode,\n accountId: row.accountId,\n workspaceId: row.workspaceId,\n pubkey: row.pubkey,\n os: row.os as EnrollmentOs,\n arch: row.arch,\n machineName: row.machineName ?? null,\n requestedExposure: row.requestedExposure as EnrollmentExposure,\n canOfferDisplay: row.canOfferDisplay,\n requestsScreenControl: row.requestsScreenControl,\n status: row.status as DeviceEnrollmentStatus,\n approvedBySubjectId: row.approvedBySubjectId ?? null,\n approvedBySubjectLabel: row.approvedBySubjectLabel ?? null,\n allowScreenControl: row.allowScreenControl,\n approvedAt: row.approvedAt ? row.approvedAt.toISOString() : null,\n enrollmentId: row.enrollmentId ?? null,\n sandboxId: row.sandboxId ?? null,\n expiresAt: row.expiresAt.toISOString(),\n createdAt: row.createdAt.toISOString(),\n updatedAt: row.updatedAt.toISOString(),\n };\n}\n\n// Persist a fresh PENDING device-auth request (the agent's POST /start). The\n// caller supplies the unguessable device_code + user_code (minted with a CSPRNG)\n// and the short TTL. RLS-scoped to the workspace the flow binds to.\nexport async function createDeviceEnrollmentRequest(db: Database, input: {\n accountId: string;\n workspaceId: string;\n deviceCode: string;\n userCode: string;\n pubkey: string;\n os?: EnrollmentOs;\n arch?: string;\n machineName?: string | null;\n requestedExposure?: EnrollmentExposure;\n canOfferDisplay?: boolean;\n requestsScreenControl?: boolean;\n expiresAt: Date;\n}): Promise<DeviceEnrollmentRequestRecord> {\n return await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId }, async (scopedDb) => {\n const [row] = await scopedDb.insert(schema.deviceEnrollmentRequests).values({\n accountId: input.accountId,\n workspaceId: input.workspaceId,\n deviceCode: input.deviceCode,\n userCode: input.userCode,\n pubkey: input.pubkey,\n os: input.os ?? \"linux\",\n arch: input.arch ?? \"x86_64\",\n machineName: input.machineName ?? null,\n requestedExposure: input.requestedExposure ?? \"whole-machine\",\n canOfferDisplay: input.canOfferDisplay ?? false,\n requestsScreenControl: input.requestsScreenControl ?? false,\n status: \"pending\",\n expiresAt: input.expiresAt,\n }).returning();\n if (!row) {\n throw new Error(\"Failed to create device enrollment request\");\n }\n return mapDeviceEnrollmentRequest(row);\n });\n}\n\n// Look up a request by its opaque device_code (the agent's poll key). The\n// device_code IS the capability (unguessable + unique) and the agent has NO\n// workspace context yet, so resolve (account_id, workspace_id) via the SECURITY\n// DEFINER resolver (mirrors the global reaper's cross-workspace read), then re-read\n// the FULL row under that workspace's RLS scope. Returns null when unknown.\nexport async function getDeviceEnrollmentRequestByDeviceCode(db: Database, deviceCode: string): Promise<DeviceEnrollmentRequestRecord | null> {\n const resolved = await db.execute<{ account_id: string; workspace_id: string }>(sql`\n select account_id, workspace_id from opengeni_private.resolve_device_enrollment_request(${deviceCode})\n `);\n const ctx = resolved[0];\n if (!ctx) {\n return null;\n }\n return await withRlsContext(db, { accountId: ctx.account_id, workspaceId: ctx.workspace_id }, async (scopedDb) => {\n const [row] = await scopedDb.select().from(schema.deviceEnrollmentRequests)\n .where(eq(schema.deviceEnrollmentRequests.deviceCode, deviceCode))\n .limit(1);\n return row ? mapDeviceEnrollmentRequest(row) : null;\n });\n}\n\n// Look up the PENDING request for a user_code within a workspace (the approve\n// lookup). Workspace-scoped: a user can only approve a request bound to a\n// workspace they hold a grant in. Returns null when no LIVE pending row matches.\nexport async function getPendingDeviceEnrollmentRequestByUserCode(db: Database, workspaceId: string, userCode: string): Promise<DeviceEnrollmentRequestRecord | null> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const [row] = await scopedDb.select().from(schema.deviceEnrollmentRequests)\n .where(and(\n eq(schema.deviceEnrollmentRequests.workspaceId, workspaceId),\n eq(schema.deviceEnrollmentRequests.userCode, userCode),\n eq(schema.deviceEnrollmentRequests.status, \"pending\"),\n ))\n .limit(1);\n return row ? mapDeviceEnrollmentRequest(row) : null;\n });\n}\n\n// Look up the PENDING request for a user_code GLOBALLY (no workspace context) —\n// the click-Grant approve page lookup (design 11 §B.1). The user_code is globally\n// unique among LIVE (pending) rows, so — exactly like getDeviceEnrollmentRequestByDeviceCode\n// resolves a device_code — this resolves (account_id, workspace_id) via the 0026\n// SECURITY DEFINER resolver, then re-reads the FULL pending row under that\n// workspace's RLS scope. The ROUTE then re-checks the caller holds a grant in the\n// resolved workspace before returning anything. Returns null when no live pending\n// row matches (an unknown / terminal / expired code).\nexport async function getPendingDeviceEnrollmentRequestByUserCodeGlobal(db: Database, userCode: string): Promise<DeviceEnrollmentRequestRecord | null> {\n const resolved = await db.execute<{ account_id: string; workspace_id: string }>(sql`\n select account_id, workspace_id from opengeni_private.resolve_pending_device_enrollment_by_user_code(${userCode})\n `);\n const ctx = resolved[0];\n if (!ctx) {\n return null;\n }\n return await withRlsContext(db, { accountId: ctx.account_id, workspaceId: ctx.workspace_id }, async (scopedDb) => {\n const [row] = await scopedDb.select().from(schema.deviceEnrollmentRequests)\n .where(and(\n eq(schema.deviceEnrollmentRequests.userCode, userCode),\n eq(schema.deviceEnrollmentRequests.status, \"pending\"),\n ))\n .limit(1);\n return row ? mapDeviceEnrollmentRequest(row) : null;\n });\n}\n\n// The SHARED finalize core (design 11 §A2.3 \"reuse, don't fork\"): \"upsert the\n// enrollment (idempotent on (workspace_id, pubkey)) + ensure a kind='selfhosted'\n// sandbox row\" — the exact end state BOTH the device approve and the headless\n// token exchange must produce. Takes an ALREADY-RLS-SCOPED `scopedDb` so the\n// caller controls the transaction boundary:\n// * approveDeviceEnrollmentRequest calls it INSIDE its FOR-UPDATE txn (so the\n// re-read fence + the request stamp stay in ONE txn — semantics unchanged), and\n// * finalizeEnrollmentByToken calls it inside its OWN txn (no pending row exists\n// for a stateless token).\n// Idempotent: a re-run for the same (workspace, pubkey) re-activates the existing\n// enrollment (M2 upsert) and REUSES its selfhosted sandbox — never a duplicate.\nasync function finalizeEnrollmentInScope(scopedDb: Database, input: {\n accountId: string;\n workspaceId: string;\n pubkey: string;\n hasDisplay: boolean;\n allowScreenControl: boolean;\n os: EnrollmentOs;\n arch: string;\n sandboxName: string;\n now: Date;\n}): Promise<{ enrollment: EnrollmentRecord; sandbox: SandboxRecord }> {\n // createEnrollment (idempotent upsert) — whole-machine is mandatory; display +\n // screen-control come from the agent's offer + the consenting decision. We inline\n // the insert here (rather than calling createEnrollment, which opens its OWN\n // scope) so it shares the caller's transaction.\n const [enrollmentRow] = await scopedDb.insert(schema.enrollments).values({\n accountId: input.accountId,\n workspaceId: input.workspaceId,\n pubkey: input.pubkey,\n exposure: \"whole-machine\",\n hasDisplay: input.hasDisplay,\n allowScreenControl: input.allowScreenControl,\n os: input.os,\n arch: input.arch,\n status: \"active\",\n }).onConflictDoUpdate({\n target: [schema.enrollments.workspaceId, schema.enrollments.pubkey],\n set: {\n exposure: \"whole-machine\",\n hasDisplay: input.hasDisplay,\n allowScreenControl: input.allowScreenControl,\n os: input.os,\n arch: input.arch,\n status: \"active\",\n revokedAt: null,\n updatedAt: input.now,\n },\n }).returning();\n if (!enrollmentRow) {\n throw new Error(\"Failed to create enrollment during finalize\");\n }\n const enrollment = mapEnrollment(enrollmentRow);\n\n // Ensure a selfhosted sandbox for this enrollment. A re-finalize of the SAME\n // machine reuses the existing sandbox rather than creating a duplicate.\n const [existingSandbox] = await scopedDb.select().from(schema.sandboxes)\n .where(and(\n eq(schema.sandboxes.workspaceId, input.workspaceId),\n eq(schema.sandboxes.enrollmentId, enrollment.id),\n ))\n .limit(1);\n let sandbox: SandboxRecord;\n if (existingSandbox) {\n sandbox = mapSandbox(existingSandbox);\n } else {\n const [sandboxRow] = await scopedDb.insert(schema.sandboxes).values({\n accountId: input.accountId,\n workspaceId: input.workspaceId,\n kind: \"selfhosted\",\n name: input.sandboxName,\n enrollmentId: enrollment.id,\n }).returning();\n if (!sandboxRow) {\n throw new Error(\"Failed to create sandbox during finalize\");\n }\n sandbox = mapSandbox(sandboxRow);\n }\n return { enrollment, sandbox };\n}\n\n// FINALIZE a headless enroll-token exchange (design 11 §A2.3). Produces the SAME\n// end state as approveDeviceEnrollmentRequest — an enrollments row + a selfhosted\n// sandbox row — but WITHOUT a pending device-flow request (a stateless `oget_`\n// token carries the grant). Idempotent via the shared finalize core's upsert.\nexport async function finalizeEnrollmentByToken(db: Database, input: {\n accountId: string;\n workspaceId: string;\n pubkey: string;\n hasDisplay: boolean;\n allowScreenControl: boolean;\n os: EnrollmentOs;\n arch: string;\n sandboxName: string;\n now?: Date;\n}): Promise<{ enrollment: EnrollmentRecord; sandbox: SandboxRecord }> {\n const now = input.now ?? new Date();\n return await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId }, async (scopedDb) => {\n return await finalizeEnrollmentInScope(scopedDb, {\n accountId: input.accountId,\n workspaceId: input.workspaceId,\n pubkey: input.pubkey,\n hasDisplay: input.hasDisplay,\n allowScreenControl: input.allowScreenControl,\n os: input.os,\n arch: input.arch,\n sandboxName: input.sandboxName,\n now,\n });\n });\n}\n\n// THE LOUD-CONSENT APPROVE (the user's POST /approve). In ONE transaction:\n// 1. re-read the pending row FOR UPDATE (fence against a double-approve / a\n// concurrent expiry),\n// 2. createEnrollment (idempotent upsert: pubkey, whole-machine exposure,\n// has_display from can_offer_display, allow_screen_control per the user's\n// decision, os/arch) → an enrollments row,\n// 3. createSandbox (kind selfhosted, enrollment_id, a generated name) → a\n// sandboxes row (acceptance #2),\n// 4. stamp the request approved + the consent record (WHO approved WHEN to WHAT)\n// + the resulting enrollment_id / sandbox_id.\n// IDEMPOTENT: a re-approve of an ALREADY-approved row (same user_code re-submitted)\n// re-runs the enrollment upsert (M2 reactivate semantics) and returns the existing\n// enrollment/sandbox — never a duplicate. An expired / denied / consumed row is a\n// no-op (approved:false). Returns the enrollment + sandbox so the route echoes them.\nexport async function approveDeviceEnrollmentRequest(db: Database, input: {\n accountId: string;\n workspaceId: string;\n requestId: string;\n allowScreenControl: boolean;\n approvedBySubjectId: string;\n approvedBySubjectLabel?: string | null;\n // A name for the generated sandbox (machine name or a fallback).\n sandboxName: string;\n now?: Date;\n}): Promise<{ approved: boolean; enrollment: EnrollmentRecord | null; sandbox: SandboxRecord | null }> {\n const now = input.now ?? new Date();\n return await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId }, async (scopedDb) => {\n // Re-read FOR UPDATE under the txn so a concurrent approve / expiry can't race.\n const [pending] = await scopedDb.select().from(schema.deviceEnrollmentRequests)\n .where(and(\n eq(schema.deviceEnrollmentRequests.workspaceId, input.workspaceId),\n eq(schema.deviceEnrollmentRequests.id, input.requestId),\n ))\n .for(\"update\")\n .limit(1);\n if (!pending) {\n return { approved: false, enrollment: null, sandbox: null };\n }\n // Already terminally approved → idempotent return of the existing rows (re-run\n // the consent fields in case allow_screen_control changed on re-approve).\n const expired = pending.expiresAt.getTime() <= now.getTime();\n if (pending.status === \"denied\" || pending.status === \"consumed\") {\n return { approved: false, enrollment: null, sandbox: null };\n }\n if (pending.status === \"pending\" && expired) {\n return { approved: false, enrollment: null, sandbox: null };\n }\n\n // The SHARED finalize core: upsert the enrollment (idempotent) + ensure a\n // selfhosted sandbox. RLS is already set on scopedDb's session and this call\n // runs INSIDE this FOR-UPDATE txn, so the re-read fence + the stamp below + the\n // enrollment/sandbox writes all commit atomically (semantics unchanged from the\n // pre-refactor inline block — acceptance #2 stays one machine). The headless\n // token exchange (finalizeEnrollmentByToken) calls the SAME core.\n const { enrollment, sandbox } = await finalizeEnrollmentInScope(scopedDb, {\n accountId: input.accountId,\n workspaceId: input.workspaceId,\n pubkey: pending.pubkey,\n hasDisplay: pending.canOfferDisplay,\n allowScreenControl: input.allowScreenControl,\n os: pending.os as EnrollmentOs,\n arch: pending.arch,\n sandboxName: input.sandboxName,\n now,\n });\n\n // Stamp the request approved + the LOUD CONSENT record (who/when/what).\n await scopedDb.update(schema.deviceEnrollmentRequests)\n .set({\n status: \"approved\",\n allowScreenControl: input.allowScreenControl,\n approvedBySubjectId: input.approvedBySubjectId,\n approvedBySubjectLabel: input.approvedBySubjectLabel ?? null,\n approvedAt: now,\n enrollmentId: enrollment.id,\n sandboxId: sandbox.id,\n updatedAt: now,\n })\n .where(eq(schema.deviceEnrollmentRequests.id, pending.id));\n\n return { approved: true, enrollment, sandbox };\n });\n}\n\n// Mark a pending request DENIED (an explicit user \"no\" at the approve page).\n// Idempotent: a non-pending row is a no-op (denied:false).\nexport async function denyDeviceEnrollmentRequest(db: Database, input: {\n accountId: string; workspaceId: string; requestId: string;\n}): Promise<{ denied: boolean }> {\n return await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId }, async (scopedDb) => {\n const rows = await scopedDb.update(schema.deviceEnrollmentRequests)\n .set({ status: \"denied\", updatedAt: new Date() })\n .where(and(\n eq(schema.deviceEnrollmentRequests.workspaceId, input.workspaceId),\n eq(schema.deviceEnrollmentRequests.id, input.requestId),\n eq(schema.deviceEnrollmentRequests.status, \"pending\"),\n ))\n .returning({ id: schema.deviceEnrollmentRequests.id });\n return { denied: rows.length > 0 };\n });\n}\n\n// Flip an APPROVED request to CONSUMED once the agent has polled its credentials\n// (single-use). Fenced on status='approved' so a double-poll consumes exactly once;\n// a second poll then re-reads the consumed row and still returns credentials (the\n// agent may legitimately retry the same poll) — the route decides. Returns whether\n// THIS call performed the consume transition.\nexport async function consumeDeviceEnrollmentRequest(db: Database, input: {\n accountId: string; workspaceId: string; requestId: string;\n}): Promise<{ consumed: boolean }> {\n return await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId }, async (scopedDb) => {\n const rows = await scopedDb.update(schema.deviceEnrollmentRequests)\n .set({ status: \"consumed\", updatedAt: new Date() })\n .where(and(\n eq(schema.deviceEnrollmentRequests.workspaceId, input.workspaceId),\n eq(schema.deviceEnrollmentRequests.id, input.requestId),\n eq(schema.deviceEnrollmentRequests.status, \"approved\"),\n ))\n .returning({ id: schema.deviceEnrollmentRequests.id });\n return { consumed: rows.length > 0 };\n });\n}\n\n// ---- sandboxes ------------------------------------------------------------\n\n// Create a first-class named sandbox (the pointer target a session swaps to). The\n// DB CHECK pins selfhosted<->enrollment_id: a selfhosted sandbox MUST carry an\n// enrollment; a modal sandbox MUST NOT. We surface that as a typed pre-check so\n// the caller gets a clear error rather than a raw constraint violation.\nexport async function createSandbox(db: Database, input: {\n accountId: string;\n workspaceId: string;\n kind: SandboxKind;\n name: string;\n enrollmentId?: string | null;\n}): Promise<SandboxRecord> {\n const enrollmentId = input.enrollmentId ?? null;\n if (input.kind === \"selfhosted\" && !enrollmentId) {\n throw new Error(\"A selfhosted sandbox requires an enrollmentId.\");\n }\n if (input.kind !== \"selfhosted\" && enrollmentId) {\n throw new Error(`A ${input.kind} sandbox must not carry an enrollmentId.`);\n }\n return await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId }, async (scopedDb) => {\n const [row] = await scopedDb.insert(schema.sandboxes).values({\n accountId: input.accountId,\n workspaceId: input.workspaceId,\n kind: input.kind,\n name: input.name,\n enrollmentId,\n }).returning();\n if (!row) {\n throw new Error(\"Failed to create sandbox\");\n }\n return mapSandbox(row);\n });\n}\n\nexport async function getSandbox(db: Database, workspaceId: string, sandboxId: string): Promise<SandboxRecord | null> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const [row] = await scopedDb.select().from(schema.sandboxes)\n .where(and(eq(schema.sandboxes.workspaceId, workspaceId), eq(schema.sandboxes.id, sandboxId)))\n .limit(1);\n return row ? mapSandbox(row) : null;\n });\n}\n\n// List a workspace's sandboxes, newest first (the sandboxes_list tool surface).\nexport async function listSandboxes(db: Database, workspaceId: string): Promise<SandboxRecord[]> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const rows = await scopedDb.select().from(schema.sandboxes)\n .where(eq(schema.sandboxes.workspaceId, workspaceId))\n .orderBy(desc(schema.sandboxes.createdAt));\n return rows.map(mapSandbox);\n });\n}\n\n// ---- the per-session active-sandbox pointer (epoch-fenced swap) -----------\n\nexport type ActiveSandboxPointer = {\n activeSandboxId: string | null;\n activeEpoch: number;\n // The session's working directory (the path/cwd base for a selfhosted backend),\n // surfaced alongside the pointer. NULL ⇒ the default workspace_root behavior.\n workingDir: string | null;\n};\n\n// Read the session's current pointer (the routing proxy re-reads this PER TOOL\n// CALL). NULL active_sandbox_id == \"use the session's own group sandbox\".\nexport async function readActiveSandbox(db: Database, workspaceId: string, sessionId: string): Promise<ActiveSandboxPointer | null> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const [row] = await scopedDb.select({\n activeSandboxId: schema.sessions.activeSandboxId,\n activeEpoch: schema.sessions.activeEpoch,\n workingDir: schema.sessions.workingDir,\n }).from(schema.sessions)\n .where(and(eq(schema.sessions.workspaceId, workspaceId), eq(schema.sessions.id, sessionId)))\n .limit(1);\n if (!row) {\n return null;\n }\n return { activeSandboxId: row.activeSandboxId ?? null, activeEpoch: Number(row.activeEpoch), workingDir: row.workingDir ?? null };\n });\n}\n\n// THE SWAP. Repoint a session at `targetSandboxId` (NULL == back to the group\n// sandbox) and BUMP active_epoch under a fence: the write is gated on the\n// session's current active_epoch == expectedEpoch, so a concurrent double-swap\n// (two callers both reading epoch N) lets exactly ONE win — the loser sees\n// swapped:false and re-reads. The bumped epoch fences any in-flight op cached\n// against the old pointer, which then retries against the new active sandbox.\n// integer epoch returns a JS number; Number()-coerced defensively (lease lesson).\nexport async function setActiveSandbox(db: Database, input: {\n accountId: string;\n workspaceId: string;\n sessionId: string;\n targetSandboxId: string | null;\n expectedEpoch: number;\n // The session's working directory to write alongside the pointer. OMITTED\n // (undefined) ⇒ the column is left UNCHANGED (a plain swap/attach never touches\n // it); a string sets it; null clears it back to the default. Per-session\n // working dir is seeded create-time through this CAS, not the row INSERT.\n workingDir?: string | null;\n}): Promise<{ swapped: boolean; pointer: ActiveSandboxPointer | null }> {\n return await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId }, async (scopedDb) => {\n const rows = await scopedDb.execute<{ active_sandbox_id: string | null; active_epoch: number | string; working_dir: string | null }>(sql`\n update sessions set\n active_sandbox_id = ${input.targetSandboxId},\n active_epoch = active_epoch + 1,\n working_dir = ${input.workingDir === undefined ? sql`working_dir` : input.workingDir},\n updated_at = now()\n where workspace_id = ${input.workspaceId} and id = ${input.sessionId}\n and active_epoch = ${input.expectedEpoch}\n returning active_sandbox_id, active_epoch, working_dir\n `);\n const row = rows[0];\n if (!row) {\n return { swapped: false, pointer: null };\n }\n return {\n swapped: true,\n pointer: { activeSandboxId: row.active_sandbox_id ?? null, activeEpoch: Number(row.active_epoch), workingDir: row.working_dir ?? null },\n };\n });\n}\n\n// ---- per-machine metrics (§10.7) ------------------------------------------\n\n// The sampled signal set the agent piggybacks on the heartbeat. Every field is\n// optional (a platform/sample may not provide it — no GPU, headless, etc.).\nexport type MachineMetricsSample = {\n cpuPercent?: number | null;\n load1?: number | null;\n load5?: number | null;\n load15?: number | null;\n memUsedBytes?: number | null;\n memTotalBytes?: number | null;\n diskUsedBytes?: number | null;\n diskTotalBytes?: number | null;\n gpuUtilPercent?: number | null;\n gpuMemUsedBytes?: number | null;\n gpuMemTotalBytes?: number | null;\n contention?: number | null;\n sampledAt: Date;\n};\n\nfunction metricColumns(sample: MachineMetricsSample) {\n return {\n cpuPercent: sample.cpuPercent ?? null,\n load1: sample.load1 ?? null,\n load5: sample.load5 ?? null,\n load15: sample.load15 ?? null,\n memUsedBytes: sample.memUsedBytes ?? null,\n memTotalBytes: sample.memTotalBytes ?? null,\n diskUsedBytes: sample.diskUsedBytes ?? null,\n diskTotalBytes: sample.diskTotalBytes ?? null,\n gpuUtilPercent: sample.gpuUtilPercent ?? null,\n gpuMemUsedBytes: sample.gpuMemUsedBytes ?? null,\n gpuMemTotalBytes: sample.gpuMemTotalBytes ?? null,\n contention: sample.contention ?? null,\n sampledAt: sample.sampledAt,\n };\n}\n\n// Last-sample UPSERT: one row per enrollment, overwritten every sample (PK on\n// enrollment_id is the conflict target). The Machines dashboard's \"now\" read.\nexport async function upsertMachineMetricsLatest(db: Database, input: {\n accountId: string; workspaceId: string; enrollmentId: string; sample: MachineMetricsSample;\n}): Promise<void> {\n await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId }, async (scopedDb) => {\n const cols = metricColumns(input.sample);\n await scopedDb.insert(schema.machineMetricsLatest).values({\n enrollmentId: input.enrollmentId,\n accountId: input.accountId,\n workspaceId: input.workspaceId,\n ...cols,\n }).onConflictDoUpdate({\n target: schema.machineMetricsLatest.enrollmentId,\n set: { ...cols, updatedAt: new Date() },\n });\n });\n}\n\n// Append a downsampled (~1/min) series row (the history the dashboard time-range\n// reads + the later retention sweep prune).\nexport async function insertMachineMetricsSeries(db: Database, input: {\n accountId: string; workspaceId: string; enrollmentId: string; sample: MachineMetricsSample;\n}): Promise<void> {\n await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId }, async (scopedDb) => {\n await scopedDb.insert(schema.machineMetricsSeries).values({\n enrollmentId: input.enrollmentId,\n accountId: input.accountId,\n workspaceId: input.workspaceId,\n ...metricColumns(input.sample),\n });\n });\n}\n\n// The target spacing between series rows: the agent heartbeats ~every 5s, but we\n// downsample the long-term history to ~1/min (dossier §10.7). A new series row is\n// appended only when >= this much time has elapsed since the last one.\nexport const MACHINE_METRICS_SERIES_INTERVAL_MS = 60_000;\n\n/**\n * Ingest ONE sampled metrics point for an enrollment (the M10 ingestion seam):\n * 1. UPSERT machine_metrics_latest (the \"now\" row, one per enrollment) — always.\n * 2. APPEND a machine_metrics_series row only when >= ~1/min has elapsed since\n * the last series row (downsample) — so the 5s heartbeat cadence does not\n * flood the history table.\n * Both happen under the same RLS context. Returns whether a series row was\n * appended (the downsample decision) so the caller / tests can assert the ~1/min\n * spacing. A null/absent `sampledAt` on the prior row treats it as \"no prior\" →\n * append.\n */\nexport async function ingestMachineMetricsSample(db: Database, input: {\n accountId: string; workspaceId: string; enrollmentId: string; sample: MachineMetricsSample;\n /** Override the downsample interval (tests). Defaults to ~1/min. */\n seriesIntervalMs?: number;\n}): Promise<{ latestUpserted: true; seriesAppended: boolean }> {\n return await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId }, async (scopedDb) => {\n const cols = metricColumns(input.sample);\n // 1. Latest upsert — always.\n await scopedDb.insert(schema.machineMetricsLatest).values({\n enrollmentId: input.enrollmentId,\n accountId: input.accountId,\n workspaceId: input.workspaceId,\n ...cols,\n }).onConflictDoUpdate({\n target: schema.machineMetricsLatest.enrollmentId,\n set: { ...cols, updatedAt: new Date() },\n });\n\n // 2. Series append — downsampled. Read the most recent series sampled_at and\n // only append when the new sample is >= the interval newer (or there is no\n // prior row). Done in-context so RLS scopes the read to this workspace.\n const intervalMs = input.seriesIntervalMs ?? MACHINE_METRICS_SERIES_INTERVAL_MS;\n const [prior] = await scopedDb.select({ sampledAt: schema.machineMetricsSeries.sampledAt })\n .from(schema.machineMetricsSeries)\n .where(eq(schema.machineMetricsSeries.enrollmentId, input.enrollmentId))\n .orderBy(desc(schema.machineMetricsSeries.sampledAt))\n .limit(1);\n const priorMs = prior?.sampledAt ? prior.sampledAt.getTime() : null;\n const sampleMs = input.sample.sampledAt.getTime();\n const seriesAppended = priorMs === null || sampleMs - priorMs >= intervalMs;\n if (seriesAppended) {\n await scopedDb.insert(schema.machineMetricsSeries).values({\n enrollmentId: input.enrollmentId,\n accountId: input.accountId,\n workspaceId: input.workspaceId,\n ...cols,\n });\n }\n return { latestUpserted: true, seriesAppended };\n });\n}\n\n// The mapped read shape of a stored metrics sample (latest or a series point).\n// numeric columns come back as strings from postgres-js; map them to numbers (or\n// null when never reported). The byte columns are bigint(mode:\"number\").\nexport type MachineMetricsRow = {\n enrollmentId: string;\n cpuPercent: number | null;\n load1: number | null;\n load5: number | null;\n load15: number | null;\n memUsedBytes: number | null;\n memTotalBytes: number | null;\n diskUsedBytes: number | null;\n diskTotalBytes: number | null;\n gpuUtilPercent: number | null;\n gpuMemUsedBytes: number | null;\n gpuMemTotalBytes: number | null;\n contention: number | null;\n sampledAt: string;\n};\n\nfunction numericOrNull(value: unknown): number | null {\n if (value === null || value === undefined) return null;\n const n = typeof value === \"number\" ? value : Number(value);\n return Number.isFinite(n) ? n : null;\n}\n\nfunction mapMetricsRow(row: {\n enrollmentId: string;\n cpuPercent: number | string | null;\n load1: number | string | null;\n load5: number | string | null;\n load15: number | string | null;\n memUsedBytes: number | null;\n memTotalBytes: number | null;\n diskUsedBytes: number | null;\n diskTotalBytes: number | null;\n gpuUtilPercent: number | string | null;\n gpuMemUsedBytes: number | null;\n gpuMemTotalBytes: number | null;\n contention: number | string | null;\n sampledAt: Date;\n}): MachineMetricsRow {\n return {\n enrollmentId: row.enrollmentId,\n cpuPercent: numericOrNull(row.cpuPercent),\n load1: numericOrNull(row.load1),\n load5: numericOrNull(row.load5),\n load15: numericOrNull(row.load15),\n memUsedBytes: row.memUsedBytes ?? null,\n memTotalBytes: row.memTotalBytes ?? null,\n diskUsedBytes: row.diskUsedBytes ?? null,\n diskTotalBytes: row.diskTotalBytes ?? null,\n gpuUtilPercent: numericOrNull(row.gpuUtilPercent),\n gpuMemUsedBytes: row.gpuMemUsedBytes ?? null,\n gpuMemTotalBytes: row.gpuMemTotalBytes ?? null,\n contention: numericOrNull(row.contention),\n sampledAt: row.sampledAt.toISOString(),\n };\n}\n\n// Read the latest sample for ONE enrollment (the dashboard \"now\" read), or null\n// when none has landed (never seen / offline before a first heartbeat).\nexport async function readMachineMetricsLatest(db: Database, workspaceId: string, enrollmentId: string): Promise<MachineMetricsRow | null> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const [row] = await scopedDb.select().from(schema.machineMetricsLatest)\n .where(and(\n eq(schema.machineMetricsLatest.workspaceId, workspaceId),\n eq(schema.machineMetricsLatest.enrollmentId, enrollmentId),\n ))\n .limit(1);\n return row ? mapMetricsRow(row) : null;\n });\n}\n\n// Read the latest sample for EVERY enrollment in a workspace, keyed by\n// enrollmentId — the Machines list joins this onto the fleet entries with ONE\n// query rather than N per-machine reads.\nexport async function readMachineMetricsLatestForWorkspace(db: Database, workspaceId: string): Promise<Map<string, MachineMetricsRow>> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const rows = await scopedDb.select().from(schema.machineMetricsLatest)\n .where(eq(schema.machineMetricsLatest.workspaceId, workspaceId));\n const byEnrollment = new Map<string, MachineMetricsRow>();\n for (const row of rows) {\n byEnrollment.set(row.enrollmentId, mapMetricsRow(row));\n }\n return byEnrollment;\n });\n}\n\n// Read the downsampled series for ONE enrollment over a time window (the\n// dashboard time-range read). `sinceMs` bounds the window (e.g. now - 1h);\n// ordered oldest-first for a left-to-right chart. `limit` caps the row count\n// (defensive against an unbounded window).\nexport async function readMachineMetricsSeries(db: Database, input: {\n workspaceId: string; enrollmentId: string; since: Date; limit?: number;\n}): Promise<MachineMetricsRow[]> {\n return await withWorkspaceRls(db, input.workspaceId, async (scopedDb) => {\n const rows = await scopedDb.select().from(schema.machineMetricsSeries)\n .where(and(\n eq(schema.machineMetricsSeries.workspaceId, input.workspaceId),\n eq(schema.machineMetricsSeries.enrollmentId, input.enrollmentId),\n gte(schema.machineMetricsSeries.sampledAt, input.since),\n ))\n .orderBy(asc(schema.machineMetricsSeries.sampledAt))\n .limit(input.limit ?? 5_000);\n return rows.map(mapMetricsRow);\n });\n}\n\n// ============================================================================\n// P3.2 — the un-redacted-pixel consent gate + viewer revocation.\n//\n// The desktop-stream path is gated behind an explicit acknowledgment that the\n// pixel plane is un-redacted (it can show cloud creds the agent cat's into a\n// terminal — strictly broader than the redacted Channel-A event log). For a\n// SHARED box (the group has >1 session) the principal must additionally consent\n// to the shared-exposure disclosure: watching A's desktop also shows B's agent\n// on the one :0 framebuffer (addendum E.1 / stress g). Consent is per-PRINCIPAL\n// and per-GROUP (one :0 per group), recorded in session_stream_acknowledgments\n// (0019). Reuses the acknowledgment machinery — no new permission beyond\n// stream:acknowledge.\n// ============================================================================\n\nexport interface StreamAcknowledgment {\n acknowledgedUnredacted: boolean;\n acknowledgedShared: boolean;\n}\n\n// Record (or upsert) a principal's acknowledgment of the group's un-redacted\n// pixel plane (and, when shared, the shared-exposure disclosure). Keyed on\n// (workspace, group, subject); a re-ack (e.g. a solo→shared upgrade adding the\n// shared consent) is ON CONFLICT DO UPDATE, never a duplicate row.\nexport async function recordStreamAcknowledgment(db: Database, input: {\n accountId: string;\n workspaceId: string;\n sandboxGroupId: string;\n subjectId: string;\n acknowledgeUnredacted: boolean;\n acknowledgeShared: boolean;\n}): Promise<StreamAcknowledgment> {\n return await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId },\n async (scopedDb) => {\n const rows = await scopedDb.execute<{ acknowledged_unredacted: boolean; acknowledged_shared: boolean }>(sql`\n insert into session_stream_acknowledgments\n (account_id, workspace_id, sandbox_group_id, subject_id,\n acknowledged_unredacted, acknowledged_shared, acknowledged_at, updated_at)\n values\n (${input.accountId}, ${input.workspaceId}, ${input.sandboxGroupId}, ${input.subjectId},\n ${input.acknowledgeUnredacted}, ${input.acknowledgeShared}, now(), now())\n on conflict (workspace_id, sandbox_group_id, subject_id) do update set\n -- Acknowledgment is monotonic: a later ack can ADD the shared consent\n -- but never silently withdraw a prior one (OR the bits in).\n acknowledged_unredacted = session_stream_acknowledgments.acknowledged_unredacted or excluded.acknowledged_unredacted,\n acknowledged_shared = session_stream_acknowledgments.acknowledged_shared or excluded.acknowledged_shared,\n acknowledged_at = now(),\n updated_at = now()\n returning acknowledged_unredacted, acknowledged_shared\n `);\n const row = rows[0]!;\n return { acknowledgedUnredacted: row.acknowledged_unredacted, acknowledgedShared: row.acknowledged_shared };\n });\n}\n\n// Read a principal's recorded acknowledgment for a group, or null if they have\n// never acknowledged the un-redacted pixel plane. The negotiation read + the\n// desktop-stream gate both consult this.\nexport async function getStreamAcknowledgment(db: Database, input: {\n workspaceId: string;\n sandboxGroupId: string;\n subjectId: string;\n}): Promise<StreamAcknowledgment | null> {\n return await withWorkspaceRls(db, input.workspaceId, async (scopedDb) => {\n const rows = await scopedDb.execute<{ acknowledged_unredacted: boolean; acknowledged_shared: boolean }>(sql`\n select acknowledged_unredacted, acknowledged_shared\n from session_stream_acknowledgments\n where workspace_id = ${input.workspaceId}\n and sandbox_group_id = ${input.sandboxGroupId}\n and subject_id = ${input.subjectId}\n limit 1\n `);\n if (!rows[0]) return null;\n return { acknowledgedUnredacted: rows[0].acknowledged_unredacted, acknowledgedShared: rows[0].acknowledged_shared };\n });\n}\n\n// Enumerate the session ids in a group (workspace-scoped). The shared-exposure\n// disclosure surfaces the OTHER sessions' ids ONLY — never their goal/metadata/\n// conversation. The query selects ONLY the id column (id is the disclosure\n// boundary; stress g). RLS-scoped: a foreign-workspace group returns no rows.\nexport async function listSessionIdsInGroup(db: Database, workspaceId: string, sandboxGroupId: string): Promise<string[]> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const rows = await rawRows<{ id: string }>(scopedDb, sql`\n select id from sessions\n where workspace_id = ${workspaceId} and sandbox_group_id = ${sandboxGroupId}\n order by created_at asc\n `);\n return rows.map((r) => r.id);\n });\n}\n\n// OD-6 v1 — revoke a viewer: DROP that viewer's holder from the GROUP lease so\n// refcount recomputes (the box drains iff nothing else holds it — a turn-held or\n// other-viewer-held box survives), AND block its reconnect by recording the\n// revoked subject so a re-attach with the same viewerId is refused. The\n// live-RFB force-disconnect of an already-open socket is a P4 follow-up; the\n// holder-drop (so the box can drain) is here.\n//\n// Returns the post-drop lease liveness/refcount (null if the lease was already\n// cold-and-reaped — a revoke is then an idempotent no-op). A revoked viewer who\n// independently holds a holder on a SIBLING session may still watch via that\n// session (correct — authorized there); this drops ONLY the named viewerId's\n// holder.\nexport async function revokeViewer(db: Database, input: {\n accountId: string;\n workspaceId: string;\n sandboxGroupId: string;\n viewerId: string;\n idleGraceMs: number;\n}): Promise<{ liveness: SandboxLeaseLiveness; refcount: number } | null> {\n // The drop is exactly releaseLeaseHolder's idempotent delete-my-row +\n // recompute (refcount recomputes; warm→draining is guarded refcount=0 AND\n // turn_holders=0, so a turn-held box never drains on a viewer revoke). The\n // reconnect-block is a P4 concern (the holder-drop is the v1 deliverable —\n // the box can now drain); a re-attach mints a fresh viewerId regardless.\n return await releaseLeaseHolder(db, {\n accountId: input.accountId,\n workspaceId: input.workspaceId,\n sandboxGroupId: input.sandboxGroupId,\n kind: \"viewer\",\n holderId: input.viewerId,\n idleGraceMs: input.idleGraceMs,\n });\n}\n\n// ============================================================================\n// Warm-time metering (P2.1) — the COST hole the lease design opens.\n//\n// A box held warm by a viewer with no agent turn running emits ZERO model usage\n// today; the provider bills by wall-clock and OpenGeni meters nothing. Warm-time\n// accrues on TWO stateless ticks: (a) the turn's existing activity heartbeat\n// (while a turn runs); (b) the reaper sweep (for viewer-only boxes between turns).\n//\n// The meter is GROUP-KEYED + epoch-keyed + tick-keyed:\n// idempotencyKey = usage:sandbox.warm_seconds:<group>:<epoch>:<tick>\n// so a SHARED box (N sessions on one group) is metered EXACTLY ONCE per tick\n// (N sessions != N x bill — a session-keyed meter would N x-over-bill), and a\n// re-dispatched/overlapping tick at the same (group,epoch,tick) can never\n// double-charge (recordUsageEvent is onConflictDoNothing on idempotencyKey).\n//\n// Cursor advance + usage insert are ATOMIC: both run inside ONE FOR UPDATE txn on\n// the lease row (the M3 cross-statement-atomicity fix). The insert uses ON\n// CONFLICT DO NOTHING on idempotency_key (matching recordUsageEvent), and the\n// cursor (last_meter_at/last_meter_tick) is advanced in the SAME txn — so the tick\n// index and the metered seconds can never desync, and a partial-failure rollback\n// leaves BOTH the cursor and the event untouched.\n// ============================================================================\n\nexport interface AccrueWarmSecondsResult {\n /** false when nothing was accrued (epoch fenced / not warm / no elapsed / the\n * first tick that only seeds the cursor). */\n accrued: boolean;\n /** Whole seconds metered this tick (0 when accrued:false). */\n seconds: number;\n /** The monotonic tick index this accrual was recorded under. */\n tick: number;\n /** usd_micros charged for this tick (0 when rate is 0). */\n costMicros: number;\n}\n\n/**\n * Accrue warm-seconds for the elapsed wall-clock since the lease's last meter\n * cursor, idempotent on (sandbox_group_id, lease_epoch, tick). EPOCH-FENCED +\n * liveness-guarded (warm only): a stale-epoch tick or a draining/cold lease is a\n * no-op, so a superseded writer that re-fires cannot mis-meter. The FIRST tick on\n * a never-metered lease (last_meter_at IS NULL) only SEEDS the cursor — it\n * accrues nothing (there is no prior cursor to diff against), matching the\n * \"delta since last tick\" contract. warmRateMicrosPerSecond > 0 also records a\n * sandbox.warm_cost event (cost = seconds x rate) AND debits the same micros from\n * the credit balance via applyCreditDebitUpToBalance (the model-cost precedent),\n * idempotent on the SAME (group, epoch, tick) key. The usage event is the\n * REQUESTED cost; the ledger is the ACTUAL debit (they legitimately differ when\n * balance is low — M2). Set debitCredits:false to meter without debiting.\n */\nexport async function accrueWarmSeconds(db: Database, input: {\n accountId: string;\n workspaceId: string;\n sandboxGroupId: string;\n /** The epoch the tick observed; the fence — a stale writer no-ops. */\n expectedEpoch: number;\n /** usd_micros per warm-second for this box's backend (0 = meter only, no cost). */\n warmRateMicrosPerSecond: number;\n /** Optional attribution: the founding/observing session (visibility only — the\n * group meter key makes the workspace charge correct regardless). */\n subjectId?: string | null;\n /** Debit credits for warm-cost (default true). The force-drain at 0 balance\n * depends on this decrementing the balance. */\n debitCredits?: boolean;\n}): Promise<AccrueWarmSecondsResult> {\n const none: AccrueWarmSecondsResult = { accrued: false, seconds: 0, tick: 0, costMicros: 0 };\n const result = await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId },\n async (scopedDb) => await scopedDb.transaction(async (txRaw) => {\n const tx = txRaw as unknown as Database;\n // Lock the group's lease row so the cursor advance + the usage insert are\n // one atomic step (no other tick can interleave between the diff and the\n // cursor write).\n const rows = await tx.execute<LeaseRow & { meter_elapsed_s: number | null }>(sql`\n select *,\n case when last_meter_at is null then null\n else floor(extract(epoch from (now() - last_meter_at)))::int end as meter_elapsed_s\n from sandbox_leases\n where workspace_id = ${input.workspaceId} and sandbox_group_id = ${input.sandboxGroupId}\n for update\n `);\n const row = rows[0];\n if (!row) return none;\n\n // Epoch fence + liveness guard: only a live-epoch warm box meters. A stale\n // (superseded) tick or a draining/cold/warming lease is a no-op.\n if (Number(row.lease_epoch) !== input.expectedEpoch || row.liveness !== \"warm\") {\n return none;\n }\n\n // First tick on a never-metered lease: SEED the cursor, accrue nothing.\n if (row.last_meter_at == null) {\n await tx.execute(sql`\n update sandbox_leases set last_meter_at = now(), updated_at = now()\n where id = ${row.id}\n `);\n return none;\n }\n\n const elapsedS = Number(row.meter_elapsed_s ?? 0);\n if (elapsedS <= 0) {\n // No whole second elapsed yet — leave the cursor untouched so the\n // remainder accrues on the next tick (no silent seconds loss).\n return none;\n }\n\n const tick = Number(row.last_meter_tick) + 1;\n const costMicros = Math.round(elapsedS * Math.max(0, input.warmRateMicrosPerSecond));\n\n // (1) The warm-seconds meter — GROUP+epoch+tick keyed, ON CONFLICT DO\n // NOTHING (the idempotency that makes a shared box one stream + a re-fire a\n // no-op). sourceResourceId is keyed on (group, epoch).\n await tx.execute(sql`\n insert into usage_events\n (account_id, workspace_id, subject_id, event_type, quantity, unit,\n source_resource_type, source_resource_id, idempotency_key, occurred_at)\n values\n (${input.accountId}, ${input.workspaceId}, ${input.subjectId ?? null},\n 'sandbox.warm_seconds', ${elapsedS}, 'seconds',\n 'sandbox_lease', ${`${input.sandboxGroupId}:${input.expectedEpoch}`},\n ${`usage:sandbox.warm_seconds:${input.sandboxGroupId}:${input.expectedEpoch}:${tick}`},\n now())\n on conflict (idempotency_key) do nothing\n `);\n\n // (2) The warm-cost meter (only when a rate is configured). Same keying.\n if (costMicros > 0) {\n await tx.execute(sql`\n insert into usage_events\n (account_id, workspace_id, subject_id, event_type, quantity, unit,\n source_resource_type, source_resource_id, idempotency_key, occurred_at)\n values\n (${input.accountId}, ${input.workspaceId}, ${input.subjectId ?? null},\n 'sandbox.warm_cost', ${costMicros}, 'usd_micros',\n 'sandbox_lease', ${`${input.sandboxGroupId}:${input.expectedEpoch}`},\n ${`usage:sandbox.warm_cost:${input.sandboxGroupId}:${input.expectedEpoch}:${tick}`},\n now())\n on conflict (idempotency_key) do nothing\n `);\n }\n\n // (3) Advance the cursor IN THE SAME TXN — the atomicity that makes the tick\n // index and the metered seconds inseparable.\n await tx.execute(sql`\n update sandbox_leases set\n last_meter_at = now(), last_meter_tick = ${tick}, updated_at = now()\n where id = ${row.id}\n `);\n\n return { accrued: true, seconds: elapsedS, tick, costMicros };\n }));\n\n // Debit credits for the warm-cost OUTSIDE the lease-row txn (applyCreditDebit\n // takes its own per-account advisory lock — never nest it under the lease row\n // lock). Idempotent on the SAME (group, epoch, tick) key so a re-fire of an\n // already-committed tick cannot double-debit. The ledger records the ACTUAL\n // debit (min(requested, balance)); the warm_cost usage event above is the\n // requested cost.\n if (result.accrued && result.costMicros > 0 && (input.debitCredits ?? true)) {\n await applyCreditDebitUpToBalance(db, {\n accountId: input.accountId,\n workspaceId: input.workspaceId,\n type: \"sandbox.warm_cost\",\n requestedAmountMicros: result.costMicros,\n sourceType: \"sandbox_lease\",\n sourceId: `${input.sandboxGroupId}:${input.expectedEpoch}`,\n idempotencyKey: `debit:sandbox.warm_cost:${input.sandboxGroupId}:${input.expectedEpoch}:${result.tick}`,\n }).catch(() => undefined);\n }\n\n return result;\n}\n\n// §2.2/2.3 — the per-workspace warm-cap + force-drain. Under the EXISTING usage\n// lock (withWorkspaceUsageLock — NOT a bare count, so two concurrent ticks in\n// different sessions of one workspace can't both read \"under cap\" and race past\n// it). A workspace at 0 balance OR over its warm-second cap force-drains its\n// VIEWER-ONLY boxes: CAS warm->draining guarded `AND turn_holders = 0` so a box\n// with a running (paying) turn is NEVER killed. The reaper then issues the\n// provider stop() at refcount 0 (this fn is DB-only — no provider call).\n//\n// Group-wide force-drain on workspace balance exhaustion is deliberate (one\n// balance drains a multi-session box): the workspace, not the session, is the\n// billing unit — correctness (charged once) is automatic from the group meter key.\nexport interface ForceDrainResult {\n /** Whether the workspace was over a limit (0 balance or over the warm cap). */\n overLimit: boolean;\n /** The reason, for observability. */\n reason: \"balance\" | \"warm_cap\" | null;\n /** The (workspaceId, sandboxGroupId) viewer-only boxes CASed warm->draining. */\n drained: { workspaceId: string; sandboxGroupId: string }[];\n}\n\n// Start of the current UTC month (the default warm-cap window). Local helper so\n// packages/db has no dependency on a worker/api date util; callers may override\n// via capWindowStart to keep the fn time-source-agnostic for tests.\nfunction startOfUtcMonthDefault(date = new Date()): Date {\n return new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), 1, 0, 0, 0, 0));\n}\n\nexport async function forceDrainOverLimitViewerOnlyBoxes(db: Database, input: {\n workspaceId: string;\n /** account balance gate: when <= 0 (and a billing/managed mode is on) drain. */\n balanceMicros: number;\n enforceBalance: boolean;\n /** warm-second cap (cumulative this UTC month). 0 = unbounded (no cap gate). */\n maxWarmSecondsPerWorkspace: number;\n /** start of the cap window (caller passes startOfUtcMonth() so the fn stays\n * time-source-agnostic for tests). */\n capWindowStart?: Date;\n /** drain-grace horizon stamped on the newly-draining rows (matches the reaper). */\n idleGraceMs: number;\n}): Promise<ForceDrainResult> {\n return await withWorkspaceUsageLock(db, input.workspaceId, async (scopedDb) => {\n // Determine over-limit under the lock (so the cap read + the drain are one\n // serialized critical section per workspace).\n let reason: \"balance\" | \"warm_cap\" | null = null;\n if (input.enforceBalance && input.balanceMicros <= 0) {\n reason = \"balance\";\n } else if (input.maxWarmSecondsPerWorkspace > 0) {\n const since = input.capWindowStart ?? startOfUtcMonthDefault();\n const [{ total } = { total: 0 }] = await scopedDb.select({\n total: sql<number>`coalesce(sum(${schema.usageEvents.quantity}), 0)`,\n }).from(schema.usageEvents).where(and(\n eq(schema.usageEvents.workspaceId, input.workspaceId),\n eq(schema.usageEvents.eventType, \"sandbox.warm_seconds\"),\n gt(schema.usageEvents.occurredAt, since),\n ));\n if (Number(total) >= input.maxWarmSecondsPerWorkspace) {\n reason = \"warm_cap\";\n }\n }\n\n if (!reason) {\n return { overLimit: false, reason: null, drained: [] };\n }\n\n // Force-drain VIEWER-ONLY warm boxes: CAS warm->draining guarded\n // turn_holders = 0 (a paying turn is NEVER killed). Stamp the grace deadline\n // so the reaper terminates at refcount 0 past the grace, exactly as a normal\n // refcount->0 drain would.\n // Drop the viewer holders of every warm VIEWER-ONLY lease (turn_holders=0 — a\n // paying turn is never killed) so refcount → 0 (otherwise the viewer holder\n // pins refcount > 0 and the reaper never terminates at refcount=0, and the\n // holder heartbeat would re-arm the lease). Scoped to the warm viewer-only\n // leases via a subselect so a turn-held box's holders are untouched.\n await scopedDb.execute(sql`\n delete from sandbox_lease_holders h\n where h.kind = 'viewer'\n and h.lease_id in (\n select id from sandbox_leases\n where workspace_id = ${input.workspaceId}\n and liveness = 'warm' and turn_holders = 0\n )\n `);\n // CAS the now-holderless leases warm→draining at refcount 0 with the grace\n // deadline stamped — so the SAME reaper sweep's refcount=0 drain predicate\n // then terminates the box.\n const drained = await rawRows<{ sandbox_group_id: string }>(scopedDb, sql`\n update sandbox_leases set\n liveness = 'draining',\n refcount = 0, turn_holders = 0, viewer_holders = 0,\n expires_at = now() + (${String(input.idleGraceMs)} || ' milliseconds')::interval,\n updated_at = now()\n where workspace_id = ${input.workspaceId}\n and liveness = 'warm' and turn_holders = 0\n returning sandbox_group_id\n `);\n\n return {\n overLimit: true,\n reason,\n drained: drained.map((r) => ({ workspaceId: input.workspaceId, sandboxGroupId: r.sandbox_group_id })),\n };\n });\n}\n\nexport async function saveRunState(db: Database, input: {\n accountId: string;\n workspaceId: string;\n sessionId: string;\n turnId?: string | null;\n serializedRunState: string;\n pendingApprovals: unknown[];\n // The codex account freezing this state (the turn's resolved credential id),\n // or null on a non-codex turn. Stamped so a resume on a DIFFERENT codex\n // account can strip the blob's account-bound reasoning. Defaults null so\n // every legacy caller (and the non-codex path) is byte-identical.\n frozenCodexCredentialId?: string | null;\n}): Promise<void> {\n await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId }, async (scopedDb) => {\n const [{ maxVersion } = { maxVersion: 0 }] = await scopedDb.select({\n maxVersion: sql<number>`coalesce(max(${schema.agentRunStates.stateVersion}), 0)`,\n }).from(schema.agentRunStates).where(and(eq(schema.agentRunStates.workspaceId, input.workspaceId), eq(schema.agentRunStates.sessionId, input.sessionId)));\n await scopedDb.insert(schema.agentRunStates).values({\n accountId: input.accountId,\n workspaceId: input.workspaceId,\n sessionId: input.sessionId,\n turnId: input.turnId ?? null,\n stateVersion: Number(maxVersion) + 1,\n serializedRunState: input.serializedRunState,\n pendingApprovals: input.pendingApprovals,\n frozenCodexCredentialId: input.frozenCodexCredentialId ?? null,\n });\n });\n}\n\nexport type CreateSessionGoalInput = {\n accountId: string;\n workspaceId: string;\n sessionId: string;\n text: string;\n successCriteria?: string | null;\n maxAutoContinuations?: number | null;\n createdBy: SessionGoalCreatedBy;\n};\n\nexport async function createSessionGoal(db: Database, input: CreateSessionGoalInput): Promise<SessionGoal> {\n return await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId }, async (scopedDb) => {\n const [row] = await scopedDb.insert(schema.sessionGoals).values({\n accountId: input.accountId,\n workspaceId: input.workspaceId,\n sessionId: input.sessionId,\n text: input.text,\n successCriteria: input.successCriteria ?? null,\n maxAutoContinuations: input.maxAutoContinuations ?? null,\n createdBy: input.createdBy,\n }).returning();\n if (!row) {\n throw new Error(\"Failed to create session goal\");\n }\n return mapSessionGoal(row);\n });\n}\n\nexport async function getSessionGoal(db: Database, workspaceId: string, sessionId: string): Promise<SessionGoal | null> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const [row] = await scopedDb.select().from(schema.sessionGoals)\n .where(and(eq(schema.sessionGoals.workspaceId, workspaceId), eq(schema.sessionGoals.sessionId, sessionId)))\n .limit(1);\n return row ? mapSessionGoal(row) : null;\n });\n}\n\n/**\n * goal_set semantics: insert, or replace the existing goal in place. A replace\n * re-activates the goal (even when paused or completed), bumps the version,\n * and resets the continuation counters — re-stating the objective re-arms the\n * auto-continuation budget.\n */\nexport async function upsertSessionGoal(db: Database, input: CreateSessionGoalInput): Promise<{ goal: SessionGoal; replaced: boolean }> {\n return await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId }, async (scopedDb) => {\n const [existing] = await scopedDb.select().from(schema.sessionGoals)\n .where(and(eq(schema.sessionGoals.workspaceId, input.workspaceId), eq(schema.sessionGoals.sessionId, input.sessionId)))\n .for(\"update\")\n .limit(1);\n if (!existing) {\n const [row] = await scopedDb.insert(schema.sessionGoals).values({\n accountId: input.accountId,\n workspaceId: input.workspaceId,\n sessionId: input.sessionId,\n text: input.text,\n successCriteria: input.successCriteria ?? null,\n maxAutoContinuations: input.maxAutoContinuations ?? null,\n createdBy: input.createdBy,\n }).returning();\n if (!row) {\n throw new Error(\"Failed to upsert session goal\");\n }\n return { goal: mapSessionGoal(row), replaced: false };\n }\n const [row] = await scopedDb.update(schema.sessionGoals).set({\n status: \"active\",\n text: input.text,\n successCriteria: input.successCriteria ?? null,\n maxAutoContinuations: input.maxAutoContinuations ?? null,\n evidence: null,\n rationale: null,\n pausedReason: null,\n createdBy: input.createdBy,\n version: existing.version + 1,\n autoContinuations: 0,\n noProgressStreak: 0,\n lastContinuationTurnId: null,\n versionAtLastContinuation: null,\n updatedAt: new Date(),\n }).where(eq(schema.sessionGoals.id, existing.id)).returning();\n if (!row) {\n throw new Error(\"Failed to upsert session goal\");\n }\n return { goal: mapSessionGoal(row), replaced: true };\n });\n}\n\n/**\n * goal_update semantics: revise text/criteria without changing status. The\n * version bump counts as progress for the no-progress detector.\n */\nexport async function updateSessionGoal(db: Database, workspaceId: string, sessionId: string, input: {\n text?: string;\n successCriteria?: string | null;\n}): Promise<SessionGoal> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const [row] = await scopedDb.update(schema.sessionGoals).set({\n ...(input.text !== undefined ? { text: input.text } : {}),\n ...(input.successCriteria !== undefined ? { successCriteria: input.successCriteria } : {}),\n version: sql`${schema.sessionGoals.version} + 1`,\n noProgressStreak: 0,\n updatedAt: new Date(),\n }).where(and(eq(schema.sessionGoals.workspaceId, workspaceId), eq(schema.sessionGoals.sessionId, sessionId))).returning();\n if (!row) {\n throw new Error(`Session goal not found: ${sessionId}`);\n }\n return mapSessionGoal(row);\n });\n}\n\n/**\n * Sets a session's display title. The clobber guard lives entirely in this\n * single atomic UPDATE: a user-set title is permanent, so agent/auto writes\n * carry an `AND title_source IS DISTINCT FROM 'user'` guard (NULL-safe in\n * Postgres) while user writes are unconditional. Never read-modify-write.\n * Returns `{ updated, title }`: `updated` is false when an agent write was\n * skipped because a user title already pinned the session, true otherwise;\n * `title` is the resulting title (null when skipped).\n */\nexport async function updateSessionTitle(db: Database, input: {\n workspaceId: string;\n sessionId: string;\n title: string;\n source: \"user\" | \"agent\";\n}): Promise<{ updated: boolean; title: string | null }> {\n return await withWorkspaceRls(db, input.workspaceId, async (scopedDb) => {\n const [row] = await scopedDb.update(schema.sessions).set({\n title: input.title,\n titleSource: input.source,\n updatedAt: new Date(),\n }).where(and(\n eq(schema.sessions.workspaceId, input.workspaceId),\n eq(schema.sessions.id, input.sessionId),\n ...(input.source === \"agent\" ? [sql`${schema.sessions.titleSource} is distinct from 'user'`] : []),\n )).returning({ title: schema.sessions.title });\n return { updated: Boolean(row), title: row?.title ?? null };\n });\n}\n\n/**\n * Status transition helper. Idempotent: requesting the current status returns\n * `changed: false` so callers can skip emitting a duplicate event. `completed`\n * is terminal for transitions; only `upsertSessionGoal` can replace a\n * completed goal. Resuming to `active` clears the pause fields and resets the\n * continuation counters.\n */\nexport async function setSessionGoalStatus(db: Database, workspaceId: string, sessionId: string, input: {\n status: SessionGoalStatus;\n evidence?: string;\n rationale?: string;\n pausedReason?: string;\n}): Promise<{ goal: SessionGoal; changed: boolean }> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const [existing] = await scopedDb.select().from(schema.sessionGoals)\n .where(and(eq(schema.sessionGoals.workspaceId, workspaceId), eq(schema.sessionGoals.sessionId, sessionId)))\n .for(\"update\")\n .limit(1);\n if (!existing) {\n throw new Error(`Session goal not found: ${sessionId}`);\n }\n if (existing.status === input.status) {\n return { goal: mapSessionGoal(existing), changed: false };\n }\n if (existing.status === \"completed\") {\n throw new Error(\"session goal is completed; set a new goal to continue\");\n }\n const [row] = await scopedDb.update(schema.sessionGoals).set({\n status: input.status,\n version: existing.version + 1,\n updatedAt: new Date(),\n ...(input.status === \"completed\" ? {\n evidence: input.evidence ?? null,\n pausedReason: null,\n } : {}),\n ...(input.status === \"paused\" ? {\n rationale: input.rationale ?? null,\n pausedReason: input.pausedReason ?? null,\n } : {}),\n ...(input.status === \"active\" ? {\n rationale: null,\n pausedReason: null,\n autoContinuations: 0,\n noProgressStreak: 0,\n // A re-armed goal starts a fresh continuation epoch; stale pointers to\n // a pre-pause continuation turn must not feed the progress detector.\n lastContinuationTurnId: null,\n versionAtLastContinuation: null,\n } : {}),\n }).where(eq(schema.sessionGoals.id, existing.id)).returning();\n if (!row) {\n throw new Error(`Session goal not found: ${sessionId}`);\n }\n return { goal: mapSessionGoal(row), changed: true };\n });\n}\n\nexport async function setSessionGoalLastContinuationTurn(db: Database, workspaceId: string, sessionId: string, turnId: string): Promise<void> {\n await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n await scopedDb.update(schema.sessionGoals).set({\n lastContinuationTurnId: turnId,\n updatedAt: new Date(),\n }).where(and(eq(schema.sessionGoals.workspaceId, workspaceId), eq(schema.sessionGoals.sessionId, sessionId)));\n });\n}\n\nexport type GoalContinuationDecision =\n | { decision: \"none\" }\n | { decision: \"queue\" }\n | { decision: \"paused\"; reason: \"no_progress\" | \"max_auto_continuations\" | \"limits\"; goal: SessionGoal }\n | { decision: \"continue\"; goal: SessionGoal; autoContinuation: number; cap: number | null };\n\n/**\n * Core continuation decision, taken in one transaction with the goal row\n * locked. Queued work always wins; any non-terminal turn (queued, running, or\n * requires_action awaiting a human approval) blocks auto-continuation. The\n * no-progress and max-continuation guards mutate counters here only, so a\n * replaying workflow re-reads recorded activity results and never recomputes\n * them.\n */\nexport async function evaluateGoalContinuation(db: Database, input: {\n workspaceId: string;\n sessionId: string;\n // Optional: when absent (the default posture) goals are uncapped and length\n // is governed by the no-progress and budget guards only.\n defaultMaxAutoContinuations?: number | null;\n noProgressLimit: number;\n // Caller-computed billing/limits block reason. Applied inside the locked\n // decision (before the counter bump) so a budget pause never consumes\n // continuation budget.\n budgetBlocked?: string | null;\n}): Promise<GoalContinuationDecision> {\n return await withWorkspaceRls(db, input.workspaceId, async (scopedDb) => await scopedDb.transaction(async (tx) => {\n const [row] = await tx.select().from(schema.sessionGoals)\n .where(and(eq(schema.sessionGoals.workspaceId, input.workspaceId), eq(schema.sessionGoals.sessionId, input.sessionId)))\n .for(\"update\")\n .limit(1);\n if (!row || row.status !== \"active\") {\n return { decision: \"none\" } as const;\n }\n const [pendingTurn] = await tx.select({ id: schema.sessionTurns.id, status: schema.sessionTurns.status })\n .from(schema.sessionTurns)\n .where(and(\n eq(schema.sessionTurns.workspaceId, input.workspaceId),\n eq(schema.sessionTurns.sessionId, input.sessionId),\n inArray(schema.sessionTurns.status, [\"queued\", \"running\", \"requires_action\"]),\n ))\n .limit(1);\n if (pendingTurn) {\n // \"queue\" tells the workflow to claim immediately; running/requires_action\n // turns (e.g. a pending approval on a restarted workflow) must not be\n // bypassed by a continuation, so they decline instead.\n return pendingTurn.status === \"queued\" ? { decision: \"queue\" } as const : { decision: \"none\" } as const;\n }\n let autoContinuations = row.autoContinuations;\n let noProgressStreak = row.noProgressStreak;\n // P3: a 429-failover continuation (the last continuation turn carried the `rotated`\n // marker) is a multi-account rotate, not goal progress OR a goal stall — it must not\n // burn the auto-continuation budget while walking accounts. Freezes the increment below,\n // mirroring the budget-pause precedent that a limits pause never consumes budget.\n let rotatedFailover = false;\n if (row.lastContinuationTurnId) {\n const [lastFinished] = await tx.select({ id: schema.sessionTurns.id })\n .from(schema.sessionTurns)\n .where(and(\n eq(schema.sessionTurns.workspaceId, input.workspaceId),\n eq(schema.sessionTurns.sessionId, input.sessionId),\n sql`${schema.sessionTurns.finishedAt} is not null`,\n ))\n .orderBy(desc(schema.sessionTurns.position), desc(schema.sessionTurns.createdAt))\n .limit(1);\n if (lastFinished && lastFinished.id !== row.lastContinuationTurnId) {\n // A user/scheduled turn ran since the last continuation: human\n // re-engagement re-arms the auto-continuation budget.\n autoContinuations = 0;\n noProgressStreak = 0;\n } else if (lastFinished) {\n const [{ rotatedFailures } = { rotatedFailures: 0 }] = await tx.select({\n rotatedFailures: sql<number>`count(*)::int`,\n }).from(schema.sessionEvents)\n .where(and(\n eq(schema.sessionEvents.workspaceId, input.workspaceId),\n eq(schema.sessionEvents.turnId, row.lastContinuationTurnId),\n eq(schema.sessionEvents.type, \"turn.failed\"),\n sql`${schema.sessionEvents.payload} ->> 'rotated' = 'true'`,\n ));\n rotatedFailover = Number(rotatedFailures) > 0;\n const [{ toolCalls } = { toolCalls: 0 }] = await tx.select({\n toolCalls: sql<number>`count(*)::int`,\n }).from(schema.sessionEvents)\n .where(and(\n eq(schema.sessionEvents.workspaceId, input.workspaceId),\n eq(schema.sessionEvents.turnId, row.lastContinuationTurnId),\n eq(schema.sessionEvents.type, \"agent.toolCall.created\"),\n ));\n const goalRevised = row.versionAtLastContinuation !== null && row.version > row.versionAtLastContinuation;\n if (Number(toolCalls) > 0 || goalRevised) {\n noProgressStreak = 0;\n } else {\n // A turn that died on retryable provider backpressure says nothing\n // about whether the goal can progress; freezing the streak keeps a\n // sustained rate-limit window from masquerading as a stuck goal.\n // The auto-continuation cap remains the backstop for a real outage.\n const [{ backpressureFailures } = { backpressureFailures: 0 }] = await tx.select({\n backpressureFailures: sql<number>`count(*)::int`,\n }).from(schema.sessionEvents)\n .where(and(\n eq(schema.sessionEvents.workspaceId, input.workspaceId),\n eq(schema.sessionEvents.turnId, row.lastContinuationTurnId),\n eq(schema.sessionEvents.type, \"turn.failed\"),\n sql`${schema.sessionEvents.payload} ->> 'recovery' = 'goal_continuation'`,\n ));\n if (Number(backpressureFailures) === 0) {\n noProgressStreak = noProgressStreak + 1;\n }\n }\n }\n }\n if (noProgressStreak >= input.noProgressLimit) {\n const [paused] = await tx.update(schema.sessionGoals).set({\n status: \"paused\",\n pausedReason: \"no_progress\",\n autoContinuations,\n noProgressStreak,\n version: row.version + 1,\n updatedAt: new Date(),\n }).where(eq(schema.sessionGoals.id, row.id)).returning();\n return { decision: \"paused\", reason: \"no_progress\", goal: mapSessionGoal(paused!) } as const;\n }\n // No configured default means uncapped: goal length is bounded by the\n // no-progress and budget guards above, never by count. When a default is\n // configured it is a hard ceiling; per-goal overrides can only lower it.\n const capCandidates = [row.maxAutoContinuations, input.defaultMaxAutoContinuations]\n .filter((value): value is number => typeof value === \"number\");\n const cap = capCandidates.length > 0 ? Math.min(...capCandidates) : null;\n if (cap !== null && autoContinuations >= cap) {\n const [paused] = await tx.update(schema.sessionGoals).set({\n status: \"paused\",\n pausedReason: \"max_auto_continuations\",\n autoContinuations,\n noProgressStreak,\n version: row.version + 1,\n updatedAt: new Date(),\n }).where(eq(schema.sessionGoals.id, row.id)).returning();\n return { decision: \"paused\", reason: \"max_auto_continuations\", goal: mapSessionGoal(paused!) } as const;\n }\n if (input.budgetBlocked) {\n // Budget exhaustion pauses the goal visibly without bumping the\n // continuation counter — no turn is synthesized for this pass.\n const [paused] = await tx.update(schema.sessionGoals).set({\n status: \"paused\",\n pausedReason: \"limits\",\n rationale: input.budgetBlocked,\n autoContinuations,\n noProgressStreak,\n version: row.version + 1,\n updatedAt: new Date(),\n }).where(eq(schema.sessionGoals.id, row.id)).returning();\n return { decision: \"paused\", reason: \"limits\", goal: mapSessionGoal(paused!) } as const;\n }\n // Freeze the counter on a rotation failover (invariant: a rotation walk never\n // consumes continuation budget); a normal continuation increments as before.\n const nextAutoContinuations = autoContinuations + (rotatedFailover ? 0 : 1);\n const [updated] = await tx.update(schema.sessionGoals).set({\n autoContinuations: nextAutoContinuations,\n noProgressStreak,\n versionAtLastContinuation: row.version,\n updatedAt: new Date(),\n }).where(eq(schema.sessionGoals.id, row.id)).returning();\n return { decision: \"continue\", goal: mapSessionGoal(updated!), autoContinuation: nextAutoContinuations, cap } as const;\n }));\n}\n\nfunction mapSessionGoal(row: typeof schema.sessionGoals.$inferSelect): SessionGoal {\n return {\n id: row.id,\n accountId: row.accountId,\n workspaceId: row.workspaceId,\n sessionId: row.sessionId,\n status: row.status as SessionGoal[\"status\"],\n text: row.text,\n successCriteria: row.successCriteria,\n evidence: row.evidence,\n rationale: row.rationale,\n pausedReason: row.pausedReason,\n createdBy: row.createdBy as SessionGoal[\"createdBy\"],\n version: row.version,\n autoContinuations: row.autoContinuations,\n noProgressStreak: row.noProgressStreak,\n maxAutoContinuations: row.maxAutoContinuations,\n metadata: row.metadata,\n createdAt: row.createdAt.toISOString(),\n updatedAt: row.updatedAt.toISOString(),\n };\n}\n\nexport async function createTurn(db: Database, input: {\n workspaceId: string;\n sessionId: string;\n triggerEventId: string;\n temporalWorkflowId: string;\n}): Promise<string> {\n return await withWorkspaceRls(db, input.workspaceId, async (scopedDb) => {\n const session = await requireSession(scopedDb, input.workspaceId, input.sessionId);\n const trigger = await getSessionEvent(scopedDb, input.workspaceId, input.triggerEventId);\n const position = await nextTurnPosition(scopedDb, input.workspaceId, input.sessionId);\n const [row] = await scopedDb.insert(schema.sessionTurns).values({\n accountId: session.accountId,\n workspaceId: session.workspaceId,\n sessionId: input.sessionId,\n triggerEventId: input.triggerEventId,\n temporalWorkflowId: input.temporalWorkflowId,\n status: \"running\",\n source: \"user\",\n position,\n prompt: promptFromTrigger(trigger?.payload) ?? session.initialMessage,\n resources: resourcesFromTrigger(trigger?.payload) ?? session.resources,\n tools: toolsFromTrigger(trigger?.payload) ?? session.tools,\n model: session.model,\n reasoningEffort: reasoningEffortFromSession(session),\n sandboxBackend: session.sandboxBackend,\n metadata: {},\n startedAt: new Date(),\n }).returning({ id: schema.sessionTurns.id });\n if (!row) {\n throw new Error(\"Failed to create turn\");\n }\n await scopedDb.update(schema.sessions).set({\n activeTurnId: row.id,\n status: \"running\",\n updatedAt: new Date(),\n }).where(and(eq(schema.sessions.workspaceId, input.workspaceId), eq(schema.sessions.id, input.sessionId)));\n return row.id;\n });\n}\n\nexport async function enqueueSessionTurn(db: Database, input: EnqueueSessionTurnInput): Promise<SessionTurn> {\n return await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId }, async (scopedDb) => await scopedDb.transaction(async (tx) => {\n const position = await nextTurnPosition(tx as unknown as Database, input.workspaceId, input.sessionId);\n const [row] = await tx.insert(schema.sessionTurns).values({\n accountId: input.accountId,\n workspaceId: input.workspaceId,\n sessionId: input.sessionId,\n triggerEventId: input.triggerEventId,\n temporalWorkflowId: input.temporalWorkflowId,\n status: \"queued\",\n source: input.source,\n position,\n prompt: input.prompt,\n resources: input.resources,\n tools: input.tools,\n model: input.model,\n reasoningEffort: input.reasoningEffort,\n sandboxBackend: input.sandboxBackend,\n metadata: input.metadata,\n }).returning();\n if (!row) {\n throw new Error(\"Failed to enqueue session turn\");\n }\n return mapSessionTurn(row);\n }));\n}\n\nexport async function claimNextQueuedTurn(db: Database, workspaceId: string, sessionId: string, workflowId: string): Promise<SessionTurn | null> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => await scopedDb.transaction(async (tx) => {\n const rows = await tx.execute(sql<{ id: string }>`\n select id from session_turns\n where workspace_id = ${workspaceId} and session_id = ${sessionId} and status = 'queued'\n order by position asc, created_at asc, id asc\n for update skip locked\n limit 1\n `);\n const id = rows[0]?.id as string | undefined;\n if (!id) {\n return null;\n }\n const [row] = await tx.update(schema.sessionTurns).set({\n status: \"running\",\n temporalWorkflowId: workflowId,\n startedAt: new Date(),\n updatedAt: new Date(),\n }).where(and(eq(schema.sessionTurns.workspaceId, workspaceId), eq(schema.sessionTurns.id, id))).returning();\n if (!row) {\n throw new Error(`Session turn not found: ${id}`);\n }\n await tx.update(schema.sessions).set({\n status: \"running\",\n activeTurnId: row.id,\n updatedAt: new Date(),\n }).where(and(eq(schema.sessions.workspaceId, workspaceId), eq(schema.sessions.id, sessionId)));\n return mapSessionTurn(row);\n }));\n}\n\nexport async function setSessionStatus(db: Database, workspaceId: string, sessionId: string, status: SessionStatus, activeTurnId?: string | null): Promise<void> {\n await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n await scopedDb.update(schema.sessions).set({\n status,\n activeTurnId: activeTurnId === undefined ? undefined : activeTurnId,\n updatedAt: new Date(),\n }).where(and(eq(schema.sessions.workspaceId, workspaceId), eq(schema.sessions.id, sessionId)));\n });\n}\n\nexport type WakeParentForChildCompletionInput = {\n workspaceId: string;\n parentSessionId: string;\n // Stable per terminal episode, unique across episodes: the idempotency key\n // for exactly-once delivery (a unique session_events.client_event_id).\n clientEventId: string;\n // System-authored wake text rendered to the manager as its next turn input.\n text: string;\n // Structured payload describing the completed child (id, status, goal).\n childCompletion: Record<string, unknown>;\n reasoningEffortFallback: ReasoningEffort;\n};\n\nexport type WakeParentForChildCompletionResult =\n | { delivered: false; reason: \"already_delivered\" | \"parent_cancelled\" }\n | { delivered: true; turn: SessionTurn; triggerEvent: SessionEvent; events: SessionEvent[]; temporalWorkflowId: string };\n\n/**\n * Deliver a one-shot completion wake from a spawned worker into its parent\n * (manager) session: append a system-authored `user.message`, transition the\n * parent idle/failed -> queued (a queued/running parent already has a turn in\n * flight and keeps it), and enqueue the resulting turn. The whole thing runs\n * under the parent's row lock in one transaction, and is idempotent on\n * `clientEventId`: a duplicate call for the same terminal episode (activity\n * retry, the workflow's idle re-check) is a no-op that enqueues no second\n * turn. The caller publishes the returned events and signals the parent's\n * Temporal workflow (signalWithStart) only when `delivered` is true.\n *\n * Mirrors `acceptSessionUserMessage`/`postUserMessageTurn` in the API domain:\n * cancelled is the one parent state that refuses the wake (an explicit stop);\n * failed stays revivable, matching the revivable-failed-sessions contract.\n */\nexport async function wakeParentSessionForChildCompletion(\n db: Database,\n input: WakeParentForChildCompletionInput,\n): Promise<WakeParentForChildCompletionResult> {\n return await withWorkspaceRls(db, input.workspaceId, async (scopedDb) => await scopedDb.transaction(async (tx) => {\n const [parent] = await tx.select().from(schema.sessions)\n .where(and(eq(schema.sessions.workspaceId, input.workspaceId), eq(schema.sessions.id, input.parentSessionId)))\n .for(\"update\")\n .limit(1);\n if (!parent) {\n throw new Error(`Parent session not found: ${input.parentSessionId}`);\n }\n if (parent.status === \"cancelled\") {\n // Cancelled is the one terminal state that refuses new input; a manager a\n // human explicitly stopped is not revived by a worker finishing.\n return { delivered: false, reason: \"parent_cancelled\" as const };\n }\n // Idempotency gate: a wake for this terminal episode was already delivered.\n const [existing] = await tx.select({ id: schema.sessionEvents.id }).from(schema.sessionEvents)\n .where(and(\n eq(schema.sessionEvents.workspaceId, input.workspaceId),\n eq(schema.sessionEvents.sessionId, input.parentSessionId),\n eq(schema.sessionEvents.clientEventId, input.clientEventId),\n ))\n .limit(1);\n if (existing) {\n return { delivered: false, reason: \"already_delivered\" as const };\n }\n\n const shouldQueue = parent.status === \"idle\" || parent.status === \"failed\";\n const workflowId = parent.temporalWorkflowId ?? `session-${parent.id}`;\n let sequence = parent.lastSequence;\n const now = new Date();\n const eventRows = [\n {\n type: \"user.message\",\n payload: { text: input.text, childCompletion: input.childCompletion },\n clientEventId: input.clientEventId,\n },\n ...(shouldQueue ? [{ type: \"session.status.changed\", payload: { status: \"queued\" }, clientEventId: null as string | null }] : []),\n ].map((event) => ({\n accountId: parent.accountId,\n workspaceId: parent.workspaceId,\n sessionId: parent.id,\n sequence: ++sequence,\n type: event.type,\n payload: sanitizeEventPayload(event.payload),\n clientEventId: event.clientEventId ?? null,\n turnId: null,\n producerId: null,\n producerSeq: null,\n occurredAt: now,\n }));\n const inserted = (await tx.insert(schema.sessionEvents).values(eventRows).returning()).map(mapEvent);\n const triggerEvent = inserted[0]!;\n\n const position = await nextTurnPosition(tx as unknown as Database, input.workspaceId, parent.id);\n const [turnRow] = await tx.insert(schema.sessionTurns).values({\n accountId: parent.accountId,\n workspaceId: parent.workspaceId,\n sessionId: parent.id,\n triggerEventId: triggerEvent.id,\n temporalWorkflowId: workflowId,\n status: \"queued\",\n source: \"user\",\n position,\n prompt: input.text,\n resources: [],\n tools: parent.tools as ToolRef[],\n model: parent.model,\n reasoningEffort: reasoningEffortForMetadata(parent.metadata, input.reasoningEffortFallback),\n sandboxBackend: parent.sandboxBackend as SandboxBackend,\n metadata: { childCompletion: input.childCompletion },\n }).returning();\n if (!turnRow) {\n throw new Error(\"Failed to enqueue parent wake turn\");\n }\n const turn = mapSessionTurn(turnRow);\n\n sequence += 1;\n const [queuedEventRow] = await tx.insert(schema.sessionEvents).values({\n accountId: parent.accountId,\n workspaceId: parent.workspaceId,\n sessionId: parent.id,\n sequence,\n type: \"turn.queued\",\n payload: sanitizeEventPayload({ turnId: turn.id, triggerEventId: triggerEvent.id, source: turn.source }),\n clientEventId: null,\n turnId: turn.id,\n producerId: null,\n producerSeq: null,\n occurredAt: now,\n }).returning();\n const events = [...inserted, ...(queuedEventRow ? [mapEvent(queuedEventRow)] : [])];\n\n await tx.update(schema.sessions).set({\n lastSequence: sequence,\n ...(shouldQueue ? { status: \"queued\" as const, activeTurnId: null } : {}),\n updatedAt: now,\n }).where(and(eq(schema.sessions.workspaceId, input.workspaceId), eq(schema.sessions.id, parent.id)));\n\n return { delivered: true as const, turn, triggerEvent, events, temporalWorkflowId: workflowId };\n }));\n}\n\nexport async function setTemporalWorkflowId(db: Database, workspaceId: string, sessionId: string, workflowId: string): Promise<void> {\n await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n await scopedDb.update(schema.sessions).set({\n temporalWorkflowId: workflowId,\n updatedAt: new Date(),\n }).where(and(eq(schema.sessions.workspaceId, workspaceId), eq(schema.sessions.id, sessionId)));\n });\n}\n\nexport async function finishTurn(db: Database, workspaceId: string, turnId: string, status: SessionStatus | SessionTurnStatus): Promise<void> {\n await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n await scopedDb.update(schema.sessionTurns).set({\n status: turnStatusForFinish(status),\n finishedAt: status === \"requires_action\" ? undefined : new Date(),\n updatedAt: new Date(),\n }).where(and(eq(schema.sessionTurns.workspaceId, workspaceId), eq(schema.sessionTurns.id, turnId)));\n });\n}\n\n/**\n * Put a preempted (worker shutdown mid-flight) turn back on the session\n * queue so the workflow's next claim re-dispatches it on a healthy worker.\n * The trigger event is swapped when the resumed attempt should enter\n * through a synthesized resume notice instead of replaying the original\n * trigger (the original input is already part of persisted conversation\n * truth by then). Keeping the original position lets the resumed turn run\n * before any turns queued behind it. Accepts `running` turns and\n * `requires_action` turns: an approval rerun re-dispatches the same turn\n * without a fresh claim, so the row still carries the approval-wait status\n * while the rerun activity executes.\n */\nexport async function requeuePreemptedTurn(db: Database, workspaceId: string, turnId: string, triggerEventId: string): Promise<void> {\n await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const [row] = await scopedDb.update(schema.sessionTurns).set({\n status: \"queued\",\n triggerEventId,\n startedAt: null,\n finishedAt: null,\n updatedAt: new Date(),\n }).where(and(eq(schema.sessionTurns.workspaceId, workspaceId), eq(schema.sessionTurns.id, turnId), inArray(schema.sessionTurns.status, [\"running\", \"requires_action\"]))).returning({ id: schema.sessionTurns.id });\n if (!row) {\n throw new Error(`Preemptible session turn not found: ${turnId}`);\n }\n });\n}\n\n/**\n * Bump the per-turn worker-death redispatch counter and return the new value.\n * Stored in the turn row's metadata (not workflow-local state) so the\n * crash-loop guard is replay-safe: the count survives workflow replay, worker\n * restarts, and even a session-workflow re-run, and the increment is a single\n * atomic statement.\n */\nexport async function incrementTurnWorkerDeathRedispatches(db: Database, workspaceId: string, turnId: string): Promise<number> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const rows = await scopedDb.execute(sql<{ count: number }>`\n update session_turns\n set metadata = jsonb_set(\n coalesce(metadata, '{}'::jsonb),\n '{workerDeathRedispatches}',\n to_jsonb(coalesce((metadata->>'workerDeathRedispatches')::int, 0) + 1),\n true\n ),\n updated_at = now()\n where workspace_id = ${workspaceId} and id = ${turnId}\n returning (metadata->>'workerDeathRedispatches')::int as count\n `);\n const count = rows[0]?.count;\n if (count === undefined || count === null) {\n throw new Error(`Session turn not found: ${turnId}`);\n }\n return Number(count);\n });\n}\n\nexport async function getSessionTurn(db: Database, workspaceId: string, turnId: string): Promise<SessionTurn | null> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const [row] = await scopedDb.select().from(schema.sessionTurns).where(and(eq(schema.sessionTurns.workspaceId, workspaceId), eq(schema.sessionTurns.id, turnId))).limit(1);\n return row ? mapSessionTurn(row) : null;\n });\n}\n\nexport async function listSessionTurns(db: Database, workspaceId: string, sessionId: string, limit = 100): Promise<SessionTurn[]> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const rows = await scopedDb.select().from(schema.sessionTurns)\n .where(and(eq(schema.sessionTurns.workspaceId, workspaceId), eq(schema.sessionTurns.sessionId, sessionId)))\n .orderBy(asc(schema.sessionTurns.position), asc(schema.sessionTurns.createdAt))\n .limit(limit);\n return rows.map(mapSessionTurn);\n });\n}\n\nexport async function updateQueuedSessionTurn(db: Database, workspaceId: string, turnId: string, input: UpdateQueuedSessionTurnInput): Promise<SessionTurn> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const [row] = await scopedDb.update(schema.sessionTurns).set({\n ...(input.prompt !== undefined ? { prompt: input.prompt } : {}),\n ...(input.resources !== undefined ? { resources: input.resources } : {}),\n ...(input.tools !== undefined ? { tools: input.tools } : {}),\n ...(input.model !== undefined ? { model: input.model } : {}),\n ...(input.reasoningEffort !== undefined ? { reasoningEffort: input.reasoningEffort } : {}),\n ...(input.sandboxBackend !== undefined ? { sandboxBackend: input.sandboxBackend } : {}),\n ...(input.metadata !== undefined ? { metadata: input.metadata } : {}),\n updatedAt: new Date(),\n }).where(and(eq(schema.sessionTurns.workspaceId, workspaceId), eq(schema.sessionTurns.id, turnId), eq(schema.sessionTurns.status, \"queued\"))).returning();\n if (!row) {\n throw new Error(`Queued session turn not found: ${turnId}`);\n }\n return mapSessionTurn(row);\n });\n}\n\nexport async function cancelQueuedSessionTurn(db: Database, workspaceId: string, turnId: string): Promise<SessionTurn> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const [row] = await scopedDb.update(schema.sessionTurns).set({\n status: \"cancelled\",\n finishedAt: new Date(),\n updatedAt: new Date(),\n }).where(and(eq(schema.sessionTurns.workspaceId, workspaceId), eq(schema.sessionTurns.id, turnId), eq(schema.sessionTurns.status, \"queued\"))).returning();\n if (!row) {\n throw new Error(`Queued session turn not found: ${turnId}`);\n }\n return mapSessionTurn(row);\n });\n}\n\nexport async function reorderQueuedSessionTurns(db: Database, workspaceId: string, sessionId: string, turnIds: string[]): Promise<SessionTurn[]> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => await scopedDb.transaction(async (tx) => {\n const rows = await tx.select().from(schema.sessionTurns)\n .where(and(eq(schema.sessionTurns.workspaceId, workspaceId), eq(schema.sessionTurns.sessionId, sessionId), eq(schema.sessionTurns.status, \"queued\"), inArray(schema.sessionTurns.id, turnIds)));\n if (rows.length !== turnIds.length) {\n throw new Error(\"All reordered turns must be queued turns in the session\");\n }\n let index = 0;\n for (const turnId of turnIds) {\n index += 1;\n await tx.update(schema.sessionTurns).set({\n position: index,\n updatedAt: new Date(),\n }).where(and(eq(schema.sessionTurns.workspaceId, workspaceId), eq(schema.sessionTurns.id, turnId)));\n }\n const updated = await tx.select().from(schema.sessionTurns)\n .where(and(eq(schema.sessionTurns.workspaceId, workspaceId), eq(schema.sessionTurns.sessionId, sessionId), eq(schema.sessionTurns.status, \"queued\")))\n .orderBy(asc(schema.sessionTurns.position), asc(schema.sessionTurns.createdAt));\n return updated.map(mapSessionTurn);\n }));\n}\n\nexport async function appendSessionEvents(db: Database, workspaceId: string, sessionId: string, inputs: AppendEventInput[]): Promise<SessionEvent[]> {\n if (inputs.length === 0) {\n return [];\n }\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => await scopedDb.transaction(async (tx) => {\n const [row] = await tx.select().from(schema.sessions)\n .where(and(eq(schema.sessions.workspaceId, workspaceId), eq(schema.sessions.id, sessionId)))\n .for(\"update\")\n .limit(1);\n if (!row) {\n throw new Error(`Session not found: ${sessionId}`);\n }\n let sequence = row.lastSequence;\n const values = inputs.map((input) => ({\n accountId: row.accountId,\n workspaceId: row.workspaceId,\n sessionId,\n sequence: ++sequence,\n type: input.type,\n payload: sanitizeEventPayload(input.payload ?? {}),\n clientEventId: input.clientEventId ?? null,\n turnId: input.turnId ?? null,\n producerId: input.producerId ?? null,\n producerSeq: input.producerSeq ?? null,\n occurredAt: input.occurredAt ?? new Date(),\n }));\n const inserted = await tx.insert(schema.sessionEvents).values(values).returning();\n await tx.update(schema.sessions).set({ lastSequence: sequence, updatedAt: new Date() }).where(and(eq(schema.sessions.workspaceId, workspaceId), eq(schema.sessions.id, sessionId)));\n return inserted.map(mapEvent);\n }));\n}\n\nexport async function appendSessionEventsAndUpdateSession(db: Database, workspaceId: string, sessionId: string, inputs: AppendEventInput[], update: {\n resources?: ResourceRef[];\n tools?: ToolRef[];\n model?: string;\n metadata?: Record<string, unknown>;\n status?: SessionStatus;\n activeTurnId?: string | null;\n}): Promise<SessionEvent[]> {\n if (inputs.length === 0) {\n return [];\n }\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => await scopedDb.transaction(async (tx) => {\n const [row] = await tx.select().from(schema.sessions)\n .where(and(eq(schema.sessions.workspaceId, workspaceId), eq(schema.sessions.id, sessionId)))\n .for(\"update\")\n .limit(1);\n if (!row) {\n throw new Error(`Session not found: ${sessionId}`);\n }\n let sequence = row.lastSequence;\n const now = new Date();\n const values = inputs.map((input) => ({\n accountId: row.accountId,\n workspaceId: row.workspaceId,\n sessionId,\n sequence: ++sequence,\n type: input.type,\n payload: sanitizeEventPayload(input.payload ?? {}),\n clientEventId: input.clientEventId ?? null,\n turnId: input.turnId ?? null,\n producerId: input.producerId ?? null,\n producerSeq: input.producerSeq ?? null,\n occurredAt: input.occurredAt ?? now,\n }));\n const inserted = await tx.insert(schema.sessionEvents).values(values).returning();\n await tx.update(schema.sessions).set({\n lastSequence: sequence,\n ...(update.resources !== undefined ? { resources: update.resources } : {}),\n ...(update.tools !== undefined ? { tools: update.tools } : {}),\n ...(update.model !== undefined ? { model: update.model } : {}),\n ...(update.metadata !== undefined ? { metadata: update.metadata } : {}),\n ...(update.status !== undefined ? { status: update.status } : {}),\n ...(update.activeTurnId !== undefined ? { activeTurnId: update.activeTurnId } : {}),\n updatedAt: now,\n }).where(and(eq(schema.sessions.workspaceId, workspaceId), eq(schema.sessions.id, sessionId)));\n return inserted.map(mapEvent);\n }));\n}\n\ntype LockedSessionUpdateContext = {\n updateSessionMcpServerCredentials: (updates: UpdateSessionMcpServerCredentialsInput[]) => Promise<UpdateSessionMcpServerCredentialsResult>;\n};\n\ntype LockedSessionUpdateResult = {\n events: AppendEventInput[];\n update?: {\n resources?: ResourceRef[];\n tools?: ToolRef[];\n model?: string;\n metadata?: Record<string, unknown>;\n status?: SessionStatus;\n activeTurnId?: string | null;\n };\n};\n\nexport async function appendSessionEventsWithLockedSessionUpdate(\n db: Database,\n workspaceId: string,\n sessionId: string,\n build: (session: Session, context: LockedSessionUpdateContext) => LockedSessionUpdateResult | Promise<LockedSessionUpdateResult>,\n): Promise<SessionEvent[]> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => await scopedDb.transaction(async (tx) => {\n const [sessionRow] = await tx.select().from(schema.sessions).where(and(eq(schema.sessions.workspaceId, workspaceId), eq(schema.sessions.id, sessionId))).for(\"update\").limit(1);\n if (!sessionRow) {\n throw new Error(`Session not found: ${sessionId}`);\n }\n const built = await build(mapSession(sessionRow), {\n updateSessionMcpServerCredentials: async (updates) => await updateSessionMcpServerCredentialsInTransaction(tx, { workspaceId, sessionId, updates }),\n });\n if (built.events.length === 0) {\n return [];\n }\n let sequence = sessionRow.lastSequence;\n const now = new Date();\n const values = built.events.map((input) => ({\n accountId: sessionRow.accountId,\n workspaceId: sessionRow.workspaceId,\n sessionId,\n sequence: ++sequence,\n type: input.type,\n payload: sanitizeEventPayload(input.payload ?? {}),\n clientEventId: input.clientEventId ?? null,\n turnId: input.turnId ?? null,\n producerId: input.producerId ?? null,\n producerSeq: input.producerSeq ?? null,\n occurredAt: input.occurredAt ?? now,\n }));\n const inserted = await tx.insert(schema.sessionEvents).values(values).returning();\n const update = built.update ?? {};\n await tx.update(schema.sessions).set({\n lastSequence: sequence,\n ...(update.resources !== undefined ? { resources: update.resources } : {}),\n ...(update.tools !== undefined ? { tools: update.tools } : {}),\n ...(update.model !== undefined ? { model: update.model } : {}),\n ...(update.metadata !== undefined ? { metadata: update.metadata } : {}),\n ...(update.status !== undefined ? { status: update.status } : {}),\n ...(update.activeTurnId !== undefined ? { activeTurnId: update.activeTurnId } : {}),\n updatedAt: now,\n }).where(and(eq(schema.sessions.workspaceId, workspaceId), eq(schema.sessions.id, sessionId)));\n return inserted.map(mapEvent);\n }));\n}\n\nexport function sessionSubject(workspaceId: string, sessionId: string): string {\n return `workspaces.${workspaceId}.sessions.${sessionId}.events`;\n}\n\nfunction mapSession(row: typeof schema.sessions.$inferSelect, mcpServers: SessionMcpServerMetadata[] = []): Session {\n return {\n id: row.id,\n accountId: row.accountId,\n workspaceId: row.workspaceId,\n status: row.status as SessionStatus,\n initialMessage: row.initialMessage,\n title: row.title ?? null,\n titleSource: (row.titleSource as \"user\" | \"agent\" | null) ?? null,\n resources: row.resources as ResourceRef[],\n tools: row.tools as ToolRef[],\n metadata: row.metadata,\n model: row.model,\n sandboxBackend: row.sandboxBackend as SandboxBackend,\n sandboxOs: row.sandboxOs as SandboxOs,\n sandboxGroupId: row.sandboxGroupId,\n // The first-class swappable-sandbox pointer (M2). null == use the group\n // sandbox; active_epoch is the swap fence. Defensive Number() coercion keeps\n // the fence exact even if the column type ever drifts (the lease-epoch lesson).\n activeSandboxId: row.activeSandboxId ?? null,\n activeEpoch: Number(row.activeEpoch),\n environmentId: row.environmentId,\n firstPartyMcpPermissions: (row.firstPartyMcpPermissions as Permission[] | null) ?? null,\n mcpServers,\n parentSessionId: row.parentSessionId ?? null,\n createIdempotencyKey: row.createIdempotencyKey ?? null,\n temporalWorkflowId: row.temporalWorkflowId,\n activeTurnId: row.activeTurnId,\n lastInputTokens: row.lastInputTokens ?? null,\n lastSequence: row.lastSequence,\n codexPinnedCredentialId: row.codexPinnedCredentialId ?? null,\n codexLastCredentialId: row.codexLastCredentialId ?? null,\n createdAt: row.createdAt.toISOString(),\n updatedAt: row.updatedAt.toISOString(),\n };\n}\n\nfunction mapEvent(row: typeof schema.sessionEvents.$inferSelect): SessionEvent {\n return {\n id: row.id,\n workspaceId: row.workspaceId,\n sessionId: row.sessionId,\n sequence: row.sequence,\n type: row.type as SessionEventType,\n payload: row.payload,\n occurredAt: row.occurredAt.toISOString(),\n clientEventId: row.clientEventId,\n turnId: row.turnId,\n };\n}\n\nfunction mapSessionTurn(row: typeof schema.sessionTurns.$inferSelect): SessionTurn {\n return {\n id: row.id,\n workspaceId: row.workspaceId,\n sessionId: row.sessionId,\n triggerEventId: row.triggerEventId,\n temporalWorkflowId: row.temporalWorkflowId,\n status: row.status as SessionTurnStatus,\n source: row.source as SessionTurnSource,\n position: row.position,\n prompt: row.prompt,\n resources: row.resources as ResourceRef[],\n tools: row.tools as ToolRef[],\n model: row.model,\n reasoningEffort: row.reasoningEffort as ReasoningEffort,\n sandboxBackend: row.sandboxBackend as SandboxBackend,\n sandboxOs: (row.sandboxOs as SandboxOs | null) ?? null,\n metadata: row.metadata,\n startedAt: row.startedAt ? row.startedAt.toISOString() : null,\n finishedAt: row.finishedAt ? row.finishedAt.toISOString() : null,\n createdAt: row.createdAt.toISOString(),\n updatedAt: row.updatedAt.toISOString(),\n };\n}\n\nasync function nextTurnPosition(db: Database, workspaceId: string, sessionId: string): Promise<number> {\n const [{ maxPosition } = { maxPosition: 0 }] = await db.select({\n maxPosition: sql<number>`coalesce(max(${schema.sessionTurns.position}), 0)`,\n }).from(schema.sessionTurns).where(and(eq(schema.sessionTurns.workspaceId, workspaceId), eq(schema.sessionTurns.sessionId, sessionId)));\n return Number(maxPosition) + 1;\n}\n\nfunction turnStatusForFinish(status: SessionStatus | SessionTurnStatus): SessionTurnStatus {\n if (status === \"idle\") {\n return \"completed\";\n }\n if (status === \"queued\") {\n return \"queued\";\n }\n if (status === \"running\") {\n return \"running\";\n }\n return status;\n}\n\nfunction promptFromTrigger(payload: unknown): string | null {\n if (payload && typeof payload === \"object\" && \"text\" in payload && typeof payload.text === \"string\") {\n return payload.text;\n }\n return null;\n}\n\nfunction resourcesFromTrigger(payload: unknown): ResourceRef[] | null {\n if (payload && typeof payload === \"object\" && \"resources\" in payload && Array.isArray(payload.resources)) {\n return payload.resources as ResourceRef[];\n }\n return null;\n}\n\nfunction toolsFromTrigger(payload: unknown): ToolRef[] | null {\n if (payload && typeof payload === \"object\" && \"tools\" in payload && Array.isArray(payload.tools)) {\n return payload.tools as ToolRef[];\n }\n return null;\n}\n\nfunction reasoningEffortFromSession(session: Session): ReasoningEffort {\n const value = session.metadata.reasoningEffort;\n return value === \"none\" || value === \"minimal\" || value === \"low\" || value === \"medium\" || value === \"high\" || value === \"xhigh\"\n ? value\n : \"medium\";\n}\n\nfunction mapFile(row: typeof schema.files.$inferSelect): FileAsset {\n return {\n id: row.id,\n workspaceId: row.workspaceId,\n status: row.status as FileStatus,\n filename: row.filename,\n safeFilename: row.safeFilename,\n contentType: row.contentType,\n sizeBytes: row.sizeBytes,\n sha256: row.sha256,\n bucket: row.bucket,\n objectKey: row.objectKey,\n createdAt: row.createdAt.toISOString(),\n updatedAt: row.updatedAt.toISOString(),\n };\n}\n\nfunction mapScheduledTask(row: typeof schema.scheduledTasks.$inferSelect): ScheduledTask {\n return {\n id: row.id,\n accountId: row.accountId,\n workspaceId: row.workspaceId,\n name: row.name,\n status: row.status as ScheduledTaskStatus,\n schedule: row.schedule as ScheduledTaskScheduleSpec,\n temporalScheduleId: row.temporalScheduleId,\n runMode: row.runMode as ScheduledTaskRunMode,\n overlapPolicy: row.overlapPolicy as ScheduledTaskOverlapPolicy,\n agentConfig: row.agentConfig as ScheduledTaskAgentConfig,\n reusableSessionId: row.reusableSessionId,\n environmentId: row.environmentId,\n metadata: row.metadata,\n createdAt: row.createdAt.toISOString(),\n updatedAt: row.updatedAt.toISOString(),\n };\n}\n\nfunction mapScheduledTaskRun(row: typeof schema.scheduledTaskRuns.$inferSelect): ScheduledTaskRun {\n return {\n id: row.id,\n accountId: row.accountId,\n workspaceId: row.workspaceId,\n taskId: row.taskId,\n status: row.status as ScheduledTaskRunStatus,\n triggerType: row.triggerType as ScheduledTaskTriggerType,\n scheduledAt: row.scheduledAt ? row.scheduledAt.toISOString() : null,\n firedAt: row.firedAt.toISOString(),\n sessionId: row.sessionId,\n triggerEventId: row.triggerEventId,\n error: row.error,\n createdAt: row.createdAt.toISOString(),\n updatedAt: row.updatedAt.toISOString(),\n };\n}\n\nfunction mapAccount(row: typeof schema.managedAccounts.$inferSelect): ManagedAccount {\n return {\n id: row.id,\n name: row.name,\n externalSource: row.externalSource,\n externalId: row.externalId,\n createdAt: row.createdAt.toISOString(),\n updatedAt: row.updatedAt.toISOString(),\n };\n}\n\nfunction mapPackInstallation(row: typeof schema.packInstallations.$inferSelect): PackInstallation {\n return {\n id: row.id,\n accountId: row.accountId,\n workspaceId: row.workspaceId,\n packId: row.packId,\n status: row.status as PackInstallationStatus,\n metadata: row.metadata,\n enabledAt: row.enabledAt.toISOString(),\n updatedAt: row.updatedAt.toISOString(),\n };\n}\n\nfunction mapWorkspacePack(row: typeof schema.workspacePacks.$inferSelect): WorkspaceRegisteredPack {\n return {\n accountId: row.accountId,\n workspaceId: row.workspaceId,\n // Manifests are validated with the CapabilityPack contract at the API\n // boundary before they are stored.\n pack: row.manifest as unknown as CapabilityPack,\n createdAt: row.createdAt.toISOString(),\n updatedAt: row.updatedAt.toISOString(),\n };\n}\n\nfunction mapCapabilityCatalogItem(row: typeof schema.capabilityCatalogItems.$inferSelect): CapabilityCatalogItem {\n const runtime = row.kind === \"mcp\" && row.endpointUrl\n ? {\n available: true,\n mcpServerId: mcpServerIdForCapability(row.id, row.metadata),\n transport: \"streamable-http\",\n notes: row.authModel\n ? \"Requires credential headers supplied in the enable request.\"\n : null,\n }\n : {\n available: false,\n notes: row.kind === \"mcp\"\n ? \"Remote streamable HTTP endpoint is required for runtime use.\"\n : null,\n };\n return {\n id: row.id,\n accountId: row.accountId,\n workspaceId: row.workspaceId,\n kind: row.kind as CapabilityKind,\n source: row.source as CapabilitySource,\n name: row.name,\n description: row.description,\n category: row.category,\n tags: row.tags,\n homepageUrl: row.homepageUrl,\n endpointUrl: row.endpointUrl,\n installUrl: row.installUrl,\n authModel: row.authModel,\n tools: [],\n runtime,\n enabled: false,\n enabledReason: null,\n metadata: row.metadata,\n createdAt: row.createdAt.toISOString(),\n updatedAt: row.updatedAt.toISOString(),\n };\n}\n\nfunction mapWorkspace(row: typeof schema.workspaces.$inferSelect): Workspace {\n return {\n id: row.id,\n accountId: row.accountId,\n name: row.name,\n slug: row.slug,\n externalSource: row.externalSource,\n externalId: row.externalId,\n agentInstructions: row.agentInstructions ?? null,\n createdAt: row.createdAt.toISOString(),\n updatedAt: row.updatedAt.toISOString(),\n };\n}\n\nfunction mapWorkspaceMember(row: typeof schema.workspaceMemberships.$inferSelect): WorkspaceMember {\n return {\n subjectId: row.subjectId,\n subjectLabel: row.subjectLabel,\n role: row.role,\n permissions: row.permissions as Permission[],\n createdAt: row.createdAt.toISOString(),\n };\n}\n\nfunction mapCapabilityInstallation(row: typeof schema.capabilityInstallations.$inferSelect): CapabilityInstallation {\n return {\n id: row.id,\n accountId: row.accountId,\n workspaceId: row.workspaceId,\n capabilityId: row.capabilityId,\n kind: row.kind as CapabilityKind,\n status: row.status as CapabilityInstallationStatus,\n config: redactInstallationConfig(row.config),\n metadata: row.metadata,\n enabledAt: row.enabledAt.toISOString(),\n updatedAt: row.updatedAt.toISOString(),\n };\n}\n\n/**\n * Stored credential-header ciphertext never leaves the database through the\n * generic installation mapping — callers see only the sorted header names.\n * The runtime reads ciphertext through listEnabledMcpCapabilityServers and\n * the enable flow through getStoredCapabilityHeaderCiphertext.\n */\nfunction redactInstallationConfig(config: Record<string, unknown>): Record<string, unknown> {\n const headersEncrypted = encryptedHeadersConfig(config.headersEncrypted);\n if (!headersEncrypted) {\n return config;\n }\n const { headersEncrypted: _omitted, ...rest } = config;\n return { ...rest, headerNames: Object.keys(headersEncrypted).sort() };\n}\n\nfunction mapSocialConnection(row: typeof schema.socialConnections.$inferSelect): SocialConnection {\n return {\n id: row.id,\n accountId: row.accountId,\n workspaceId: row.workspaceId,\n provider: row.provider as SocialProvider,\n accountHandle: row.accountHandle,\n accountName: row.accountName,\n externalAccountId: row.externalAccountId,\n status: row.status as SocialConnectionStatus,\n scopes: row.scopes,\n credentialRef: row.credentialRef,\n tokenMetadata: row.tokenMetadata,\n metadata: row.metadata,\n createdAt: row.createdAt.toISOString(),\n updatedAt: row.updatedAt.toISOString(),\n };\n}\n\nfunction mapApiKey(row: typeof schema.apiKeys.$inferSelect): ApiKey {\n return {\n id: row.id,\n accountId: row.accountId,\n workspaceId: row.workspaceId,\n name: row.name,\n prefix: row.prefix,\n permissions: row.permissions as Permission[],\n expiresAt: row.expiresAt ? row.expiresAt.toISOString() : null,\n revokedAt: row.revokedAt ? row.revokedAt.toISOString() : null,\n lastUsedAt: row.lastUsedAt ? row.lastUsedAt.toISOString() : null,\n createdAt: row.createdAt.toISOString(),\n updatedAt: row.updatedAt.toISOString(),\n };\n}\n\nfunction mapGitHubInstallation(row: typeof schema.githubInstallations.$inferSelect): GitHubInstallation {\n return {\n id: row.id,\n accountId: row.accountId,\n workspaceId: row.workspaceId,\n installationId: row.installationId,\n accountLogin: row.accountLogin,\n accountType: row.accountType,\n createdAt: row.createdAt.toISOString(),\n updatedAt: row.updatedAt.toISOString(),\n };\n}\n\nfunction mapUsageEvent(row: typeof schema.usageEvents.$inferSelect): UsageEvent {\n return {\n id: row.id,\n workspaceId: row.workspaceId,\n accountId: row.accountId,\n subjectId: row.subjectId,\n eventType: row.eventType as UsageEvent[\"eventType\"],\n quantity: row.quantity,\n unit: row.unit,\n sourceResourceType: row.sourceResourceType,\n sourceResourceId: row.sourceResourceId,\n idempotencyKey: row.idempotencyKey,\n occurredAt: row.occurredAt.toISOString(),\n recordedAt: row.recordedAt.toISOString(),\n exportedToBillingAt: row.exportedToBillingAt ? row.exportedToBillingAt.toISOString() : null,\n billingProviderEventId: row.billingProviderEventId,\n };\n}\n\nfunction mapSocialPost(row: typeof schema.socialPosts.$inferSelect): SocialPost {\n return {\n id: row.id,\n accountId: row.accountId,\n workspaceId: row.workspaceId,\n connectionId: row.connectionId,\n provider: row.provider as SocialProvider,\n externalPostId: row.externalPostId,\n url: row.url,\n authorHandle: row.authorHandle,\n text: row.text,\n publishedAt: row.publishedAt.toISOString(),\n metrics: row.metrics,\n raw: row.raw,\n createdAt: row.createdAt.toISOString(),\n };\n}\n\nfunction stringArrayConfig(value: unknown): string[] | undefined {\n if (!Array.isArray(value)) {\n return undefined;\n }\n const values = value.filter((item): item is string => typeof item === \"string\" && item.trim().length > 0);\n return values.length > 0 ? [...new Set(values.map((item) => item.trim()))] : undefined;\n}\n\nfunction positiveIntegerConfig(value: unknown): number | undefined {\n if (typeof value === \"number\" && Number.isInteger(value) && value > 0) {\n return value;\n }\n if (typeof value === \"string\" && /^\\d+$/.test(value) && Number(value) > 0) {\n return Number(value);\n }\n return undefined;\n}\n\nfunction booleanConfig(value: unknown): boolean | undefined {\n return typeof value === \"boolean\" ? value : undefined;\n}\n\nfunction encryptedHeadersConfig(value: unknown): Record<string, string> | undefined {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) {\n return undefined;\n }\n const entries = Object.entries(value as Record<string, unknown>)\n .filter((entry): entry is [string, string] => typeof entry[1] === \"string\" && entry[1].length > 0);\n return entries.length > 0 ? Object.fromEntries(entries) : undefined;\n}\n\nfunction mcpConnectivityOk(metadata: Record<string, unknown>): boolean {\n const value = metadata.mcpConnectivity;\n return !!value && typeof value === \"object\" && \"status\" in value && value.status === \"ok\";\n}\n\nfunction shortHash(value: string): string {\n let hash = 0x811c9dc5;\n for (let index = 0; index < value.length; index += 1) {\n hash ^= value.charCodeAt(index);\n hash = Math.imul(hash, 0x01000193);\n }\n return (hash >>> 0).toString(36).padStart(7, \"0\").slice(0, 7);\n}\n\n// Shared, refreshing, id-addressed Codex token resolver + the per-account usage\n// wrapper (P2). Placed at the END so every accessor it orchestrates\n// (loadCodexCredentialForRun / recordCodexTokenRefresh / setCodexCredentialStatus /\n// recordCodexAccountUsage) is already initialized when its default-deps bag\n// evaluates under the index↔resolver module cycle.\nexport * from \"./codex-token-resolver\";\n","import { createCipheriv, createDecipheriv, randomBytes } from \"node:crypto\";\n\nconst VERSION_PREFIX = \"v1\";\nconst IV_BYTES = 12;\nconst GCM_TAG_BYTES = 16;\nconst KEY_BYTES = 32;\n\n/**\n * Encrypts one workspace environment variable value with AES-256-GCM under an\n * operator key held outside Postgres. Output format: `v1:<b64 iv>:<b64 ciphertext||tag>`.\n */\nexport function encryptEnvironmentValue(key: Uint8Array, plaintext: string): string {\n assertKey(key);\n const iv = randomBytes(IV_BYTES);\n const cipher = createCipheriv(\"aes-256-gcm\", key, iv);\n const ciphertext = Buffer.concat([cipher.update(plaintext, \"utf8\"), cipher.final(), cipher.getAuthTag()]);\n return `${VERSION_PREFIX}:${iv.toString(\"base64\")}:${ciphertext.toString(\"base64\")}`;\n}\n\n/**\n * Decrypts a stored `v1:` value. Error messages never echo plaintext or\n * ciphertext: unknown versions throw \"unsupported environment value format\",\n * auth-tag mismatches throw \"environment value decryption failed\".\n */\nexport function decryptEnvironmentValue(key: Uint8Array, stored: string): string {\n assertKey(key);\n const parts = stored.split(\":\");\n if (parts.length !== 3 || parts[0] !== VERSION_PREFIX) {\n throw new Error(\"unsupported environment value format\");\n }\n const iv = Buffer.from(parts[1]!, \"base64\");\n const payload = Buffer.from(parts[2]!, \"base64\");\n if (iv.length !== IV_BYTES || payload.length <= GCM_TAG_BYTES) {\n throw new Error(\"unsupported environment value format\");\n }\n const tag = payload.subarray(payload.length - GCM_TAG_BYTES);\n const ciphertext = payload.subarray(0, payload.length - GCM_TAG_BYTES);\n const decipher = createDecipheriv(\"aes-256-gcm\", key, iv);\n decipher.setAuthTag(tag);\n try {\n return Buffer.concat([decipher.update(ciphertext), decipher.final()]).toString(\"utf8\");\n } catch {\n throw new Error(\"environment value decryption failed\");\n }\n}\n\nfunction assertKey(key: Uint8Array): void {\n if (key.length !== KEY_BYTES) {\n throw new Error(\"environment encryption key must be exactly 32 bytes\");\n }\n}\n","/**\n * Last line of defense against a session event crashing a whole turn.\n *\n * Postgres `text`/`jsonb` cannot store a NUL byte (U+0000) nor lone UTF-16\n * surrogates. Raw exec output routinely carries both -- chrome/crashpad logs,\n * `cat` of a binary, random bytes -- and the worker persists that output verbatim\n * inside `agent.toolCall.output` / `sandbox.command.output` event payloads. When\n * such a payload reaches `INSERT INTO session_events`, the driver rejects it\n * (\"Failed query: insert into session_events\") and the turn dies.\n *\n * `sanitizeEventPayload` deep-walks any payload value (objects, arrays, nested)\n * and, for every string, strips NUL and rewrites invalid/lone UTF-16 surrogates\n * to the Unicode replacement char (U+FFFD), so the result is always valid UTF-8\n * that jsonb can store. It is cheap and total: only strings are touched, and only\n * the two disallowed classes of code unit -- no meaningful text is lost, no\n * truncation (truncation is handled elsewhere).\n */\n\nconst REPLACEMENT = \"�\";\n\n/**\n * Strip NUL and repair invalid/lone UTF-16 surrogates in a single string.\n * Returns the input unchanged (same reference) when it is already clean, so the\n * common case allocates nothing.\n */\nexport function sanitizeEventString(value: string): string {\n // Fast path: no NUL and no surrogate code unit at all -> nothing to do.\n // Surrogates live in U+D800..U+DFFF; a quick scan avoids the rebuild cost.\n let needsWork = false;\n for (let i = 0; i < value.length; i++) {\n const code = value.charCodeAt(i);\n if (code === 0x0000 || (code >= 0xd800 && code <= 0xdfff)) {\n needsWork = true;\n break;\n }\n }\n if (!needsWork) {\n return value;\n }\n\n let out = \"\";\n for (let i = 0; i < value.length; i++) {\n const code = value.charCodeAt(i);\n if (code === 0x0000) {\n // Drop NUL entirely.\n continue;\n }\n if (code >= 0xd800 && code <= 0xdbff) {\n // High surrogate: valid only when immediately followed by a low surrogate.\n const next = i + 1 < value.length ? value.charCodeAt(i + 1) : 0;\n if (next >= 0xdc00 && next <= 0xdfff) {\n out += value[i]! + value[i + 1]!;\n i += 1;\n continue;\n }\n out += REPLACEMENT;\n continue;\n }\n if (code >= 0xdc00 && code <= 0xdfff) {\n // Lone low surrogate (a valid pair would have been consumed above).\n out += REPLACEMENT;\n continue;\n }\n out += value[i]!;\n }\n return out;\n}\n\n/**\n * Deep-walk a session event payload and sanitize every string value. Mirrors the\n * shape of the worker redaction deep-walk: objects, arrays, and nested\n * combinations are traversed; non-string leaves pass through untouched. Object\n * keys are sanitized too -- they are jsonb-constrained the same as values.\n */\nexport function sanitizeEventPayload<T>(payload: T): T {\n if (typeof payload === \"string\") {\n return sanitizeEventString(payload) as unknown as T;\n }\n if (Array.isArray(payload)) {\n return payload.map((item) => sanitizeEventPayload(item)) as unknown as T;\n }\n if (payload && typeof payload === \"object\") {\n const entries = Object.entries(payload as Record<string, unknown>).map(\n ([key, value]) => [sanitizeEventString(key), sanitizeSensitiveEventField(key, value)] as const,\n );\n return Object.fromEntries(entries) as unknown as T;\n }\n return payload;\n}\n\nfunction sanitizeSensitiveEventField(key: string, value: unknown): unknown {\n if (key === \"mcpServers\") {\n return sanitizeSessionMcpServerList(value);\n }\n if (key === \"mcpCredentialUpdates\") {\n return sanitizeMcpCredentialUpdateList(value);\n }\n return sanitizeEventPayload(value);\n}\n\nfunction sanitizeSessionMcpServerList(value: unknown): unknown {\n if (!Array.isArray(value)) {\n return sanitizeEventPayload(value);\n }\n return value.map((item) => {\n if (!isPlainObject(item)) {\n return sanitizeEventPayload(item);\n }\n const { headers, headersEncrypted, ...rest } = item;\n const cleaned = sanitizeEventPayload(rest) as Record<string, unknown>;\n const headerNames = safeHeaderNames(headers) ?? safeHeaderNames(headersEncrypted);\n if (headerNames) {\n cleaned.headerNames = headerNames;\n }\n return cleaned;\n });\n}\n\nfunction sanitizeMcpCredentialUpdateList(value: unknown): unknown {\n if (!Array.isArray(value)) {\n return sanitizeEventPayload(value);\n }\n return value.map((item) => {\n if (!isPlainObject(item)) {\n return sanitizeEventPayload(item);\n }\n const { headers, headersEncrypted, ...rest } = item;\n const cleaned = sanitizeEventPayload(rest) as Record<string, unknown>;\n const headerNames = safeHeaderNames(headers) ?? safeHeaderNames(headersEncrypted);\n if (headerNames) {\n cleaned.headerNames = headerNames;\n }\n return cleaned;\n });\n}\n\nfunction safeHeaderNames(value: unknown): string[] | null {\n if (!isPlainObject(value)) {\n return null;\n }\n return Object.keys(value).map(sanitizeEventString).sort();\n}\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n return Boolean(value && typeof value === \"object\" && !Array.isArray(value));\n}\n","// Shared, id-addressed, REFRESHING Codex token resolver (P2).\n//\n// Hoisted here from apps/worker/src/activities/codex-auth.ts so BOTH the worker\n// (turn-time bearer for the streamed run) AND the api (the /wham/usage quota-bar\n// reads) drive ONE resolver — no duplicated refresh/CAS/single-flight logic. The\n// worker re-exports buildCodexTokenResolver from this module for back-compat, so\n// the agent-turn.ts call site is unchanged.\n//\n// Why @opengeni/db is the right home: the resolver only orchestrates accessors\n// this package already owns (loadCodexCredentialForRun / recordCodexTokenRefresh /\n// setCodexCredentialStatus / encryptEnvironmentValue) plus pure @opengeni/codex\n// refresh helpers and the @opengeni/config key — keeping the refresh-CAS + RLS\n// invariants co-located with the rows they protect.\n//\n// CROSS-PROCESS SAFETY is preserved unchanged: the single-flight `inflight` map is\n// process-module-scoped, so worker and api each get their own — that is CORRECT\n// (each process coalesces its own concurrent refreshes). The real cross-process\n// guard is the (id, version) CAS inside recordCodexTokenRefresh: if the api\n// refreshes a token while a worker turn refreshes the same account, the loser's\n// CAS writes 0 rows (stale version) and it re-reads the winner's token, so the\n// one-time refresh token is never double-spent. RLS is untouched (every accessor\n// wraps withWorkspaceRls internally).\n\nimport { environmentsEncryptionKeyBytes, type Settings } from \"@opengeni/config\";\nimport {\n accessTokenExpiry,\n CODEX_CLIENT_VERSION,\n CODEX_REFRESH_FALLBACK_MS,\n CODEX_REFRESH_WINDOW_MS,\n CodexReloginRequired,\n type CodexTokenSnapshot,\n type CodexUsagePayload,\n fetchCodexUsage,\n normalizeCodexUsage,\n refreshCodexToken,\n} from \"@opengeni/codex\";\nimport { encryptEnvironmentValue } from \"./environment-crypto\";\nimport {\n loadCodexCredentialForRun,\n recordCodexAccountUsage,\n recordCodexTokenRefresh,\n setCodexCredentialStatus,\n type CodexCredentialForRun,\n type Database,\n} from \"./index\";\n\n// Single-flight per CREDENTIAL INSTANCE (row id + version), process-module scope.\n// Keying by the loaded credential's id+version — NOT by workspaceId alone (P1-b) —\n// is what makes a disconnect→reconnect safe: a post-reconnect getToken loads a\n// DIFFERENT row (new uuid id) and so gets a distinct key, instead of coalescing\n// onto the OLD in-flight refresh and writing stale rotated tokens over the freshly\n// connected credential. Concurrent calls for the SAME credential still coalesce,\n// so the one-time refresh token is never double-spent.\nconst inflight = new Map<string, Promise<CodexTokenSnapshot>>();\n\n// Dependencies are injectable so the lifecycle logic (single-flight, staleness,\n// needs_relogin transition) is unit-testable without a database. Production uses\n// the real db + codex functions via the default bag.\nexport type CodexAuthDeps = {\n loadCredential: typeof loadCodexCredentialForRun;\n recordRefresh: typeof recordCodexTokenRefresh;\n setStatus: typeof setCodexCredentialStatus;\n refresh: typeof refreshCodexToken;\n encrypt: typeof encryptEnvironmentValue;\n keyBytes: typeof environmentsEncryptionKeyBytes;\n};\n\nconst defaultDeps: CodexAuthDeps = {\n loadCredential: loadCodexCredentialForRun,\n recordRefresh: recordCodexTokenRefresh,\n setStatus: setCodexCredentialStatus,\n refresh: refreshCodexToken,\n encrypt: encryptEnvironmentValue,\n keyBytes: environmentsEncryptionKeyBytes,\n};\n\nexport function buildCodexTokenResolver(\n db: Database,\n settings: Settings,\n workspaceId: string,\n // The RESOLVED effective credential id (pin > workspace active), threaded from\n // the worker. A mid-turn switch loads a DIFFERENT row id, gets a distinct\n // single-flight key, and the (id, version) CAS in recordCodexTokenRefresh writes\n // 0 rows against the now-inactive row — so a refresh racing a switch can never\n // clobber the newly-active account. The single-flight map needs zero change.\n credentialId: string,\n deps: CodexAuthDeps = defaultDeps,\n): { getToken: () => Promise<CodexTokenSnapshot>; refresh: () => Promise<CodexTokenSnapshot> } {\n const snapshot = (cred: CodexCredentialForRun): CodexTokenSnapshot => ({\n accessToken: cred.tokens.accessToken,\n chatgptAccountId: cred.chatgptAccountId,\n isFedramp: cred.isFedramp,\n });\n\n const performRefresh = async (cred: CodexCredentialForRun): Promise<CodexTokenSnapshot> => {\n try {\n const next = await deps.refresh(cred.tokens.refreshToken);\n const tokens = {\n access_token: next.accessToken ?? cred.tokens.accessToken,\n refresh_token: next.refreshToken ?? cred.tokens.refreshToken,\n id_token: next.idToken ?? cred.tokens.idToken,\n };\n const key = deps.keyBytes(settings);\n if (!key) {\n throw new Error(\"OPENGENI_ENVIRONMENTS_ENCRYPTION_KEY is not configured\");\n }\n // Compare-and-set on the loaded (id, version): if a disconnect→reconnect\n // replaced the row mid-refresh, this writes 0 rows and we must NOT clobber\n // the new credential with our now-defunct rotated tokens.\n const persisted = await deps.recordRefresh(db, {\n id: cred.id,\n version: cred.version,\n workspaceId,\n credentialEncrypted: deps.encrypt(key, JSON.stringify(tokens)),\n expiresAt: accessTokenExpiry(tokens.access_token),\n lastRefreshAt: new Date(),\n });\n if (!persisted) {\n // The row changed under us. Our rotated tokens belong to a stale family;\n // fall back to whatever is connected NOW (a reconnect leaves an active\n // row). If nothing active remains, a relogin is genuinely required.\n const current = await deps.loadCredential(db, settings, workspaceId, credentialId);\n if (current && current.status === \"active\") {\n return snapshot(current);\n }\n throw new CodexReloginRequired(\"Codex credential changed during token refresh; reconnect required.\");\n }\n return { accessToken: tokens.access_token, chatgptAccountId: cred.chatgptAccountId, isFedramp: cred.isFedramp };\n } catch (error) {\n if (error instanceof CodexReloginRequired) {\n // Stamp needs_relogin ONLY if the row we refreshed is STILL current\n // (compare-and-set on the loaded id+version). A relogin triggered by the\n // OLD token family must never stamp needs_relogin onto a freshly\n // reconnected credential.\n await deps.setStatus(db, workspaceId, \"needs_relogin\", error.message, { id: cred.id, version: cred.version });\n }\n throw error;\n }\n };\n\n // ALL refreshes — whether triggered by proactive staleness (getToken) or by a\n // 401 retry (refresh) — coalesce onto one in-flight promise per credential\n // instance, so concurrent calls can never double-spend the one-time refresh\n // token (which would trigger refresh_token_reused -> needs_relogin).\n const doRefresh = (cred: CodexCredentialForRun): Promise<CodexTokenSnapshot> => {\n const key = `${cred.id}:${cred.version}`;\n const existing = inflight.get(key);\n if (existing) {\n return existing;\n }\n const promise = performRefresh(cred).finally(() => {\n if (inflight.get(key) === promise) {\n inflight.delete(key);\n }\n });\n inflight.set(key, promise);\n return promise;\n };\n\n const resolve = async (force: boolean): Promise<CodexTokenSnapshot> => {\n const cred = await deps.loadCredential(db, settings, workspaceId, credentialId);\n if (!cred) {\n throw new CodexReloginRequired(\"No Codex subscription is connected for this workspace.\");\n }\n const exp = cred.expiresAt ?? accessTokenExpiry(cred.tokens.accessToken);\n const stale =\n force ||\n (exp\n ? exp.getTime() <= Date.now() + CODEX_REFRESH_WINDOW_MS\n : cred.lastRefreshAt\n ? cred.lastRefreshAt.getTime() < Date.now() - CODEX_REFRESH_FALLBACK_MS\n : true);\n return stale ? doRefresh(cred) : snapshot(cred);\n };\n\n return { getToken: () => resolve(false), refresh: () => resolve(true) };\n}\n\nfunction errorUsagePayload(reason?: \"needs_relogin\"): CodexUsagePayload {\n return {\n status: \"error\",\n planType: null,\n fiveHour: null,\n weekly: null,\n limitReached: false,\n fetchedAt: new Date().toISOString(),\n ...(reason ? { reason } : {}),\n };\n}\n\n/**\n * THE single per-account usage path both the api route and an (optional) worker\n * poll call, so the refresh discipline and the cache-write can never drift.\n *\n * 1. resolve a REFRESHING bearer for THIS account (proactive staleness refresh,\n * single-flight, (id,version) CAS-persist) — this is what stops an idle\n * account's expired JWT from 401-ing the usage read.\n * 2. fetch GET /wham/usage with that bearer.\n * 3. normalize (§3) into the P2/P3 contract.\n * 4. on any windows present, write the five usage-cache columns (the TTL clock).\n *\n * A refresh that stamps needs_relogin returns { status:\"error\", reason } and never\n * hits the provider; a transient refresh error returns a plain error payload.\n */\nexport async function fetchCodexUsageForAccount(\n db: Database,\n settings: Settings,\n workspaceId: string,\n credentialId: string,\n): Promise<CodexUsagePayload> {\n const resolver = buildCodexTokenResolver(db, settings, workspaceId, credentialId);\n let token: CodexTokenSnapshot;\n try {\n token = await resolver.getToken();\n } catch (error) {\n return errorUsagePayload(error instanceof CodexReloginRequired ? \"needs_relogin\" : undefined);\n }\n\n let normalized: CodexUsagePayload;\n try {\n const usage = await fetchCodexUsage({\n accessToken: token.accessToken,\n chatgptAccountId: token.chatgptAccountId,\n isFedramp: token.isFedramp,\n clientVersion: CODEX_CLIENT_VERSION,\n });\n normalized = normalizeCodexUsage(usage.status, usage.payload);\n } catch {\n // A network throw on the /wham/usage read must surface as an error PAYLOAD\n // ({status:\"error\"} at 200), never an unhandled 500 from the route.\n return errorUsagePayload();\n }\n\n if (normalized.fiveHour || normalized.weekly) {\n // Cache-write is best-effort: a disconnect under us (false) or a transient\n // write error must NOT sink the freshly-read usage we are about to return.\n await recordCodexAccountUsage(db, workspaceId, credentialId, {\n primaryUsedPercent: normalized.fiveHour?.percent ?? null,\n primaryResetAt: normalized.fiveHour?.resetAt ? new Date(normalized.fiveHour.resetAt) : null,\n secondaryUsedPercent: normalized.weekly?.percent ?? null,\n secondaryResetAt: normalized.weekly?.resetAt ? new Date(normalized.weekly.resetAt) : null,\n checkedAt: new Date(),\n }).catch(() => undefined);\n }\n\n return normalized;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAsDA,SAAS,4BAA4B,8BAA8B;AACnE,SAAS,kCAAAA,uCAAqD;AAC9D,SAAS,0BAA0B;AAGnC,SAAS,sBAAAC,2BAA0B;AACnC,SAAS,KAAK,KAAK,MAAM,IAAI,IAAI,KAAK,SAAS,IAAI,IAAI,WAAqB;AAE5E,SAAS,eAAe;AACxB,OAAO,cAAc;;;AC/DrB,SAAS,gBAAgB,kBAAkB,mBAAmB;AAE9D,IAAM,iBAAiB;AACvB,IAAM,WAAW;AACjB,IAAM,gBAAgB;AACtB,IAAM,YAAY;AAMX,SAAS,wBAAwB,KAAiB,WAA2B;AAClF,YAAU,GAAG;AACb,QAAM,KAAK,YAAY,QAAQ;AAC/B,QAAM,SAAS,eAAe,eAAe,KAAK,EAAE;AACpD,QAAM,aAAa,OAAO,OAAO,CAAC,OAAO,OAAO,WAAW,MAAM,GAAG,OAAO,MAAM,GAAG,OAAO,WAAW,CAAC,CAAC;AACxG,SAAO,GAAG,cAAc,IAAI,GAAG,SAAS,QAAQ,CAAC,IAAI,WAAW,SAAS,QAAQ,CAAC;AACpF;AAOO,SAAS,wBAAwB,KAAiB,QAAwB;AAC/E,YAAU,GAAG;AACb,QAAM,QAAQ,OAAO,MAAM,GAAG;AAC9B,MAAI,MAAM,WAAW,KAAK,MAAM,CAAC,MAAM,gBAAgB;AACrD,UAAM,IAAI,MAAM,sCAAsC;AAAA,EACxD;AACA,QAAM,KAAK,OAAO,KAAK,MAAM,CAAC,GAAI,QAAQ;AAC1C,QAAM,UAAU,OAAO,KAAK,MAAM,CAAC,GAAI,QAAQ;AAC/C,MAAI,GAAG,WAAW,YAAY,QAAQ,UAAU,eAAe;AAC7D,UAAM,IAAI,MAAM,sCAAsC;AAAA,EACxD;AACA,QAAM,MAAM,QAAQ,SAAS,QAAQ,SAAS,aAAa;AAC3D,QAAM,aAAa,QAAQ,SAAS,GAAG,QAAQ,SAAS,aAAa;AACrE,QAAM,WAAW,iBAAiB,eAAe,KAAK,EAAE;AACxD,WAAS,WAAW,GAAG;AACvB,MAAI;AACF,WAAO,OAAO,OAAO,CAAC,SAAS,OAAO,UAAU,GAAG,SAAS,MAAM,CAAC,CAAC,EAAE,SAAS,MAAM;AAAA,EACvF,QAAQ;AACN,UAAM,IAAI,MAAM,qCAAqC;AAAA,EACvD;AACF;AAEA,SAAS,UAAU,KAAuB;AACxC,MAAI,IAAI,WAAW,WAAW;AAC5B,UAAM,IAAI,MAAM,qDAAqD;AAAA,EACvE;AACF;;;AChCA,IAAM,cAAc;AAOb,SAAS,oBAAoB,OAAuB;AAGzD,MAAI,YAAY;AAChB,WAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AACrC,UAAM,OAAO,MAAM,WAAW,CAAC;AAC/B,QAAI,SAAS,KAAW,QAAQ,SAAU,QAAQ,OAAS;AACzD,kBAAY;AACZ;AAAA,IACF;AAAA,EACF;AACA,MAAI,CAAC,WAAW;AACd,WAAO;AAAA,EACT;AAEA,MAAI,MAAM;AACV,WAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AACrC,UAAM,OAAO,MAAM,WAAW,CAAC;AAC/B,QAAI,SAAS,GAAQ;AAEnB;AAAA,IACF;AACA,QAAI,QAAQ,SAAU,QAAQ,OAAQ;AAEpC,YAAM,OAAO,IAAI,IAAI,MAAM,SAAS,MAAM,WAAW,IAAI,CAAC,IAAI;AAC9D,UAAI,QAAQ,SAAU,QAAQ,OAAQ;AACpC,eAAO,MAAM,CAAC,IAAK,MAAM,IAAI,CAAC;AAC9B,aAAK;AACL;AAAA,MACF;AACA,aAAO;AACP;AAAA,IACF;AACA,QAAI,QAAQ,SAAU,QAAQ,OAAQ;AAEpC,aAAO;AACP;AAAA,IACF;AACA,WAAO,MAAM,CAAC;AAAA,EAChB;AACA,SAAO;AACT;AAQO,SAAS,qBAAwB,SAAe;AACrD,MAAI,OAAO,YAAY,UAAU;AAC/B,WAAO,oBAAoB,OAAO;AAAA,EACpC;AACA,MAAI,MAAM,QAAQ,OAAO,GAAG;AAC1B,WAAO,QAAQ,IAAI,CAAC,SAAS,qBAAqB,IAAI,CAAC;AAAA,EACzD;AACA,MAAI,WAAW,OAAO,YAAY,UAAU;AAC1C,UAAM,UAAU,OAAO,QAAQ,OAAkC,EAAE;AAAA,MACjE,CAAC,CAAC,KAAK,KAAK,MAAM,CAAC,oBAAoB,GAAG,GAAG,4BAA4B,KAAK,KAAK,CAAC;AAAA,IACtF;AACA,WAAO,OAAO,YAAY,OAAO;AAAA,EACnC;AACA,SAAO;AACT;AAEA,SAAS,4BAA4B,KAAa,OAAyB;AACzE,MAAI,QAAQ,cAAc;AACxB,WAAO,6BAA6B,KAAK;AAAA,EAC3C;AACA,MAAI,QAAQ,wBAAwB;AAClC,WAAO,gCAAgC,KAAK;AAAA,EAC9C;AACA,SAAO,qBAAqB,KAAK;AACnC;AAEA,SAAS,6BAA6B,OAAyB;AAC7D,MAAI,CAAC,MAAM,QAAQ,KAAK,GAAG;AACzB,WAAO,qBAAqB,KAAK;AAAA,EACnC;AACA,SAAO,MAAM,IAAI,CAAC,SAAS;AACzB,QAAI,CAAC,cAAc,IAAI,GAAG;AACxB,aAAO,qBAAqB,IAAI;AAAA,IAClC;AACA,UAAM,EAAE,SAAS,kBAAkB,GAAG,KAAK,IAAI;AAC/C,UAAM,UAAU,qBAAqB,IAAI;AACzC,UAAM,cAAc,gBAAgB,OAAO,KAAK,gBAAgB,gBAAgB;AAChF,QAAI,aAAa;AACf,cAAQ,cAAc;AAAA,IACxB;AACA,WAAO;AAAA,EACT,CAAC;AACH;AAEA,SAAS,gCAAgC,OAAyB;AAChE,MAAI,CAAC,MAAM,QAAQ,KAAK,GAAG;AACzB,WAAO,qBAAqB,KAAK;AAAA,EACnC;AACA,SAAO,MAAM,IAAI,CAAC,SAAS;AACzB,QAAI,CAAC,cAAc,IAAI,GAAG;AACxB,aAAO,qBAAqB,IAAI;AAAA,IAClC;AACA,UAAM,EAAE,SAAS,kBAAkB,GAAG,KAAK,IAAI;AAC/C,UAAM,UAAU,qBAAqB,IAAI;AACzC,UAAM,cAAc,gBAAgB,OAAO,KAAK,gBAAgB,gBAAgB;AAChF,QAAI,aAAa;AACf,cAAQ,cAAc;AAAA,IACxB;AACA,WAAO;AAAA,EACT,CAAC;AACH;AAEA,SAAS,gBAAgB,OAAiC;AACxD,MAAI,CAAC,cAAc,KAAK,GAAG;AACzB,WAAO;AAAA,EACT;AACA,SAAO,OAAO,KAAK,KAAK,EAAE,IAAI,mBAAmB,EAAE,KAAK;AAC1D;AAEA,SAAS,cAAc,OAAkD;AACvE,SAAO,QAAQ,SAAS,OAAO,UAAU,YAAY,CAAC,MAAM,QAAQ,KAAK,CAAC;AAC5E;;;AF7EA,SAAgB,OAAPC,YAAoB;;;AG7C7B,SAAS,sCAAqD;AAC9D;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAGA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAkBP,IAAM,WAAW,oBAAI,IAAyC;AAc9D,IAAM,cAA6B;AAAA,EACjC,gBAAgB;AAAA,EAChB,eAAe;AAAA,EACf,WAAW;AAAA,EACX,SAAS;AAAA,EACT,SAAS;AAAA,EACT,UAAU;AACZ;AAEO,SAAS,wBACd,IACA,UACA,aAMA,cACA,OAAsB,aACuE;AAC7F,QAAM,WAAW,CAAC,UAAqD;AAAA,IACrE,aAAa,KAAK,OAAO;AAAA,IACzB,kBAAkB,KAAK;AAAA,IACvB,WAAW,KAAK;AAAA,EAClB;AAEA,QAAM,iBAAiB,OAAO,SAA6D;AACzF,QAAI;AACF,YAAM,OAAO,MAAM,KAAK,QAAQ,KAAK,OAAO,YAAY;AACxD,YAAM,SAAS;AAAA,QACb,cAAc,KAAK,eAAe,KAAK,OAAO;AAAA,QAC9C,eAAe,KAAK,gBAAgB,KAAK,OAAO;AAAA,QAChD,UAAU,KAAK,WAAW,KAAK,OAAO;AAAA,MACxC;AACA,YAAM,MAAM,KAAK,SAAS,QAAQ;AAClC,UAAI,CAAC,KAAK;AACR,cAAM,IAAI,MAAM,wDAAwD;AAAA,MAC1E;AAIA,YAAM,YAAY,MAAM,KAAK,cAAc,IAAI;AAAA,QAC7C,IAAI,KAAK;AAAA,QACT,SAAS,KAAK;AAAA,QACd;AAAA,QACA,qBAAqB,KAAK,QAAQ,KAAK,KAAK,UAAU,MAAM,CAAC;AAAA,QAC7D,WAAW,kBAAkB,OAAO,YAAY;AAAA,QAChD,eAAe,oBAAI,KAAK;AAAA,MAC1B,CAAC;AACD,UAAI,CAAC,WAAW;AAId,cAAM,UAAU,MAAM,KAAK,eAAe,IAAI,UAAU,aAAa,YAAY;AACjF,YAAI,WAAW,QAAQ,WAAW,UAAU;AAC1C,iBAAO,SAAS,OAAO;AAAA,QACzB;AACA,cAAM,IAAI,qBAAqB,oEAAoE;AAAA,MACrG;AACA,aAAO,EAAE,aAAa,OAAO,cAAc,kBAAkB,KAAK,kBAAkB,WAAW,KAAK,UAAU;AAAA,IAChH,SAAS,OAAO;AACd,UAAI,iBAAiB,sBAAsB;AAKzC,cAAM,KAAK,UAAU,IAAI,aAAa,iBAAiB,MAAM,SAAS,EAAE,IAAI,KAAK,IAAI,SAAS,KAAK,QAAQ,CAAC;AAAA,MAC9G;AACA,YAAM;AAAA,IACR;AAAA,EACF;AAMA,QAAM,YAAY,CAAC,SAA6D;AAC9E,UAAM,MAAM,GAAG,KAAK,EAAE,IAAI,KAAK,OAAO;AACtC,UAAM,WAAW,SAAS,IAAI,GAAG;AACjC,QAAI,UAAU;AACZ,aAAO;AAAA,IACT;AACA,UAAM,UAAU,eAAe,IAAI,EAAE,QAAQ,MAAM;AACjD,UAAI,SAAS,IAAI,GAAG,MAAM,SAAS;AACjC,iBAAS,OAAO,GAAG;AAAA,MACrB;AAAA,IACF,CAAC;AACD,aAAS,IAAI,KAAK,OAAO;AACzB,WAAO;AAAA,EACT;AAEA,QAAM,UAAU,OAAO,UAAgD;AACrE,UAAM,OAAO,MAAM,KAAK,eAAe,IAAI,UAAU,aAAa,YAAY;AAC9E,QAAI,CAAC,MAAM;AACT,YAAM,IAAI,qBAAqB,wDAAwD;AAAA,IACzF;AACA,UAAM,MAAM,KAAK,aAAa,kBAAkB,KAAK,OAAO,WAAW;AACvE,UAAM,QACJ,UACC,MACG,IAAI,QAAQ,KAAK,KAAK,IAAI,IAAI,0BAC9B,KAAK,gBACH,KAAK,cAAc,QAAQ,IAAI,KAAK,IAAI,IAAI,4BAC5C;AACR,WAAO,QAAQ,UAAU,IAAI,IAAI,SAAS,IAAI;AAAA,EAChD;AAEA,SAAO,EAAE,UAAU,MAAM,QAAQ,KAAK,GAAG,SAAS,MAAM,QAAQ,IAAI,EAAE;AACxE;AAEA,SAAS,kBAAkB,QAA6C;AACtE,SAAO;AAAA,IACL,QAAQ;AAAA,IACR,UAAU;AAAA,IACV,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,cAAc;AAAA,IACd,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,IAClC,GAAI,SAAS,EAAE,OAAO,IAAI,CAAC;AAAA,EAC7B;AACF;AAgBA,eAAsB,0BACpB,IACA,UACA,aACA,cAC4B;AAC5B,QAAM,WAAW,wBAAwB,IAAI,UAAU,aAAa,YAAY;AAChF,MAAI;AACJ,MAAI;AACF,YAAQ,MAAM,SAAS,SAAS;AAAA,EAClC,SAAS,OAAO;AACd,WAAO,kBAAkB,iBAAiB,uBAAuB,kBAAkB,MAAS;AAAA,EAC9F;AAEA,MAAI;AACJ,MAAI;AACF,UAAM,QAAQ,MAAM,gBAAgB;AAAA,MAClC,aAAa,MAAM;AAAA,MACnB,kBAAkB,MAAM;AAAA,MACxB,WAAW,MAAM;AAAA,MACjB,eAAe;AAAA,IACjB,CAAC;AACD,iBAAa,oBAAoB,MAAM,QAAQ,MAAM,OAAO;AAAA,EAC9D,QAAQ;AAGN,WAAO,kBAAkB;AAAA,EAC3B;AAEA,MAAI,WAAW,YAAY,WAAW,QAAQ;AAG5C,UAAM,wBAAwB,IAAI,aAAa,cAAc;AAAA,MAC3D,oBAAoB,WAAW,UAAU,WAAW;AAAA,MACpD,gBAAgB,WAAW,UAAU,UAAU,IAAI,KAAK,WAAW,SAAS,OAAO,IAAI;AAAA,MACvF,sBAAsB,WAAW,QAAQ,WAAW;AAAA,MACpD,kBAAkB,WAAW,QAAQ,UAAU,IAAI,KAAK,WAAW,OAAO,OAAO,IAAI;AAAA,MACrF,WAAW,oBAAI,KAAK;AAAA,IACtB,CAAC,EAAE,MAAM,MAAM,MAAS;AAAA,EAC1B;AAEA,SAAO;AACT;;;AH3EA,IAAM,aAAa,oBAAI,QAA2B;AAG3C,SAAS,eAAe,IAA2B;AACxD,SAAO,WAAW,IAAI,EAAuB,GAAG,eAAe;AACjE;AAiBA,eAAe,QACb,UACA,OACc;AACd,QAAM,SAAS,MAAM,SAAS,QAAW,KAAK;AAC9C,SAAO;AACT;AAEO,SAAS,SAAS,aAAqB,UAA2B,CAAC,GAAa;AAUrF,QAAM,SAAS,SAAS,aAAa;AAAA,IACnC,KAAK,QAAQ,OAAO;AAAA,IACpB,SAAS;AAAA,IACT,cAAc;AAAA,IACd,cAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAMd,YAAY;AAAA,MACV,kBAAkB;AAAA,MAClB,GAAI,QAAQ,aAAa,EAAE,aAAa,QAAQ,WAAW,IAAI,CAAC;AAAA,IAClE;AAAA,EACF,CAAC;AACD,QAAM,KAAK,QAAQ,QAAQ,EAAE,uBAAO,CAAC;AACrC,aAAW,IAAI,IAAyB;AAAA,IACtC,aAAa,QAAQ,eAAe;AAAA,IACpC,GAAI,QAAQ,aAAa,EAAE,YAAY,QAAQ,WAAW,IAAI,CAAC;AAAA,EACjE,CAAC;AACD,SAAO;AAAA,IACL;AAAA,IACA,OAAO,YAAY;AACjB,YAAM,OAAO,IAAI;AAAA,IACnB;AAAA,EACF;AACF;AAQO,SAAS,kBAAkB,IAAc,SAAuE;AACrH,aAAW,IAAI,IAAyB;AAAA,IACtC,aAAa,QAAQ,eAAe;AAAA,IACpC,GAAI,QAAQ,aAAa,EAAE,YAAY,QAAQ,WAAW,IAAI,CAAC;AAAA,EACjE,CAAC;AACH;AAEA,eAAsB,cAAc,IAAc,SAAoC;AAKpF,MAAI,OAAO,QAAQ,cAAc,YAAY,QAAQ,UAAU,KAAK,MAAM,IAAI;AAC5E,UAAM,IAAI,MAAM,8EAA8E;AAAA,EAChG;AACA,QAAM,GAAG,QAAQ,+CAA+C,QAAQ,SAAS,SAAS;AAC1F,QAAM,GAAG,QAAQ,iDAAiD,QAAQ,eAAe,EAAE,SAAS;AACtG;AAEA,eAAsB,eACpB,IACA,SACA,IACY;AACZ,SAAO,MAAM,GAAG,YAAY,OAAO,OAAO;AACxC,UAAM,SAAS;AACf,UAAM,cAAc,QAAQ,OAAO;AAUnC,UAAM,UAAU,MAAM,GAAG;AAAA,MACvB;AAAA,IACF;AACA,UAAM,mBAAmB,QAAQ,CAAC,GAAG,cAAc;AACnD,QAAI,qBAAqB,QAAQ,WAAW;AAC1C,YAAM,IAAI;AAAA,QACR,mEAAmE,QAAQ,SAAS,UAAU,gBAAgB;AAAA,MAChH;AAAA,IACF;AACA,WAAO,MAAM,GAAG,MAAM;AAAA,EACxB,CAAC;AACH;AAEA,eAAsB,uBAAuB,IAAc,aAA0C;AACnG,QAAM,CAAC,GAAG,IAAI,MAAM,GAAG,OAAO,EAAE,WAAkB,WAAW,UAAU,CAAC,EACrE,KAAY,UAAU,EACtB,MAAM,GAAU,WAAW,IAAI,WAAW,CAAC,EAC3C,MAAM,CAAC;AACV,MAAI,CAAC,KAAK;AACR,UAAM,IAAI,MAAM,wBAAwB,WAAW,EAAE;AAAA,EACvD;AACA,SAAO,EAAE,WAAW,IAAI,WAAW,YAAY;AACjD;AAEA,eAAsB,iBACpB,IACA,aACA,IACY;AACZ,SAAO,MAAM,eAAe,IAAI,MAAM,uBAAuB,IAAI,WAAW,GAAG,EAAE;AACnF;AAEA,eAAsB,uBACpB,IACA,aACA,IACY;AACZ,QAAM,UAAU,MAAM,uBAAuB,IAAI,WAAW;AAC5D,SAAO,MAAM,eAAe,IAAI,SAAS,OAAO,aAAa;AAC3D,UAAM,SAAS,QAAQ,4CAA4C,SAAS,WAAW,EAAE,IAAI;AAC7F,WAAO,MAAM,GAAG,QAAQ;AAAA,EAC1B,CAAC;AACH;AAEA,eAAsB,eACpB,IACA,WACA,IACY;AACZ,SAAO,MAAM,eAAe,IAAI,EAAE,WAAW,aAAa,KAAK,GAAG,EAAE;AACtE;AAEO,IAAM,0BAAwC;AAAA,EACnD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAEO,IAAM,wBAAsC;AAAA,EACjD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAeA,eAAsB,mBAAmB,IAAc,OAAwD;AAC7G,SAAO,MAAM,GAAG,YAAY,OAAO,OAAO;AACxC,UAAM,CAAC,OAAO,IAAI,MAAM,GAAG,OAAc,eAAe,EAAE,OAAO;AAAA,MAC/D,MAAM,MAAM;AAAA,MACZ,gBAAgB,MAAM;AAAA,MACtB,YAAY,MAAM;AAAA,IACpB,CAAC,EAAE,mBAAmB;AAAA,MACpB,QAAQ,CAAQ,gBAAgB,gBAAuB,gBAAgB,UAAU;AAAA,MACjF,KAAK;AAAA,QACH,MAAM,MAAM;AAAA,QACZ,WAAW,oBAAI,KAAK;AAAA,MACtB;AAAA,IACF,CAAC,EAAE,UAAU;AACb,QAAI,CAAC,SAAS;AACZ,YAAM,IAAI,MAAM,6BAA6B;AAAA,IAC/C;AACA,UAAM,CAAC,SAAS,IAAI,MAAM,GAAG,OAAc,UAAU,EAAE,OAAO;AAAA,MAC5D,WAAW,QAAQ;AAAA,MACnB,MAAM,MAAM;AAAA,MACZ,gBAAgB,MAAM;AAAA,MACtB,YAAY,MAAM;AAAA,IACpB,CAAC,EAAE,mBAAmB;AAAA,MACpB,QAAQ,CAAQ,WAAW,gBAAuB,WAAW,UAAU;AAAA,MACvE,KAAK;AAAA,QACH,MAAM,MAAM;AAAA,QACZ,WAAW,oBAAI,KAAK;AAAA,MACtB;AAAA,IACF,CAAC,EAAE,UAAU;AACb,QAAI,CAAC,WAAW;AACd,YAAM,IAAI,MAAM,+BAA+B;AAAA,IACjD;AACA,UAAM,uBAAuB,MAAM,wBAAwB;AAC3D,UAAM,GAAG,OAAc,oBAAoB,EAAE,OAAO;AAAA,MAClD,WAAW,QAAQ;AAAA,MACnB,aAAa,UAAU;AAAA,MACvB,WAAW,MAAM;AAAA,MACjB,cAAc,MAAM,gBAAgB;AAAA,MACpC,MAAM;AAAA,MACN,aAAa;AAAA,IACf,CAAC,EAAE,mBAAmB;AAAA,MACpB,QAAQ,CAAQ,qBAAqB,WAAkB,qBAAqB,WAAW;AAAA,MACvF,KAAK;AAAA,QACH,cAAc,MAAM,gBAAgB;AAAA,QACpC,MAAM;AAAA,QACN,aAAa;AAAA,QACb,WAAW,oBAAI,KAAK;AAAA,MACtB;AAAA,IACF,CAAC;AACD,WAAO;AAAA,MACL,MAAM,MAAM,0BAA0B,mBAAmB,UAAU;AAAA,MACnE,WAAW,MAAM;AAAA,MACjB,GAAI,MAAM,eAAe,EAAE,cAAc,MAAM,aAAa,IAAI,CAAC;AAAA,MACjE,eAAe,CAAC;AAAA,QACd,WAAW,QAAQ;AAAA,QACnB,WAAW,MAAM;AAAA,QACjB,GAAI,MAAM,eAAe,EAAE,cAAc,MAAM,aAAa,IAAI,CAAC;AAAA,QACjE,MAAM;AAAA,QACN,aAAa,MAAM,sBAAsB;AAAA,MAC3C,CAAC;AAAA,MACD,iBAAiB,CAAC;AAAA,QAChB,aAAa,UAAU;AAAA,QACvB,WAAW,QAAQ;AAAA,QACnB,WAAW,MAAM;AAAA,QACjB,GAAI,MAAM,eAAe,EAAE,cAAc,MAAM,aAAa,IAAI,CAAC;AAAA,QACjE,aAAa;AAAA,MACf,CAAC;AAAA,MACD,kBAAkB,QAAQ;AAAA,MAC1B,oBAAoB,UAAU;AAAA,IAChC;AAAA,EACF,CAAC;AACH;AAEA,eAAsB,2BAA2B,IAAc,OAIpC;AACzB,QAAM,YAAY,QAAQ,MAAM,MAAM;AACtC,QAAM,eAAe,MAAM,SAAS,MAAM;AAC1C,SAAO,MAAM,GAAG,YAAY,OAAO,OAAO;AACxC,UAAM,CAAC,OAAO,IAAI,MAAM,GAAG,OAAc,eAAe,EAAE,OAAO;AAAA,MAC/D,MAAM,MAAM,QAAQ,MAAM;AAAA,MAC1B,gBAAgB;AAAA,MAChB,YAAY,MAAM;AAAA,IACpB,CAAC,EAAE,mBAAmB;AAAA,MACpB,QAAQ,CAAQ,gBAAgB,gBAAuB,gBAAgB,UAAU;AAAA,MACjF,KAAK;AAAA,QACH,MAAM,MAAM,QAAQ,MAAM;AAAA,QAC1B,WAAW,oBAAI,KAAK;AAAA,MACtB;AAAA,IACF,CAAC,EAAE,UAAU;AACb,QAAI,CAAC,SAAS;AACZ,YAAM,IAAI,MAAM,kCAAkC;AAAA,IACpD;AACA,UAAM,CAAC,gBAAgB,IAAI,MAAM,GAAG,OAAc,UAAU,EAAE,OAAO;AAAA,MACnE,WAAW,QAAQ;AAAA,MACnB,MAAM;AAAA,MACN,MAAM;AAAA,MACN,gBAAgB;AAAA,MAChB,YAAY,GAAG,MAAM,MAAM;AAAA,IAC7B,CAAC,EAAE,mBAAmB;AAAA,MACpB,QAAQ,CAAQ,WAAW,gBAAuB,WAAW,UAAU;AAAA,MACvE,KAAK;AAAA,QACH,MAAM;AAAA,QACN,WAAW,oBAAI,KAAK;AAAA,MACtB;AAAA,IACF,CAAC,EAAE,UAAU;AACb,QAAI,CAAC,kBAAkB;AACrB,YAAM,IAAI,MAAM,oCAAoC;AAAA,IACtD;AACA,UAAM,GAAG,OAAc,oBAAoB,EAAE,OAAO;AAAA,MAClD,WAAW,QAAQ;AAAA,MACnB,aAAa,iBAAiB;AAAA,MAC9B;AAAA,MACA;AAAA,MACA,MAAM;AAAA,MACN,aAAa;AAAA,IACf,CAAC,EAAE,mBAAmB;AAAA,MACpB,QAAQ,CAAQ,qBAAqB,WAAkB,qBAAqB,WAAW;AAAA,MACvF,KAAK;AAAA,QACH;AAAA,QACA,MAAM;AAAA,QACN,aAAa;AAAA,QACb,WAAW,oBAAI,KAAK;AAAA,MACtB;AAAA,IACF,CAAC;AACD,UAAM,cAAc,MAAM,GAAG,OAAO;AAAA,MAClC,YAAmB;AAAA,MACnB,WAAkB;AAAA,IACpB,CAAC,EAAE,KAAY,oBAAoB,EAChC,UAAiB,YAAY,GAAU,qBAAqB,aAAoB,WAAW,EAAE,CAAC,EAC9F,MAAM,GAAU,qBAAqB,WAAW,SAAS,CAAC,EAC1D,QAAQ,KAAY,WAAW,SAAS,CAAC;AAC5C,WAAO;AAAA,MACL,MAAM;AAAA,MACN;AAAA,MACA;AAAA,MACA,eAAe,CAAC;AAAA,QACd,WAAW,QAAQ;AAAA,QACnB;AAAA,QACA;AAAA,QACA,MAAM;AAAA,QACN,aAAa;AAAA,MACf,CAAC;AAAA,MACD,iBAAiB,YAAY,IAAI,CAAC,SAAS;AAAA,QACzC,aAAa,IAAI,UAAU;AAAA,QAC3B,WAAW,IAAI,UAAU;AAAA,QACzB;AAAA,QACA;AAAA,QACA,aAAa,IAAI,WAAW;AAAA,MAC9B,EAAE;AAAA,MACF,kBAAkB,QAAQ;AAAA,MAC1B,oBAAoB,iBAAiB;AAAA,IACvC;AAAA,EACF,CAAC;AACH;AAEA,eAAsB,aAAa,IAAc,aAAgD;AAC/F,QAAM,CAAC,GAAG,IAAI,MAAM,GAAG,OAAO,EAAE,KAAY,UAAU,EAAE,MAAM,GAAU,WAAW,IAAI,WAAW,CAAC,EAAE,MAAM,CAAC;AAC5G,SAAO,MAAM,aAAa,GAAG,IAAI;AACnC;AAEA,eAAsB,kBAAkB,IAAc,WAAmD;AACvG,QAAM,CAAC,GAAG,IAAI,MAAM,GAAG,OAAO,EAAE,KAAY,eAAe,EAAE,MAAM,GAAU,gBAAgB,IAAI,SAAS,CAAC,EAAE,MAAM,CAAC;AACpH,SAAO,MAAM,WAAW,GAAG,IAAI;AACjC;AAEA,eAAsB,iBAAiB,IAAc,aAAyC;AAC5F,QAAM,YAAY,MAAM,aAAa,IAAI,WAAW;AACpD,MAAI,CAAC,WAAW;AACd,UAAM,IAAI,MAAM,wBAAwB,WAAW,EAAE;AAAA,EACvD;AACA,SAAO;AACT;AAEA,eAAsB,yBAAyB,IAAc,WAAmB,QAAQ,KAA2B;AACjH,QAAM,OAAO,MAAM,GAAG,OAAO,EAAE,WAAkB,WAAW,CAAC,EAAE,KAAY,oBAAoB,EAC5F,UAAiB,YAAY,GAAU,qBAAqB,aAAoB,WAAW,EAAE,CAAC,EAC9F,MAAM,GAAU,qBAAqB,WAAW,SAAS,CAAC,EAC1D,QAAQ,KAAY,WAAW,SAAS,CAAC,EACzC,MAAM,KAAK;AACd,SAAO,KAAK,IAAI,CAAC,QAAQ,aAAa,IAAI,SAAS,CAAC;AACtD;AAEA,eAAsB,0BAA0B,IAAc,WAAoC;AAChG,QAAM,CAAC,EAAE,MAAM,IAAI,EAAE,OAAO,EAAE,CAAC,IAAI,MAAM,GAAG,OAAO;AAAA,IACjD,OAAO;AAAA,EACT,CAAC,EAAE,KAAY,UAAU,EAAE,MAAM,GAAU,WAAW,WAAW,SAAS,CAAC;AAC3E,SAAO,OAAO,KAAK;AACrB;AAEA,eAAsB,gBAAgB,IAAc,OAO7B;AACrB,QAAM,CAAC,GAAG,IAAI,MAAM,GAAG,OAAc,UAAU,EAAE,OAAO;AAAA,IACtD,WAAW,MAAM;AAAA,IACjB,MAAM,MAAM;AAAA,IACZ,MAAM,MAAM,QAAQ;AAAA,IACpB,gBAAgB,MAAM,kBAAkB;AAAA,IACxC,YAAY,MAAM,cAAc;AAAA,IAChC,mBAAmB,MAAM,qBAAqB;AAAA,EAChD,CAAC,EAAE,UAAU;AACb,MAAI,CAAC,KAAK;AACR,UAAM,IAAI,MAAM,4BAA4B;AAAA,EAC9C;AACA,SAAO,aAAa,GAAG;AACzB;AAEA,eAAsB,qBAAqB,IAAc,OAOvC;AAChB,QAAM,GAAG,OAAc,oBAAoB,EAAE,OAAO;AAAA,IAClD,WAAW,MAAM;AAAA,IACjB,aAAa,MAAM;AAAA,IACnB,WAAW,MAAM;AAAA,IACjB,cAAc,MAAM,gBAAgB;AAAA,IACpC,MAAM,MAAM,QAAQ;AAAA,IACpB,aAAa,MAAM;AAAA,EACrB,CAAC,EAAE,mBAAmB;AAAA,IACpB,QAAQ,CAAQ,qBAAqB,WAAkB,qBAAqB,WAAW;AAAA,IACvF,KAAK;AAAA,MACH,cAAc,MAAM,gBAAgB;AAAA,MACpC,MAAM,MAAM,QAAQ;AAAA,MACpB,aAAa,MAAM;AAAA,MACnB,WAAW,oBAAI,KAAK;AAAA,IACtB;AAAA,EACF,CAAC;AACH;AAEA,eAAsB,gBAAgB,IAAc,aAAqB,OAIlD;AACrB,QAAM,CAAC,GAAG,IAAI,MAAM,GAAG,OAAc,UAAU,EAAE,IAAI;AAAA,IACnD,GAAI,MAAM,SAAS,SAAY,EAAE,MAAM,MAAM,KAAK,IAAI,CAAC;AAAA,IACvD,GAAI,MAAM,SAAS,SAAY,EAAE,MAAM,MAAM,KAAK,IAAI,CAAC;AAAA,IACvD,GAAI,MAAM,sBAAsB,SAAY,EAAE,mBAAmB,MAAM,kBAAkB,IAAI,CAAC;AAAA,IAC9F,WAAW,oBAAI,KAAK;AAAA,EACtB,CAAC,EAAE,MAAM,GAAU,WAAW,IAAI,WAAW,CAAC,EAAE,UAAU;AAC1D,MAAI,CAAC,KAAK;AACR,UAAM,IAAI,MAAM,wBAAwB,WAAW,EAAE;AAAA,EACvD;AACA,SAAO,aAAa,GAAG;AACzB;AAEA,eAAsB,kBAAkB,IAAc,WAAmB,aAAkD;AACzH,QAAM,CAAC,GAAG,IAAI,MAAM,GAAG,OAAO;AAAA,IAC5B,YAAmB;AAAA,IACnB,WAAkB;AAAA,EACpB,CAAC,EAAE,KAAY,oBAAoB,EAChC,UAAiB,YAAY,GAAU,qBAAqB,aAAoB,WAAW,EAAE,CAAC,EAC9F,MAAM,IAAI,GAAU,qBAAqB,WAAW,SAAS,GAAG,GAAU,qBAAqB,aAAa,WAAW,CAAC,CAAC,EACzH,MAAM,CAAC;AACV,SAAO,MAAM;AAAA,IACX,aAAa,IAAI,UAAU;AAAA,IAC3B,WAAW,IAAI,UAAU;AAAA,IACzB,WAAW,IAAI,WAAW;AAAA,IAC1B,GAAI,IAAI,WAAW,eAAe,EAAE,cAAc,IAAI,WAAW,aAAa,IAAI,CAAC;AAAA,IACnF,aAAa,IAAI,WAAW;AAAA,EAC9B,IAAI;AACN;AAEA,eAAsB,qBAAqB,IAAc,aAAiD;AACxG,SAAO,MAAM,iBAAiB,IAAI,aAAa,OAAO,aAAa;AACjE,UAAM,OAAO,MAAM,SAAS,OAAO,EAAE,KAAY,oBAAoB,EAClE,MAAM,GAAU,qBAAqB,aAAa,WAAW,CAAC,EAC9D,QAAQ,IAAW,qBAAqB,SAAS,CAAC;AACrD,WAAO,KAAK,IAAI,kBAAkB;AAAA,EACpC,CAAC;AACH;AAEA,eAAsB,sBAAsB,IAAc,aAAqB,WAAqC;AAClH,SAAO,MAAM,iBAAiB,IAAI,aAAa,OAAO,aAAa;AACjE,UAAM,OAAO,MAAM,SAAS,OAAc,oBAAoB,EAC3D,MAAM,IAAI,GAAU,qBAAqB,aAAa,WAAW,GAAG,GAAU,qBAAqB,WAAW,SAAS,CAAC,CAAC,EACzH,UAAU,EAAE,IAAW,qBAAqB,GAAG,CAAC;AACnD,WAAO,KAAK,SAAS;AAAA,EACvB,CAAC;AACH;AAmBA,eAAsB,sBAAsB,IAAc,OAAuC;AAC/F,QAAM,UAAU,WAAW,IAAI,EAAuB;AACtD,MAAI,SAAS,YAAY;AACvB,WAAO,MAAM,QAAQ,WAAW,IAAI,KAAK;AAAA,EAC3C;AACA,QAAM,OAAO,MAAM,GAAG,QAAQ;AAAA,2DAC2B,KAAK;AAAA,GAC7D;AACD,SAAS,KAA2C,CAAC,GAAG,MAAO;AACjE;AAEA,eAAsB,gBAAgB,IAAc,aAAoC;AACtF,QAAM,GAAG,OAAc,UAAU,EAAE,MAAM,GAAU,WAAW,IAAI,WAAW,CAAC;AAChF;AAEA,eAAsB,aAAa,IAAc,OAQ7B;AAClB,SAAO,MAAM,eAAe,IAAI,EAAE,WAAW,MAAM,WAAW,aAAa,MAAM,eAAe,KAAK,GAAG,OAAO,aAAa;AAC1H,UAAM,CAAC,GAAG,IAAI,MAAM,SAAS,OAAc,OAAO,EAAE,OAAO;AAAA,MACzD,WAAW,MAAM;AAAA,MACjB,aAAa,MAAM,eAAe;AAAA,MAClC,MAAM,MAAM;AAAA,MACZ,QAAQ,MAAM;AAAA,MACd,SAAS,MAAM;AAAA,MACf,aAAa,MAAM;AAAA,MACnB,WAAW,MAAM,aAAa;AAAA,IAChC,CAAC,EAAE,UAAU;AACb,QAAI,CAAC,KAAK;AACR,YAAM,IAAI,MAAM,0BAA0B;AAAA,IAC5C;AACA,WAAO,UAAU,GAAG;AAAA,EACtB,CAAC;AACH;AAEA,eAAsB,YAAY,IAAc,aAAwC;AACtF,SAAO,MAAM,iBAAiB,IAAI,aAAa,OAAO,aAAa;AACjE,UAAM,OAAO,MAAM,SAAS,OAAO,EAAE,KAAY,OAAO,EACrD,MAAM,GAAU,QAAQ,aAAa,WAAW,CAAC,EACjD,QAAQ,KAAY,QAAQ,SAAS,CAAC;AACzC,WAAO,KAAK,IAAI,SAAS;AAAA,EAC3B,CAAC;AACH;AAEA,eAAsB,+BAA+B,IAAc,aAAsC;AACvG,SAAO,MAAM,iBAAiB,IAAI,aAAa,OAAO,aAAa;AACjE,UAAM,CAAC,EAAE,MAAM,IAAI,EAAE,OAAO,EAAE,CAAC,IAAI,MAAM,SAAS,OAAO;AAAA,MACvD,OAAO;AAAA,IACT,CAAC,EAAE,KAAY,OAAO,EACnB,MAAM,IAAI,GAAU,QAAQ,aAAa,WAAW,GAAG,MAAa,QAAQ,SAAS,YAAY,OAAc,QAAQ,SAAS,eAAsB,QAAQ,SAAS,WAAW,CAAC;AACtL,WAAO,OAAO,KAAK;AAAA,EACrB,CAAC;AACH;AAEA,eAAsB,aAAa,IAAc,aAAqB,UAAmC;AACvG,SAAO,MAAM,iBAAiB,IAAI,aAAa,OAAO,aAAa;AACjE,UAAM,CAAC,GAAG,IAAI,MAAM,SAAS,OAAc,OAAO,EAAE,IAAI;AAAA,MACtD,WAAW,oBAAI,KAAK;AAAA,MACpB,WAAW,oBAAI,KAAK;AAAA,IACtB,CAAC,EAAE,MAAM,IAAI,GAAU,QAAQ,aAAa,WAAW,GAAG,GAAU,QAAQ,IAAI,QAAQ,CAAC,CAAC,EAAE,UAAU;AACtG,QAAI,CAAC,KAAK;AACR,YAAM,IAAI,MAAM,sBAAsB,QAAQ,EAAE;AAAA,IAClD;AACA,WAAO,UAAU,GAAG;AAAA,EACtB,CAAC;AACH;AAEA,eAAsB,uBAAuB,IAAc,SAAyC;AAClG,SAAO,MAAM,GAAG,YAAY,OAAO,OAAO;AACxC,UAAM,GAAG,QAAQ,iDAAiD,OAAO,SAAS;AAClF,UAAM,CAAC,GAAG,IAAI,MAAM,GAAG,OAAO,EAAE,KAAY,OAAO,EAChD,MAAM,IAAI,GAAU,QAAQ,SAAS,OAAO,GAAG,MAAa,QAAQ,SAAS,YAAY,OAAc,QAAQ,SAAS,eAAsB,QAAQ,SAAS,WAAW,CAAC,EAC3K,MAAM,CAAC;AACV,QAAI,CAAC,KAAK;AACR,aAAO;AAAA,IACT;AACA,UAAM,MAAM,oBAAI,KAAK;AACrB,UAAM,GAAG,OAAc,OAAO,EAAE,IAAI,EAAE,YAAY,KAAK,WAAW,IAAI,CAAC,EAAE,MAAM,GAAU,QAAQ,IAAI,IAAI,EAAE,CAAC;AAC5G,WAAO,UAAU,EAAE,GAAG,KAAK,YAAY,IAAI,CAAC;AAAA,EAC9C,CAAC;AACH;AAaA,eAAsB,yBAAyB,IAAc,OAM7B;AAC9B,SAAO,MAAM,eAAe,IAAI,EAAE,WAAW,MAAM,WAAW,aAAa,MAAM,YAAY,GAAG,OAAO,aAAa;AAClH,UAAM,CAAC,GAAG,IAAI,MAAM,SAAS,OAAc,mBAAmB,EAAE,OAAO;AAAA,MACrE,WAAW,MAAM;AAAA,MACjB,aAAa,MAAM;AAAA,MACnB,gBAAgB,MAAM;AAAA,MACtB,cAAc,MAAM,gBAAgB;AAAA,MACpC,aAAa,MAAM,eAAe;AAAA,IACpC,CAAC,EAAE,mBAAmB;AAAA,MACpB,QAAQ,CAAQ,oBAAoB,aAAoB,oBAAoB,cAAc;AAAA,MAC1F,KAAK;AAAA,QACH,WAAW,MAAM;AAAA,QACjB,cAAc,MAAM,gBAAgB;AAAA,QACpC,aAAa,MAAM,eAAe;AAAA,QAClC,WAAW,oBAAI,KAAK;AAAA,MACtB;AAAA,IACF,CAAC,EAAE,UAAU;AACb,QAAI,CAAC,KAAK;AACR,YAAM,IAAI,MAAM,sCAAsC;AAAA,IACxD;AACA,WAAO,sBAAsB,GAAG;AAAA,EAClC,CAAC;AACH;AAEA,eAAsB,oCAAoC,IAAc,aAAoD;AAC1H,SAAO,MAAM,iBAAiB,IAAI,aAAa,OAAO,aAAa;AACjE,UAAM,OAAO,MAAM,SAAS,OAAO,EAAE,KAAY,mBAAmB,EACjE,MAAM,GAAU,oBAAoB,aAAa,WAAW,CAAC,EAC7D,QAAQ,KAAY,oBAAoB,SAAS,CAAC;AACrD,WAAO,KAAK,IAAI,qBAAqB;AAAA,EACvC,CAAC;AACH;AAEA,eAAsB,sCAAsC,IAAc,aAAwC;AAChH,SAAO,MAAM,iBAAiB,IAAI,aAAa,OAAO,aAAa;AACjE,UAAM,OAAO,MAAM,SAAS,OAAO,EAAE,gBAAuB,oBAAoB,eAAe,CAAC,EAC7F,KAAY,mBAAmB,EAC/B,MAAM,GAAU,oBAAoB,aAAa,WAAW,CAAC,EAC7D,QAAQ,KAAY,oBAAoB,SAAS,CAAC;AACrD,WAAO,KAAK,IAAI,CAAC,QAAQ,IAAI,cAAc;AAAA,EAC7C,CAAC;AACH;AAEA,eAAsB,iBAAiB,IAAc,OAW7B;AACtB,SAAO,MAAM,eAAe,IAAI,EAAE,WAAW,MAAM,WAAW,aAAa,MAAM,YAAY,GAAG,OAAO,aAAa;AAClH,UAAM,CAAC,GAAG,IAAI,MAAM,SAAS,OAAc,WAAW,EAAE,OAAO;AAAA,MAC7D,WAAW,MAAM;AAAA,MACjB,aAAa,MAAM;AAAA,MACnB,WAAW,MAAM,aAAa;AAAA,MAC9B,WAAW,MAAM;AAAA,MACjB,UAAU,MAAM;AAAA,MAChB,MAAM,MAAM;AAAA,MACZ,oBAAoB,MAAM,sBAAsB;AAAA,MAChD,kBAAkB,MAAM,oBAAoB;AAAA,MAC5C,gBAAgB,MAAM;AAAA,MACtB,YAAY,MAAM,cAAc,oBAAI,KAAK;AAAA,IAC3C,CAAC,EAAE,oBAAoB,EAAE,QAAe,YAAY,eAAe,CAAC,EAAE,UAAU;AAChF,QAAI,KAAK;AACP,aAAO,cAAc,GAAG;AAAA,IAC1B;AACA,UAAM,CAAC,QAAQ,IAAI,MAAM,SAAS,OAAO,EAAE,KAAY,WAAW,EAAE,MAAM,GAAU,YAAY,gBAAgB,MAAM,cAAc,CAAC,EAAE,MAAM,CAAC;AAC9I,QAAI,CAAC,UAAU;AACb,YAAM,IAAI,MAAM,8BAA8B;AAAA,IAChD;AACA,WAAO,cAAc,QAAQ;AAAA,EAC/B,CAAC;AACH;AAEA,eAAsB,gBAAgB,IAAc,OAI1B;AACxB,SAAO,MAAM,eAAe,IAAI,EAAE,WAAW,MAAM,WAAW,aAAa,MAAM,eAAe,KAAK,GAAG,OAAO,aAAa;AAC1H,UAAM,OAAO,MAAM,SAAS,OAAO,EAAE,KAAY,WAAW,EACzD,MAAM,MAAM,cACT,IAAI,GAAU,YAAY,WAAW,MAAM,SAAS,GAAG,GAAU,YAAY,aAAa,MAAM,WAAW,CAAC,IAC5G,GAAU,YAAY,WAAW,MAAM,SAAS,CAAC,EACpD,QAAQ,KAAY,YAAY,UAAU,GAAG,KAAY,YAAY,UAAU,CAAC,EAChF,MAAM,MAAM,SAAS,GAAG;AAC3B,WAAO,KAAK,IAAI,aAAa;AAAA,EAC/B,CAAC;AACH;AAEA,eAAsB,iBAAiB,IAAc,OAKjC;AAClB,QAAM,UAAU,MAAM,cAClB,MAAM,uBAAuB,IAAI,MAAM,WAAW,IAClD,MAAM,YACJ,EAAE,WAAW,MAAM,WAAW,aAAa,KAAK,IAChD;AACN,MAAI,CAAC,SAAS;AACZ,UAAM,IAAI,MAAM,yDAAyD;AAAA,EAC3E;AACA,SAAO,MAAM,eAAe,IAAI,SAAS,OAAO,aAAa;AAC3D,UAAM,UAAU;AAAA,MACd,GAAU,YAAY,WAAW,MAAM,SAAS;AAAA,MAChD,GAAI,MAAM,YAAY,CAAC,GAAU,YAAY,WAAW,MAAM,SAAS,CAAC,IAAI,CAAC;AAAA,MAC7E,GAAI,MAAM,cAAc,CAAC,GAAU,YAAY,aAAa,MAAM,WAAW,CAAC,IAAI,CAAC;AAAA,MACnF,GAAI,MAAM,QAAQ,CAAC,GAAU,YAAY,YAAY,MAAM,KAAK,CAAC,IAAI,CAAC;AAAA,IACxE;AACA,UAAM,CAAC,EAAE,MAAM,IAAI,EAAE,OAAO,EAAE,CAAC,IAAI,MAAM,SAAS,OAAO;AAAA,MACvD,OAAO,mBAAkC,YAAY,QAAQ;AAAA,IAC/D,CAAC,EAAE,KAAY,WAAW,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC;AACjD,WAAO,OAAO,KAAK;AAAA,EACrB,CAAC;AACH;AAEA,eAAsB,uBAAuB,IAAc,OAU/B;AAC1B,SAAO,MAAM,eAAe,IAAI,EAAE,WAAW,MAAM,WAAW,aAAa,MAAM,eAAe,KAAK,GAAG,OAAO,aAAa;AAC1H,UAAM,SAAS,OAAc,mBAAmB,EAAE,OAAO;AAAA,MACvD,WAAW,MAAM;AAAA,MACjB,aAAa,MAAM,eAAe;AAAA,MAClC,MAAM,MAAM;AAAA,MACZ,cAAc,MAAM;AAAA,MACpB,YAAY,MAAM,cAAc;AAAA,MAChC,UAAU,MAAM,YAAY;AAAA,MAC5B,gBAAgB,MAAM;AAAA,MACtB,UAAU,MAAM,YAAY,CAAC;AAAA,MAC7B,YAAY,MAAM,cAAc,oBAAI,KAAK;AAAA,IAC3C,CAAC,EAAE,oBAAoB,EAAE,QAAe,oBAAoB,eAAe,CAAC;AAC5E,WAAO,MAAM,kBAAkB,UAAU,MAAM,SAAS;AAAA,EAC1D,CAAC;AACH;AAEA,eAAsB,4BAA4B,IAAc,OAUA;AAC9D,MAAI,MAAM,yBAAyB,GAAG;AACpC,WAAO,EAAE,SAAS,MAAM,kBAAkB,IAAI,MAAM,SAAS,GAAG,eAAe,EAAE;AAAA,EACnF;AACA,SAAO,MAAM,eAAe,IAAI,EAAE,WAAW,MAAM,WAAW,aAAa,MAAM,eAAe,KAAK,GAAG,OAAO,aAAa;AAC1H,UAAM,SAAS,QAAQ,4CAA4C,MAAM,SAAS,IAAI;AACtF,UAAM,SAAS,MAAM,kBAAkB,UAAU,MAAM,SAAS;AAChE,UAAM,gBAAgB,KAAK,IAAI,MAAM,uBAAuB,KAAK,IAAI,GAAG,OAAO,aAAa,CAAC;AAC7F,QAAI,gBAAgB,GAAG;AACrB,YAAM,SAAS,OAAc,mBAAmB,EAAE,OAAO;AAAA,QACvD,WAAW,MAAM;AAAA,QACjB,aAAa,MAAM,eAAe;AAAA,QAClC,MAAM,MAAM;AAAA,QACZ,cAAc,CAAC;AAAA,QACf,YAAY,MAAM,cAAc;AAAA,QAChC,UAAU,MAAM,YAAY;AAAA,QAC5B,gBAAgB,MAAM;AAAA,QACtB,UAAU;AAAA,UACR,GAAG,MAAM;AAAA,UACT,uBAAuB,MAAM;AAAA,UAC7B;AAAA,QACF;AAAA,QACA,YAAY,MAAM,cAAc,oBAAI,KAAK;AAAA,MAC3C,CAAC,EAAE,oBAAoB,EAAE,QAAe,oBAAoB,eAAe,CAAC;AAAA,IAC9E;AACA,WAAO,EAAE,SAAS,MAAM,kBAAkB,UAAU,MAAM,SAAS,GAAG,cAAc;AAAA,EACtF,CAAC;AACH;AAEA,eAAsB,qBAAqB,IAAc,WAAmB,gBAA0C;AACpH,SAAO,MAAM,eAAe,IAAI,WAAW,OAAO,aAAa;AAC7D,UAAM,CAAC,GAAG,IAAI,MAAM,SAAS,OAAO,EAAE,IAAW,oBAAoB,GAAG,CAAC,EACtE,KAAY,mBAAmB,EAC/B,MAAM,IAAI,GAAU,oBAAoB,WAAW,SAAS,GAAG,GAAU,oBAAoB,gBAAgB,cAAc,CAAC,CAAC,EAC7H,MAAM,CAAC;AACV,WAAO,QAAQ,GAAG;AAAA,EACpB,CAAC;AACH;AAEA,eAAsB,mBAAmB,IAAc,WAAmB,WAAW,UAK3E;AACR,SAAO,MAAM,eAAe,IAAI,WAAW,OAAO,aAAa;AAC7D,UAAM,CAAC,GAAG,IAAI,MAAM,SAAS,OAAO,EAAE,KAAY,gBAAgB,EAC/D,MAAM,IAAI,GAAU,iBAAiB,WAAW,SAAS,GAAG,GAAU,iBAAiB,UAAU,QAAQ,CAAC,CAAC,EAC3G,MAAM,CAAC;AACV,WAAO,MAAM;AAAA,MACX,WAAW,IAAI;AAAA,MACf,UAAU,IAAI;AAAA,MACd,oBAAoB,IAAI;AAAA,MACxB,OAAO,IAAI;AAAA,IACb,IAAI;AAAA,EACN,CAAC;AACH;AAEA,eAAsB,sBAAsB,IAAc,OAKxC;AAChB,QAAM,eAAe,IAAI,MAAM,WAAW,OAAO,aAAa;AAC5D,UAAM,SAAS,OAAc,gBAAgB,EAAE,OAAO;AAAA,MACpD,WAAW,MAAM;AAAA,MACjB,UAAU,MAAM,YAAY;AAAA,MAC5B,oBAAoB,MAAM;AAAA,MAC1B,OAAO,MAAM,SAAS;AAAA,IACxB,CAAC,EAAE,mBAAmB;AAAA,MACpB,QAAQ,CAAQ,iBAAiB,WAAkB,iBAAiB,QAAQ;AAAA,MAC5E,KAAK;AAAA,QACH,oBAAoB,MAAM;AAAA,QAC1B,OAAO,MAAM,SAAS;AAAA,QACtB,WAAW,oBAAI,KAAK;AAAA,MACtB;AAAA,IACF,CAAC;AAAA,EACH,CAAC;AACH;AAEA,eAAsB,yBAAyB,IAAc,OAKxC;AACnB,QAAM,CAAC,GAAG,IAAI,MAAM,GAAG,OAAc,mBAAmB,EAAE,OAAO;AAAA,IAC/D,IAAI,MAAM;AAAA,IACV,MAAM,MAAM;AAAA,IACZ,UAAU,OAAO,MAAM,QAAQ;AAAA,IAC/B,SAAS,MAAM;AAAA,EACjB,CAAC,EAAE,oBAAoB,EAAE,QAAe,oBAAoB,GAAG,CAAC,EAAE,UAAU,EAAE,IAAW,oBAAoB,GAAG,CAAC;AACjH,SAAO,QAAQ,GAAG;AACpB;AAEA,eAAsB,yBAAyB,IAAc,IAA8B;AACzF,QAAM,CAAC,GAAG,IAAI,MAAM,GAAG,OAAO,EAAE,aAAoB,oBAAoB,YAAY,CAAC,EAClF,KAAY,mBAAmB,EAC/B,MAAM,GAAU,oBAAoB,IAAI,EAAE,CAAC,EAC3C,MAAM,CAAC;AACV,SAAO,QAAQ,KAAK,WAAW;AACjC;AAEA,eAAsB,2BAA2B,IAAc,IAA2B;AACxF,QAAM,GAAG,OAAc,mBAAmB,EAAE,IAAI,EAAE,aAAa,oBAAI,KAAK,EAAE,CAAC,EAAE,MAAM,GAAU,oBAAoB,IAAI,EAAE,CAAC;AAC1H;AAEA,eAAsB,kBAAkB,IAAc,WAA4C;AAChG,SAAO,MAAM,eAAe,IAAI,WAAW,OAAO,aAAa;AAC7D,UAAM,CAAC,EAAE,QAAQ,IAAI,EAAE,SAAS,EAAE,CAAC,IAAI,MAAM,SAAS,OAAO;AAAA,MAC3D,SAAS,mBAAkC,oBAAoB,YAAY;AAAA,IAC7E,CAAC,EAAE,KAAY,mBAAmB,EAAE,MAAM,GAAU,oBAAoB,WAAW,SAAS,CAAC;AAC7F,WAAO;AAAA,MACL;AAAA,MACA,eAAe,OAAO,OAAO;AAAA,MAC7B,UAAU;AAAA,MACV,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,IACpC;AAAA,EACF,CAAC;AACH;AAEA,eAAsB,gCAAgC,IAAc,aAAsC;AACxG,SAAO,MAAM,iBAAiB,IAAI,aAAa,OAAO,aAAa;AACjE,UAAM,CAAC,EAAE,MAAM,IAAI,EAAE,OAAO,EAAE,CAAC,IAAI,MAAM,SAAS,OAAO;AAAA,MACvD,OAAO;AAAA,IACT,CAAC,EAAE,KAAY,cAAc,EAAE,MAAM,GAAU,eAAe,aAAa,WAAW,CAAC;AACvF,WAAO,OAAO,KAAK;AAAA,EACrB,CAAC;AACH;AA+KA,eAAsB,iBAAiB,IAAc,OAYiB;AACpE,SAAO,MAAM,eAAe,IAAI,EAAE,WAAW,MAAM,WAAW,aAAa,MAAM,YAAY,GAAG,OAAO,aAAa,MAAM,SAAS,YAAY,OAAO,OAAO;AAC3J,UAAM,CAAC,OAAO,IAAI,MAAM,GAAG,OAAc,KAAK,EAAE,OAAO;AAAA,MACrD,IAAI,MAAM;AAAA,MACV,WAAW,MAAM;AAAA,MACjB,aAAa,MAAM;AAAA,MACnB,UAAU,MAAM;AAAA,MAChB,cAAc,MAAM;AAAA,MACpB,aAAa,MAAM;AAAA,MACnB,WAAW,MAAM;AAAA,MACjB,QAAQ,MAAM,UAAU;AAAA,MACxB,QAAQ,MAAM;AAAA,MACd,WAAW,MAAM;AAAA,MACjB,QAAQ;AAAA,IACV,CAAC,EAAE,UAAU;AACb,QAAI,CAAC,SAAS;AACZ,YAAM,IAAI,MAAM,uBAAuB;AAAA,IACzC;AACA,UAAM,CAAC,SAAS,IAAI,MAAM,GAAG,OAAc,WAAW,EAAE,OAAO;AAAA,MAC7D,WAAW,MAAM;AAAA,MACjB,aAAa,MAAM;AAAA,MACnB,QAAQ,QAAQ;AAAA,MAChB,QAAQ;AAAA,MACR,WAAW,MAAM;AAAA,IACnB,CAAC,EAAE,UAAU,EAAE,IAAW,YAAY,IAAI,WAAkB,YAAY,UAAU,CAAC;AACnF,QAAI,CAAC,WAAW;AACd,YAAM,IAAI,MAAM,8BAA8B;AAAA,IAChD;AACA,WAAO;AAAA,MACL,MAAM,QAAQ,OAAO;AAAA,MACrB,UAAU,UAAU;AAAA,MACpB,WAAW,UAAU,UAAU,YAAY;AAAA,IAC7C;AAAA,EACF,CAAC,CAAC;AACJ;AAEA,eAAsB,QAAQ,IAAc,aAAqB,QAA2C;AAC1G,SAAO,MAAM,iBAAiB,IAAI,aAAa,OAAO,aAAa;AACjE,UAAM,CAAC,GAAG,IAAI,MAAM,SAAS,OAAO,EAAE,KAAY,KAAK,EAAE,MAAM,IAAI,GAAU,MAAM,aAAa,WAAW,GAAG,GAAU,MAAM,IAAI,MAAM,CAAC,CAAC,EAAE,MAAM,CAAC;AACnJ,WAAO,MAAM,QAAQ,GAAG,IAAI;AAAA,EAC9B,CAAC;AACH;AAEA,eAAsB,YAAY,IAAc,aAAqB,QAAoC;AACvG,QAAM,OAAO,MAAM,QAAQ,IAAI,aAAa,MAAM;AAClD,MAAI,CAAC,MAAM;AACT,UAAM,IAAI,MAAM,mBAAmB,MAAM,EAAE;AAAA,EAC7C;AACA,SAAO;AACT;AAEA,eAAsB,cAAc,IAAc,aAAqB,UAA8G;AACnL,SAAO,MAAM,iBAAiB,IAAI,aAAa,OAAO,aAAa;AACjE,UAAM,CAAC,GAAG,IAAI,MAAM,SAAS,OAAO;AAAA,MAClC,IAAW,YAAY;AAAA,MACvB,QAAe,YAAY;AAAA,MAC3B,WAAkB,YAAY;AAAA,MAC9B,MAAa;AAAA,IACf,CAAC,EAAE,KAAY,WAAW,EACvB,UAAiB,OAAO,GAAU,YAAY,QAAe,MAAM,EAAE,CAAC,EACtE,MAAM,IAAI,GAAU,YAAY,aAAa,WAAW,GAAG,GAAU,YAAY,IAAI,QAAQ,CAAC,CAAC,EAC/F,MAAM,CAAC;AACV,WAAO,MAAM;AAAA,MACX,IAAI,IAAI;AAAA,MACR,QAAQ,IAAI;AAAA,MACZ,WAAW,IAAI;AAAA,MACf,MAAM,QAAQ,IAAI,IAAI;AAAA,IACxB,IAAI;AAAA,EACN,CAAC;AACH;AAEA,eAAsB,mBAAmB,IAAc,aAAqB,UAAsC;AAChH,SAAO,MAAM,iBAAiB,IAAI,aAAa,OAAO,aAAa,MAAM,SAAS,YAAY,OAAO,OAAO;AAC1G,UAAM,CAAC,SAAS,IAAI,MAAM,GAAG,OAAO,EAAE,KAAY,WAAW,EAAE,MAAM,IAAI,GAAU,YAAY,aAAa,WAAW,GAAG,GAAU,YAAY,IAAI,QAAQ,CAAC,CAAC,EAAE,IAAI,QAAQ,EAAE,MAAM,CAAC;AACrL,QAAI,CAAC,WAAW;AACd,YAAM,IAAI,MAAM,0BAA0B,QAAQ,EAAE;AAAA,IACtD;AACA,UAAM,CAAC,OAAO,IAAI,MAAM,GAAG,OAAO,EAAE,KAAY,KAAK,EAAE,MAAM,IAAI,GAAU,MAAM,aAAa,WAAW,GAAG,GAAU,MAAM,IAAI,UAAU,MAAM,CAAC,CAAC,EAAE,IAAI,QAAQ,EAAE,MAAM,CAAC;AACzK,QAAI,CAAC,SAAS;AACZ,YAAM,IAAI,MAAM,8BAA8B,QAAQ,EAAE;AAAA,IAC1D;AACA,UAAM,MAAM,oBAAI,KAAK;AACrB,UAAM,CAAC,WAAW,IAAI,MAAM,GAAG,OAAc,KAAK,EAAE,IAAI;AAAA,MACtD,QAAQ;AAAA,MACR,WAAW;AAAA,IACb,CAAC,EAAE,MAAM,IAAI,GAAU,MAAM,aAAa,WAAW,GAAG,GAAU,MAAM,IAAI,QAAQ,EAAE,CAAC,CAAC,EAAE,UAAU;AACpG,UAAM,GAAG,OAAc,WAAW,EAAE,IAAI;AAAA,MACtC,QAAQ;AAAA,MACR,aAAa;AAAA,MACb,WAAW;AAAA,IACb,CAAC,EAAE,MAAM,IAAI,GAAU,YAAY,aAAa,WAAW,GAAG,GAAU,YAAY,IAAI,QAAQ,CAAC,CAAC;AAClG,QAAI,CAAC,aAAa;AAChB,YAAM,IAAI,MAAM,gCAAgC;AAAA,IAClD;AACA,WAAO,QAAQ,WAAW;AAAA,EAC5B,CAAC,CAAC;AACJ;AAEA,eAAsB,qBAAqB,IAAc,aAAqB,UAAkB,QAA+B;AAC7H,QAAM,MAAM,oBAAI,KAAK;AACrB,QAAM,iBAAiB,IAAI,aAAa,OAAO,aAAa,MAAM,SAAS,YAAY,OAAO,OAAO;AACnG,UAAM,GAAG,OAAc,WAAW,EAAE,IAAI,EAAE,QAAQ,UAAU,WAAW,IAAI,CAAC,EAAE,MAAM,IAAI,GAAU,YAAY,aAAa,WAAW,GAAG,GAAU,YAAY,IAAI,QAAQ,CAAC,CAAC;AAC7K,UAAM,GAAG,OAAc,KAAK,EAAE,IAAI,EAAE,QAAQ,UAAU,WAAW,IAAI,CAAC,EAAE,MAAM,IAAI,GAAU,MAAM,aAAa,WAAW,GAAG,GAAU,MAAM,IAAI,MAAM,CAAC,CAAC;AAAA,EAC3J,CAAC,CAAC;AACJ;AAEA,eAAsB,uBAAuB,IAAc,OAA+D;AACxH,SAAO,MAAM,eAAe,IAAI,EAAE,WAAW,MAAM,WAAW,aAAa,MAAM,YAAY,GAAG,OAAO,aAAa;AAClH,UAAM,MAAM,oBAAI,KAAK;AACrB,UAAM,WAAW,MAAM,oBAAoB,UAAU,MAAM,aAAa,MAAM,MAAM;AACpF,QAAI,UAAU;AACZ,YAAM,CAACC,IAAG,IAAI,MAAM,SAAS,OAAc,iBAAiB,EAAE,IAAI;AAAA,QAChE,QAAQ;AAAA,QACR,UAAU,MAAM,YAAY,SAAS;AAAA,QACrC,WAAW;AAAA,QACX,WAAW;AAAA,MACb,CAAC,EAAE,MAAM,IAAI,GAAU,kBAAkB,aAAa,MAAM,WAAW,GAAG,GAAU,kBAAkB,QAAQ,MAAM,MAAM,CAAC,CAAC,EAAE,UAAU;AACxI,UAAI,CAACA,MAAK;AACR,cAAM,IAAI,MAAM,gCAAgC,MAAM,MAAM,EAAE;AAAA,MAChE;AACA,aAAO,oBAAoBA,IAAG;AAAA,IAChC;AACA,UAAM,CAAC,GAAG,IAAI,MAAM,SAAS,OAAc,iBAAiB,EAAE,OAAO;AAAA,MACnE,WAAW,MAAM;AAAA,MACjB,aAAa,MAAM;AAAA,MACnB,QAAQ,MAAM;AAAA,MACd,QAAQ;AAAA,MACR,UAAU,MAAM,YAAY,CAAC;AAAA,IAC/B,CAAC,EAAE,UAAU;AACb,QAAI,CAAC,KAAK;AACR,YAAM,IAAI,MAAM,oCAAoC;AAAA,IACtD;AACA,WAAO,oBAAoB,GAAG;AAAA,EAChC,CAAC;AACH;AAEA,eAAsB,sBAAsB,IAAc,aAAkD;AAC1G,SAAO,MAAM,iBAAiB,IAAI,aAAa,OAAO,aAAa;AACjE,UAAM,OAAO,MAAM,SAAS,OAAO,EAAE,KAAY,iBAAiB,EAC/D,MAAM,GAAU,kBAAkB,aAAa,WAAW,CAAC,EAC3D,QAAQ,KAAY,kBAAkB,SAAS,CAAC;AACnD,WAAO,KAAK,IAAI,mBAAmB;AAAA,EACrC,CAAC;AACH;AAEA,eAAsB,oBAAoB,IAAc,aAAqB,QAAkD;AAC7H,SAAO,MAAM,iBAAiB,IAAI,aAAa,OAAO,aAAa;AACjE,UAAM,CAAC,GAAG,IAAI,MAAM,SAAS,OAAO,EAAE,KAAY,iBAAiB,EAChE,MAAM,IAAI,GAAU,kBAAkB,aAAa,WAAW,GAAG,GAAU,kBAAkB,QAAQ,MAAM,CAAC,CAAC,EAC7G,MAAM,CAAC;AACV,WAAO,MAAM,oBAAoB,GAAG,IAAI;AAAA,EAC1C,CAAC;AACH;AAEA,eAAsB,6BAA6B,IAAc,aAAqB,QAAgB,QAA2D;AAC/J,SAAO,MAAM,iBAAiB,IAAI,aAAa,OAAO,aAAa;AACjE,UAAM,CAAC,GAAG,IAAI,MAAM,SAAS,OAAc,iBAAiB,EAAE,IAAI;AAAA,MAChE;AAAA,MACA,WAAW,oBAAI,KAAK;AAAA,IACtB,CAAC,EAAE,MAAM,IAAI,GAAU,kBAAkB,aAAa,WAAW,GAAG,GAAU,kBAAkB,QAAQ,MAAM,CAAC,CAAC,EAAE,UAAU;AAC5H,QAAI,CAAC,KAAK;AACR,YAAM,IAAI,MAAM,gCAAgC,MAAM,EAAE;AAAA,IAC1D;AACA,WAAO,oBAAoB,GAAG;AAAA,EAChC,CAAC;AACH;AAEA,eAAsB,sBAAsB,IAAc,OAAiG;AACzJ,SAAO,MAAM,eAAe,IAAI,EAAE,WAAW,MAAM,WAAW,aAAa,MAAM,YAAY,GAAG,OAAO,aAAa;AAClH,UAAM,MAAM,oBAAI,KAAK;AACrB,UAAM,CAAC,GAAG,IAAI,MAAM,SAAS,OAAc,cAAc,EAAE,OAAO;AAAA,MAChE,WAAW,MAAM;AAAA,MACjB,aAAa,MAAM;AAAA,MACnB,QAAQ,MAAM,KAAK;AAAA,MACnB,UAAU,MAAM;AAAA,IAClB,CAAC,EACE,mBAAmB;AAAA,MAClB,QAAQ,CAAQ,eAAe,aAAoB,eAAe,MAAM;AAAA,MACxE,KAAK;AAAA,QACH,UAAU,MAAM;AAAA,QAChB,WAAW;AAAA,MACb;AAAA,IACF,CAAC,EACA,UAAU;AACb,QAAI,CAAC,KAAK;AACR,YAAM,IAAI,MAAM,mCAAmC;AAAA,IACrD;AACA,WAAO,EAAE,MAAM,iBAAiB,GAAG,GAAG,SAAS,IAAI,UAAU,QAAQ,MAAM,IAAI,UAAU,QAAQ,EAAE;AAAA,EACrG,CAAC;AACH;AAEA,eAAsB,mBAAmB,IAAc,aAAyD;AAC9G,SAAO,MAAM,iBAAiB,IAAI,aAAa,OAAO,aAAa;AACjE,UAAM,OAAO,MAAM,SAAS,OAAO,EAAE,KAAY,cAAc,EAC5D,MAAM,GAAU,eAAe,aAAa,WAAW,CAAC,EACxD,QAAQ,IAAW,eAAe,MAAM,CAAC;AAC5C,WAAO,KAAK,IAAI,gBAAgB;AAAA,EAClC,CAAC;AACH;AAEA,eAAsB,iBAAiB,IAAc,aAAqB,QAAyD;AACjI,SAAO,MAAM,iBAAiB,IAAI,aAAa,OAAO,aAAa;AACjE,UAAM,CAAC,GAAG,IAAI,MAAM,SAAS,OAAO,EAAE,KAAY,cAAc,EAC7D,MAAM,IAAI,GAAU,eAAe,aAAa,WAAW,GAAG,GAAU,eAAe,QAAQ,MAAM,CAAC,CAAC,EACvG,MAAM,CAAC;AACV,WAAO,MAAM,iBAAiB,GAAG,IAAI;AAAA,EACvC,CAAC;AACH;AAEA,eAAsB,oBAAoB,IAAc,aAAqB,QAAkC;AAC7G,SAAO,MAAM,iBAAiB,IAAI,aAAa,OAAO,aAAa;AACjE,UAAM,OAAO,MAAM,SAAS,OAAc,cAAc,EACrD,MAAM,IAAI,GAAU,eAAe,aAAa,WAAW,GAAG,GAAU,eAAe,QAAQ,MAAM,CAAC,CAAC,EACvG,UAAU,EAAE,IAAW,eAAe,GAAG,CAAC;AAC7C,WAAO,KAAK,SAAS;AAAA,EACvB,CAAC;AACH;AAEA,eAAsB,4BAA4B,IAAc,OAAyE;AACvI,SAAO,MAAM,eAAe,IAAI,EAAE,WAAW,MAAM,WAAW,aAAa,MAAM,YAAY,GAAG,OAAO,aAAa;AAClH,UAAM,MAAM,oBAAI,KAAK;AACrB,UAAM,SAAS;AAAA,MACb,IAAI,MAAM;AAAA,MACV,WAAW,MAAM;AAAA,MACjB,aAAa,MAAM;AAAA,MACnB,MAAM,MAAM;AAAA,MACZ,QAAQ,MAAM;AAAA,MACd,MAAM,MAAM;AAAA,MACZ,aAAa,MAAM,eAAe;AAAA,MAClC,UAAU,MAAM,YAAY;AAAA,MAC5B,MAAM,MAAM,QAAQ,CAAC;AAAA,MACrB,aAAa,MAAM,eAAe;AAAA,MAClC,aAAa,MAAM,eAAe;AAAA,MAClC,YAAY,MAAM,cAAc;AAAA,MAChC,WAAW,MAAM,aAAa;AAAA,MAC9B,UAAU,MAAM,YAAY,CAAC;AAAA,MAC7B,WAAW;AAAA,IACb;AACA,UAAM,eAAe;AAAA,MACnB,MAAM,OAAO;AAAA,MACb,QAAQ,OAAO;AAAA,MACf,MAAM,OAAO;AAAA,MACb,aAAa,OAAO;AAAA,MACpB,UAAU,OAAO;AAAA,MACjB,MAAM,OAAO;AAAA,MACb,aAAa,OAAO;AAAA,MACpB,aAAa,OAAO;AAAA,MACpB,YAAY,OAAO;AAAA,MACnB,WAAW,OAAO;AAAA,MAClB,UAAU,OAAO;AAAA,MACjB,WAAW,OAAO;AAAA,IACpB;AACA,UAAM,CAAC,GAAG,IAAI,MAAM,SAAS,OAAc,sBAAsB,EAAE,OAAO,MAAM,EAC7E,mBAAmB;AAAA,MAClB,QAAQ,CAAQ,uBAAuB,aAAoB,uBAAuB,EAAE;AAAA,MACpF,KAAK;AAAA,IACP,CAAC,EACA,UAAU;AACb,QAAI,CAAC,KAAK;AACR,YAAM,IAAI,MAAM,0CAA0C;AAAA,IAC5D;AACA,WAAO,yBAAyB,GAAG;AAAA,EACrC,CAAC;AACH;AAEA,eAAsB,2BAA2B,IAAc,aAAuD;AACpH,SAAO,MAAM,iBAAiB,IAAI,aAAa,OAAO,aAAa;AACjE,UAAM,OAAO,MAAM,SAAS,OAAO,EAAE,KAAY,sBAAsB,EACpE,MAAM,GAAU,uBAAuB,aAAa,WAAW,CAAC,EAChE,QAAQ,IAAW,uBAAuB,IAAI,GAAG,IAAW,uBAAuB,IAAI,CAAC;AAC3F,WAAO,KAAK,IAAI,wBAAwB;AAAA,EAC1C,CAAC;AACH;AAEA,eAAsB,yBAAyB,IAAc,aAAqB,cAA6D;AAC7I,SAAO,MAAM,iBAAiB,IAAI,aAAa,OAAO,aAAa;AACjE,UAAM,CAAC,GAAG,IAAI,MAAM,SAAS,OAAO,EAAE,KAAY,sBAAsB,EACrE,MAAM,IAAI,GAAU,uBAAuB,aAAa,WAAW,GAAG,GAAU,uBAAuB,IAAI,YAAY,CAAC,CAAC,EACzH,MAAM,CAAC;AACV,WAAO,MAAM,yBAAyB,GAAG,IAAI;AAAA,EAC/C,CAAC;AACH;AAEA,eAAsB,6BAA6B,IAAc,OAA2E;AAC1I,SAAO,MAAM,eAAe,IAAI,EAAE,WAAW,MAAM,WAAW,aAAa,MAAM,YAAY,GAAG,OAAO,aAAa;AAClH,UAAM,MAAM,oBAAI,KAAK;AAGrB,UAAM,CAAC,QAAQ,IAAI,MAAM,SAAS,OAAO,EAAE,KAAY,uBAAuB,EAC3E,MAAM,IAAI,GAAU,wBAAwB,aAAa,MAAM,WAAW,GAAG,GAAU,wBAAwB,cAAc,MAAM,YAAY,CAAC,CAAC,EACjJ,MAAM,CAAC;AACV,QAAI,UAAU;AACZ,YAAM,CAACA,IAAG,IAAI,MAAM,SAAS,OAAc,uBAAuB,EAAE,IAAI;AAAA,QACtE,MAAM,MAAM;AAAA,QACZ,QAAQ;AAAA,QACR,QAAQ,MAAM,UAAU,SAAS;AAAA,QACjC,UAAU,MAAM,YAAY,SAAS;AAAA,QACrC,WAAW;AAAA,QACX,WAAW;AAAA,MACb,CAAC,EAAE,MAAM,IAAI,GAAU,wBAAwB,aAAa,MAAM,WAAW,GAAG,GAAU,wBAAwB,cAAc,MAAM,YAAY,CAAC,CAAC,EAAE,UAAU;AAChK,UAAI,CAACA,MAAK;AACR,cAAM,IAAI,MAAM,sCAAsC,MAAM,YAAY,EAAE;AAAA,MAC5E;AACA,aAAO,0BAA0BA,IAAG;AAAA,IACtC;AACA,UAAM,CAAC,GAAG,IAAI,MAAM,SAAS,OAAc,uBAAuB,EAAE,OAAO;AAAA,MACzE,WAAW,MAAM;AAAA,MACjB,aAAa,MAAM;AAAA,MACnB,cAAc,MAAM;AAAA,MACpB,MAAM,MAAM;AAAA,MACZ,QAAQ;AAAA,MACR,QAAQ,MAAM,UAAU,CAAC;AAAA,MACzB,UAAU,MAAM,YAAY,CAAC;AAAA,IAC/B,CAAC,EAAE,UAAU;AACb,QAAI,CAAC,KAAK;AACR,YAAM,IAAI,MAAM,0CAA0C;AAAA,IAC5D;AACA,WAAO,0BAA0B,GAAG;AAAA,EACtC,CAAC;AACH;AAEA,eAAsB,8BAA8B,IAAc,aAAqB,cAAuD;AAC5I,SAAO,MAAM,iBAAiB,IAAI,aAAa,OAAO,aAAa;AACjE,UAAM,CAAC,GAAG,IAAI,MAAM,SAAS,OAAc,uBAAuB,EAAE,IAAI;AAAA,MACtE,QAAQ;AAAA,MACR,WAAW,oBAAI,KAAK;AAAA,IACtB,CAAC,EAAE,MAAM,IAAI,GAAU,wBAAwB,aAAa,WAAW,GAAG,GAAU,wBAAwB,cAAc,YAAY,CAAC,CAAC,EAAE,UAAU;AACpJ,QAAI,CAAC,KAAK;AACR,YAAM,IAAI,MAAM,sCAAsC,YAAY,EAAE;AAAA,IACtE;AACA,WAAO,0BAA0B,GAAG;AAAA,EACtC,CAAC;AACH;AAEA,eAAsB,4BAA4B,IAAc,aAAwD;AACtH,SAAO,MAAM,iBAAiB,IAAI,aAAa,OAAO,aAAa;AACjE,UAAM,OAAO,MAAM,SAAS,OAAO,EAAE,KAAY,uBAAuB,EACrE,MAAM,GAAU,wBAAwB,aAAa,WAAW,CAAC,EACjE,QAAQ,KAAY,wBAAwB,SAAS,CAAC;AACzD,WAAO,KAAK,IAAI,yBAAyB;AAAA,EAC3C,CAAC;AACH;AAEA,eAAsB,0BAA0B,IAAc,aAAqB,cAA8D;AAC/I,SAAO,MAAM,iBAAiB,IAAI,aAAa,OAAO,aAAa;AACjE,UAAM,CAAC,GAAG,IAAI,MAAM,SAAS,OAAO,EAAE,KAAY,uBAAuB,EACtE,MAAM,IAAI,GAAU,wBAAwB,aAAa,WAAW,GAAG,GAAU,wBAAwB,cAAc,YAAY,CAAC,CAAC,EACrI,MAAM,CAAC;AACV,WAAO,MAAM,0BAA0B,GAAG,IAAI;AAAA,EAChD,CAAC;AACH;AAEA,eAAsB,gCAAgC,IAAc,aAA4D;AAC9H,QAAM,OAAO,MAAM,iBAAiB,IAAI,aAAa,OAAO,aAAa,MAAM,SAAS,OAAO;AAAA,IAC7F,MAAa;AAAA,IACb,cAAqB;AAAA,EACvB,CAAC,EAAE,KAAY,uBAAuB,EACnC,UAAiB,wBAAwB;AAAA,IACxC,GAAU,wBAAwB,aAAoB,uBAAuB,WAAW;AAAA,IACxF,GAAU,wBAAwB,cAAqB,uBAAuB,EAAE;AAAA,EAClF,CAAC,EACA,MAAM;AAAA,IACL,GAAU,wBAAwB,aAAa,WAAW;AAAA,IAC1D,GAAU,wBAAwB,MAAM,KAAK;AAAA,IAC7C,GAAU,wBAAwB,QAAQ,QAAQ;AAAA,EACpD,CAAC,EACA,QAAQ,IAAW,uBAAuB,IAAI,CAAC,CAAC;AAEnD,SAAO,KAAK,QAAQ,CAAC,EAAE,MAAM,aAAa,MAAM;AAC9C,QAAI,CAAC,KAAK,eAAe,CAAC,kBAAkB,aAAa,QAAQ,GAAG;AAClE,aAAO,CAAC;AAAA,IACV;AACA,UAAM,mBAAmB,uBAAuB,aAAa,OAAO,gBAAgB;AACpF,QAAI,KAAK,aAAa,CAAC,kBAAkB;AAGvC,aAAO,CAAC;AAAA,IACV;AACA,UAAM,WAAW,KAAK;AACtB,UAAM,SAAS,aAAa;AAC5B,UAAM,eAAe,kBAAkB,OAAO,gBAAgB,SAAS,YAAY;AACnF,UAAM,YAAY,sBAAsB,OAAO,aAAa,SAAS,SAAS;AAC9E,UAAM,iBAAiB,cAAc,OAAO,kBAAkB,SAAS,cAAc;AACrF,WAAO,CAAC;AAAA,MACN,cAAc,KAAK;AAAA,MACnB,IAAI,yBAAyB,KAAK,IAAI,QAAQ;AAAA,MAC9C,MAAM,KAAK;AAAA,MACX,KAAK,KAAK;AAAA,MACV,GAAI,eAAe,EAAE,aAAa,IAAI,CAAC;AAAA,MACvC,GAAI,YAAY,EAAE,UAAU,IAAI,CAAC;AAAA,MACjC,GAAI,mBAAmB,SAAY,EAAE,eAAe,IAAI,CAAC;AAAA,MACzD,GAAI,mBAAmB,EAAE,iBAAiB,IAAI,CAAC;AAAA,IACjD,CAAC;AAAA,EACH,CAAC;AACH;AAQO,SAAS,2BACd,QACA,eAC+C;AAC/C,MAAI,CAAC,OAAO,oBAAoB,OAAO,KAAK,OAAO,gBAAgB,EAAE,WAAW,GAAG;AACjF,WAAO;AAAA,EACT;AACA,MAAI,CAAC,eAAe;AAClB,WAAO;AAAA,EACT;AACA,MAAI;AACF,WAAO,OAAO,YAAY,OAAO,QAAQ,OAAO,gBAAgB,EAAE,IAAI,CAAC,CAAC,MAAM,KAAK,MAAM,CAAC,MAAM,wBAAwB,eAAe,KAAK,CAAC,CAAC,CAAC;AAAA,EACjJ,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAQA,eAAsB,oCAAoC,IAAc,aAAqB,cAA8D;AACzJ,SAAO,MAAM,iBAAiB,IAAI,aAAa,OAAO,aAAa;AACjE,UAAM,CAAC,GAAG,IAAI,MAAM,SAAS,OAAO,EAAE,QAAe,wBAAwB,OAAO,CAAC,EAAE,KAAY,uBAAuB,EACvH,MAAM,IAAI,GAAU,wBAAwB,aAAa,WAAW,GAAG,GAAU,wBAAwB,cAAc,YAAY,CAAC,CAAC,EACrI,MAAM,CAAC;AACV,WAAO,MAAM,uBAAuB,IAAI,OAAO,gBAAgB,KAAK,OAAO;AAAA,EAC7E,CAAC;AACH;AAEO,SAAS,yBAAyB,cAAsB,WAAoC,CAAC,GAAW;AAC7G,QAAM,WAAW,OAAO,SAAS,gBAAgB,WAAW,SAAS,YAAY,KAAK,IAAI;AAC1F,MAAI,mBAAmB,KAAK,QAAQ,GAAG;AACrC,WAAO;AAAA,EACT;AACA,QAAM,OAAO,aACV,QAAQ,WAAW,EAAE,EACrB,YAAY,EACZ,QAAQ,iBAAiB,GAAG,EAC5B,QAAQ,YAAY,EAAE,EACtB,MAAM,GAAG,EAAE,KAAK;AACnB,SAAO,OAAO,IAAI,IAAI,UAAU,YAAY,CAAC;AAC/C;AAEA,eAAsB,uBAAuB,IAAc,OAA+D;AACxH,SAAO,MAAM,eAAe,IAAI,EAAE,WAAW,MAAM,WAAW,aAAa,MAAM,YAAY,GAAG,OAAO,aAAa;AAClH,UAAM,CAAC,GAAG,IAAI,MAAM,SAAS,OAAc,iBAAiB,EAAE,OAAO;AAAA,MACnE,WAAW,MAAM;AAAA,MACjB,aAAa,MAAM;AAAA,MACnB,UAAU,MAAM;AAAA,MAChB,eAAe,MAAM;AAAA,MACrB,aAAa,MAAM,eAAe;AAAA,MAClC,mBAAmB,MAAM,qBAAqB;AAAA,MAC9C,QAAQ,MAAM;AAAA,MACd,QAAQ,MAAM,UAAU,CAAC;AAAA,MACzB,eAAe,MAAM,iBAAiB;AAAA,MACtC,eAAe,MAAM,iBAAiB,CAAC;AAAA,MACvC,UAAU,MAAM,YAAY,CAAC;AAAA,IAC/B,CAAC,EAAE,UAAU;AACb,QAAI,CAAC,KAAK;AACR,YAAM,IAAI,MAAM,oCAAoC;AAAA,IACtD;AACA,WAAO,oBAAoB,GAAG;AAAA,EAChC,CAAC;AACH;AAEA,eAAsB,sBAAsB,IAAc,aAAqB,QAAQ,KAAkC;AACvH,SAAO,MAAM,iBAAiB,IAAI,aAAa,OAAO,aAAa;AACjE,UAAM,OAAO,MAAM,SAAS,OAAO,EAAE,KAAY,iBAAiB,EAC/D,MAAM,GAAU,kBAAkB,aAAa,WAAW,CAAC,EAC3D,QAAQ,KAAY,kBAAkB,SAAS,CAAC,EAChD,MAAM,KAAK;AACd,WAAO,KAAK,IAAI,mBAAmB;AAAA,EACrC,CAAC;AACH;AAEA,eAAsB,oBAAoB,IAAc,aAAqB,cAAwD;AACnI,SAAO,MAAM,iBAAiB,IAAI,aAAa,OAAO,aAAa;AACjE,UAAM,CAAC,GAAG,IAAI,MAAM,SAAS,OAAO,EAAE,KAAY,iBAAiB,EAChE,MAAM,IAAI,GAAU,kBAAkB,aAAa,WAAW,GAAG,GAAU,kBAAkB,IAAI,YAAY,CAAC,CAAC,EAC/G,MAAM,CAAC;AACV,WAAO,MAAM,oBAAoB,GAAG,IAAI;AAAA,EAC1C,CAAC;AACH;AAEA,eAAsB,wBAAwB,IAAc,aAAqB,cAAiD;AAChI,QAAM,aAAa,MAAM,oBAAoB,IAAI,aAAa,YAAY;AAC1E,MAAI,CAAC,YAAY;AACf,UAAM,IAAI,MAAM,gCAAgC,YAAY,EAAE;AAAA,EAChE;AACA,SAAO;AACT;AAEA,eAAsB,iBAAiB,IAAc,OAAmD;AACtG,SAAO,MAAM,eAAe,IAAI,EAAE,WAAW,MAAM,WAAW,aAAa,MAAM,YAAY,GAAG,OAAO,aAAa;AAClH,UAAM,aAAa,MAAM,wBAAwB,UAAU,MAAM,aAAa,MAAM,YAAY;AAChG,UAAM,CAAC,GAAG,IAAI,MAAM,SAAS,OAAc,WAAW,EAAE,OAAO;AAAA,MAC7D,WAAW,MAAM;AAAA,MACjB,aAAa,MAAM;AAAA,MACnB,cAAc,MAAM;AAAA,MACpB,UAAU,WAAW;AAAA,MACrB,gBAAgB,MAAM,kBAAkB;AAAA,MACxC,KAAK,MAAM,OAAO;AAAA,MAClB,cAAc,MAAM,gBAAgB,WAAW;AAAA,MAC/C,MAAM,MAAM;AAAA,MACZ,aAAa,MAAM;AAAA,MACnB,SAAS,MAAM,WAAW,CAAC;AAAA,MAC3B,KAAK,MAAM,OAAO,CAAC;AAAA,IACrB,CAAC,EAAE,UAAU;AACb,QAAI,CAAC,KAAK;AACR,YAAM,IAAI,MAAM,8BAA8B;AAAA,IAChD;AACA,WAAO,cAAc,GAAG;AAAA,EAC1B,CAAC;AACH;AAEA,eAAsB,gBAAgB,IAAc,SAK1B;AACxB,QAAM,aAAoB,CAAC,GAAU,YAAY,aAAa,QAAQ,WAAW,CAAC;AAClF,MAAI,QAAQ,eAAe,QAAQ;AACjC,eAAW,KAAK,QAAe,YAAY,cAAc,QAAQ,aAAa,CAAC;AAAA,EACjF;AACA,MAAI,QAAQ,OAAO;AACjB,eAAW,KAAK,IAAW,YAAY,aAAa,QAAQ,KAAK,CAAC;AAAA,EACpE;AACA,QAAM,QAAQ,QAAQ,SAAS;AAC/B,SAAO,MAAM,iBAAiB,IAAI,QAAQ,aAAa,OAAO,aAAa;AACzE,UAAM,OAAO,MAAM,SAAS,OAAO,EAAE,KAAY,WAAW,EACzD,MAAM,IAAI,GAAG,UAAU,CAAC,EACxB,QAAQ,KAAY,YAAY,WAAW,CAAC,EAC5C,MAAM,KAAK;AACd,WAAO,KAAK,IAAI,aAAa;AAAA,EAC/B,CAAC;AACH;AAEA,eAAsB,oBAAoB,IAAc,OAAyD;AAC/G,SAAO,MAAM,eAAe,IAAI,EAAE,WAAW,MAAM,WAAW,aAAa,MAAM,YAAY,GAAG,OAAO,aAAa;AAClH,UAAM,CAAC,GAAG,IAAI,MAAM,SAAS,OAAc,cAAc,EAAE,OAAO,KAAK,EAAE,UAAU;AACnF,QAAI,CAAC,KAAK;AACR,YAAM,IAAI,MAAM,iCAAiC;AAAA,IACnD;AACA,WAAO,iBAAiB,GAAG;AAAA,EAC7B,CAAC;AACH;AAEA,eAAsB,oBAAoB,IAAc,aAAqB,QAAgB,OAAyD;AACpJ,SAAO,MAAM,iBAAiB,IAAI,aAAa,OAAO,aAAa;AACjE,UAAM,CAAC,GAAG,IAAI,MAAM,SAAS,OAAc,cAAc,EAAE,IAAI;AAAA,MAC7D,GAAI,MAAM,SAAS,SAAY,EAAE,MAAM,MAAM,KAAK,IAAI,CAAC;AAAA,MACvD,GAAI,MAAM,WAAW,SAAY,EAAE,QAAQ,MAAM,OAAO,IAAI,CAAC;AAAA,MAC7D,GAAI,MAAM,aAAa,SAAY,EAAE,UAAU,MAAM,SAAS,IAAI,CAAC;AAAA,MACnE,GAAI,MAAM,YAAY,SAAY,EAAE,SAAS,MAAM,QAAQ,IAAI,CAAC;AAAA,MAChE,GAAI,MAAM,kBAAkB,SAAY,EAAE,eAAe,MAAM,cAAc,IAAI,CAAC;AAAA,MAClF,GAAI,MAAM,gBAAgB,SAAY,EAAE,aAAa,MAAM,YAAY,IAAI,CAAC;AAAA,MAC5E,GAAI,MAAM,sBAAsB,SAAY,EAAE,mBAAmB,MAAM,kBAAkB,IAAI,CAAC;AAAA,MAC9F,GAAI,MAAM,kBAAkB,SAAY,EAAE,eAAe,MAAM,cAAc,IAAI,CAAC;AAAA,MAClF,GAAI,MAAM,aAAa,SAAY,EAAE,UAAU,MAAM,SAAS,IAAI,CAAC;AAAA,MACnE,WAAW,oBAAI,KAAK;AAAA,IACtB,CAAC,EAAE,MAAM,IAAI,GAAU,eAAe,aAAa,WAAW,GAAG,GAAU,eAAe,IAAI,MAAM,CAAC,CAAC,EAAE,UAAU;AAClH,QAAI,CAAC,KAAK;AACR,YAAM,IAAI,MAAM,6BAA6B,MAAM,EAAE;AAAA,IACvD;AACA,WAAO,iBAAiB,GAAG;AAAA,EAC7B,CAAC;AACH;AAEA,eAAsB,iBAAiB,IAAc,aAAqB,QAA+C;AACvH,SAAO,MAAM,iBAAiB,IAAI,aAAa,OAAO,aAAa;AACjE,UAAM,CAAC,GAAG,IAAI,MAAM,SAAS,OAAO,EAAE,KAAY,cAAc,EAAE,MAAM,IAAI,GAAU,eAAe,aAAa,WAAW,GAAG,GAAU,eAAe,IAAI,MAAM,CAAC,CAAC,EAAE,MAAM,CAAC;AAC9K,WAAO,MAAM,iBAAiB,GAAG,IAAI;AAAA,EACvC,CAAC;AACH;AAEA,eAAsB,qBAAqB,IAAc,aAAqB,QAAwC;AACpH,QAAM,OAAO,MAAM,iBAAiB,IAAI,aAAa,MAAM;AAC3D,MAAI,CAAC,MAAM;AACT,UAAM,IAAI,MAAM,6BAA6B,MAAM,EAAE;AAAA,EACvD;AACA,SAAO;AACT;AAEA,eAAsB,mBAAmB,IAAc,aAAqB,QAAQ,KAA+B;AACjH,SAAO,MAAM,iBAAiB,IAAI,aAAa,OAAO,aAAa;AACjE,UAAM,OAAO,MAAM,SAAS,OAAO,EAAE,KAAY,cAAc,EAC5D,MAAM,GAAU,eAAe,aAAa,WAAW,CAAC,EACxD,QAAQ,KAAY,eAAe,SAAS,CAAC,EAC7C,MAAM,KAAK;AACd,WAAO,KAAK,IAAI,gBAAgB;AAAA,EAClC,CAAC;AACH;AAEA,eAAsB,oBAAoB,IAAc,aAAqB,QAA+B;AAC1G,QAAM,iBAAiB,IAAI,aAAa,OAAO,aAAa;AAC1D,UAAM,SAAS,OAAc,cAAc,EAAE,MAAM,IAAI,GAAU,eAAe,aAAa,WAAW,GAAG,GAAU,eAAe,IAAI,MAAM,CAAC,CAAC;AAAA,EAClJ,CAAC;AACH;AAEA,eAAsB,uBAAuB,IAAc,OAM7B;AAC5B,SAAO,MAAM,iBAAiB,IAAI,MAAM,aAAa,OAAO,aAAa;AACvE,UAAM,CAAC,OAAO,IAAI,MAAM,SAAS,OAAO,EAAE,KAAY,cAAc,EACjE,MAAM,IAAI,GAAU,eAAe,aAAa,MAAM,WAAW,GAAG,GAAU,eAAe,IAAI,MAAM,MAAM,CAAC,CAAC,EAC/G,MAAM,CAAC;AACV,QAAI,CAAC,SAAS;AACZ,YAAM,IAAI,MAAM,6BAA6B,MAAM,MAAM,EAAE;AAAA,IAC7D;AACA,UAAM,CAAC,GAAG,IAAI,MAAM,SAAS,OAAc,iBAAiB,EAAE,OAAO;AAAA,MACnE,WAAW,QAAQ;AAAA,MACnB,aAAa,QAAQ;AAAA,MACrB,QAAQ,MAAM;AAAA,MACd,aAAa,MAAM;AAAA,MACnB,aAAa,MAAM,eAAe;AAAA,MAClC,SAAS,MAAM,WAAW,oBAAI,KAAK;AAAA,MACnC,QAAQ;AAAA,IACV,CAAC,EAAE,UAAU;AACb,QAAI,CAAC,KAAK;AACR,YAAM,IAAI,MAAM,qCAAqC;AAAA,IACvD;AACA,WAAO,oBAAoB,GAAG;AAAA,EAChC,CAAC;AACH;AAEA,eAAsB,uBAAuB,IAAc,aAAqB,OAAe,OAKhE;AAC7B,SAAO,MAAM,iBAAiB,IAAI,aAAa,OAAO,aAAa;AACjE,UAAM,CAAC,GAAG,IAAI,MAAM,SAAS,OAAc,iBAAiB,EAAE,IAAI;AAAA,MAChE,GAAI,MAAM,WAAW,SAAY,EAAE,QAAQ,MAAM,OAAO,IAAI,CAAC;AAAA,MAC7D,GAAI,MAAM,cAAc,SAAY,EAAE,WAAW,MAAM,UAAU,IAAI,CAAC;AAAA,MACtE,GAAI,MAAM,mBAAmB,SAAY,EAAE,gBAAgB,MAAM,eAAe,IAAI,CAAC;AAAA,MACrF,GAAI,MAAM,UAAU,SAAY,EAAE,OAAO,MAAM,MAAM,IAAI,CAAC;AAAA,MAC1D,WAAW,oBAAI,KAAK;AAAA,IACtB,CAAC,EAAE,MAAM,IAAI,GAAU,kBAAkB,aAAa,WAAW,GAAG,GAAU,kBAAkB,IAAI,KAAK,CAAC,CAAC,EAAE,UAAU;AACvH,QAAI,CAAC,KAAK;AACR,YAAM,IAAI,MAAM,iCAAiC,KAAK,EAAE;AAAA,IAC1D;AACA,WAAO,oBAAoB,GAAG;AAAA,EAChC,CAAC;AACH;AAEA,eAAsB,sBAAsB,IAAc,aAAqB,QAAgB,QAAQ,KAAkC;AACvI,SAAO,MAAM,iBAAiB,IAAI,aAAa,OAAO,aAAa;AACjE,UAAM,OAAO,MAAM,SAAS,OAAO,EAAE,KAAY,iBAAiB,EAC/D,MAAM,IAAI,GAAU,kBAAkB,aAAa,WAAW,GAAG,GAAU,kBAAkB,QAAQ,MAAM,CAAC,CAAC,EAC7G,QAAQ,KAAY,kBAAkB,SAAS,CAAC,EAChD,MAAM,KAAK;AACd,WAAO,KAAK,IAAI,mBAAmB;AAAA,EACrC,CAAC;AACH;AAEA,eAAsB,2BAA2B,IAAc,OAM7B;AAGhC,SAAO,MAAM,eAAe,IAAI,EAAE,WAAW,MAAM,WAAW,aAAa,MAAM,YAAY,GAAG,OAAO,aAAa;AAClH,UAAM,CAAC,GAAG,IAAI,MAAM,SAAS,OAAc,qBAAqB,EAAE,OAAO;AAAA,MACvE,WAAW,MAAM;AAAA,MACjB,aAAa,MAAM;AAAA,MACnB,MAAM,MAAM;AAAA,MACZ,aAAa,MAAM,eAAe;AAAA,IACpC,CAAC,EAAE,UAAU;AACb,QAAI,CAAC,KAAK;AACR,YAAM,IAAI,MAAM,wCAAwC;AAAA,IAC1D;AACA,UAAM,YAAY,MAAM,aAAa,CAAC;AACtC,QAAI,UAAU,WAAW,GAAG;AAC1B,aAAO,wBAAwB,KAAK,CAAC,CAAC;AAAA,IACxC;AACA,UAAM,WAAW,MAAM,SAAS,OAAc,6BAA6B,EAAE,OAAO,UAAU,IAAI,CAAC,cAAc;AAAA,MAC/G,WAAW,MAAM;AAAA,MACjB,aAAa,MAAM;AAAA,MACnB,eAAe,IAAI;AAAA,MACnB,MAAM,SAAS;AAAA,MACf,gBAAgB,SAAS;AAAA,IAC3B,EAAE,CAAC,EAAE,UAAU;AAAA,MACb,MAAa,8BAA8B;AAAA,MAC3C,SAAgB,8BAA8B;AAAA,MAC9C,WAAkB,8BAA8B;AAAA,MAChD,WAAkB,8BAA8B;AAAA,IAClD,CAAC;AACD,WAAO,wBAAwB,KAAK,SACjC,IAAI,uCAAuC,EAC3C,KAAK,CAAC,GAAG,MAAM,EAAE,KAAK,cAAc,EAAE,IAAI,CAAC,CAAC;AAAA,EACjD,CAAC;AACH;AAEA,eAAsB,0BAA0B,IAAc,aAAsD;AAClH,SAAO,MAAM,iBAAiB,IAAI,aAAa,OAAO,aAAa;AACjE,UAAM,OAAO,MAAM,SAAS,OAAO,EAAE,KAAY,qBAAqB,EACnE,MAAM,GAAU,sBAAsB,aAAa,WAAW,CAAC,EAC/D,QAAQ,IAAW,sBAAsB,SAAS,CAAC;AACtD,UAAM,eAAe,MAAM,SAAS,OAAO;AAAA,MACzC,eAAsB,8BAA8B;AAAA,MACpD,MAAa,8BAA8B;AAAA,MAC3C,SAAgB,8BAA8B;AAAA,MAC9C,WAAkB,8BAA8B;AAAA,MAChD,WAAkB,8BAA8B;AAAA,IAClD,CAAC,EAAE,KAAY,6BAA6B,EACzC,MAAM,GAAU,8BAA8B,aAAa,WAAW,CAAC,EACvE,QAAQ,IAAW,8BAA8B,IAAI,CAAC;AACzD,UAAM,UAAU,oBAAI,IAAoD;AACxE,eAAW,YAAY,cAAc;AACnC,YAAM,OAAO,QAAQ,IAAI,SAAS,aAAa,KAAK,CAAC;AACrD,WAAK,KAAK,wCAAwC,QAAQ,CAAC;AAC3D,cAAQ,IAAI,SAAS,eAAe,IAAI;AAAA,IAC1C;AACA,WAAO,KAAK,IAAI,CAAC,QAAQ,wBAAwB,KAAK,QAAQ,IAAI,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC;AAAA,EAClF,CAAC;AACH;AAEA,eAAsB,wBAAwB,IAAc,aAAqB,eAA6D;AAC5I,SAAO,MAAM,iBAAiB,IAAI,aAAa,OAAO,aAAa;AACjE,UAAM,CAAC,GAAG,IAAI,MAAM,SAAS,OAAO,EAAE,KAAY,qBAAqB,EACpE,MAAM,IAAI,GAAU,sBAAsB,aAAa,WAAW,GAAG,GAAU,sBAAsB,IAAI,aAAa,CAAC,CAAC,EACxH,MAAM,CAAC;AACV,QAAI,CAAC,KAAK;AACR,aAAO;AAAA,IACT;AACA,WAAO,wBAAwB,KAAK,MAAM,gCAAgC,UAAU,aAAa,aAAa,CAAC;AAAA,EACjH,CAAC;AACH;AAEA,eAAsB,8BAA8B,IAAc,aAAqB,MAAoD;AACzI,SAAO,MAAM,iBAAiB,IAAI,aAAa,OAAO,aAAa;AACjE,UAAM,CAAC,GAAG,IAAI,MAAM,SAAS,OAAO,EAAE,KAAY,qBAAqB,EACpE,MAAM,IAAI,GAAU,sBAAsB,aAAa,WAAW,GAAG,GAAU,sBAAsB,MAAM,IAAI,CAAC,CAAC,EACjH,MAAM,CAAC;AACV,QAAI,CAAC,KAAK;AACR,aAAO;AAAA,IACT;AACA,WAAO,wBAAwB,KAAK,MAAM,gCAAgC,UAAU,aAAa,IAAI,EAAE,CAAC;AAAA,EAC1G,CAAC;AACH;AAEA,eAAsB,2BAA2B,IAAc,aAAqB,eAAuB,OAGzE;AAChC,SAAO,MAAM,iBAAiB,IAAI,aAAa,OAAO,aAAa;AACjE,UAAM,CAAC,GAAG,IAAI,MAAM,SAAS,OAAc,qBAAqB,EAAE,IAAI;AAAA,MACpE,GAAI,MAAM,SAAS,SAAY,EAAE,MAAM,MAAM,KAAK,IAAI,CAAC;AAAA,MACvD,GAAI,MAAM,gBAAgB,SAAY,EAAE,aAAa,MAAM,YAAY,IAAI,CAAC;AAAA,MAC5E,WAAW,oBAAI,KAAK;AAAA,IACtB,CAAC,EAAE,MAAM,IAAI,GAAU,sBAAsB,aAAa,WAAW,GAAG,GAAU,sBAAsB,IAAI,aAAa,CAAC,CAAC,EAAE,UAAU;AACvI,QAAI,CAAC,KAAK;AACR,YAAM,IAAI,MAAM,oCAAoC,aAAa,EAAE;AAAA,IACrE;AACA,WAAO,wBAAwB,KAAK,MAAM,gCAAgC,UAAU,aAAa,aAAa,CAAC;AAAA,EACjH,CAAC;AACH;AAEA,eAAsB,2BAA2B,IAAc,aAAqB,eAAyC;AAC3H,SAAO,MAAM,iBAAiB,IAAI,aAAa,OAAO,aAAa;AACjE,UAAM,OAAO,MAAM,SAAS,OAAc,qBAAqB,EAC5D,MAAM,IAAI,GAAU,sBAAsB,aAAa,WAAW,GAAG,GAAU,sBAAsB,IAAI,aAAa,CAAC,CAAC,EACxH,UAAU,EAAE,IAAW,sBAAsB,GAAG,CAAC;AACpD,WAAO,KAAK,SAAS;AAAA,EACvB,CAAC;AACH;AAEA,eAAsB,2BAA2B,IAAc,aAAsC;AACnG,SAAO,MAAM,iBAAiB,IAAI,aAAa,OAAO,aAAa;AACjE,UAAM,CAAC,EAAE,MAAM,IAAI,EAAE,OAAO,EAAE,CAAC,IAAI,MAAM,SAAS,OAAO;AAAA,MACvD,OAAO;AAAA,IACT,CAAC,EAAE,KAAY,qBAAqB,EAAE,MAAM,GAAU,sBAAsB,aAAa,WAAW,CAAC;AACrG,WAAO,OAAO,KAAK;AAAA,EACrB,CAAC;AACH;AAEA,eAAsB,oCAAoC,IAAc,aAAqB,eAAwC;AACnI,SAAO,MAAM,iBAAiB,IAAI,aAAa,OAAO,aAAa;AACjE,UAAM,CAAC,EAAE,MAAM,IAAI,EAAE,OAAO,EAAE,CAAC,IAAI,MAAM,SAAS,OAAO;AAAA,MACvD,OAAO;AAAA,IACT,CAAC,EAAE,KAAY,cAAc,EAC1B,MAAM,IAAI,GAAU,eAAe,aAAa,WAAW,GAAG,GAAU,eAAe,eAAe,aAAa,CAAC,CAAC;AACxH,WAAO,OAAO,KAAK;AAAA,EACrB,CAAC;AACH;AAEA,eAAsB,oCAAoC,IAAc,aAAqB,eAAwC;AACnI,SAAO,MAAM,iBAAiB,IAAI,aAAa,OAAO,aAAa;AACjE,UAAM,CAAC,EAAE,MAAM,IAAI,EAAE,OAAO,EAAE,CAAC,IAAI,MAAM,SAAS,OAAO;AAAA,MACvD,OAAO;AAAA,IACT,CAAC,EAAE,KAAY,QAAQ,EACpB,MAAM;AAAA,MACL,GAAU,SAAS,aAAa,WAAW;AAAA,MAC3C,GAAU,SAAS,eAAe,aAAa;AAAA,MAC/C,QAAe,SAAS,QAAQ,CAAC,UAAU,WAAW,iBAAiB,CAAC;AAAA,IAC1E,CAAC;AACH,WAAO,OAAO,KAAK;AAAA,EACrB,CAAC;AACH;AAEA,eAAsB,gCAAgC,IAAc,OAMlB;AAChD,SAAO,MAAM,eAAe,IAAI,EAAE,WAAW,MAAM,WAAW,aAAa,MAAM,YAAY,GAAG,OAAO,aAAa;AAClH,UAAM,MAAM,oBAAI,KAAK;AACrB,UAAM,CAAC,GAAG,IAAI,MAAM,SAAS,OAAc,6BAA6B,EAAE,OAAO;AAAA,MAC/E,WAAW,MAAM;AAAA,MACjB,aAAa,MAAM;AAAA,MACnB,eAAe,MAAM;AAAA,MACrB,MAAM,MAAM;AAAA,MACZ,gBAAgB,MAAM;AAAA,IACxB,CAAC,EAAE,mBAAmB;AAAA,MACpB,QAAQ;AAAA,QACC,8BAA8B;AAAA,QAC9B,8BAA8B;AAAA,QAC9B,8BAA8B;AAAA,MACvC;AAAA,MACA,KAAK;AAAA,QACH,gBAAgB,MAAM;AAAA,QACtB,SAAS,MAAa,8BAA8B,OAAO;AAAA,QAC3D,WAAW;AAAA,MACb;AAAA,IACF,CAAC,EAAE,UAAU;AAAA,MACX,MAAa,8BAA8B;AAAA,MAC3C,SAAgB,8BAA8B;AAAA,MAC9C,WAAkB,8BAA8B;AAAA,MAChD,WAAkB,8BAA8B;AAAA,IAClD,CAAC;AACD,QAAI,CAAC,KAAK;AACR,YAAM,IAAI,MAAM,8CAA8C;AAAA,IAChE;AACA,UAAM,SAAS,OAAc,qBAAqB,EAAE,IAAI,EAAE,WAAW,IAAI,CAAC,EACvE,MAAM,IAAI,GAAU,sBAAsB,aAAa,MAAM,WAAW,GAAG,GAAU,sBAAsB,IAAI,MAAM,aAAa,CAAC,CAAC;AACvI,WAAO,wCAAwC,GAAG;AAAA,EACpD,CAAC;AACH;AAEA,eAAsB,mCAAmC,IAAc,aAAqB,eAAuB,MAAgC;AACjJ,SAAO,MAAM,iBAAiB,IAAI,aAAa,OAAO,aAAa;AACjE,UAAM,OAAO,MAAM,SAAS,OAAc,6BAA6B,EACpE,MAAM;AAAA,MACL,GAAU,8BAA8B,aAAa,WAAW;AAAA,MAChE,GAAU,8BAA8B,eAAe,aAAa;AAAA,MACpE,GAAU,8BAA8B,MAAM,IAAI;AAAA,IACpD,CAAC,EACA,UAAU,EAAE,IAAW,8BAA8B,GAAG,CAAC;AAC5D,QAAI,KAAK,SAAS,GAAG;AACnB,YAAM,SAAS,OAAc,qBAAqB,EAAE,IAAI,EAAE,WAAW,oBAAI,KAAK,EAAE,CAAC,EAC9E,MAAM,IAAI,GAAU,sBAAsB,aAAa,WAAW,GAAG,GAAU,sBAAsB,IAAI,aAAa,CAAC,CAAC;AAAA,IAC7H;AACA,WAAO,KAAK,SAAS;AAAA,EACvB,CAAC;AACH;AAOA,eAAsB,oCAAoC,IAAc,aAAqB,eAGnF;AACR,SAAO,MAAM,iBAAiB,IAAI,aAAa,OAAO,aAAa;AACjE,UAAM,CAAC,WAAW,IAAI,MAAM,SAAS,OAAO;AAAA,MAC1C,IAAW,sBAAsB;AAAA,MACjC,MAAa,sBAAsB;AAAA,MACnC,aAAoB,sBAAsB;AAAA,IAC5C,CAAC,EAAE,KAAY,qBAAqB,EACjC,MAAM,IAAI,GAAU,sBAAsB,aAAa,WAAW,GAAG,GAAU,sBAAsB,IAAI,aAAa,CAAC,CAAC,EACxH,MAAM,CAAC;AACV,QAAI,CAAC,aAAa;AAChB,aAAO;AAAA,IACT;AACA,UAAM,OAAO,MAAM,SAAS,OAAO;AAAA,MACjC,MAAa,8BAA8B;AAAA,MAC3C,gBAAuB,8BAA8B;AAAA,IACvD,CAAC,EAAE,KAAY,6BAA6B,EACzC,MAAM;AAAA,MACL,GAAU,8BAA8B,aAAa,WAAW;AAAA,MAChE,GAAU,8BAA8B,eAAe,aAAa;AAAA,IACtE,CAAC;AACH,WAAO;AAAA,MACL,aAAa,EAAE,IAAI,YAAY,IAAI,MAAM,YAAY,MAAM,aAAa,YAAY,YAAY;AAAA,MAChG,QAAQ,OAAO,YAAY,KAAK,IAAI,CAAC,QAAQ,CAAC,IAAI,MAAM,IAAI,cAAc,CAAC,CAAC;AAAA,IAC9E;AAAA,EACF,CAAC;AACH;AAuBA,eAAsB,+BACpB,IACA,UACA,aACA,eAC4C;AAC5C,MAAI,CAAC,eAAe;AAClB,WAAO;AAAA,EACT;AACA,QAAM,MAAMC,gCAA+B,QAAQ;AACnD,MAAI,CAAC,KAAK;AACR,UAAM,IAAI,MAAM,2FAA2F;AAAA,EAC7G;AACA,QAAM,SAAS,MAAM,oCAAoC,IAAI,aAAa,aAAa;AACvF,MAAI,CAAC,QAAQ;AACX,UAAM,IAAI,MAAM,oCAAoC,aAAa,EAAE;AAAA,EACrE;AACA,QAAM,SAAiC,CAAC;AACxC,aAAW,CAAC,MAAM,SAAS,KAAK,OAAO,QAAQ,OAAO,MAAM,GAAG;AAC7D,QAAI;AACF,aAAO,IAAI,IAAI,wBAAwB,KAAK,SAAS;AAAA,IACvD,SAAS,OAAO;AACd,YAAM,SAAS,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AACpE,YAAM,IAAI,MAAM,oDAAoD,IAAI,KAAK,MAAM,EAAE;AAAA,IACvF;AAAA,EACF;AACA,SAAO;AAAA,IACL,IAAI,OAAO,YAAY;AAAA,IACvB,MAAM,OAAO,YAAY;AAAA,IACzB,aAAa,OAAO,YAAY;AAAA,IAChC;AAAA,EACF;AACF;AAuCA,eAAsB,kCAAkC,IAAc,OAY1B;AAC1C,SAAO,MAAM,eAAe,IAAI,EAAE,WAAW,MAAM,WAAW,aAAa,MAAM,YAAY,GAAG,OAAO,aAAa;AAClH,UAAM,MAAM,oBAAI,KAAK;AACrB,UAAM,CAAC,GAAG,IAAI,MAAM,SAAS,OAAc,4BAA4B,EAAE,OAAO;AAAA,MAC9E,WAAW,MAAM;AAAA,MACjB,aAAa,MAAM;AAAA,MACnB,qBAAqB,MAAM;AAAA,MAC3B,kBAAkB,MAAM;AAAA,MACxB,QAAQ,MAAM;AAAA,MACd,UAAU,MAAM;AAAA,MAChB,WAAW,MAAM;AAAA,MACjB,WAAW,MAAM;AAAA,MACjB,eAAe,MAAM;AAAA,MACrB,cAAc,MAAM,gBAAgB;AAAA,MACpC,OAAO,MAAM,SAAS;AAAA,MACtB,QAAQ;AAAA,MACR,WAAW;AAAA,IACb,CAAC,EAAE,mBAAmB;AAAA;AAAA;AAAA;AAAA,MAIpB,QAAQ,CAAQ,6BAA6B,aAAoB,6BAA6B,gBAAgB;AAAA,MAC9G,aAAa;AAAA,MACb,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA,QAKH,WAAW,MAAM;AAAA,QACjB,qBAAqB,MAAM;AAAA,QAC3B,QAAQ,MAAM;AAAA,QACd,UAAU,MAAM;AAAA,QAChB,WAAW,MAAM;AAAA,QACjB,WAAW,MAAM;AAAA,QACjB,eAAe,MAAM;AAAA;AAAA;AAAA,QAGrB,cAAc,MAAM,gBAAgB;AAAA,QACpC,OAAO,eAAsB,6BAA6B,KAAK,KAAK,MAAM,SAAS,IAAI;AAAA,QACvF,QAAQ;AAAA,QACR,WAAW;AAAA,QACX,SAAS,MAAa,6BAA6B,OAAO;AAAA,QAC1D,WAAW;AAAA,MACb;AAAA,IACF,CAAC,EAAE,UAAU;AAAA,MACX,IAAW,6BAA6B;AAAA,MACxC,WAAkB,6BAA6B;AAAA,MAC/C,WAAkB,6BAA6B;AAAA,IACjD,CAAC;AAED,QAAI,CAAC,KAAK;AACR,YAAM,IAAI,MAAM,mDAAmD;AAAA,IACrE;AAKA,UAAM,QAAQ,IAAI,UAAU,QAAQ,MAAM,IAAI,UAAU,QAAQ;AAChE,WAAO,EAAE,IAAI,IAAI,IAAI,MAAM;AAAA,EAC7B,CAAC;AACH;AAYA,eAAsB,0BACpB,IACA,UACA,aACA,cACuC;AACvC,QAAM,MAAMA,gCAA+B,QAAQ;AACnD,MAAI,CAAC,KAAK;AACR,UAAM,IAAI,MAAM,qFAAqF;AAAA,EACvG;AACA,SAAO,MAAM,iBAAiB,IAAI,aAAa,OAAO,aAAa;AACjE,UAAM,CAAC,GAAG,IAAI,MAAM,SAAS,OAAO,EAAE,KAAY,4BAA4B,EAC3E,MAAM;AAAA,MACL,GAAU,6BAA6B,IAAI,YAAY;AAAA,MACvD,GAAU,6BAA6B,aAAa,WAAW;AAAA,IACjE,CAAC,EAAE,MAAM,CAAC;AACZ,QAAI,CAAC,KAAK;AACR,aAAO;AAAA,IACT;AACA,QAAI;AACJ,QAAI;AAGF,YAAM,SAAS,KAAK,MAAM,wBAAwB,KAAK,IAAI,mBAAmB,CAAC;AAK/E,eAAS,EAAE,aAAa,OAAO,cAAc,cAAc,OAAO,eAAe,SAAS,OAAO,SAAS;AAAA,IAC5G,SAAS,OAAO;AACd,YAAM,SAAS,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AACpE,YAAM,IAAI,MAAM,oDAAoD,WAAW,KAAK,MAAM,EAAE;AAAA,IAC9F;AACA,WAAO;AAAA,MACL,IAAI,IAAI;AAAA,MACR,SAAS,IAAI;AAAA,MACb;AAAA,MACA;AAAA,MACA,kBAAkB,IAAI;AAAA,MACtB,QAAQ,IAAI;AAAA,MACZ,UAAU,IAAI;AAAA,MACd,WAAW,IAAI;AAAA,MACf,WAAW,IAAI;AAAA,MACf,eAAe,IAAI;AAAA,MACnB,QAAQ,IAAI;AAAA,MACZ,WAAW,IAAI;AAAA,IACjB;AAAA,EACF,CAAC;AACH;AAYA,eAAsB,wBAAwB,IAAc,OAOvC;AACnB,SAAO,MAAM,iBAAiB,IAAI,MAAM,aAAa,OAAO,aAAa;AACvE,UAAM,UAAU,MAAM,SAAS,OAAc,4BAA4B,EAAE,IAAI;AAAA,MAC7E,qBAAqB,MAAM;AAAA,MAC3B,WAAW,MAAM;AAAA,MACjB,eAAe,MAAM;AAAA,MACrB,QAAQ;AAAA,MACR,WAAW;AAAA,MACX,SAAS,MAAa,6BAA6B,OAAO;AAAA,MAC1D,WAAW,oBAAI,KAAK;AAAA,IACtB,CAAC,EAAE,MAAM;AAAA,MACP,GAAU,6BAA6B,IAAI,MAAM,EAAE;AAAA,MACnD,GAAU,6BAA6B,SAAS,MAAM,OAAO;AAAA,IAC/D,CAAC,EAAE,UAAU,EAAE,IAAW,6BAA6B,GAAG,CAAC;AAC3D,WAAO,QAAQ,SAAS;AAAA,EAC1B,CAAC;AACH;AAYA,eAAsB,yBACpB,IACA,aACA,QACA,WACA,QACkB;AAClB,SAAO,MAAM,iBAAiB,IAAI,aAAa,OAAO,aAAa;AACjE,UAAM,UAAU,MAAM,SAAS,OAAc,4BAA4B,EACtE,IAAI,EAAE,QAAQ,WAAW,WAAW,oBAAI,KAAK,EAAE,CAAC,EAChD,MAAM;AAAA,MACL,GAAU,6BAA6B,IAAI,OAAO,EAAE;AAAA,MACpD,GAAU,6BAA6B,SAAS,OAAO,OAAO;AAAA,IAChE,CAAC,EACA,UAAU,EAAE,IAAW,6BAA6B,GAAG,CAAC;AAC3D,WAAO,QAAQ,SAAS;AAAA,EAC1B,CAAC;AACH;AAYA,eAAsB,yBAAyB,IAAc,aAUnD;AACR,SAAO,MAAM,iBAAiB,IAAI,aAAa,OAAO,aAAa;AACjE,UAAM,OAAO;AAAA,MACX,IAAW,6BAA6B;AAAA,MACxC,kBAAyB,6BAA6B;AAAA,MACtD,QAAe,6BAA6B;AAAA,MAC5C,UAAiB,6BAA6B;AAAA,MAC9C,QAAe,6BAA6B;AAAA,MAC5C,WAAkB,6BAA6B;AAAA,MAC/C,eAAsB,6BAA6B;AAAA,MACnD,WAAkB,6BAA6B;AAAA,IACjD;AACA,UAAM,CAAC,WAAW,IAAI,MAAM,SAAS,OAAO,EAAE,oBAA2B,sBAAsB,mBAAmB,CAAC,EAChH,KAAY,qBAAqB,EACjC,MAAM,GAAU,sBAAsB,aAAa,WAAW,CAAC,EAAE,MAAM,CAAC;AAE3E,QAAI;AACJ,QAAI,aAAa,oBAAoB;AACnC,OAAC,GAAG,IAAI,MAAM,SAAS,OAAO,IAAI,EAAE,KAAY,4BAA4B,EACzE,MAAM;AAAA,QACL,GAAU,6BAA6B,IAAI,YAAY,kBAAkB;AAAA,QACzE,GAAU,6BAA6B,aAAa,WAAW;AAAA,MACjE,CAAC,EAAE,MAAM,CAAC;AAAA,IACd;AACA,QAAI,CAAC,KAAK;AAGR,OAAC,GAAG,IAAI,MAAM,SAAS,OAAO,IAAI,EAAE,KAAY,4BAA4B,EACzE,MAAM,GAAU,6BAA6B,aAAa,WAAW,CAAC,EACtE,QAAQ,KAAY,6BAA6B,SAAS,CAAC,EAAE,MAAM,CAAC;AACvE,UAAI,OAAO,eAAe,YAAY,uBAAuB,IAAI,IAAI;AACnE,cAAM,SAAS,OAAc,qBAAqB,EAC/C,IAAI,EAAE,oBAAoB,IAAI,IAAI,WAAW,oBAAI,KAAK,EAAE,CAAC,EACzD,MAAM,GAAU,sBAAsB,aAAa,WAAW,CAAC;AAAA,MACpE;AAAA,IACF;AACA,QAAI,CAAC,KAAK;AACR,aAAO;AAAA,IACT;AACA,UAAM,EAAE,IAAI,GAAG,KAAK,IAAI;AACxB,WAAO,EAAE,WAAW,KAAK,WAAW,UAAU,cAAc,IAAI,GAAG,KAAK;AAAA,EAC1E,CAAC;AACH;AAUA,eAAsB,iCACpB,IACA,UACA,aACkB;AAClB,MAAI,CAAC,SAAS,0BAA0B;AACtC,WAAO;AAAA,EACT;AAUA,MAAI;AACJ,WAAS,UAAU,GAAG,UAAU,4BAA4B,WAAW;AACrE,QAAI;AACF,YAAM,SAAS,MAAM,yBAAyB,IAAI,WAAW;AAC7D,aAAO,QAAQ,WAAW;AAAA,IAC5B,SAAS,OAAO;AACd,kBAAY;AACZ,UAAI,UAAU,6BAA6B,GAAG;AAC5C,cAAM,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,8BAA8B,UAAU,EAAE,CAAC;AAAA,MAChG;AAAA,IACF;AAAA,EACF;AAIA,UAAQ;AAAA,IACN,0EAA0E,WAAW,UAAU,0BAA0B;AAAA,IACzH;AAAA,EACF;AACA,QAAM,qBAAqB,QAAQ,YAAY,IAAI,MAAM,OAAO,SAAS,CAAC;AAC5E;AAKA,IAAM,6BAA6B;AACnC,IAAM,6BAA6B;AAenC,eAAsB,kBAAkB,OAanB;AACnB,MAAI,CAAC,mBAAmB,MAAM,KAAK,GAAG;AACpC,WAAO;AAAA,EACT;AACA,MAAI,MAAM,WAAW,QAAW;AAC9B,WAAO,MAAM;AAAA,EACf;AACA,SAAO,iCAAiC,MAAM,IAAI,MAAM,UAAU,MAAM,WAAW;AACrF;AAuCA,eAAsB,yBAAyB,IAAc,aAAoD;AAC/G,SAAO,MAAM,iBAAiB,IAAI,aAAa,OAAO,aAAa;AACjE,UAAM,CAAC,WAAW,IAAI,MAAM,SAAS,OAAO,EAAE,oBAA2B,sBAAsB,mBAAmB,CAAC,EAChH,KAAY,qBAAqB,EACjC,MAAM,GAAU,sBAAsB,aAAa,WAAW,CAAC,EAAE,MAAM,CAAC;AAC3E,UAAM,WAAW,aAAa,sBAAsB;AACpD,UAAM,OAAO,MAAM,SAAS,OAAO;AAAA,MACjC,IAAW,6BAA6B;AAAA,MACxC,kBAAyB,6BAA6B;AAAA,MACtD,OAAc,6BAA6B;AAAA,MAC3C,cAAqB,6BAA6B;AAAA,MAClD,UAAiB,6BAA6B;AAAA,MAC9C,QAAe,6BAA6B;AAAA,MAC5C,WAAkB,6BAA6B;AAAA,MAC/C,eAAsB,6BAA6B;AAAA,MACnD,WAAkB,6BAA6B;AAAA;AAAA,MAE/C,oBAA2B,6BAA6B;AAAA,MACxD,gBAAuB,6BAA6B;AAAA,MACpD,sBAA6B,6BAA6B;AAAA,MAC1D,kBAAyB,6BAA6B;AAAA,MACtD,gBAAuB,6BAA6B;AAAA,MACpD,gBAAuB,6BAA6B;AAAA;AAAA,MAEpD,qBAA4B,6BAA6B;AAAA,MACzD,qBAA4B,6BAA6B;AAAA,IAC3D,CAAC,EAAE,KAAY,4BAA4B,EACxC,MAAM,GAAU,6BAA6B,aAAa,WAAW,CAAC,EACtE,QAAQ,IAAW,6BAA6B,SAAS,CAAC;AAC7D,WAAO,KAAK,IAAI,CAAC,SAAS,EAAE,GAAG,KAAK,UAAU,IAAI,OAAO,SAAS,EAAE;AAAA,EACtE,CAAC;AACH;AAmBA,eAAsB,wBACpB,IACA,aACA,cACA,UACkB;AAClB,SAAO,MAAM,iBAAiB,IAAI,aAAa,OAAO,aAAa;AACjE,UAAM,UAAU,MAAM,SAAS,OAAc,4BAA4B,EACtE,IAAI;AAAA,MACH,oBAAoB,SAAS;AAAA,MAC7B,gBAAgB,SAAS;AAAA,MACzB,sBAAsB,SAAS;AAAA,MAC/B,kBAAkB,SAAS;AAAA,MAC3B,gBAAgB,SAAS;AAAA;AAAA;AAAA;AAAA,IAI3B,CAAC,EACA,MAAM;AAAA,MACL,GAAU,6BAA6B,IAAI,YAAY;AAAA,MACvD,GAAU,6BAA6B,aAAa,WAAW;AAAA,IACjE,CAAC,EACA,UAAU,EAAE,IAAW,6BAA6B,GAAG,CAAC;AAC3D,WAAO,QAAQ,SAAS;AAAA,EAC1B,CAAC;AACH;AASA,eAAsB,yBAAyB,IAAc,aAA4D;AACvH,SAAO,MAAM,iBAAiB,IAAI,aAAa,OAAO,aAAa;AACjE,UAAM,CAAC,GAAG,IAAI,MAAM,SAAS,OAAO;AAAA,MAClC,oBAA2B,sBAAsB;AAAA,MACjD,iBAAwB,sBAAsB;AAAA,MAC9C,kBAAyB,sBAAsB;AAAA,IACjD,CAAC,EAAE,KAAY,qBAAqB,EACjC,MAAM,GAAU,sBAAsB,aAAa,WAAW,CAAC,EAAE,MAAM,CAAC;AAC3E,WAAO,OAAO;AAAA,EAChB,CAAC;AACH;AAGA,eAAsB,4BAA4B,IAAc,WAAmB,aAAoC;AACrH,QAAM,eAAe,IAAI,EAAE,WAAW,YAAY,GAAG,OAAO,aAAa;AACvE,UAAM,SAAS,OAAc,qBAAqB,EAC/C,OAAO,EAAE,WAAW,YAAY,CAAC,EACjC,oBAAoB,EAAE,QAAQ,CAAQ,sBAAsB,WAAW,EAAE,CAAC;AAAA,EAC/E,CAAC;AACH;AAOA,eAAsB,yBAAyB,IAAc,aAAqB,cAAwC;AACxH,SAAO,MAAM,iBAAiB,IAAI,aAAa,OAAO,aAAa;AACjE,UAAM,CAAC,IAAI,IAAI,MAAM,SAAS,OAAO,EAAE,IAAW,6BAA6B,GAAG,CAAC,EAChF,KAAY,4BAA4B,EACxC,MAAM;AAAA,MACL,GAAU,6BAA6B,IAAI,YAAY;AAAA,MACvD,GAAU,6BAA6B,aAAa,WAAW;AAAA,IACjE,CAAC,EAAE,MAAM,CAAC;AACZ,QAAI,CAAC,MAAM;AACT,aAAO;AAAA,IACT;AACA,UAAM,UAAU,MAAM,SAAS,OAAc,qBAAqB,EAC/D,IAAI,EAAE,oBAAoB,cAAc,WAAW,oBAAI,KAAK,EAAE,CAAC,EAC/D,MAAM,GAAU,sBAAsB,aAAa,WAAW,CAAC,EAC/D,UAAU,EAAE,IAAW,sBAAsB,GAAG,CAAC;AACpD,WAAO,QAAQ,SAAS;AAAA,EAC1B,CAAC;AACH;AAUA,eAAsB,4BACpB,IACA,aACA,cACA,OACkB;AAClB,SAAO,MAAM,iBAAiB,IAAI,aAAa,OAAO,aAAa;AACjE,UAAM,UAAU,MAAM,SAAS,OAAc,4BAA4B,EACtE,IAAI,EAAE,gBAAgB,MAAM,CAAC,EAC7B,MAAM;AAAA,MACL,GAAU,6BAA6B,IAAI,YAAY;AAAA,MACvD,GAAU,6BAA6B,aAAa,WAAW;AAAA,IACjE,CAAC,EACA,UAAU,EAAE,IAAW,6BAA6B,GAAG,CAAC;AAC3D,WAAO,QAAQ,SAAS;AAAA,EAC1B,CAAC;AACH;AAeA,eAAsB,kCACpB,IACA,aACA,WACiB;AACjB,SAAO,MAAM,iBAAiB,IAAI,aAAa,OAAO,aAAa;AACjE,UAAM,CAAC,MAAM,IAAI,MAAM,SAAS,OAAO,EAAE,UAAiB,cAAc,SAAS,CAAC,EAC/E,KAAY,aAAa,EACzB,MAAM;AAAA,MACL,GAAU,cAAc,aAAa,WAAW;AAAA,MAChD,GAAU,cAAc,WAAW,SAAS;AAAA,MAC5C,GAAU,cAAc,MAAM,gBAAgB;AAAA,IAChD,CAAC,EACA,QAAQ,KAAY,cAAc,QAAQ,CAAC,EAC3C,MAAM,CAAC;AACV,UAAM,aAAa;AAAA,MACjB,GAAU,cAAc,aAAa,WAAW;AAAA,MAChD,GAAU,cAAc,WAAW,SAAS;AAAA,MAC5C,GAAU,cAAc,MAAM,aAAa;AAAA,MAC3C,MAAa,cAAc,OAAO;AAAA,IACpC;AACA,QAAI,QAAQ;AACV,iBAAW,KAAK,MAAa,cAAc,QAAQ,MAAM,OAAO,QAAQ,EAAE;AAAA,IAC5E;AACA,UAAM,CAAC,EAAE,QAAQ,IAAI,EAAE,SAAS,EAAE,CAAC,IAAI,MAAM,SAAS,OAAO;AAAA,MAC3D,SAAS;AAAA,IACX,CAAC,EAAE,KAAY,aAAa,EAAE,MAAM,IAAI,GAAG,UAAU,CAAC;AACtD,WAAO,OAAO,OAAO;AAAA,EACvB,CAAC;AACH;AAeA,eAAsB,6BACpB,IACA,aACA,cACA,YACkB;AAClB,SAAO,MAAM,iBAAiB,IAAI,aAAa,OAAO,aAAa;AACjE,UAAM,UAAU,MAAM,SAAS,OAAc,4BAA4B,EACtE,IAAI;AAAA,MACH,qBAAqB;AAAA,MACrB,qBAAqB,oBAAI,KAAK;AAAA;AAAA;AAAA;AAAA,IAIhC,CAAC,EACA,MAAM;AAAA,MACL,GAAU,6BAA6B,IAAI,YAAY;AAAA,MACvD,GAAU,6BAA6B,aAAa,WAAW;AAAA,IACjE,CAAC,EACA,UAAU,EAAE,IAAW,6BAA6B,GAAG,CAAC;AAC3D,WAAO,QAAQ,SAAS;AAAA,EAC1B,CAAC;AACH;AAGO,IAAM,4BAA4B,CAAC,kBAAkB,eAAe,iBAAiB;AAS5F,eAAsB,4BACpB,IACA,aACA,OACuC;AACvC,MAAI,MAAM,qBAAqB,UAAa,CAAC,0BAA0B,SAAS,MAAM,gBAAgB,GAAG;AACvG,UAAM,IAAI,MAAM,oCAAoC,MAAM,gBAAgB,EAAE;AAAA,EAC9E;AACA,SAAO,MAAM,iBAAiB,IAAI,aAAa,OAAO,aAAa;AACjE,UAAM,MAA+B,EAAE,WAAW,oBAAI,KAAK,EAAE;AAC7D,QAAI,MAAM,oBAAoB,QAAW;AACvC,UAAI,kBAAkB,MAAM;AAAA,IAC9B;AACA,QAAI,MAAM,qBAAqB,QAAW;AACxC,UAAI,mBAAmB,MAAM;AAAA,IAC/B;AACA,UAAM,CAAC,GAAG,IAAI,MAAM,SAAS,OAAc,qBAAqB,EAC7D,IAAI,GAAG,EACP,MAAM,GAAU,sBAAsB,aAAa,WAAW,CAAC,EAC/D,UAAU;AAAA,MACT,oBAA2B,sBAAsB;AAAA,MACjD,iBAAwB,sBAAsB;AAAA,MAC9C,kBAAyB,sBAAsB;AAAA,IACjD,CAAC;AACH,WAAO,OAAO;AAAA,EAChB,CAAC;AACH;AAGA,eAAsB,mBAAmB,IAAc,aAAqB,cAAsB,OAAwC;AACxI,SAAO,MAAM,iBAAiB,IAAI,aAAa,OAAO,aAAa;AACjE,UAAM,UAAU,MAAM,SAAS,OAAc,4BAA4B,EACtE,IAAI,EAAE,OAAO,WAAW,oBAAI,KAAK,EAAE,CAAC,EACpC,MAAM;AAAA,MACL,GAAU,6BAA6B,IAAI,YAAY;AAAA,MACvD,GAAU,6BAA6B,aAAa,WAAW;AAAA,IACjE,CAAC,EACA,UAAU,EAAE,IAAW,6BAA6B,GAAG,CAAC;AAC3D,WAAO,QAAQ,SAAS;AAAA,EAC1B,CAAC;AACH;AAQA,eAAsB,qBAAqB,IAAc,aAAqB,WAAsD;AAClI,SAAO,MAAM,iBAAiB,IAAI,aAAa,OAAO,aAAa;AACjE,UAAM,CAAC,GAAG,IAAI,MAAM,SAAS,OAAO;AAAA,MAClC,oBAA2B,SAAS;AAAA,MACpC,kBAAyB,SAAS;AAAA,IACpC,CAAC,EAAE,KAAY,QAAQ,EACpB,MAAM,IAAI,GAAU,SAAS,aAAa,WAAW,GAAG,GAAU,SAAS,IAAI,SAAS,CAAC,CAAC,EAAE,MAAM,CAAC;AACtG,WAAO,OAAO;AAAA,EAChB,CAAC;AACH;AAOA,eAAsB,mBACpB,IAAc,aAAqB,WAAmB,oBACpC;AAClB,SAAO,MAAM,iBAAiB,IAAI,aAAa,OAAO,aAAa;AACjE,QAAI,uBAAuB,MAAM;AAC/B,YAAM,CAAC,IAAI,IAAI,MAAM,SAAS,OAAO,EAAE,IAAW,6BAA6B,GAAG,CAAC,EAChF,KAAY,4BAA4B,EACxC,MAAM;AAAA,QACL,GAAU,6BAA6B,IAAI,kBAAkB;AAAA,QAC7D,GAAU,6BAA6B,aAAa,WAAW;AAAA,MACjE,CAAC,EAAE,MAAM,CAAC;AACZ,UAAI,CAAC,MAAM;AACT,eAAO;AAAA,MACT;AAAA,IACF;AACA,UAAM,UAAU,MAAM,SAAS,OAAc,QAAQ,EAClD,IAAI,EAAE,yBAAyB,oBAAoB,WAAW,oBAAI,KAAK,EAAE,CAAC,EAC1E,MAAM,IAAI,GAAU,SAAS,aAAa,WAAW,GAAG,GAAU,SAAS,IAAI,SAAS,CAAC,CAAC,EAC1F,UAAU,EAAE,IAAW,SAAS,GAAG,CAAC;AACvC,WAAO,QAAQ,SAAS;AAAA,EAC1B,CAAC;AACH;AAGA,eAAsB,mCACpB,IAAc,aAAqB,WAAmB,cACvC;AACf,QAAM,iBAAiB,IAAI,aAAa,OAAO,aAAa;AAC1D,UAAM,SAAS,OAAc,QAAQ,EAClC,IAAI,EAAE,uBAAuB,cAAc,WAAW,oBAAI,KAAK,EAAE,CAAC,EAClE,MAAM,IAAI,GAAU,SAAS,aAAa,WAAW,GAAG,GAAU,SAAS,IAAI,SAAS,CAAC,CAAC;AAAA,EAC/F,CAAC;AACH;AAQA,eAAsB,uBACpB,IAAc,aAAqB,cACkC;AACrE,SAAO,MAAM,iBAAiB,IAAI,aAAa,OAAO,aAAa;AACjE,UAAM,cAAc,MAAM,SAAS,OAAc,4BAA4B,EAC1E,MAAM;AAAA,MACL,GAAU,6BAA6B,IAAI,YAAY;AAAA,MACvD,GAAU,6BAA6B,aAAa,WAAW;AAAA,IACjE,CAAC,EACA,UAAU,EAAE,IAAW,6BAA6B,GAAG,CAAC;AAE3D,UAAM,CAAC,WAAW,IAAI,MAAM,SAAS,OAAO,EAAE,oBAA2B,sBAAsB,mBAAmB,CAAC,EAChH,KAAY,qBAAqB,EACjC,MAAM,GAAU,sBAAsB,aAAa,WAAW,CAAC,EAAE,MAAM,CAAC;AAC3E,QAAI,YAAY,WAAW,GAAG;AAC5B,aAAO,EAAE,SAAS,OAAO,uBAAuB,aAAa,sBAAsB,KAAK;AAAA,IAC1F;AACA,QAAI,YAAY,aAAa,sBAAsB;AACnD,QAAI,cAAc,MAAM;AACtB,YAAM,CAAC,IAAI,IAAI,MAAM,SAAS,OAAO,EAAE,IAAW,6BAA6B,GAAG,CAAC,EAChF,KAAY,4BAA4B,EACxC,MAAM,GAAU,6BAA6B,aAAa,WAAW,CAAC,EACtE,QAAQ,KAAY,6BAA6B,SAAS,CAAC,EAAE,MAAM,CAAC;AACvE,kBAAY,MAAM,MAAM;AACxB,UAAI,aAAa;AACf,cAAM,SAAS,OAAc,qBAAqB,EAC/C,IAAI,EAAE,oBAAoB,WAAW,WAAW,oBAAI,KAAK,EAAE,CAAC,EAC5D,MAAM,GAAU,sBAAsB,aAAa,WAAW,CAAC;AAAA,MACpE;AAAA,IACF;AACA,WAAO,EAAE,SAAS,MAAM,uBAAuB,UAAU;AAAA,EAC3D,CAAC;AACH;AAGA,eAAsB,2BAA2B,IAAc,aAAsC;AACnG,SAAO,MAAM,iBAAiB,IAAI,aAAa,OAAO,aAAa;AACjE,UAAM,OAAO,MAAM,SAAS,OAAc,4BAA4B,EACnE,MAAM,GAAU,6BAA6B,aAAa,WAAW,CAAC,EACtE,UAAU,EAAE,IAAW,6BAA6B,GAAG,CAAC;AAC3D,WAAO,KAAK;AAAA,EACd,CAAC;AACH;AAEA,eAAsB,iBAAiB,IAAc,OAQnC;AAGhB,QAAM,eAAe,IAAI,EAAE,WAAW,MAAM,WAAW,aAAa,MAAM,eAAe,KAAK,GAAG,OAAO,aAAa;AACnH,UAAM,SAAS,OAAc,WAAW,EAAE,OAAO;AAAA,MAC/C,WAAW,MAAM;AAAA,MACjB,aAAa,MAAM,eAAe;AAAA,MAClC,WAAW,MAAM,aAAa;AAAA,MAC9B,QAAQ,MAAM;AAAA,MACd,YAAY,MAAM,cAAc;AAAA,MAChC,UAAU,MAAM,YAAY;AAAA,MAC5B,UAAU,MAAM,YAAY,CAAC;AAAA,IAC/B,CAAC;AAAA,EACH,CAAC;AACH;AAEA,eAAe,gCAAgC,IAAc,aAAqB,eAAwE;AACxJ,QAAM,OAAO,MAAM,GAAG,OAAO;AAAA,IAC3B,MAAa,8BAA8B;AAAA,IAC3C,SAAgB,8BAA8B;AAAA,IAC9C,WAAkB,8BAA8B;AAAA,IAChD,WAAkB,8BAA8B;AAAA,EAClD,CAAC,EAAE,KAAY,6BAA6B,EACzC,MAAM;AAAA,IACL,GAAU,8BAA8B,aAAa,WAAW;AAAA,IAChE,GAAU,8BAA8B,eAAe,aAAa;AAAA,EACtE,CAAC,EACA,QAAQ,IAAW,8BAA8B,IAAI,CAAC;AACzD,SAAO,KAAK,IAAI,uCAAuC;AACzD;AAEA,SAAS,wBAAwB,KAAuD,WAAyE;AAC/J,SAAO;AAAA,IACL,IAAI,IAAI;AAAA,IACR,WAAW,IAAI;AAAA,IACf,aAAa,IAAI;AAAA,IACjB,MAAM,IAAI;AAAA,IACV,aAAa,IAAI;AAAA,IACjB;AAAA,IACA,WAAW,IAAI,UAAU,YAAY;AAAA,IACrC,WAAW,IAAI,UAAU,YAAY;AAAA,EACvC;AACF;AAEA,SAAS,wCAAwC,KAKR;AACvC,SAAO;AAAA,IACL,MAAM,IAAI;AAAA,IACV,SAAS,IAAI;AAAA,IACb,WAAW,IAAI,UAAU,YAAY;AAAA,IACrC,WAAW,IAAI,UAAU,YAAY;AAAA,EACvC;AACF;AAEA,SAAS,4BAA4B,KAA6E;AAChH,SAAO;AAAA,IACL,IAAI,IAAI;AAAA,IACR,MAAM,IAAI,QAAQ;AAAA,IAClB,KAAK,IAAI;AAAA,IACT,aAAa,OAAO,KAAK,IAAI,oBAAoB,CAAC,CAAC,EAAE,KAAK;AAAA,IAC1D,mBAAmB,OAAO,IAAI,iBAAiB;AAAA,EACjD;AACF;AAEA,eAAe,oCACb,IACA,aACA,YACkD;AAClD,QAAM,UAAU,oBAAI,IAAwC;AAC5D,MAAI,WAAW,WAAW,GAAG;AAC3B,WAAO;AAAA,EACT;AACA,QAAM,OAAO,MAAM,GAAG,OAAO,EAAE,KAAY,iBAAiB,EACzD,MAAM;AAAA,IACL,GAAU,kBAAkB,aAAa,WAAW;AAAA,IACpD,QAAe,kBAAkB,WAAW,UAAU;AAAA,EACxD,CAAC,EACA,QAAQ,IAAW,kBAAkB,SAAS,GAAG,IAAW,kBAAkB,QAAQ,CAAC;AAC1F,aAAW,OAAO,MAAM;AACtB,UAAM,OAAO,QAAQ,IAAI,IAAI,SAAS,KAAK,CAAC;AAC5C,SAAK,KAAK,4BAA4B,GAAG,CAAC;AAC1C,YAAQ,IAAI,IAAI,WAAW,IAAI;AAAA,EACjC;AACA,SAAO;AACT;AAEA,eAAe,wBAAwB,IAAc,OAKb;AACtC,MAAI,MAAM,QAAQ,WAAW,GAAG;AAC9B,WAAO,CAAC;AAAA,EACV;AACA,QAAM,OAAO,MAAM,GAAG,OAAc,iBAAiB,EAAE,OAAO,MAAM,QAAQ,IAAI,CAAC,YAAY;AAAA,IAC3F,WAAW,MAAM;AAAA,IACjB,aAAa,MAAM;AAAA,IACnB,WAAW,MAAM;AAAA,IACjB,UAAU,OAAO;AAAA,IACjB,MAAM,OAAO,QAAQ;AAAA,IACrB,KAAK,OAAO;AAAA,IACZ,cAAc,OAAO,gBAAgB;AAAA,IACrC,WAAW,OAAO,aAAa;AAAA,IAC/B,gBAAgB,OAAO,kBAAkB;AAAA,IACzC,kBAAkB,OAAO,oBAAoB,CAAC;AAAA,EAChD,EAAE,CAAC,EAAE,UAAU;AACf,SAAO,KAAK,IAAI,2BAA2B;AAC7C;AAEA,eAAsB,wBAAwB,IAAc,OAKpB;AACtC,SAAO,MAAM;AAAA,IAAe;AAAA,IAAI,EAAE,WAAW,MAAM,WAAW,aAAa,MAAM,YAAY;AAAA,IAAG,OAAO,aACrG,MAAM,wBAAwB,UAAU,KAAK;AAAA,EAC/C;AACF;AAEA,eAAsB,6BAA6B,IAAc,aAAqB,WAAwD;AAC5I,SAAO,MAAM,iBAAiB,IAAI,aAAa,OAAO,aAAa;AACjE,UAAM,UAAU,MAAM,oCAAoC,UAAU,aAAa,CAAC,SAAS,CAAC;AAC5F,WAAO,QAAQ,IAAI,SAAS,KAAK,CAAC;AAAA,EACpC,CAAC;AACH;AAEA,eAAsB,kCAAkC,IAAc,OAIjB;AACnD,SAAO,MAAM,iBAAiB,IAAI,MAAM,aAAa,OAAO,aAAa,MAAM,SAAS;AAAA,IAAY,OAAO,OACzG,MAAM,+CAA+C,IAAI,KAAK;AAAA,EAChE,CAAC;AACH;AAEA,eAAe,+CACb,IACA,OAKkD;AAClD,QAAM,UAAsC,CAAC;AAC7C,QAAM,aAAuB,CAAC;AAC9B,aAAW,UAAU,MAAM,SAAS;AAClC,UAAM,CAAC,GAAG,IAAI,MAAM,GAAG,OAAc,iBAAiB,EACnD,IAAI;AAAA,MACH,kBAAkB,OAAO;AAAA,MACzB,mBAAmB,MAAa,kBAAkB,iBAAiB;AAAA,MACnE,WAAW,oBAAI,KAAK;AAAA,IACtB,CAAC,EACA,MAAM;AAAA,MACL,GAAU,kBAAkB,aAAa,MAAM,WAAW;AAAA,MAC1D,GAAU,kBAAkB,WAAW,MAAM,SAAS;AAAA,MACtD,GAAU,kBAAkB,UAAU,OAAO,EAAE;AAAA,IACjD,CAAC,EACA,UAAU;AACb,QAAI,CAAC,KAAK;AACR,iBAAW,KAAK,OAAO,EAAE;AAAA,IAC3B,OAAO;AACL,cAAQ,KAAK,4BAA4B,GAAG,CAAC;AAAA,IAC/C;AAAA,EACF;AACA,SAAO,EAAE,SAAS,WAAW;AAC/B;AAEA,eAAsB,4BACpB,IACA,aACA,WACA,eACmC;AACnC,SAAO,MAAM,iBAAiB,IAAI,aAAa,OAAO,aAAa;AACjE,UAAM,OAAO,MAAM,SAAS,OAAO,EAAE,KAAY,iBAAiB,EAC/D,MAAM;AAAA,MACL,GAAU,kBAAkB,aAAa,WAAW;AAAA,MACpD,GAAU,kBAAkB,WAAW,SAAS;AAAA,IAClD,CAAC,EACA,QAAQ,IAAW,kBAAkB,SAAS,GAAG,IAAW,kBAAkB,QAAQ,CAAC;AAC1F,WAAO,KAAK,IAAI,CAAC,QAAQ;AACvB,UAAI;AACJ,UAAI;AACF,kBAAU,OAAO,YAAY,OAAO,QAAQ,IAAI,oBAAoB,CAAC,CAAC,EACnE,IAAI,CAAC,CAAC,MAAM,MAAM,MAAM,CAAC,MAAM,wBAAwB,eAAe,MAAM,CAAC,CAAC,CAAC;AAAA,MACpF,QAAQ;AACN,cAAM,IAAI,MAAM,iDAAiD;AAAA,MACnE;AACA,aAAO;AAAA,QACL,GAAG,4BAA4B,GAAG;AAAA,QAClC,GAAI,IAAI,eAAe,EAAE,cAAc,IAAI,aAAa,IAAI,CAAC;AAAA,QAC7D,GAAI,IAAI,YAAY,EAAE,WAAW,IAAI,UAAU,IAAI,CAAC;AAAA,QACpD,GAAI,IAAI,iBAAiB,EAAE,gBAAgB,IAAI,eAAe,IAAI,CAAC;AAAA,QACnE;AAAA,MACF;AAAA,IACF,CAAC;AAAA,EACH,CAAC;AACH;AAEA,eAAsB,cAAc,IAAc,OAmB7B;AAGnB,QAAM,KAAK,OAAO,WAAW;AAC7B,SAAO,MAAM,eAAe,IAAI,EAAE,WAAW,MAAM,WAAW,aAAa,MAAM,YAAY,GAAG,OAAO,aAAa;AAClH,UAAM,CAAC,GAAG,IAAI,MAAM,SAAS,OAAc,QAAQ,EAAE,OAAO;AAAA,MAC1D;AAAA,MACA,WAAW,MAAM;AAAA,MACjB,aAAa,MAAM;AAAA,MACnB,gBAAgB,MAAM;AAAA,MACtB,WAAW,MAAM;AAAA,MACjB,OAAO,MAAM,SAAS,CAAC;AAAA,MACvB,UAAU,MAAM;AAAA,MAChB,OAAO,MAAM;AAAA,MACb,gBAAgB,MAAM;AAAA,MACtB,WAAW,MAAM,aAAa;AAAA,MAC9B,gBAAgB,MAAM,kBAAkB;AAAA,MACxC,eAAe,MAAM,iBAAiB;AAAA,MACtC,0BAA0B,MAAM,4BAA4B;AAAA,MAC5D,iBAAiB,MAAM,mBAAmB;AAAA,MAC1C,sBAAsB,MAAM,wBAAwB;AAAA,MACpD,QAAQ;AAAA,IACV,CAAC,EAAE,UAAU;AACb,QAAI,CAAC,KAAK;AACR,YAAM,IAAI,MAAM,0BAA0B;AAAA,IAC5C;AACA,UAAM,aAAa,MAAM,wBAAwB,UAAU;AAAA,MACzD,WAAW,MAAM;AAAA,MACjB,aAAa,MAAM;AAAA,MACnB,WAAW,IAAI;AAAA,MACf,SAAS,MAAM,cAAc,CAAC;AAAA,IAChC,CAAC;AACD,WAAO,WAAW,KAAK,UAAU;AAAA,EACnC,CAAC;AACH;AAYA,eAAsB,gCAAgC,IAAc,OAkBhB;AAGlD,QAAM,KAAK,OAAO,WAAW;AAC7B,SAAO,MAAM,eAAe,IAAI,EAAE,WAAW,MAAM,WAAW,aAAa,MAAM,YAAY,GAAG,OAAO,aAAa;AAClH,UAAM,CAAC,QAAQ,IAAI,MAAM,SAAS,OAAc,QAAQ,EAAE,OAAO;AAAA,MAC/D;AAAA,MACA,WAAW,MAAM;AAAA,MACjB,aAAa,MAAM;AAAA,MACnB,gBAAgB,MAAM;AAAA,MACtB,WAAW,MAAM;AAAA,MACjB,OAAO,MAAM,SAAS,CAAC;AAAA,MACvB,UAAU,MAAM;AAAA,MAChB,OAAO,MAAM;AAAA,MACb,gBAAgB,MAAM;AAAA,MACtB,WAAW,MAAM,aAAa;AAAA,MAC9B,gBAAgB,MAAM,kBAAkB;AAAA,MACxC,eAAe,MAAM,iBAAiB;AAAA,MACtC,0BAA0B,MAAM,4BAA4B;AAAA,MAC5D,iBAAiB,MAAM,mBAAmB;AAAA,MAC1C,sBAAsB,MAAM;AAAA,MAC5B,QAAQ;AAAA,IACV,CAAC,EAAE,oBAAoB;AAAA,MACrB,QAAQ,CAAQ,SAAS,aAAoB,SAAS,oBAAoB;AAAA,MAC1E,OAAO,MAAa,SAAS,oBAAoB;AAAA,IACnD,CAAC,EAAE,UAAU;AACb,QAAI,UAAU;AACZ,YAAM,aAAa,MAAM,wBAAwB,UAAU;AAAA,QACzD,WAAW,MAAM;AAAA,QACjB,aAAa,MAAM;AAAA,QACnB,WAAW,SAAS;AAAA,QACpB,SAAS,MAAM,cAAc,CAAC;AAAA,MAChC,CAAC;AACD,aAAO,EAAE,SAAS,WAAW,UAAU,UAAU,GAAG,SAAS,KAAK;AAAA,IACpE;AACA,UAAM,CAAC,QAAQ,IAAI,MAAM,SAAS,OAAO,EAAE,KAAY,QAAQ,EAAE,MAAM;AAAA,MACrE,GAAU,SAAS,aAAa,MAAM,WAAW;AAAA,MACjD,GAAU,SAAS,sBAAsB,MAAM,oBAAoB;AAAA,IACrE,CAAC,EAAE,MAAM,CAAC;AACV,QAAI,CAAC,UAAU;AAIb,YAAM,IAAI,MAAM,gDAAgD;AAAA,IAClE;AACA,UAAM,UAAU,MAAM,oCAAoC,UAAU,MAAM,aAAa,CAAC,SAAS,EAAE,CAAC;AACpG,WAAO,EAAE,SAAS,WAAW,UAAU,QAAQ,IAAI,SAAS,EAAE,KAAK,CAAC,CAAC,GAAG,SAAS,MAAM;AAAA,EACzF,CAAC;AACH;AAEA,eAAsB,iCAAiC,IAAc,aAAqB,sBAAuD;AAC/I,SAAO,MAAM,iBAAiB,IAAI,aAAa,OAAO,aAAa;AACjE,UAAM,CAAC,GAAG,IAAI,MAAM,SAAS,OAAO,EAAE,KAAY,QAAQ,EAAE,MAAM;AAAA,MAChE,GAAU,SAAS,aAAa,WAAW;AAAA,MAC3C,GAAU,SAAS,sBAAsB,oBAAoB;AAAA,IAC/D,CAAC,EAAE,MAAM,CAAC;AACV,QAAI,CAAC,IAAK,QAAO;AACjB,UAAM,UAAU,MAAM,oCAAoC,UAAU,aAAa,CAAC,IAAI,EAAE,CAAC;AACzF,WAAO,WAAW,KAAK,QAAQ,IAAI,IAAI,EAAE,KAAK,CAAC,CAAC;AAAA,EAClD,CAAC;AACH;AAEA,eAAsB,WAAW,IAAc,aAAqB,WAA4C;AAC9G,SAAO,MAAM,iBAAiB,IAAI,aAAa,OAAO,aAAa;AACjE,UAAM,CAAC,GAAG,IAAI,MAAM,SAAS,OAAO,EAAE,KAAY,QAAQ,EAAE,MAAM,IAAI,GAAU,SAAS,aAAa,WAAW,GAAG,GAAU,SAAS,IAAI,SAAS,CAAC,CAAC,EAAE,MAAM,CAAC;AAC/J,QAAI,CAAC,IAAK,QAAO;AACjB,UAAM,UAAU,MAAM,oCAAoC,UAAU,aAAa,CAAC,IAAI,EAAE,CAAC;AACzF,WAAO,WAAW,KAAK,QAAQ,IAAI,IAAI,EAAE,KAAK,CAAC,CAAC;AAAA,EAClD,CAAC;AACH;AAcA,eAAsB,qBAAqB,IAAc,aAAqB,gBAAiD;AAC7H,SAAO,MAAM,iBAAiB,IAAI,aAAa,OAAO,aAAa;AACjE,UAAM,CAAC,GAAG,IAAI,MAAM,SAAS,OAAO,EAAE,KAAY,QAAQ,EACvD,MAAM,IAAI,GAAU,SAAS,aAAa,WAAW,GAAG,GAAU,SAAS,gBAAgB,cAAc,CAAC,CAAC,EAC3G,MAAM,CAAC;AACV,WAAO,MAAM,WAAW,GAAG,IAAI;AAAA,EACjC,CAAC;AACH;AASA,eAAsB,kCAAkC,IAAc,aAAqB,gBAAuD;AAChJ,SAAO,MAAM,iBAAiB,IAAI,aAAa,OAAO,aAAa;AACjE,UAAM,OAAO,MAAM,SAAS,eAAe,EAAE,eAAsB,SAAS,cAAc,CAAC,EAAE,KAAY,QAAQ,EAC9G,MAAM,IAAI,GAAU,SAAS,aAAa,WAAW,GAAG,GAAU,SAAS,gBAAgB,cAAc,CAAC,CAAC;AAC9G,WAAO,KAAK,IAAI,CAAC,MAAM,EAAE,iBAAiB,IAAI;AAAA,EAChD,CAAC;AACH;AAEA,eAAsB,aAAa,IAAc,aAAqB,QAAQ,IAAwB;AACpG,SAAO,MAAM,iBAAiB,IAAI,aAAa,OAAO,aAAa;AACjE,UAAM,OAAO,MAAM,SAAS,OAAO,EAAE,KAAY,QAAQ,EACtD,MAAM,GAAU,SAAS,aAAa,WAAW,CAAC,EAClD,QAAQ,KAAY,SAAS,SAAS,GAAG,KAAY,SAAS,EAAE,CAAC,EACjE,MAAM,KAAK;AACd,UAAM,UAAU,MAAM,oCAAoC,UAAU,aAAa,KAAK,IAAI,CAAC,QAAQ,IAAI,EAAE,CAAC;AAC1G,WAAO,KAAK,IAAI,CAAC,QAAQ,WAAW,KAAK,QAAQ,IAAI,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC;AAAA,EACrE,CAAC;AACH;AASA,eAAsB,gCAAgC,IAAc,aAAsC;AACxG,SAAO,MAAM,iBAAiB,IAAI,aAAa,OAAO,aAAa;AACjE,UAAM,CAAC,EAAE,MAAM,IAAI,EAAE,OAAO,EAAE,CAAC,IAAI,MAAM,SAAS,OAAO;AAAA,MACvD,OAAO;AAAA,IACT,CAAC,EAAE,KAAY,QAAQ,EACpB,MAAM;AAAA,MACL,GAAU,SAAS,aAAa,WAAW;AAAA,MAC3C,QAAe,SAAS,QAAQ,CAAC,UAAU,WAAW,iBAAiB,CAAC;AAAA,IAC1E,CAAC;AACH,WAAO,OAAO,KAAK;AAAA,EACrB,CAAC;AACH;AAEA,eAAsB,eAAe,IAAc,aAAqB,WAAqC;AAC3G,QAAM,UAAU,MAAM,WAAW,IAAI,aAAa,SAAS;AAC3D,MAAI,CAAC,SAAS;AACZ,UAAM,IAAI,MAAM,sBAAsB,SAAS,EAAE;AAAA,EACnD;AACA,SAAO;AACT;AAQA,IAAM,mBAAmB;AAKzB,eAAsB,kBACpB,IACA,aACA,WACA,iBAAoD,GACpD,cAAc,KACW;AACzB,QAAM,UAAU,OAAO,mBAAmB,WACtC,EAAE,OAAO,gBAAgB,OAAO,YAAY,IAC5C;AACJ,QAAM,QAAQ,uBAAuB,QAAQ,OAAO,CAAC;AACrD,QAAM,QAAQ,oBAAoB,QAAQ,OAAO,GAAG;AACpD,QAAM,YAAY,QAAQ,WAAW,UAAa,OAAO,SAAS,QAAQ,MAAM;AAChF,QAAM,SAAS,YAAY,KAAK,MAAM,QAAQ,MAAgB,IAAI;AAElE,SAAO,MAAM,iBAAiB,IAAI,aAAa,OAAO,aAAa;AACjE,UAAM,UAAiB;AAAA,MACrB,GAAU,cAAc,aAAa,WAAW;AAAA,MAChD,GAAU,cAAc,WAAW,SAAS;AAAA,MAC5C,GAAU,cAAc,UAAU,KAAK;AAAA,IACzC;AACA,QAAI,WAAW,UAAa,UAAU,kBAAkB;AACtD,cAAQ,KAAK,GAAU,cAAc,UAAU,MAAM,CAAC;AAAA,IACxD;AACA,UAAM,OAAO,MAAM,SAAS,OAAO,EAAE,KAAY,aAAa,EAC3D,MAAM,IAAI,GAAG,OAAO,CAAC,EACrB,QAAQ,YAAY,KAAY,cAAc,QAAQ,IAAI,IAAW,cAAc,QAAQ,CAAC,EAC5F,MAAM,KAAK;AACd,YAAQ,YAAY,KAAK,QAAQ,IAAI,MAAM,IAAI,QAAQ;AAAA,EACzD,CAAC;AACH;AAEA,SAAS,uBAAuB,OAA2B,UAA0B;AACnF,MAAI,UAAU,UAAa,CAAC,OAAO,SAAS,KAAK,GAAG;AAClD,WAAO;AAAA,EACT;AACA,SAAO,KAAK,MAAM,KAAK;AACzB;AAEA,SAAS,oBAAoB,OAA2B,UAA0B;AAChF,MAAI,UAAU,UAAa,CAAC,OAAO,SAAS,KAAK,GAAG;AAClD,WAAO;AAAA,EACT;AACA,SAAO,KAAK,IAAI,GAAG,KAAK,MAAM,KAAK,CAAC;AACtC;AAEA,eAAsB,gBAAgB,IAAc,aAAqB,SAA+C;AACtH,SAAO,MAAM,iBAAiB,IAAI,aAAa,OAAO,aAAa;AACjE,UAAM,CAAC,GAAG,IAAI,MAAM,SAAS,OAAO,EAAE,KAAY,aAAa,EAAE,MAAM,IAAI,GAAU,cAAc,aAAa,WAAW,GAAG,GAAU,cAAc,IAAI,OAAO,CAAC,CAAC,EAAE,MAAM,CAAC;AAC5K,WAAO,MAAM,SAAS,GAAG,IAAI;AAAA,EAC/B,CAAC;AACH;AAEA,eAAsB,kBAAkB,IAAc,aAAqB,WASjE;AACR,SAAO,MAAM,iBAAiB,IAAI,aAAa,OAAO,aAAa;AACjE,UAAM,CAAC,GAAG,IAAI,MAAM,SAAS,OAAO,EAAE,KAAY,cAAc,EAC7D,MAAM,IAAI,GAAU,eAAe,aAAa,WAAW,GAAG,GAAU,eAAe,WAAW,SAAS,CAAC,CAAC,EAC7G,QAAQ,KAAY,eAAe,SAAS,CAAC,EAC7C,MAAM,CAAC;AACV,WAAO,MAAM;AAAA,MACX,IAAI,IAAI;AAAA,MACR,oBAAoB,IAAI;AAAA,MACxB,kBAAkB,IAAI;AAAA,MACtB,yBAAyB,IAAI,2BAA2B;AAAA,IAC1D,IAAI;AAAA,EACN,CAAC;AACH;AAQA,eAAsB,0BAA0B,IAAc,OAU5C;AAChB,MAAI,MAAM,MAAM,WAAW,GAAG;AAC5B;AAAA,EACF;AACA,QAAM,eAAe,IAAI,EAAE,WAAW,MAAM,WAAW,aAAa,MAAM,YAAY,GAAG,OAAO,aAAa;AAC3G,UAAM,SAAS,OAAc,mBAAmB,EAAE,OAAO,MAAM,MAAM,IAAI,CAAC,WAAW;AAAA,MACnF,WAAW,MAAM;AAAA,MACjB,aAAa,MAAM;AAAA,MACnB,WAAW,MAAM;AAAA,MACjB,QAAQ,MAAM,UAAU;AAAA,MACxB,2BAA2B,MAAM,6BAA6B;AAAA,MAC9D,UAAU,MAAM;AAAA,MAChB,MAAM,qBAAqB,MAAM,IAAI;AAAA,IACvC,EAAE,CAAC,EAAE,oBAAoB;AAAA,MACvB,QAAQ,CAAQ,oBAAoB,aAAoB,oBAAoB,WAAkB,oBAAoB,QAAQ;AAAA,IAC5H,CAAC;AAAA,EACH,CAAC;AACH;AAEA,eAAsB,uBAAuB,IAAc,aAAqB,WAAwF;AACtK,SAAO,MAAM,iBAAiB,IAAI,aAAa,OAAO,aAAa;AACjE,UAAM,OAAO,MAAM,SAAS,OAAO;AAAA,MACjC,UAAiB,oBAAoB;AAAA,MACrC,MAAa,oBAAoB;AAAA,IACnC,CAAC,EAAE,KAAY,mBAAmB,EAC/B,MAAM,IAAI,GAAU,oBAAoB,aAAa,WAAW,GAAG,GAAU,oBAAoB,WAAW,SAAS,CAAC,CAAC,EACvH,QAAe,oBAAoB,QAAQ;AAC9C,WAAO;AAAA,EACT,CAAC;AACH;AAUA,eAAsB,6BAA6B,IAAc,aAAqB,WAAkI;AACtN,SAAO,MAAM,iBAAiB,IAAI,aAAa,OAAO,aAAa;AACjE,UAAM,OAAO,MAAM,SAAS,OAAO;AAAA,MACjC,UAAiB,oBAAoB;AAAA,MACrC,MAAa,oBAAoB;AAAA,MACjC,2BAAkC,oBAAoB;AAAA,IACxD,CAAC,EAAE,KAAY,mBAAmB,EAC/B,MAAM;AAAA,MACL,GAAU,oBAAoB,aAAa,WAAW;AAAA,MACtD,GAAU,oBAAoB,WAAW,SAAS;AAAA,MAClD,GAAU,oBAAoB,QAAQ,IAAI;AAAA,IAC5C,CAAC,EACA,QAAe,oBAAoB,QAAQ;AAC9C,WAAO;AAAA,EACT,CAAC;AACH;AAQA,eAAsB,+BAA+B,IAAc,aAAqB,WAAoC;AAC1H,SAAO,MAAM,iBAAiB,IAAI,aAAa,OAAO,aAAa;AACjE,UAAM,CAAC,GAAG,IAAI,MAAM,SAAS,OAAO;AAAA,MAClC,OAAO;AAAA,IACT,CAAC,EAAE,KAAY,mBAAmB,EAC/B,MAAM;AAAA,MACL,GAAU,oBAAoB,aAAa,WAAW;AAAA,MACtD,GAAU,oBAAoB,WAAW,SAAS;AAAA,MAClD,GAAU,oBAAoB,QAAQ,IAAI;AAAA,IAC5C,CAAC;AACH,WAAO,OAAO,KAAK,SAAS,CAAC;AAAA,EAC/B,CAAC;AACH;AAQA,IAAM,kCAA0D;AAAA,EAC9D,sBAAsB;AAAA,EACtB,sBAAsB;AAAA,EACtB,mBAAmB;AAAA,EACnB,yBAAyB;AAC3B;AAEA,SAAS,eAAe,MAAmC;AACzD,MAAI,CAAC,QAAQ,OAAO,SAAS,UAAU;AACrC,WAAO;AAAA,EACT;AACA,QAAM,SAAS;AACf,MAAI,OAAO,OAAO,WAAW,UAAU;AACrC,WAAO,OAAO;AAAA,EAChB;AACA,MAAI,OAAO,OAAO,YAAY,UAAU;AACtC,WAAO,OAAO;AAAA,EAChB;AACA,SAAO;AACT;AAEA,SAAS,eAAe,MAAmC;AACzD,MAAI,CAAC,QAAQ,OAAO,SAAS,UAAU;AACrC,WAAO;AAAA,EACT;AACA,QAAM,OAAQ,KAA4B;AAC1C,SAAO,OAAO,SAAS,WAAW,OAAO;AAC3C;AA+BO,SAAS,kCACd,2BACU;AAGV,QAAM,0BAA0B,oBAAI,IAAyB;AAE7D,QAAM,uBAA+C,CAAC;AACtD,aAAW,CAAC,YAAY,QAAQ,KAAK,OAAO,QAAQ,+BAA+B,GAAG;AACpF,yBAAqB,QAAQ,IAAI;AAAA,EACnC;AACA,QAAM,gBAA0B,CAAC;AACjC,4BAA0B,QAAQ,CAAC,KAAK,UAAU;AAChD,UAAM,OAAO,eAAe,IAAI,IAAI;AACpC,UAAM,SAAS,eAAe,IAAI,IAAI;AACtC,QAAI,CAAC,QAAQ,CAAC,QAAQ;AACpB;AAAA,IACF;AACA,UAAM,oBAAoB,qBAAqB,IAAI;AACnD,QAAI,mBAAmB;AAErB,YAAM,OAAO,wBAAwB,IAAI,iBAAiB,KAAK,oBAAI,IAAY;AAC/E,WAAK,IAAI,MAAM;AACf,8BAAwB,IAAI,mBAAmB,IAAI;AACnD;AAAA,IACF;AACA,QAAI,gCAAgC,IAAI,GAAG;AAEzC,YAAM,OAAO,wBAAwB,IAAI,IAAI;AAC7C,UAAI,CAAC,QAAQ,CAAC,KAAK,IAAI,MAAM,GAAG;AAC9B,sBAAc,KAAK,KAAK;AAAA,MAC1B;AAAA,IACF;AAAA,EACF,CAAC;AACD,SAAO;AACT;AAsBA,eAAsB,uBAAuB,IAAc,OAiBzC;AAChB,QAAM,eAAe,IAAI,EAAE,WAAW,MAAM,WAAW,aAAa,MAAM,YAAY,GAAG,OAAO,aAAa;AAC3G,UAAM,SAAS,YAAY,OAAO,OAAO;AACvC,YAAM,GAAG,OAAc,mBAAmB,EACvC,IAAI,EAAE,QAAQ,MAAM,CAAC,EACrB,MAAM;AAAA,QACL,GAAU,oBAAoB,aAAa,MAAM,WAAW;AAAA,QAC5D,GAAU,oBAAoB,WAAW,MAAM,SAAS;AAAA,QACxD,GAAU,oBAAoB,QAAQ,IAAI;AAAA,QAC1C,GAAU,oBAAoB,UAAU,MAAM,gBAAgB;AAAA,MAChE,CAAC;AACH,UAAI,MAAM,oBAAoB,MAAM,iBAAiB,SAAS,GAAG;AAC/D,cAAM,GAAG,OAAc,mBAAmB,EAAE,OAAO,MAAM,iBAAiB,IAAI,CAAC,WAAW;AAAA,UACxF,WAAW,MAAM;AAAA,UACjB,aAAa,MAAM;AAAA,UACnB,WAAW,MAAM;AAAA,UACjB,QAAQ;AAAA,UACR,UAAU,MAAM;AAAA,UAChB,MAAM,qBAAqB,MAAM,IAAI;AAAA,UACrC,QAAQ;AAAA,QACV,EAAE,CAAC,EAAE,mBAAmB;AAAA,UACtB,QAAQ,CAAQ,oBAAoB,aAAoB,oBAAoB,WAAkB,oBAAoB,QAAQ;AAAA,UAC1H,KAAK,EAAE,QAAQ,KAAK;AAAA,QACtB,CAAC;AAAA,MACH;AAYA,YAAM,GAAG,OAAc,mBAAmB,EAAE,OAAO;AAAA,QACjD,WAAW,MAAM;AAAA,QACjB,aAAa,MAAM;AAAA,QACnB,WAAW,MAAM;AAAA,QACjB,QAAQ,MAAM,UAAU;AAAA,QACxB,UAAU,MAAM;AAAA,QAChB,MAAM,qBAAqB,MAAM,WAAW;AAAA,QAC5C,QAAQ;AAAA,MACV,CAAC,EAAE,mBAAmB;AAAA,QACpB,QAAQ,CAAQ,oBAAoB,aAAoB,oBAAoB,WAAkB,oBAAoB,QAAQ;AAAA,QAC1H,KAAK,EAAE,QAAQ,KAAK;AAAA,MACtB,CAAC;AAAA,IACH,CAAC;AAAA,EACH,CAAC;AACH;AAUA,eAAsB,2BAA2B,IAAc,aAAqB,WAAoC;AACtH,SAAO,MAAM,iBAAiB,IAAI,aAAa,OAAO,aAAa;AACjE,UAAM,CAAC,GAAG,IAAI,MAAM,SAAS,OAAO;AAAA,MAClC,aAAa,UAAgC,oBAAoB,QAAQ;AAAA,IAC3E,CAAC,EAAE,KAAY,mBAAmB,EAC/B,MAAM,IAAI,GAAU,oBAAoB,aAAa,WAAW,GAAG,GAAU,oBAAoB,WAAW,SAAS,CAAC,CAAC;AAC1H,UAAM,MAAM,KAAK;AACjB,WAAO,QAAQ,QAAQ,QAAQ,SAAY,IAAI,KAAK,MAAM,OAAO,GAAG,CAAC,IAAI;AAAA,EAC3E,CAAC;AACH;AAMA,eAAsB,0BAA0B,IAAc,aAAqB,WAAmB,iBAAwC;AAC5I,QAAM,iBAAiB,IAAI,aAAa,OAAO,aAAa;AAC1D,UAAM,SAAS,OAAc,QAAQ,EAClC,IAAI,EAAE,iBAAiB,WAAW,oBAAI,KAAK,EAAE,CAAC,EAC9C,MAAM,IAAI,GAAU,SAAS,aAAa,WAAW,GAAG,GAAU,SAAS,IAAI,SAAS,CAAC,CAAC;AAAA,EAC/F,CAAC;AACH;AASO,SAAS,2BAAoD;AAClE,SAAO,EAAE,MAAM,WAAW,MAAM,QAAQ,SAAS,oBAAoB;AACvE;AAoBO,IAAM,oBAAoB;AAiCjC,eAAsB,oBAAoB,IAAc,OAIjB;AACrC,SAAO,MAAM,eAAe,IAAI,EAAE,WAAW,MAAM,WAAW,aAAa,MAAM,YAAY,GAAG,OAAO,aAAa;AAClH,WAAO,MAAM,SAAS,YAAY,OAAO,OAAO;AAC9C,YAAM,iBAAiB,MAAM,GAAG,OAAc,mBAAmB,EAC9D,IAAI,EAAE,QAAQ,MAAM,CAAC,EACrB,MAAM;AAAA,QACL,GAAU,oBAAoB,aAAa,MAAM,WAAW;AAAA,QAC5D,GAAU,oBAAoB,WAAW,MAAM,SAAS;AAAA,QACxD,GAAU,oBAAoB,QAAQ,IAAI;AAAA,MAC5C,CAAC,EACA,UAAU,EAAE,IAAW,oBAAoB,GAAG,CAAC;AAElD,YAAM,CAAC,EAAE,YAAY,IAAI,EAAE,aAAa,GAAG,CAAC,IAAI,MAAM,GAAG,OAAO;AAAA,QAC9D,aAAa,mBAAkC,oBAAoB,QAAQ;AAAA,MAC7E,CAAC,EAAE,KAAY,mBAAmB,EAC/B,MAAM;AAAA,QACL,GAAU,oBAAoB,aAAa,MAAM,WAAW;AAAA,QAC5D,GAAU,oBAAoB,WAAW,MAAM,SAAS;AAAA,MAC1D,CAAC;AACH,YAAM,iBAAiB,OAAO,WAAW,IAAI;AAC7C,YAAM,GAAG,OAAc,mBAAmB,EAAE,OAAO;AAAA,QACjD,WAAW,MAAM;AAAA,QACjB,aAAa,MAAM;AAAA,QACnB,WAAW,MAAM;AAAA,QACjB,QAAQ;AAAA,QACR,UAAU;AAAA,QACV,MAAM,qBAAqB,yBAAyB,CAAC;AAAA,QACrD,QAAQ;AAAA,MACV,CAAC,EAAE,oBAAoB;AAAA,QACrB,QAAQ,CAAQ,oBAAoB,aAAoB,oBAAoB,WAAkB,oBAAoB,QAAQ;AAAA,MAC5H,CAAC;AAED,YAAM,CAAC,EAAE,WAAW,IAAI,EAAE,YAAY,EAAE,CAAC,IAAI,MAAM,GAAG,OAAO;AAAA,QAC3D,YAAY,mBAAkC,eAAe,YAAY;AAAA,MAC3E,CAAC,EAAE,KAAY,cAAc,EAC1B,MAAM;AAAA,QACL,GAAU,eAAe,aAAa,MAAM,WAAW;AAAA,QACvD,GAAU,eAAe,WAAW,MAAM,SAAS;AAAA,MACrD,CAAC;AACH,YAAM,kBAAkB,OAAO,UAAU,IAAI;AAC7C,YAAM,GAAG,OAAc,cAAc,EAAE,OAAO;AAAA,QAC5C,WAAW,MAAM;AAAA,QACjB,aAAa,MAAM;AAAA,QACnB,WAAW,MAAM;AAAA,QACjB,QAAQ;AAAA,QACR,cAAc;AAAA,QACd,oBAAoB;AAAA,QACpB,kBAAkB,CAAC;AAAA,MACrB,CAAC;AAED,YAAM,GAAG,OAAc,QAAQ,EAC5B,IAAI,EAAE,iBAAiB,GAAG,WAAW,oBAAI,KAAK,EAAE,CAAC,EACjD,MAAM,IAAI,GAAU,SAAS,aAAa,MAAM,WAAW,GAAG,GAAU,SAAS,IAAI,MAAM,SAAS,CAAC,CAAC;AAEzG,aAAO,EAAE,iBAAiB,eAAe,QAAQ,gBAAgB,gBAAgB;AAAA,IACnF,CAAC;AAAA,EACH,CAAC;AACH;AAEA,eAAsB,yBAAyB,IAAc,aAAqB,WAAoC;AACpH,SAAO,MAAM,iBAAiB,IAAI,aAAa,OAAO,aAAa;AACjE,UAAM,CAAC,GAAG,IAAI,MAAM,SAAS,OAAO;AAAA,MAClC,OAAO;AAAA,IACT,CAAC,EAAE,KAAY,mBAAmB,EAC/B,MAAM,IAAI,GAAU,oBAAoB,aAAa,WAAW,GAAG,GAAU,oBAAoB,WAAW,SAAS,CAAC,CAAC;AAC1H,WAAO,OAAO,KAAK,SAAS,CAAC;AAAA,EAC/B,CAAC;AACH;AAOA,eAAsB,yBAAyB,IAAc,aAAqB,WAAkC;AAClH,QAAM,iBAAiB,IAAI,aAAa,OAAO,aAAa;AAC1D,UAAM,SAAS,OAAc,QAAQ,EAClC,IAAI,EAAE,kBAAkB,MAAM,WAAW,oBAAI,KAAK,EAAE,CAAC,EACrD,MAAM,IAAI,GAAU,SAAS,aAAa,WAAW,GAAG,GAAU,SAAS,IAAI,SAAS,CAAC,CAAC;AAAA,EAC/F,CAAC;AACH;AAOA,eAAsB,gCAAgC,IAAc,aAAqB,WAAqC;AAC5H,SAAO,MAAM,iBAAiB,IAAI,aAAa,OAAO,aAAa;AACjE,UAAM,UAAU,MAAM,SAAS,OAAc,QAAQ,EAClD,IAAI,EAAE,kBAAkB,OAAO,WAAW,oBAAI,KAAK,EAAE,CAAC,EACtD,MAAM;AAAA,MACL,GAAU,SAAS,aAAa,WAAW;AAAA,MAC3C,GAAU,SAAS,IAAI,SAAS;AAAA,MAChC,GAAU,SAAS,kBAAkB,IAAI;AAAA,IAC3C,CAAC,EACA,UAAU,EAAE,IAAW,SAAS,GAAG,CAAC;AACvC,WAAO,QAAQ,SAAS;AAAA,EAC1B,CAAC;AACH;AASA,eAAsB,6BAA6B,IAAc,aAAqB,QAAiC;AACrH,SAAO,MAAM,iBAAiB,IAAI,aAAa,OAAO,aAAa;AACjE,UAAM,CAAC,GAAG,IAAI,MAAM,SAAS,OAAO;AAAA,MAClC,OAAO;AAAA,IACT,CAAC,EAAE,KAAY,mBAAmB,EAC/B,MAAM,IAAI,GAAU,oBAAoB,aAAa,WAAW,GAAG,GAAU,oBAAoB,QAAQ,MAAM,CAAC,CAAC;AACpH,WAAO,OAAO,KAAK,SAAS,CAAC;AAAA,EAC/B,CAAC;AACH;AAOA,eAAsB,6BAA6B,IAAc,OAK/C;AAChB,QAAM,eAAe,IAAI,EAAE,WAAW,MAAM,WAAW,aAAa,MAAM,YAAY,GAAG,OAAO,aAAa;AAC3G,UAAM,SAAS,OAAc,uBAAuB,EAAE,OAAO;AAAA,MAC3D,WAAW,MAAM;AAAA,MACjB,aAAa,MAAM;AAAA,MACnB,WAAW,MAAM;AAAA,MACjB,UAAU,MAAM;AAAA,IAClB,CAAC,EAAE,mBAAmB;AAAA,MACpB,QAAQ,CAAQ,wBAAwB,aAAoB,wBAAwB,SAAS;AAAA,MAC7F,KAAK,EAAE,UAAU,MAAM,UAAU,WAAW,oBAAI,KAAK,EAAE;AAAA,IACzD,CAAC;AAAA,EACH,CAAC;AACH;AAEA,eAAsB,0BAA0B,IAAc,aAAqB,WAA4D;AAC7I,SAAO,MAAM,iBAAiB,IAAI,aAAa,OAAO,aAAa;AACjE,UAAM,CAAC,GAAG,IAAI,MAAM,SAAS,OAAO,EAAE,UAAiB,wBAAwB,SAAS,CAAC,EACtF,KAAY,uBAAuB,EACnC,MAAM,IAAI,GAAU,wBAAwB,aAAa,WAAW,GAAG,GAAU,wBAAwB,WAAW,SAAS,CAAC,CAAC,EAC/H,MAAM,CAAC;AACV,WAAO,KAAK,YAAY;AAAA,EAC1B,CAAC;AACH;AA+BA,SAAS,aAAa,KAAwE;AAC5F,SAAO;AAAA,IACL,IAAI,IAAI;AAAA,IACR,aAAa,IAAI;AAAA,IACjB,WAAW,IAAI;AAAA,IACf,QAAQ,IAAI;AAAA,IACZ,OAAO,IAAI;AAAA,IACX,MAAM,IAAI;AAAA,IACV,OAAO,IAAI;AAAA,IACX,YAAY,IAAI;AAAA,IAChB,WAAW,IAAI,cAAc,QAAQ,IAAI,cAAc,SAAY,OAAO,OAAO,IAAI,SAAS;AAAA,IAC9F,iBAAiB,IAAI,oBAAoB,QAAQ,IAAI,oBAAoB,SAAY,OAAO,OAAO,IAAI,eAAe;AAAA,IACtH,OAAO,IAAI;AAAA,IACX,QAAQ,IAAI;AAAA,IACZ,QAAQ,IAAI;AAAA,IACZ,WAAW,IAAI;AAAA,IACf,aAAa,IAAI;AAAA,EACnB;AACF;AAEA,eAAsB,gBAAgB,IAAc,OAWnB;AAC/B,SAAO,MAAM,eAAe,IAAI,EAAE,WAAW,MAAM,WAAW,aAAa,MAAM,YAAY,GAAG,OAAO,aAAa;AAClH,UAAM,CAAC,GAAG,IAAI,MAAM,SAAS,OAAc,iBAAiB,EAAE,OAAO;AAAA,MACnE,IAAI,MAAM;AAAA,MACV,WAAW,MAAM;AAAA,MACjB,aAAa,MAAM;AAAA,MACnB,WAAW,MAAM;AAAA,MACjB,QAAQ,MAAM,UAAU;AAAA,MACxB,OAAO;AAAA,MACP,MAAM,MAAM;AAAA,MACZ,OAAO,MAAM;AAAA,MACb,OAAO,MAAM;AAAA,MACb,QAAQ,MAAM;AAAA,MACd,QAAQ,MAAM,UAAU;AAAA,IAC1B,CAAC,EAAE,UAAU;AACb,WAAO,aAAa,GAAI;AAAA,EAC1B,CAAC;AACH;AAEA,eAAsB,gBAAgB,IAAc,OAUZ;AACtC,SAAO,MAAM,eAAe,IAAI,EAAE,WAAW,MAAM,WAAW,aAAa,MAAM,YAAY,GAAG,OAAO,aAAa;AAClH,UAAM,MAA6D,EAAE,OAAO,MAAM,MAAM;AACxF,QAAI,MAAM,eAAe,OAAW,KAAI,aAAa,MAAM;AAC3D,QAAI,MAAM,cAAc,OAAW,KAAI,YAAY,MAAM;AACzD,QAAI,MAAM,oBAAoB,OAAW,KAAI,kBAAkB,MAAM;AACrE,QAAI,MAAM,WAAW,OAAW,KAAI,SAAS,MAAM;AACnD,QAAI,MAAM,aAAa,MAAM,UAAU,eAAe,MAAM,UAAU,UAAU;AAC9E,UAAI,cAAc,oBAAI,KAAK;AAAA,IAC7B;AACA,UAAM,CAAC,GAAG,IAAI,MAAM,SAAS,OAAc,iBAAiB,EACzD,IAAI,GAAG,EACP,MAAM;AAAA,MACL,GAAU,kBAAkB,aAAa,MAAM,WAAW;AAAA,MAC1D,GAAU,kBAAkB,IAAI,MAAM,WAAW;AAAA,IACnD,CAAC,EACA,UAAU;AACb,WAAO,MAAM,aAAa,GAAG,IAAI;AAAA,EACnC,CAAC;AACH;AASA,eAAsB,gBAAgB,IAAc,OAIlC;AAChB,QAAM,eAAe,IAAI,EAAE,WAAW,MAAM,WAAW,aAAa,MAAM,YAAY,GAAG,OAAO,aAAa;AAC3G,UAAM,SAAS,OAAc,iBAAiB,EAC3C,MAAM;AAAA,MACL,GAAU,kBAAkB,aAAa,MAAM,WAAW;AAAA,MAC1D,GAAU,kBAAkB,IAAI,MAAM,WAAW;AAAA,IACnD,CAAC;AAAA,EACL,CAAC;AACH;AAEA,eAAsB,aAAa,IAAc,aAAqB,aAA0D;AAC9H,SAAO,MAAM,iBAAiB,IAAI,aAAa,OAAO,aAAa;AACjE,UAAM,CAAC,GAAG,IAAI,MAAM,SAAS,OAAO,EAAE,KAAY,iBAAiB,EAChE,MAAM;AAAA,MACL,GAAU,kBAAkB,aAAa,WAAW;AAAA,MACpD,GAAU,kBAAkB,IAAI,WAAW;AAAA,IAC7C,CAAC,EACA,MAAM,CAAC;AACV,WAAO,MAAM,aAAa,GAAG,IAAI;AAAA,EACnC,CAAC;AACH;AAEA,eAAsB,eAAe,IAAc,aAAqB,WAAmD;AACzH,SAAO,MAAM,iBAAiB,IAAI,aAAa,OAAO,aAAa;AACjE,UAAM,OAAO,MAAM,SAAS,OAAO,EAAE,KAAY,iBAAiB,EAC/D,MAAM;AAAA,MACL,GAAU,kBAAkB,aAAa,WAAW;AAAA,MACpD,GAAU,kBAAkB,WAAW,SAAS;AAAA,IAClD,CAAC,EACA,QAAQ,KAAY,kBAAkB,SAAS,CAAC;AACnD,WAAO,KAAK,IAAI,YAAY;AAAA,EAC9B,CAAC;AACH;AAyBA,SAAS,cAAc,KAA0E;AAC/F,SAAO;AAAA,IACL,IAAI,IAAI;AAAA,IACR,WAAW,IAAI;AAAA,IACf,aAAa,IAAI;AAAA,IACjB,WAAW,IAAI;AAAA,IACf,eAAe,IAAI,iBAAiB;AAAA,IACpC,YAAY,IAAI;AAAA,IAChB,MAAM,IAAI;AAAA,IACV,MAAM,IAAI;AAAA,IACV,OAAO,IAAI;AAAA,IACX,KAAK,IAAI;AAAA,IACT,QAAQ,IAAI;AAAA,IACZ,UAAU,IAAI;AAAA,IACd,aAAa,IAAI,YAAY,YAAY;AAAA,IACzC,WAAW,IAAI,UAAU,YAAY;AAAA,IACrC,UAAU,IAAI,WAAW,IAAI,SAAS,YAAY,IAAI;AAAA,EACxD;AACF;AAEA,eAAsB,iBAAiB,IAAc,OAYnB;AAChC,SAAO,MAAM,eAAe,IAAI,EAAE,WAAW,MAAM,WAAW,aAAa,MAAM,YAAY,GAAG,OAAO,aAAa;AAClH,UAAM,CAAC,GAAG,IAAI,MAAM,SAAS,OAAc,kBAAkB,EAAE,OAAO;AAAA,MACpE,IAAI,MAAM;AAAA,MACV,WAAW,MAAM;AAAA,MACjB,aAAa,MAAM;AAAA,MACnB,WAAW,MAAM;AAAA,MACjB,eAAe,MAAM,iBAAiB;AAAA,MACtC,YAAY,MAAM;AAAA,MAClB,MAAM,MAAM;AAAA,MACZ,MAAM,MAAM;AAAA,MACZ,OAAO,MAAM;AAAA,MACb,KAAK,MAAM;AAAA,MACX,QAAQ;AAAA,MACR,UAAU,MAAM;AAAA,IAClB,CAAC,EAAE,UAAU;AACb,WAAO,cAAc,GAAI;AAAA,EAC3B,CAAC;AACH;AAGA,eAAsB,kBAAkB,IAAc,aAAqB,OAAqD;AAC9H,SAAO,MAAM,iBAAiB,IAAI,aAAa,OAAO,aAAa;AACjE,UAAM,CAAC,GAAG,IAAI,MAAM,SAAS,OAAO,EAAE,KAAY,kBAAkB,EACjE,MAAM;AAAA,MACL,GAAU,mBAAmB,aAAa,WAAW;AAAA,MACrD,GAAU,mBAAmB,IAAI,KAAK;AAAA,MACtC,GAAU,mBAAmB,QAAQ,MAAM;AAAA,IAC7C,CAAC,EACA,MAAM,CAAC;AACV,WAAO,MAAM,cAAc,GAAG,IAAI;AAAA,EACpC,CAAC;AACH;AAIA,eAAsB,yBAAyB,IAAc,OAOpB;AACvC,SAAO,MAAM,eAAe,IAAI,EAAE,WAAW,MAAM,WAAW,aAAa,MAAM,YAAY,GAAG,OAAO,aAAa;AAClH,UAAM,MAA8D,EAAE,aAAa,oBAAI,KAAK,EAAE;AAC9F,QAAI,MAAM,kBAAkB,OAAW,KAAI,gBAAgB,MAAM;AACjE,QAAI,MAAM,SAAS,OAAW,KAAI,OAAO,MAAM;AAC/C,QAAI,MAAM,SAAS,OAAW,KAAI,OAAO,MAAM;AAC/C,UAAM,CAAC,GAAG,IAAI,MAAM,SAAS,OAAc,kBAAkB,EAC1D,IAAI,GAAG,EACP,MAAM;AAAA,MACL,GAAU,mBAAmB,aAAa,MAAM,WAAW;AAAA,MAC3D,GAAU,mBAAmB,IAAI,MAAM,KAAK;AAAA,MAC5C,GAAU,mBAAmB,QAAQ,MAAM;AAAA,IAC7C,CAAC,EACA,UAAU;AACb,WAAO,MAAM,cAAc,GAAG,IAAI;AAAA,EACpC,CAAC;AACH;AAGA,eAAsB,gBAAgB,IAAc,OAIX;AACvC,SAAO,MAAM,eAAe,IAAI,EAAE,WAAW,MAAM,WAAW,aAAa,MAAM,YAAY,GAAG,OAAO,aAAa;AAClH,UAAM,CAAC,GAAG,IAAI,MAAM,SAAS,OAAc,kBAAkB,EAC1D,IAAI,EAAE,QAAQ,UAAU,UAAU,oBAAI,KAAK,EAAE,CAAC,EAC9C,MAAM;AAAA,MACL,GAAU,mBAAmB,aAAa,MAAM,WAAW;AAAA,MAC3D,GAAU,mBAAmB,IAAI,MAAM,KAAK;AAAA,IAC9C,CAAC,EACA,UAAU;AACb,WAAO,MAAM,cAAc,GAAG,IAAI;AAAA,EACpC,CAAC;AACH;AAGA,eAAsB,oBAAoB,IAAc,aAAqB,WAAoD;AAC/H,SAAO,MAAM,iBAAiB,IAAI,aAAa,OAAO,aAAa;AACjE,UAAM,OAAO,MAAM,SAAS,OAAO,EAAE,KAAY,kBAAkB,EAChE,MAAM;AAAA,MACL,GAAU,mBAAmB,aAAa,WAAW;AAAA,MACrD,GAAU,mBAAmB,WAAW,SAAS;AAAA,MACjD,GAAU,mBAAmB,QAAQ,MAAM;AAAA,IAC7C,CAAC,EACA,QAAQ,KAAY,mBAAmB,SAAS,CAAC;AACpD,WAAO,KAAK,IAAI,aAAa;AAAA,EAC/B,CAAC;AACH;AA2GO,IAAM,8BAAN,cAA0C,MAAM;AAAA,EACrD,YAA4B,gBAAwC,YAAoB;AACtF,UAAM,sCAAsC,cAAc,WAAW,UAAU,GAAG;AADxD;AAAwC;AAElE,SAAK,OAAO;AAAA,EACd;AAAA,EAH4B;AAAA,EAAwC;AAItE;AAQO,IAAM,4BAAN,cAAwC,MAAM;AAAA,EACnD,YACkB,gBACA,cACA,gBAChB;AACA;AAAA,MACE,iBAAiB,cAAc,eAAe,YAAY,6BAA6B,cAAc;AAAA,IAEvG;AAPgB;AACA;AACA;AAMhB,SAAK,OAAO;AAAA,EACd;AAAA,EATkB;AAAA,EACA;AAAA,EACA;AAQpB;AAEA,SAAS,YAAY,KAA8B;AACjD,SAAO;AAAA,IACL,IAAI,IAAI;AAAA,IACR,gBAAgB,IAAI;AAAA,IACpB,UAAU,IAAI;AAAA,IACd,UAAU,OAAO,IAAI,QAAQ;AAAA,IAC7B,aAAa,OAAO,IAAI,YAAY;AAAA,IACpC,eAAe,OAAO,IAAI,cAAc;AAAA,IACxC,YAAY,IAAI;AAAA,IAChB,SAAS,IAAI;AAAA,IACb,IAAI,IAAI;AAAA,IACR,OAAO,IAAI,SAAS;AAAA,IACpB,cAAc,IAAI;AAAA,IAClB,sBAAsB,IAAI,2BAA2B;AAAA;AAAA;AAAA,IAGrD,YAAY,OAAO,IAAI,WAAW;AAAA,IAClC,iBAAiB,IAAI;AAAA,IACrB,aAAa,IAAI;AAAA,IACjB,WAAW,IAAI,sBAAsB,OAAO,IAAI,aAAa,IAAI,KAAK,IAAI,UAAU;AAAA,EACtF;AACF;AAIA,eAAe,uBACb,IACA,SACA,YACA,aACmB;AACnB,QAAM,SAAS,MAAM,GAAG,QAA2D;AAAA;AAAA;AAAA;AAAA,kDAInC,OAAO;AAAA,GACtD;AACD,QAAM,IAAI,OAAO,CAAC;AAClB,QAAM,UAAU,MAAM,GAAG,QAAkB;AAAA;AAAA,yBAEpB,EAAE,KAAK;AAAA,yBACP,EAAE,KAAK;AAAA,yBACP,EAAE,OAAO;AAAA,kCACA,OAAO,UAAU,CAAC;AAAA,QAC5C,cAAc,iBAAiB,WAAW,MAAM,KAAK;AAAA;AAAA,iBAE5C,OAAO;AAAA;AAAA,GAErB;AACD,SAAO,QAAQ,CAAC;AAClB;AAIA,eAAe,kBACb,IAAc,SAAiB,WAAmB,aAClD,MAAuB,UAAkB,WAC1B;AACf,QAAM,GAAG,QAAQ;AAAA;AAAA;AAAA,cAGL,SAAS,KAAK,WAAW,KAAK,OAAO,KAAK,IAAI,KAAK,QAAQ,KAAK,SAAS;AAAA;AAAA;AAAA,GAGpF;AACH;AAKA,eAAsB,aAAa,IAAc,OAAuD;AACtG,QAAM,EAAE,WAAW,aAAa,gBAAgB,MAAM,UAAU,QAAQ,IAAI;AAC5E,QAAM,KAAK,MAAM,MAAM;AACvB,QAAM,YAAY,MAAM,aAAa;AACrC,SAAO,MAAM;AAAA,IAAe;AAAA,IAAI,EAAE,WAAW,YAAY;AAAA,IAAG,OAAO,aACjE,MAAM,SAAS,YAAY,OAAO,UAAU;AAC1C,YAAM,KAAK;AACX,YAAM,QAAQ,MAAM,SAAS;AAM7B,YAAM,GAAG,QAAQ;AAAA;AAAA;AAAA;AAAA,aAIV,SAAS,KAAK,WAAW,KAAK,cAAc,aAAa,OAAO,KAAK,EAAE,KAAK,KAAK;AAAA,sBACxE,OAAO,MAAM,UAAU,CAAC;AAAA;AAAA,OAEvC;AAKD,YAAM,OAAO,MAAM,GAAG,QAAkB;AAAA;AAAA,+BAEf,WAAW,2BAA2B,cAAc;AAAA;AAAA,OAE5E;AACD,YAAM,MAAM,KAAK,CAAC;AAClB,UAAI,CAAC,IAAK,OAAM,IAAI,MAAM,mCAAmC,cAAc,EAAE;AAE7E,UAAI,WAAW,IAAI;AAenB,UAAI,aAAa,UAAU,UAAU,QAAQ,IAAI,UAAU,QAAQ,IAAI,UAAU,OAAO;AACtF,cAAM,SAAS,MAAM,GAAG,QAAuB;AAAA;AAAA,6BAE1B,IAAI,EAAE,oBAAoB,IAAI,oBAAoB,QAAQ;AAAA,SAC9E;AACD,cAAM,eAAe,OAAO,OAAO,CAAC,GAAG,KAAK,CAAC;AAC7C,YAAI,eAAe,GAAG;AACpB,gBAAM,IAAI,0BAA0B,gBAAgB,IAAI,OAAO,KAAK;AAAA,QACtE;AAOA,cAAM,GAAG,QAAQ;AAAA;AAAA,yCAEgB,KAAK;AAAA;AAAA;AAAA,uBAGvB,IAAI,EAAE;AAAA,SACpB;AACD,mBAAW;AAAA,MACb;AAGA,UAAI,aAAa,YAAY;AAC3B,cAAM,kBAAkB,IAAI,IAAI,IAAI,WAAW,aAAa,MAAM,UAAU,SAAS;AACrF,cAAMC,WAAU,MAAM,uBAAuB,IAAI,IAAI,IAAI,MAAM,YAAY,MAAM;AACjF,eAAO,EAAE,MAAM,WAAoB,OAAO,YAAYA,QAAO,EAAE;AAAA,MACjE;AAMA,UAAI,aAAa,QAAQ;AACvB,cAAM,UAAU,MAAM,GAAG,QAAwB;AAAA;AAAA;AAAA,cAG3C,UAAU,OAAO,cAAc,KAAK,MAAM,KAAK;AAAA;AAAA,uBAEtC,IAAI,EAAE;AAAA;AAAA,SAEpB;AACD,cAAM,kBAAkB,IAAI,IAAI,IAAI,WAAW,aAAa,MAAM,UAAU,SAAS;AACrF,cAAMA,WAAU,MAAM,uBAAuB,IAAI,IAAI,IAAI,MAAM,YAAY,IAAI;AAG/E,cAAM,OAAO,QAAQ,WAAW,IAAI,aAAsB;AAC1D,eAAO,EAAE,MAAM,OAAO,YAAYA,QAAO,EAAE;AAAA,MAC7C;AAMA,UAAI,aAAa,UAAU,SAAS,UAAU,MAAM,kBAAkB,UAC/D,OAAO,IAAI,WAAW,MAAM,MAAM,eAAe;AACtD,eAAO,EAAE,MAAM,UAAmB,OAAO,YAAY,GAAG,EAAE;AAAA,MAC5D;AAIA,YAAM,kBAAkB,IAAI,IAAI,IAAI,WAAW,aAAa,MAAM,UAAU,SAAS;AACrF,YAAM,UAAU,MAAM,uBAAuB,IAAI,IAAI,IAAI,MAAM,YAAY,IAAI;AAC/E,aAAO,EAAE,MAAM,YAAqB,OAAO,YAAY,OAAO,EAAE;AAAA,IAClE,CAAC;AAAA,EACH;AACF;AAIA,eAAsB,oBAAoB,IAAc,OAQS;AAC/D,SAAO,MAAM;AAAA,IAAe;AAAA,IAAI,EAAE,WAAW,MAAM,WAAW,aAAa,MAAM,YAAY;AAAA,IAC3F,OAAO,aAAa;AAKlB,YAAM,kBAAkB,MAAM,eAAe,OAAO,OAAO,KAAK,UAAU,MAAM,WAAW;AAC3F,YAAM,OAAO,MAAM,SAAS,QAAkB;AAAA;AAAA;AAAA,gCAGpB,MAAM,UAAU;AAAA,gCAChB,MAAM,gBAAgB,IAAI;AAAA;AAAA;AAAA;AAAA;AAAA,gCAK1B,MAAM,mBAAmB,IAAI;AAAA,gCAC7B,eAAe;AAAA;AAAA,yCAEN,OAAO,MAAM,UAAU,CAAC;AAAA;AAAA,+BAElC,MAAM,WAAW,2BAA2B,MAAM,cAAc;AAAA,uDACxC,MAAM,aAAa;AAAA;AAAA,OAEnE;AAKD,UAAI,KAAK,WAAW,EAAG,QAAO,EAAE,WAAW,OAAO,OAAO,KAAK;AAC9D,aAAO,EAAE,WAAW,MAAM,OAAO,YAAY,KAAK,CAAC,CAAE,EAAE;AAAA,IACzD;AAAA,EAAC;AACL;AAiBA,eAAsB,kBAAkB,IAAc,OAEpC;AAChB,QAAM;AAAA,IAAe;AAAA,IAAI,EAAE,WAAW,MAAM,WAAW,aAAa,MAAM,YAAY;AAAA,IACpF,OAAO,aAAa;AAClB,YAAM,SAAS,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,+BAiBE,MAAM,WAAW,2BAA2B,MAAM,cAAc;AAAA,uDACxC,MAAM,aAAa;AAAA,OACnE;AAAA,IACH;AAAA,EAAC;AACL;AAIA,eAAsB,mBAAmB,IAAc,OAGkB;AACvE,SAAO,MAAM;AAAA,IAAe;AAAA,IAAI,EAAE,WAAW,MAAM,WAAW,aAAa,MAAM,YAAY;AAAA,IAC3F,OAAO,aAAa,MAAM,SAAS,YAAY,OAAO,UAAU;AAC9D,YAAM,KAAK;AACX,YAAM,OAAO,MAAM,GAAG,QAAkB;AAAA;AAAA,+BAEf,MAAM,WAAW,2BAA2B,MAAM,cAAc;AAAA;AAAA,OAExF;AACD,YAAM,MAAM,KAAK,CAAC;AAClB,UAAI,CAAC,IAAK,QAAO;AAGjB,YAAM,GAAG,QAAQ;AAAA;AAAA,2BAEI,IAAI,EAAE,eAAe,MAAM,IAAI,oBAAoB,MAAM,QAAQ;AAAA,OACrF;AAED,YAAM,SAAS,MAAM,GAAG,QAA2D;AAAA;AAAA;AAAA;AAAA,sDAInC,IAAI,EAAE;AAAA,OACrD;AACD,YAAM,IAAI,OAAO,CAAC;AAKlB,YAAM,gBAAgB,IAAI,aAAa,UAAU,EAAE,UAAU,KAAK,EAAE,UAAU;AAC9E,YAAM,UAAU,MAAM,GAAG,QAAkB;AAAA;AAAA,uBAE1B,EAAE,KAAK,oBAAoB,EAAE,KAAK,sBAAsB,EAAE,OAAO;AAAA,YAC5E,gBACE,mDAAmD,OAAO,MAAM,WAAW,CAAC,oCAC5E,KAAK;AAAA;AAAA,qBAEE,IAAI,EAAE;AAAA;AAAA,OAEpB;AACD,aAAO,EAAE,UAAU,QAAQ,CAAC,EAAG,UAAU,UAAU,OAAO,EAAE,KAAK,EAAE;AAAA,IACrE,CAAC;AAAA,EAAC;AACN;AAMA,eAAsB,qBAAqB,IAAc,OAGpC;AACnB,SAAO,MAAM;AAAA,IAAe;AAAA,IAAI,EAAE,WAAW,MAAM,WAAW,aAAa,MAAM,YAAY;AAAA,IAC3F,OAAO,aAAa,MAAM,SAAS,YAAY,OAAO,UAAU;AAC9D,YAAM,KAAK;AACX,YAAM,UAAU,MAAM,GAAG,QAAwB;AAAA;AAAA;AAAA,iDAGN,MAAM,WAAW,2BAA2B,MAAM,cAAc;AAAA,uBAC1F,MAAM,IAAI,oBAAoB,MAAM,QAAQ;AAAA;AAAA,OAE5D;AACD,UAAI,QAAQ,WAAW,EAAG,QAAO;AAIjC,YAAM,YAAY,MAAM,GAAG,QAAwB;AAAA;AAAA,kCAEvB,OAAO,MAAM,UAAU,CAAC;AAAA;AAAA,+BAE3B,MAAM,WAAW,2BAA2B,MAAM,cAAc;AAAA,8BACjE,MAAM,aAAa;AAAA;AAAA;AAAA,OAG1C;AACD,aAAO,UAAU,SAAS;AAAA,IAC5B,CAAC;AAAA,EAAC;AACN;AAiBA,eAAsB,sBAAsB,IAAc,OAI6B;AACrF,SAAO,MAAM,iBAAiB,IAAI,MAAM,aAAa,OAAO,aAC1D,MAAM,SAAS,YAAY,OAAO,UAAU;AAC1C,UAAM,KAAK;AAEX,UAAM,SAAS,MAAM,GAAG,QAA8B;AAAA;AAAA,+BAE7B,MAAM,WAAW;AAAA,6CACH,OAAO,MAAM,iBAAiB,CAAC;AAAA;AAAA,OAErE;AAKD,UAAM,GAAG,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,0CAQmB,OAAO,MAAM,WAAW,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,2DAQR,MAAM,WAAW;AAAA;AAAA,iDAE3B,MAAM,WAAW;AAAA,OAC3D;AAID,UAAM,eAAe,MAAM,GAAG,QAAwB;AAAA;AAAA;AAAA;AAAA;AAAA,+BAK7B,MAAM,WAAW;AAAA;AAAA;AAAA,OAGzC;AAKD,UAAM,YAAY,MAAM,QAAgG,IAAI;AAAA;AAAA,+BAEnG,MAAM,WAAW;AAAA;AAAA,OAEzC;AAED,WAAO;AAAA,MACL,eAAe,OAAO;AAAA,MACtB,cAAc,aAAa;AAAA,MAC3B,SAAS,UAAU,IAAI,CAAC,OAAO;AAAA,QAC7B,aAAa,MAAM;AAAA,QACnB,gBAAgB,EAAE;AAAA,QAClB,YAAY,EAAE;AAAA,QACd,YAAY,OAAO,EAAE,WAAW;AAAA,MAClC,EAAE;AAAA,IACJ;AAAA,EACF,CAAC,CAAC;AACN;AAQA,eAAsB,4BAA4B,IAAc,OAGnC;AAC3B,QAAM,OAAO,MAAM,QAAsH,IAAI;AAAA;AAAA,gDAE/F,MAAM,iBAAiB,KAAK,MAAM,WAAW;AAAA,GAC1F;AACD,SAAO,KAAK,IAAI,CAAC,OAAO;AAAA,IACtB,aAAa,EAAE;AAAA,IACf,gBAAgB,EAAE;AAAA,IAClB,YAAY,EAAE;AAAA,IACd,YAAY,OAAO,EAAE,WAAW;AAAA,EAClC,EAAE;AACJ;AAeA,eAAsB,wBAAwB,IAA6C;AACzF,QAAM,OAAO,MAAM,QAA+H,IAAI;AAAA;AAAA;AAAA,GAGrJ;AACD,SAAO,KAAK,IAAI,CAAC,OAAO;AAAA,IACtB,WAAW,EAAE;AAAA,IACb,aAAa,EAAE;AAAA,IACf,gBAAgB,EAAE;AAAA,IAClB,YAAY,OAAO,EAAE,WAAW;AAAA,IAChC,SAAS,EAAE;AAAA,EACb,EAAE;AACJ;AAKA,eAAsB,mBAAmB,IAAc,OAErB;AAChC,SAAO,MAAM;AAAA,IAAe;AAAA,IAAI,EAAE,WAAW,MAAM,WAAW,aAAa,MAAM,YAAY;AAAA,IAC3F,OAAO,aAAa;AAClB,YAAM,OAAO,MAAM,SAAS,QAAwB;AAAA;AAAA;AAAA,kCAGxB,OAAO,MAAM,UAAU,CAAC;AAAA;AAAA,+BAE3B,MAAM,WAAW,2BAA2B,MAAM,cAAc;AAAA;AAAA;AAAA,OAGxF;AACD,aAAO,EAAE,SAAS,KAAK,SAAS,EAAE;AAAA,IACpC;AAAA,EAAC;AACL;AAOA,eAAsB,iBAAiB,IAAc,OAElB;AACjC,SAAO,MAAM;AAAA,IAAe;AAAA,IAAI,EAAE,WAAW,MAAM,WAAW,aAAa,MAAM,YAAY;AAAA,IAC3F,OAAO,aAAa;AAelB,YAAM,OAAO,MAAM,SAAS,QAAwB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,+BAiB3B,MAAM,WAAW,2BAA2B,MAAM,cAAc;AAAA,yEACtB,MAAM,aAAa;AAAA;AAAA,OAErF;AACD,aAAO,EAAE,UAAU,KAAK,SAAS,EAAE;AAAA,IACrC;AAAA,EAAC;AACL;AA4BA,eAAsB,qBAAqB,IAAc,OAMI;AAK3D,SAAO,MAAM;AAAA,IAAe;AAAA,IAAI,EAAE,WAAW,MAAM,WAAW,aAAa,MAAM,YAAY;AAAA,IAC3F,OAAO,aAAa;AAIlB,YAAM,QAAQ,MAAM,SAAS,QAA0C;AAAA;AAAA;AAAA,+BAG9C,MAAM,WAAW,2BAA2B,MAAM,cAAc;AAAA,yEACtB,MAAM,aAAa;AAAA;AAAA,OAErF;AACD,UAAI,MAAM,WAAW,GAAG;AACtB,eAAO,EAAE,OAAO,OAAO,cAAc,KAAK;AAAA,MAC5C;AACA,YAAM,eAAe,MAAM,CAAC,EAAG,iBAAiB;AAGhD,UAAI,MAAM,qBAAqB,MAAM;AACnC,eAAO,EAAE,OAAO,MAAM,cAAc,KAAK;AAAA,MAC3C;AAUA,YAAM,SAAS,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mEAUsC,MAAM,gBAAgB;AAAA;AAAA;AAAA;AAAA,+BAI1D,MAAM,WAAW,2BAA2B,MAAM,cAAc;AAAA,yEACtB,MAAM,aAAa;AAAA,OACrF;AACD,aAAO,EAAE,OAAO,MAAM,aAAa;AAAA,IACrC;AAAA,EAAC;AACL;AAGA,eAAsB,UAAU,IAAc,aAAqB,gBAAuD;AACxH,SAAO,MAAM,iBAAiB,IAAI,aAAa,OAAO,aAAa;AACjE,UAAM,OAAO,MAAM,SAAS,QAAkB;AAAA;AAAA,6BAErB,WAAW,2BAA2B,cAAc;AAAA;AAAA,KAE5E;AACD,WAAO,KAAK,CAAC,IAAI,YAAY,KAAK,CAAC,CAAC,IAAI;AAAA,EAC1C,CAAC;AACH;AAUA,eAAsB,wBAAwB,IAAc,OAM1B;AAChC,SAAO,MAAM;AAAA,IAAe;AAAA,IAAI,EAAE,WAAW,MAAM,WAAW,aAAa,MAAM,YAAY;AAAA,IAC3F,OAAO,aAAa;AAClB,YAAM,OAAO,MAAM,SAAS,QAAkB;AAAA;AAAA,6BAEvB,MAAM,gBAAgB,IAAI;AAAA;AAAA,+BAExB,MAAM,WAAW,2BAA2B,MAAM,cAAc;AAAA,8BACjE,MAAM,aAAa;AAAA;AAAA;AAAA,OAG1C;AACD,aAAO,KAAK,CAAC,IAAI,YAAY,KAAK,CAAC,CAAC,IAAI;AAAA,IAC1C;AAAA,EAAC;AACL;AAUA,eAAsB,gCAAgC,IAAc,OAMlC;AAChC,SAAO,MAAM;AAAA,IAAe;AAAA,IAAI,EAAE,WAAW,MAAM,WAAW,aAAa,MAAM,YAAY;AAAA,IAC3F,OAAO,aAAa;AAClB,YAAM,OAAO,MAAM,SAAS,QAAkB;AAAA;AAAA,sCAEd,MAAM,wBAAwB,IAAI;AAAA;AAAA,+BAEzC,MAAM,WAAW,2BAA2B,MAAM,cAAc;AAAA,8BACjE,MAAM,aAAa;AAAA;AAAA;AAAA,OAG1C;AACD,aAAO,KAAK,CAAC,IAAI,YAAY,KAAK,CAAC,CAAC,IAAI;AAAA,IAC1C;AAAA,EAAC;AACL;AA+BA,SAAS,cAAc,KAA+D;AACpF,SAAO;AAAA,IACL,IAAI,IAAI;AAAA,IACR,WAAW,IAAI;AAAA,IACf,aAAa,IAAI;AAAA,IACjB,QAAQ,IAAI;AAAA,IACZ,UAAU,IAAI;AAAA,IACd,YAAY,IAAI;AAAA,IAChB,oBAAoB,IAAI;AAAA,IACxB,QAAQ,IAAI;AAAA,IACZ,IAAI,IAAI;AAAA,IACR,MAAM,IAAI;AAAA,IACV,YAAY,IAAI,aAAa,IAAI,WAAW,YAAY,IAAI;AAAA,IAC5D,WAAW,IAAI,UAAU,YAAY;AAAA,IACrC,WAAW,IAAI,YAAY,IAAI,UAAU,YAAY,IAAI;AAAA,IACzD,WAAW,IAAI,UAAU,YAAY;AAAA,EACvC;AACF;AAaA,SAAS,WAAW,KAA0D;AAC5E,SAAO;AAAA,IACL,IAAI,IAAI;AAAA,IACR,WAAW,IAAI;AAAA,IACf,aAAa,IAAI;AAAA,IACjB,MAAM,IAAI;AAAA,IACV,MAAM,IAAI;AAAA,IACV,cAAc,IAAI,gBAAgB;AAAA,IAClC,WAAW,IAAI,UAAU,YAAY;AAAA,IACrC,WAAW,IAAI,UAAU,YAAY;AAAA,EACvC;AACF;AASA,eAAsB,iBAAiB,IAAc,OASvB;AAC5B,SAAO,MAAM,eAAe,IAAI,EAAE,WAAW,MAAM,WAAW,aAAa,MAAM,YAAY,GAAG,OAAO,aAAa;AAClH,UAAM,CAAC,GAAG,IAAI,MAAM,SAAS,OAAc,WAAW,EAAE,OAAO;AAAA,MAC7D,WAAW,MAAM;AAAA,MACjB,aAAa,MAAM;AAAA,MACnB,QAAQ,MAAM;AAAA,MACd,UAAU,MAAM,YAAY;AAAA,MAC5B,YAAY,MAAM,cAAc;AAAA,MAChC,oBAAoB,MAAM,sBAAsB;AAAA,MAChD,IAAI,MAAM,MAAM;AAAA,MAChB,MAAM,MAAM,QAAQ;AAAA,MACpB,QAAQ;AAAA,IACV,CAAC,EAAE,mBAAmB;AAAA,MACpB,QAAQ,CAAQ,YAAY,aAAoB,YAAY,MAAM;AAAA,MAClE,KAAK;AAAA,QACH,UAAU,MAAM,YAAY;AAAA,QAC5B,YAAY,MAAM,cAAc;AAAA,QAChC,oBAAoB,MAAM,sBAAsB;AAAA,QAChD,IAAI,MAAM,MAAM;AAAA,QAChB,MAAM,MAAM,QAAQ;AAAA;AAAA,QAEpB,QAAQ;AAAA,QACR,WAAW;AAAA,QACX,WAAW,oBAAI,KAAK;AAAA,MACtB;AAAA,IACF,CAAC,EAAE,UAAU;AACb,QAAI,CAAC,KAAK;AACR,YAAM,IAAI,MAAM,6BAA6B;AAAA,IAC/C;AACA,WAAO,cAAc,GAAG;AAAA,EAC1B,CAAC;AACH;AAEA,eAAsB,cAAc,IAAc,aAAqB,cAAwD;AAC7H,SAAO,MAAM,iBAAiB,IAAI,aAAa,OAAO,aAAa;AACjE,UAAM,CAAC,GAAG,IAAI,MAAM,SAAS,OAAO,EAAE,KAAY,WAAW,EAC1D,MAAM,IAAI,GAAU,YAAY,aAAa,WAAW,GAAG,GAAU,YAAY,IAAI,YAAY,CAAC,CAAC,EACnG,MAAM,CAAC;AACV,WAAO,MAAM,cAAc,GAAG,IAAI;AAAA,EACpC,CAAC;AACH;AAIA,eAAsB,gBAAgB,IAAc,aAAqB,UAAyC,CAAC,GAAgC;AACjJ,SAAO,MAAM,iBAAiB,IAAI,aAAa,OAAO,aAAa;AACjE,UAAM,QAAQ,QAAQ,SAClB,IAAI,GAAU,YAAY,aAAa,WAAW,GAAG,GAAU,YAAY,QAAQ,QAAQ,MAAM,CAAC,IAClG,GAAU,YAAY,aAAa,WAAW;AAClD,UAAM,OAAO,MAAM,SAAS,OAAO,EAAE,KAAY,WAAW,EACzD,MAAM,KAAK,EACX,QAAQ,KAAY,YAAY,SAAS,CAAC;AAC7C,WAAO,KAAK,IAAI,aAAa;AAAA,EAC/B,CAAC;AACH;AAIA,eAAsB,iBAAiB,IAAc,OAEnB;AAChC,SAAO,MAAM,eAAe,IAAI,EAAE,WAAW,MAAM,WAAW,aAAa,MAAM,YAAY,GAAG,OAAO,aAAa;AAClH,UAAM,OAAO,MAAM,SAAS,OAAc,WAAW,EAClD,IAAI,EAAE,QAAQ,WAAW,WAAW,oBAAI,KAAK,GAAG,WAAW,oBAAI,KAAK,EAAE,CAAC,EACvE,MAAM;AAAA,MACL,GAAU,YAAY,aAAa,MAAM,WAAW;AAAA,MACpD,GAAU,YAAY,IAAI,MAAM,YAAY;AAAA,MAC5C,GAAU,YAAY,QAAQ,QAAQ;AAAA,IACxC,CAAC,EACA,UAAU,EAAE,IAAW,YAAY,GAAG,CAAC;AAC1C,WAAO,EAAE,SAAS,KAAK,SAAS,EAAE;AAAA,EACpC,CAAC;AACH;AAIA,eAAsB,wBAAwB,IAAc,OAE1C;AAChB,QAAM,eAAe,IAAI,EAAE,WAAW,MAAM,WAAW,aAAa,MAAM,YAAY,GAAG,OAAO,aAAa;AAC3G,UAAM,SAAS,OAAc,WAAW,EACrC,IAAI,EAAE,YAAY,oBAAI,KAAK,GAAG,WAAW,oBAAI,KAAK,EAAE,CAAC,EACrD,MAAM;AAAA,MACL,GAAU,YAAY,aAAa,MAAM,WAAW;AAAA,MACpD,GAAU,YAAY,IAAI,MAAM,YAAY;AAAA,IAC9C,CAAC;AAAA,EACL,CAAC;AACH;AAYA,eAAsB,wBAAwB,IAAc,OAE1B;AAChC,SAAO,MAAM,eAAe,IAAI,EAAE,WAAW,MAAM,WAAW,aAAa,MAAM,YAAY,GAAG,OAAO,aAAa;AAClH,UAAM,OAAO,MAAM,SAAS,OAAc,WAAW,EAClD,IAAI,EAAE,YAAY,MAAM,YAAY,WAAW,oBAAI,KAAK,EAAE,CAAC,EAC3D,MAAM;AAAA,MACL,GAAU,YAAY,aAAa,MAAM,WAAW;AAAA,MACpD,GAAU,YAAY,IAAI,MAAM,YAAY;AAAA;AAAA;AAAA,MAG5C,GAAU,YAAY,YAAY,MAAM,UAAU;AAAA,IACpD,CAAC,EACA,UAAU,EAAE,IAAW,YAAY,GAAG,CAAC;AAC1C,WAAO,EAAE,SAAS,KAAK,SAAS,EAAE;AAAA,EACpC,CAAC;AACH;AAqCA,SAAS,2BAA2B,KAAyF;AAC3H,SAAO;AAAA,IACL,IAAI,IAAI;AAAA,IACR,YAAY,IAAI;AAAA,IAChB,UAAU,IAAI;AAAA,IACd,WAAW,IAAI;AAAA,IACf,aAAa,IAAI;AAAA,IACjB,QAAQ,IAAI;AAAA,IACZ,IAAI,IAAI;AAAA,IACR,MAAM,IAAI;AAAA,IACV,aAAa,IAAI,eAAe;AAAA,IAChC,mBAAmB,IAAI;AAAA,IACvB,iBAAiB,IAAI;AAAA,IACrB,uBAAuB,IAAI;AAAA,IAC3B,QAAQ,IAAI;AAAA,IACZ,qBAAqB,IAAI,uBAAuB;AAAA,IAChD,wBAAwB,IAAI,0BAA0B;AAAA,IACtD,oBAAoB,IAAI;AAAA,IACxB,YAAY,IAAI,aAAa,IAAI,WAAW,YAAY,IAAI;AAAA,IAC5D,cAAc,IAAI,gBAAgB;AAAA,IAClC,WAAW,IAAI,aAAa;AAAA,IAC5B,WAAW,IAAI,UAAU,YAAY;AAAA,IACrC,WAAW,IAAI,UAAU,YAAY;AAAA,IACrC,WAAW,IAAI,UAAU,YAAY;AAAA,EACvC;AACF;AAKA,eAAsB,8BAA8B,IAAc,OAavB;AACzC,SAAO,MAAM,eAAe,IAAI,EAAE,WAAW,MAAM,WAAW,aAAa,MAAM,YAAY,GAAG,OAAO,aAAa;AAClH,UAAM,CAAC,GAAG,IAAI,MAAM,SAAS,OAAc,wBAAwB,EAAE,OAAO;AAAA,MAC1E,WAAW,MAAM;AAAA,MACjB,aAAa,MAAM;AAAA,MACnB,YAAY,MAAM;AAAA,MAClB,UAAU,MAAM;AAAA,MAChB,QAAQ,MAAM;AAAA,MACd,IAAI,MAAM,MAAM;AAAA,MAChB,MAAM,MAAM,QAAQ;AAAA,MACpB,aAAa,MAAM,eAAe;AAAA,MAClC,mBAAmB,MAAM,qBAAqB;AAAA,MAC9C,iBAAiB,MAAM,mBAAmB;AAAA,MAC1C,uBAAuB,MAAM,yBAAyB;AAAA,MACtD,QAAQ;AAAA,MACR,WAAW,MAAM;AAAA,IACnB,CAAC,EAAE,UAAU;AACb,QAAI,CAAC,KAAK;AACR,YAAM,IAAI,MAAM,4CAA4C;AAAA,IAC9D;AACA,WAAO,2BAA2B,GAAG;AAAA,EACvC,CAAC;AACH;AAOA,eAAsB,uCAAuC,IAAc,YAAmE;AAC5I,QAAM,WAAW,MAAM,GAAG,QAAsD;AAAA,8FACY,UAAU;AAAA,GACrG;AACD,QAAM,MAAM,SAAS,CAAC;AACtB,MAAI,CAAC,KAAK;AACR,WAAO;AAAA,EACT;AACA,SAAO,MAAM,eAAe,IAAI,EAAE,WAAW,IAAI,YAAY,aAAa,IAAI,aAAa,GAAG,OAAO,aAAa;AAChH,UAAM,CAAC,GAAG,IAAI,MAAM,SAAS,OAAO,EAAE,KAAY,wBAAwB,EACvE,MAAM,GAAU,yBAAyB,YAAY,UAAU,CAAC,EAChE,MAAM,CAAC;AACV,WAAO,MAAM,2BAA2B,GAAG,IAAI;AAAA,EACjD,CAAC;AACH;AAKA,eAAsB,4CAA4C,IAAc,aAAqB,UAAiE;AACpK,SAAO,MAAM,iBAAiB,IAAI,aAAa,OAAO,aAAa;AACjE,UAAM,CAAC,GAAG,IAAI,MAAM,SAAS,OAAO,EAAE,KAAY,wBAAwB,EACvE,MAAM;AAAA,MACL,GAAU,yBAAyB,aAAa,WAAW;AAAA,MAC3D,GAAU,yBAAyB,UAAU,QAAQ;AAAA,MACrD,GAAU,yBAAyB,QAAQ,SAAS;AAAA,IACtD,CAAC,EACA,MAAM,CAAC;AACV,WAAO,MAAM,2BAA2B,GAAG,IAAI;AAAA,EACjD,CAAC;AACH;AAUA,eAAsB,kDAAkD,IAAc,UAAiE;AACrJ,QAAM,WAAW,MAAM,GAAG,QAAsD;AAAA,2GACyB,QAAQ;AAAA,GAChH;AACD,QAAM,MAAM,SAAS,CAAC;AACtB,MAAI,CAAC,KAAK;AACR,WAAO;AAAA,EACT;AACA,SAAO,MAAM,eAAe,IAAI,EAAE,WAAW,IAAI,YAAY,aAAa,IAAI,aAAa,GAAG,OAAO,aAAa;AAChH,UAAM,CAAC,GAAG,IAAI,MAAM,SAAS,OAAO,EAAE,KAAY,wBAAwB,EACvE,MAAM;AAAA,MACL,GAAU,yBAAyB,UAAU,QAAQ;AAAA,MACrD,GAAU,yBAAyB,QAAQ,SAAS;AAAA,IACtD,CAAC,EACA,MAAM,CAAC;AACV,WAAO,MAAM,2BAA2B,GAAG,IAAI;AAAA,EACjD,CAAC;AACH;AAaA,eAAe,0BAA0B,UAAoB,OAUS;AAKpE,QAAM,CAAC,aAAa,IAAI,MAAM,SAAS,OAAc,WAAW,EAAE,OAAO;AAAA,IACvE,WAAW,MAAM;AAAA,IACjB,aAAa,MAAM;AAAA,IACnB,QAAQ,MAAM;AAAA,IACd,UAAU;AAAA,IACV,YAAY,MAAM;AAAA,IAClB,oBAAoB,MAAM;AAAA,IAC1B,IAAI,MAAM;AAAA,IACV,MAAM,MAAM;AAAA,IACZ,QAAQ;AAAA,EACV,CAAC,EAAE,mBAAmB;AAAA,IACpB,QAAQ,CAAQ,YAAY,aAAoB,YAAY,MAAM;AAAA,IAClE,KAAK;AAAA,MACH,UAAU;AAAA,MACV,YAAY,MAAM;AAAA,MAClB,oBAAoB,MAAM;AAAA,MAC1B,IAAI,MAAM;AAAA,MACV,MAAM,MAAM;AAAA,MACZ,QAAQ;AAAA,MACR,WAAW;AAAA,MACX,WAAW,MAAM;AAAA,IACnB;AAAA,EACF,CAAC,EAAE,UAAU;AACb,MAAI,CAAC,eAAe;AAClB,UAAM,IAAI,MAAM,6CAA6C;AAAA,EAC/D;AACA,QAAM,aAAa,cAAc,aAAa;AAI9C,QAAM,CAAC,eAAe,IAAI,MAAM,SAAS,OAAO,EAAE,KAAY,SAAS,EACpE,MAAM;AAAA,IACL,GAAU,UAAU,aAAa,MAAM,WAAW;AAAA,IAClD,GAAU,UAAU,cAAc,WAAW,EAAE;AAAA,EACjD,CAAC,EACA,MAAM,CAAC;AACV,MAAI;AACJ,MAAI,iBAAiB;AACnB,cAAU,WAAW,eAAe;AAAA,EACtC,OAAO;AACL,UAAM,CAAC,UAAU,IAAI,MAAM,SAAS,OAAc,SAAS,EAAE,OAAO;AAAA,MAClE,WAAW,MAAM;AAAA,MACjB,aAAa,MAAM;AAAA,MACnB,MAAM;AAAA,MACN,MAAM,MAAM;AAAA,MACZ,cAAc,WAAW;AAAA,IAC3B,CAAC,EAAE,UAAU;AACb,QAAI,CAAC,YAAY;AACf,YAAM,IAAI,MAAM,0CAA0C;AAAA,IAC5D;AACA,cAAU,WAAW,UAAU;AAAA,EACjC;AACA,SAAO,EAAE,YAAY,QAAQ;AAC/B;AAMA,eAAsB,0BAA0B,IAAc,OAUQ;AACpE,QAAM,MAAM,MAAM,OAAO,oBAAI,KAAK;AAClC,SAAO,MAAM,eAAe,IAAI,EAAE,WAAW,MAAM,WAAW,aAAa,MAAM,YAAY,GAAG,OAAO,aAAa;AAClH,WAAO,MAAM,0BAA0B,UAAU;AAAA,MAC/C,WAAW,MAAM;AAAA,MACjB,aAAa,MAAM;AAAA,MACnB,QAAQ,MAAM;AAAA,MACd,YAAY,MAAM;AAAA,MAClB,oBAAoB,MAAM;AAAA,MAC1B,IAAI,MAAM;AAAA,MACV,MAAM,MAAM;AAAA,MACZ,aAAa,MAAM;AAAA,MACnB;AAAA,IACF,CAAC;AAAA,EACH,CAAC;AACH;AAgBA,eAAsB,+BAA+B,IAAc,OAUoC;AACrG,QAAM,MAAM,MAAM,OAAO,oBAAI,KAAK;AAClC,SAAO,MAAM,eAAe,IAAI,EAAE,WAAW,MAAM,WAAW,aAAa,MAAM,YAAY,GAAG,OAAO,aAAa;AAElH,UAAM,CAAC,OAAO,IAAI,MAAM,SAAS,OAAO,EAAE,KAAY,wBAAwB,EAC3E,MAAM;AAAA,MACL,GAAU,yBAAyB,aAAa,MAAM,WAAW;AAAA,MACjE,GAAU,yBAAyB,IAAI,MAAM,SAAS;AAAA,IACxD,CAAC,EACA,IAAI,QAAQ,EACZ,MAAM,CAAC;AACV,QAAI,CAAC,SAAS;AACZ,aAAO,EAAE,UAAU,OAAO,YAAY,MAAM,SAAS,KAAK;AAAA,IAC5D;AAGA,UAAM,UAAU,QAAQ,UAAU,QAAQ,KAAK,IAAI,QAAQ;AAC3D,QAAI,QAAQ,WAAW,YAAY,QAAQ,WAAW,YAAY;AAChE,aAAO,EAAE,UAAU,OAAO,YAAY,MAAM,SAAS,KAAK;AAAA,IAC5D;AACA,QAAI,QAAQ,WAAW,aAAa,SAAS;AAC3C,aAAO,EAAE,UAAU,OAAO,YAAY,MAAM,SAAS,KAAK;AAAA,IAC5D;AAQA,UAAM,EAAE,YAAY,QAAQ,IAAI,MAAM,0BAA0B,UAAU;AAAA,MACxE,WAAW,MAAM;AAAA,MACjB,aAAa,MAAM;AAAA,MACnB,QAAQ,QAAQ;AAAA,MAChB,YAAY,QAAQ;AAAA,MACpB,oBAAoB,MAAM;AAAA,MAC1B,IAAI,QAAQ;AAAA,MACZ,MAAM,QAAQ;AAAA,MACd,aAAa,MAAM;AAAA,MACnB;AAAA,IACF,CAAC;AAGD,UAAM,SAAS,OAAc,wBAAwB,EAClD,IAAI;AAAA,MACH,QAAQ;AAAA,MACR,oBAAoB,MAAM;AAAA,MAC1B,qBAAqB,MAAM;AAAA,MAC3B,wBAAwB,MAAM,0BAA0B;AAAA,MACxD,YAAY;AAAA,MACZ,cAAc,WAAW;AAAA,MACzB,WAAW,QAAQ;AAAA,MACnB,WAAW;AAAA,IACb,CAAC,EACA,MAAM,GAAU,yBAAyB,IAAI,QAAQ,EAAE,CAAC;AAE3D,WAAO,EAAE,UAAU,MAAM,YAAY,QAAQ;AAAA,EAC/C,CAAC;AACH;AAIA,eAAsB,4BAA4B,IAAc,OAE/B;AAC/B,SAAO,MAAM,eAAe,IAAI,EAAE,WAAW,MAAM,WAAW,aAAa,MAAM,YAAY,GAAG,OAAO,aAAa;AAClH,UAAM,OAAO,MAAM,SAAS,OAAc,wBAAwB,EAC/D,IAAI,EAAE,QAAQ,UAAU,WAAW,oBAAI,KAAK,EAAE,CAAC,EAC/C,MAAM;AAAA,MACL,GAAU,yBAAyB,aAAa,MAAM,WAAW;AAAA,MACjE,GAAU,yBAAyB,IAAI,MAAM,SAAS;AAAA,MACtD,GAAU,yBAAyB,QAAQ,SAAS;AAAA,IACtD,CAAC,EACA,UAAU,EAAE,IAAW,yBAAyB,GAAG,CAAC;AACvD,WAAO,EAAE,QAAQ,KAAK,SAAS,EAAE;AAAA,EACnC,CAAC;AACH;AAOA,eAAsB,+BAA+B,IAAc,OAEhC;AACjC,SAAO,MAAM,eAAe,IAAI,EAAE,WAAW,MAAM,WAAW,aAAa,MAAM,YAAY,GAAG,OAAO,aAAa;AAClH,UAAM,OAAO,MAAM,SAAS,OAAc,wBAAwB,EAC/D,IAAI,EAAE,QAAQ,YAAY,WAAW,oBAAI,KAAK,EAAE,CAAC,EACjD,MAAM;AAAA,MACL,GAAU,yBAAyB,aAAa,MAAM,WAAW;AAAA,MACjE,GAAU,yBAAyB,IAAI,MAAM,SAAS;AAAA,MACtD,GAAU,yBAAyB,QAAQ,UAAU;AAAA,IACvD,CAAC,EACA,UAAU,EAAE,IAAW,yBAAyB,GAAG,CAAC;AACvD,WAAO,EAAE,UAAU,KAAK,SAAS,EAAE;AAAA,EACrC,CAAC;AACH;AAQA,eAAsB,cAAc,IAAc,OAMvB;AACzB,QAAM,eAAe,MAAM,gBAAgB;AAC3C,MAAI,MAAM,SAAS,gBAAgB,CAAC,cAAc;AAChD,UAAM,IAAI,MAAM,gDAAgD;AAAA,EAClE;AACA,MAAI,MAAM,SAAS,gBAAgB,cAAc;AAC/C,UAAM,IAAI,MAAM,KAAK,MAAM,IAAI,0CAA0C;AAAA,EAC3E;AACA,SAAO,MAAM,eAAe,IAAI,EAAE,WAAW,MAAM,WAAW,aAAa,MAAM,YAAY,GAAG,OAAO,aAAa;AAClH,UAAM,CAAC,GAAG,IAAI,MAAM,SAAS,OAAc,SAAS,EAAE,OAAO;AAAA,MAC3D,WAAW,MAAM;AAAA,MACjB,aAAa,MAAM;AAAA,MACnB,MAAM,MAAM;AAAA,MACZ,MAAM,MAAM;AAAA,MACZ;AAAA,IACF,CAAC,EAAE,UAAU;AACb,QAAI,CAAC,KAAK;AACR,YAAM,IAAI,MAAM,0BAA0B;AAAA,IAC5C;AACA,WAAO,WAAW,GAAG;AAAA,EACvB,CAAC;AACH;AAEA,eAAsB,WAAW,IAAc,aAAqB,WAAkD;AACpH,SAAO,MAAM,iBAAiB,IAAI,aAAa,OAAO,aAAa;AACjE,UAAM,CAAC,GAAG,IAAI,MAAM,SAAS,OAAO,EAAE,KAAY,SAAS,EACxD,MAAM,IAAI,GAAU,UAAU,aAAa,WAAW,GAAG,GAAU,UAAU,IAAI,SAAS,CAAC,CAAC,EAC5F,MAAM,CAAC;AACV,WAAO,MAAM,WAAW,GAAG,IAAI;AAAA,EACjC,CAAC;AACH;AAGA,eAAsB,cAAc,IAAc,aAA+C;AAC/F,SAAO,MAAM,iBAAiB,IAAI,aAAa,OAAO,aAAa;AACjE,UAAM,OAAO,MAAM,SAAS,OAAO,EAAE,KAAY,SAAS,EACvD,MAAM,GAAU,UAAU,aAAa,WAAW,CAAC,EACnD,QAAQ,KAAY,UAAU,SAAS,CAAC;AAC3C,WAAO,KAAK,IAAI,UAAU;AAAA,EAC5B,CAAC;AACH;AAcA,eAAsB,kBAAkB,IAAc,aAAqB,WAAyD;AAClI,SAAO,MAAM,iBAAiB,IAAI,aAAa,OAAO,aAAa;AACjE,UAAM,CAAC,GAAG,IAAI,MAAM,SAAS,OAAO;AAAA,MAClC,iBAAwB,SAAS;AAAA,MACjC,aAAoB,SAAS;AAAA,MAC7B,YAAmB,SAAS;AAAA,IAC9B,CAAC,EAAE,KAAY,QAAQ,EACpB,MAAM,IAAI,GAAU,SAAS,aAAa,WAAW,GAAG,GAAU,SAAS,IAAI,SAAS,CAAC,CAAC,EAC1F,MAAM,CAAC;AACV,QAAI,CAAC,KAAK;AACR,aAAO;AAAA,IACT;AACA,WAAO,EAAE,iBAAiB,IAAI,mBAAmB,MAAM,aAAa,OAAO,IAAI,WAAW,GAAG,YAAY,IAAI,cAAc,KAAK;AAAA,EAClI,CAAC;AACH;AASA,eAAsB,iBAAiB,IAAc,OAWmB;AACtE,SAAO,MAAM,eAAe,IAAI,EAAE,WAAW,MAAM,WAAW,aAAa,MAAM,YAAY,GAAG,OAAO,aAAa;AAClH,UAAM,OAAO,MAAM,SAAS,QAAyG;AAAA;AAAA,8BAE3G,MAAM,eAAe;AAAA;AAAA,8BAErB,MAAM,eAAe,SAAY,mBAAmB,MAAM,UAAU;AAAA;AAAA,6BAErE,MAAM,WAAW,aAAa,MAAM,SAAS;AAAA,6BAC7C,MAAM,aAAa;AAAA;AAAA,KAE3C;AACD,UAAM,MAAM,KAAK,CAAC;AAClB,QAAI,CAAC,KAAK;AACR,aAAO,EAAE,SAAS,OAAO,SAAS,KAAK;AAAA,IACzC;AACA,WAAO;AAAA,MACL,SAAS;AAAA,MACT,SAAS,EAAE,iBAAiB,IAAI,qBAAqB,MAAM,aAAa,OAAO,IAAI,YAAY,GAAG,YAAY,IAAI,eAAe,KAAK;AAAA,IACxI;AAAA,EACF,CAAC;AACH;AAsBA,SAAS,cAAc,QAA8B;AACnD,SAAO;AAAA,IACL,YAAY,OAAO,cAAc;AAAA,IACjC,OAAO,OAAO,SAAS;AAAA,IACvB,OAAO,OAAO,SAAS;AAAA,IACvB,QAAQ,OAAO,UAAU;AAAA,IACzB,cAAc,OAAO,gBAAgB;AAAA,IACrC,eAAe,OAAO,iBAAiB;AAAA,IACvC,eAAe,OAAO,iBAAiB;AAAA,IACvC,gBAAgB,OAAO,kBAAkB;AAAA,IACzC,gBAAgB,OAAO,kBAAkB;AAAA,IACzC,iBAAiB,OAAO,mBAAmB;AAAA,IAC3C,kBAAkB,OAAO,oBAAoB;AAAA,IAC7C,YAAY,OAAO,cAAc;AAAA,IACjC,WAAW,OAAO;AAAA,EACpB;AACF;AAIA,eAAsB,2BAA2B,IAAc,OAE7C;AAChB,QAAM,eAAe,IAAI,EAAE,WAAW,MAAM,WAAW,aAAa,MAAM,YAAY,GAAG,OAAO,aAAa;AAC3G,UAAM,OAAO,cAAc,MAAM,MAAM;AACvC,UAAM,SAAS,OAAc,oBAAoB,EAAE,OAAO;AAAA,MACxD,cAAc,MAAM;AAAA,MACpB,WAAW,MAAM;AAAA,MACjB,aAAa,MAAM;AAAA,MACnB,GAAG;AAAA,IACL,CAAC,EAAE,mBAAmB;AAAA,MACpB,QAAe,qBAAqB;AAAA,MACpC,KAAK,EAAE,GAAG,MAAM,WAAW,oBAAI,KAAK,EAAE;AAAA,IACxC,CAAC;AAAA,EACH,CAAC;AACH;AAIA,eAAsB,2BAA2B,IAAc,OAE7C;AAChB,QAAM,eAAe,IAAI,EAAE,WAAW,MAAM,WAAW,aAAa,MAAM,YAAY,GAAG,OAAO,aAAa;AAC3G,UAAM,SAAS,OAAc,oBAAoB,EAAE,OAAO;AAAA,MACxD,cAAc,MAAM;AAAA,MACpB,WAAW,MAAM;AAAA,MACjB,aAAa,MAAM;AAAA,MACnB,GAAG,cAAc,MAAM,MAAM;AAAA,IAC/B,CAAC;AAAA,EACH,CAAC;AACH;AAKO,IAAM,qCAAqC;AAalD,eAAsB,2BAA2B,IAAc,OAIA;AAC7D,SAAO,MAAM,eAAe,IAAI,EAAE,WAAW,MAAM,WAAW,aAAa,MAAM,YAAY,GAAG,OAAO,aAAa;AAClH,UAAM,OAAO,cAAc,MAAM,MAAM;AAEvC,UAAM,SAAS,OAAc,oBAAoB,EAAE,OAAO;AAAA,MACxD,cAAc,MAAM;AAAA,MACpB,WAAW,MAAM;AAAA,MACjB,aAAa,MAAM;AAAA,MACnB,GAAG;AAAA,IACL,CAAC,EAAE,mBAAmB;AAAA,MACpB,QAAe,qBAAqB;AAAA,MACpC,KAAK,EAAE,GAAG,MAAM,WAAW,oBAAI,KAAK,EAAE;AAAA,IACxC,CAAC;AAKD,UAAM,aAAa,MAAM,oBAAoB;AAC7C,UAAM,CAAC,KAAK,IAAI,MAAM,SAAS,OAAO,EAAE,WAAkB,qBAAqB,UAAU,CAAC,EACvF,KAAY,oBAAoB,EAChC,MAAM,GAAU,qBAAqB,cAAc,MAAM,YAAY,CAAC,EACtE,QAAQ,KAAY,qBAAqB,SAAS,CAAC,EACnD,MAAM,CAAC;AACV,UAAM,UAAU,OAAO,YAAY,MAAM,UAAU,QAAQ,IAAI;AAC/D,UAAM,WAAW,MAAM,OAAO,UAAU,QAAQ;AAChD,UAAM,iBAAiB,YAAY,QAAQ,WAAW,WAAW;AACjE,QAAI,gBAAgB;AAClB,YAAM,SAAS,OAAc,oBAAoB,EAAE,OAAO;AAAA,QACxD,cAAc,MAAM;AAAA,QACpB,WAAW,MAAM;AAAA,QACjB,aAAa,MAAM;AAAA,QACnB,GAAG;AAAA,MACL,CAAC;AAAA,IACH;AACA,WAAO,EAAE,gBAAgB,MAAM,eAAe;AAAA,EAChD,CAAC;AACH;AAsBA,SAAS,cAAc,OAA+B;AACpD,MAAI,UAAU,QAAQ,UAAU,OAAW,QAAO;AAClD,QAAM,IAAI,OAAO,UAAU,WAAW,QAAQ,OAAO,KAAK;AAC1D,SAAO,OAAO,SAAS,CAAC,IAAI,IAAI;AAClC;AAEA,SAAS,cAAc,KAeD;AACpB,SAAO;AAAA,IACL,cAAc,IAAI;AAAA,IAClB,YAAY,cAAc,IAAI,UAAU;AAAA,IACxC,OAAO,cAAc,IAAI,KAAK;AAAA,IAC9B,OAAO,cAAc,IAAI,KAAK;AAAA,IAC9B,QAAQ,cAAc,IAAI,MAAM;AAAA,IAChC,cAAc,IAAI,gBAAgB;AAAA,IAClC,eAAe,IAAI,iBAAiB;AAAA,IACpC,eAAe,IAAI,iBAAiB;AAAA,IACpC,gBAAgB,IAAI,kBAAkB;AAAA,IACtC,gBAAgB,cAAc,IAAI,cAAc;AAAA,IAChD,iBAAiB,IAAI,mBAAmB;AAAA,IACxC,kBAAkB,IAAI,oBAAoB;AAAA,IAC1C,YAAY,cAAc,IAAI,UAAU;AAAA,IACxC,WAAW,IAAI,UAAU,YAAY;AAAA,EACvC;AACF;AAIA,eAAsB,yBAAyB,IAAc,aAAqB,cAAyD;AACzI,SAAO,MAAM,iBAAiB,IAAI,aAAa,OAAO,aAAa;AACjE,UAAM,CAAC,GAAG,IAAI,MAAM,SAAS,OAAO,EAAE,KAAY,oBAAoB,EACnE,MAAM;AAAA,MACL,GAAU,qBAAqB,aAAa,WAAW;AAAA,MACvD,GAAU,qBAAqB,cAAc,YAAY;AAAA,IAC3D,CAAC,EACA,MAAM,CAAC;AACV,WAAO,MAAM,cAAc,GAAG,IAAI;AAAA,EACpC,CAAC;AACH;AAKA,eAAsB,qCAAqC,IAAc,aAA8D;AACrI,SAAO,MAAM,iBAAiB,IAAI,aAAa,OAAO,aAAa;AACjE,UAAM,OAAO,MAAM,SAAS,OAAO,EAAE,KAAY,oBAAoB,EAClE,MAAM,GAAU,qBAAqB,aAAa,WAAW,CAAC;AACjE,UAAM,eAAe,oBAAI,IAA+B;AACxD,eAAW,OAAO,MAAM;AACtB,mBAAa,IAAI,IAAI,cAAc,cAAc,GAAG,CAAC;AAAA,IACvD;AACA,WAAO;AAAA,EACT,CAAC;AACH;AAMA,eAAsB,yBAAyB,IAAc,OAE5B;AAC/B,SAAO,MAAM,iBAAiB,IAAI,MAAM,aAAa,OAAO,aAAa;AACvE,UAAM,OAAO,MAAM,SAAS,OAAO,EAAE,KAAY,oBAAoB,EAClE,MAAM;AAAA,MACL,GAAU,qBAAqB,aAAa,MAAM,WAAW;AAAA,MAC7D,GAAU,qBAAqB,cAAc,MAAM,YAAY;AAAA,MAC/D,IAAW,qBAAqB,WAAW,MAAM,KAAK;AAAA,IACxD,CAAC,EACA,QAAQ,IAAW,qBAAqB,SAAS,CAAC,EAClD,MAAM,MAAM,SAAS,GAAK;AAC7B,WAAO,KAAK,IAAI,aAAa;AAAA,EAC/B,CAAC;AACH;AAyBA,eAAsB,2BAA2B,IAAc,OAO7B;AAChC,SAAO,MAAM;AAAA,IAAe;AAAA,IAAI,EAAE,WAAW,MAAM,WAAW,aAAa,MAAM,YAAY;AAAA,IAC3F,OAAO,aAAa;AAClB,YAAM,OAAO,MAAM,SAAS,QAA4E;AAAA;AAAA;AAAA;AAAA;AAAA,aAKjG,MAAM,SAAS,KAAK,MAAM,WAAW,KAAK,MAAM,cAAc,KAAK,MAAM,SAAS;AAAA,aAClF,MAAM,qBAAqB,KAAK,MAAM,iBAAiB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,OAS7D;AACD,YAAM,MAAM,KAAK,CAAC;AAClB,aAAO,EAAE,wBAAwB,IAAI,yBAAyB,oBAAoB,IAAI,oBAAoB;AAAA,IAC5G;AAAA,EAAC;AACL;AAKA,eAAsB,wBAAwB,IAAc,OAInB;AACvC,SAAO,MAAM,iBAAiB,IAAI,MAAM,aAAa,OAAO,aAAa;AACvE,UAAM,OAAO,MAAM,SAAS,QAA4E;AAAA;AAAA;AAAA,6BAG/E,MAAM,WAAW;AAAA,iCACb,MAAM,cAAc;AAAA,2BAC1B,MAAM,SAAS;AAAA;AAAA,KAErC;AACD,QAAI,CAAC,KAAK,CAAC,EAAG,QAAO;AACrB,WAAO,EAAE,wBAAwB,KAAK,CAAC,EAAE,yBAAyB,oBAAoB,KAAK,CAAC,EAAE,oBAAoB;AAAA,EACpH,CAAC;AACH;AAMA,eAAsB,sBAAsB,IAAc,aAAqB,gBAA2C;AACxH,SAAO,MAAM,iBAAiB,IAAI,aAAa,OAAO,aAAa;AACjE,UAAM,OAAO,MAAM,QAAwB,UAAU;AAAA;AAAA,6BAE5B,WAAW,2BAA2B,cAAc;AAAA;AAAA,KAE5E;AACD,WAAO,KAAK,IAAI,CAAC,MAAM,EAAE,EAAE;AAAA,EAC7B,CAAC;AACH;AAcA,eAAsB,aAAa,IAAc,OAMwB;AAMvE,SAAO,MAAM,mBAAmB,IAAI;AAAA,IAClC,WAAW,MAAM;AAAA,IACjB,aAAa,MAAM;AAAA,IACnB,gBAAgB,MAAM;AAAA,IACtB,MAAM;AAAA,IACN,UAAU,MAAM;AAAA,IAChB,aAAa,MAAM;AAAA,EACrB,CAAC;AACH;AAmDA,eAAsB,kBAAkB,IAAc,OAcjB;AACnC,QAAM,OAAgC,EAAE,SAAS,OAAO,SAAS,GAAG,MAAM,GAAG,YAAY,EAAE;AAC3F,QAAM,SAAS,MAAM;AAAA,IAAe;AAAA,IAAI,EAAE,WAAW,MAAM,WAAW,aAAa,MAAM,YAAY;AAAA,IACnG,OAAO,aAAa,MAAM,SAAS,YAAY,OAAO,UAAU;AAC9D,YAAM,KAAK;AAIX,YAAM,OAAO,MAAM,GAAG,QAAuD;AAAA;AAAA;AAAA;AAAA;AAAA,+BAKpD,MAAM,WAAW,2BAA2B,MAAM,cAAc;AAAA;AAAA,OAExF;AACD,YAAM,MAAM,KAAK,CAAC;AAClB,UAAI,CAAC,IAAK,QAAO;AAIjB,UAAI,OAAO,IAAI,WAAW,MAAM,MAAM,iBAAiB,IAAI,aAAa,QAAQ;AAC9E,eAAO;AAAA,MACT;AAGA,UAAI,IAAI,iBAAiB,MAAM;AAC7B,cAAM,GAAG,QAAQ;AAAA;AAAA,uBAEF,IAAI,EAAE;AAAA,SACpB;AACD,eAAO;AAAA,MACT;AAEA,YAAM,WAAW,OAAO,IAAI,mBAAmB,CAAC;AAChD,UAAI,YAAY,GAAG;AAGjB,eAAO;AAAA,MACT;AAEA,YAAM,OAAO,OAAO,IAAI,eAAe,IAAI;AAC3C,YAAM,aAAa,KAAK,MAAM,WAAW,KAAK,IAAI,GAAG,MAAM,uBAAuB,CAAC;AAKnF,YAAM,GAAG,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA,aAKV,MAAM,SAAS,KAAK,MAAM,WAAW,KAAK,MAAM,aAAa,IAAI;AAAA,qCACzC,QAAQ;AAAA,8BACf,GAAG,MAAM,cAAc,IAAI,MAAM,aAAa,EAAE;AAAA,aACjE,8BAA8B,MAAM,cAAc,IAAI,MAAM,aAAa,IAAI,IAAI,EAAE;AAAA;AAAA;AAAA,OAGzF;AAGD,UAAI,aAAa,GAAG;AAClB,cAAM,GAAG,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA,eAKV,MAAM,SAAS,KAAK,MAAM,WAAW,KAAK,MAAM,aAAa,IAAI;AAAA,oCAC5C,UAAU;AAAA,gCACd,GAAG,MAAM,cAAc,IAAI,MAAM,aAAa,EAAE;AAAA,eACjE,2BAA2B,MAAM,cAAc,IAAI,MAAM,aAAa,IAAI,IAAI,EAAE;AAAA;AAAA;AAAA,SAGtF;AAAA,MACH;AAIA,YAAM,GAAG,QAAQ;AAAA;AAAA,qDAE8B,IAAI;AAAA,qBACpC,IAAI,EAAE;AAAA,OACpB;AAED,aAAO,EAAE,SAAS,MAAM,SAAS,UAAU,MAAM,WAAW;AAAA,IAC9D,CAAC;AAAA,EAAC;AAQJ,MAAI,OAAO,WAAW,OAAO,aAAa,MAAM,MAAM,gBAAgB,OAAO;AAC3E,UAAM,4BAA4B,IAAI;AAAA,MACpC,WAAW,MAAM;AAAA,MACjB,aAAa,MAAM;AAAA,MACnB,MAAM;AAAA,MACN,uBAAuB,OAAO;AAAA,MAC9B,YAAY;AAAA,MACZ,UAAU,GAAG,MAAM,cAAc,IAAI,MAAM,aAAa;AAAA,MACxD,gBAAgB,2BAA2B,MAAM,cAAc,IAAI,MAAM,aAAa,IAAI,OAAO,IAAI;AAAA,IACvG,CAAC,EAAE,MAAM,MAAM,MAAS;AAAA,EAC1B;AAEA,SAAO;AACT;AAyBA,SAAS,uBAAuB,OAAO,oBAAI,KAAK,GAAS;AACvD,SAAO,IAAI,KAAK,KAAK,IAAI,KAAK,eAAe,GAAG,KAAK,YAAY,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC,CAAC;AACpF;AAEA,eAAsB,mCAAmC,IAAc,OAYzC;AAC5B,SAAO,MAAM,uBAAuB,IAAI,MAAM,aAAa,OAAO,aAAa;AAG7E,QAAI,SAAwC;AAC5C,QAAI,MAAM,kBAAkB,MAAM,iBAAiB,GAAG;AACpD,eAAS;AAAA,IACX,WAAW,MAAM,6BAA6B,GAAG;AAC/C,YAAM,QAAQ,MAAM,kBAAkB,uBAAuB;AAC7D,YAAM,CAAC,EAAE,MAAM,IAAI,EAAE,OAAO,EAAE,CAAC,IAAI,MAAM,SAAS,OAAO;AAAA,QACvD,OAAO,mBAAkC,YAAY,QAAQ;AAAA,MAC/D,CAAC,EAAE,KAAY,WAAW,EAAE,MAAM;AAAA,QAChC,GAAU,YAAY,aAAa,MAAM,WAAW;AAAA,QACpD,GAAU,YAAY,WAAW,sBAAsB;AAAA,QACvD,GAAU,YAAY,YAAY,KAAK;AAAA,MACzC,CAAC;AACD,UAAI,OAAO,KAAK,KAAK,MAAM,4BAA4B;AACrD,iBAAS;AAAA,MACX;AAAA,IACF;AAEA,QAAI,CAAC,QAAQ;AACX,aAAO,EAAE,WAAW,OAAO,QAAQ,MAAM,SAAS,CAAC,EAAE;AAAA,IACvD;AAWA,UAAM,SAAS,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA,iCAKM,MAAM,WAAW;AAAA;AAAA;AAAA,KAG7C;AAID,UAAM,UAAU,MAAM,QAAsC,UAAU;AAAA;AAAA;AAAA;AAAA,gCAI1C,OAAO,MAAM,WAAW,CAAC;AAAA;AAAA,6BAE5B,MAAM,WAAW;AAAA;AAAA;AAAA,KAGzC;AAED,WAAO;AAAA,MACL,WAAW;AAAA,MACX;AAAA,MACA,SAAS,QAAQ,IAAI,CAAC,OAAO,EAAE,aAAa,MAAM,aAAa,gBAAgB,EAAE,iBAAiB,EAAE;AAAA,IACtG;AAAA,EACF,CAAC;AACH;AAEA,eAAsB,aAAa,IAAc,OAY/B;AAChB,QAAM,eAAe,IAAI,EAAE,WAAW,MAAM,WAAW,aAAa,MAAM,YAAY,GAAG,OAAO,aAAa;AAC3G,UAAM,CAAC,EAAE,WAAW,IAAI,EAAE,YAAY,EAAE,CAAC,IAAI,MAAM,SAAS,OAAO;AAAA,MACjE,YAAY,mBAAkC,eAAe,YAAY;AAAA,IAC3E,CAAC,EAAE,KAAY,cAAc,EAAE,MAAM,IAAI,GAAU,eAAe,aAAa,MAAM,WAAW,GAAG,GAAU,eAAe,WAAW,MAAM,SAAS,CAAC,CAAC;AACxJ,UAAM,SAAS,OAAc,cAAc,EAAE,OAAO;AAAA,MAClD,WAAW,MAAM;AAAA,MACjB,aAAa,MAAM;AAAA,MACnB,WAAW,MAAM;AAAA,MACjB,QAAQ,MAAM,UAAU;AAAA,MACxB,cAAc,OAAO,UAAU,IAAI;AAAA,MACnC,oBAAoB,MAAM;AAAA,MAC1B,kBAAkB,MAAM;AAAA,MACxB,yBAAyB,MAAM,2BAA2B;AAAA,IAC5D,CAAC;AAAA,EACH,CAAC;AACH;AAYA,eAAsB,kBAAkB,IAAc,OAAqD;AACzG,SAAO,MAAM,eAAe,IAAI,EAAE,WAAW,MAAM,WAAW,aAAa,MAAM,YAAY,GAAG,OAAO,aAAa;AAClH,UAAM,CAAC,GAAG,IAAI,MAAM,SAAS,OAAc,YAAY,EAAE,OAAO;AAAA,MAC9D,WAAW,MAAM;AAAA,MACjB,aAAa,MAAM;AAAA,MACnB,WAAW,MAAM;AAAA,MACjB,MAAM,MAAM;AAAA,MACZ,iBAAiB,MAAM,mBAAmB;AAAA,MAC1C,sBAAsB,MAAM,wBAAwB;AAAA,MACpD,WAAW,MAAM;AAAA,IACnB,CAAC,EAAE,UAAU;AACb,QAAI,CAAC,KAAK;AACR,YAAM,IAAI,MAAM,+BAA+B;AAAA,IACjD;AACA,WAAO,eAAe,GAAG;AAAA,EAC3B,CAAC;AACH;AAEA,eAAsB,eAAe,IAAc,aAAqB,WAAgD;AACtH,SAAO,MAAM,iBAAiB,IAAI,aAAa,OAAO,aAAa;AACjE,UAAM,CAAC,GAAG,IAAI,MAAM,SAAS,OAAO,EAAE,KAAY,YAAY,EAC3D,MAAM,IAAI,GAAU,aAAa,aAAa,WAAW,GAAG,GAAU,aAAa,WAAW,SAAS,CAAC,CAAC,EACzG,MAAM,CAAC;AACV,WAAO,MAAM,eAAe,GAAG,IAAI;AAAA,EACrC,CAAC;AACH;AAQA,eAAsB,kBAAkB,IAAc,OAAkF;AACtI,SAAO,MAAM,eAAe,IAAI,EAAE,WAAW,MAAM,WAAW,aAAa,MAAM,YAAY,GAAG,OAAO,aAAa;AAClH,UAAM,CAAC,QAAQ,IAAI,MAAM,SAAS,OAAO,EAAE,KAAY,YAAY,EAChE,MAAM,IAAI,GAAU,aAAa,aAAa,MAAM,WAAW,GAAG,GAAU,aAAa,WAAW,MAAM,SAAS,CAAC,CAAC,EACrH,IAAI,QAAQ,EACZ,MAAM,CAAC;AACV,QAAI,CAAC,UAAU;AACb,YAAM,CAACF,IAAG,IAAI,MAAM,SAAS,OAAc,YAAY,EAAE,OAAO;AAAA,QAC9D,WAAW,MAAM;AAAA,QACjB,aAAa,MAAM;AAAA,QACnB,WAAW,MAAM;AAAA,QACjB,MAAM,MAAM;AAAA,QACZ,iBAAiB,MAAM,mBAAmB;AAAA,QAC1C,sBAAsB,MAAM,wBAAwB;AAAA,QACpD,WAAW,MAAM;AAAA,MACnB,CAAC,EAAE,UAAU;AACb,UAAI,CAACA,MAAK;AACR,cAAM,IAAI,MAAM,+BAA+B;AAAA,MACjD;AACA,aAAO,EAAE,MAAM,eAAeA,IAAG,GAAG,UAAU,MAAM;AAAA,IACtD;AACA,UAAM,CAAC,GAAG,IAAI,MAAM,SAAS,OAAc,YAAY,EAAE,IAAI;AAAA,MAC3D,QAAQ;AAAA,MACR,MAAM,MAAM;AAAA,MACZ,iBAAiB,MAAM,mBAAmB;AAAA,MAC1C,sBAAsB,MAAM,wBAAwB;AAAA,MACpD,UAAU;AAAA,MACV,WAAW;AAAA,MACX,cAAc;AAAA,MACd,WAAW,MAAM;AAAA,MACjB,SAAS,SAAS,UAAU;AAAA,MAC5B,mBAAmB;AAAA,MACnB,kBAAkB;AAAA,MAClB,wBAAwB;AAAA,MACxB,2BAA2B;AAAA,MAC3B,WAAW,oBAAI,KAAK;AAAA,IACtB,CAAC,EAAE,MAAM,GAAU,aAAa,IAAI,SAAS,EAAE,CAAC,EAAE,UAAU;AAC5D,QAAI,CAAC,KAAK;AACR,YAAM,IAAI,MAAM,+BAA+B;AAAA,IACjD;AACA,WAAO,EAAE,MAAM,eAAe,GAAG,GAAG,UAAU,KAAK;AAAA,EACrD,CAAC;AACH;AAMA,eAAsB,kBAAkB,IAAc,aAAqB,WAAmB,OAGrE;AACvB,SAAO,MAAM,iBAAiB,IAAI,aAAa,OAAO,aAAa;AACjE,UAAM,CAAC,GAAG,IAAI,MAAM,SAAS,OAAc,YAAY,EAAE,IAAI;AAAA,MAC3D,GAAI,MAAM,SAAS,SAAY,EAAE,MAAM,MAAM,KAAK,IAAI,CAAC;AAAA,MACvD,GAAI,MAAM,oBAAoB,SAAY,EAAE,iBAAiB,MAAM,gBAAgB,IAAI,CAAC;AAAA,MACxF,SAAS,MAAa,aAAa,OAAO;AAAA,MAC1C,kBAAkB;AAAA,MAClB,WAAW,oBAAI,KAAK;AAAA,IACtB,CAAC,EAAE,MAAM,IAAI,GAAU,aAAa,aAAa,WAAW,GAAG,GAAU,aAAa,WAAW,SAAS,CAAC,CAAC,EAAE,UAAU;AACxH,QAAI,CAAC,KAAK;AACR,YAAM,IAAI,MAAM,2BAA2B,SAAS,EAAE;AAAA,IACxD;AACA,WAAO,eAAe,GAAG;AAAA,EAC3B,CAAC;AACH;AAWA,eAAsB,mBAAmB,IAAc,OAKC;AACtD,SAAO,MAAM,iBAAiB,IAAI,MAAM,aAAa,OAAO,aAAa;AACvE,UAAM,CAAC,GAAG,IAAI,MAAM,SAAS,OAAc,QAAQ,EAAE,IAAI;AAAA,MACvD,OAAO,MAAM;AAAA,MACb,aAAa,MAAM;AAAA,MACnB,WAAW,oBAAI,KAAK;AAAA,IACtB,CAAC,EAAE,MAAM;AAAA,MACP,GAAU,SAAS,aAAa,MAAM,WAAW;AAAA,MACjD,GAAU,SAAS,IAAI,MAAM,SAAS;AAAA,MACtC,GAAI,MAAM,WAAW,UAAU,CAAC,MAAa,SAAS,WAAW,0BAA0B,IAAI,CAAC;AAAA,IAClG,CAAC,EAAE,UAAU,EAAE,OAAc,SAAS,MAAM,CAAC;AAC7C,WAAO,EAAE,SAAS,QAAQ,GAAG,GAAG,OAAO,KAAK,SAAS,KAAK;AAAA,EAC5D,CAAC;AACH;AASA,eAAsB,qBAAqB,IAAc,aAAqB,WAAmB,OAK5C;AACnD,SAAO,MAAM,iBAAiB,IAAI,aAAa,OAAO,aAAa;AACjE,UAAM,CAAC,QAAQ,IAAI,MAAM,SAAS,OAAO,EAAE,KAAY,YAAY,EAChE,MAAM,IAAI,GAAU,aAAa,aAAa,WAAW,GAAG,GAAU,aAAa,WAAW,SAAS,CAAC,CAAC,EACzG,IAAI,QAAQ,EACZ,MAAM,CAAC;AACV,QAAI,CAAC,UAAU;AACb,YAAM,IAAI,MAAM,2BAA2B,SAAS,EAAE;AAAA,IACxD;AACA,QAAI,SAAS,WAAW,MAAM,QAAQ;AACpC,aAAO,EAAE,MAAM,eAAe,QAAQ,GAAG,SAAS,MAAM;AAAA,IAC1D;AACA,QAAI,SAAS,WAAW,aAAa;AACnC,YAAM,IAAI,MAAM,uDAAuD;AAAA,IACzE;AACA,UAAM,CAAC,GAAG,IAAI,MAAM,SAAS,OAAc,YAAY,EAAE,IAAI;AAAA,MAC3D,QAAQ,MAAM;AAAA,MACd,SAAS,SAAS,UAAU;AAAA,MAC5B,WAAW,oBAAI,KAAK;AAAA,MACpB,GAAI,MAAM,WAAW,cAAc;AAAA,QACjC,UAAU,MAAM,YAAY;AAAA,QAC5B,cAAc;AAAA,MAChB,IAAI,CAAC;AAAA,MACL,GAAI,MAAM,WAAW,WAAW;AAAA,QAC9B,WAAW,MAAM,aAAa;AAAA,QAC9B,cAAc,MAAM,gBAAgB;AAAA,MACtC,IAAI,CAAC;AAAA,MACL,GAAI,MAAM,WAAW,WAAW;AAAA,QAC9B,WAAW;AAAA,QACX,cAAc;AAAA,QACd,mBAAmB;AAAA,QACnB,kBAAkB;AAAA;AAAA;AAAA,QAGlB,wBAAwB;AAAA,QACxB,2BAA2B;AAAA,MAC7B,IAAI,CAAC;AAAA,IACP,CAAC,EAAE,MAAM,GAAU,aAAa,IAAI,SAAS,EAAE,CAAC,EAAE,UAAU;AAC5D,QAAI,CAAC,KAAK;AACR,YAAM,IAAI,MAAM,2BAA2B,SAAS,EAAE;AAAA,IACxD;AACA,WAAO,EAAE,MAAM,eAAe,GAAG,GAAG,SAAS,KAAK;AAAA,EACpD,CAAC;AACH;AAEA,eAAsB,mCAAmC,IAAc,aAAqB,WAAmB,QAA+B;AAC5I,QAAM,iBAAiB,IAAI,aAAa,OAAO,aAAa;AAC1D,UAAM,SAAS,OAAc,YAAY,EAAE,IAAI;AAAA,MAC7C,wBAAwB;AAAA,MACxB,WAAW,oBAAI,KAAK;AAAA,IACtB,CAAC,EAAE,MAAM,IAAI,GAAU,aAAa,aAAa,WAAW,GAAG,GAAU,aAAa,WAAW,SAAS,CAAC,CAAC;AAAA,EAC9G,CAAC;AACH;AAgBA,eAAsB,yBAAyB,IAAc,OAWvB;AACpC,SAAO,MAAM,iBAAiB,IAAI,MAAM,aAAa,OAAO,aAAa,MAAM,SAAS,YAAY,OAAO,OAAO;AAChH,UAAM,CAAC,GAAG,IAAI,MAAM,GAAG,OAAO,EAAE,KAAY,YAAY,EACrD,MAAM,IAAI,GAAU,aAAa,aAAa,MAAM,WAAW,GAAG,GAAU,aAAa,WAAW,MAAM,SAAS,CAAC,CAAC,EACrH,IAAI,QAAQ,EACZ,MAAM,CAAC;AACV,QAAI,CAAC,OAAO,IAAI,WAAW,UAAU;AACnC,aAAO,EAAE,UAAU,OAAO;AAAA,IAC5B;AACA,UAAM,CAAC,WAAW,IAAI,MAAM,GAAG,OAAO,EAAE,IAAW,aAAa,IAAI,QAAe,aAAa,OAAO,CAAC,EACrG,KAAY,YAAY,EACxB,MAAM;AAAA,MACL,GAAU,aAAa,aAAa,MAAM,WAAW;AAAA,MACrD,GAAU,aAAa,WAAW,MAAM,SAAS;AAAA,MACjD,QAAe,aAAa,QAAQ,CAAC,UAAU,WAAW,iBAAiB,CAAC;AAAA,IAC9E,CAAC,EACA,MAAM,CAAC;AACV,QAAI,aAAa;AAIf,aAAO,YAAY,WAAW,WAAW,EAAE,UAAU,QAAQ,IAAa,EAAE,UAAU,OAAO;AAAA,IAC/F;AACA,QAAI,oBAAoB,IAAI;AAC5B,QAAI,mBAAmB,IAAI;AAK3B,QAAI,kBAAkB;AACtB,QAAI,IAAI,wBAAwB;AAC9B,YAAM,CAAC,YAAY,IAAI,MAAM,GAAG,OAAO,EAAE,IAAW,aAAa,GAAG,CAAC,EAClE,KAAY,YAAY,EACxB,MAAM;AAAA,QACL,GAAU,aAAa,aAAa,MAAM,WAAW;AAAA,QACrD,GAAU,aAAa,WAAW,MAAM,SAAS;AAAA,QACjD,MAAa,aAAa,UAAU;AAAA,MACtC,CAAC,EACA,QAAQ,KAAY,aAAa,QAAQ,GAAG,KAAY,aAAa,SAAS,CAAC,EAC/E,MAAM,CAAC;AACV,UAAI,gBAAgB,aAAa,OAAO,IAAI,wBAAwB;AAGlE,4BAAoB;AACpB,2BAAmB;AAAA,MACrB,WAAW,cAAc;AACvB,cAAM,CAAC,EAAE,gBAAgB,IAAI,EAAE,iBAAiB,EAAE,CAAC,IAAI,MAAM,GAAG,OAAO;AAAA,UACrE,iBAAiB;AAAA,QACnB,CAAC,EAAE,KAAY,aAAa,EACzB,MAAM;AAAA,UACL,GAAU,cAAc,aAAa,MAAM,WAAW;AAAA,UACtD,GAAU,cAAc,QAAQ,IAAI,sBAAsB;AAAA,UAC1D,GAAU,cAAc,MAAM,aAAa;AAAA,UAC3C,MAAa,cAAc,OAAO;AAAA,QACpC,CAAC;AACH,0BAAkB,OAAO,eAAe,IAAI;AAC5C,cAAM,CAAC,EAAE,UAAU,IAAI,EAAE,WAAW,EAAE,CAAC,IAAI,MAAM,GAAG,OAAO;AAAA,UACzD,WAAW;AAAA,QACb,CAAC,EAAE,KAAY,aAAa,EACzB,MAAM;AAAA,UACL,GAAU,cAAc,aAAa,MAAM,WAAW;AAAA,UACtD,GAAU,cAAc,QAAQ,IAAI,sBAAsB;AAAA,UAC1D,GAAU,cAAc,MAAM,wBAAwB;AAAA,QACxD,CAAC;AACH,cAAM,cAAc,IAAI,8BAA8B,QAAQ,IAAI,UAAU,IAAI;AAChF,YAAI,OAAO,SAAS,IAAI,KAAK,aAAa;AACxC,6BAAmB;AAAA,QACrB,OAAO;AAKL,gBAAM,CAAC,EAAE,qBAAqB,IAAI,EAAE,sBAAsB,EAAE,CAAC,IAAI,MAAM,GAAG,OAAO;AAAA,YAC/E,sBAAsB;AAAA,UACxB,CAAC,EAAE,KAAY,aAAa,EACzB,MAAM;AAAA,YACL,GAAU,cAAc,aAAa,MAAM,WAAW;AAAA,YACtD,GAAU,cAAc,QAAQ,IAAI,sBAAsB;AAAA,YAC1D,GAAU,cAAc,MAAM,aAAa;AAAA,YAC3C,MAAa,cAAc,OAAO;AAAA,UACpC,CAAC;AACH,cAAI,OAAO,oBAAoB,MAAM,GAAG;AACtC,+BAAmB,mBAAmB;AAAA,UACxC;AAAA,QACF;AAAA,MACF;AAAA,IACF;AACA,QAAI,oBAAoB,MAAM,iBAAiB;AAC7C,YAAM,CAAC,MAAM,IAAI,MAAM,GAAG,OAAc,YAAY,EAAE,IAAI;AAAA,QACxD,QAAQ;AAAA,QACR,cAAc;AAAA,QACd;AAAA,QACA;AAAA,QACA,SAAS,IAAI,UAAU;AAAA,QACvB,WAAW,oBAAI,KAAK;AAAA,MACtB,CAAC,EAAE,MAAM,GAAU,aAAa,IAAI,IAAI,EAAE,CAAC,EAAE,UAAU;AACvD,aAAO,EAAE,UAAU,UAAU,QAAQ,eAAe,MAAM,eAAe,MAAO,EAAE;AAAA,IACpF;AAIA,UAAM,gBAAgB,CAAC,IAAI,sBAAsB,MAAM,2BAA2B,EAC/E,OAAO,CAAC,UAA2B,OAAO,UAAU,QAAQ;AAC/D,UAAM,MAAM,cAAc,SAAS,IAAI,KAAK,IAAI,GAAG,aAAa,IAAI;AACpE,QAAI,QAAQ,QAAQ,qBAAqB,KAAK;AAC5C,YAAM,CAAC,MAAM,IAAI,MAAM,GAAG,OAAc,YAAY,EAAE,IAAI;AAAA,QACxD,QAAQ;AAAA,QACR,cAAc;AAAA,QACd;AAAA,QACA;AAAA,QACA,SAAS,IAAI,UAAU;AAAA,QACvB,WAAW,oBAAI,KAAK;AAAA,MACtB,CAAC,EAAE,MAAM,GAAU,aAAa,IAAI,IAAI,EAAE,CAAC,EAAE,UAAU;AACvD,aAAO,EAAE,UAAU,UAAU,QAAQ,0BAA0B,MAAM,eAAe,MAAO,EAAE;AAAA,IAC/F;AACA,QAAI,MAAM,eAAe;AAGvB,YAAM,CAAC,MAAM,IAAI,MAAM,GAAG,OAAc,YAAY,EAAE,IAAI;AAAA,QACxD,QAAQ;AAAA,QACR,cAAc;AAAA,QACd,WAAW,MAAM;AAAA,QACjB;AAAA,QACA;AAAA,QACA,SAAS,IAAI,UAAU;AAAA,QACvB,WAAW,oBAAI,KAAK;AAAA,MACtB,CAAC,EAAE,MAAM,GAAU,aAAa,IAAI,IAAI,EAAE,CAAC,EAAE,UAAU;AACvD,aAAO,EAAE,UAAU,UAAU,QAAQ,UAAU,MAAM,eAAe,MAAO,EAAE;AAAA,IAC/E;AAGA,UAAM,wBAAwB,qBAAqB,kBAAkB,IAAI;AACzE,UAAM,CAAC,OAAO,IAAI,MAAM,GAAG,OAAc,YAAY,EAAE,IAAI;AAAA,MACzD,mBAAmB;AAAA,MACnB;AAAA,MACA,2BAA2B,IAAI;AAAA,MAC/B,WAAW,oBAAI,KAAK;AAAA,IACtB,CAAC,EAAE,MAAM,GAAU,aAAa,IAAI,IAAI,EAAE,CAAC,EAAE,UAAU;AACvD,WAAO,EAAE,UAAU,YAAY,MAAM,eAAe,OAAQ,GAAG,kBAAkB,uBAAuB,IAAI;AAAA,EAC9G,CAAC,CAAC;AACJ;AAEA,SAAS,eAAe,KAA2D;AACjF,SAAO;AAAA,IACL,IAAI,IAAI;AAAA,IACR,WAAW,IAAI;AAAA,IACf,aAAa,IAAI;AAAA,IACjB,WAAW,IAAI;AAAA,IACf,QAAQ,IAAI;AAAA,IACZ,MAAM,IAAI;AAAA,IACV,iBAAiB,IAAI;AAAA,IACrB,UAAU,IAAI;AAAA,IACd,WAAW,IAAI;AAAA,IACf,cAAc,IAAI;AAAA,IAClB,WAAW,IAAI;AAAA,IACf,SAAS,IAAI;AAAA,IACb,mBAAmB,IAAI;AAAA,IACvB,kBAAkB,IAAI;AAAA,IACtB,sBAAsB,IAAI;AAAA,IAC1B,UAAU,IAAI;AAAA,IACd,WAAW,IAAI,UAAU,YAAY;AAAA,IACrC,WAAW,IAAI,UAAU,YAAY;AAAA,EACvC;AACF;AAEA,eAAsB,WAAW,IAAc,OAK3B;AAClB,SAAO,MAAM,iBAAiB,IAAI,MAAM,aAAa,OAAO,aAAa;AACvE,UAAM,UAAU,MAAM,eAAe,UAAU,MAAM,aAAa,MAAM,SAAS;AACjF,UAAM,UAAU,MAAM,gBAAgB,UAAU,MAAM,aAAa,MAAM,cAAc;AACvF,UAAM,WAAW,MAAM,iBAAiB,UAAU,MAAM,aAAa,MAAM,SAAS;AACpF,UAAM,CAAC,GAAG,IAAI,MAAM,SAAS,OAAc,YAAY,EAAE,OAAO;AAAA,MAC9D,WAAW,QAAQ;AAAA,MACnB,aAAa,QAAQ;AAAA,MACrB,WAAW,MAAM;AAAA,MACjB,gBAAgB,MAAM;AAAA,MACtB,oBAAoB,MAAM;AAAA,MAC1B,QAAQ;AAAA,MACR,QAAQ;AAAA,MACR;AAAA,MACA,QAAQ,kBAAkB,SAAS,OAAO,KAAK,QAAQ;AAAA,MACvD,WAAW,qBAAqB,SAAS,OAAO,KAAK,QAAQ;AAAA,MAC7D,OAAO,iBAAiB,SAAS,OAAO,KAAK,QAAQ;AAAA,MACrD,OAAO,QAAQ;AAAA,MACf,iBAAiB,2BAA2B,OAAO;AAAA,MACnD,gBAAgB,QAAQ;AAAA,MACxB,UAAU,CAAC;AAAA,MACX,WAAW,oBAAI,KAAK;AAAA,IACtB,CAAC,EAAE,UAAU,EAAE,IAAW,aAAa,GAAG,CAAC;AAC3C,QAAI,CAAC,KAAK;AACR,YAAM,IAAI,MAAM,uBAAuB;AAAA,IACzC;AACA,UAAM,SAAS,OAAc,QAAQ,EAAE,IAAI;AAAA,MACzC,cAAc,IAAI;AAAA,MAClB,QAAQ;AAAA,MACR,WAAW,oBAAI,KAAK;AAAA,IACtB,CAAC,EAAE,MAAM,IAAI,GAAU,SAAS,aAAa,MAAM,WAAW,GAAG,GAAU,SAAS,IAAI,MAAM,SAAS,CAAC,CAAC;AACzG,WAAO,IAAI;AAAA,EACb,CAAC;AACH;AAEA,eAAsB,mBAAmB,IAAc,OAAsD;AAC3G,SAAO,MAAM,eAAe,IAAI,EAAE,WAAW,MAAM,WAAW,aAAa,MAAM,YAAY,GAAG,OAAO,aAAa,MAAM,SAAS,YAAY,OAAO,OAAO;AAC3J,UAAM,WAAW,MAAM,iBAAiB,IAA2B,MAAM,aAAa,MAAM,SAAS;AACrG,UAAM,CAAC,GAAG,IAAI,MAAM,GAAG,OAAc,YAAY,EAAE,OAAO;AAAA,MACxD,WAAW,MAAM;AAAA,MACjB,aAAa,MAAM;AAAA,MACnB,WAAW,MAAM;AAAA,MACjB,gBAAgB,MAAM;AAAA,MACtB,oBAAoB,MAAM;AAAA,MAC1B,QAAQ;AAAA,MACR,QAAQ,MAAM;AAAA,MACd;AAAA,MACA,QAAQ,MAAM;AAAA,MACd,WAAW,MAAM;AAAA,MACjB,OAAO,MAAM;AAAA,MACb,OAAO,MAAM;AAAA,MACb,iBAAiB,MAAM;AAAA,MACvB,gBAAgB,MAAM;AAAA,MACtB,UAAU,MAAM;AAAA,IAClB,CAAC,EAAE,UAAU;AACb,QAAI,CAAC,KAAK;AACR,YAAM,IAAI,MAAM,gCAAgC;AAAA,IAClD;AACA,WAAO,eAAe,GAAG;AAAA,EAC3B,CAAC,CAAC;AACJ;AAEA,eAAsB,oBAAoB,IAAc,aAAqB,WAAmB,YAAiD;AAC/I,SAAO,MAAM,iBAAiB,IAAI,aAAa,OAAO,aAAa,MAAM,SAAS,YAAY,OAAO,OAAO;AAC1G,UAAM,OAAO,MAAM,GAAG,QAAQ;AAAA;AAAA,6BAEL,WAAW,qBAAqB,SAAS;AAAA;AAAA;AAAA;AAAA,KAIjE;AACD,UAAM,KAAK,KAAK,CAAC,GAAG;AACpB,QAAI,CAAC,IAAI;AACP,aAAO;AAAA,IACT;AACA,UAAM,CAAC,GAAG,IAAI,MAAM,GAAG,OAAc,YAAY,EAAE,IAAI;AAAA,MACrD,QAAQ;AAAA,MACR,oBAAoB;AAAA,MACpB,WAAW,oBAAI,KAAK;AAAA,MACpB,WAAW,oBAAI,KAAK;AAAA,IACtB,CAAC,EAAE,MAAM,IAAI,GAAU,aAAa,aAAa,WAAW,GAAG,GAAU,aAAa,IAAI,EAAE,CAAC,CAAC,EAAE,UAAU;AAC1G,QAAI,CAAC,KAAK;AACR,YAAM,IAAI,MAAM,2BAA2B,EAAE,EAAE;AAAA,IACjD;AACA,UAAM,GAAG,OAAc,QAAQ,EAAE,IAAI;AAAA,MACnC,QAAQ;AAAA,MACR,cAAc,IAAI;AAAA,MAClB,WAAW,oBAAI,KAAK;AAAA,IACtB,CAAC,EAAE,MAAM,IAAI,GAAU,SAAS,aAAa,WAAW,GAAG,GAAU,SAAS,IAAI,SAAS,CAAC,CAAC;AAC7F,WAAO,eAAe,GAAG;AAAA,EAC3B,CAAC,CAAC;AACJ;AAEA,eAAsB,iBAAiB,IAAc,aAAqB,WAAmB,QAAuB,cAA6C;AAC/J,QAAM,iBAAiB,IAAI,aAAa,OAAO,aAAa;AAC1D,UAAM,SAAS,OAAc,QAAQ,EAAE,IAAI;AAAA,MACzC;AAAA,MACA,cAAc,iBAAiB,SAAY,SAAY;AAAA,MACvD,WAAW,oBAAI,KAAK;AAAA,IACtB,CAAC,EAAE,MAAM,IAAI,GAAU,SAAS,aAAa,WAAW,GAAG,GAAU,SAAS,IAAI,SAAS,CAAC,CAAC;AAAA,EAC/F,CAAC;AACH;AAkCA,eAAsB,oCACpB,IACA,OAC6C;AAC7C,SAAO,MAAM,iBAAiB,IAAI,MAAM,aAAa,OAAO,aAAa,MAAM,SAAS,YAAY,OAAO,OAAO;AAChH,UAAM,CAAC,MAAM,IAAI,MAAM,GAAG,OAAO,EAAE,KAAY,QAAQ,EACpD,MAAM,IAAI,GAAU,SAAS,aAAa,MAAM,WAAW,GAAG,GAAU,SAAS,IAAI,MAAM,eAAe,CAAC,CAAC,EAC5G,IAAI,QAAQ,EACZ,MAAM,CAAC;AACV,QAAI,CAAC,QAAQ;AACX,YAAM,IAAI,MAAM,6BAA6B,MAAM,eAAe,EAAE;AAAA,IACtE;AACA,QAAI,OAAO,WAAW,aAAa;AAGjC,aAAO,EAAE,WAAW,OAAO,QAAQ,mBAA4B;AAAA,IACjE;AAEA,UAAM,CAAC,QAAQ,IAAI,MAAM,GAAG,OAAO,EAAE,IAAW,cAAc,GAAG,CAAC,EAAE,KAAY,aAAa,EAC1F,MAAM;AAAA,MACL,GAAU,cAAc,aAAa,MAAM,WAAW;AAAA,MACtD,GAAU,cAAc,WAAW,MAAM,eAAe;AAAA,MACxD,GAAU,cAAc,eAAe,MAAM,aAAa;AAAA,IAC5D,CAAC,EACA,MAAM,CAAC;AACV,QAAI,UAAU;AACZ,aAAO,EAAE,WAAW,OAAO,QAAQ,oBAA6B;AAAA,IAClE;AAEA,UAAM,cAAc,OAAO,WAAW,UAAU,OAAO,WAAW;AAClE,UAAM,aAAa,OAAO,sBAAsB,WAAW,OAAO,EAAE;AACpE,QAAI,WAAW,OAAO;AACtB,UAAM,MAAM,oBAAI,KAAK;AACrB,UAAM,YAAY;AAAA,MAChB;AAAA,QACE,MAAM;AAAA,QACN,SAAS,EAAE,MAAM,MAAM,MAAM,iBAAiB,MAAM,gBAAgB;AAAA,QACpE,eAAe,MAAM;AAAA,MACvB;AAAA,MACA,GAAI,cAAc,CAAC,EAAE,MAAM,0BAA0B,SAAS,EAAE,QAAQ,SAAS,GAAG,eAAe,KAAsB,CAAC,IAAI,CAAC;AAAA,IACjI,EAAE,IAAI,CAAC,WAAW;AAAA,MAChB,WAAW,OAAO;AAAA,MAClB,aAAa,OAAO;AAAA,MACpB,WAAW,OAAO;AAAA,MAClB,UAAU,EAAE;AAAA,MACZ,MAAM,MAAM;AAAA,MACZ,SAAS,qBAAqB,MAAM,OAAO;AAAA,MAC3C,eAAe,MAAM,iBAAiB;AAAA,MACtC,QAAQ;AAAA,MACR,YAAY;AAAA,MACZ,aAAa;AAAA,MACb,YAAY;AAAA,IACd,EAAE;AACF,UAAM,YAAY,MAAM,GAAG,OAAc,aAAa,EAAE,OAAO,SAAS,EAAE,UAAU,GAAG,IAAI,QAAQ;AACnG,UAAM,eAAe,SAAS,CAAC;AAE/B,UAAM,WAAW,MAAM,iBAAiB,IAA2B,MAAM,aAAa,OAAO,EAAE;AAC/F,UAAM,CAAC,OAAO,IAAI,MAAM,GAAG,OAAc,YAAY,EAAE,OAAO;AAAA,MAC5D,WAAW,OAAO;AAAA,MAClB,aAAa,OAAO;AAAA,MACpB,WAAW,OAAO;AAAA,MAClB,gBAAgB,aAAa;AAAA,MAC7B,oBAAoB;AAAA,MACpB,QAAQ;AAAA,MACR,QAAQ;AAAA,MACR;AAAA,MACA,QAAQ,MAAM;AAAA,MACd,WAAW,CAAC;AAAA,MACZ,OAAO,OAAO;AAAA,MACd,OAAO,OAAO;AAAA,MACd,iBAAiB,2BAA2B,OAAO,UAAU,MAAM,uBAAuB;AAAA,MAC1F,gBAAgB,OAAO;AAAA,MACvB,UAAU,EAAE,iBAAiB,MAAM,gBAAgB;AAAA,IACrD,CAAC,EAAE,UAAU;AACb,QAAI,CAAC,SAAS;AACZ,YAAM,IAAI,MAAM,oCAAoC;AAAA,IACtD;AACA,UAAM,OAAO,eAAe,OAAO;AAEnC,gBAAY;AACZ,UAAM,CAAC,cAAc,IAAI,MAAM,GAAG,OAAc,aAAa,EAAE,OAAO;AAAA,MACpE,WAAW,OAAO;AAAA,MAClB,aAAa,OAAO;AAAA,MACpB,WAAW,OAAO;AAAA,MAClB;AAAA,MACA,MAAM;AAAA,MACN,SAAS,qBAAqB,EAAE,QAAQ,KAAK,IAAI,gBAAgB,aAAa,IAAI,QAAQ,KAAK,OAAO,CAAC;AAAA,MACvG,eAAe;AAAA,MACf,QAAQ,KAAK;AAAA,MACb,YAAY;AAAA,MACZ,aAAa;AAAA,MACb,YAAY;AAAA,IACd,CAAC,EAAE,UAAU;AACb,UAAM,SAAS,CAAC,GAAG,UAAU,GAAI,iBAAiB,CAAC,SAAS,cAAc,CAAC,IAAI,CAAC,CAAE;AAElF,UAAM,GAAG,OAAc,QAAQ,EAAE,IAAI;AAAA,MACnC,cAAc;AAAA,MACd,GAAI,cAAc,EAAE,QAAQ,UAAmB,cAAc,KAAK,IAAI,CAAC;AAAA,MACvE,WAAW;AAAA,IACb,CAAC,EAAE,MAAM,IAAI,GAAU,SAAS,aAAa,MAAM,WAAW,GAAG,GAAU,SAAS,IAAI,OAAO,EAAE,CAAC,CAAC;AAEnG,WAAO,EAAE,WAAW,MAAe,MAAM,cAAc,QAAQ,oBAAoB,WAAW;AAAA,EAChG,CAAC,CAAC;AACJ;AAEA,eAAsB,sBAAsB,IAAc,aAAqB,WAAmB,YAAmC;AACnI,QAAM,iBAAiB,IAAI,aAAa,OAAO,aAAa;AAC1D,UAAM,SAAS,OAAc,QAAQ,EAAE,IAAI;AAAA,MACzC,oBAAoB;AAAA,MACpB,WAAW,oBAAI,KAAK;AAAA,IACtB,CAAC,EAAE,MAAM,IAAI,GAAU,SAAS,aAAa,WAAW,GAAG,GAAU,SAAS,IAAI,SAAS,CAAC,CAAC;AAAA,EAC/F,CAAC;AACH;AAEA,eAAsB,WAAW,IAAc,aAAqB,QAAgB,QAA0D;AAC5I,QAAM,iBAAiB,IAAI,aAAa,OAAO,aAAa;AAC1D,UAAM,SAAS,OAAc,YAAY,EAAE,IAAI;AAAA,MAC7C,QAAQ,oBAAoB,MAAM;AAAA,MAClC,YAAY,WAAW,oBAAoB,SAAY,oBAAI,KAAK;AAAA,MAChE,WAAW,oBAAI,KAAK;AAAA,IACtB,CAAC,EAAE,MAAM,IAAI,GAAU,aAAa,aAAa,WAAW,GAAG,GAAU,aAAa,IAAI,MAAM,CAAC,CAAC;AAAA,EACpG,CAAC;AACH;AAcA,eAAsB,qBAAqB,IAAc,aAAqB,QAAgB,gBAAuC;AACnI,QAAM,iBAAiB,IAAI,aAAa,OAAO,aAAa;AAC1D,UAAM,CAAC,GAAG,IAAI,MAAM,SAAS,OAAc,YAAY,EAAE,IAAI;AAAA,MAC3D,QAAQ;AAAA,MACR;AAAA,MACA,WAAW;AAAA,MACX,YAAY;AAAA,MACZ,WAAW,oBAAI,KAAK;AAAA,IACtB,CAAC,EAAE,MAAM,IAAI,GAAU,aAAa,aAAa,WAAW,GAAG,GAAU,aAAa,IAAI,MAAM,GAAG,QAAe,aAAa,QAAQ,CAAC,WAAW,iBAAiB,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,IAAW,aAAa,GAAG,CAAC;AACjN,QAAI,CAAC,KAAK;AACR,YAAM,IAAI,MAAM,uCAAuC,MAAM,EAAE;AAAA,IACjE;AAAA,EACF,CAAC;AACH;AASA,eAAsB,qCAAqC,IAAc,aAAqB,QAAiC;AAC7H,SAAO,MAAM,iBAAiB,IAAI,aAAa,OAAO,aAAa;AACjE,UAAM,OAAO,MAAM,SAAS,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,6BASX,WAAW,aAAa,MAAM;AAAA;AAAA,KAEtD;AACD,UAAM,QAAQ,KAAK,CAAC,GAAG;AACvB,QAAI,UAAU,UAAa,UAAU,MAAM;AACzC,YAAM,IAAI,MAAM,2BAA2B,MAAM,EAAE;AAAA,IACrD;AACA,WAAO,OAAO,KAAK;AAAA,EACrB,CAAC;AACH;AAEA,eAAsB,eAAe,IAAc,aAAqB,QAA6C;AACnH,SAAO,MAAM,iBAAiB,IAAI,aAAa,OAAO,aAAa;AACjE,UAAM,CAAC,GAAG,IAAI,MAAM,SAAS,OAAO,EAAE,KAAY,YAAY,EAAE,MAAM,IAAI,GAAU,aAAa,aAAa,WAAW,GAAG,GAAU,aAAa,IAAI,MAAM,CAAC,CAAC,EAAE,MAAM,CAAC;AACxK,WAAO,MAAM,eAAe,GAAG,IAAI;AAAA,EACrC,CAAC;AACH;AAEA,eAAsB,iBAAiB,IAAc,aAAqB,WAAmB,QAAQ,KAA6B;AAChI,SAAO,MAAM,iBAAiB,IAAI,aAAa,OAAO,aAAa;AACjE,UAAM,OAAO,MAAM,SAAS,OAAO,EAAE,KAAY,YAAY,EAC1D,MAAM,IAAI,GAAU,aAAa,aAAa,WAAW,GAAG,GAAU,aAAa,WAAW,SAAS,CAAC,CAAC,EACzG,QAAQ,IAAW,aAAa,QAAQ,GAAG,IAAW,aAAa,SAAS,CAAC,EAC7E,MAAM,KAAK;AACd,WAAO,KAAK,IAAI,cAAc;AAAA,EAChC,CAAC;AACH;AAEA,eAAsB,wBAAwB,IAAc,aAAqB,QAAgB,OAA2D;AAC1J,SAAO,MAAM,iBAAiB,IAAI,aAAa,OAAO,aAAa;AACjE,UAAM,CAAC,GAAG,IAAI,MAAM,SAAS,OAAc,YAAY,EAAE,IAAI;AAAA,MAC3D,GAAI,MAAM,WAAW,SAAY,EAAE,QAAQ,MAAM,OAAO,IAAI,CAAC;AAAA,MAC7D,GAAI,MAAM,cAAc,SAAY,EAAE,WAAW,MAAM,UAAU,IAAI,CAAC;AAAA,MACtE,GAAI,MAAM,UAAU,SAAY,EAAE,OAAO,MAAM,MAAM,IAAI,CAAC;AAAA,MAC1D,GAAI,MAAM,UAAU,SAAY,EAAE,OAAO,MAAM,MAAM,IAAI,CAAC;AAAA,MAC1D,GAAI,MAAM,oBAAoB,SAAY,EAAE,iBAAiB,MAAM,gBAAgB,IAAI,CAAC;AAAA,MACxF,GAAI,MAAM,mBAAmB,SAAY,EAAE,gBAAgB,MAAM,eAAe,IAAI,CAAC;AAAA,MACrF,GAAI,MAAM,aAAa,SAAY,EAAE,UAAU,MAAM,SAAS,IAAI,CAAC;AAAA,MACnE,WAAW,oBAAI,KAAK;AAAA,IACtB,CAAC,EAAE,MAAM,IAAI,GAAU,aAAa,aAAa,WAAW,GAAG,GAAU,aAAa,IAAI,MAAM,GAAG,GAAU,aAAa,QAAQ,QAAQ,CAAC,CAAC,EAAE,UAAU;AACxJ,QAAI,CAAC,KAAK;AACR,YAAM,IAAI,MAAM,kCAAkC,MAAM,EAAE;AAAA,IAC5D;AACA,WAAO,eAAe,GAAG;AAAA,EAC3B,CAAC;AACH;AAEA,eAAsB,wBAAwB,IAAc,aAAqB,QAAsC;AACrH,SAAO,MAAM,iBAAiB,IAAI,aAAa,OAAO,aAAa;AACjE,UAAM,CAAC,GAAG,IAAI,MAAM,SAAS,OAAc,YAAY,EAAE,IAAI;AAAA,MAC3D,QAAQ;AAAA,MACR,YAAY,oBAAI,KAAK;AAAA,MACrB,WAAW,oBAAI,KAAK;AAAA,IACtB,CAAC,EAAE,MAAM,IAAI,GAAU,aAAa,aAAa,WAAW,GAAG,GAAU,aAAa,IAAI,MAAM,GAAG,GAAU,aAAa,QAAQ,QAAQ,CAAC,CAAC,EAAE,UAAU;AACxJ,QAAI,CAAC,KAAK;AACR,YAAM,IAAI,MAAM,kCAAkC,MAAM,EAAE;AAAA,IAC5D;AACA,WAAO,eAAe,GAAG;AAAA,EAC3B,CAAC;AACH;AAEA,eAAsB,0BAA0B,IAAc,aAAqB,WAAmB,SAA2C;AAC/I,SAAO,MAAM,iBAAiB,IAAI,aAAa,OAAO,aAAa,MAAM,SAAS,YAAY,OAAO,OAAO;AAC1G,UAAM,OAAO,MAAM,GAAG,OAAO,EAAE,KAAY,YAAY,EACpD,MAAM,IAAI,GAAU,aAAa,aAAa,WAAW,GAAG,GAAU,aAAa,WAAW,SAAS,GAAG,GAAU,aAAa,QAAQ,QAAQ,GAAG,QAAe,aAAa,IAAI,OAAO,CAAC,CAAC;AAChM,QAAI,KAAK,WAAW,QAAQ,QAAQ;AAClC,YAAM,IAAI,MAAM,yDAAyD;AAAA,IAC3E;AACA,QAAI,QAAQ;AACZ,eAAW,UAAU,SAAS;AAC5B,eAAS;AACT,YAAM,GAAG,OAAc,YAAY,EAAE,IAAI;AAAA,QACvC,UAAU;AAAA,QACV,WAAW,oBAAI,KAAK;AAAA,MACtB,CAAC,EAAE,MAAM,IAAI,GAAU,aAAa,aAAa,WAAW,GAAG,GAAU,aAAa,IAAI,MAAM,CAAC,CAAC;AAAA,IACpG;AACA,UAAM,UAAU,MAAM,GAAG,OAAO,EAAE,KAAY,YAAY,EACvD,MAAM,IAAI,GAAU,aAAa,aAAa,WAAW,GAAG,GAAU,aAAa,WAAW,SAAS,GAAG,GAAU,aAAa,QAAQ,QAAQ,CAAC,CAAC,EACnJ,QAAQ,IAAW,aAAa,QAAQ,GAAG,IAAW,aAAa,SAAS,CAAC;AAChF,WAAO,QAAQ,IAAI,cAAc;AAAA,EACnC,CAAC,CAAC;AACJ;AAEA,eAAsB,oBAAoB,IAAc,aAAqB,WAAmB,QAAqD;AACnJ,MAAI,OAAO,WAAW,GAAG;AACvB,WAAO,CAAC;AAAA,EACV;AACA,SAAO,MAAM,iBAAiB,IAAI,aAAa,OAAO,aAAa,MAAM,SAAS,YAAY,OAAO,OAAO;AAC1G,UAAM,CAAC,GAAG,IAAI,MAAM,GAAG,OAAO,EAAE,KAAY,QAAQ,EACjD,MAAM,IAAI,GAAU,SAAS,aAAa,WAAW,GAAG,GAAU,SAAS,IAAI,SAAS,CAAC,CAAC,EAC1F,IAAI,QAAQ,EACZ,MAAM,CAAC;AACV,QAAI,CAAC,KAAK;AACR,YAAM,IAAI,MAAM,sBAAsB,SAAS,EAAE;AAAA,IACnD;AACA,QAAI,WAAW,IAAI;AACnB,UAAM,SAAS,OAAO,IAAI,CAAC,WAAW;AAAA,MACpC,WAAW,IAAI;AAAA,MACf,aAAa,IAAI;AAAA,MACjB;AAAA,MACA,UAAU,EAAE;AAAA,MACZ,MAAM,MAAM;AAAA,MACZ,SAAS,qBAAqB,MAAM,WAAW,CAAC,CAAC;AAAA,MACjD,eAAe,MAAM,iBAAiB;AAAA,MACtC,QAAQ,MAAM,UAAU;AAAA,MACxB,YAAY,MAAM,cAAc;AAAA,MAChC,aAAa,MAAM,eAAe;AAAA,MAClC,YAAY,MAAM,cAAc,oBAAI,KAAK;AAAA,IAC3C,EAAE;AACF,UAAM,WAAW,MAAM,GAAG,OAAc,aAAa,EAAE,OAAO,MAAM,EAAE,UAAU;AAChF,UAAM,GAAG,OAAc,QAAQ,EAAE,IAAI,EAAE,cAAc,UAAU,WAAW,oBAAI,KAAK,EAAE,CAAC,EAAE,MAAM,IAAI,GAAU,SAAS,aAAa,WAAW,GAAG,GAAU,SAAS,IAAI,SAAS,CAAC,CAAC;AAClL,WAAO,SAAS,IAAI,QAAQ;AAAA,EAC9B,CAAC,CAAC;AACJ;AAEA,eAAsB,oCAAoC,IAAc,aAAqB,WAAmB,QAA4B,QAOhH;AAC1B,MAAI,OAAO,WAAW,GAAG;AACvB,WAAO,CAAC;AAAA,EACV;AACA,SAAO,MAAM,iBAAiB,IAAI,aAAa,OAAO,aAAa,MAAM,SAAS,YAAY,OAAO,OAAO;AAC1G,UAAM,CAAC,GAAG,IAAI,MAAM,GAAG,OAAO,EAAE,KAAY,QAAQ,EACjD,MAAM,IAAI,GAAU,SAAS,aAAa,WAAW,GAAG,GAAU,SAAS,IAAI,SAAS,CAAC,CAAC,EAC1F,IAAI,QAAQ,EACZ,MAAM,CAAC;AACV,QAAI,CAAC,KAAK;AACR,YAAM,IAAI,MAAM,sBAAsB,SAAS,EAAE;AAAA,IACnD;AACA,QAAI,WAAW,IAAI;AACnB,UAAM,MAAM,oBAAI,KAAK;AACrB,UAAM,SAAS,OAAO,IAAI,CAAC,WAAW;AAAA,MACpC,WAAW,IAAI;AAAA,MACf,aAAa,IAAI;AAAA,MACjB;AAAA,MACA,UAAU,EAAE;AAAA,MACZ,MAAM,MAAM;AAAA,MACZ,SAAS,qBAAqB,MAAM,WAAW,CAAC,CAAC;AAAA,MACjD,eAAe,MAAM,iBAAiB;AAAA,MACtC,QAAQ,MAAM,UAAU;AAAA,MACxB,YAAY,MAAM,cAAc;AAAA,MAChC,aAAa,MAAM,eAAe;AAAA,MAClC,YAAY,MAAM,cAAc;AAAA,IAClC,EAAE;AACF,UAAM,WAAW,MAAM,GAAG,OAAc,aAAa,EAAE,OAAO,MAAM,EAAE,UAAU;AAChF,UAAM,GAAG,OAAc,QAAQ,EAAE,IAAI;AAAA,MACnC,cAAc;AAAA,MACd,GAAI,OAAO,cAAc,SAAY,EAAE,WAAW,OAAO,UAAU,IAAI,CAAC;AAAA,MACxE,GAAI,OAAO,UAAU,SAAY,EAAE,OAAO,OAAO,MAAM,IAAI,CAAC;AAAA,MAC5D,GAAI,OAAO,UAAU,SAAY,EAAE,OAAO,OAAO,MAAM,IAAI,CAAC;AAAA,MAC5D,GAAI,OAAO,aAAa,SAAY,EAAE,UAAU,OAAO,SAAS,IAAI,CAAC;AAAA,MACrE,GAAI,OAAO,WAAW,SAAY,EAAE,QAAQ,OAAO,OAAO,IAAI,CAAC;AAAA,MAC/D,GAAI,OAAO,iBAAiB,SAAY,EAAE,cAAc,OAAO,aAAa,IAAI,CAAC;AAAA,MACjF,WAAW;AAAA,IACb,CAAC,EAAE,MAAM,IAAI,GAAU,SAAS,aAAa,WAAW,GAAG,GAAU,SAAS,IAAI,SAAS,CAAC,CAAC;AAC7F,WAAO,SAAS,IAAI,QAAQ;AAAA,EAC9B,CAAC,CAAC;AACJ;AAkBA,eAAsB,2CACpB,IACA,aACA,WACA,OACyB;AACzB,SAAO,MAAM,iBAAiB,IAAI,aAAa,OAAO,aAAa,MAAM,SAAS,YAAY,OAAO,OAAO;AAC1G,UAAM,CAAC,UAAU,IAAI,MAAM,GAAG,OAAO,EAAE,KAAY,QAAQ,EAAE,MAAM,IAAI,GAAU,SAAS,aAAa,WAAW,GAAG,GAAU,SAAS,IAAI,SAAS,CAAC,CAAC,EAAE,IAAI,QAAQ,EAAE,MAAM,CAAC;AAC9K,QAAI,CAAC,YAAY;AACf,YAAM,IAAI,MAAM,sBAAsB,SAAS,EAAE;AAAA,IACnD;AACA,UAAM,QAAQ,MAAM,MAAM,WAAW,UAAU,GAAG;AAAA,MAChD,mCAAmC,OAAO,YAAY,MAAM,+CAA+C,IAAI,EAAE,aAAa,WAAW,QAAQ,CAAC;AAAA,IACpJ,CAAC;AACD,QAAI,MAAM,OAAO,WAAW,GAAG;AAC7B,aAAO,CAAC;AAAA,IACV;AACA,QAAI,WAAW,WAAW;AAC1B,UAAM,MAAM,oBAAI,KAAK;AACrB,UAAM,SAAS,MAAM,OAAO,IAAI,CAAC,WAAW;AAAA,MAC1C,WAAW,WAAW;AAAA,MACtB,aAAa,WAAW;AAAA,MACxB;AAAA,MACA,UAAU,EAAE;AAAA,MACZ,MAAM,MAAM;AAAA,MACZ,SAAS,qBAAqB,MAAM,WAAW,CAAC,CAAC;AAAA,MACjD,eAAe,MAAM,iBAAiB;AAAA,MACtC,QAAQ,MAAM,UAAU;AAAA,MACxB,YAAY,MAAM,cAAc;AAAA,MAChC,aAAa,MAAM,eAAe;AAAA,MAClC,YAAY,MAAM,cAAc;AAAA,IAClC,EAAE;AACF,UAAM,WAAW,MAAM,GAAG,OAAc,aAAa,EAAE,OAAO,MAAM,EAAE,UAAU;AAChF,UAAM,SAAS,MAAM,UAAU,CAAC;AAChC,UAAM,GAAG,OAAc,QAAQ,EAAE,IAAI;AAAA,MACnC,cAAc;AAAA,MACd,GAAI,OAAO,cAAc,SAAY,EAAE,WAAW,OAAO,UAAU,IAAI,CAAC;AAAA,MACxE,GAAI,OAAO,UAAU,SAAY,EAAE,OAAO,OAAO,MAAM,IAAI,CAAC;AAAA,MAC5D,GAAI,OAAO,UAAU,SAAY,EAAE,OAAO,OAAO,MAAM,IAAI,CAAC;AAAA,MAC5D,GAAI,OAAO,aAAa,SAAY,EAAE,UAAU,OAAO,SAAS,IAAI,CAAC;AAAA,MACrE,GAAI,OAAO,WAAW,SAAY,EAAE,QAAQ,OAAO,OAAO,IAAI,CAAC;AAAA,MAC/D,GAAI,OAAO,iBAAiB,SAAY,EAAE,cAAc,OAAO,aAAa,IAAI,CAAC;AAAA,MACjF,WAAW;AAAA,IACb,CAAC,EAAE,MAAM,IAAI,GAAU,SAAS,aAAa,WAAW,GAAG,GAAU,SAAS,IAAI,SAAS,CAAC,CAAC;AAC7F,WAAO,SAAS,IAAI,QAAQ;AAAA,EAC9B,CAAC,CAAC;AACJ;AAEO,SAAS,eAAe,aAAqB,WAA2B;AAC7E,SAAO,cAAc,WAAW,aAAa,SAAS;AACxD;AAEA,SAAS,WAAW,KAA0C,aAAyC,CAAC,GAAY;AAClH,SAAO;AAAA,IACL,IAAI,IAAI;AAAA,IACR,WAAW,IAAI;AAAA,IACf,aAAa,IAAI;AAAA,IACjB,QAAQ,IAAI;AAAA,IACZ,gBAAgB,IAAI;AAAA,IACpB,OAAO,IAAI,SAAS;AAAA,IACpB,aAAc,IAAI,eAA2C;AAAA,IAC7D,WAAW,IAAI;AAAA,IACf,OAAO,IAAI;AAAA,IACX,UAAU,IAAI;AAAA,IACd,OAAO,IAAI;AAAA,IACX,gBAAgB,IAAI;AAAA,IACpB,WAAW,IAAI;AAAA,IACf,gBAAgB,IAAI;AAAA;AAAA;AAAA;AAAA,IAIpB,iBAAiB,IAAI,mBAAmB;AAAA,IACxC,aAAa,OAAO,IAAI,WAAW;AAAA,IACnC,eAAe,IAAI;AAAA,IACnB,0BAA2B,IAAI,4BAAoD;AAAA,IACnF;AAAA,IACA,iBAAiB,IAAI,mBAAmB;AAAA,IACxC,sBAAsB,IAAI,wBAAwB;AAAA,IAClD,oBAAoB,IAAI;AAAA,IACxB,cAAc,IAAI;AAAA,IAClB,iBAAiB,IAAI,mBAAmB;AAAA,IACxC,cAAc,IAAI;AAAA,IAClB,yBAAyB,IAAI,2BAA2B;AAAA,IACxD,uBAAuB,IAAI,yBAAyB;AAAA,IACpD,WAAW,IAAI,UAAU,YAAY;AAAA,IACrC,WAAW,IAAI,UAAU,YAAY;AAAA,EACvC;AACF;AAEA,SAAS,SAAS,KAA6D;AAC7E,SAAO;AAAA,IACL,IAAI,IAAI;AAAA,IACR,aAAa,IAAI;AAAA,IACjB,WAAW,IAAI;AAAA,IACf,UAAU,IAAI;AAAA,IACd,MAAM,IAAI;AAAA,IACV,SAAS,IAAI;AAAA,IACb,YAAY,IAAI,WAAW,YAAY;AAAA,IACvC,eAAe,IAAI;AAAA,IACnB,QAAQ,IAAI;AAAA,EACd;AACF;AAEA,SAAS,eAAe,KAA2D;AACjF,SAAO;AAAA,IACL,IAAI,IAAI;AAAA,IACR,aAAa,IAAI;AAAA,IACjB,WAAW,IAAI;AAAA,IACf,gBAAgB,IAAI;AAAA,IACpB,oBAAoB,IAAI;AAAA,IACxB,QAAQ,IAAI;AAAA,IACZ,QAAQ,IAAI;AAAA,IACZ,UAAU,IAAI;AAAA,IACd,QAAQ,IAAI;AAAA,IACZ,WAAW,IAAI;AAAA,IACf,OAAO,IAAI;AAAA,IACX,OAAO,IAAI;AAAA,IACX,iBAAiB,IAAI;AAAA,IACrB,gBAAgB,IAAI;AAAA,IACpB,WAAY,IAAI,aAAkC;AAAA,IAClD,UAAU,IAAI;AAAA,IACd,WAAW,IAAI,YAAY,IAAI,UAAU,YAAY,IAAI;AAAA,IACzD,YAAY,IAAI,aAAa,IAAI,WAAW,YAAY,IAAI;AAAA,IAC5D,WAAW,IAAI,UAAU,YAAY;AAAA,IACrC,WAAW,IAAI,UAAU,YAAY;AAAA,EACvC;AACF;AAEA,eAAe,iBAAiB,IAAc,aAAqB,WAAoC;AACrG,QAAM,CAAC,EAAE,YAAY,IAAI,EAAE,aAAa,EAAE,CAAC,IAAI,MAAM,GAAG,OAAO;AAAA,IAC7D,aAAa,mBAAkC,aAAa,QAAQ;AAAA,EACtE,CAAC,EAAE,KAAY,YAAY,EAAE,MAAM,IAAI,GAAU,aAAa,aAAa,WAAW,GAAG,GAAU,aAAa,WAAW,SAAS,CAAC,CAAC;AACtI,SAAO,OAAO,WAAW,IAAI;AAC/B;AAEA,SAAS,oBAAoB,QAA8D;AACzF,MAAI,WAAW,QAAQ;AACrB,WAAO;AAAA,EACT;AACA,MAAI,WAAW,UAAU;AACvB,WAAO;AAAA,EACT;AACA,MAAI,WAAW,WAAW;AACxB,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAEA,SAAS,kBAAkB,SAAiC;AAC1D,MAAI,WAAW,OAAO,YAAY,YAAY,UAAU,WAAW,OAAO,QAAQ,SAAS,UAAU;AACnG,WAAO,QAAQ;AAAA,EACjB;AACA,SAAO;AACT;AAEA,SAAS,qBAAqB,SAAwC;AACpE,MAAI,WAAW,OAAO,YAAY,YAAY,eAAe,WAAW,MAAM,QAAQ,QAAQ,SAAS,GAAG;AACxG,WAAO,QAAQ;AAAA,EACjB;AACA,SAAO;AACT;AAEA,SAAS,iBAAiB,SAAoC;AAC5D,MAAI,WAAW,OAAO,YAAY,YAAY,WAAW,WAAW,MAAM,QAAQ,QAAQ,KAAK,GAAG;AAChG,WAAO,QAAQ;AAAA,EACjB;AACA,SAAO;AACT;AAEA,SAAS,2BAA2B,SAAmC;AACrE,QAAM,QAAQ,QAAQ,SAAS;AAC/B,SAAO,UAAU,UAAU,UAAU,aAAa,UAAU,SAAS,UAAU,YAAY,UAAU,UAAU,UAAU,UACrH,QACA;AACN;AAEA,SAAS,QAAQ,KAAkD;AACjE,SAAO;AAAA,IACL,IAAI,IAAI;AAAA,IACR,aAAa,IAAI;AAAA,IACjB,QAAQ,IAAI;AAAA,IACZ,UAAU,IAAI;AAAA,IACd,cAAc,IAAI;AAAA,IAClB,aAAa,IAAI;AAAA,IACjB,WAAW,IAAI;AAAA,IACf,QAAQ,IAAI;AAAA,IACZ,QAAQ,IAAI;AAAA,IACZ,WAAW,IAAI;AAAA,IACf,WAAW,IAAI,UAAU,YAAY;AAAA,IACrC,WAAW,IAAI,UAAU,YAAY;AAAA,EACvC;AACF;AAEA,SAAS,iBAAiB,KAA+D;AACvF,SAAO;AAAA,IACL,IAAI,IAAI;AAAA,IACR,WAAW,IAAI;AAAA,IACf,aAAa,IAAI;AAAA,IACjB,MAAM,IAAI;AAAA,IACV,QAAQ,IAAI;AAAA,IACZ,UAAU,IAAI;AAAA,IACd,oBAAoB,IAAI;AAAA,IACxB,SAAS,IAAI;AAAA,IACb,eAAe,IAAI;AAAA,IACnB,aAAa,IAAI;AAAA,IACjB,mBAAmB,IAAI;AAAA,IACvB,eAAe,IAAI;AAAA,IACnB,UAAU,IAAI;AAAA,IACd,WAAW,IAAI,UAAU,YAAY;AAAA,IACrC,WAAW,IAAI,UAAU,YAAY;AAAA,EACvC;AACF;AAEA,SAAS,oBAAoB,KAAqE;AAChG,SAAO;AAAA,IACL,IAAI,IAAI;AAAA,IACR,WAAW,IAAI;AAAA,IACf,aAAa,IAAI;AAAA,IACjB,QAAQ,IAAI;AAAA,IACZ,QAAQ,IAAI;AAAA,IACZ,aAAa,IAAI;AAAA,IACjB,aAAa,IAAI,cAAc,IAAI,YAAY,YAAY,IAAI;AAAA,IAC/D,SAAS,IAAI,QAAQ,YAAY;AAAA,IACjC,WAAW,IAAI;AAAA,IACf,gBAAgB,IAAI;AAAA,IACpB,OAAO,IAAI;AAAA,IACX,WAAW,IAAI,UAAU,YAAY;AAAA,IACrC,WAAW,IAAI,UAAU,YAAY;AAAA,EACvC;AACF;AAEA,SAAS,WAAW,KAAiE;AACnF,SAAO;AAAA,IACL,IAAI,IAAI;AAAA,IACR,MAAM,IAAI;AAAA,IACV,gBAAgB,IAAI;AAAA,IACpB,YAAY,IAAI;AAAA,IAChB,WAAW,IAAI,UAAU,YAAY;AAAA,IACrC,WAAW,IAAI,UAAU,YAAY;AAAA,EACvC;AACF;AAEA,SAAS,oBAAoB,KAAqE;AAChG,SAAO;AAAA,IACL,IAAI,IAAI;AAAA,IACR,WAAW,IAAI;AAAA,IACf,aAAa,IAAI;AAAA,IACjB,QAAQ,IAAI;AAAA,IACZ,QAAQ,IAAI;AAAA,IACZ,UAAU,IAAI;AAAA,IACd,WAAW,IAAI,UAAU,YAAY;AAAA,IACrC,WAAW,IAAI,UAAU,YAAY;AAAA,EACvC;AACF;AAEA,SAAS,iBAAiB,KAAyE;AACjG,SAAO;AAAA,IACL,WAAW,IAAI;AAAA,IACf,aAAa,IAAI;AAAA;AAAA;AAAA,IAGjB,MAAM,IAAI;AAAA,IACV,WAAW,IAAI,UAAU,YAAY;AAAA,IACrC,WAAW,IAAI,UAAU,YAAY;AAAA,EACvC;AACF;AAEA,SAAS,yBAAyB,KAA+E;AAC/G,QAAM,UAAU,IAAI,SAAS,SAAS,IAAI,cACtC;AAAA,IACA,WAAW;AAAA,IACX,aAAa,yBAAyB,IAAI,IAAI,IAAI,QAAQ;AAAA,IAC1D,WAAW;AAAA,IACX,OAAO,IAAI,YACP,gEACA;AAAA,EACN,IACE;AAAA,IACA,WAAW;AAAA,IACX,OAAO,IAAI,SAAS,QAChB,iEACA;AAAA,EACN;AACF,SAAO;AAAA,IACL,IAAI,IAAI;AAAA,IACR,WAAW,IAAI;AAAA,IACf,aAAa,IAAI;AAAA,IACjB,MAAM,IAAI;AAAA,IACV,QAAQ,IAAI;AAAA,IACZ,MAAM,IAAI;AAAA,IACV,aAAa,IAAI;AAAA,IACjB,UAAU,IAAI;AAAA,IACd,MAAM,IAAI;AAAA,IACV,aAAa,IAAI;AAAA,IACjB,aAAa,IAAI;AAAA,IACjB,YAAY,IAAI;AAAA,IAChB,WAAW,IAAI;AAAA,IACf,OAAO,CAAC;AAAA,IACR;AAAA,IACA,SAAS;AAAA,IACT,eAAe;AAAA,IACf,UAAU,IAAI;AAAA,IACd,WAAW,IAAI,UAAU,YAAY;AAAA,IACrC,WAAW,IAAI,UAAU,YAAY;AAAA,EACvC;AACF;AAEA,SAAS,aAAa,KAAuD;AAC3E,SAAO;AAAA,IACL,IAAI,IAAI;AAAA,IACR,WAAW,IAAI;AAAA,IACf,MAAM,IAAI;AAAA,IACV,MAAM,IAAI;AAAA,IACV,gBAAgB,IAAI;AAAA,IACpB,YAAY,IAAI;AAAA,IAChB,mBAAmB,IAAI,qBAAqB;AAAA,IAC5C,WAAW,IAAI,UAAU,YAAY;AAAA,IACrC,WAAW,IAAI,UAAU,YAAY;AAAA,EACvC;AACF;AAEA,SAAS,mBAAmB,KAAuE;AACjG,SAAO;AAAA,IACL,WAAW,IAAI;AAAA,IACf,cAAc,IAAI;AAAA,IAClB,MAAM,IAAI;AAAA,IACV,aAAa,IAAI;AAAA,IACjB,WAAW,IAAI,UAAU,YAAY;AAAA,EACvC;AACF;AAEA,SAAS,0BAA0B,KAAiF;AAClH,SAAO;AAAA,IACL,IAAI,IAAI;AAAA,IACR,WAAW,IAAI;AAAA,IACf,aAAa,IAAI;AAAA,IACjB,cAAc,IAAI;AAAA,IAClB,MAAM,IAAI;AAAA,IACV,QAAQ,IAAI;AAAA,IACZ,QAAQ,yBAAyB,IAAI,MAAM;AAAA,IAC3C,UAAU,IAAI;AAAA,IACd,WAAW,IAAI,UAAU,YAAY;AAAA,IACrC,WAAW,IAAI,UAAU,YAAY;AAAA,EACvC;AACF;AAQA,SAAS,yBAAyB,QAA0D;AAC1F,QAAM,mBAAmB,uBAAuB,OAAO,gBAAgB;AACvE,MAAI,CAAC,kBAAkB;AACrB,WAAO;AAAA,EACT;AACA,QAAM,EAAE,kBAAkB,UAAU,GAAG,KAAK,IAAI;AAChD,SAAO,EAAE,GAAG,MAAM,aAAa,OAAO,KAAK,gBAAgB,EAAE,KAAK,EAAE;AACtE;AAEA,SAAS,oBAAoB,KAAqE;AAChG,SAAO;AAAA,IACL,IAAI,IAAI;AAAA,IACR,WAAW,IAAI;AAAA,IACf,aAAa,IAAI;AAAA,IACjB,UAAU,IAAI;AAAA,IACd,eAAe,IAAI;AAAA,IACnB,aAAa,IAAI;AAAA,IACjB,mBAAmB,IAAI;AAAA,IACvB,QAAQ,IAAI;AAAA,IACZ,QAAQ,IAAI;AAAA,IACZ,eAAe,IAAI;AAAA,IACnB,eAAe,IAAI;AAAA,IACnB,UAAU,IAAI;AAAA,IACd,WAAW,IAAI,UAAU,YAAY;AAAA,IACrC,WAAW,IAAI,UAAU,YAAY;AAAA,EACvC;AACF;AAEA,SAAS,UAAU,KAAiD;AAClE,SAAO;AAAA,IACL,IAAI,IAAI;AAAA,IACR,WAAW,IAAI;AAAA,IACf,aAAa,IAAI;AAAA,IACjB,MAAM,IAAI;AAAA,IACV,QAAQ,IAAI;AAAA,IACZ,aAAa,IAAI;AAAA,IACjB,WAAW,IAAI,YAAY,IAAI,UAAU,YAAY,IAAI;AAAA,IACzD,WAAW,IAAI,YAAY,IAAI,UAAU,YAAY,IAAI;AAAA,IACzD,YAAY,IAAI,aAAa,IAAI,WAAW,YAAY,IAAI;AAAA,IAC5D,WAAW,IAAI,UAAU,YAAY;AAAA,IACrC,WAAW,IAAI,UAAU,YAAY;AAAA,EACvC;AACF;AAEA,SAAS,sBAAsB,KAAyE;AACtG,SAAO;AAAA,IACL,IAAI,IAAI;AAAA,IACR,WAAW,IAAI;AAAA,IACf,aAAa,IAAI;AAAA,IACjB,gBAAgB,IAAI;AAAA,IACpB,cAAc,IAAI;AAAA,IAClB,aAAa,IAAI;AAAA,IACjB,WAAW,IAAI,UAAU,YAAY;AAAA,IACrC,WAAW,IAAI,UAAU,YAAY;AAAA,EACvC;AACF;AAEA,SAAS,cAAc,KAAyD;AAC9E,SAAO;AAAA,IACL,IAAI,IAAI;AAAA,IACR,aAAa,IAAI;AAAA,IACjB,WAAW,IAAI;AAAA,IACf,WAAW,IAAI;AAAA,IACf,WAAW,IAAI;AAAA,IACf,UAAU,IAAI;AAAA,IACd,MAAM,IAAI;AAAA,IACV,oBAAoB,IAAI;AAAA,IACxB,kBAAkB,IAAI;AAAA,IACtB,gBAAgB,IAAI;AAAA,IACpB,YAAY,IAAI,WAAW,YAAY;AAAA,IACvC,YAAY,IAAI,WAAW,YAAY;AAAA,IACvC,qBAAqB,IAAI,sBAAsB,IAAI,oBAAoB,YAAY,IAAI;AAAA,IACvF,wBAAwB,IAAI;AAAA,EAC9B;AACF;AAEA,SAAS,cAAc,KAAyD;AAC9E,SAAO;AAAA,IACL,IAAI,IAAI;AAAA,IACR,WAAW,IAAI;AAAA,IACf,aAAa,IAAI;AAAA,IACjB,cAAc,IAAI;AAAA,IAClB,UAAU,IAAI;AAAA,IACd,gBAAgB,IAAI;AAAA,IACpB,KAAK,IAAI;AAAA,IACT,cAAc,IAAI;AAAA,IAClB,MAAM,IAAI;AAAA,IACV,aAAa,IAAI,YAAY,YAAY;AAAA,IACzC,SAAS,IAAI;AAAA,IACb,KAAK,IAAI;AAAA,IACT,WAAW,IAAI,UAAU,YAAY;AAAA,EACvC;AACF;AAEA,SAAS,kBAAkB,OAAsC;AAC/D,MAAI,CAAC,MAAM,QAAQ,KAAK,GAAG;AACzB,WAAO;AAAA,EACT;AACA,QAAM,SAAS,MAAM,OAAO,CAAC,SAAyB,OAAO,SAAS,YAAY,KAAK,KAAK,EAAE,SAAS,CAAC;AACxG,SAAO,OAAO,SAAS,IAAI,CAAC,GAAG,IAAI,IAAI,OAAO,IAAI,CAAC,SAAS,KAAK,KAAK,CAAC,CAAC,CAAC,IAAI;AAC/E;AAEA,SAAS,sBAAsB,OAAoC;AACjE,MAAI,OAAO,UAAU,YAAY,OAAO,UAAU,KAAK,KAAK,QAAQ,GAAG;AACrE,WAAO;AAAA,EACT;AACA,MAAI,OAAO,UAAU,YAAY,QAAQ,KAAK,KAAK,KAAK,OAAO,KAAK,IAAI,GAAG;AACzE,WAAO,OAAO,KAAK;AAAA,EACrB;AACA,SAAO;AACT;AAEA,SAAS,cAAc,OAAqC;AAC1D,SAAO,OAAO,UAAU,YAAY,QAAQ;AAC9C;AAEA,SAAS,uBAAuB,OAAoD;AAClF,MAAI,CAAC,SAAS,OAAO,UAAU,YAAY,MAAM,QAAQ,KAAK,GAAG;AAC/D,WAAO;AAAA,EACT;AACA,QAAM,UAAU,OAAO,QAAQ,KAAgC,EAC5D,OAAO,CAAC,UAAqC,OAAO,MAAM,CAAC,MAAM,YAAY,MAAM,CAAC,EAAE,SAAS,CAAC;AACnG,SAAO,QAAQ,SAAS,IAAI,OAAO,YAAY,OAAO,IAAI;AAC5D;AAEA,SAAS,kBAAkB,UAA4C;AACrE,QAAM,QAAQ,SAAS;AACvB,SAAO,CAAC,CAAC,SAAS,OAAO,UAAU,YAAY,YAAY,SAAS,MAAM,WAAW;AACvF;AAEA,SAAS,UAAU,OAAuB;AACxC,MAAI,OAAO;AACX,WAAS,QAAQ,GAAG,QAAQ,MAAM,QAAQ,SAAS,GAAG;AACpD,YAAQ,MAAM,WAAW,KAAK;AAC9B,WAAO,KAAK,KAAK,MAAM,QAAU;AAAA,EACnC;AACA,UAAQ,SAAS,GAAG,SAAS,EAAE,EAAE,SAAS,GAAG,GAAG,EAAE,MAAM,GAAG,CAAC;AAC9D;","names":["environmentsEncryptionKeyBytes","isCodexBilledModel","sql","row","environmentsEncryptionKeyBytes","updated"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/environment-crypto.ts","../src/event-payload-sanitizer.ts","../src/codex-token-resolver.ts"],"sourcesContent":["import type {\n AccessContext,\n AccessGrant,\n ApiKey,\n BillingBalance,\n CapabilityCatalogItem,\n CapabilityInstallation,\n CapabilityInstallationStatus,\n CapabilityKind,\n CapabilityPack,\n CapabilitySource,\n FileAsset,\n FileStatus,\n FileUploadStatus,\n ManagedAccount,\n Permission,\n PackInstallation,\n PackInstallationStatus,\n ResourceRef,\n SandboxBackend,\n SandboxOs,\n ScheduledTask,\n ScheduledTaskAgentConfig,\n ScheduledTaskOverlapPolicy,\n ScheduledTaskRun,\n ScheduledTaskRunMode,\n ScheduledTaskRunStatus,\n ScheduledTaskScheduleSpec,\n ScheduledTaskStatus,\n ScheduledTaskTriggerType,\n Session,\n SessionEvent,\n SessionEventType,\n SessionGoal,\n SessionGoalCreatedBy,\n SessionGoalStatus,\n SessionMcpServerMetadata,\n SessionStatus,\n SessionTurn,\n SessionTurnSource,\n SessionTurnStatus,\n SocialConnection,\n SocialConnectionStatus,\n SocialPost,\n SocialProvider,\n ToolRef,\n ReasoningEffort,\n UsageEvent,\n Workspace,\n WorkspaceEnvironment,\n WorkspaceEnvironmentVariableMetadata,\n WorkspaceMember,\n WorkspaceRegisteredPack,\n} from \"@opengeni/contracts\";\nimport { reasoningEffortForMetadata, CLEARED_RUN_STATE_BLOB } from \"@opengeni/contracts\";\nimport { environmentsEncryptionKeyBytes, type Settings } from \"@opengeni/config\";\nimport { isCodexBilledModel } from \"@opengeni/codex\";\n// Re-exported so consumers get the whole codex-billed detection surface (the pure\n// prefix test + the credential-aware predicates below) from a single import.\nexport { isCodexBilledModel } from \"@opengeni/codex\";\nimport { and, asc, desc, eq, gt, gte, inArray, lt, ne, sql, type SQL } from \"drizzle-orm\";\nimport type { PgDatabase } from \"drizzle-orm/pg-core\";\nimport { drizzle } from \"drizzle-orm/postgres-js\";\nimport postgres from \"postgres\";\nimport { decryptEnvironmentValue } from \"./environment-crypto\";\nimport { sanitizeEventPayload } from \"./event-payload-sanitizer\";\nimport * as schema from \"./schema\";\n\nexport { sql as dbSql } from \"drizzle-orm\";\nexport { decryptEnvironmentValue, encryptEnvironmentValue } from \"./environment-crypto\";\nexport { sanitizeEventPayload, sanitizeEventString } from \"./event-payload-sanitizer\";\n// Re-exported so external consumers can `import { migrate } from \"@opengeni/db\"`.\n// The `@opengeni/db/migrate` subpath stays available too (internal callers + the\n// db:migrate script use it). Re-exporting does NOT run migrate.ts's\n// `import.meta.main` block — that only fires when migrate.ts is the entry.\nexport { migrate, runMigrations } from \"./migrate\";\n// Step I SDK entry points for the embedded topology: a host drives migration +\n// role provisioning over an explicit admin connection + target schema. Importing\n// these does NOT run the modules' `import.meta.main` CLI blocks.\nexport { provisionRoles, type ProvisionResult, type ProvisionRolesOptions } from \"./provision-roles\";\n\n// §7.7 driver widening (Step I). `Database` is the structural, cross-driver\n// query-layer port: every helper in this file accepts `db: Database` and uses\n// only the methods present on drizzle's base `PgDatabase` (select/insert/update/\n// delete/transaction/execute). Widening from the concrete\n// `PostgresJsDatabase<typeof schema>` to `PgDatabase<any, typeof schema>` is a\n// pure TYPE change — no runtime behavior changes — that lets an embedded host\n// inject ANY drizzle pg driver handle (node-postgres, neon-http, etc.) bound to\n// OpenGeni's schema, not just the postgres-js handle `createDb` builds. The\n// `any` for the query-result HKT is deliberate: it keeps `db.execute(sql\\`…\\`)`\n// callable across drivers whose raw-result shapes differ (postgres-js returns a\n// row array; node-postgres returns `{ rows }`). The three raw `db.execute(…)`\n// reads that index a row array (`getManagedUserByEmail` here is the only\n// host-facing one — see `userLookup`) stay postgres-js-shaped for standalone;\n// `userLookup` is the injection seam for hosts on a different driver.\n// `PostgresJsDatabase<typeof schema>` is assignable to this, so standalone is\n// unaffected.\nexport type Database = PgDatabase<any, typeof schema>;\n\nexport type DbClient = {\n db: Database;\n close: () => Promise<void>;\n};\n\nexport type RlsContext = {\n accountId: string;\n workspaceId?: string | null;\n};\n\n/**\n * RLS posture for the connection OpenGeni's query layer runs over (Step I, §7.7).\n *\n * - `\"force\"` (DEFAULT — today's standalone behavior, byte-for-byte): OpenGeni\n * connects as a NON-OWNER role (`opengeni_app`) and every table carries\n * `FORCE ROW LEVEL SECURITY`, so the workspace/account GUCs set by\n * `setRlsContext` are the ONLY thing that admits rows — even the table owner\n * is subject to RLS. This is the Fork-A isolation guarantee.\n * - `\"scoped\"` (embedded Fork-B opt-in): the host runs OpenGeni's queries over a\n * role that OWNS the dedicated schema (RLS need not be forced for that role),\n * relying on the host's own tenant boundary. OpenGeni STILL emits the\n * `set_config('opengeni.account_id'/'workspace_id', …)` GUCs defensively on\n * every scoped query, so the application query path is byte-identical between\n * the two strategies and the app code is RLS-mode-agnostic. The strategy is a\n * declared posture (consumed by `provisionRoles` and as a documented\n * invariant), NOT a query-path branch — there is deliberately no `if\n * (strategy === …)` anywhere in the helpers below. Picking `\"scoped\"` does not\n * relax any GUC; it only changes which DB role the host provisions/connects as\n * and asserts that the host accepts owning the isolation boundary.\n */\nexport type RlsStrategy = \"force\" | \"scoped\";\n\n/**\n * Resolve a host-IdP/Better-Auth user *identifier* by email. Injected via\n * `createDb({ userLookup })` (Step I). UNSET → today's raw parameterized select\n * against Better Auth's `auth_users` table (see `getManagedUserByEmail`), which\n * relies on the postgres-js array-shaped `db.execute` result. An embedded host\n * whose identity lives elsewhere (a different IdP table, a different driver, or\n * a non-`auth_users` user store) injects this closure so OpenGeni never touches\n * `auth_users` directly. Returns the user id, or null when no such user exists.\n */\nexport type UserLookup = (db: Database, email: string) => Promise<string | null>;\n\nexport type CreateDbOptions = {\n /**\n * The Postgres `search_path` for this connection (Step I, §7.8 runtime half).\n * UNSET → today's behavior: NO `search_path` startup parameter is sent, so the\n * server default applies (`public` for standalone, where every table + the\n * `vector` extension + `gen_random_uuid()` live). For an embedded dedicated\n * schema, pass e.g. `\"opengeni,opengeni_private,public\"` — postgres-js sends\n * it as a per-session startup parameter (the supported, query-param-free way;\n * URL `?search_path=` is IGNORED by postgres-js). Keep `public` LAST so the\n * `vector` type and `gen_random_uuid()` (which live in `public` on the\n * pgvector image) still resolve — the SPIKE-1 live footgun.\n */\n searchPath?: string;\n /** RLS posture; defaults to `\"force\"` (today's standalone). */\n rlsStrategy?: RlsStrategy;\n /** Host-provided user-by-email resolver; unset → today's raw `auth_users` query. */\n userLookup?: UserLookup;\n /** postgres-js pool size; defaults to today's `10`. */\n max?: number;\n};\n\n/**\n * The active RLS strategy + userLookup for an injected `Database`, recorded in a\n * side WeakMap so helpers (and `getManagedUserByEmail`) can consult the host's\n * binding without changing every call signature. A handle with no recorded\n * config (e.g. one built outside `createDb`, or in a test) falls back to the\n * standalone defaults: `rlsStrategy: \"force\"`, raw `auth_users` lookup.\n */\ntype DbBinding = { rlsStrategy: RlsStrategy; userLookup?: UserLookup };\nconst dbBindings = new WeakMap<object, DbBinding>();\n\n/** The strategy bound to a handle (or the `\"force\"` default). */\nexport function rlsStrategyFor(db: Database): RlsStrategy {\n return dbBindings.get(db as unknown as object)?.rlsStrategy ?? \"force\";\n}\n\n/**\n * Run a raw SQL query and read its rows as a typed array.\n *\n * Why this exists: the Step I driver widening (`Database = PgDatabase<any, …>`)\n * deliberately sets the query-result HKT to `any` so `db.execute(…)` is callable\n * across drivers whose raw-result shapes differ (postgres-js → row array;\n * node-postgres → `{ rows }`). A side effect is that `db.execute<T>(…)` now\n * resolves to `any`, erasing the per-row element type at the call site. OpenGeni's\n * OWN internal raw queries (sandbox-lease reaping, warm-meter reads, group\n * session-id lists) ALWAYS run over the postgres-js handle `createDb` builds,\n * whose `.execute` returns an array of rows — so this helper re-applies that\n * array-of-`T` typing in ONE documented place instead of scattering casts. It is\n * NOT a cross-driver abstraction: a host on a non-array driver must override the\n * specific helper (today only `userLookup`), not call internal raw queries.\n */\nasync function rawRows<T extends Record<string, unknown>>(\n executor: Pick<Database, \"execute\">,\n query: SQL,\n): Promise<T[]> {\n const result = await executor.execute<T>(query);\n return result as unknown as T[];\n}\n\nexport function createDb(databaseUrl: string, options: CreateDbOptions = {}): DbClient {\n // `prepare: false` is REQUIRED for Azure Database for PostgreSQL Flexible\n // Server's transaction-pooling PgBouncer: postgres-js's default named prepared\n // statements (`s_N`) are bound to one backend, but a transaction pooler hands\n // each transaction a different backend, so a later `execute` intermittently\n // throws `prepared statement \"s_N\" does not exist`. Every RLS read in this\n // module (set_config + SELECT inside one db.transaction) rides on this pool, so\n // the failure surfaces as a \"worked, then didn't\" credential/permission read.\n // idle_timeout + max_lifetime recycle connections so a pooler-recycled backend\n // is never reused indefinitely; application_name aids server-side diagnostics.\n const client = postgres(databaseUrl, {\n max: options.max ?? 10,\n prepare: false,\n idle_timeout: 30,\n max_lifetime: 1800,\n // `connection` carries per-session Postgres STARTUP parameters. `application_name`\n // (always) aids server-side diagnostics; `search_path` (embedded only) is the\n // supported, query-param-free way to scope a connection to a dedicated schema —\n // postgres-js IGNORES a URL `?search_path=`. Unset searchPath → omit it so the\n // server default (`public`) is unchanged for standalone.\n connection: {\n application_name: \"opengeni\",\n ...(options.searchPath ? { search_path: options.searchPath } : {}),\n },\n });\n const db = drizzle(client, { schema });\n dbBindings.set(db as unknown as object, {\n rlsStrategy: options.rlsStrategy ?? \"force\",\n ...(options.userLookup ? { userLookup: options.userLookup } : {}),\n });\n return {\n db,\n close: async () => {\n await client.end();\n },\n };\n}\n\n/**\n * Register a host's `rlsStrategy`/`userLookup` against an externally-constructed\n * `Database` handle (e.g. one the embedded host built from its own driver and\n * injected, rather than via `createDb`). Lets the same WeakMap-backed lookups\n * work for injected handles. Standalone never calls this (it uses `createDb`).\n */\nexport function registerDbBinding(db: Database, binding: { rlsStrategy?: RlsStrategy; userLookup?: UserLookup }): void {\n dbBindings.set(db as unknown as object, {\n rlsStrategy: binding.rlsStrategy ?? \"force\",\n ...(binding.userLookup ? { userLookup: binding.userLookup } : {}),\n });\n}\n\nexport async function setRlsContext(db: Database, context: RlsContext): Promise<void> {\n // Fail loud on an empty/blank account id: a \"\" account would set an RLS GUC\n // that matches no tenant row, silently returning zero rows from every scoped\n // read (a phantom \"not found\" / \"no active subscription\"). An RLS context with\n // no account is always a bug at the call site, never a valid query scope.\n if (typeof context.accountId !== \"string\" || context.accountId.trim() === \"\") {\n throw new Error(\"setRlsContext: a non-empty accountId is required to establish an RLS context\");\n }\n await db.execute(sql`select set_config('opengeni.account_id', ${context.accountId}, true)`);\n await db.execute(sql`select set_config('opengeni.workspace_id', ${context.workspaceId ?? \"\"}, true)`);\n}\n\nexport async function withRlsContext<T>(\n db: Database,\n context: RlsContext,\n fn: (db: Database) => Promise<T>,\n): Promise<T> {\n return await db.transaction(async (tx) => {\n const scoped = tx as unknown as Database;\n await setRlsContext(scoped, context);\n // Defense-in-depth: read the LOCAL GUC back on THIS backend BEFORE running\n // the scoped query. The set_config and this read share one db.transaction,\n // which a transaction pooler pins to a single backend — so a mismatch here\n // means the context was genuinely lost (a torn transaction / pooler backend\n // swap), not normal operation. Without this guard such an event runs the\n // scoped read with an empty account_id and returns zero RLS-visible rows,\n // manufacturing a phantom \"no active subscription\" from a credential that is\n // in fact active. Convert that silent false into a loud, root-cause-bearing\n // error so the caller can retry rather than permanently mis-decide.\n const applied = await tx.execute<{ account_id: string | null }>(\n sql`select current_setting('opengeni.account_id', true) as account_id`,\n );\n const appliedAccountId = applied[0]?.account_id ?? \"\";\n if (appliedAccountId !== context.accountId) {\n throw new Error(\n `RLS context not applied on the active backend: expected account ${context.accountId}, got \"${appliedAccountId}\"`,\n );\n }\n return await fn(scoped);\n });\n}\n\nexport async function rlsContextForWorkspace(db: Database, workspaceId: string): Promise<RlsContext> {\n const [row] = await db.select({ accountId: schema.workspaces.accountId })\n .from(schema.workspaces)\n .where(eq(schema.workspaces.id, workspaceId))\n .limit(1);\n if (!row) {\n throw new Error(`Workspace not found: ${workspaceId}`);\n }\n return { accountId: row.accountId, workspaceId };\n}\n\nexport async function withWorkspaceRls<T>(\n db: Database,\n workspaceId: string,\n fn: (db: Database) => Promise<T>,\n): Promise<T> {\n return await withRlsContext(db, await rlsContextForWorkspace(db, workspaceId), fn);\n}\n\nexport async function withWorkspaceUsageLock<T>(\n db: Database,\n workspaceId: string,\n fn: (db: Database) => Promise<T>,\n): Promise<T> {\n const context = await rlsContextForWorkspace(db, workspaceId);\n return await withRlsContext(db, context, async (scopedDb) => {\n await scopedDb.execute(sql`select pg_advisory_xact_lock(hashtext(${`usage:${workspaceId}`}))`);\n return await fn(scopedDb);\n });\n}\n\nexport async function withAccountRls<T>(\n db: Database,\n accountId: string,\n fn: (db: Database) => Promise<T>,\n): Promise<T> {\n return await withRlsContext(db, { accountId, workspaceId: null }, fn);\n}\n\nexport const allWorkspacePermissions: Permission[] = [\n \"workspace:read\",\n \"workspace:admin\",\n \"members:manage\",\n \"sessions:create\",\n \"sessions:read\",\n \"sessions:control\",\n \"files:upload\",\n \"files:read\",\n \"documents:manage\",\n \"documents:search\",\n \"scheduled_tasks:manage\",\n \"scheduled_tasks:run\",\n \"github:manage\",\n \"github:use\",\n \"api_keys:manage\",\n \"environments:manage\",\n \"environments:use\",\n \"mcp_servers:attach\",\n \"goals:manage\",\n \"enrollments:read\",\n \"enrollments:manage\",\n];\n\nexport const allAccountPermissions: Permission[] = [\n \"account:read\",\n \"account:admin\",\n \"members:manage\",\n \"workspace:create\",\n \"billing:read\",\n \"billing:manage\",\n \"api_keys:manage\",\n];\n\nexport type BootstrapWorkspaceInput = {\n accountExternalSource: string;\n accountExternalId: string;\n accountName: string;\n workspaceExternalSource: string;\n workspaceExternalId: string;\n workspaceName: string;\n subjectId: string;\n subjectLabel?: string;\n accountPermissions?: Permission[];\n workspacePermissions?: Permission[];\n};\n\nexport async function bootstrapWorkspace(db: Database, input: BootstrapWorkspaceInput): Promise<AccessContext> {\n return await db.transaction(async (tx) => {\n const [account] = await tx.insert(schema.managedAccounts).values({\n name: input.accountName,\n externalSource: input.accountExternalSource,\n externalId: input.accountExternalId,\n }).onConflictDoUpdate({\n target: [schema.managedAccounts.externalSource, schema.managedAccounts.externalId],\n set: {\n name: input.accountName,\n updatedAt: new Date(),\n },\n }).returning();\n if (!account) {\n throw new Error(\"Failed to bootstrap account\");\n }\n const [workspace] = await tx.insert(schema.workspaces).values({\n accountId: account.id,\n name: input.workspaceName,\n externalSource: input.workspaceExternalSource,\n externalId: input.workspaceExternalId,\n }).onConflictDoUpdate({\n target: [schema.workspaces.externalSource, schema.workspaces.externalId],\n set: {\n name: input.workspaceName,\n updatedAt: new Date(),\n },\n }).returning();\n if (!workspace) {\n throw new Error(\"Failed to bootstrap workspace\");\n }\n const workspacePermissions = input.workspacePermissions ?? allWorkspacePermissions;\n await tx.insert(schema.workspaceMemberships).values({\n accountId: account.id,\n workspaceId: workspace.id,\n subjectId: input.subjectId,\n subjectLabel: input.subjectLabel ?? null,\n role: \"owner\",\n permissions: workspacePermissions,\n }).onConflictDoUpdate({\n target: [schema.workspaceMemberships.subjectId, schema.workspaceMemberships.workspaceId],\n set: {\n subjectLabel: input.subjectLabel ?? null,\n role: \"owner\",\n permissions: workspacePermissions,\n updatedAt: new Date(),\n },\n });\n return {\n mode: input.accountExternalSource === \"opengeni:local\" ? \"local\" : \"configured\",\n subjectId: input.subjectId,\n ...(input.subjectLabel ? { subjectLabel: input.subjectLabel } : {}),\n accountGrants: [{\n accountId: account.id,\n subjectId: input.subjectId,\n ...(input.subjectLabel ? { subjectLabel: input.subjectLabel } : {}),\n role: \"owner\",\n permissions: input.accountPermissions ?? allAccountPermissions,\n }],\n workspaceGrants: [{\n workspaceId: workspace.id,\n accountId: account.id,\n subjectId: input.subjectId,\n ...(input.subjectLabel ? { subjectLabel: input.subjectLabel } : {}),\n permissions: workspacePermissions,\n }],\n defaultAccountId: account.id,\n defaultWorkspaceId: workspace.id,\n };\n });\n}\n\nexport async function ensureManagedAccessForUser(db: Database, input: {\n userId: string;\n email: string;\n name: string;\n}): Promise<AccessContext> {\n const subjectId = `user:${input.userId}`;\n const subjectLabel = input.email || input.name;\n return await db.transaction(async (tx) => {\n const [account] = await tx.insert(schema.managedAccounts).values({\n name: input.name || input.email,\n externalSource: \"better-auth:user\",\n externalId: input.userId,\n }).onConflictDoUpdate({\n target: [schema.managedAccounts.externalSource, schema.managedAccounts.externalId],\n set: {\n name: input.name || input.email,\n updatedAt: new Date(),\n },\n }).returning();\n if (!account) {\n throw new Error(\"Failed to ensure managed account\");\n }\n const [defaultWorkspace] = await tx.insert(schema.workspaces).values({\n accountId: account.id,\n name: \"Default workspace\",\n slug: \"default\",\n externalSource: \"better-auth:user\",\n externalId: `${input.userId}:default`,\n }).onConflictDoUpdate({\n target: [schema.workspaces.externalSource, schema.workspaces.externalId],\n set: {\n name: \"Default workspace\",\n updatedAt: new Date(),\n },\n }).returning();\n if (!defaultWorkspace) {\n throw new Error(\"Failed to ensure default workspace\");\n }\n await tx.insert(schema.workspaceMemberships).values({\n accountId: account.id,\n workspaceId: defaultWorkspace.id,\n subjectId,\n subjectLabel,\n role: \"owner\",\n permissions: allWorkspacePermissions,\n }).onConflictDoUpdate({\n target: [schema.workspaceMemberships.subjectId, schema.workspaceMemberships.workspaceId],\n set: {\n subjectLabel,\n role: \"owner\",\n permissions: allWorkspacePermissions,\n updatedAt: new Date(),\n },\n });\n const memberships = await tx.select({\n membership: schema.workspaceMemberships,\n workspace: schema.workspaces,\n }).from(schema.workspaceMemberships)\n .innerJoin(schema.workspaces, eq(schema.workspaceMemberships.workspaceId, schema.workspaces.id))\n .where(eq(schema.workspaceMemberships.subjectId, subjectId))\n .orderBy(desc(schema.workspaces.createdAt));\n return {\n mode: \"managed\",\n subjectId,\n subjectLabel,\n accountGrants: [{\n accountId: account.id,\n subjectId,\n subjectLabel,\n role: \"owner\",\n permissions: allAccountPermissions,\n }],\n workspaceGrants: memberships.map((row) => ({\n workspaceId: row.workspace.id,\n accountId: row.workspace.accountId,\n subjectId,\n subjectLabel,\n permissions: row.membership.permissions as Permission[],\n })),\n defaultAccountId: account.id,\n defaultWorkspaceId: defaultWorkspace.id,\n };\n });\n}\n\nexport async function getWorkspace(db: Database, workspaceId: string): Promise<Workspace | null> {\n const [row] = await db.select().from(schema.workspaces).where(eq(schema.workspaces.id, workspaceId)).limit(1);\n return row ? mapWorkspace(row) : null;\n}\n\nexport async function getManagedAccount(db: Database, accountId: string): Promise<ManagedAccount | null> {\n const [row] = await db.select().from(schema.managedAccounts).where(eq(schema.managedAccounts.id, accountId)).limit(1);\n return row ? mapAccount(row) : null;\n}\n\nexport async function requireWorkspace(db: Database, workspaceId: string): Promise<Workspace> {\n const workspace = await getWorkspace(db, workspaceId);\n if (!workspace) {\n throw new Error(`Workspace not found: ${workspaceId}`);\n }\n return workspace;\n}\n\nexport async function listWorkspacesForSubject(db: Database, subjectId: string, limit = 100): Promise<Workspace[]> {\n const rows = await db.select({ workspace: schema.workspaces }).from(schema.workspaceMemberships)\n .innerJoin(schema.workspaces, eq(schema.workspaceMemberships.workspaceId, schema.workspaces.id))\n .where(eq(schema.workspaceMemberships.subjectId, subjectId))\n .orderBy(desc(schema.workspaces.createdAt))\n .limit(limit);\n return rows.map((row) => mapWorkspace(row.workspace));\n}\n\nexport async function countWorkspacesForAccount(db: Database, accountId: string): Promise<number> {\n const [{ count } = { count: 0 }] = await db.select({\n count: sql<number>`count(*)::int`,\n }).from(schema.workspaces).where(eq(schema.workspaces.accountId, accountId));\n return Number(count);\n}\n\nexport async function createWorkspace(db: Database, input: {\n accountId: string;\n name: string;\n slug?: string | null;\n externalSource?: string | null;\n externalId?: string | null;\n agentInstructions?: string | null;\n}): Promise<Workspace> {\n const [row] = await db.insert(schema.workspaces).values({\n accountId: input.accountId,\n name: input.name,\n slug: input.slug ?? null,\n externalSource: input.externalSource ?? null,\n externalId: input.externalId ?? null,\n agentInstructions: input.agentInstructions ?? null,\n }).returning();\n if (!row) {\n throw new Error(\"Failed to create workspace\");\n }\n return mapWorkspace(row);\n}\n\nexport async function grantWorkspaceAccess(db: Database, input: {\n accountId: string;\n workspaceId: string;\n subjectId: string;\n subjectLabel?: string;\n role?: string;\n permissions: Permission[];\n}): Promise<void> {\n await db.insert(schema.workspaceMemberships).values({\n accountId: input.accountId,\n workspaceId: input.workspaceId,\n subjectId: input.subjectId,\n subjectLabel: input.subjectLabel ?? null,\n role: input.role ?? \"member\",\n permissions: input.permissions,\n }).onConflictDoUpdate({\n target: [schema.workspaceMemberships.subjectId, schema.workspaceMemberships.workspaceId],\n set: {\n subjectLabel: input.subjectLabel ?? null,\n role: input.role ?? \"member\",\n permissions: input.permissions,\n updatedAt: new Date(),\n },\n });\n}\n\nexport async function updateWorkspace(db: Database, workspaceId: string, input: {\n name?: string;\n slug?: string | null;\n agentInstructions?: string | null;\n}): Promise<Workspace> {\n const [row] = await db.update(schema.workspaces).set({\n ...(input.name !== undefined ? { name: input.name } : {}),\n ...(input.slug !== undefined ? { slug: input.slug } : {}),\n ...(input.agentInstructions !== undefined ? { agentInstructions: input.agentInstructions } : {}),\n updatedAt: new Date(),\n }).where(eq(schema.workspaces.id, workspaceId)).returning();\n if (!row) {\n throw new Error(`Workspace not found: ${workspaceId}`);\n }\n return mapWorkspace(row);\n}\n\nexport async function getWorkspaceGrant(db: Database, subjectId: string, workspaceId: string): Promise<AccessGrant | null> {\n const [row] = await db.select({\n membership: schema.workspaceMemberships,\n workspace: schema.workspaces,\n }).from(schema.workspaceMemberships)\n .innerJoin(schema.workspaces, eq(schema.workspaceMemberships.workspaceId, schema.workspaces.id))\n .where(and(eq(schema.workspaceMemberships.subjectId, subjectId), eq(schema.workspaceMemberships.workspaceId, workspaceId)))\n .limit(1);\n return row ? {\n workspaceId: row.workspace.id,\n accountId: row.workspace.accountId,\n subjectId: row.membership.subjectId,\n ...(row.membership.subjectLabel ? { subjectLabel: row.membership.subjectLabel } : {}),\n permissions: row.membership.permissions as Permission[],\n } : null;\n}\n\nexport async function listWorkspaceMembers(db: Database, workspaceId: string): Promise<WorkspaceMember[]> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const rows = await scopedDb.select().from(schema.workspaceMemberships)\n .where(eq(schema.workspaceMemberships.workspaceId, workspaceId))\n .orderBy(asc(schema.workspaceMemberships.createdAt));\n return rows.map(mapWorkspaceMember);\n });\n}\n\nexport async function removeWorkspaceMember(db: Database, workspaceId: string, subjectId: string): Promise<boolean> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const rows = await scopedDb.delete(schema.workspaceMemberships)\n .where(and(eq(schema.workspaceMemberships.workspaceId, workspaceId), eq(schema.workspaceMemberships.subjectId, subjectId)))\n .returning({ id: schema.workspaceMemberships.id });\n return rows.length > 0;\n });\n}\n\n/**\n * Resolve a managed user email to its user id.\n *\n * STANDALONE (default, unchanged): the `auth_users` table is owned by Better\n * Auth and is NOT in the Drizzle schema, so this runs the raw parameterized\n * select below — matching emails case-insensitively, returning the id or null.\n *\n * EMBEDDED (Step I `userLookup` port): when the handle was built via\n * `createDb({ userLookup })` (or registered with `registerDbBinding`), this\n * delegates to the host's resolver instead — so a host whose identity lives in\n * a different IdP/table/driver never forces OpenGeni to touch `auth_users`. The\n * raw query also assumes the postgres-js array-shaped `db.execute` result; the\n * port is the cross-driver escape hatch for that too.\n *\n * Used to add an already-registered user to a workspace; email invites for\n * unknown users are deferred.\n */\nexport async function getManagedUserByEmail(db: Database, email: string): Promise<string | null> {\n const binding = dbBindings.get(db as unknown as object);\n if (binding?.userLookup) {\n return await binding.userLookup(db, email);\n }\n const rows = await db.execute(sql<{ id: string }>`\n select id from auth_users where lower(email) = lower(${email}) limit 1\n `);\n return ((rows as unknown as Array<{ id?: string }>)[0]?.id) ?? null;\n}\n\nexport async function deleteWorkspace(db: Database, workspaceId: string): Promise<void> {\n await db.delete(schema.workspaces).where(eq(schema.workspaces.id, workspaceId));\n}\n\nexport async function createApiKey(db: Database, input: {\n accountId: string;\n workspaceId?: string | null;\n name: string;\n prefix: string;\n keyHash: string;\n permissions: Permission[];\n expiresAt?: Date | null;\n}): Promise<ApiKey> {\n return await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId ?? null }, async (scopedDb) => {\n const [row] = await scopedDb.insert(schema.apiKeys).values({\n accountId: input.accountId,\n workspaceId: input.workspaceId ?? null,\n name: input.name,\n prefix: input.prefix,\n keyHash: input.keyHash,\n permissions: input.permissions,\n expiresAt: input.expiresAt ?? null,\n }).returning();\n if (!row) {\n throw new Error(\"Failed to create API key\");\n }\n return mapApiKey(row);\n });\n}\n\nexport async function listApiKeys(db: Database, workspaceId: string): Promise<ApiKey[]> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const rows = await scopedDb.select().from(schema.apiKeys)\n .where(eq(schema.apiKeys.workspaceId, workspaceId))\n .orderBy(desc(schema.apiKeys.createdAt));\n return rows.map(mapApiKey);\n });\n}\n\nexport async function countActiveApiKeysForWorkspace(db: Database, workspaceId: string): Promise<number> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const [{ count } = { count: 0 }] = await scopedDb.select({\n count: sql<number>`count(*)::int`,\n }).from(schema.apiKeys)\n .where(and(eq(schema.apiKeys.workspaceId, workspaceId), sql`${schema.apiKeys.revokedAt} is null`, sql`(${schema.apiKeys.expiresAt} is null or ${schema.apiKeys.expiresAt} > now())`));\n return Number(count);\n });\n}\n\nexport async function revokeApiKey(db: Database, workspaceId: string, apiKeyId: string): Promise<ApiKey> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const [row] = await scopedDb.update(schema.apiKeys).set({\n revokedAt: new Date(),\n updatedAt: new Date(),\n }).where(and(eq(schema.apiKeys.workspaceId, workspaceId), eq(schema.apiKeys.id, apiKeyId))).returning();\n if (!row) {\n throw new Error(`API key not found: ${apiKeyId}`);\n }\n return mapApiKey(row);\n });\n}\n\nexport async function findActiveApiKeyByHash(db: Database, keyHash: string): Promise<ApiKey | null> {\n return await db.transaction(async (tx) => {\n await tx.execute(sql`select set_config('opengeni.api_key_hash', ${keyHash}, true)`);\n const [row] = await tx.select().from(schema.apiKeys)\n .where(and(eq(schema.apiKeys.keyHash, keyHash), sql`${schema.apiKeys.revokedAt} is null`, sql`(${schema.apiKeys.expiresAt} is null or ${schema.apiKeys.expiresAt} > now())`))\n .limit(1);\n if (!row) {\n return null;\n }\n const now = new Date();\n await tx.update(schema.apiKeys).set({ lastUsedAt: now, updatedAt: now }).where(eq(schema.apiKeys.id, row.id));\n return mapApiKey({ ...row, lastUsedAt: now });\n });\n}\n\nexport type GitHubInstallation = {\n id: string;\n accountId: string;\n workspaceId: string;\n installationId: number;\n accountLogin: string | null;\n accountType: string | null;\n createdAt: string;\n updatedAt: string;\n};\n\nexport async function upsertGitHubInstallation(db: Database, input: {\n accountId: string;\n workspaceId: string;\n installationId: number;\n accountLogin?: string | null;\n accountType?: string | null;\n}): Promise<GitHubInstallation> {\n return await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId }, async (scopedDb) => {\n const [row] = await scopedDb.insert(schema.githubInstallations).values({\n accountId: input.accountId,\n workspaceId: input.workspaceId,\n installationId: input.installationId,\n accountLogin: input.accountLogin ?? null,\n accountType: input.accountType ?? null,\n }).onConflictDoUpdate({\n target: [schema.githubInstallations.workspaceId, schema.githubInstallations.installationId],\n set: {\n accountId: input.accountId,\n accountLogin: input.accountLogin ?? null,\n accountType: input.accountType ?? null,\n updatedAt: new Date(),\n },\n }).returning();\n if (!row) {\n throw new Error(\"Failed to upsert GitHub installation\");\n }\n return mapGitHubInstallation(row);\n });\n}\n\nexport async function listGitHubInstallationsForWorkspace(db: Database, workspaceId: string): Promise<GitHubInstallation[]> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const rows = await scopedDb.select().from(schema.githubInstallations)\n .where(eq(schema.githubInstallations.workspaceId, workspaceId))\n .orderBy(desc(schema.githubInstallations.updatedAt));\n return rows.map(mapGitHubInstallation);\n });\n}\n\nexport async function listGitHubInstallationIdsForWorkspace(db: Database, workspaceId: string): Promise<number[]> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const rows = await scopedDb.select({ installationId: schema.githubInstallations.installationId })\n .from(schema.githubInstallations)\n .where(eq(schema.githubInstallations.workspaceId, workspaceId))\n .orderBy(desc(schema.githubInstallations.updatedAt));\n return rows.map((row) => row.installationId);\n });\n}\n\nexport async function recordUsageEvent(db: Database, input: {\n accountId: string;\n workspaceId: string;\n subjectId?: string | null;\n eventType: string;\n quantity: number;\n unit: string;\n sourceResourceType?: string | null;\n sourceResourceId?: string | null;\n idempotencyKey: string;\n occurredAt?: Date;\n}): Promise<UsageEvent> {\n return await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId }, async (scopedDb) => {\n const [row] = await scopedDb.insert(schema.usageEvents).values({\n accountId: input.accountId,\n workspaceId: input.workspaceId,\n subjectId: input.subjectId ?? null,\n eventType: input.eventType,\n quantity: input.quantity,\n unit: input.unit,\n sourceResourceType: input.sourceResourceType ?? null,\n sourceResourceId: input.sourceResourceId ?? null,\n idempotencyKey: input.idempotencyKey,\n occurredAt: input.occurredAt ?? new Date(),\n }).onConflictDoNothing({ target: schema.usageEvents.idempotencyKey }).returning();\n if (row) {\n return mapUsageEvent(row);\n }\n const [existing] = await scopedDb.select().from(schema.usageEvents).where(eq(schema.usageEvents.idempotencyKey, input.idempotencyKey)).limit(1);\n if (!existing) {\n throw new Error(\"Failed to record usage event\");\n }\n return mapUsageEvent(existing);\n });\n}\n\nexport async function listUsageEvents(db: Database, input: {\n accountId: string;\n workspaceId?: string;\n limit?: number;\n}): Promise<UsageEvent[]> {\n return await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId ?? null }, async (scopedDb) => {\n const rows = await scopedDb.select().from(schema.usageEvents)\n .where(input.workspaceId\n ? and(eq(schema.usageEvents.accountId, input.accountId), eq(schema.usageEvents.workspaceId, input.workspaceId))\n : eq(schema.usageEvents.accountId, input.accountId))\n .orderBy(desc(schema.usageEvents.occurredAt), desc(schema.usageEvents.recordedAt))\n .limit(input.limit ?? 100);\n return rows.map(mapUsageEvent);\n });\n}\n\nexport async function sumUsageQuantity(db: Database, input: {\n accountId?: string;\n workspaceId?: string;\n eventType: string;\n since?: Date;\n}): Promise<number> {\n const context = input.workspaceId\n ? await rlsContextForWorkspace(db, input.workspaceId)\n : input.accountId\n ? { accountId: input.accountId, workspaceId: null }\n : null;\n if (!context) {\n throw new Error(\"Usage quantity queries require accountId or workspaceId\");\n }\n return await withRlsContext(db, context, async (scopedDb) => {\n const clauses = [\n eq(schema.usageEvents.eventType, input.eventType),\n ...(input.accountId ? [eq(schema.usageEvents.accountId, input.accountId)] : []),\n ...(input.workspaceId ? [eq(schema.usageEvents.workspaceId, input.workspaceId)] : []),\n ...(input.since ? [gt(schema.usageEvents.occurredAt, input.since)] : []),\n ];\n const [{ total } = { total: 0 }] = await scopedDb.select({\n total: sql<number>`coalesce(sum(${schema.usageEvents.quantity}), 0)`,\n }).from(schema.usageEvents).where(and(...clauses));\n return Number(total);\n });\n}\n\nexport async function applyCreditLedgerEntry(db: Database, input: {\n accountId: string;\n workspaceId?: string | null;\n type: string;\n amountMicros: number;\n sourceType?: string | null;\n sourceId?: string | null;\n idempotencyKey: string;\n metadata?: Record<string, unknown>;\n occurredAt?: Date;\n}): Promise<BillingBalance> {\n return await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId ?? null }, async (scopedDb) => {\n await scopedDb.insert(schema.creditLedgerEntries).values({\n accountId: input.accountId,\n workspaceId: input.workspaceId ?? null,\n type: input.type,\n amountMicros: input.amountMicros,\n sourceType: input.sourceType ?? null,\n sourceId: input.sourceId ?? null,\n idempotencyKey: input.idempotencyKey,\n metadata: input.metadata ?? {},\n occurredAt: input.occurredAt ?? new Date(),\n }).onConflictDoNothing({ target: schema.creditLedgerEntries.idempotencyKey });\n return await getBillingBalance(scopedDb, input.accountId);\n });\n}\n\nexport async function applyCreditDebitUpToBalance(db: Database, input: {\n accountId: string;\n workspaceId?: string | null;\n type: string;\n requestedAmountMicros: number;\n sourceType?: string | null;\n sourceId?: string | null;\n idempotencyKey: string;\n metadata?: Record<string, unknown>;\n occurredAt?: Date;\n}): Promise<{ balance: BillingBalance; debitedMicros: number }> {\n if (input.requestedAmountMicros <= 0) {\n return { balance: await getBillingBalance(db, input.accountId), debitedMicros: 0 };\n }\n return await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId ?? null }, async (scopedDb) => {\n await scopedDb.execute(sql`select pg_advisory_xact_lock(hashtext(${input.accountId}))`);\n const before = await getBillingBalance(scopedDb, input.accountId);\n const debitedMicros = Math.min(input.requestedAmountMicros, Math.max(0, before.balanceMicros));\n if (debitedMicros > 0) {\n await scopedDb.insert(schema.creditLedgerEntries).values({\n accountId: input.accountId,\n workspaceId: input.workspaceId ?? null,\n type: input.type,\n amountMicros: -debitedMicros,\n sourceType: input.sourceType ?? null,\n sourceId: input.sourceId ?? null,\n idempotencyKey: input.idempotencyKey,\n metadata: {\n ...input.metadata,\n requestedAmountMicros: input.requestedAmountMicros,\n debitedMicros,\n },\n occurredAt: input.occurredAt ?? new Date(),\n }).onConflictDoNothing({ target: schema.creditLedgerEntries.idempotencyKey });\n }\n return { balance: await getBillingBalance(scopedDb, input.accountId), debitedMicros };\n });\n}\n\nexport async function hasCreditLedgerEntry(db: Database, accountId: string, idempotencyKey: string): Promise<boolean> {\n return await withAccountRls(db, accountId, async (scopedDb) => {\n const [row] = await scopedDb.select({ id: schema.creditLedgerEntries.id })\n .from(schema.creditLedgerEntries)\n .where(and(eq(schema.creditLedgerEntries.accountId, accountId), eq(schema.creditLedgerEntries.idempotencyKey, idempotencyKey)))\n .limit(1);\n return Boolean(row);\n });\n}\n\nexport async function getBillingCustomer(db: Database, accountId: string, provider = \"stripe\"): Promise<{\n accountId: string;\n provider: string;\n providerCustomerId: string;\n email: string | null;\n} | null> {\n return await withAccountRls(db, accountId, async (scopedDb) => {\n const [row] = await scopedDb.select().from(schema.billingCustomers)\n .where(and(eq(schema.billingCustomers.accountId, accountId), eq(schema.billingCustomers.provider, provider)))\n .limit(1);\n return row ? {\n accountId: row.accountId,\n provider: row.provider,\n providerCustomerId: row.providerCustomerId,\n email: row.email,\n } : null;\n });\n}\n\nexport async function upsertBillingCustomer(db: Database, input: {\n accountId: string;\n provider?: string;\n providerCustomerId: string;\n email?: string | null;\n}): Promise<void> {\n await withAccountRls(db, input.accountId, async (scopedDb) => {\n await scopedDb.insert(schema.billingCustomers).values({\n accountId: input.accountId,\n provider: input.provider ?? \"stripe\",\n providerCustomerId: input.providerCustomerId,\n email: input.email ?? null,\n }).onConflictDoUpdate({\n target: [schema.billingCustomers.accountId, schema.billingCustomers.provider],\n set: {\n providerCustomerId: input.providerCustomerId,\n email: input.email ?? null,\n updatedAt: new Date(),\n },\n });\n });\n}\n\nexport async function recordStripeWebhookEvent(db: Database, input: {\n id: string;\n type: string;\n livemode: boolean;\n payload: unknown;\n}): Promise<boolean> {\n const [row] = await db.insert(schema.stripeWebhookEvents).values({\n id: input.id,\n type: input.type,\n livemode: String(input.livemode),\n payload: input.payload,\n }).onConflictDoNothing({ target: schema.stripeWebhookEvents.id }).returning({ id: schema.stripeWebhookEvents.id });\n return Boolean(row);\n}\n\nexport async function isStripeWebhookProcessed(db: Database, id: string): Promise<boolean> {\n const [row] = await db.select({ processedAt: schema.stripeWebhookEvents.processedAt })\n .from(schema.stripeWebhookEvents)\n .where(eq(schema.stripeWebhookEvents.id, id))\n .limit(1);\n return Boolean(row?.processedAt);\n}\n\nexport async function markStripeWebhookProcessed(db: Database, id: string): Promise<void> {\n await db.update(schema.stripeWebhookEvents).set({ processedAt: new Date() }).where(eq(schema.stripeWebhookEvents.id, id));\n}\n\nexport async function getBillingBalance(db: Database, accountId: string): Promise<BillingBalance> {\n return await withAccountRls(db, accountId, async (scopedDb) => {\n const [{ balance } = { balance: 0 }] = await scopedDb.select({\n balance: sql<number>`coalesce(sum(${schema.creditLedgerEntries.amountMicros}), 0)`,\n }).from(schema.creditLedgerEntries).where(eq(schema.creditLedgerEntries.accountId, accountId));\n return {\n accountId,\n balanceMicros: Number(balance),\n currency: \"usd\",\n updatedAt: new Date().toISOString(),\n };\n });\n}\n\nexport async function countScheduledTasksForWorkspace(db: Database, workspaceId: string): Promise<number> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const [{ count } = { count: 0 }] = await scopedDb.select({\n count: sql<number>`count(*)::int`,\n }).from(schema.scheduledTasks).where(eq(schema.scheduledTasks.workspaceId, workspaceId));\n return Number(count);\n });\n}\n\nexport type AppendEventInput = {\n type: SessionEventType;\n payload?: unknown;\n clientEventId?: string;\n turnId?: string | null;\n producerId?: string;\n producerSeq?: number;\n occurredAt?: Date;\n};\n\nexport type CreateScheduledTaskInput = {\n id?: string;\n accountId: string;\n workspaceId: string;\n name: string;\n status: ScheduledTaskStatus;\n schedule: ScheduledTaskScheduleSpec;\n temporalScheduleId: string;\n runMode: ScheduledTaskRunMode;\n overlapPolicy: ScheduledTaskOverlapPolicy;\n agentConfig: ScheduledTaskAgentConfig;\n environmentId?: string | null;\n metadata: Record<string, unknown>;\n};\n\nexport type UpdateScheduledTaskInput = Partial<{\n name: string;\n status: ScheduledTaskStatus;\n schedule: ScheduledTaskScheduleSpec;\n runMode: ScheduledTaskRunMode;\n overlapPolicy: ScheduledTaskOverlapPolicy;\n agentConfig: ScheduledTaskAgentConfig;\n reusableSessionId: string | null;\n environmentId: string | null;\n metadata: Record<string, unknown>;\n}>;\n\nexport type CreatePackInstallationInput = {\n accountId: string;\n workspaceId: string;\n packId: string;\n metadata?: Record<string, unknown>;\n};\n\nexport type RegisterWorkspacePackInput = {\n accountId: string;\n workspaceId: string;\n pack: CapabilityPack;\n};\n\nexport type CreateSocialConnectionInput = {\n accountId: string;\n workspaceId: string;\n provider: SocialProvider;\n accountHandle: string;\n accountName?: string | null;\n externalAccountId?: string | null;\n status: SocialConnectionStatus;\n scopes?: string[];\n credentialRef?: string | null;\n tokenMetadata?: Record<string, unknown>;\n metadata?: Record<string, unknown>;\n};\n\nexport type CreateSocialPostInput = {\n accountId: string;\n workspaceId: string;\n connectionId: string;\n externalPostId?: string | null;\n url?: string | null;\n authorHandle?: string | null;\n text: string;\n publishedAt: Date;\n metrics?: Record<string, number>;\n raw?: Record<string, unknown>;\n};\n\nexport type CreateCapabilityCatalogItemInput = {\n accountId: string;\n workspaceId: string;\n id: string;\n kind: Exclude<CapabilityKind, \"pack\">;\n source: CapabilitySource;\n name: string;\n description?: string | null;\n category?: string;\n tags?: string[];\n homepageUrl?: string | null;\n endpointUrl?: string | null;\n installUrl?: string | null;\n authModel?: string | null;\n metadata?: Record<string, unknown>;\n};\n\nexport type EnableCapabilityInstallationInput = {\n accountId: string;\n workspaceId: string;\n capabilityId: string;\n kind: CapabilityKind;\n config?: Record<string, unknown>;\n metadata?: Record<string, unknown>;\n};\n\nexport type EnabledMcpCapabilityServer = {\n capabilityId: string;\n id: string;\n name: string;\n url: string;\n allowedTools?: string[];\n timeoutMs?: number;\n cacheToolsList?: boolean;\n /**\n * Credential request headers stored encrypted at enable time\n * (AES-256-GCM under the workspace-environments key). Decrypted only at\n * the runtime boundary that builds the MCP client; never exposed by the\n * capability API surface.\n */\n headersEncrypted?: Record<string, string>;\n};\n\nexport type CreateSessionMcpServerInput = {\n id: string;\n name?: string | null;\n url: string;\n allowedTools?: string[] | null;\n timeoutMs?: number | null;\n cacheToolsList?: boolean | null;\n headersEncrypted?: Record<string, string>;\n};\n\nexport type UpdateSessionMcpServerCredentialsInput = {\n id: string;\n headersEncrypted: Record<string, string>;\n};\n\nexport type UpdateSessionMcpServerCredentialsResult = {\n servers: SessionMcpServerMetadata[];\n missingIds: string[];\n};\n\nexport type SessionMcpServerForRun = SessionMcpServerMetadata & {\n allowedTools?: string[];\n timeoutMs?: number;\n cacheToolsList?: boolean;\n headers: Record<string, string>;\n};\n\nexport type EnqueueSessionTurnInput = {\n accountId: string;\n workspaceId: string;\n sessionId: string;\n triggerEventId: string;\n temporalWorkflowId: string;\n source: SessionTurnSource;\n prompt: string;\n resources: ResourceRef[];\n tools: ToolRef[];\n model: string;\n reasoningEffort: ReasoningEffort;\n sandboxBackend: SandboxBackend;\n metadata: Record<string, unknown>;\n};\n\nexport type UpdateQueuedSessionTurnInput = Partial<{\n prompt: string;\n resources: ResourceRef[];\n tools: ToolRef[];\n model: string;\n reasoningEffort: ReasoningEffort;\n sandboxBackend: SandboxBackend;\n metadata: Record<string, unknown>;\n}>;\n\nexport async function createFileUpload(db: Database, input: {\n accountId: string;\n workspaceId: string;\n fileId: string;\n filename: string;\n safeFilename: string;\n contentType: string;\n sizeBytes: number;\n sha256?: string | null;\n bucket: string;\n objectKey: string;\n expiresAt: Date;\n}): Promise<{ file: FileAsset; uploadId: string; expiresAt: string }> {\n return await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId }, async (scopedDb) => await scopedDb.transaction(async (tx) => {\n const [fileRow] = await tx.insert(schema.files).values({\n id: input.fileId,\n accountId: input.accountId,\n workspaceId: input.workspaceId,\n filename: input.filename,\n safeFilename: input.safeFilename,\n contentType: input.contentType,\n sizeBytes: input.sizeBytes,\n sha256: input.sha256 ?? null,\n bucket: input.bucket,\n objectKey: input.objectKey,\n status: \"pending_upload\",\n }).returning();\n if (!fileRow) {\n throw new Error(\"Failed to create file\");\n }\n const [uploadRow] = await tx.insert(schema.fileUploads).values({\n accountId: input.accountId,\n workspaceId: input.workspaceId,\n fileId: fileRow.id,\n status: \"pending\",\n expiresAt: input.expiresAt,\n }).returning({ id: schema.fileUploads.id, expiresAt: schema.fileUploads.expiresAt });\n if (!uploadRow) {\n throw new Error(\"Failed to create file upload\");\n }\n return {\n file: mapFile(fileRow),\n uploadId: uploadRow.id,\n expiresAt: uploadRow.expiresAt.toISOString(),\n };\n }));\n}\n\nexport async function getFile(db: Database, workspaceId: string, fileId: string): Promise<FileAsset | null> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const [row] = await scopedDb.select().from(schema.files).where(and(eq(schema.files.workspaceId, workspaceId), eq(schema.files.id, fileId))).limit(1);\n return row ? mapFile(row) : null;\n });\n}\n\nexport async function requireFile(db: Database, workspaceId: string, fileId: string): Promise<FileAsset> {\n const file = await getFile(db, workspaceId, fileId);\n if (!file) {\n throw new Error(`File not found: ${fileId}`);\n }\n return file;\n}\n\nexport async function getFileUpload(db: Database, workspaceId: string, uploadId: string): Promise<{ id: string; status: FileUploadStatus; expiresAt: Date; file: FileAsset } | null> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const [row] = await scopedDb.select({\n id: schema.fileUploads.id,\n status: schema.fileUploads.status,\n expiresAt: schema.fileUploads.expiresAt,\n file: schema.files,\n }).from(schema.fileUploads)\n .innerJoin(schema.files, eq(schema.fileUploads.fileId, schema.files.id))\n .where(and(eq(schema.fileUploads.workspaceId, workspaceId), eq(schema.fileUploads.id, uploadId)))\n .limit(1);\n return row ? {\n id: row.id,\n status: row.status as FileUploadStatus,\n expiresAt: row.expiresAt,\n file: mapFile(row.file),\n } : null;\n });\n}\n\nexport async function completeFileUpload(db: Database, workspaceId: string, uploadId: string): Promise<FileAsset> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => await scopedDb.transaction(async (tx) => {\n const [uploadRow] = await tx.select().from(schema.fileUploads).where(and(eq(schema.fileUploads.workspaceId, workspaceId), eq(schema.fileUploads.id, uploadId))).for(\"update\").limit(1);\n if (!uploadRow) {\n throw new Error(`File upload not found: ${uploadId}`);\n }\n const [fileRow] = await tx.select().from(schema.files).where(and(eq(schema.files.workspaceId, workspaceId), eq(schema.files.id, uploadRow.fileId))).for(\"update\").limit(1);\n if (!fileRow) {\n throw new Error(`File not found for upload: ${uploadId}`);\n }\n const now = new Date();\n const [updatedFile] = await tx.update(schema.files).set({\n status: \"ready\",\n updatedAt: now,\n }).where(and(eq(schema.files.workspaceId, workspaceId), eq(schema.files.id, fileRow.id))).returning();\n await tx.update(schema.fileUploads).set({\n status: \"completed\",\n completedAt: now,\n updatedAt: now,\n }).where(and(eq(schema.fileUploads.workspaceId, workspaceId), eq(schema.fileUploads.id, uploadId)));\n if (!updatedFile) {\n throw new Error(\"Failed to complete file upload\");\n }\n return mapFile(updatedFile);\n }));\n}\n\nexport async function markFileUploadFailed(db: Database, workspaceId: string, uploadId: string, fileId: string): Promise<void> {\n const now = new Date();\n await withWorkspaceRls(db, workspaceId, async (scopedDb) => await scopedDb.transaction(async (tx) => {\n await tx.update(schema.fileUploads).set({ status: \"failed\", updatedAt: now }).where(and(eq(schema.fileUploads.workspaceId, workspaceId), eq(schema.fileUploads.id, uploadId)));\n await tx.update(schema.files).set({ status: \"failed\", updatedAt: now }).where(and(eq(schema.files.workspaceId, workspaceId), eq(schema.files.id, fileId)));\n }));\n}\n\nexport async function enablePackInstallation(db: Database, input: CreatePackInstallationInput): Promise<PackInstallation> {\n return await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId }, async (scopedDb) => {\n const now = new Date();\n const existing = await getPackInstallation(scopedDb, input.workspaceId, input.packId);\n if (existing) {\n const [row] = await scopedDb.update(schema.packInstallations).set({\n status: \"active\",\n metadata: input.metadata ?? existing.metadata,\n enabledAt: now,\n updatedAt: now,\n }).where(and(eq(schema.packInstallations.workspaceId, input.workspaceId), eq(schema.packInstallations.packId, input.packId))).returning();\n if (!row) {\n throw new Error(`Pack installation not found: ${input.packId}`);\n }\n return mapPackInstallation(row);\n }\n const [row] = await scopedDb.insert(schema.packInstallations).values({\n accountId: input.accountId,\n workspaceId: input.workspaceId,\n packId: input.packId,\n status: \"active\",\n metadata: input.metadata ?? {},\n }).returning();\n if (!row) {\n throw new Error(\"Failed to enable pack installation\");\n }\n return mapPackInstallation(row);\n });\n}\n\nexport async function listPackInstallations(db: Database, workspaceId: string): Promise<PackInstallation[]> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const rows = await scopedDb.select().from(schema.packInstallations)\n .where(eq(schema.packInstallations.workspaceId, workspaceId))\n .orderBy(desc(schema.packInstallations.updatedAt));\n return rows.map(mapPackInstallation);\n });\n}\n\nexport async function getPackInstallation(db: Database, workspaceId: string, packId: string): Promise<PackInstallation | null> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const [row] = await scopedDb.select().from(schema.packInstallations)\n .where(and(eq(schema.packInstallations.workspaceId, workspaceId), eq(schema.packInstallations.packId, packId)))\n .limit(1);\n return row ? mapPackInstallation(row) : null;\n });\n}\n\nexport async function updatePackInstallationStatus(db: Database, workspaceId: string, packId: string, status: PackInstallationStatus): Promise<PackInstallation> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const [row] = await scopedDb.update(schema.packInstallations).set({\n status,\n updatedAt: new Date(),\n }).where(and(eq(schema.packInstallations.workspaceId, workspaceId), eq(schema.packInstallations.packId, packId))).returning();\n if (!row) {\n throw new Error(`Pack installation not found: ${packId}`);\n }\n return mapPackInstallation(row);\n });\n}\n\nexport async function registerWorkspacePack(db: Database, input: RegisterWorkspacePackInput): Promise<{ pack: WorkspaceRegisteredPack; created: boolean }> {\n return await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId }, async (scopedDb) => {\n const now = new Date();\n const [row] = await scopedDb.insert(schema.workspacePacks).values({\n accountId: input.accountId,\n workspaceId: input.workspaceId,\n packId: input.pack.id,\n manifest: input.pack as unknown as Record<string, unknown>,\n })\n .onConflictDoUpdate({\n target: [schema.workspacePacks.workspaceId, schema.workspacePacks.packId],\n set: {\n manifest: input.pack as unknown as Record<string, unknown>,\n updatedAt: now,\n },\n })\n .returning();\n if (!row) {\n throw new Error(\"Failed to register workspace pack\");\n }\n return { pack: mapWorkspacePack(row), created: row.createdAt.getTime() === row.updatedAt.getTime() };\n });\n}\n\nexport async function listWorkspacePacks(db: Database, workspaceId: string): Promise<WorkspaceRegisteredPack[]> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const rows = await scopedDb.select().from(schema.workspacePacks)\n .where(eq(schema.workspacePacks.workspaceId, workspaceId))\n .orderBy(asc(schema.workspacePacks.packId));\n return rows.map(mapWorkspacePack);\n });\n}\n\nexport async function getWorkspacePack(db: Database, workspaceId: string, packId: string): Promise<WorkspaceRegisteredPack | null> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const [row] = await scopedDb.select().from(schema.workspacePacks)\n .where(and(eq(schema.workspacePacks.workspaceId, workspaceId), eq(schema.workspacePacks.packId, packId)))\n .limit(1);\n return row ? mapWorkspacePack(row) : null;\n });\n}\n\nexport async function deleteWorkspacePack(db: Database, workspaceId: string, packId: string): Promise<boolean> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const rows = await scopedDb.delete(schema.workspacePacks)\n .where(and(eq(schema.workspacePacks.workspaceId, workspaceId), eq(schema.workspacePacks.packId, packId)))\n .returning({ id: schema.workspacePacks.id });\n return rows.length > 0;\n });\n}\n\nexport async function upsertCapabilityCatalogItem(db: Database, input: CreateCapabilityCatalogItemInput): Promise<CapabilityCatalogItem> {\n return await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId }, async (scopedDb) => {\n const now = new Date();\n const values = {\n id: input.id,\n accountId: input.accountId,\n workspaceId: input.workspaceId,\n kind: input.kind,\n source: input.source,\n name: input.name,\n description: input.description ?? null,\n category: input.category ?? \"custom\",\n tags: input.tags ?? [],\n homepageUrl: input.homepageUrl ?? null,\n endpointUrl: input.endpointUrl ?? null,\n installUrl: input.installUrl ?? null,\n authModel: input.authModel ?? null,\n metadata: input.metadata ?? {},\n updatedAt: now,\n };\n const updateValues = {\n kind: values.kind,\n source: values.source,\n name: values.name,\n description: values.description,\n category: values.category,\n tags: values.tags,\n homepageUrl: values.homepageUrl,\n endpointUrl: values.endpointUrl,\n installUrl: values.installUrl,\n authModel: values.authModel,\n metadata: values.metadata,\n updatedAt: values.updatedAt,\n };\n const [row] = await scopedDb.insert(schema.capabilityCatalogItems).values(values)\n .onConflictDoUpdate({\n target: [schema.capabilityCatalogItems.workspaceId, schema.capabilityCatalogItems.id],\n set: updateValues,\n })\n .returning();\n if (!row) {\n throw new Error(\"Failed to upsert capability catalog item\");\n }\n return mapCapabilityCatalogItem(row);\n });\n}\n\nexport async function listCapabilityCatalogItems(db: Database, workspaceId: string): Promise<CapabilityCatalogItem[]> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const rows = await scopedDb.select().from(schema.capabilityCatalogItems)\n .where(eq(schema.capabilityCatalogItems.workspaceId, workspaceId))\n .orderBy(asc(schema.capabilityCatalogItems.kind), asc(schema.capabilityCatalogItems.name));\n return rows.map(mapCapabilityCatalogItem);\n });\n}\n\nexport async function getCapabilityCatalogItem(db: Database, workspaceId: string, capabilityId: string): Promise<CapabilityCatalogItem | null> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const [row] = await scopedDb.select().from(schema.capabilityCatalogItems)\n .where(and(eq(schema.capabilityCatalogItems.workspaceId, workspaceId), eq(schema.capabilityCatalogItems.id, capabilityId)))\n .limit(1);\n return row ? mapCapabilityCatalogItem(row) : null;\n });\n}\n\nexport async function enableCapabilityInstallation(db: Database, input: EnableCapabilityInstallationInput): Promise<CapabilityInstallation> {\n return await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId }, async (scopedDb) => {\n const now = new Date();\n // Read the raw row (not the redacted mapping) so an omitted config\n // preserves stored credential-header ciphertext instead of the redaction.\n const [existing] = await scopedDb.select().from(schema.capabilityInstallations)\n .where(and(eq(schema.capabilityInstallations.workspaceId, input.workspaceId), eq(schema.capabilityInstallations.capabilityId, input.capabilityId)))\n .limit(1);\n if (existing) {\n const [row] = await scopedDb.update(schema.capabilityInstallations).set({\n kind: input.kind,\n status: \"active\",\n config: input.config ?? existing.config,\n metadata: input.metadata ?? existing.metadata,\n enabledAt: now,\n updatedAt: now,\n }).where(and(eq(schema.capabilityInstallations.workspaceId, input.workspaceId), eq(schema.capabilityInstallations.capabilityId, input.capabilityId))).returning();\n if (!row) {\n throw new Error(`Capability installation not found: ${input.capabilityId}`);\n }\n return mapCapabilityInstallation(row);\n }\n const [row] = await scopedDb.insert(schema.capabilityInstallations).values({\n accountId: input.accountId,\n workspaceId: input.workspaceId,\n capabilityId: input.capabilityId,\n kind: input.kind,\n status: \"active\",\n config: input.config ?? {},\n metadata: input.metadata ?? {},\n }).returning();\n if (!row) {\n throw new Error(\"Failed to enable capability installation\");\n }\n return mapCapabilityInstallation(row);\n });\n}\n\nexport async function disableCapabilityInstallation(db: Database, workspaceId: string, capabilityId: string): Promise<CapabilityInstallation> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const [row] = await scopedDb.update(schema.capabilityInstallations).set({\n status: \"disabled\",\n updatedAt: new Date(),\n }).where(and(eq(schema.capabilityInstallations.workspaceId, workspaceId), eq(schema.capabilityInstallations.capabilityId, capabilityId))).returning();\n if (!row) {\n throw new Error(`Capability installation not found: ${capabilityId}`);\n }\n return mapCapabilityInstallation(row);\n });\n}\n\nexport async function listCapabilityInstallations(db: Database, workspaceId: string): Promise<CapabilityInstallation[]> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const rows = await scopedDb.select().from(schema.capabilityInstallations)\n .where(eq(schema.capabilityInstallations.workspaceId, workspaceId))\n .orderBy(desc(schema.capabilityInstallations.updatedAt));\n return rows.map(mapCapabilityInstallation);\n });\n}\n\nexport async function getCapabilityInstallation(db: Database, workspaceId: string, capabilityId: string): Promise<CapabilityInstallation | null> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const [row] = await scopedDb.select().from(schema.capabilityInstallations)\n .where(and(eq(schema.capabilityInstallations.workspaceId, workspaceId), eq(schema.capabilityInstallations.capabilityId, capabilityId)))\n .limit(1);\n return row ? mapCapabilityInstallation(row) : null;\n });\n}\n\nexport async function listEnabledMcpCapabilityServers(db: Database, workspaceId: string): Promise<EnabledMcpCapabilityServer[]> {\n const rows = await withWorkspaceRls(db, workspaceId, async (scopedDb) => await scopedDb.select({\n item: schema.capabilityCatalogItems,\n installation: schema.capabilityInstallations,\n }).from(schema.capabilityInstallations)\n .innerJoin(schema.capabilityCatalogItems, and(\n eq(schema.capabilityInstallations.workspaceId, schema.capabilityCatalogItems.workspaceId),\n eq(schema.capabilityInstallations.capabilityId, schema.capabilityCatalogItems.id),\n ))\n .where(and(\n eq(schema.capabilityInstallations.workspaceId, workspaceId),\n eq(schema.capabilityInstallations.kind, \"mcp\"),\n eq(schema.capabilityInstallations.status, \"active\"),\n ))\n .orderBy(asc(schema.capabilityCatalogItems.name)));\n\n return rows.flatMap(({ item, installation }) => {\n if (!item.endpointUrl || !mcpConnectivityOk(installation.metadata)) {\n return [];\n }\n const headersEncrypted = encryptedHeadersConfig(installation.config.headersEncrypted);\n if (item.authModel && !headersEncrypted) {\n // Credential-gated MCPs are runnable only when credential headers were\n // stored at enable time.\n return [];\n }\n const metadata = item.metadata;\n const config = installation.config;\n const allowedTools = stringArrayConfig(config.allowedTools ?? metadata.allowedTools);\n const timeoutMs = positiveIntegerConfig(config.timeoutMs ?? metadata.timeoutMs);\n const cacheToolsList = booleanConfig(config.cacheToolsList ?? metadata.cacheToolsList);\n return [{\n capabilityId: item.id,\n id: mcpServerIdForCapability(item.id, metadata),\n name: item.name,\n url: item.endpointUrl,\n ...(allowedTools ? { allowedTools } : {}),\n ...(timeoutMs ? { timeoutMs } : {}),\n ...(cacheToolsList !== undefined ? { cacheToolsList } : {}),\n ...(headersEncrypted ? { headersEncrypted } : {}),\n }];\n });\n}\n\n/**\n * Decrypts an enabled capability MCP's stored credential headers. Returns\n * null when the server has none, and \"unavailable\" when headers exist but\n * cannot be recovered (missing key or failed decryption) — in which case the\n * server must be skipped rather than connected without credentials.\n */\nexport function decryptedCapabilityHeaders(\n server: EnabledMcpCapabilityServer,\n encryptionKey: Uint8Array | null,\n): Record<string, string> | null | \"unavailable\" {\n if (!server.headersEncrypted || Object.keys(server.headersEncrypted).length === 0) {\n return null;\n }\n if (!encryptionKey) {\n return \"unavailable\";\n }\n try {\n return Object.fromEntries(Object.entries(server.headersEncrypted).map(([name, value]) => [name, decryptEnvironmentValue(encryptionKey, value)]));\n } catch {\n return \"unavailable\";\n }\n}\n\n/**\n * Returns the encrypted credential-header map stored on a capability\n * installation, or null when none is stored. This is the only read path for\n * the ciphertext besides listEnabledMcpCapabilityServers; the generic\n * installation mapping redacts it to header names.\n */\nexport async function getStoredCapabilityHeaderCiphertext(db: Database, workspaceId: string, capabilityId: string): Promise<Record<string, string> | null> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const [row] = await scopedDb.select({ config: schema.capabilityInstallations.config }).from(schema.capabilityInstallations)\n .where(and(eq(schema.capabilityInstallations.workspaceId, workspaceId), eq(schema.capabilityInstallations.capabilityId, capabilityId)))\n .limit(1);\n return row ? encryptedHeadersConfig(row.config.headersEncrypted) ?? null : null;\n });\n}\n\nexport function mcpServerIdForCapability(capabilityId: string, metadata: Record<string, unknown> = {}): string {\n const explicit = typeof metadata.mcpServerId === \"string\" ? metadata.mcpServerId.trim() : \"\";\n if (/^[A-Za-z0-9_-]+$/.test(explicit)) {\n return explicit;\n }\n const body = capabilityId\n .replace(/^[^:]+:/, \"\")\n .toLowerCase()\n .replace(/[^a-z0-9_-]+/g, \"-\")\n .replace(/^-+|-+$/g, \"\")\n .slice(0, 44) || \"mcp\";\n return `cap-${body}-${shortHash(capabilityId)}`;\n}\n\nexport async function createSocialConnection(db: Database, input: CreateSocialConnectionInput): Promise<SocialConnection> {\n return await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId }, async (scopedDb) => {\n const [row] = await scopedDb.insert(schema.socialConnections).values({\n accountId: input.accountId,\n workspaceId: input.workspaceId,\n provider: input.provider,\n accountHandle: input.accountHandle,\n accountName: input.accountName ?? null,\n externalAccountId: input.externalAccountId ?? null,\n status: input.status,\n scopes: input.scopes ?? [],\n credentialRef: input.credentialRef ?? null,\n tokenMetadata: input.tokenMetadata ?? {},\n metadata: input.metadata ?? {},\n }).returning();\n if (!row) {\n throw new Error(\"Failed to create social connection\");\n }\n return mapSocialConnection(row);\n });\n}\n\nexport async function listSocialConnections(db: Database, workspaceId: string, limit = 100): Promise<SocialConnection[]> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const rows = await scopedDb.select().from(schema.socialConnections)\n .where(eq(schema.socialConnections.workspaceId, workspaceId))\n .orderBy(desc(schema.socialConnections.createdAt))\n .limit(limit);\n return rows.map(mapSocialConnection);\n });\n}\n\nexport async function getSocialConnection(db: Database, workspaceId: string, connectionId: string): Promise<SocialConnection | null> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const [row] = await scopedDb.select().from(schema.socialConnections)\n .where(and(eq(schema.socialConnections.workspaceId, workspaceId), eq(schema.socialConnections.id, connectionId)))\n .limit(1);\n return row ? mapSocialConnection(row) : null;\n });\n}\n\nexport async function requireSocialConnection(db: Database, workspaceId: string, connectionId: string): Promise<SocialConnection> {\n const connection = await getSocialConnection(db, workspaceId, connectionId);\n if (!connection) {\n throw new Error(`Social connection not found: ${connectionId}`);\n }\n return connection;\n}\n\nexport async function createSocialPost(db: Database, input: CreateSocialPostInput): Promise<SocialPost> {\n return await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId }, async (scopedDb) => {\n const connection = await requireSocialConnection(scopedDb, input.workspaceId, input.connectionId);\n const [row] = await scopedDb.insert(schema.socialPosts).values({\n accountId: input.accountId,\n workspaceId: input.workspaceId,\n connectionId: input.connectionId,\n provider: connection.provider,\n externalPostId: input.externalPostId ?? null,\n url: input.url ?? null,\n authorHandle: input.authorHandle ?? connection.accountHandle,\n text: input.text,\n publishedAt: input.publishedAt,\n metrics: input.metrics ?? {},\n raw: input.raw ?? {},\n }).returning();\n if (!row) {\n throw new Error(\"Failed to create social post\");\n }\n return mapSocialPost(row);\n });\n}\n\nexport async function listSocialPosts(db: Database, options: {\n workspaceId: string;\n connectionIds?: string[];\n since?: Date;\n limit?: number;\n}): Promise<SocialPost[]> {\n const conditions: SQL[] = [eq(schema.socialPosts.workspaceId, options.workspaceId)];\n if (options.connectionIds?.length) {\n conditions.push(inArray(schema.socialPosts.connectionId, options.connectionIds));\n }\n if (options.since) {\n conditions.push(gte(schema.socialPosts.publishedAt, options.since));\n }\n const limit = options.limit ?? 100;\n return await withWorkspaceRls(db, options.workspaceId, async (scopedDb) => {\n const rows = await scopedDb.select().from(schema.socialPosts)\n .where(and(...conditions))\n .orderBy(desc(schema.socialPosts.publishedAt))\n .limit(limit);\n return rows.map(mapSocialPost);\n });\n}\n\nexport async function createScheduledTask(db: Database, input: CreateScheduledTaskInput): Promise<ScheduledTask> {\n return await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId }, async (scopedDb) => {\n const [row] = await scopedDb.insert(schema.scheduledTasks).values(input).returning();\n if (!row) {\n throw new Error(\"Failed to create scheduled task\");\n }\n return mapScheduledTask(row);\n });\n}\n\nexport async function updateScheduledTask(db: Database, workspaceId: string, taskId: string, input: UpdateScheduledTaskInput): Promise<ScheduledTask> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const [row] = await scopedDb.update(schema.scheduledTasks).set({\n ...(input.name !== undefined ? { name: input.name } : {}),\n ...(input.status !== undefined ? { status: input.status } : {}),\n ...(input.schedule !== undefined ? { schedule: input.schedule } : {}),\n ...(input.runMode !== undefined ? { runMode: input.runMode } : {}),\n ...(input.overlapPolicy !== undefined ? { overlapPolicy: input.overlapPolicy } : {}),\n ...(input.agentConfig !== undefined ? { agentConfig: input.agentConfig } : {}),\n ...(input.reusableSessionId !== undefined ? { reusableSessionId: input.reusableSessionId } : {}),\n ...(input.environmentId !== undefined ? { environmentId: input.environmentId } : {}),\n ...(input.metadata !== undefined ? { metadata: input.metadata } : {}),\n updatedAt: new Date(),\n }).where(and(eq(schema.scheduledTasks.workspaceId, workspaceId), eq(schema.scheduledTasks.id, taskId))).returning();\n if (!row) {\n throw new Error(`Scheduled task not found: ${taskId}`);\n }\n return mapScheduledTask(row);\n });\n}\n\nexport async function getScheduledTask(db: Database, workspaceId: string, taskId: string): Promise<ScheduledTask | null> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const [row] = await scopedDb.select().from(schema.scheduledTasks).where(and(eq(schema.scheduledTasks.workspaceId, workspaceId), eq(schema.scheduledTasks.id, taskId))).limit(1);\n return row ? mapScheduledTask(row) : null;\n });\n}\n\nexport async function requireScheduledTask(db: Database, workspaceId: string, taskId: string): Promise<ScheduledTask> {\n const task = await getScheduledTask(db, workspaceId, taskId);\n if (!task) {\n throw new Error(`Scheduled task not found: ${taskId}`);\n }\n return task;\n}\n\nexport async function listScheduledTasks(db: Database, workspaceId: string, limit = 100): Promise<ScheduledTask[]> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const rows = await scopedDb.select().from(schema.scheduledTasks)\n .where(eq(schema.scheduledTasks.workspaceId, workspaceId))\n .orderBy(desc(schema.scheduledTasks.createdAt))\n .limit(limit);\n return rows.map(mapScheduledTask);\n });\n}\n\nexport async function deleteScheduledTask(db: Database, workspaceId: string, taskId: string): Promise<void> {\n await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n await scopedDb.delete(schema.scheduledTasks).where(and(eq(schema.scheduledTasks.workspaceId, workspaceId), eq(schema.scheduledTasks.id, taskId)));\n });\n}\n\nexport async function createScheduledTaskRun(db: Database, input: {\n workspaceId: string;\n taskId: string;\n triggerType: ScheduledTaskTriggerType;\n scheduledAt?: Date | null;\n firedAt?: Date;\n}): Promise<ScheduledTaskRun> {\n return await withWorkspaceRls(db, input.workspaceId, async (scopedDb) => {\n const [taskRow] = await scopedDb.select().from(schema.scheduledTasks)\n .where(and(eq(schema.scheduledTasks.workspaceId, input.workspaceId), eq(schema.scheduledTasks.id, input.taskId)))\n .limit(1);\n if (!taskRow) {\n throw new Error(`Scheduled task not found: ${input.taskId}`);\n }\n const [row] = await scopedDb.insert(schema.scheduledTaskRuns).values({\n accountId: taskRow.accountId,\n workspaceId: taskRow.workspaceId,\n taskId: input.taskId,\n triggerType: input.triggerType,\n scheduledAt: input.scheduledAt ?? null,\n firedAt: input.firedAt ?? new Date(),\n status: \"queued\",\n }).returning();\n if (!row) {\n throw new Error(\"Failed to create scheduled task run\");\n }\n return mapScheduledTaskRun(row);\n });\n}\n\nexport async function updateScheduledTaskRun(db: Database, workspaceId: string, runId: string, input: Partial<{\n status: ScheduledTaskRunStatus;\n sessionId: string | null;\n triggerEventId: string | null;\n error: string | null;\n}>): Promise<ScheduledTaskRun> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const [row] = await scopedDb.update(schema.scheduledTaskRuns).set({\n ...(input.status !== undefined ? { status: input.status } : {}),\n ...(input.sessionId !== undefined ? { sessionId: input.sessionId } : {}),\n ...(input.triggerEventId !== undefined ? { triggerEventId: input.triggerEventId } : {}),\n ...(input.error !== undefined ? { error: input.error } : {}),\n updatedAt: new Date(),\n }).where(and(eq(schema.scheduledTaskRuns.workspaceId, workspaceId), eq(schema.scheduledTaskRuns.id, runId))).returning();\n if (!row) {\n throw new Error(`Scheduled task run not found: ${runId}`);\n }\n return mapScheduledTaskRun(row);\n });\n}\n\nexport async function listScheduledTaskRuns(db: Database, workspaceId: string, taskId: string, limit = 100): Promise<ScheduledTaskRun[]> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const rows = await scopedDb.select().from(schema.scheduledTaskRuns)\n .where(and(eq(schema.scheduledTaskRuns.workspaceId, workspaceId), eq(schema.scheduledTaskRuns.taskId, taskId)))\n .orderBy(desc(schema.scheduledTaskRuns.createdAt))\n .limit(limit);\n return rows.map(mapScheduledTaskRun);\n });\n}\n\nexport async function createWorkspaceEnvironment(db: Database, input: {\n accountId: string;\n workspaceId: string;\n name: string;\n description?: string | null;\n variables?: Array<{ name: string; valueEncrypted: string }>;\n}): Promise<WorkspaceEnvironment> {\n // withRlsContext wraps the callback in one transaction, so the environment\n // row and all initial variables commit or roll back together.\n return await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId }, async (scopedDb) => {\n const [row] = await scopedDb.insert(schema.workspaceEnvironments).values({\n accountId: input.accountId,\n workspaceId: input.workspaceId,\n name: input.name,\n description: input.description ?? null,\n }).returning();\n if (!row) {\n throw new Error(\"Failed to create workspace environment\");\n }\n const variables = input.variables ?? [];\n if (variables.length === 0) {\n return mapWorkspaceEnvironment(row, []);\n }\n const inserted = await scopedDb.insert(schema.workspaceEnvironmentVariables).values(variables.map((variable) => ({\n accountId: input.accountId,\n workspaceId: input.workspaceId,\n environmentId: row.id,\n name: variable.name,\n valueEncrypted: variable.valueEncrypted,\n }))).returning({\n name: schema.workspaceEnvironmentVariables.name,\n version: schema.workspaceEnvironmentVariables.version,\n createdAt: schema.workspaceEnvironmentVariables.createdAt,\n updatedAt: schema.workspaceEnvironmentVariables.updatedAt,\n });\n return mapWorkspaceEnvironment(row, inserted\n .map(mapWorkspaceEnvironmentVariableMetadata)\n .sort((a, b) => a.name.localeCompare(b.name)));\n });\n}\n\nexport async function listWorkspaceEnvironments(db: Database, workspaceId: string): Promise<WorkspaceEnvironment[]> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const rows = await scopedDb.select().from(schema.workspaceEnvironments)\n .where(eq(schema.workspaceEnvironments.workspaceId, workspaceId))\n .orderBy(asc(schema.workspaceEnvironments.createdAt));\n const variableRows = await scopedDb.select({\n environmentId: schema.workspaceEnvironmentVariables.environmentId,\n name: schema.workspaceEnvironmentVariables.name,\n version: schema.workspaceEnvironmentVariables.version,\n createdAt: schema.workspaceEnvironmentVariables.createdAt,\n updatedAt: schema.workspaceEnvironmentVariables.updatedAt,\n }).from(schema.workspaceEnvironmentVariables)\n .where(eq(schema.workspaceEnvironmentVariables.workspaceId, workspaceId))\n .orderBy(asc(schema.workspaceEnvironmentVariables.name));\n const grouped = new Map<string, WorkspaceEnvironmentVariableMetadata[]>();\n for (const variable of variableRows) {\n const list = grouped.get(variable.environmentId) ?? [];\n list.push(mapWorkspaceEnvironmentVariableMetadata(variable));\n grouped.set(variable.environmentId, list);\n }\n return rows.map((row) => mapWorkspaceEnvironment(row, grouped.get(row.id) ?? []));\n });\n}\n\nexport async function getWorkspaceEnvironment(db: Database, workspaceId: string, environmentId: string): Promise<WorkspaceEnvironment | null> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const [row] = await scopedDb.select().from(schema.workspaceEnvironments)\n .where(and(eq(schema.workspaceEnvironments.workspaceId, workspaceId), eq(schema.workspaceEnvironments.id, environmentId)))\n .limit(1);\n if (!row) {\n return null;\n }\n return mapWorkspaceEnvironment(row, await listEnvironmentVariableMetadata(scopedDb, workspaceId, environmentId));\n });\n}\n\nexport async function getWorkspaceEnvironmentByName(db: Database, workspaceId: string, name: string): Promise<WorkspaceEnvironment | null> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const [row] = await scopedDb.select().from(schema.workspaceEnvironments)\n .where(and(eq(schema.workspaceEnvironments.workspaceId, workspaceId), eq(schema.workspaceEnvironments.name, name)))\n .limit(1);\n if (!row) {\n return null;\n }\n return mapWorkspaceEnvironment(row, await listEnvironmentVariableMetadata(scopedDb, workspaceId, row.id));\n });\n}\n\nexport async function updateWorkspaceEnvironment(db: Database, workspaceId: string, environmentId: string, input: {\n name?: string;\n description?: string | null;\n}): Promise<WorkspaceEnvironment> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const [row] = await scopedDb.update(schema.workspaceEnvironments).set({\n ...(input.name !== undefined ? { name: input.name } : {}),\n ...(input.description !== undefined ? { description: input.description } : {}),\n updatedAt: new Date(),\n }).where(and(eq(schema.workspaceEnvironments.workspaceId, workspaceId), eq(schema.workspaceEnvironments.id, environmentId))).returning();\n if (!row) {\n throw new Error(`Workspace environment not found: ${environmentId}`);\n }\n return mapWorkspaceEnvironment(row, await listEnvironmentVariableMetadata(scopedDb, workspaceId, environmentId));\n });\n}\n\nexport async function deleteWorkspaceEnvironment(db: Database, workspaceId: string, environmentId: string): Promise<boolean> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const rows = await scopedDb.delete(schema.workspaceEnvironments)\n .where(and(eq(schema.workspaceEnvironments.workspaceId, workspaceId), eq(schema.workspaceEnvironments.id, environmentId)))\n .returning({ id: schema.workspaceEnvironments.id });\n return rows.length > 0;\n });\n}\n\nexport async function countWorkspaceEnvironments(db: Database, workspaceId: string): Promise<number> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const [{ count } = { count: 0 }] = await scopedDb.select({\n count: sql<number>`count(*)::int`,\n }).from(schema.workspaceEnvironments).where(eq(schema.workspaceEnvironments.workspaceId, workspaceId));\n return Number(count);\n });\n}\n\nexport async function countScheduledTasksUsingEnvironment(db: Database, workspaceId: string, environmentId: string): Promise<number> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const [{ count } = { count: 0 }] = await scopedDb.select({\n count: sql<number>`count(*)::int`,\n }).from(schema.scheduledTasks)\n .where(and(eq(schema.scheduledTasks.workspaceId, workspaceId), eq(schema.scheduledTasks.environmentId, environmentId)));\n return Number(count);\n });\n}\n\nexport async function countActiveSessionsUsingEnvironment(db: Database, workspaceId: string, environmentId: string): Promise<number> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const [{ count } = { count: 0 }] = await scopedDb.select({\n count: sql<number>`count(*)::int`,\n }).from(schema.sessions)\n .where(and(\n eq(schema.sessions.workspaceId, workspaceId),\n eq(schema.sessions.environmentId, environmentId),\n inArray(schema.sessions.status, [\"queued\", \"running\", \"requires_action\"]),\n ));\n return Number(count);\n });\n}\n\nexport async function setWorkspaceEnvironmentVariable(db: Database, input: {\n accountId: string;\n workspaceId: string;\n environmentId: string;\n name: string;\n valueEncrypted: string;\n}): Promise<WorkspaceEnvironmentVariableMetadata> {\n return await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId }, async (scopedDb) => {\n const now = new Date();\n const [row] = await scopedDb.insert(schema.workspaceEnvironmentVariables).values({\n accountId: input.accountId,\n workspaceId: input.workspaceId,\n environmentId: input.environmentId,\n name: input.name,\n valueEncrypted: input.valueEncrypted,\n }).onConflictDoUpdate({\n target: [\n schema.workspaceEnvironmentVariables.workspaceId,\n schema.workspaceEnvironmentVariables.environmentId,\n schema.workspaceEnvironmentVariables.name,\n ],\n set: {\n valueEncrypted: input.valueEncrypted,\n version: sql`${schema.workspaceEnvironmentVariables.version} + 1`,\n updatedAt: now,\n },\n }).returning({\n name: schema.workspaceEnvironmentVariables.name,\n version: schema.workspaceEnvironmentVariables.version,\n createdAt: schema.workspaceEnvironmentVariables.createdAt,\n updatedAt: schema.workspaceEnvironmentVariables.updatedAt,\n });\n if (!row) {\n throw new Error(\"Failed to set workspace environment variable\");\n }\n await scopedDb.update(schema.workspaceEnvironments).set({ updatedAt: now })\n .where(and(eq(schema.workspaceEnvironments.workspaceId, input.workspaceId), eq(schema.workspaceEnvironments.id, input.environmentId)));\n return mapWorkspaceEnvironmentVariableMetadata(row);\n });\n}\n\nexport async function deleteWorkspaceEnvironmentVariable(db: Database, workspaceId: string, environmentId: string, name: string): Promise<boolean> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const rows = await scopedDb.delete(schema.workspaceEnvironmentVariables)\n .where(and(\n eq(schema.workspaceEnvironmentVariables.workspaceId, workspaceId),\n eq(schema.workspaceEnvironmentVariables.environmentId, environmentId),\n eq(schema.workspaceEnvironmentVariables.name, name),\n ))\n .returning({ id: schema.workspaceEnvironmentVariables.id });\n if (rows.length > 0) {\n await scopedDb.update(schema.workspaceEnvironments).set({ updatedAt: new Date() })\n .where(and(eq(schema.workspaceEnvironments.workspaceId, workspaceId), eq(schema.workspaceEnvironments.id, environmentId)));\n }\n return rows.length > 0;\n });\n}\n\n/**\n * The ONLY helper that selects value_encrypted. Used exclusively by the worker\n * activity that materializes a sandbox for a run whose session carries an\n * environment attachment. Do not call from API routes: values are write-only.\n */\nexport async function getWorkspaceEnvironmentValuesForRun(db: Database, workspaceId: string, environmentId: string): Promise<{\n environment: { id: string; name: string; description: string | null };\n values: Record<string, string>;\n} | null> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const [environment] = await scopedDb.select({\n id: schema.workspaceEnvironments.id,\n name: schema.workspaceEnvironments.name,\n description: schema.workspaceEnvironments.description,\n }).from(schema.workspaceEnvironments)\n .where(and(eq(schema.workspaceEnvironments.workspaceId, workspaceId), eq(schema.workspaceEnvironments.id, environmentId)))\n .limit(1);\n if (!environment) {\n return null;\n }\n const rows = await scopedDb.select({\n name: schema.workspaceEnvironmentVariables.name,\n valueEncrypted: schema.workspaceEnvironmentVariables.valueEncrypted,\n }).from(schema.workspaceEnvironmentVariables)\n .where(and(\n eq(schema.workspaceEnvironmentVariables.workspaceId, workspaceId),\n eq(schema.workspaceEnvironmentVariables.environmentId, environmentId),\n ));\n return {\n environment: { id: environment.id, name: environment.name, description: environment.description },\n values: Object.fromEntries(rows.map((row) => [row.name, row.valueEncrypted])),\n };\n });\n}\n\nexport type WorkspaceEnvironmentForRun = {\n id: string;\n name: string;\n description: string | null;\n values: Record<string, string>;\n};\n\n/**\n * Load and decrypt the workspace environment attached to a run's session. SHARED\n * by the worker TURN path (apps/worker agent-turn) AND the API-direct ATTACH paths\n * (viewer / Channel-A / desktop / terminal) so a box first warmed by an attach is\n * created with the SAME decrypted workspace-environment values the turn declares —\n * the box-manifest env must match the agent-manifest env or the SDK's\n * `validateNoEnvironmentDelta` throws when the agent injects its manifest into the\n * resumed non-owned box.\n *\n * `environmentId === null` is the unattached path: zero DB work and behavior\n * byte-identical to deployments without this feature. Attached runs fail closed: a\n * missing key or a deleted environment throws (names/ids only in messages) instead\n * of silently running without the secrets the run expects.\n */\nexport async function loadWorkspaceEnvironmentForRun(\n db: Database,\n settings: Settings,\n workspaceId: string,\n environmentId: string | null,\n): Promise<WorkspaceEnvironmentForRun | null> {\n if (!environmentId) {\n return null;\n }\n const key = environmentsEncryptionKeyBytes(settings);\n if (!key) {\n throw new Error(\"workspace environment attached but OPENGENI_ENVIRONMENTS_ENCRYPTION_KEY is not configured\");\n }\n const stored = await getWorkspaceEnvironmentValuesForRun(db, workspaceId, environmentId);\n if (!stored) {\n throw new Error(`workspace environment not found: ${environmentId}`);\n }\n const values: Record<string, string> = {};\n for (const [name, encrypted] of Object.entries(stored.values)) {\n try {\n values[name] = decryptEnvironmentValue(key, encrypted);\n } catch (error) {\n const reason = error instanceof Error ? error.message : String(error);\n throw new Error(`failed to decrypt workspace environment variable ${name}: ${reason}`);\n }\n }\n return {\n id: stored.environment.id,\n name: stored.environment.name,\n description: stored.environment.description,\n values,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Codex (ChatGPT) subscription credentials\n//\n// One row per workspace. Secret tokens live inside `credential_encrypted` (v1\n// AES-256-GCM, same envelope as workspace env vars). The caller pre-encrypts the\n// JSON bundle {access_token, refresh_token, id_token} — the db layer never sees\n// plaintext token JSON on the write path. `loadCodexCredentialForRun` is the\n// ONLY decrypt-read accessor and must never be called from an API route;\n// `getCodexCredentialStatus` returns metadata only (never the secret column).\n// ---------------------------------------------------------------------------\n\nexport type CodexCredentialTokens = { accessToken: string; refreshToken: string; idToken: string };\n\nexport type CodexCredentialForRun = {\n id: string; // row id — for compare-and-set writes (P1-c)\n version: number; // optimistic-concurrency version loaded with this snapshot\n workspaceId: string;\n tokens: CodexCredentialTokens; // decrypted — never logged, never returned by a route\n chatgptAccountId: string | null;\n scopes: string | null;\n planType: string | null;\n isFedramp: boolean;\n expiresAt: Date | null;\n lastRefreshAt: Date | null;\n status: string;\n lastError: string | null;\n};\n\n/**\n * Login / rotation write (multi-account P1). Caller passes the PRE-encrypted\n * credential blob. Keyed on the composite partial index (workspace, chatgpt\n * account): re-connecting the SAME ChatGPT account updates that row in place\n * (re-asserts account_id, bumps version); connecting a NEW account inserts a new\n * row. Returns the row id + whether it was newly inserted. The route — not this\n * accessor — auto-activates a brand-new first account and ensures the\n * rotation-settings row exists.\n */\nexport async function upsertCodexSubscriptionCredential(db: Database, input: {\n accountId: string;\n workspaceId: string;\n credentialEncrypted: string; // v1 envelope of JSON {access_token, refresh_token, id_token}\n chatgptAccountId: string | null;\n scopes: string | null;\n planType: string | null;\n isFedramp: boolean;\n expiresAt: Date | null;\n lastRefreshAt: Date | null;\n accountEmail?: string | null;\n label?: string | null;\n}): Promise<{ id: string; isNew: boolean }> {\n return await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId }, async (scopedDb) => {\n const now = new Date();\n const [row] = await scopedDb.insert(schema.codexSubscriptionCredentials).values({\n accountId: input.accountId,\n workspaceId: input.workspaceId,\n credentialEncrypted: input.credentialEncrypted,\n chatgptAccountId: input.chatgptAccountId,\n scopes: input.scopes,\n planType: input.planType,\n isFedramp: input.isFedramp,\n expiresAt: input.expiresAt,\n lastRefreshAt: input.lastRefreshAt,\n accountEmail: input.accountEmail ?? null,\n label: input.label ?? null,\n status: \"active\",\n lastError: null,\n }).onConflictDoUpdate({\n // The unique index is PARTIAL (WHERE chatgpt_account_id IS NOT NULL), so the\n // conflict target MUST repeat that predicate via targetWhere, else postgres\n // raises \"no unique or exclusion constraint matching the ON CONFLICT\".\n target: [schema.codexSubscriptionCredentials.workspaceId, schema.codexSubscriptionCredentials.chatgptAccountId],\n targetWhere: sql`chatgpt_account_id is not null`,\n set: {\n // account_id MUST be re-asserted on conflict. Omitting it leaves a stale\n // account_id on a row whose owning account changed (e.g. a reconnect\n // under a different grant), which makes the row RLS-INVISIBLE to every\n // subsequent scoped read — a permanent phantom \"no active subscription\".\n accountId: input.accountId,\n credentialEncrypted: input.credentialEncrypted,\n scopes: input.scopes,\n planType: input.planType,\n isFedramp: input.isFedramp,\n expiresAt: input.expiresAt,\n lastRefreshAt: input.lastRefreshAt,\n // Refresh the derived email; keep an existing user-chosen label (only seed\n // it when still null) so a re-connect never clobbers a rename.\n accountEmail: input.accountEmail ?? null,\n label: sql`coalesce(${schema.codexSubscriptionCredentials.label}, ${input.label ?? null})`,\n status: \"active\",\n lastError: null,\n version: sql`${schema.codexSubscriptionCredentials.version} + 1`,\n updatedAt: now,\n },\n }).returning({\n id: schema.codexSubscriptionCredentials.id,\n createdAt: schema.codexSubscriptionCredentials.createdAt,\n updatedAt: schema.codexSubscriptionCredentials.updatedAt,\n });\n // The upsert always returns exactly one row (insert or update).\n if (!row) {\n throw new Error(\"upsertCodexSubscriptionCredential returned no row\");\n }\n // A fresh INSERT leaves created_at === updated_at (both the same per-txn db\n // now()). A conflict UPDATE stamps updated_at to our JS `now` while created_at\n // keeps the original (older) value, so the two diverge. This distinguishes\n // insert from update without a second read.\n const isNew = row.createdAt.getTime() === row.updatedAt.getTime();\n return { id: row.id, isNew };\n });\n}\n\n/**\n * The ONLY decrypt-read accessor. Fails closed. Never call from an API route that\n * returns the result.\n *\n * The run's account is the resolved pin-or-active credential id, not LIMIT 1: the\n * caller (worker) resolves the effective credential id and passes it here so a\n * pinned session loads its SPECIFIC account. RLS still constrains the row to the\n * workspace; an unknown/disconnected id returns null → the caller treats it as\n * \"needs relogin / re-pick\".\n */\nexport async function loadCodexCredentialForRun(\n db: Database,\n settings: Settings,\n workspaceId: string,\n credentialId: string,\n): Promise<CodexCredentialForRun | null> {\n const key = environmentsEncryptionKeyBytes(settings);\n if (!key) {\n throw new Error(\"codex credential present but OPENGENI_ENVIRONMENTS_ENCRYPTION_KEY is not configured\");\n }\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const [row] = await scopedDb.select().from(schema.codexSubscriptionCredentials)\n .where(and(\n eq(schema.codexSubscriptionCredentials.id, credentialId),\n eq(schema.codexSubscriptionCredentials.workspaceId, workspaceId),\n )).limit(1);\n if (!row) {\n return null;\n }\n let tokens: CodexCredentialTokens;\n try {\n // The stored blob uses OpenAI's snake_case token field names; map to the\n // camelCase internal shape. Callers (route + worker) write snake_case.\n const parsed = JSON.parse(decryptEnvironmentValue(key, row.credentialEncrypted)) as {\n access_token: string;\n refresh_token: string;\n id_token: string;\n };\n tokens = { accessToken: parsed.access_token, refreshToken: parsed.refresh_token, idToken: parsed.id_token };\n } catch (error) {\n const reason = error instanceof Error ? error.message : String(error);\n throw new Error(`failed to decrypt codex credential for workspace ${workspaceId}: ${reason}`);\n }\n return {\n id: row.id,\n version: row.version,\n workspaceId,\n tokens,\n chatgptAccountId: row.chatgptAccountId,\n scopes: row.scopes,\n planType: row.planType,\n isFedramp: row.isFedramp,\n expiresAt: row.expiresAt,\n lastRefreshAt: row.lastRefreshAt,\n status: row.status,\n lastError: row.lastError,\n };\n });\n}\n\n/**\n * Persist rotated tokens after a successful refresh. Caller pre-encrypts.\n *\n * COMPARE-AND-SET (P1-c): the write is guarded by the (id, version) the resolver\n * loaded. If a disconnect→reconnect replaced/rotated the row between the load and\n * this write, the guard matches 0 rows and we DO NOT clobber the freshly\n * reconnected credential with tokens from the now-defunct family. Returns true\n * iff the guarded row was updated; false means \"credential changed under me —\n * the rotation is moot, drop it.\"\n */\nexport async function recordCodexTokenRefresh(db: Database, input: {\n id: string;\n version: number;\n workspaceId: string;\n credentialEncrypted: string;\n expiresAt: Date | null;\n lastRefreshAt: Date;\n}): Promise<boolean> {\n return await withWorkspaceRls(db, input.workspaceId, async (scopedDb) => {\n const updated = await scopedDb.update(schema.codexSubscriptionCredentials).set({\n credentialEncrypted: input.credentialEncrypted,\n expiresAt: input.expiresAt,\n lastRefreshAt: input.lastRefreshAt,\n status: \"active\",\n lastError: null,\n version: sql`${schema.codexSubscriptionCredentials.version} + 1`,\n updatedAt: new Date(),\n }).where(and(\n eq(schema.codexSubscriptionCredentials.id, input.id),\n eq(schema.codexSubscriptionCredentials.version, input.version),\n )).returning({ id: schema.codexSubscriptionCredentials.id });\n return updated.length > 0;\n });\n}\n\n/**\n * Surface a permanent or transient failure on a SPECIFIC credential row.\n *\n * COMPARE-AND-SET (P1-c): the status is stamped only if the row STILL matches the\n * (id, version) the resolver loaded. This stops a refresh that began before a\n * disconnect→reconnect (or a manual account switch) from stamping `needs_relogin`\n * on the brand-new, good credential — with N accounts per workspace a\n * workspace-wide write would be flat-out wrong (it would scribble on every\n * account). Returns true iff the guarded row was updated.\n */\nexport async function setCodexCredentialStatus(\n db: Database,\n workspaceId: string,\n status: \"active\" | \"needs_relogin\" | \"error\",\n lastError: string | null,\n target: { id: string; version: number },\n): Promise<boolean> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const updated = await scopedDb.update(schema.codexSubscriptionCredentials)\n .set({ status, lastError, updatedAt: new Date() })\n .where(and(\n eq(schema.codexSubscriptionCredentials.id, target.id),\n eq(schema.codexSubscriptionCredentials.version, target.version),\n ))\n .returning({ id: schema.codexSubscriptionCredentials.id });\n return updated.length > 0;\n });\n}\n\n/**\n * Metadata-only read for API routes, repointed to the per-workspace ACTIVE\n * credential. NEVER selects credential_encrypted.\n *\n * Reads codex_rotation_settings.active_credential_id and joins the credential by\n * id (deterministic). If the pointer is NULL but credentials exist (the\n * mid-disconnect window), it falls back to the most-recently-connected row and\n * lazily repairs the pointer so the next read is deterministic. The returned\n * `credentialId` is the active row's id (null when no credential exists at all).\n */\nexport async function getCodexCredentialStatus(db: Database, workspaceId: string): Promise<{\n connected: boolean;\n credentialId: string | null;\n chatgptAccountId: string | null;\n scopes: string | null;\n planType: string | null;\n status: string;\n expiresAt: Date | null;\n lastRefreshAt: Date | null;\n lastError: string | null;\n} | null> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const cols = {\n id: schema.codexSubscriptionCredentials.id,\n chatgptAccountId: schema.codexSubscriptionCredentials.chatgptAccountId,\n scopes: schema.codexSubscriptionCredentials.scopes,\n planType: schema.codexSubscriptionCredentials.planType,\n status: schema.codexSubscriptionCredentials.status,\n expiresAt: schema.codexSubscriptionCredentials.expiresAt,\n lastRefreshAt: schema.codexSubscriptionCredentials.lastRefreshAt,\n lastError: schema.codexSubscriptionCredentials.lastError,\n } as const;\n const [settingsRow] = await scopedDb.select({ activeCredentialId: schema.codexRotationSettings.activeCredentialId })\n .from(schema.codexRotationSettings)\n .where(eq(schema.codexRotationSettings.workspaceId, workspaceId)).limit(1);\n\n let row: { id: string; chatgptAccountId: string | null; scopes: string | null; planType: string | null; status: string; expiresAt: Date | null; lastRefreshAt: Date | null; lastError: string | null } | undefined;\n if (settingsRow?.activeCredentialId) {\n [row] = await scopedDb.select(cols).from(schema.codexSubscriptionCredentials)\n .where(and(\n eq(schema.codexSubscriptionCredentials.id, settingsRow.activeCredentialId),\n eq(schema.codexSubscriptionCredentials.workspaceId, workspaceId),\n )).limit(1);\n }\n if (!row) {\n // No active pointer (or it dangles): fall back to the most-recently-connected\n // credential and lazily repair the pointer so the active account is stable.\n [row] = await scopedDb.select(cols).from(schema.codexSubscriptionCredentials)\n .where(eq(schema.codexSubscriptionCredentials.workspaceId, workspaceId))\n .orderBy(desc(schema.codexSubscriptionCredentials.createdAt)).limit(1);\n if (row && settingsRow && settingsRow.activeCredentialId !== row.id) {\n await scopedDb.update(schema.codexRotationSettings)\n .set({ activeCredentialId: row.id, updatedAt: new Date() })\n .where(eq(schema.codexRotationSettings.workspaceId, workspaceId));\n }\n }\n if (!row) {\n return null;\n }\n const { id, ...rest } = row;\n return { connected: rest.status === \"active\", credentialId: id, ...rest };\n });\n}\n\n/**\n * Single source of truth for \"this workspace has an ACTIVE ChatGPT/Codex\n * subscription connected AND the feature is enabled for this deployment.\"\n *\n * This is the SAME condition `settingsWithCodexCredential` (worker) uses to\n * decide whether to inject the synthetic codex-subscription provider, so billing\n * and provider-injection cannot drift. Metadata-only read (never the secret).\n */\nexport async function workspaceCodexSubscriptionActive(\n db: Database,\n settings: Pick<Settings, \"codexSubscriptionEnabled\">,\n workspaceId: string,\n): Promise<boolean> {\n if (!settings.codexSubscriptionEnabled) {\n return false;\n }\n // Bounded re-read. A TRANSIENT read failure (a pooled-connection blip or a\n // lost RLS GUC — now thrown loud by withRlsContext's read-back guard rather\n // than silently returning zero rows) must never permanently decide a\n // genuinely-active subscription is disconnected, which would throw the\n // fail-loud CodexSubscriptionUnavailableError at model resolution and fail the\n // turn. Retry only on a THROWN error (the transient signature); a cleanly\n // returned status — a row (any status) or a confirmed absent row (null) — is\n // authoritative and resolves immediately, so the common no-subscription turn\n // pays no extra latency.\n let lastError: unknown;\n for (let attempt = 0; attempt < CODEX_ACTIVE_READ_ATTEMPTS; attempt++) {\n try {\n const status = await getCodexCredentialStatus(db, workspaceId);\n return status?.status === \"active\";\n } catch (error) {\n lastError = error;\n if (attempt < CODEX_ACTIVE_READ_ATTEMPTS - 1) {\n await new Promise((resolve) => setTimeout(resolve, CODEX_ACTIVE_READ_RETRY_MS * (attempt + 1)));\n }\n }\n }\n // Every attempt threw: this is a real, persistent read outage, not a one-off\n // blip. Surface the underlying error (truthful + retryable) instead of\n // silently denying an active subscription.\n console.error(\n `workspaceCodexSubscriptionActive: credential read failed for workspace ${workspaceId} after ${CODEX_ACTIVE_READ_ATTEMPTS} attempts`,\n lastError,\n );\n throw lastError instanceof Error ? lastError : new Error(String(lastError));\n}\n\n// Bounded re-read tuning for the codex active-credential check. A handful of\n// attempts with a short linear backoff rides out a transient pooler/RLS blip\n// without materially delaying a genuine outage's failure.\nconst CODEX_ACTIVE_READ_ATTEMPTS = 3;\nconst CODEX_ACTIVE_READ_RETRY_MS = 50;\n\n/**\n * CANONICAL \"is this a Codex-billed turn?\" predicate.\n *\n * True iff: the turn's model is a `codex/<slug>` id (`isCodexBilledModel`) AND\n * the deployment flag is on AND the workspace has an ACTIVE credential. A true\n * result means the turn is paid by the USER's ChatGPT/Codex plan and MUST consume\n * ZERO OpenGeni credits: callers skip the credit-balance / model-cost / token\n * gates and skip OpenGeni pricing + credit debit.\n *\n * The prefix ALONE never returns true: an unconnected user typing `codex/...`\n * gets the normal gates (and the worker fails the turn for a missing credential),\n * so there is no free/uncapped-run bypass.\n */\nexport async function isCodexBilledTurn(input: {\n db: Database;\n settings: Pick<Settings, \"codexSubscriptionEnabled\">;\n workspaceId: string;\n model: string | null | undefined;\n /**\n * Precomputed `workspaceCodexSubscriptionActive` result (P2-b). When the caller\n * already resolved the active flag for provider injection, pass it here so the\n * billed-turn predicate and the routing overlay read the credential ONCE and\n * cannot disagree across a concurrent disconnect/reconnect — a drift that would\n * either wrongly debit OpenGeni credits for a ChatGPT-paid turn or the inverse.\n */\n active?: boolean;\n}): Promise<boolean> {\n if (!isCodexBilledModel(input.model)) {\n return false; // cheap; no db hit on the common path\n }\n if (input.active !== undefined) {\n return input.active;\n }\n return workspaceCodexSubscriptionActive(input.db, input.settings, input.workspaceId);\n}\n\n// ---------------------------------------------------------------------------\n// Multi-account (P1) metadata accessors. All metadata-only — NEVER decrypt.\n// ---------------------------------------------------------------------------\n\nexport type CodexAccountStatus = {\n id: string;\n chatgptAccountId: string | null;\n label: string | null;\n accountEmail: string | null;\n planType: string | null;\n status: string; // active | needs_relogin | error\n isActive: boolean;\n expiresAt: Date | null;\n lastRefreshAt: Date | null;\n lastError: string | null;\n // P2 cached usage (plaintext metadata; rides along on this metadata-only read\n // with ZERO provider calls and ZERO decrypts). null until the first refresh.\n primaryUsedPercent: number | null;\n primaryResetAt: Date | null;\n secondaryUsedPercent: number | null;\n secondaryResetAt: Date | null;\n usageCheckedAt: Date | null;\n // P3 rotation cooldown: when set and in the future, this account is cooling-down\n // (rotated-off after a usage cap) and the engine skips it. null ⇒ not cooling.\n exhaustedUntil: Date | null;\n // P4 connector-aware rotation: the ORIGINAL-dotted connector namespaces this\n // account exposes via codex_apps (github/gmail/linear/…). null ⇒ never probed\n // (the ranker treats it as unknown: never credited as covering, never excluded).\n connectorNamespaces: string[] | null;\n connectorsCheckedAt: Date | null;\n};\n\n/**\n * Metadata-only list of every connected Codex account in the workspace, for the\n * accounts UI + the worker's selection resolver. NEVER decrypts. `isActive` marks\n * the workspace active pointer. Ordered by created_at ASC (stable list order).\n */\nexport async function listCodexAccountStatuses(db: Database, workspaceId: string): Promise<CodexAccountStatus[]> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const [settingsRow] = await scopedDb.select({ activeCredentialId: schema.codexRotationSettings.activeCredentialId })\n .from(schema.codexRotationSettings)\n .where(eq(schema.codexRotationSettings.workspaceId, workspaceId)).limit(1);\n const activeId = settingsRow?.activeCredentialId ?? null;\n const rows = await scopedDb.select({\n id: schema.codexSubscriptionCredentials.id,\n chatgptAccountId: schema.codexSubscriptionCredentials.chatgptAccountId,\n label: schema.codexSubscriptionCredentials.label,\n accountEmail: schema.codexSubscriptionCredentials.accountEmail,\n planType: schema.codexSubscriptionCredentials.planType,\n status: schema.codexSubscriptionCredentials.status,\n expiresAt: schema.codexSubscriptionCredentials.expiresAt,\n lastRefreshAt: schema.codexSubscriptionCredentials.lastRefreshAt,\n lastError: schema.codexSubscriptionCredentials.lastError,\n // P2 cached usage columns — metadata-only, ride along on this read.\n primaryUsedPercent: schema.codexSubscriptionCredentials.primaryUsedPercent,\n primaryResetAt: schema.codexSubscriptionCredentials.primaryResetAt,\n secondaryUsedPercent: schema.codexSubscriptionCredentials.secondaryUsedPercent,\n secondaryResetAt: schema.codexSubscriptionCredentials.secondaryResetAt,\n usageCheckedAt: schema.codexSubscriptionCredentials.usageCheckedAt,\n exhaustedUntil: schema.codexSubscriptionCredentials.exhaustedUntil,\n // P4 connector-set cache — metadata-only, rides along on this read.\n connectorNamespaces: schema.codexSubscriptionCredentials.connectorNamespaces,\n connectorsCheckedAt: schema.codexSubscriptionCredentials.connectorsCheckedAt,\n }).from(schema.codexSubscriptionCredentials)\n .where(eq(schema.codexSubscriptionCredentials.workspaceId, workspaceId))\n .orderBy(asc(schema.codexSubscriptionCredentials.createdAt));\n return rows.map((row) => ({ ...row, isActive: row.id === activeId }));\n });\n}\n\n/** The P2 usage-cache snapshot written by the refreshing usage wrapper. */\nexport type CodexAccountUsageSnapshot = {\n primaryUsedPercent: number | null;\n primaryResetAt: Date | null;\n secondaryUsedPercent: number | null;\n secondaryResetAt: Date | null;\n checkedAt: Date;\n};\n\n/**\n * Cache-write for P2 quota bars: persist the five plaintext usage columns on a\n * SPECIFIC credential row. NEVER touches credential_encrypted. RLS-scoped, guarded\n * by (id, workspace_id) so it can only write a row the workspace owns. Returns true\n * iff a row was updated (false ⇒ the credential was disconnected under us — the\n * snapshot is moot, drop it). This is the only writer of the usage_checked_at TTL\n * clock that `listCodexAccountStatuses` reads back.\n */\nexport async function recordCodexAccountUsage(\n db: Database,\n workspaceId: string,\n credentialId: string,\n snapshot: CodexAccountUsageSnapshot,\n): Promise<boolean> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const updated = await scopedDb.update(schema.codexSubscriptionCredentials)\n .set({\n primaryUsedPercent: snapshot.primaryUsedPercent,\n primaryResetAt: snapshot.primaryResetAt,\n secondaryUsedPercent: snapshot.secondaryUsedPercent,\n secondaryResetAt: snapshot.secondaryResetAt,\n usageCheckedAt: snapshot.checkedAt,\n // NB: no `version` bump and no `updatedAt` touch — usage is non-credential\n // metadata and must NOT race the (id, version) refresh CAS in\n // recordCodexTokenRefresh / setCodexCredentialStatus.\n })\n .where(and(\n eq(schema.codexSubscriptionCredentials.id, credentialId),\n eq(schema.codexSubscriptionCredentials.workspaceId, workspaceId),\n ))\n .returning({ id: schema.codexSubscriptionCredentials.id });\n return updated.length > 0;\n });\n}\n\nexport type CodexRotationSettings = {\n activeCredentialId: string | null;\n rotationEnabled: boolean; // P1: always false\n rotationStrategy: string; // P1: 'most_remaining' (unused)\n};\n\n/** The per-workspace rotation/active-pointer row (null when none exists yet). */\nexport async function getCodexRotationSettings(db: Database, workspaceId: string): Promise<CodexRotationSettings | null> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const [row] = await scopedDb.select({\n activeCredentialId: schema.codexRotationSettings.activeCredentialId,\n rotationEnabled: schema.codexRotationSettings.rotationEnabled,\n rotationStrategy: schema.codexRotationSettings.rotationStrategy,\n }).from(schema.codexRotationSettings)\n .where(eq(schema.codexRotationSettings.workspaceId, workspaceId)).limit(1);\n return row ?? null;\n });\n}\n\n/** Idempotently ensure the per-workspace rotation-settings row exists. */\nexport async function ensureCodexRotationSettings(db: Database, accountId: string, workspaceId: string): Promise<void> {\n await withRlsContext(db, { accountId, workspaceId }, async (scopedDb) => {\n await scopedDb.insert(schema.codexRotationSettings)\n .values({ accountId, workspaceId })\n .onConflictDoNothing({ target: [schema.codexRotationSettings.workspaceId] });\n });\n}\n\n/**\n * THE manual-switch primitive (workspace scope). Validates the credential id\n * belongs to the workspace, then one-cell UPDATEs active_credential_id. Returns\n * false if the id is unknown (so the route can 404).\n */\nexport async function setActiveCodexCredential(db: Database, workspaceId: string, credentialId: string): Promise<boolean> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const [cred] = await scopedDb.select({ id: schema.codexSubscriptionCredentials.id })\n .from(schema.codexSubscriptionCredentials)\n .where(and(\n eq(schema.codexSubscriptionCredentials.id, credentialId),\n eq(schema.codexSubscriptionCredentials.workspaceId, workspaceId),\n )).limit(1);\n if (!cred) {\n return false;\n }\n const updated = await scopedDb.update(schema.codexRotationSettings)\n .set({ activeCredentialId: credentialId, updatedAt: new Date() })\n .where(eq(schema.codexRotationSettings.workspaceId, workspaceId))\n .returning({ id: schema.codexRotationSettings.id });\n return updated.length > 0;\n });\n}\n\n/**\n * P3 rotation cooldown writer: stamp `exhausted_until` on a SPECIFIC credential row so the\n * rotation engine treats it as cooling-down (capped) until `until`. Pass `until = null` to\n * clear the cooldown. Modeled EXACTLY on recordCodexAccountUsage: RLS-scoped, guarded by\n * (id, workspace_id), and — critically — NO `version` bump and NO `updatedAt` touch, so it can\n * never race the (id, version) token-refresh CAS in recordCodexTokenRefresh / setCodexCredentialStatus.\n * Returns true iff a row was updated (false ⇒ the credential was disconnected under us).\n */\nexport async function setCodexCredentialExhausted(\n db: Database,\n workspaceId: string,\n credentialId: string,\n until: Date | null,\n): Promise<boolean> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const updated = await scopedDb.update(schema.codexSubscriptionCredentials)\n .set({ exhaustedUntil: until })\n .where(and(\n eq(schema.codexSubscriptionCredentials.id, credentialId),\n eq(schema.codexSubscriptionCredentials.workspaceId, workspaceId),\n ))\n .returning({ id: schema.codexSubscriptionCredentials.id });\n return updated.length > 0;\n });\n}\n\n/**\n * P3 reactive-rotation boundedness (Finding 1b): the number of CONSECUTIVE rotated\n * 429-failover turns since the session last had a SUCCESSFUL turn. Counts\n * `turn.failed` events carrying the `rotated` marker that occurred AFTER the most\n * recent `turn.completed` event (the natural reset anchor — any successful turn\n * moves the anchor past every prior failover, so the streak resets to 0). The\n * reactive 429 catch consults this to bound its otherwise-0-delay re-dispatch:\n * once the streak exceeds ~(connected accounts + margin) the path degrades to a\n * fixed positive idle instead of another hot re-dispatch (invariant 4: NO THRASH),\n * covering the double-fault where a cooldown write did not persist AND the 429\n * carried no usage headers. Derived from persisted events so it is correct across\n * the Temporal re-dispatch (each failover is a NEW turn, but its event survives).\n */\nexport async function countConsecutiveReactiveRotations(\n db: Database,\n workspaceId: string,\n sessionId: string,\n): Promise<number> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const [lastOk] = await scopedDb.select({ sequence: schema.sessionEvents.sequence })\n .from(schema.sessionEvents)\n .where(and(\n eq(schema.sessionEvents.workspaceId, workspaceId),\n eq(schema.sessionEvents.sessionId, sessionId),\n eq(schema.sessionEvents.type, \"turn.completed\"),\n ))\n .orderBy(desc(schema.sessionEvents.sequence))\n .limit(1);\n const conditions = [\n eq(schema.sessionEvents.workspaceId, workspaceId),\n eq(schema.sessionEvents.sessionId, sessionId),\n eq(schema.sessionEvents.type, \"turn.failed\"),\n sql`${schema.sessionEvents.payload} ->> 'rotated' = 'true'`,\n ];\n if (lastOk) {\n conditions.push(sql`${schema.sessionEvents.sequence} > ${lastOk.sequence}`);\n }\n const [{ rotated } = { rotated: 0 }] = await scopedDb.select({\n rotated: sql<number>`count(*)::int`,\n }).from(schema.sessionEvents).where(and(...conditions));\n return Number(rotated);\n });\n}\n\n/**\n * P4 connector-set cache writer: persist the set of ORIGINAL-dotted connector\n * namespaces a SPECIFIC credential exposes via codex_apps (+ the freshness clock).\n * Modeled byte-for-byte on recordCodexAccountUsage / setCodexCredentialExhausted:\n * RLS-scoped, guarded by (id, workspace_id), and — critically — NO `version` bump and\n * NO `updatedAt` touch, so it can never race the (id, version) token-refresh CAS.\n *\n * The CALLER must only invoke this with a NON-EMPTY set: codex_apps connects\n * best-effort (a transient failure yields an empty tools/list), and overwriting a\n * known non-empty set with [] would falsely \"drop\" coverage on a flaky turn. A\n * genuinely connector-less account stays null (the ranker treats null as unknown).\n * Returns true iff a row was updated (false ⇒ the credential was disconnected under us).\n */\nexport async function recordCodexAccountConnectors(\n db: Database,\n workspaceId: string,\n credentialId: string,\n namespaces: string[],\n): Promise<boolean> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const updated = await scopedDb.update(schema.codexSubscriptionCredentials)\n .set({\n connectorNamespaces: namespaces,\n connectorsCheckedAt: new Date(),\n // NB: no `version` bump and no `updatedAt` touch — connector set is non-credential\n // metadata and must NOT race the (id, version) refresh CAS (same discipline as\n // recordCodexAccountUsage / setCodexCredentialExhausted).\n })\n .where(and(\n eq(schema.codexSubscriptionCredentials.id, credentialId),\n eq(schema.codexSubscriptionCredentials.workspaceId, workspaceId),\n ))\n .returning({ id: schema.codexSubscriptionCredentials.id });\n return updated.length > 0;\n });\n}\n\n/** The supported rotation strategies (P3). */\nexport const CODEX_ROTATION_STRATEGIES = [\"most_remaining\", \"round_robin\", \"drain_then_next\"] as const;\nexport type CodexRotationStrategy = (typeof CODEX_ROTATION_STRATEGIES)[number];\n\n/**\n * P3 rotation-settings write path: one-cell UPDATE of `rotation_enabled` and/or\n * `rotation_strategy` on the per-workspace row. Validates the strategy enum (rejects unknown).\n * Guarded by workspaceId; ensureCodexRotationSettings guarantees the row exists. Returns the\n * effective settings after the patch (null when no row exists yet — caller should ensure first).\n */\nexport async function updateCodexRotationSettings(\n db: Database,\n workspaceId: string,\n patch: { rotationEnabled?: boolean; rotationStrategy?: CodexRotationStrategy },\n): Promise<CodexRotationSettings | null> {\n if (patch.rotationStrategy !== undefined && !CODEX_ROTATION_STRATEGIES.includes(patch.rotationStrategy)) {\n throw new Error(`invalid codex rotation strategy: ${patch.rotationStrategy}`);\n }\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const set: Record<string, unknown> = { updatedAt: new Date() };\n if (patch.rotationEnabled !== undefined) {\n set.rotationEnabled = patch.rotationEnabled;\n }\n if (patch.rotationStrategy !== undefined) {\n set.rotationStrategy = patch.rotationStrategy;\n }\n const [row] = await scopedDb.update(schema.codexRotationSettings)\n .set(set)\n .where(eq(schema.codexRotationSettings.workspaceId, workspaceId))\n .returning({\n activeCredentialId: schema.codexRotationSettings.activeCredentialId,\n rotationEnabled: schema.codexRotationSettings.rotationEnabled,\n rotationStrategy: schema.codexRotationSettings.rotationStrategy,\n });\n return row ?? null;\n });\n}\n\n/** P1 rename (label only); P3 widens to rotation fields. */\nexport async function renameCodexAccount(db: Database, workspaceId: string, credentialId: string, label: string | null): Promise<boolean> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const updated = await scopedDb.update(schema.codexSubscriptionCredentials)\n .set({ label, updatedAt: new Date() })\n .where(and(\n eq(schema.codexSubscriptionCredentials.id, credentialId),\n eq(schema.codexSubscriptionCredentials.workspaceId, workspaceId),\n ))\n .returning({ id: schema.codexSubscriptionCredentials.id });\n return updated.length > 0;\n });\n}\n\nexport type SessionCodexState = {\n pinnedCredentialId: string | null;\n lastCredentialId: string | null;\n};\n\n/** The session's pin + last-ran-on Codex account (drives the worker resolver + indicator). */\nexport async function getSessionCodexState(db: Database, workspaceId: string, sessionId: string): Promise<SessionCodexState | null> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const [row] = await scopedDb.select({\n pinnedCredentialId: schema.sessions.codexPinnedCredentialId,\n lastCredentialId: schema.sessions.codexLastCredentialId,\n }).from(schema.sessions)\n .where(and(eq(schema.sessions.workspaceId, workspaceId), eq(schema.sessions.id, sessionId))).limit(1);\n return row ?? null;\n });\n}\n\n/**\n * Per-session pin (manual override). pinnedCredentialId === null clears the pin\n * (follow the workspace active). Validates the id belongs to the workspace when\n * non-null. Returns false if the session is unknown or the id is invalid.\n */\nexport async function setSessionCodexPin(\n db: Database, workspaceId: string, sessionId: string, pinnedCredentialId: string | null,\n): Promise<boolean> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n if (pinnedCredentialId !== null) {\n const [cred] = await scopedDb.select({ id: schema.codexSubscriptionCredentials.id })\n .from(schema.codexSubscriptionCredentials)\n .where(and(\n eq(schema.codexSubscriptionCredentials.id, pinnedCredentialId),\n eq(schema.codexSubscriptionCredentials.workspaceId, workspaceId),\n )).limit(1);\n if (!cred) {\n return false;\n }\n }\n const updated = await scopedDb.update(schema.sessions)\n .set({ codexPinnedCredentialId: pinnedCredentialId, updatedAt: new Date() })\n .where(and(eq(schema.sessions.workspaceId, workspaceId), eq(schema.sessions.id, sessionId)))\n .returning({ id: schema.sessions.id });\n return updated.length > 0;\n });\n}\n\n/** Written by the worker at the turn boundary; drives the in-session indicator. */\nexport async function recordSessionActiveCodexCredential(\n db: Database, workspaceId: string, sessionId: string, credentialId: string,\n): Promise<void> {\n await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n await scopedDb.update(schema.sessions)\n .set({ codexLastCredentialId: credentialId, updatedAt: new Date() })\n .where(and(eq(schema.sessions.workspaceId, workspaceId), eq(schema.sessions.id, sessionId)));\n });\n}\n\n/**\n * Disconnect ONE account. DELETE WHERE id = credentialId AND workspace_id. If it\n * was the active pointer, the FK ON DELETE SET NULL clears it; this fn then\n * re-picks the most-recently-connected remaining account as active, atomically in\n * the same RLS txn. Returns whether a row was removed + the new active id.\n */\nexport async function disconnectCodexAccount(\n db: Database, workspaceId: string, credentialId: string,\n): Promise<{ removed: boolean; newActiveCredentialId: string | null }> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const removedRows = await scopedDb.delete(schema.codexSubscriptionCredentials)\n .where(and(\n eq(schema.codexSubscriptionCredentials.id, credentialId),\n eq(schema.codexSubscriptionCredentials.workspaceId, workspaceId),\n ))\n .returning({ id: schema.codexSubscriptionCredentials.id });\n // The FK SET NULL already cleared the pointer if we deleted the active row.\n const [settingsRow] = await scopedDb.select({ activeCredentialId: schema.codexRotationSettings.activeCredentialId })\n .from(schema.codexRotationSettings)\n .where(eq(schema.codexRotationSettings.workspaceId, workspaceId)).limit(1);\n if (removedRows.length === 0) {\n return { removed: false, newActiveCredentialId: settingsRow?.activeCredentialId ?? null };\n }\n let newActive = settingsRow?.activeCredentialId ?? null;\n if (newActive === null) {\n const [next] = await scopedDb.select({ id: schema.codexSubscriptionCredentials.id })\n .from(schema.codexSubscriptionCredentials)\n .where(eq(schema.codexSubscriptionCredentials.workspaceId, workspaceId))\n .orderBy(desc(schema.codexSubscriptionCredentials.createdAt)).limit(1);\n newActive = next?.id ?? null;\n if (settingsRow) {\n await scopedDb.update(schema.codexRotationSettings)\n .set({ activeCredentialId: newActive, updatedAt: new Date() })\n .where(eq(schema.codexRotationSettings.workspaceId, workspaceId));\n }\n }\n return { removed: true, newActiveCredentialId: newActive };\n });\n}\n\n/** Legacy \"disconnect all\" (old workspace-wide behavior). Returns rows removed. */\nexport async function disconnectAllCodexAccounts(db: Database, workspaceId: string): Promise<number> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const rows = await scopedDb.delete(schema.codexSubscriptionCredentials)\n .where(eq(schema.codexSubscriptionCredentials.workspaceId, workspaceId))\n .returning({ id: schema.codexSubscriptionCredentials.id });\n return rows.length;\n });\n}\n\nexport async function recordAuditEvent(db: Database, input: {\n accountId: string;\n workspaceId?: string | null;\n subjectId?: string | null;\n action: string;\n targetType?: string | null;\n targetId?: string | null;\n metadata?: Record<string, unknown>;\n}): Promise<void> {\n // audit_events has a FORCED RLS policy keyed on the account/workspace GUCs,\n // so the insert must run inside an RLS context.\n await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId ?? null }, async (scopedDb) => {\n await scopedDb.insert(schema.auditEvents).values({\n accountId: input.accountId,\n workspaceId: input.workspaceId ?? null,\n subjectId: input.subjectId ?? null,\n action: input.action,\n targetType: input.targetType ?? null,\n targetId: input.targetId ?? null,\n metadata: input.metadata ?? {},\n });\n });\n}\n\nasync function listEnvironmentVariableMetadata(db: Database, workspaceId: string, environmentId: string): Promise<WorkspaceEnvironmentVariableMetadata[]> {\n const rows = await db.select({\n name: schema.workspaceEnvironmentVariables.name,\n version: schema.workspaceEnvironmentVariables.version,\n createdAt: schema.workspaceEnvironmentVariables.createdAt,\n updatedAt: schema.workspaceEnvironmentVariables.updatedAt,\n }).from(schema.workspaceEnvironmentVariables)\n .where(and(\n eq(schema.workspaceEnvironmentVariables.workspaceId, workspaceId),\n eq(schema.workspaceEnvironmentVariables.environmentId, environmentId),\n ))\n .orderBy(asc(schema.workspaceEnvironmentVariables.name));\n return rows.map(mapWorkspaceEnvironmentVariableMetadata);\n}\n\nfunction mapWorkspaceEnvironment(row: typeof schema.workspaceEnvironments.$inferSelect, variables: WorkspaceEnvironmentVariableMetadata[]): WorkspaceEnvironment {\n return {\n id: row.id,\n accountId: row.accountId,\n workspaceId: row.workspaceId,\n name: row.name,\n description: row.description,\n variables,\n createdAt: row.createdAt.toISOString(),\n updatedAt: row.updatedAt.toISOString(),\n };\n}\n\nfunction mapWorkspaceEnvironmentVariableMetadata(row: {\n name: string;\n version: number;\n createdAt: Date;\n updatedAt: Date;\n}): WorkspaceEnvironmentVariableMetadata {\n return {\n name: row.name,\n version: row.version,\n createdAt: row.createdAt.toISOString(),\n updatedAt: row.updatedAt.toISOString(),\n };\n}\n\nfunction mapSessionMcpServerMetadata(row: typeof schema.sessionMcpServers.$inferSelect): SessionMcpServerMetadata {\n return {\n id: row.serverId,\n name: row.name ?? null,\n url: row.url,\n headerNames: Object.keys(row.headersEncrypted ?? {}).sort(),\n credentialVersion: Number(row.credentialVersion),\n };\n}\n\nasync function sessionMcpServerMetadataForSessions(\n db: Database,\n workspaceId: string,\n sessionIds: string[],\n): Promise<Map<string, SessionMcpServerMetadata[]>> {\n const grouped = new Map<string, SessionMcpServerMetadata[]>();\n if (sessionIds.length === 0) {\n return grouped;\n }\n const rows = await db.select().from(schema.sessionMcpServers)\n .where(and(\n eq(schema.sessionMcpServers.workspaceId, workspaceId),\n inArray(schema.sessionMcpServers.sessionId, sessionIds),\n ))\n .orderBy(asc(schema.sessionMcpServers.createdAt), asc(schema.sessionMcpServers.serverId));\n for (const row of rows) {\n const list = grouped.get(row.sessionId) ?? [];\n list.push(mapSessionMcpServerMetadata(row));\n grouped.set(row.sessionId, list);\n }\n return grouped;\n}\n\nasync function insertSessionMcpServers(db: Database, input: {\n accountId: string;\n workspaceId: string;\n sessionId: string;\n servers: CreateSessionMcpServerInput[];\n}): Promise<SessionMcpServerMetadata[]> {\n if (input.servers.length === 0) {\n return [];\n }\n const rows = await db.insert(schema.sessionMcpServers).values(input.servers.map((server) => ({\n accountId: input.accountId,\n workspaceId: input.workspaceId,\n sessionId: input.sessionId,\n serverId: server.id,\n name: server.name ?? null,\n url: server.url,\n allowedTools: server.allowedTools ?? null,\n timeoutMs: server.timeoutMs ?? null,\n cacheToolsList: server.cacheToolsList ?? false,\n headersEncrypted: server.headersEncrypted ?? {},\n }))).returning();\n return rows.map(mapSessionMcpServerMetadata);\n}\n\nexport async function createSessionMcpServers(db: Database, input: {\n accountId: string;\n workspaceId: string;\n sessionId: string;\n servers: CreateSessionMcpServerInput[];\n}): Promise<SessionMcpServerMetadata[]> {\n return await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId }, async (scopedDb) =>\n await insertSessionMcpServers(scopedDb, input)\n );\n}\n\nexport async function listSessionMcpServerMetadata(db: Database, workspaceId: string, sessionId: string): Promise<SessionMcpServerMetadata[]> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const grouped = await sessionMcpServerMetadataForSessions(scopedDb, workspaceId, [sessionId]);\n return grouped.get(sessionId) ?? [];\n });\n}\n\nexport async function updateSessionMcpServerCredentials(db: Database, input: {\n workspaceId: string;\n sessionId: string;\n updates: UpdateSessionMcpServerCredentialsInput[];\n}): Promise<UpdateSessionMcpServerCredentialsResult> {\n return await withWorkspaceRls(db, input.workspaceId, async (scopedDb) => await scopedDb.transaction(async (tx) =>\n await updateSessionMcpServerCredentialsInTransaction(tx, input)\n ));\n}\n\nasync function updateSessionMcpServerCredentialsInTransaction(\n tx: Pick<Database, \"update\">,\n input: {\n workspaceId: string;\n sessionId: string;\n updates: UpdateSessionMcpServerCredentialsInput[];\n },\n): Promise<UpdateSessionMcpServerCredentialsResult> {\n const servers: SessionMcpServerMetadata[] = [];\n const missingIds: string[] = [];\n for (const update of input.updates) {\n const [row] = await tx.update(schema.sessionMcpServers)\n .set({\n headersEncrypted: update.headersEncrypted,\n credentialVersion: sql`${schema.sessionMcpServers.credentialVersion} + 1`,\n updatedAt: new Date(),\n })\n .where(and(\n eq(schema.sessionMcpServers.workspaceId, input.workspaceId),\n eq(schema.sessionMcpServers.sessionId, input.sessionId),\n eq(schema.sessionMcpServers.serverId, update.id),\n ))\n .returning();\n if (!row) {\n missingIds.push(update.id);\n } else {\n servers.push(mapSessionMcpServerMetadata(row));\n }\n }\n return { servers, missingIds };\n}\n\nexport async function listSessionMcpServersForRun(\n db: Database,\n workspaceId: string,\n sessionId: string,\n encryptionKey: Uint8Array,\n): Promise<SessionMcpServerForRun[]> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const rows = await scopedDb.select().from(schema.sessionMcpServers)\n .where(and(\n eq(schema.sessionMcpServers.workspaceId, workspaceId),\n eq(schema.sessionMcpServers.sessionId, sessionId),\n ))\n .orderBy(asc(schema.sessionMcpServers.createdAt), asc(schema.sessionMcpServers.serverId));\n return rows.map((row) => {\n let headers: Record<string, string>;\n try {\n headers = Object.fromEntries(Object.entries(row.headersEncrypted ?? {})\n .map(([name, stored]) => [name, decryptEnvironmentValue(encryptionKey, stored)]));\n } catch {\n throw new Error(\"session MCP server credential decryption failed\");\n }\n return {\n ...mapSessionMcpServerMetadata(row),\n ...(row.allowedTools ? { allowedTools: row.allowedTools } : {}),\n ...(row.timeoutMs ? { timeoutMs: row.timeoutMs } : {}),\n ...(row.cacheToolsList ? { cacheToolsList: row.cacheToolsList } : {}),\n headers,\n };\n });\n });\n}\n\nexport async function createSession(db: Database, input: {\n accountId: string;\n workspaceId: string;\n initialMessage: string;\n resources: ResourceRef[];\n tools?: ToolRef[];\n metadata: Record<string, unknown>;\n model: string;\n sandboxBackend: SandboxBackend;\n environmentId?: string | null;\n firstPartyMcpPermissions?: Permission[] | null;\n // Per-session agent persona/system instructions (org-visible, not a secret).\n // Null/omitted ⇒ the session carries none (composed instructions unchanged).\n instructions?: string | null;\n parentSessionId?: string | null;\n createIdempotencyKey?: string | null;\n // The shared-sandbox group to join. Omit (or null) for a singleton group:\n // the new row's own id is used (group === session), today's 1:1 behavior. A\n // shared spawn passes the parent's sandboxGroupId so both run in ONE box.\n sandboxGroupId?: string | null;\n sandboxOs?: SandboxOs;\n mcpServers?: CreateSessionMcpServerInput[];\n}): Promise<Session> {\n // Generate the id up front so the same uuid can seed sandbox_group_id for a\n // singleton group (sandbox_group_id cannot SQL-default to id).\n const id = crypto.randomUUID();\n return await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId }, async (scopedDb) => {\n const [row] = await scopedDb.insert(schema.sessions).values({\n id,\n accountId: input.accountId,\n workspaceId: input.workspaceId,\n initialMessage: input.initialMessage,\n resources: input.resources,\n tools: input.tools ?? [],\n metadata: input.metadata,\n model: input.model,\n sandboxBackend: input.sandboxBackend,\n sandboxOs: input.sandboxOs ?? \"linux\",\n sandboxGroupId: input.sandboxGroupId ?? id,\n environmentId: input.environmentId ?? null,\n firstPartyMcpPermissions: input.firstPartyMcpPermissions ?? null,\n instructions: input.instructions ?? null,\n parentSessionId: input.parentSessionId ?? null,\n createIdempotencyKey: input.createIdempotencyKey ?? null,\n status: \"queued\",\n }).returning();\n if (!row) {\n throw new Error(\"Failed to create session\");\n }\n const mcpServers = await insertSessionMcpServers(scopedDb, {\n accountId: input.accountId,\n workspaceId: input.workspaceId,\n sessionId: row.id,\n servers: input.mcpServers ?? [],\n });\n return mapSession(row, mcpServers);\n });\n}\n\n/**\n * Inserts a session under a workspace-scoped CREATE idempotency key, collapsing\n * a concurrent race on the same key to a single row. On the unique-violation\n * the conflicting insert does nothing (`onConflictDoNothing` on the partial\n * unique index) and the now-existing winning row is fetched and returned, so\n * two near-simultaneous creates with the same key yield ONE session and both\n * callers see the same id. `created` distinguishes the winner (true: this call\n * inserted and must run the rest of the start flow) from the loser/dup (false:\n * the row already existed and must be returned as-is).\n */\nexport async function createSessionWithIdempotencyKey(db: Database, input: {\n accountId: string;\n workspaceId: string;\n initialMessage: string;\n resources: ResourceRef[];\n tools?: ToolRef[];\n metadata: Record<string, unknown>;\n model: string;\n sandboxBackend: SandboxBackend;\n environmentId?: string | null;\n firstPartyMcpPermissions?: Permission[] | null;\n // Per-session agent persona/system instructions (org-visible, not a secret).\n instructions?: string | null;\n parentSessionId?: string | null;\n createIdempotencyKey: string;\n // The shared-sandbox group to join. Omit (or null) for a singleton group\n // (group === the new row's own id); a shared spawn passes the parent's group.\n sandboxGroupId?: string | null;\n sandboxOs?: SandboxOs;\n mcpServers?: CreateSessionMcpServerInput[];\n}): Promise<{ session: Session; created: boolean }> {\n // Generate the id up front so the same uuid can seed sandbox_group_id for a\n // singleton group (sandbox_group_id cannot SQL-default to id).\n const id = crypto.randomUUID();\n return await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId }, async (scopedDb) => {\n const [inserted] = await scopedDb.insert(schema.sessions).values({\n id,\n accountId: input.accountId,\n workspaceId: input.workspaceId,\n initialMessage: input.initialMessage,\n resources: input.resources,\n tools: input.tools ?? [],\n metadata: input.metadata,\n model: input.model,\n sandboxBackend: input.sandboxBackend,\n sandboxOs: input.sandboxOs ?? \"linux\",\n sandboxGroupId: input.sandboxGroupId ?? id,\n environmentId: input.environmentId ?? null,\n firstPartyMcpPermissions: input.firstPartyMcpPermissions ?? null,\n instructions: input.instructions ?? null,\n parentSessionId: input.parentSessionId ?? null,\n createIdempotencyKey: input.createIdempotencyKey,\n status: \"queued\",\n }).onConflictDoNothing({\n target: [schema.sessions.workspaceId, schema.sessions.createIdempotencyKey],\n where: sql`${schema.sessions.createIdempotencyKey} is not null`,\n }).returning();\n if (inserted) {\n const mcpServers = await insertSessionMcpServers(scopedDb, {\n accountId: input.accountId,\n workspaceId: input.workspaceId,\n sessionId: inserted.id,\n servers: input.mcpServers ?? [],\n });\n return { session: mapSession(inserted, mcpServers), created: true };\n }\n const [existing] = await scopedDb.select().from(schema.sessions).where(and(\n eq(schema.sessions.workspaceId, input.workspaceId),\n eq(schema.sessions.createIdempotencyKey, input.createIdempotencyKey),\n )).limit(1);\n if (!existing) {\n // No row inserted and none found: the conflict target did not actually\n // collide (should never happen for a present key) — surface it rather\n // than silently returning a phantom.\n throw new Error(\"Failed to create session under idempotency key\");\n }\n const grouped = await sessionMcpServerMetadataForSessions(scopedDb, input.workspaceId, [existing.id]);\n return { session: mapSession(existing, grouped.get(existing.id) ?? []), created: false };\n });\n}\n\nexport async function getSessionByCreateIdempotencyKey(db: Database, workspaceId: string, createIdempotencyKey: string): Promise<Session | null> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const [row] = await scopedDb.select().from(schema.sessions).where(and(\n eq(schema.sessions.workspaceId, workspaceId),\n eq(schema.sessions.createIdempotencyKey, createIdempotencyKey),\n )).limit(1);\n if (!row) return null;\n const grouped = await sessionMcpServerMetadataForSessions(scopedDb, workspaceId, [row.id]);\n return mapSession(row, grouped.get(row.id) ?? []);\n });\n}\n\nexport async function getSession(db: Database, workspaceId: string, sessionId: string): Promise<Session | null> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const [row] = await scopedDb.select().from(schema.sessions).where(and(eq(schema.sessions.workspaceId, workspaceId), eq(schema.sessions.id, sessionId))).limit(1);\n if (!row) return null;\n const grouped = await sessionMcpServerMetadataForSessions(scopedDb, workspaceId, [row.id]);\n return mapSession(row, grouped.get(row.id) ?? []);\n });\n}\n\n/**\n * Resolve ANY session that belongs to a shared-sandbox group (addendum 05 §D.3,\n * stress (e)). Used by the create-session `sandbox:{groupId}` join path to (1)\n * prove the group exists and (2) inherit its box's (backend, os).\n *\n * `workspaceId` is a MANDATORY access boundary, NOT optional: the group uuid is\n * caller-supplied, so the workspace filter (inside RLS) is what forbids a\n * cross-workspace join — a foreign group returns null → the caller 404s. The\n * group uuid itself is never an authorization boundary. Returns the first member\n * session (any one suffices to read the shared box's backend/os); null when the\n * group has no session in this workspace.\n */\nexport async function getAnySessionInGroup(db: Database, workspaceId: string, sandboxGroupId: string): Promise<Session | null> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const [row] = await scopedDb.select().from(schema.sessions)\n .where(and(eq(schema.sessions.workspaceId, workspaceId), eq(schema.sessions.sandboxGroupId, sandboxGroupId)))\n .limit(1);\n return row ? mapSession(row) : null;\n });\n}\n\n/**\n * The DISTINCT environmentIds across a group's member sessions (workspace-\n * scoped; null = no environment attached). The env-aware create check compares\n * a joiner against EVERY member — an arbitrary single member (getAnySessionInGroup)\n * makes the compatibility verdict nondeterministic for legacy env-blind groups\n * whose members carry mixed environmentIds.\n */\nexport async function listDistinctEnvironmentIdsInGroup(db: Database, workspaceId: string, sandboxGroupId: string): Promise<Array<string | null>> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const rows = await scopedDb.selectDistinct({ environmentId: schema.sessions.environmentId }).from(schema.sessions)\n .where(and(eq(schema.sessions.workspaceId, workspaceId), eq(schema.sessions.sandboxGroupId, sandboxGroupId)));\n return rows.map((r) => r.environmentId ?? null);\n });\n}\n\nexport async function listSessions(db: Database, workspaceId: string, limit = 50): Promise<Session[]> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const rows = await scopedDb.select().from(schema.sessions)\n .where(eq(schema.sessions.workspaceId, workspaceId))\n .orderBy(desc(schema.sessions.createdAt), desc(schema.sessions.id))\n .limit(limit);\n const grouped = await sessionMcpServerMetadataForSessions(scopedDb, workspaceId, rows.map((row) => row.id));\n return rows.map((row) => mapSession(row, grouped.get(row.id) ?? []));\n });\n}\n\n/**\n * Count sessions still attached to a live Temporal workflow: queued, running,\n * or awaiting an approval (requires_action). idle has no running execution and\n * failed/cancelled are terminal, so neither blocks a workspace delete. The\n * delete path uses this to refuse (409) while a session could still be running\n * in Temporal, since there is no clean session-terminate to call first.\n */\nexport async function countActiveSessionsForWorkspace(db: Database, workspaceId: string): Promise<number> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const [{ count } = { count: 0 }] = await scopedDb.select({\n count: sql<number>`count(*)::int`,\n }).from(schema.sessions)\n .where(and(\n eq(schema.sessions.workspaceId, workspaceId),\n inArray(schema.sessions.status, [\"queued\", \"running\", \"requires_action\"]),\n ));\n return Number(count);\n });\n}\n\nexport async function requireSession(db: Database, workspaceId: string, sessionId: string): Promise<Session> {\n const session = await getSession(db, workspaceId, sessionId);\n if (!session) {\n throw new Error(`Session not found: ${sessionId}`);\n }\n return session;\n}\n\nexport type ListSessionEventsOptions = {\n after?: number;\n before?: number;\n limit?: number;\n};\n\nconst POSTGRES_INT_MAX = 2_147_483_647;\n\nexport async function listSessionEvents(db: Database, workspaceId: string, sessionId: string): Promise<SessionEvent[]>;\nexport async function listSessionEvents(db: Database, workspaceId: string, sessionId: string, after: number, limit?: number): Promise<SessionEvent[]>;\nexport async function listSessionEvents(db: Database, workspaceId: string, sessionId: string, options: ListSessionEventsOptions): Promise<SessionEvent[]>;\nexport async function listSessionEvents(\n db: Database,\n workspaceId: string,\n sessionId: string,\n afterOrOptions: number | ListSessionEventsOptions = 0,\n legacyLimit = 500,\n): Promise<SessionEvent[]> {\n const options = typeof afterOrOptions === \"number\"\n ? { after: afterOrOptions, limit: legacyLimit }\n : afterOrOptions;\n const after = normalizeEventSequence(options.after, 0);\n const limit = normalizeEventLimit(options.limit, 500);\n const hasBefore = options.before !== undefined && Number.isFinite(options.before);\n const before = hasBefore ? Math.floor(options.before as number) : undefined;\n\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const filters: SQL[] = [\n eq(schema.sessionEvents.workspaceId, workspaceId),\n eq(schema.sessionEvents.sessionId, sessionId),\n gt(schema.sessionEvents.sequence, after),\n ];\n if (before !== undefined && before <= POSTGRES_INT_MAX) {\n filters.push(lt(schema.sessionEvents.sequence, before));\n }\n const rows = await scopedDb.select().from(schema.sessionEvents)\n .where(and(...filters))\n .orderBy(hasBefore ? desc(schema.sessionEvents.sequence) : asc(schema.sessionEvents.sequence))\n .limit(limit);\n return (hasBefore ? rows.reverse() : rows).map(mapEvent);\n });\n}\n\nfunction normalizeEventSequence(value: number | undefined, fallback: number): number {\n if (value === undefined || !Number.isFinite(value)) {\n return fallback;\n }\n return Math.floor(value);\n}\n\nfunction normalizeEventLimit(value: number | undefined, fallback: number): number {\n if (value === undefined || !Number.isFinite(value)) {\n return fallback;\n }\n return Math.max(0, Math.floor(value));\n}\n\nexport async function getSessionEvent(db: Database, workspaceId: string, eventId: string): Promise<SessionEvent | null> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const [row] = await scopedDb.select().from(schema.sessionEvents).where(and(eq(schema.sessionEvents.workspaceId, workspaceId), eq(schema.sessionEvents.id, eventId))).limit(1);\n return row ? mapEvent(row) : null;\n });\n}\n\nexport async function getLatestRunState(db: Database, workspaceId: string, sessionId: string): Promise<{\n id: string;\n serializedRunState: string;\n pendingApprovals: unknown[];\n // The codex account that froze this state (pin > workspace-active), or null\n // when frozen on the non-codex path / before the column existed. The replay\n // path compares it to the resuming turn's codex account to decide whether the\n // blob's account-bound reasoning must be neutralized before being replayed.\n frozenCodexCredentialId: string | null;\n} | null> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const [row] = await scopedDb.select().from(schema.agentRunStates)\n .where(and(eq(schema.agentRunStates.workspaceId, workspaceId), eq(schema.agentRunStates.sessionId, sessionId)))\n .orderBy(desc(schema.agentRunStates.createdAt))\n .limit(1);\n return row ? {\n id: row.id,\n serializedRunState: row.serializedRunState,\n pendingApprovals: row.pendingApprovals,\n frozenCodexCredentialId: row.frozenCodexCredentialId ?? null,\n } : null;\n });\n}\n\n/**\n * Append conversation items (verbatim SDK AgentInputItems) to the session's\n * history. Idempotent on (workspace, session, position): concurrent or\n * repeated writers (streaming writes + turn-end reconciliation) converge\n * instead of duplicating.\n */\nexport async function appendSessionHistoryItems(db: Database, input: {\n accountId: string;\n workspaceId: string;\n sessionId: string;\n turnId?: string | null;\n // The codex account that produced these items (the turn's resolved credential\n // id), or null/undefined on the non-codex path. Stored verbatim so the read\n // path can strip cross-account reasoning.encrypted_content blobs per turn.\n producerCodexCredentialId?: string | null;\n items: Array<{ position: number; item: Record<string, unknown> }>;\n}): Promise<void> {\n if (input.items.length === 0) {\n return;\n }\n await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId }, async (scopedDb) => {\n await scopedDb.insert(schema.sessionHistoryItems).values(input.items.map((entry) => ({\n accountId: input.accountId,\n workspaceId: input.workspaceId,\n sessionId: input.sessionId,\n turnId: input.turnId ?? null,\n producerCodexCredentialId: input.producerCodexCredentialId ?? null,\n position: entry.position,\n item: sanitizeEventPayload(entry.item),\n }))).onConflictDoNothing({\n target: [schema.sessionHistoryItems.workspaceId, schema.sessionHistoryItems.sessionId, schema.sessionHistoryItems.position],\n });\n });\n}\n\nexport async function getSessionHistoryItems(db: Database, workspaceId: string, sessionId: string): Promise<Array<{ position: number; item: Record<string, unknown> }>> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const rows = await scopedDb.select({\n position: schema.sessionHistoryItems.position,\n item: schema.sessionHistoryItems.item,\n }).from(schema.sessionHistoryItems)\n .where(and(eq(schema.sessionHistoryItems.workspaceId, workspaceId), eq(schema.sessionHistoryItems.sessionId, sessionId)))\n .orderBy(schema.sessionHistoryItems.position);\n return rows;\n });\n}\n\n/**\n * The LIVE conversation-truth read path: only active rows, position-ordered.\n * After a client-side context compaction this returns [retained user messages,\n * active summary]; with no compaction yet it equals\n * getSessionHistoryItems. The model-facing read path uses this so superseded\n * (summarized-away) prefix rows are excluded while the full transcript stays in\n * the table as an audit trail.\n */\nexport async function getActiveSessionHistoryItems(db: Database, workspaceId: string, sessionId: string): Promise<Array<{ position: number; item: Record<string, unknown>; producerCodexCredentialId: string | null }>> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const rows = await scopedDb.select({\n position: schema.sessionHistoryItems.position,\n item: schema.sessionHistoryItems.item,\n producerCodexCredentialId: schema.sessionHistoryItems.producerCodexCredentialId,\n }).from(schema.sessionHistoryItems)\n .where(and(\n eq(schema.sessionHistoryItems.workspaceId, workspaceId),\n eq(schema.sessionHistoryItems.sessionId, sessionId),\n eq(schema.sessionHistoryItems.active, true),\n ))\n .orderBy(schema.sessionHistoryItems.position);\n return rows;\n });\n}\n\n/**\n * Count of ACTIVE (live, model-facing) history rows for a session. This is the\n * length of the history the next turn is seeded from — the dual-write slice\n * index — which after a compaction is far smaller than the total persisted-row\n * count (countSessionHistoryItems still includes the superseded prefix).\n */\nexport async function countActiveSessionHistoryItems(db: Database, workspaceId: string, sessionId: string): Promise<number> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const [row] = await scopedDb.select({\n count: sql<number>`count(*)`,\n }).from(schema.sessionHistoryItems)\n .where(and(\n eq(schema.sessionHistoryItems.workspaceId, workspaceId),\n eq(schema.sessionHistoryItems.sessionId, sessionId),\n eq(schema.sessionHistoryItems.active, true),\n ));\n return Number(row?.count ?? 0);\n });\n}\n\n/**\n * Result-item types and the CALL type that settles each. Kept byte-for-byte in\n * sync with the runtime sanitizer's RESULT_TYPE_BY_CALL_TYPE and the repair\n * migration (0014). The repair, the read-path sanitizer, and this spec all share\n * one definition of a tool-call pair.\n */\nconst REPAIR_CALL_TYPE_BY_RESULT_TYPE: Record<string, string> = {\n function_call_result: \"function_call\",\n computer_call_result: \"computer_call\",\n shell_call_output: \"shell_call\",\n apply_patch_call_output: \"apply_patch_call\",\n};\n\nfunction repairCallIdOf(item: unknown): string | undefined {\n if (!item || typeof item !== \"object\") {\n return undefined;\n }\n const record = item as { callId?: unknown; call_id?: unknown };\n if (typeof record.callId === \"string\") {\n return record.callId;\n }\n if (typeof record.call_id === \"string\") {\n return record.call_id;\n }\n return undefined;\n}\n\nfunction repairItemType(item: unknown): string | undefined {\n if (!item || typeof item !== \"object\") {\n return undefined;\n }\n const type = (item as { type?: unknown }).type;\n return typeof type === \"string\" ? type : undefined;\n}\n\n/**\n * Pure TypeScript SPEC for the one-time orphan repair (migration 0014),\n * mirroring its SQL WHERE clause so the deletion rule is unit-testable without a\n * database. Given the ACTIVE history rows of a single session in position order,\n * returns the indices of the orphaned tool-call RESULT rows the repair deletes.\n *\n * An orphan is a result-type row (function_call_result / computer_call_result /\n * shell_call_output / apply_patch_call_output) with no matching CALL of the\n * paired type, same correlation id (camelCase `callId` OR snake_case `call_id`),\n * at a STRICTLY EARLIER position in the same session. This is exactly the\n * session-bricking row the Responses API 400s on (\"No tool call found for\n * function call output\").\n *\n * DANGLING CALLS (a call with no result yet) are intentionally NOT returned: a\n * call awaiting a not-yet-settled result is valid, not corruption. Only unpaired\n * results are removed.\n *\n * EXISTENCE, not consumption: like the migration's `NOT EXISTS (... earlier\n * call ...)`, a result is kept whenever ANY earlier matching call exists. A\n * second result that re-uses a call_id already settled earlier is therefore NOT\n * flagged here (a matching call still exists before it) — this conservative\n * choice matches the SQL exactly and never deletes a row whose call is present;\n * the read-path sanitizer (which consumes calls one-for-one) still drops such a\n * rare duplicate in-memory, so the model request stays valid regardless.\n *\n * Callers pass rows already ordered by position. The earlier-position test is\n * by array order (the SQL orders by the numeric position column, which the read\n * path also orders by), so identical inputs yield identical decisions.\n */\nexport function orphanedResultRowIndicesForRepair(\n activeRowsInPositionOrder: ReadonlyArray<{ item: Record<string, unknown> }>,\n): number[] {\n // call_ids of CALLs seen so far, per matching result type. A result is an\n // orphan unless a call of its paired type with the same id appeared earlier.\n const seenCallIdsByResultType = new Map<string, Set<string>>();\n // Pre-index every call type to the result type(s) it can settle.\n const resultTypeByCallType: Record<string, string> = {};\n for (const [resultType, callType] of Object.entries(REPAIR_CALL_TYPE_BY_RESULT_TYPE)) {\n resultTypeByCallType[callType] = resultType;\n }\n const orphanIndices: number[] = [];\n activeRowsInPositionOrder.forEach((row, index) => {\n const type = repairItemType(row.item);\n const callId = repairCallIdOf(row.item);\n if (!type || !callId) {\n return;\n }\n const settlesResultType = resultTypeByCallType[type];\n if (settlesResultType) {\n // This row is a CALL: record its id so a later matching result is paired.\n const seen = seenCallIdsByResultType.get(settlesResultType) ?? new Set<string>();\n seen.add(callId);\n seenCallIdsByResultType.set(settlesResultType, seen);\n return;\n }\n if (REPAIR_CALL_TYPE_BY_RESULT_TYPE[type]) {\n // This row is a RESULT: orphan unless an earlier matching call was seen.\n const seen = seenCallIdsByResultType.get(type);\n if (!seen || !seen.has(callId)) {\n orphanIndices.push(index);\n }\n }\n });\n return orphanIndices;\n}\n\n/**\n * Apply a client-side context compaction as an atomic, audit-preserving write:\n *\n * - supersede (set active=false) every active row whose position lies in\n * [0, boundaryPosition) — i.e. the summarized prefix — EXCLUDING the tail.\n * Rows are never deleted.\n * - insert ONE active synthetic summary row at `summaryPosition` (a FRACTIONAL\n * position — boundaryPosition - 0.5 — that sorts immediately before the kept\n * tail and collides with NO existing row, so no real prefix row is ever\n * overwritten). Idempotent on position: a retry that finds the summary row\n * already there does not duplicate it (it only re-activates the existing\n * summary row at that fractional position) and — crucially — never mutates\n * the real row at boundaryPosition - 1.\n *\n * The caller computes the boundary from the orphan-safe planner so no tool-call\n * pair straddles the cut. `summaryPosition` must be < boundaryPosition (between\n * the last superseded prefix row and the kept tail), guaranteeing it sorts\n * before the tail. Because positions are whole numbers and summaries are\n * half-steps, the summary's fractional position can never equal a real row.\n */\nexport async function applyContextCompaction(db: Database, input: {\n accountId: string;\n workspaceId: string;\n sessionId: string;\n turnId?: string | null;\n /** Active prefix rows with position < boundaryPosition get superseded. */\n boundaryPosition: number;\n /** Position for the new summary row. Old boundary mode uses a fractional half-step before the kept tail. */\n summaryPosition: number;\n /**\n * Optional replacement rows inserted after superseding the old active set.\n * Used by Codex-parity client compaction to rebuild active history as retained\n * user messages plus one summary. These rows are synthetic replay rows, so\n * they intentionally do not inherit the current compaction turn id.\n */\n replacementItems?: Array<{ position: number; item: Record<string, unknown> }>;\n summaryItem: Record<string, unknown>;\n}): Promise<void> {\n await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId }, async (scopedDb) => {\n await scopedDb.transaction(async (tx) => {\n await tx.update(schema.sessionHistoryItems)\n .set({ active: false })\n .where(and(\n eq(schema.sessionHistoryItems.workspaceId, input.workspaceId),\n eq(schema.sessionHistoryItems.sessionId, input.sessionId),\n eq(schema.sessionHistoryItems.active, true),\n lt(schema.sessionHistoryItems.position, input.boundaryPosition),\n ));\n if (input.replacementItems && input.replacementItems.length > 0) {\n await tx.insert(schema.sessionHistoryItems).values(input.replacementItems.map((entry) => ({\n accountId: input.accountId,\n workspaceId: input.workspaceId,\n sessionId: input.sessionId,\n turnId: null,\n position: entry.position,\n item: sanitizeEventPayload(entry.item),\n active: true,\n }))).onConflictDoUpdate({\n target: [schema.sessionHistoryItems.workspaceId, schema.sessionHistoryItems.sessionId, schema.sessionHistoryItems.position],\n set: { active: true },\n });\n }\n // Insert the summary at its FRACTIONAL position. The supersede step above\n // also sets active=false for any rows with position < boundaryPosition —\n // which on a RETRY includes the summary itself (it sits below the\n // boundary). The conflict target here is that fractional position, which\n // can ONLY ever collide with a prior summary row (real rows are whole\n // numbers), so onConflictDoUpdate set:{active:true} is safe: it merely\n // re-activates the existing summary, keeping the retry idempotent WITHOUT\n // mutating its item/turnId and — crucially — WITHOUT ever touching the\n // real row at boundaryPosition - 1 (the old integer placement overwrote\n // it). The summary carries the current turnId so per-turn counts stay\n // correct.\n await tx.insert(schema.sessionHistoryItems).values({\n accountId: input.accountId,\n workspaceId: input.workspaceId,\n sessionId: input.sessionId,\n turnId: input.turnId ?? null,\n position: input.summaryPosition,\n item: sanitizeEventPayload(input.summaryItem),\n active: true,\n }).onConflictDoUpdate({\n target: [schema.sessionHistoryItems.workspaceId, schema.sessionHistoryItems.sessionId, schema.sessionHistoryItems.position],\n set: { active: true },\n });\n });\n });\n}\n\n/**\n * The next free WHOLE-NUMBER history position for a session: one past the\n * largest existing position (active or superseded), floored so the synthetic\n * summary's fractional half-step never shifts the count. The dual-write\n * watermark uses this to append new rows at fresh absolute positions, decoupled\n * from the in-memory history length (which, after a compaction, is far shorter\n * than the total persisted-row count and so cannot serve as the next position).\n */\nexport async function nextSessionHistoryPosition(db: Database, workspaceId: string, sessionId: string): Promise<number> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const [row] = await scopedDb.select({\n maxPosition: sql<number | null>`max(${schema.sessionHistoryItems.position})`,\n }).from(schema.sessionHistoryItems)\n .where(and(eq(schema.sessionHistoryItems.workspaceId, workspaceId), eq(schema.sessionHistoryItems.sessionId, sessionId)));\n const max = row?.maxPosition;\n return max === null || max === undefined ? 0 : Math.floor(Number(max)) + 1;\n });\n}\n\n/**\n * Record the actual input-token count of the most recent turn's final model\n * call, for the next turn's pre-read compaction trigger.\n */\nexport async function setSessionLastInputTokens(db: Database, workspaceId: string, sessionId: string, lastInputTokens: number): Promise<void> {\n await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n await scopedDb.update(schema.sessions)\n .set({ lastInputTokens, updatedAt: new Date() })\n .where(and(eq(schema.sessions.workspaceId, workspaceId), eq(schema.sessions.id, sessionId)));\n });\n}\n\n/**\n * The neutral marker written by clearSessionContext as the sole active history\n * row. It keeps getActiveSessionHistoryItems().length > 0 so the items read\n * path (run-input.ts messageInput) stays selected and never falls through to\n * the getLatestRunState blob — that fallback is the resurrection vector a clear\n * must defeat. A plain user message is a valid, sanitizer-clean item.\n */\nexport function clearedContextMarkerItem(): Record<string, unknown> {\n return { type: \"message\", role: \"user\", content: \"[context cleared]\" };\n}\n\n/**\n * The sentinel serializedRunState written by clearSessionContext, re-exported\n * from @opengeni/contracts so the writer (here) and the readers (run-input /\n * runtime) share one definition. It is audit-honest (carries no prior\n * conversation) and is NOT a real Agents-SDK run state — it has no\n * `$schemaVersion`/history, so `RunState.fromString` throws on it.\n *\n * Both run-state read paths therefore guard against it explicitly via\n * {@link isClearedRunStateBlob}:\n * - the message path (run-input messageInput) honors it in BOTH items and\n * run_state history modes — in items mode the boundary marker keeps the\n * active read non-empty so the blob is never reached, and in run_state mode\n * the sentinel is recognized and treated as a fresh empty start;\n * - the approval path is additionally refused by the API for mid-turn /\n * requires_action sessions, so it never sees the sentinel.\n * Stored so getLatestRunState (the run_state-source read path) reflects the\n * clear instead of resurrecting the pre-clear blob.\n */\nexport const CLEARED_RUN_STATE = CLEARED_RUN_STATE_BLOB;\n\nexport type ClearSessionContextResult = {\n /** Active history rows superseded (active=true -> false). */\n supersededItems: number;\n /** Position of the inserted neutral boundary marker. */\n markerPosition: number;\n /** stateVersion of the fresh cleared run-state row. */\n runStateVersion: number;\n};\n\n/**\n * Clear a session's conversation context in ONE transaction, audit-preserving\n * and idempotent. Defeats the RunState-fallback resurrection on BOTH model read\n * paths:\n *\n * (a) supersede every active session_history_items row (active=true -> false).\n * Nothing is deleted — the full transcript stays as an audit trail, same\n * pattern as applyContextCompaction.\n * (b) insert ONE active neutral boundary marker at max(position)+1 so the\n * active read path returns length 1 (not 0) and run-input.ts stays on the\n * items route, away from the getLatestRunState blob (the bug).\n * (c) insert a fresh agent_run_states row (stateVersion = max+1) with an empty\n * cleared blob and pendingApprovals:[], so getLatestRunState (approval /\n * run_state-source read path) also reflects the clear.\n *\n * Also resets last_input_tokens to 0 so the next turn's compaction trigger\n * starts fresh against the now-short context.\n *\n * Idempotent: a re-run supersedes the (now sole, already-marker) active row,\n * inserts another marker at the next position, and another cleared run-state.\n * The post-conditions (one active marker row, latest run-state cleared) hold.\n */\nexport async function clearSessionContext(db: Database, input: {\n accountId: string;\n workspaceId: string;\n sessionId: string;\n}): Promise<ClearSessionContextResult> {\n return await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId }, async (scopedDb) => {\n return await scopedDb.transaction(async (tx) => {\n const supersededRows = await tx.update(schema.sessionHistoryItems)\n .set({ active: false })\n .where(and(\n eq(schema.sessionHistoryItems.workspaceId, input.workspaceId),\n eq(schema.sessionHistoryItems.sessionId, input.sessionId),\n eq(schema.sessionHistoryItems.active, true),\n ))\n .returning({ id: schema.sessionHistoryItems.id });\n\n const [{ maxPosition } = { maxPosition: -1 }] = await tx.select({\n maxPosition: sql<number>`coalesce(max(${schema.sessionHistoryItems.position}), -1)`,\n }).from(schema.sessionHistoryItems)\n .where(and(\n eq(schema.sessionHistoryItems.workspaceId, input.workspaceId),\n eq(schema.sessionHistoryItems.sessionId, input.sessionId),\n ));\n const markerPosition = Number(maxPosition) + 1;\n await tx.insert(schema.sessionHistoryItems).values({\n accountId: input.accountId,\n workspaceId: input.workspaceId,\n sessionId: input.sessionId,\n turnId: null,\n position: markerPosition,\n item: sanitizeEventPayload(clearedContextMarkerItem()),\n active: true,\n }).onConflictDoNothing({\n target: [schema.sessionHistoryItems.workspaceId, schema.sessionHistoryItems.sessionId, schema.sessionHistoryItems.position],\n });\n\n const [{ maxVersion } = { maxVersion: 0 }] = await tx.select({\n maxVersion: sql<number>`coalesce(max(${schema.agentRunStates.stateVersion}), 0)`,\n }).from(schema.agentRunStates)\n .where(and(\n eq(schema.agentRunStates.workspaceId, input.workspaceId),\n eq(schema.agentRunStates.sessionId, input.sessionId),\n ));\n const runStateVersion = Number(maxVersion) + 1;\n await tx.insert(schema.agentRunStates).values({\n accountId: input.accountId,\n workspaceId: input.workspaceId,\n sessionId: input.sessionId,\n turnId: null,\n stateVersion: runStateVersion,\n serializedRunState: CLEARED_RUN_STATE,\n pendingApprovals: [],\n });\n\n await tx.update(schema.sessions)\n .set({ lastInputTokens: 0, updatedAt: new Date() })\n .where(and(eq(schema.sessions.workspaceId, input.workspaceId), eq(schema.sessions.id, input.sessionId)));\n\n return { supersededItems: supersededRows.length, markerPosition, runStateVersion };\n });\n });\n}\n\nexport async function countSessionHistoryItems(db: Database, workspaceId: string, sessionId: string): Promise<number> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const [row] = await scopedDb.select({\n count: sql<number>`count(*)`,\n }).from(schema.sessionHistoryItems)\n .where(and(eq(schema.sessionHistoryItems.workspaceId, workspaceId), eq(schema.sessionHistoryItems.sessionId, sessionId)));\n return Number(row?.count ?? 0);\n });\n}\n\n/**\n * Set the operator /compact request flag. The worker honors it before the next\n * turn (forced client-side compaction) and clears it. Idempotent: repeated\n * requests collapse to one pending compaction.\n */\nexport async function requestSessionCompaction(db: Database, workspaceId: string, sessionId: string): Promise<void> {\n await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n await scopedDb.update(schema.sessions)\n .set({ compactRequested: true, updatedAt: new Date() })\n .where(and(eq(schema.sessions.workspaceId, workspaceId), eq(schema.sessions.id, sessionId)));\n });\n}\n\n/**\n * Atomically consume the /compact request flag: clear it and report whether it\n * was set. The worker calls this pre-turn; only the call that observed `true`\n * runs the forced compaction, so concurrent turns can't double-compact.\n */\nexport async function consumeSessionCompactionRequest(db: Database, workspaceId: string, sessionId: string): Promise<boolean> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const cleared = await scopedDb.update(schema.sessions)\n .set({ compactRequested: false, updatedAt: new Date() })\n .where(and(\n eq(schema.sessions.workspaceId, workspaceId),\n eq(schema.sessions.id, sessionId),\n eq(schema.sessions.compactRequested, true),\n ))\n .returning({ id: schema.sessions.id });\n return cleared.length > 0;\n });\n}\n\n/**\n * Number of conversation-truth items a specific turn persisted. The\n * worker-death requeue path uses this to decide whether the re-dispatched\n * turn must enter through a resume notice (its partial progress is already\n * part of conversation truth, so replaying the original trigger would hand\n * the model duplicate input) or can replay its original trigger cleanly.\n */\nexport async function countTurnSessionHistoryItems(db: Database, workspaceId: string, turnId: string): Promise<number> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const [row] = await scopedDb.select({\n count: sql<number>`count(*)`,\n }).from(schema.sessionHistoryItems)\n .where(and(eq(schema.sessionHistoryItems.workspaceId, workspaceId), eq(schema.sessionHistoryItems.turnId, turnId)));\n return Number(row?.count ?? 0);\n });\n}\n\n/**\n * Persist the session's sandbox recovery descriptor (the small versioned\n * envelope used to reattach / snapshot-restore / rebuild the sandbox),\n * decoupled from the RunState blob.\n */\nexport async function upsertSandboxSessionEnvelope(db: Database, input: {\n accountId: string;\n workspaceId: string;\n sessionId: string;\n envelope: Record<string, unknown>;\n}): Promise<void> {\n await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId }, async (scopedDb) => {\n await scopedDb.insert(schema.sandboxSessionEnvelopes).values({\n accountId: input.accountId,\n workspaceId: input.workspaceId,\n sessionId: input.sessionId,\n envelope: input.envelope,\n }).onConflictDoUpdate({\n target: [schema.sandboxSessionEnvelopes.workspaceId, schema.sandboxSessionEnvelopes.sessionId],\n set: { envelope: input.envelope, updatedAt: new Date() },\n });\n });\n}\n\nexport async function getSandboxSessionEnvelope(db: Database, workspaceId: string, sessionId: string): Promise<Record<string, unknown> | null> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const [row] = await scopedDb.select({ envelope: schema.sandboxSessionEnvelopes.envelope })\n .from(schema.sandboxSessionEnvelopes)\n .where(and(eq(schema.sandboxSessionEnvelopes.workspaceId, workspaceId), eq(schema.sandboxSessionEnvelopes.sessionId, sessionId)))\n .limit(1);\n return row?.envelope ?? null;\n });\n}\n\n// ============================================================================\n// Session recordings — the durable index for the \"agent films itself proving\n// the fix\" loop (P4.3). One row per recording; insert at start, update at\n// finalize (available with the storage_key) or failure. Read-side feeds the\n// list route + the signed-URL replay route (storage_key is the source of truth).\n// ============================================================================\n\nexport type SessionRecordingState = (typeof schema.sessionRecordingStateValues)[number];\nexport type SessionRecordingMode = (typeof schema.sessionRecordingModeValues)[number];\nexport type SessionRecordingCodec = (typeof schema.sessionRecordingCodecValues)[number];\n\nexport type SessionRecordingRow = {\n id: string;\n workspaceId: string;\n sessionId: string;\n turnId: string | null;\n state: SessionRecordingState;\n mode: SessionRecordingMode;\n codec: SessionRecordingCodec;\n storageKey: string | null;\n sizeBytes: number | null;\n durationSeconds: number | null;\n width: number;\n height: number;\n reason: string | null;\n createdAt: Date;\n finalizedAt: Date | null;\n};\n\nfunction mapRecording(row: typeof schema.sessionRecordings.$inferSelect): SessionRecordingRow {\n return {\n id: row.id,\n workspaceId: row.workspaceId,\n sessionId: row.sessionId,\n turnId: row.turnId,\n state: row.state,\n mode: row.mode,\n codec: row.codec,\n storageKey: row.storageKey,\n sizeBytes: row.sizeBytes === null || row.sizeBytes === undefined ? null : Number(row.sizeBytes),\n durationSeconds: row.durationSeconds === null || row.durationSeconds === undefined ? null : Number(row.durationSeconds),\n width: row.width,\n height: row.height,\n reason: row.reason,\n createdAt: row.createdAt,\n finalizedAt: row.finalizedAt,\n };\n}\n\nexport async function insertRecording(db: Database, input: {\n id: string;\n accountId: string;\n workspaceId: string;\n sessionId: string;\n turnId?: string | null;\n mode: SessionRecordingMode;\n codec: SessionRecordingCodec;\n width: number;\n height: number;\n reason?: string | null;\n}): Promise<SessionRecordingRow> {\n return await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId }, async (scopedDb) => {\n const [row] = await scopedDb.insert(schema.sessionRecordings).values({\n id: input.id,\n accountId: input.accountId,\n workspaceId: input.workspaceId,\n sessionId: input.sessionId,\n turnId: input.turnId ?? null,\n state: \"recording\",\n mode: input.mode,\n codec: input.codec,\n width: input.width,\n height: input.height,\n reason: input.reason ?? null,\n }).returning();\n return mapRecording(row!);\n });\n}\n\nexport async function updateRecording(db: Database, input: {\n accountId: string;\n workspaceId: string;\n recordingId: string;\n state: SessionRecordingState;\n storageKey?: string | null;\n sizeBytes?: number | null;\n durationSeconds?: number | null;\n reason?: string | null;\n finalized?: boolean;\n}): Promise<SessionRecordingRow | null> {\n return await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId }, async (scopedDb) => {\n const set: Partial<typeof schema.sessionRecordings.$inferInsert> = { state: input.state };\n if (input.storageKey !== undefined) set.storageKey = input.storageKey;\n if (input.sizeBytes !== undefined) set.sizeBytes = input.sizeBytes;\n if (input.durationSeconds !== undefined) set.durationSeconds = input.durationSeconds;\n if (input.reason !== undefined) set.reason = input.reason;\n if (input.finalized || input.state === \"available\" || input.state === \"failed\") {\n set.finalizedAt = new Date();\n }\n const [row] = await scopedDb.update(schema.sessionRecordings)\n .set(set)\n .where(and(\n eq(schema.sessionRecordings.workspaceId, input.workspaceId),\n eq(schema.sessionRecordings.id, input.recordingId),\n ))\n .returning();\n return row ? mapRecording(row) : null;\n });\n}\n\n/**\n * Hard-delete a recording row. Used to DISCARD an on-turn recording that captured\n * NO computer-use activity (a plain text turn): the row was inserted at\n * `beginRecording` (state \"recording\") but the turn never drove the desktop, so it\n * is removed entirely rather than surfaced as a phantom recording or a failure. No\n * other table FK-references session_recordings, so the delete is self-contained.\n */\nexport async function deleteRecording(db: Database, input: {\n accountId: string;\n workspaceId: string;\n recordingId: string;\n}): Promise<void> {\n await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId }, async (scopedDb) => {\n await scopedDb.delete(schema.sessionRecordings)\n .where(and(\n eq(schema.sessionRecordings.workspaceId, input.workspaceId),\n eq(schema.sessionRecordings.id, input.recordingId),\n ));\n });\n}\n\nexport async function getRecording(db: Database, workspaceId: string, recordingId: string): Promise<SessionRecordingRow | null> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const [row] = await scopedDb.select().from(schema.sessionRecordings)\n .where(and(\n eq(schema.sessionRecordings.workspaceId, workspaceId),\n eq(schema.sessionRecordings.id, recordingId),\n ))\n .limit(1);\n return row ? mapRecording(row) : null;\n });\n}\n\nexport async function listRecordings(db: Database, workspaceId: string, sessionId: string): Promise<SessionRecordingRow[]> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const rows = await scopedDb.select().from(schema.sessionRecordings)\n .where(and(\n eq(schema.sessionRecordings.workspaceId, workspaceId),\n eq(schema.sessionRecordings.sessionId, sessionId),\n ))\n .orderBy(desc(schema.sessionRecordings.createdAt));\n return rows.map(mapRecording);\n });\n}\n\n// ============================================================================\n// Channel-A interactive PTY sessions (P4.4) — the ptyId <-> exec-session-id map.\n// The ONLY new persistent state Channel A needs; FS/Git reads persist nothing.\n// ============================================================================\n\nexport type SandboxPtySessionRow = {\n id: string;\n accountId: string;\n workspaceId: string;\n sessionId: string;\n execSessionId: number | null;\n leaseEpoch: number;\n cols: number;\n rows: number;\n shell: string;\n cwd: string;\n status: \"open\" | \"closed\";\n openedBy: string;\n lastInputAt: string;\n createdAt: string;\n closedAt: string | null;\n};\n\nfunction mapPtySession(row: typeof schema.sandboxPtySessions.$inferSelect): SandboxPtySessionRow {\n return {\n id: row.id,\n accountId: row.accountId,\n workspaceId: row.workspaceId,\n sessionId: row.sessionId,\n execSessionId: row.execSessionId ?? null,\n leaseEpoch: row.leaseEpoch,\n cols: row.cols,\n rows: row.rows,\n shell: row.shell,\n cwd: row.cwd,\n status: row.status as \"open\" | \"closed\",\n openedBy: row.openedBy,\n lastInputAt: row.lastInputAt.toISOString(),\n createdAt: row.createdAt.toISOString(),\n closedAt: row.closedAt ? row.closedAt.toISOString() : null,\n };\n}\n\nexport async function insertPtySession(db: Database, input: {\n id: string;\n accountId: string;\n workspaceId: string;\n sessionId: string;\n execSessionId?: number | null;\n leaseEpoch: number;\n cols: number;\n rows: number;\n shell: string;\n cwd: string;\n openedBy: string;\n}): Promise<SandboxPtySessionRow> {\n return await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId }, async (scopedDb) => {\n const [row] = await scopedDb.insert(schema.sandboxPtySessions).values({\n id: input.id,\n accountId: input.accountId,\n workspaceId: input.workspaceId,\n sessionId: input.sessionId,\n execSessionId: input.execSessionId ?? null,\n leaseEpoch: input.leaseEpoch,\n cols: input.cols,\n rows: input.rows,\n shell: input.shell,\n cwd: input.cwd,\n status: \"open\",\n openedBy: input.openedBy,\n }).returning();\n return mapPtySession(row!);\n });\n}\n\n/** Read an OPEN PTY row by ptyId. Returns null when absent or already closed. */\nexport async function getOpenPtySession(db: Database, workspaceId: string, ptyId: string): Promise<SandboxPtySessionRow | null> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const [row] = await scopedDb.select().from(schema.sandboxPtySessions)\n .where(and(\n eq(schema.sandboxPtySessions.workspaceId, workspaceId),\n eq(schema.sandboxPtySessions.id, ptyId),\n eq(schema.sandboxPtySessions.status, \"open\"),\n ))\n .limit(1);\n return row ? mapPtySession(row) : null;\n });\n}\n\n/** Stamp the SDK exec-session id (known only after the open exec yields a still-\n * running process) + refresh the input-activity TTL. */\nexport async function updatePtySessionActivity(db: Database, input: {\n accountId: string;\n workspaceId: string;\n ptyId: string;\n execSessionId?: number | null;\n cols?: number;\n rows?: number;\n}): Promise<SandboxPtySessionRow | null> {\n return await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId }, async (scopedDb) => {\n const set: Partial<typeof schema.sandboxPtySessions.$inferInsert> = { lastInputAt: new Date() };\n if (input.execSessionId !== undefined) set.execSessionId = input.execSessionId;\n if (input.cols !== undefined) set.cols = input.cols;\n if (input.rows !== undefined) set.rows = input.rows;\n const [row] = await scopedDb.update(schema.sandboxPtySessions)\n .set(set)\n .where(and(\n eq(schema.sandboxPtySessions.workspaceId, input.workspaceId),\n eq(schema.sandboxPtySessions.id, input.ptyId),\n eq(schema.sandboxPtySessions.status, \"open\"),\n ))\n .returning();\n return row ? mapPtySession(row) : null;\n });\n}\n\n/** Mark a PTY closed (idempotent — a double close on a closed row is a no-op). */\nexport async function closePtySession(db: Database, input: {\n accountId: string;\n workspaceId: string;\n ptyId: string;\n}): Promise<SandboxPtySessionRow | null> {\n return await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId }, async (scopedDb) => {\n const [row] = await scopedDb.update(schema.sandboxPtySessions)\n .set({ status: \"closed\", closedAt: new Date() })\n .where(and(\n eq(schema.sandboxPtySessions.workspaceId, input.workspaceId),\n eq(schema.sandboxPtySessions.id, input.ptyId),\n ))\n .returning();\n return row ? mapPtySession(row) : null;\n });\n}\n\n/** List a session's OPEN PTYs (reattach + reap). */\nexport async function listOpenPtySessions(db: Database, workspaceId: string, sessionId: string): Promise<SandboxPtySessionRow[]> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const rows = await scopedDb.select().from(schema.sandboxPtySessions)\n .where(and(\n eq(schema.sandboxPtySessions.workspaceId, workspaceId),\n eq(schema.sandboxPtySessions.sessionId, sessionId),\n eq(schema.sandboxPtySessions.status, \"open\"),\n ))\n .orderBy(desc(schema.sandboxPtySessions.createdAt));\n return rows.map(mapPtySession);\n });\n}\n\n// ============================================================================\n// Sandbox singleton lease — the SOLE enforcer of one-box-per-group (P1.1).\n//\n// Group-keyed (workspace_id, sandbox_group_id) from the start. The sole\n// double-spawn guard is the UNIQUE (workspace_id, sandbox_group_id) index +\n// plain SELECT … FOR UPDATE (block, NOT skip-locked) + the cold->warming CAS\n// inside that row lock. lease_epoch is integer (returns a JS number) but every\n// read is Number()-coerced defensively. Mirrors the claimNextQueuedTurn\n// withWorkspaceRls/withRlsContext -> scopedDb.transaction -> tx.execute(sql<T>``)\n// pattern (the row type goes on the sql tag, not on .execute).\n// ============================================================================\n\nexport type SandboxLeaseLiveness = \"cold\" | \"warming\" | \"warm\" | \"draining\";\nexport type LeaseHolderKind = \"turn\" | \"viewer\";\n\n// The snake_case raw shape returned by the raw sql`` lease queries. lease_epoch\n// comes back as a number for an integer column, but we type it number|string\n// and Number()-coerce so the same code is correct regardless of column type.\n// Typed with an index signature so it satisfies db.execute<TRow extends\n// Record<string, unknown>>.\ntype LeaseRow = {\n id: string;\n account_id: string;\n workspace_id: string;\n sandbox_group_id: string;\n liveness: SandboxLeaseLiveness;\n refcount: number;\n turn_holders: number;\n viewer_holders: number;\n instance_id: string | null;\n backend: string;\n os: string;\n image: string | null;\n data_plane_url: string | null;\n terminal_data_plane_url: string | null;\n lease_epoch: number | string;\n resume_backend_id: string | null;\n resume_state: Record<string, unknown> | null;\n last_meter_at: Date | string | null;\n last_meter_tick: number;\n expires_at: Date | string;\n} & Record<string, unknown>;\n\nexport interface LeaseSnapshot {\n id: string;\n sandboxGroupId: string;\n liveness: SandboxLeaseLiveness;\n refcount: number;\n turnHolders: number;\n viewerHolders: number;\n instanceId: string | null;\n backend: string;\n os: string;\n // The container image the group box runs (Modal image ref / docker image). Null\n // for a legacy/cold row (image unknown). Shared state: all the box's sessions run\n // this image; a resume resolving a different image conflicts (B3).\n image: string | null;\n dataPlaneUrl: string | null;\n // The cached ttyd pty-ws tunnel URL (7681), separate from dataPlaneUrl (the\n // 6080 desktop tunnel). Null until mintTerminalStream resolves + records it.\n terminalDataPlaneUrl: string | null;\n leaseEpoch: number;\n resumeBackendId: string | null;\n resumeState: Record<string, unknown> | null;\n expiresAt: Date;\n}\n\nexport interface LiveModalSandboxLeaseAttribution {\n leaseId: string;\n workspaceId: string;\n sandboxGroupId: string;\n instanceId: string | null;\n liveness: SandboxLeaseLiveness;\n}\n\nexport interface AcquireLeaseInput {\n accountId: string;\n workspaceId: string;\n // The group's identity (sessions.sandbox_group_id; == session id for a\n // singleton group). The lease is per-group, not per-session.\n sandboxGroupId: string;\n kind: LeaseHolderKind;\n holderId: string; // session_turns.id (turn) | viewer connection id (viewer)\n subjectId?: string | null; // the attributing session within the group\n backend: string; // sessions.sandbox_backend\n os?: string; // default 'linux'\n // The container image this run resolves (Modal image ref / docker image). Stamped on\n // the cold-create + folded onto a warming/CAS; a warm/draining/warming box already\n // running a DIFFERENT image is a shared-state conflict (B3): a SOLO holder forces the\n // box to recreate on this image, N-holders throw SandboxImageConflictError. Omitted\n // (null/undefined) -> image is not enforced (legacy/cold rows, selfhosted).\n image?: string | null;\n leaseTtlMs: number; // refresh window for expires_at (turn-heartbeat cadence)\n // Optional epoch fence for a re-establishing turn holder: when set, the\n // turn-arrival increment is gated on lease_epoch == expectedEpoch (split-brain).\n expectedEpoch?: number;\n}\n\nexport type AcquireLeaseResult =\n // Caller WON the cold->warming CAS: it is the spawner (any pool worker). Must\n // resume-by-id from resume_state, expose the stream port, then call\n // commitWarmingToWarm. No owner process is started.\n | { role: \"spawner\"; lease: LeaseSnapshot }\n // Box live or being built by someone else: attach (and, for warming, wait).\n | { role: \"attached\"; lease: LeaseSnapshot }\n // Re-armed a draining lease back to warm (box never torn down).\n | { role: \"rearmed\"; lease: LeaseSnapshot }\n // Epoch fence rejected the turn-arrival increment: a newer epoch exists (a\n // later turn re-established the box). Caller must back off and re-read; NEVER\n // create().\n | { role: \"fenced\"; lease: LeaseSnapshot };\n\n// Thrown by callers that treat a fenced/superseded epoch as an error path.\nexport class SandboxLeaseSupersededError extends Error {\n constructor(public readonly sandboxGroupId: string, public readonly leaseEpoch: number) {\n super(`Sandbox lease superseded for group ${sandboxGroupId} (epoch ${leaseEpoch})`);\n this.name = \"SandboxLeaseSupersededError\";\n }\n}\n\n// IMAGE IS SHARED STATE (B3): thrown when a resume resolves an image DIFFERENT from\n// the one the live shared box was created with AND other holders are still on the box.\n// A shared box is ONE filesystem; recreating it on a new image would yank the running\n// filesystem out from under the OTHER sessions, so we refuse. The turn activity surfaces\n// this as an actionable error: spawn with sandbox:'new' or align the pack image. A SOLO\n// holder never hits this — acquireLease recreates the box on the new image instead.\nexport class SandboxImageConflictError extends Error {\n constructor(\n public readonly sandboxGroupId: string,\n public readonly currentImage: string,\n public readonly requestedImage: string,\n ) {\n super(\n `Sandbox group ${sandboxGroupId} runs image ${currentImage}; this run resolves image ${requestedImage}. `\n + `A shared box requires one image — spawn with sandbox:'new' for an isolated box or align the pack image.`,\n );\n this.name = \"SandboxImageConflictError\";\n }\n}\n\nfunction mapLeaseRow(row: LeaseRow): LeaseSnapshot {\n return {\n id: row.id,\n sandboxGroupId: row.sandbox_group_id,\n liveness: row.liveness,\n refcount: Number(row.refcount),\n turnHolders: Number(row.turn_holders),\n viewerHolders: Number(row.viewer_holders),\n instanceId: row.instance_id,\n backend: row.backend,\n os: row.os,\n image: row.image ?? null,\n dataPlaneUrl: row.data_plane_url,\n terminalDataPlaneUrl: row.terminal_data_plane_url ?? null,\n // Defensive coercion: integer returns a number, but coerce regardless so the\n // fence comparison stays exact even if the column type ever drifts to int8.\n leaseEpoch: Number(row.lease_epoch),\n resumeBackendId: row.resume_backend_id,\n resumeState: row.resume_state,\n expiresAt: row.expires_at instanceof Date ? row.expires_at : new Date(row.expires_at),\n };\n}\n\n// Recompute refcount/split-counts from the holder rows (holders are the source\n// of truth), refresh expires_at, optionally set liveness. Returns the updated row.\nasync function recomputeAndStampLease(\n tx: Database,\n leaseId: string,\n leaseTtlMs: number,\n setLiveness: SandboxLeaseLiveness | null,\n): Promise<LeaseRow> {\n const counts = await tx.execute<{ total: number; turns: number; viewers: number }>(sql`\n select count(*)::int as total,\n count(*) filter (where kind = 'turn')::int as turns,\n count(*) filter (where kind = 'viewer')::int as viewers\n from sandbox_lease_holders where lease_id = ${leaseId}\n `);\n const c = counts[0]!;\n const updated = await tx.execute<LeaseRow>(sql`\n update sandbox_leases set\n refcount = ${c.total},\n turn_holders = ${c.turns},\n viewer_holders = ${c.viewers},\n expires_at = now() + (${String(leaseTtlMs)} || ' milliseconds')::interval,\n ${setLiveness ? sql`liveness = ${setLiveness},` : sql``}\n updated_at = now()\n where id = ${leaseId}\n returning *\n `);\n return updated[0]!;\n}\n\n// Idempotent acquire: the unique (lease, kind, holder) index makes a retried or\n// duplicate acquire a no-op heartbeat refresh, never a double-count.\nasync function upsertLeaseHolder(\n tx: Database, leaseId: string, accountId: string, workspaceId: string,\n kind: LeaseHolderKind, holderId: string, subjectId: string | null,\n): Promise<void> {\n await tx.execute(sql`\n insert into sandbox_lease_holders\n (account_id, workspace_id, lease_id, kind, holder_id, subject_id, last_heartbeat_at)\n values (${accountId}, ${workspaceId}, ${leaseId}, ${kind}, ${holderId}, ${subjectId}, now())\n on conflict (lease_id, kind, holder_id)\n do update set last_heartbeat_at = now()\n `);\n}\n\n// §4.1 — the get-or-create critical section. ONE transaction:\n// insert-or-nothing -> SELECT … FOR UPDATE (block, not skip) -> branch -> bump.\n// The single most load-bearing function: the sole double-spawn guard.\nexport async function acquireLease(db: Database, input: AcquireLeaseInput): Promise<AcquireLeaseResult> {\n const { accountId, workspaceId, sandboxGroupId, kind, holderId, backend } = input;\n const os = input.os ?? \"linux\";\n const subjectId = input.subjectId ?? null;\n return await withRlsContext(db, { accountId, workspaceId }, async (scopedDb) =>\n await scopedDb.transaction(async (txRaw) => {\n const tx = txRaw as unknown as Database;\n const image = input.image ?? null;\n // (1) Materialize the singleton row if absent. ON CONFLICT DO NOTHING + the\n // unique index = idempotent under a race; concurrent inserts collapse to\n // one row. expires_at seeded so a never-warmed cold row has a valid TTL. The\n // image (B3) is stamped on the cold-create so a fresh box records the image it\n // will be built on; a conflict on an EXISTING live box is handled below.\n await tx.execute(sql`\n insert into sandbox_leases\n (account_id, workspace_id, sandbox_group_id, liveness, backend, os, image, expires_at)\n values\n (${accountId}, ${workspaceId}, ${sandboxGroupId}, 'cold', ${backend}, ${os}, ${image},\n now() + (${String(input.leaseTtlMs)} || ' milliseconds')::interval)\n on conflict (workspace_id, sandbox_group_id) do nothing\n `);\n\n // (2) Serialize ALL concurrent arrivals on this group's row. Plain FOR\n // UPDATE (block, do NOT skip) — unlike claimNextQueuedTurn's SKIP LOCKED,\n // because we WANT the loser to block then attach, not skip and lose.\n const rows = await tx.execute<LeaseRow>(sql`\n select * from sandbox_leases\n where workspace_id = ${workspaceId} and sandbox_group_id = ${sandboxGroupId}\n for update\n `);\n const row = rows[0];\n if (!row) throw new Error(`Lease row vanished post-insert: ${sandboxGroupId}`);\n\n let liveness = row.liveness;\n\n // -- IMAGE IS SHARED STATE (B3): a LIVE box (warm/draining/warming) already runs\n // a specific image. If this run resolves a DIFFERENT image (both sides known),\n // the shared filesystem cannot serve both. Under the held row lock we count the\n // OTHER holders (holders that are not this exact (kind, holderId) — an idempotent\n // retry of our own holder does not count as a rival):\n // - SOLO (no other holders): RECREATE. Reset the box to cold and re-stamp the\n // NEW image, then fall through to the cold branch below, which CASes us in as\n // the spawner. The spawner cold-creates a fresh box on the new image (the\n // archive replay in establishSandboxSessionFromEnvelope hydrates /workspace).\n // - OTHER holders present: REFUSE. Throw SandboxImageConflictError — recreating\n // would yank the running filesystem out from under the other sessions.\n // Only enforced when BOTH images are known; a cold row / a legacy null-image box /\n // an unset input image never conflicts (the selfhosted path passes no image).\n if (liveness !== \"cold\" && image !== null && row.image !== null && row.image !== image) {\n const others = await tx.execute<{ n: number }>(sql`\n select count(*)::int as n from sandbox_lease_holders\n where lease_id = ${row.id} and not (kind = ${kind} and holder_id = ${holderId})\n `);\n const otherHolders = Number(others[0]?.n ?? 0);\n if (otherHolders > 0) {\n throw new SandboxImageConflictError(sandboxGroupId, row.image, image);\n }\n // SOLO recreate: reset to cold + re-stamp the new image. Clear the live-box\n // fields so no stale instance/tunnel survives the image roll (symmetric with\n // failWarmingToCold). resume_state is nulled — a solo image change is an\n // intentional fresh box (a divergent image cannot replay the old box's live\n // state); the session envelope/archive still drives /workspace hydration on the\n // cold re-create. Fall through to the cold branch, which CASes us in as spawner.\n await tx.execute(sql`\n update sandbox_leases set\n liveness = 'cold', image = ${image}, instance_id = null,\n data_plane_url = null, terminal_data_plane_url = null,\n resume_backend_id = null, resume_state = null, updated_at = now()\n where id = ${row.id}\n `);\n liveness = \"cold\";\n }\n\n // -- draining: late arrival re-arms (D1). Box still alive (grace open).\n if (liveness === \"draining\") {\n await upsertLeaseHolder(tx, row.id, accountId, workspaceId, kind, holderId, subjectId);\n const updated = await recomputeAndStampLease(tx, row.id, input.leaseTtlMs, \"warm\");\n return { role: \"rearmed\" as const, lease: mapLeaseRow(updated) };\n }\n\n // -- cold: WIN the cold->warming CAS (C1). Exactly one winner under the\n // held row lock; concurrent arrivals serialize behind us and see warming.\n // The image (B3) is (re-)stamped on the CAS so the box the spawner cold-creates\n // records the image it runs — for a fresh cold row or a solo-recreate above.\n if (liveness === \"cold\") {\n const casRows = await tx.execute<{ id: string }>(sql`\n update sandbox_leases set\n liveness = 'warming',\n ${image !== null ? sql`image = ${image},` : sql``}\n updated_at = now()\n where id = ${row.id} and liveness = 'cold'\n returning id\n `);\n await upsertLeaseHolder(tx, row.id, accountId, workspaceId, kind, holderId, subjectId);\n const updated = await recomputeAndStampLease(tx, row.id, input.leaseTtlMs, null);\n // casRows.length === 0 cannot happen under the held row lock (defensive):\n // a lost CAS means a sibling flipped it first, so we attach.\n const role = casRows.length === 0 ? \"attached\" as const : \"spawner\" as const;\n return { role, lease: mapLeaseRow(updated) };\n }\n\n // -- warm: epoch fence for re-establishing turn holders (split-brain). A\n // turn arriving with expectedEpoch must match the live row epoch; a stale\n // re-dispatched turn is fenced out -> back off, NEVER create(). Number()-\n // coerced so an int8 drift cannot make the compare always-true.\n if (liveness === \"warm\" && kind === \"turn\" && input.expectedEpoch !== undefined\n && Number(row.lease_epoch) !== input.expectedEpoch) {\n return { role: \"fenced\" as const, lease: mapLeaseRow(row) };\n }\n\n // -- warm / warming: attach (A2 / A1). refcount++ ONLY; never touch\n // liveness. The spawner exclusively owns warming->warm.\n await upsertLeaseHolder(tx, row.id, accountId, workspaceId, kind, holderId, subjectId);\n const updated = await recomputeAndStampLease(tx, row.id, input.leaseTtlMs, null);\n return { role: \"attached\" as const, lease: mapLeaseRow(updated) };\n }),\n );\n}\n\n// §4.2 — the ONLY lease_epoch++ site. CAS on (warming AND lease_epoch=expected).\n// Folds the group box-envelope (resume_backend_id/resume_state) onto the lease.\nexport async function commitWarmingToWarm(db: Database, input: {\n accountId: string; workspaceId: string; sandboxGroupId: string;\n expectedEpoch: number; // the epoch the spawner observed at cold->warming\n instanceId: string;\n dataPlaneUrl?: string | null; // event-driven resolveExposedPort result, any worker\n resumeBackendId?: string | null;\n resumeState?: Record<string, unknown> | null;\n leaseTtlMs: number;\n}): Promise<{ committed: boolean; lease: LeaseSnapshot | null }> {\n return await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId },\n async (scopedDb) => {\n // resume_state is jsonb: the raw postgres driver does NOT auto-stringify a\n // plain object bound for a jsonb column, so serialize to a JSON string and\n // cast ::jsonb (null stays a real SQL null). Binding the object directly\n // throws \"string argument must be of type string\" on the wire.\n const resumeStateJson = input.resumeState == null ? null : JSON.stringify(input.resumeState);\n const rows = await scopedDb.execute<LeaseRow>(sql`\n update sandbox_leases set\n liveness = 'warm',\n instance_id = ${input.instanceId},\n data_plane_url = ${input.dataPlaneUrl ?? null},\n -- A box re-key (epoch++) invalidates the prior epoch's ttyd tunnel; the\n -- terminal URL is re-resolved + re-recorded lazily by mintTerminalStream\n -- on the next attach. Clear it here so a stale URL never survives a roll.\n terminal_data_plane_url = null,\n resume_backend_id = ${input.resumeBackendId ?? null},\n resume_state = ${resumeStateJson}::jsonb,\n lease_epoch = lease_epoch + 1,\n expires_at = now() + (${String(input.leaseTtlMs)} || ' milliseconds')::interval,\n updated_at = now()\n where workspace_id = ${input.workspaceId} and sandbox_group_id = ${input.sandboxGroupId}\n and liveness = 'warming' and lease_epoch = ${input.expectedEpoch}\n returning *\n `);\n // CAS miss = a reaper already reset this warming row to cold (the spawner\n // was too slow), or another spawner re-established and bumped the epoch.\n // The spawner MUST drop its in-memory handle and re-acquire — NEVER force\n // warm, NEVER provider-delete the box (it rides the provider idle-timeout).\n if (rows.length === 0) return { committed: false, lease: null };\n return { committed: true, lease: mapLeaseRow(rows[0]!) };\n });\n}\n\n// §4.2a — leak-proof create attribution. The spawner calls this immediately\n// after the provider create returns, before display/readiness/setup work. It\n// intentionally does NOT bump lease_epoch or mark the lease warm; it only makes\n// the just-created provider id durable while the row is still warming so a\n// failure/reaper/provider-side sweep can identify and stop it.\nexport async function recordWarmingSandboxCreated(db: Database, input: {\n accountId: string;\n workspaceId: string;\n sandboxGroupId: string;\n expectedEpoch: number;\n instanceId: string;\n resumeBackendId?: string | null;\n resumeState?: Record<string, unknown> | null;\n leaseTtlMs: number;\n}): Promise<{ recorded: boolean; lease: LeaseSnapshot | null }> {\n return await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId },\n async (scopedDb) => {\n const resumeStateJson = input.resumeState == null ? null : JSON.stringify(input.resumeState);\n const rows = await scopedDb.execute<LeaseRow>(sql`\n update sandbox_leases set\n instance_id = ${input.instanceId},\n resume_backend_id = ${input.resumeBackendId ?? null},\n resume_state = ${resumeStateJson}::jsonb,\n expires_at = now() + (${String(input.leaseTtlMs)} || ' milliseconds')::interval,\n updated_at = now()\n where workspace_id = ${input.workspaceId} and sandbox_group_id = ${input.sandboxGroupId}\n and liveness = 'warming' and lease_epoch = ${input.expectedEpoch}\n returning *\n `);\n if (rows.length === 0) return { recorded: false, lease: null };\n return { recorded: true, lease: mapLeaseRow(rows[0]!) };\n });\n}\n\n// §4.3 — caught spawn failure: warming -> cold (W3). Holders are intentionally\n// left intact — the arrival that triggered the spawn still wants a box, so the\n// next acquireLease re-CAS cold->warming.\n//\n// ARCHIVE PRESERVATION (sandbox-file-persistence): when the cold lease that was\n// selected for re-warm carried a persisted /workspace archive on its resume_state\n// (an archive-only envelope `{ backendId, sessionState: { workspaceArchive } }`\n// placed there by a prior drain), the spawn failed BEFORE commitWarmingToWarm,\n// so the LIVE box envelope was never folded onto resume_state. The warming row\n// still holds the ORIGINAL archive-only envelope. Nulling resume_state here would\n// destroy the snapshot the NEXT re-warm must replay — the same file-persistence\n// bug confirmDrainCold guards against. So we PRESERVE a minimal archive-only\n// envelope across this failure rollback (same shape confirmDrainCold keeps) and\n// retain resume_backend_id. No archive on the warming row (a never-persisted cold\n// start) -> resume_state is nulled as before.\nexport async function failWarmingToCold(db: Database, input: {\n accountId: string; workspaceId: string; sandboxGroupId: string; expectedEpoch: number;\n}): Promise<void> {\n await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId },\n async (scopedDb) => {\n await scopedDb.execute(sql`\n update sandbox_leases set\n liveness = 'cold', instance_id = null,\n data_plane_url = null, terminal_data_plane_url = null, updated_at = now(),\n resume_state = case\n when (resume_state #>> '{sessionState,workspaceArchive}') is not null\n then jsonb_build_object(\n 'backendId', coalesce(resume_state ->> 'backendId', to_jsonb(resume_backend_id) #>> '{}'),\n 'sessionState', jsonb_build_object(\n 'workspaceArchive', resume_state #> '{sessionState,workspaceArchive}'))\n else null\n end,\n resume_backend_id = case\n when (resume_state #>> '{sessionState,workspaceArchive}') is not null\n then resume_backend_id\n else null\n end\n where workspace_id = ${input.workspaceId} and sandbox_group_id = ${input.sandboxGroupId}\n and liveness = 'warming' and lease_epoch = ${input.expectedEpoch}\n `);\n });\n}\n\n// §4.4 — idempotent delete-my-row (+ opportunistic warm->draining guarded\n// refcount=0 AND turn_holders=0, so a paying turn is never drained).\nexport async function releaseLeaseHolder(db: Database, input: {\n accountId: string; workspaceId: string; sandboxGroupId: string;\n kind: LeaseHolderKind; holderId: string; idleGraceMs: number;\n}): Promise<{ liveness: SandboxLeaseLiveness; refcount: number } | null> {\n return await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId },\n async (scopedDb) => await scopedDb.transaction(async (txRaw) => {\n const tx = txRaw as unknown as Database;\n const rows = await tx.execute<LeaseRow>(sql`\n select * from sandbox_leases\n where workspace_id = ${input.workspaceId} and sandbox_group_id = ${input.sandboxGroupId}\n for update\n `);\n const row = rows[0];\n if (!row) return null; // already cold-and-reaped; release is an idempotent no-op\n\n // Idempotent: deleting an already-gone holder affects 0 rows, fine.\n await tx.execute(sql`\n delete from sandbox_lease_holders\n where lease_id = ${row.id} and kind = ${input.kind} and holder_id = ${input.holderId}\n `);\n\n const counts = await tx.execute<{ total: number; turns: number; viewers: number }>(sql`\n select count(*)::int as total,\n count(*) filter (where kind = 'turn')::int as turns,\n count(*) filter (where kind = 'viewer')::int as viewers\n from sandbox_lease_holders where lease_id = ${row.id}\n `);\n const c = counts[0]!;\n\n // warm + dropped to 0 (AND no turn holders) -> draining, stamp grace deadline.\n // Release during warming decrements only, NEVER touches liveness (the\n // spawner owns warming->warm and re-checks refcount after committing).\n const enterDraining = row.liveness === \"warm\" && c.total === 0 && c.turns === 0;\n const updated = await tx.execute<LeaseRow>(sql`\n update sandbox_leases set\n refcount = ${c.total}, turn_holders = ${c.turns}, viewer_holders = ${c.viewers},\n ${enterDraining\n ? sql`liveness = 'draining', expires_at = now() + (${String(input.idleGraceMs)} || ' milliseconds')::interval,`\n : sql``}\n updated_at = now()\n where id = ${row.id}\n returning *\n `);\n return { liveness: updated[0]!.liveness, refcount: Number(c.total) };\n }));\n}\n\n// §4.5 — heartbeat. EPOCH-FENCED (the C1b fix — the real split-brain bug, on the\n// HEARTBEAT path): a stale (superseded) owner's lease refresh is rejected so it\n// self-evicts. Also liveness-guarded to warm/warming (C2) so a heartbeat can't\n// wedge a draining lease forever by pushing its grace deadline.\nexport async function heartbeatLeaseHolder(db: Database, input: {\n accountId: string; workspaceId: string; sandboxGroupId: string;\n kind: LeaseHolderKind; holderId: string; leaseTtlMs: number; expectedEpoch: number;\n}): Promise<boolean> {\n return await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId },\n async (scopedDb) => await scopedDb.transaction(async (txRaw) => {\n const tx = txRaw as unknown as Database;\n const updated = await tx.execute<{ id: string }>(sql`\n update sandbox_lease_holders set last_heartbeat_at = now()\n where lease_id = (select id from sandbox_leases\n where workspace_id = ${input.workspaceId} and sandbox_group_id = ${input.sandboxGroupId})\n and kind = ${input.kind} and holder_id = ${input.holderId}\n returning id\n `);\n if (updated.length === 0) return false; // holder was reaped — caller re-acquires\n // Epoch-fenced, liveness-guarded lease TTL refresh: only a live-epoch\n // warm/warming lease is refreshed. A stale-epoch (split-brain) or draining\n // lease returns 0 rows -> false -> the stale holder drops its handle.\n const leaseRows = await tx.execute<{ id: string }>(sql`\n update sandbox_leases set\n expires_at = now() + (${String(input.leaseTtlMs)} || ' milliseconds')::interval,\n updated_at = now()\n where workspace_id = ${input.workspaceId} and sandbox_group_id = ${input.sandboxGroupId}\n and lease_epoch = ${input.expectedEpoch}\n and liveness in ('warm','warming')\n returning id\n `);\n return leaseRows.length > 0;\n }));\n}\n\n// §4.6 — the reaper. DB-SIDE ONLY (no provider call — the provider stop() is\n// P1.3's runtime concern). Three actions in one pass: TTL-reap stale viewer\n// holders, recompute refcounts + warm->draining, reset warming-death to cold;\n// returns the drainable (workspaceId, sandboxGroupId) rows the caller terminates.\n//\n// This is the PER-WORKSPACE entry point (RLS-scoped). The cross-workspace global\n// sweep is the SECURITY-DEFINER opengeni_private.reap_sandbox_leases() fn —\n// reapStaleLeaseHoldersGlobal below.\nexport interface ReapDrainable {\n workspaceId: string;\n sandboxGroupId: string;\n instanceId: string | null;\n leaseEpoch: number;\n}\n\nexport async function reapStaleLeaseHolders(db: Database, input: {\n workspaceId: string;\n viewerHolderTtlMs: number; // delete viewer rows older than this\n idleGraceMs: number; // drain-grace horizon (matches releaseLeaseHolder)\n}): Promise<{ reapedViewers: number; warmingReset: number; drained: ReapDrainable[] }> {\n return await withWorkspaceRls(db, input.workspaceId, async (scopedDb) =>\n await scopedDb.transaction(async (txRaw) => {\n const tx = txRaw as unknown as Database;\n // (a) Reap stale VIEWER holders (turn holders are TTL-exempt — never reaped).\n const reaped = await tx.execute<{ lease_id: string }>(sql`\n delete from sandbox_lease_holders\n where workspace_id = ${input.workspaceId} and kind = 'viewer'\n and last_heartbeat_at < now() - (${String(input.viewerHolderTtlMs)} || ' milliseconds')::interval\n returning lease_id\n `);\n\n // (b) Recompute refcounts for every lease in the workspace; warm leases\n // that hit 0 (AND turn_holders=0) enter draining with a fresh grace\n // deadline (idleGraceMs — the SAME horizon releaseLeaseHolder stamps).\n await tx.execute(sql`\n update sandbox_leases L set\n refcount = c.total,\n turn_holders = c.turns,\n viewer_holders = c.viewers,\n liveness = case when L.liveness = 'warm' and c.total = 0 and c.turns = 0\n then 'draining' else L.liveness end,\n expires_at = case when L.liveness = 'warm' and c.total = 0 and c.turns = 0\n then now() + (${String(input.idleGraceMs)} || ' milliseconds')::interval\n else L.expires_at end,\n updated_at = now()\n from (\n select L2.id,\n (select count(*) from sandbox_lease_holders h where h.lease_id = L2.id)::int as total,\n (select count(*) from sandbox_lease_holders h where h.lease_id = L2.id and h.kind = 'turn')::int as turns,\n (select count(*) from sandbox_lease_holders h where h.lease_id = L2.id and h.kind = 'viewer')::int as viewers\n from sandbox_leases L2 where L2.workspace_id = ${input.workspaceId}\n ) c\n where L.id = c.id and L.workspace_id = ${input.workspaceId}\n `);\n\n // (c1) WARMING-death before provider create returned: no instance_id was\n // ever persisted, so there is no provider box to stop. Reset to cold so a\n // queued turn can re-acquire and re-spawn.\n const warmingReset = await tx.execute<{ id: string }>(sql`\n update sandbox_leases set\n liveness = 'cold', instance_id = null,\n resume_backend_id = null, resume_state = null,\n data_plane_url = null, terminal_data_plane_url = null, updated_at = now()\n where workspace_id = ${input.workspaceId}\n and liveness = 'warming' and expires_at < now() and instance_id is null\n returning id\n `);\n\n // (c2) WARMING-death after provider create returned: instance_id is known,\n // so do NOT drop it. Convert to immediately-drainable so the caller's\n // provider terminate path stops the box before the lease goes cold.\n const warmingDrain = await tx.execute<{ id: string }>(sql`\n update sandbox_leases set\n liveness = 'draining',\n refcount = 0,\n turn_holders = 0,\n viewer_holders = 0,\n data_plane_url = null,\n terminal_data_plane_url = null,\n expires_at = now() - interval '1 millisecond',\n updated_at = now()\n where workspace_id = ${input.workspaceId}\n and liveness = 'warming' and expires_at < now() and instance_id is not null\n returning id\n `);\n\n // (d) DRAINING-grace elapsed: surface leases whose grace is up AND still\n // idle, with instance_id + epoch, so the caller can issue the provider\n // stop() then confirmDrainCold. DB-only: no provider call here.\n const drainable = await rawRows<{ sandbox_group_id: string; instance_id: string | null; lease_epoch: number | string }>(tx, sql`\n select sandbox_group_id, instance_id, lease_epoch from sandbox_leases\n where workspace_id = ${input.workspaceId}\n and liveness = 'draining' and expires_at < now() and refcount = 0\n `);\n\n return {\n reapedViewers: reaped.length,\n warmingReset: warmingReset.length + warmingDrain.length,\n drained: drainable.map((r) => ({\n workspaceId: input.workspaceId,\n sandboxGroupId: r.sandbox_group_id,\n instanceId: r.instance_id,\n leaseEpoch: Number(r.lease_epoch),\n })),\n };\n }));\n}\n\n// §4.6 (global) — the cross-workspace reaper sweep (OD-3). Calls the\n// SECURITY-DEFINER opengeni_private.reap_sandbox_leases() fn so the global\n// reaper Temporal Schedule (P1.3) sees stale rows across ALL workspaces in ONE\n// pass, bypassing per-workspace FORCE RLS. DB-only — returns the drainable rows;\n// the provider stop() is the caller's concern. No RLS GUC is set (the DEFINER fn\n// is the sanctioned cross-workspace read).\nexport async function reapStaleLeaseHoldersGlobal(db: Database, input: {\n viewerHolderTtlMs: number;\n idleGraceMs: number;\n}): Promise<ReapDrainable[]> {\n const rows = await rawRows<{ workspace_id: string; sandbox_group_id: string; instance_id: string | null; lease_epoch: number | string }>(db, sql`\n select workspace_id, sandbox_group_id, instance_id, lease_epoch\n from opengeni_private.reap_sandbox_leases(${input.viewerHolderTtlMs}, ${input.idleGraceMs})\n `);\n return rows.map((r) => ({\n workspaceId: r.workspace_id,\n sandboxGroupId: r.sandbox_group_id,\n instanceId: r.instance_id,\n leaseEpoch: Number(r.lease_epoch),\n }));\n}\n\n// §2.2 (global) — the warm-meter read for the REAPER tick (P2.1). Returns one row\n// per WARM viewer-only group (turn-held boxes are metered by the turn heartbeat,\n// so they are EXCLUDED here — no double-meter). Cross-workspace via the\n// SECURITY-DEFINER list fn (FORCE RLS would hide other workspaces from the scoped\n// connection). DB-only read; the worker accrues per row via accrueWarmSeconds.\nexport interface MeterableWarmLease {\n accountId: string;\n workspaceId: string;\n sandboxGroupId: string;\n leaseEpoch: number;\n backend: string;\n}\n\nexport async function listMeterableWarmLeases(db: Database): Promise<MeterableWarmLease[]> {\n const rows = await rawRows<{ account_id: string; workspace_id: string; sandbox_group_id: string; lease_epoch: number | string; backend: string }>(db, sql`\n select account_id, workspace_id, sandbox_group_id, lease_epoch, backend\n from opengeni_private.list_meterable_warm_leases()\n `);\n return rows.map((r) => ({\n accountId: r.account_id,\n workspaceId: r.workspace_id,\n sandboxGroupId: r.sandbox_group_id,\n leaseEpoch: Number(r.lease_epoch),\n backend: r.backend,\n }));\n}\n\nexport async function countQueuedTurns(db: Database): Promise<number> {\n const rows = await rawRows<{ count: number | string }>(db, sql`\n select opengeni_private.count_queued_turns() as count\n `);\n return Number(rows[0]?.count ?? 0);\n}\n\nexport async function countSandboxLeasesByLiveness(db: Database): Promise<Record<SandboxLeaseLiveness, number>> {\n const counts: Record<SandboxLeaseLiveness, number> = {\n cold: 0,\n warming: 0,\n warm: 0,\n draining: 0,\n };\n const rows = await rawRows<{ liveness: SandboxLeaseLiveness; count: number | string }>(db, sql`\n select liveness, count\n from opengeni_private.count_sandbox_leases_by_liveness()\n `);\n for (const row of rows) {\n if (row.liveness in counts) {\n counts[row.liveness] = Number(row.count);\n }\n }\n return counts;\n}\n\n// Cross-workspace live Modal lease read for the provider-side orphan sweep. The\n// SECURITY DEFINER function is the sanctioned RLS bypass; see migration 0036.\nexport async function listLiveModalSandboxLeaseAttributions(db: Database): Promise<LiveModalSandboxLeaseAttribution[]> {\n const rows = await rawRows<{\n lease_id: string;\n workspace_id: string;\n sandbox_group_id: string;\n instance_id: string | null;\n liveness: SandboxLeaseLiveness;\n }>(db, sql`\n select lease_id, workspace_id, sandbox_group_id, instance_id, liveness\n from opengeni_private.list_live_modal_sandbox_leases()\n `);\n return rows.map((r) => ({\n leaseId: r.lease_id,\n workspaceId: r.workspace_id,\n sandboxGroupId: r.sandbox_group_id,\n instanceId: r.instance_id,\n liveness: r.liveness,\n }));\n}\n\n// §4.7 — explicit re-arm seam (D1). acquireLease already re-arms a draining\n// lease inline; this is the standalone version for callers that learn a holder\n// is wanted during the grace window without going through acquireLease first.\nexport async function reArmDrainingLease(db: Database, input: {\n accountId: string; workspaceId: string; sandboxGroupId: string; leaseTtlMs: number;\n}): Promise<{ rearmed: boolean }> {\n return await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId },\n async (scopedDb) => {\n const rows = await scopedDb.execute<{ id: string }>(sql`\n update sandbox_leases set\n liveness = 'warm',\n expires_at = now() + (${String(input.leaseTtlMs)} || ' milliseconds')::interval,\n updated_at = now()\n where workspace_id = ${input.workspaceId} and sandbox_group_id = ${input.sandboxGroupId}\n and liveness = 'draining'\n returning id\n `);\n return { rearmed: rows.length > 0 };\n });\n}\n\n// §4.8 — the reaper's final teardown commit (D3). Called AFTER the caller issued\n// the provider stop() on instance_id. CAS-guarded (draining AND refcount=0 AND\n// lease_epoch=expected) so a late re-arm (D1) or a newer epoch that snuck in\n// during teardown wins — wentCold:false means the box is still wanted and must\n// NOT have been stopped (the caller checks this CAS before stop(), or re-reads).\nexport async function confirmDrainCold(db: Database, input: {\n accountId: string; workspaceId: string; sandboxGroupId: string; expectedEpoch: number;\n}): Promise<{ wentCold: boolean }> {\n return await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId },\n async (scopedDb) => {\n // draining->cold: the box is terminated, so EVERY live-box field is cleared\n // (instance_id / data-plane URLs). resume_state, however, is NOT blindly\n // nulled — if the reaper PERSISTED a /workspace snapshot onto it\n // (persistDrainSnapshot folds the archive at resume_state.sessionState.\n // workspaceArchive BEFORE this CAS, in the SAME sweep), nulling it here would\n // immediately destroy the snapshot the next cold-restore must replay — the\n // file-persistence bug. So we PRESERVE a MINIMAL archive-only envelope\n // `{ backendId, sessionState: { workspaceArchive } }` (dropping the dead box's\n // providerState/sandboxId — the box is gone, resume-by-id would only fail) and\n // KEEP resume_backend_id so cold-restore knows which client to hydrate with.\n // No archive (a non-persisted drain, or a 'none'/tar config that stored none)\n // -> resume_state is nulled as before. The archive then rides the COLD lease's\n // resume_state until the next spawner reads + hydrates it; it is re-superseded\n // (GC'd) on the next drain and finally cleared on workspace teardown.\n const rows = await scopedDb.execute<{ id: string }>(sql`\n update sandbox_leases set\n liveness = 'cold', instance_id = null,\n data_plane_url = null, terminal_data_plane_url = null, updated_at = now(),\n resume_state = case\n when (resume_state #>> '{sessionState,workspaceArchive}') is not null\n then jsonb_build_object(\n 'backendId', coalesce(resume_state ->> 'backendId', to_jsonb(resume_backend_id) #>> '{}'),\n 'sessionState', jsonb_build_object(\n 'workspaceArchive', resume_state #> '{sessionState,workspaceArchive}'))\n else null\n end,\n resume_backend_id = case\n when (resume_state #>> '{sessionState,workspaceArchive}') is not null\n then resume_backend_id\n else null\n end\n where workspace_id = ${input.workspaceId} and sandbox_group_id = ${input.sandboxGroupId}\n and liveness = 'draining' and refcount = 0 and lease_epoch = ${input.expectedEpoch}\n returning id\n `);\n return { wentCold: rows.length > 0 };\n });\n}\n\n// §4.8b — persist the /workspace snapshot archive onto the lease BEFORE the\n// reaper terminates a drained box (sandbox-file-persistence). The reaper, after\n// resuming the live box and capturing `session.persistWorkspace()` (a base64\n// snapshot-ref / tar archive), CAS-folds it onto the lease's resume_state under\n// the SAME epoch fence confirmDrainCold uses (draining AND refcount=0 AND\n// lease_epoch=expected). Folding it into resume_state.sessionState.workspaceArchive\n// means a later cold-restore (establishSandboxSessionFromEnvelope) reads it back\n// off the same envelope it already deserializes, and confirmDrainCold's\n// `resume_state = null` clears it on teardown for free (delete-on-teardown).\n//\n// When workspaceArchive is null this function acts as a PURE CAS-GATE: it checks\n// (draining AND refcount=0 AND epoch=expected) under a FOR UPDATE lock and returns\n// wrote:true/false WITHOUT writing anything. This allows the reaper to guard a\n// terminate that produced no archive (a backend with no persistWorkspace) against\n// the re-arm race: a re-arm during the snapshot window sets refcount>0 / liveness!=\n// draining, so wrote:false → the reaper MUST NOT delete the box.\n//\n// Returns `{ wrote, priorArchive }`:\n// - wrote:false -> the CAS missed (re-armed / newer epoch / vanished); the\n// caller must NOT terminate (the box is wanted again). No GC.\n// - priorArchive -> the archive THIS lease carried before (if any), so the\n// caller can best-effort delete the superseded provider\n// snapshot (keep-latest-per-lease GC). null on the first\n// persist for this box or when workspaceArchive is null.\n// The fence is the split-brain guard: a stale-epoch reaper writes ZERO rows and\n// is told not to terminate.\nexport async function persistDrainSnapshot(db: Database, input: {\n accountId: string; workspaceId: string; sandboxGroupId: string;\n expectedEpoch: number;\n /** base64 of the provider snapshot-ref / tar archive from persistWorkspace().\n * Pass null to CAS-check without writing (for backends with no persistWorkspace). */\n workspaceArchive: string | null;\n}): Promise<{ wrote: boolean; priorArchive: string | null }> {\n // withRlsContext already runs `fn` inside ONE transaction with the RLS GUCs set,\n // so the SELECT...FOR UPDATE + UPDATE below are atomic (one snapshot, one lock)\n // WITHOUT an extra nested savepoint — nesting a second transaction here under\n // the RLS-scoped connection wedges the postgres-js client (\"Failed query\").\n return await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId },\n async (scopedDb) => {\n // (1) Lock + read the PRIOR archive under the CAS guard (draining AND\n // refcount=0 AND lease_epoch=expected). A miss (re-armed / newer epoch /\n // vanished) returns no row → wrote:false, the caller must NOT terminate.\n const guard = await scopedDb.execute<{ prior_archive: string | null }>(sql`\n select resume_state #>> '{sessionState,workspaceArchive}' as prior_archive\n from sandbox_leases\n where workspace_id = ${input.workspaceId} and sandbox_group_id = ${input.sandboxGroupId}\n and liveness = 'draining' and refcount = 0 and lease_epoch = ${input.expectedEpoch}\n for update\n `);\n if (guard.length === 0) {\n return { wrote: false, priorArchive: null };\n }\n const priorArchive = guard[0]!.prior_archive ?? null;\n // null workspaceArchive = pure CAS-check (re-arm guard for no-archive backends).\n // The FOR UPDATE lock above is the only synchronization needed; no write.\n if (input.workspaceArchive === null) {\n return { wrote: true, priorArchive: null };\n }\n // (2) Merge the NEW archive into resume_state.sessionState.workspaceArchive.\n // jsonb_set's create_missing does NOT create intermediate objects, so a\n // direct set of '{sessionState,workspaceArchive}' is a silent no-op when\n // `sessionState` is absent (a null resume_state, or a legacy flat envelope).\n // Instead: rebuild `sessionState` as (existing sessionState OR '{}') merged\n // (||) with `{workspaceArchive: <b64>}` — this CREATES sessionState if absent\n // AND preserves its existing siblings (providerState/manifest/exposedPorts).\n // The archive is bound as a jsonb string scalar (to_jsonb(text)). Re-asserting\n // the CAS guard keeps the write atomic with the FOR UPDATE lock above.\n await scopedDb.execute(sql`\n update sandbox_leases set\n resume_state = jsonb_set(\n -- Defensive: only treat resume_state / its sessionState as an object\n -- when it actually IS one; a null/scalar (legacy or malformed envelope)\n -- starts from '{}' so jsonb_set never throws \"cannot set path in scalar\".\n case when jsonb_typeof(resume_state) = 'object' then resume_state else '{}'::jsonb end,\n '{sessionState}',\n (case when jsonb_typeof(resume_state -> 'sessionState') = 'object'\n then resume_state -> 'sessionState' else '{}'::jsonb end)\n || jsonb_build_object('workspaceArchive', to_jsonb(${input.workspaceArchive}::text)),\n true\n ),\n updated_at = now()\n where workspace_id = ${input.workspaceId} and sandbox_group_id = ${input.sandboxGroupId}\n and liveness = 'draining' and refcount = 0 and lease_epoch = ${input.expectedEpoch}\n `);\n return { wrote: true, priorArchive };\n });\n}\n\n// §4.9 — non-locking snapshot for the API handshake & health.\nexport async function readLease(db: Database, workspaceId: string, sandboxGroupId: string): Promise<LeaseSnapshot | null> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const rows = await scopedDb.execute<LeaseRow>(sql`\n select * from sandbox_leases\n where workspace_id = ${workspaceId} and sandbox_group_id = ${sandboxGroupId}\n limit 1\n `);\n return rows[0] ? mapLeaseRow(rows[0]) : null;\n });\n}\n\n// P4.2 — record the (re-)resolved desktop data-plane URL on an ALREADY-WARM\n// lease, EPOCH-FENCED. commitWarmingToWarm records the URL at cold→warming→warm\n// (the spawn path); this is the WARM-path counterpart used when a viewer mints\n// the URL against a box that some other holder already brought up, and on\n// rollover-rotation (re-resolve under the current epoch). The fence is the\n// split-brain guard: a stale-epoch writer (a box re-established under a newer\n// epoch) updates ZERO rows and the caller backs off. Returns the updated\n// snapshot, or null on a fence miss (epoch advanced / lease vanished).\nexport async function recordLeaseDataPlaneUrl(db: Database, input: {\n accountId: string;\n workspaceId: string;\n sandboxGroupId: string;\n expectedEpoch: number;\n dataPlaneUrl: string | null;\n}): Promise<LeaseSnapshot | null> {\n return await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId },\n async (scopedDb) => {\n const rows = await scopedDb.execute<LeaseRow>(sql`\n update sandbox_leases set\n data_plane_url = ${input.dataPlaneUrl ?? null},\n updated_at = now()\n where workspace_id = ${input.workspaceId} and sandbox_group_id = ${input.sandboxGroupId}\n and lease_epoch = ${input.expectedEpoch}\n and liveness in ('warm', 'draining')\n returning *\n `);\n return rows[0] ? mapLeaseRow(rows[0]) : null;\n });\n}\n\n// P5.t — record the (re-)resolved ttyd terminal data-plane URL (7681) on an\n// ALREADY-WARM lease, EPOCH-FENCED. The exact terminal twin of\n// recordLeaseDataPlaneUrl: the REAL PTY rides a SEPARATE provider tunnel from the\n// desktop noVNC, so its URL is cached in its own column. mintTerminalStream calls\n// this after resolving the 7681 tunnel; the fast-path then re-mints only a fresh\n// token against the cached URL. The fence is the split-brain guard (a stale-epoch\n// writer updates ZERO rows). Returns the updated snapshot, or null on a fence\n// miss (epoch advanced / lease vanished).\nexport async function recordLeaseTerminalDataPlaneUrl(db: Database, input: {\n accountId: string;\n workspaceId: string;\n sandboxGroupId: string;\n expectedEpoch: number;\n terminalDataPlaneUrl: string | null;\n}): Promise<LeaseSnapshot | null> {\n return await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId },\n async (scopedDb) => {\n const rows = await scopedDb.execute<LeaseRow>(sql`\n update sandbox_leases set\n terminal_data_plane_url = ${input.terminalDataPlaneUrl ?? null},\n updated_at = now()\n where workspace_id = ${input.workspaceId} and sandbox_group_id = ${input.sandboxGroupId}\n and lease_epoch = ${input.expectedEpoch}\n and liveness in ('warm', 'draining')\n returning *\n `);\n return rows[0] ? mapLeaseRow(rows[0]) : null;\n });\n}\n\n// ============================================================================\n// Bring-your-own-compute (M2): first-class swappable sandboxes + enrollment +\n// per-machine metrics + the per-session epoch-fenced active-sandbox pointer\n// (migration 0024 / dossier §10.3 + §10.7 + §23). All workspace-scoped behind\n// the same RLS the lease DAOs use.\n// ============================================================================\n\nexport type SandboxKind = (typeof schema.sandboxKindValues)[number];\nexport type EnrollmentExposure = (typeof schema.enrollmentExposureValues)[number];\nexport type EnrollmentStatus = (typeof schema.enrollmentStatusValues)[number];\nexport type EnrollmentOs = (typeof schema.enrollmentOsValues)[number];\n\nexport type EnrollmentRecord = {\n id: string;\n accountId: string;\n workspaceId: string;\n pubkey: string;\n exposure: EnrollmentExposure;\n hasDisplay: boolean;\n allowScreenControl: boolean;\n status: EnrollmentStatus;\n os: EnrollmentOs;\n arch: string;\n lastSeenAt: string | null;\n createdAt: string;\n revokedAt: string | null;\n updatedAt: string;\n};\n\nfunction mapEnrollment(row: typeof schema.enrollments.$inferSelect): EnrollmentRecord {\n return {\n id: row.id,\n accountId: row.accountId,\n workspaceId: row.workspaceId,\n pubkey: row.pubkey,\n exposure: row.exposure as EnrollmentExposure,\n hasDisplay: row.hasDisplay,\n allowScreenControl: row.allowScreenControl,\n status: row.status as EnrollmentStatus,\n os: row.os as EnrollmentOs,\n arch: row.arch,\n lastSeenAt: row.lastSeenAt ? row.lastSeenAt.toISOString() : null,\n createdAt: row.createdAt.toISOString(),\n revokedAt: row.revokedAt ? row.revokedAt.toISOString() : null,\n updatedAt: row.updatedAt.toISOString(),\n };\n}\n\nexport type SandboxRecord = {\n id: string;\n accountId: string;\n workspaceId: string;\n kind: SandboxKind;\n name: string;\n enrollmentId: string | null;\n createdAt: string;\n updatedAt: string;\n};\n\nfunction mapSandbox(row: typeof schema.sandboxes.$inferSelect): SandboxRecord {\n return {\n id: row.id,\n accountId: row.accountId,\n workspaceId: row.workspaceId,\n kind: row.kind as SandboxKind,\n name: row.name,\n enrollmentId: row.enrollmentId ?? null,\n createdAt: row.createdAt.toISOString(),\n updatedAt: row.updatedAt.toISOString(),\n };\n}\n\n// ---- enrollments ----------------------------------------------------------\n\n// Register (or idempotently re-register) a machine. A re-enroll of the SAME\n// (workspace, pubkey) is an UPSERT — it refreshes the consent/OS fields and, if\n// the machine was previously revoked, re-activates it (status->active, revoked_at\n// cleared) — never a duplicate machine row. The agent's ed25519 pubkey is the\n// machine identity; the unique (workspace, pubkey) index is the conflict target.\nexport async function createEnrollment(db: Database, input: {\n accountId: string;\n workspaceId: string;\n pubkey: string;\n exposure?: EnrollmentExposure;\n hasDisplay?: boolean;\n allowScreenControl?: boolean;\n os?: EnrollmentOs;\n arch?: string;\n}): Promise<EnrollmentRecord> {\n return await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId }, async (scopedDb) => {\n const [row] = await scopedDb.insert(schema.enrollments).values({\n accountId: input.accountId,\n workspaceId: input.workspaceId,\n pubkey: input.pubkey,\n exposure: input.exposure ?? \"whole-machine\",\n hasDisplay: input.hasDisplay ?? false,\n allowScreenControl: input.allowScreenControl ?? false,\n os: input.os ?? \"linux\",\n arch: input.arch ?? \"x86_64\",\n status: \"active\",\n }).onConflictDoUpdate({\n target: [schema.enrollments.workspaceId, schema.enrollments.pubkey],\n set: {\n exposure: input.exposure ?? \"whole-machine\",\n hasDisplay: input.hasDisplay ?? false,\n allowScreenControl: input.allowScreenControl ?? false,\n os: input.os ?? \"linux\",\n arch: input.arch ?? \"x86_64\",\n // A re-enroll re-activates a previously revoked machine.\n status: \"active\",\n revokedAt: null,\n updatedAt: new Date(),\n },\n }).returning();\n if (!row) {\n throw new Error(\"Failed to create enrollment\");\n }\n return mapEnrollment(row);\n });\n}\n\nexport async function getEnrollment(db: Database, workspaceId: string, enrollmentId: string): Promise<EnrollmentRecord | null> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const [row] = await scopedDb.select().from(schema.enrollments)\n .where(and(eq(schema.enrollments.workspaceId, workspaceId), eq(schema.enrollments.id, enrollmentId)))\n .limit(1);\n return row ? mapEnrollment(row) : null;\n });\n}\n\n// List a workspace's enrollments, newest first. `status` filters the lifecycle\n// (omit for all; 'active' for the Machines dashboard's live list).\nexport async function listEnrollments(db: Database, workspaceId: string, options: { status?: EnrollmentStatus } = {}): Promise<EnrollmentRecord[]> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const where = options.status\n ? and(eq(schema.enrollments.workspaceId, workspaceId), eq(schema.enrollments.status, options.status))\n : eq(schema.enrollments.workspaceId, workspaceId);\n const rows = await scopedDb.select().from(schema.enrollments)\n .where(where)\n .orderBy(desc(schema.enrollments.createdAt));\n return rows.map(mapEnrollment);\n });\n}\n\n// Revoke a machine (uninstall --purge / dashboard revoke). Idempotent: an already\n// -revoked row is a no-op (revoked:false). status->revoked, revoked_at stamped.\nexport async function revokeEnrollment(db: Database, input: {\n accountId: string; workspaceId: string; enrollmentId: string;\n}): Promise<{ revoked: boolean }> {\n return await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId }, async (scopedDb) => {\n const rows = await scopedDb.update(schema.enrollments)\n .set({ status: \"revoked\", revokedAt: new Date(), updatedAt: new Date() })\n .where(and(\n eq(schema.enrollments.workspaceId, input.workspaceId),\n eq(schema.enrollments.id, input.enrollmentId),\n eq(schema.enrollments.status, \"active\"),\n ))\n .returning({ id: schema.enrollments.id });\n return { revoked: rows.length > 0 };\n });\n}\n\n// Heartbeat liveness cursor: the agent reports it is alive. last_seen_at is read\n// by the online/reconnecting/offline derivation in the Machines surface.\nexport async function touchEnrollmentLastSeen(db: Database, input: {\n accountId: string; workspaceId: string; enrollmentId: string;\n}): Promise<void> {\n await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId }, async (scopedDb) => {\n await scopedDb.update(schema.enrollments)\n .set({ lastSeenAt: new Date(), updatedAt: new Date() })\n .where(and(\n eq(schema.enrollments.workspaceId, input.workspaceId),\n eq(schema.enrollments.id, input.enrollmentId),\n ));\n });\n}\n\n// Live display cursor: the agent's connect Hello reports whether a display is\n// present RIGHT NOW (a desktop framebuffer probes). Unlike `has_display` set once\n// at enroll time from the enroll-offer snapshot, this tracks REALITY across the\n// machine's life — a Mac that later grants Screen Recording, or a Linux box whose\n// Xvfb starts after enrollment, flips false→true on its next Hello (and a display\n// that goes away flips true→false). CHANGE-GUARDED at the SQL layer (the `ne`\n// predicate): a Hello that reports the same value the row already holds updates\n// zero rows, so a steady state never churns a write. Returns whether a row was\n// actually changed. Best-effort — the caller swallows failures so a display\n// refresh never breaks the agent's connect.\nexport async function setEnrollmentHasDisplay(db: Database, input: {\n accountId: string; workspaceId: string; enrollmentId: string; hasDisplay: boolean;\n}): Promise<{ updated: boolean }> {\n return await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId }, async (scopedDb) => {\n const rows = await scopedDb.update(schema.enrollments)\n .set({ hasDisplay: input.hasDisplay, updatedAt: new Date() })\n .where(and(\n eq(schema.enrollments.workspaceId, input.workspaceId),\n eq(schema.enrollments.id, input.enrollmentId),\n // Only write on a CHANGE — an unchanged display must not churn a write on\n // every reconnect Hello.\n ne(schema.enrollments.hasDisplay, input.hasDisplay),\n ))\n .returning({ id: schema.enrollments.id });\n return { updated: rows.length > 0 };\n });\n}\n\n// ---- device-flow enrollment requests (M5, migration 0025) -----------------\n//\n// The OAuth 2.0 device-authorization (RFC 8628) PENDING request: one short-TTL,\n// single-use row per in-flight enrollment. The agent starts a flow (gets a\n// device_code + user_code), the user approves it (LOUD consent capture +\n// createEnrollment + createSandbox), and the agent polls the device_code for the\n// resulting EnrollmentCredentials. Dossier §10.2 + §18.\n\nexport type DeviceEnrollmentStatus = (typeof schema.deviceEnrollmentStatusValues)[number];\n\nexport type DeviceEnrollmentRequestRecord = {\n id: string;\n deviceCode: string;\n userCode: string;\n accountId: string;\n workspaceId: string;\n pubkey: string;\n os: EnrollmentOs;\n arch: string;\n machineName: string | null;\n requestedExposure: EnrollmentExposure;\n canOfferDisplay: boolean;\n requestsScreenControl: boolean;\n status: DeviceEnrollmentStatus;\n approvedBySubjectId: string | null;\n approvedBySubjectLabel: string | null;\n allowScreenControl: boolean;\n approvedAt: string | null;\n enrollmentId: string | null;\n sandboxId: string | null;\n expiresAt: string;\n createdAt: string;\n updatedAt: string;\n};\n\nfunction mapDeviceEnrollmentRequest(row: typeof schema.deviceEnrollmentRequests.$inferSelect): DeviceEnrollmentRequestRecord {\n return {\n id: row.id,\n deviceCode: row.deviceCode,\n userCode: row.userCode,\n accountId: row.accountId,\n workspaceId: row.workspaceId,\n pubkey: row.pubkey,\n os: row.os as EnrollmentOs,\n arch: row.arch,\n machineName: row.machineName ?? null,\n requestedExposure: row.requestedExposure as EnrollmentExposure,\n canOfferDisplay: row.canOfferDisplay,\n requestsScreenControl: row.requestsScreenControl,\n status: row.status as DeviceEnrollmentStatus,\n approvedBySubjectId: row.approvedBySubjectId ?? null,\n approvedBySubjectLabel: row.approvedBySubjectLabel ?? null,\n allowScreenControl: row.allowScreenControl,\n approvedAt: row.approvedAt ? row.approvedAt.toISOString() : null,\n enrollmentId: row.enrollmentId ?? null,\n sandboxId: row.sandboxId ?? null,\n expiresAt: row.expiresAt.toISOString(),\n createdAt: row.createdAt.toISOString(),\n updatedAt: row.updatedAt.toISOString(),\n };\n}\n\n// Persist a fresh PENDING device-auth request (the agent's POST /start). The\n// caller supplies the unguessable device_code + user_code (minted with a CSPRNG)\n// and the short TTL. RLS-scoped to the workspace the flow binds to.\nexport async function createDeviceEnrollmentRequest(db: Database, input: {\n accountId: string;\n workspaceId: string;\n deviceCode: string;\n userCode: string;\n pubkey: string;\n os?: EnrollmentOs;\n arch?: string;\n machineName?: string | null;\n requestedExposure?: EnrollmentExposure;\n canOfferDisplay?: boolean;\n requestsScreenControl?: boolean;\n expiresAt: Date;\n}): Promise<DeviceEnrollmentRequestRecord> {\n return await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId }, async (scopedDb) => {\n const [row] = await scopedDb.insert(schema.deviceEnrollmentRequests).values({\n accountId: input.accountId,\n workspaceId: input.workspaceId,\n deviceCode: input.deviceCode,\n userCode: input.userCode,\n pubkey: input.pubkey,\n os: input.os ?? \"linux\",\n arch: input.arch ?? \"x86_64\",\n machineName: input.machineName ?? null,\n requestedExposure: input.requestedExposure ?? \"whole-machine\",\n canOfferDisplay: input.canOfferDisplay ?? false,\n requestsScreenControl: input.requestsScreenControl ?? false,\n status: \"pending\",\n expiresAt: input.expiresAt,\n }).returning();\n if (!row) {\n throw new Error(\"Failed to create device enrollment request\");\n }\n return mapDeviceEnrollmentRequest(row);\n });\n}\n\n// Look up a request by its opaque device_code (the agent's poll key). The\n// device_code IS the capability (unguessable + unique) and the agent has NO\n// workspace context yet, so resolve (account_id, workspace_id) via the SECURITY\n// DEFINER resolver (mirrors the global reaper's cross-workspace read), then re-read\n// the FULL row under that workspace's RLS scope. Returns null when unknown.\nexport async function getDeviceEnrollmentRequestByDeviceCode(db: Database, deviceCode: string): Promise<DeviceEnrollmentRequestRecord | null> {\n const resolved = await db.execute<{ account_id: string; workspace_id: string }>(sql`\n select account_id, workspace_id from opengeni_private.resolve_device_enrollment_request(${deviceCode})\n `);\n const ctx = resolved[0];\n if (!ctx) {\n return null;\n }\n return await withRlsContext(db, { accountId: ctx.account_id, workspaceId: ctx.workspace_id }, async (scopedDb) => {\n const [row] = await scopedDb.select().from(schema.deviceEnrollmentRequests)\n .where(eq(schema.deviceEnrollmentRequests.deviceCode, deviceCode))\n .limit(1);\n return row ? mapDeviceEnrollmentRequest(row) : null;\n });\n}\n\n// Look up the PENDING request for a user_code within a workspace (the approve\n// lookup). Workspace-scoped: a user can only approve a request bound to a\n// workspace they hold a grant in. Returns null when no LIVE pending row matches.\nexport async function getPendingDeviceEnrollmentRequestByUserCode(db: Database, workspaceId: string, userCode: string): Promise<DeviceEnrollmentRequestRecord | null> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const [row] = await scopedDb.select().from(schema.deviceEnrollmentRequests)\n .where(and(\n eq(schema.deviceEnrollmentRequests.workspaceId, workspaceId),\n eq(schema.deviceEnrollmentRequests.userCode, userCode),\n eq(schema.deviceEnrollmentRequests.status, \"pending\"),\n ))\n .limit(1);\n return row ? mapDeviceEnrollmentRequest(row) : null;\n });\n}\n\n// Look up the PENDING request for a user_code GLOBALLY (no workspace context) —\n// the click-Grant approve page lookup (design 11 §B.1). The user_code is globally\n// unique among LIVE (pending) rows, so — exactly like getDeviceEnrollmentRequestByDeviceCode\n// resolves a device_code — this resolves (account_id, workspace_id) via the 0026\n// SECURITY DEFINER resolver, then re-reads the FULL pending row under that\n// workspace's RLS scope. The ROUTE then re-checks the caller holds a grant in the\n// resolved workspace before returning anything. Returns null when no live pending\n// row matches (an unknown / terminal / expired code).\nexport async function getPendingDeviceEnrollmentRequestByUserCodeGlobal(db: Database, userCode: string): Promise<DeviceEnrollmentRequestRecord | null> {\n const resolved = await db.execute<{ account_id: string; workspace_id: string }>(sql`\n select account_id, workspace_id from opengeni_private.resolve_pending_device_enrollment_by_user_code(${userCode})\n `);\n const ctx = resolved[0];\n if (!ctx) {\n return null;\n }\n return await withRlsContext(db, { accountId: ctx.account_id, workspaceId: ctx.workspace_id }, async (scopedDb) => {\n const [row] = await scopedDb.select().from(schema.deviceEnrollmentRequests)\n .where(and(\n eq(schema.deviceEnrollmentRequests.userCode, userCode),\n eq(schema.deviceEnrollmentRequests.status, \"pending\"),\n ))\n .limit(1);\n return row ? mapDeviceEnrollmentRequest(row) : null;\n });\n}\n\n// The SHARED finalize core (design 11 §A2.3 \"reuse, don't fork\"): \"upsert the\n// enrollment (idempotent on (workspace_id, pubkey)) + ensure a kind='selfhosted'\n// sandbox row\" — the exact end state BOTH the device approve and the headless\n// token exchange must produce. Takes an ALREADY-RLS-SCOPED `scopedDb` so the\n// caller controls the transaction boundary:\n// * approveDeviceEnrollmentRequest calls it INSIDE its FOR-UPDATE txn (so the\n// re-read fence + the request stamp stay in ONE txn — semantics unchanged), and\n// * finalizeEnrollmentByToken calls it inside its OWN txn (no pending row exists\n// for a stateless token).\n// Idempotent: a re-run for the same (workspace, pubkey) re-activates the existing\n// enrollment (M2 upsert) and REUSES its selfhosted sandbox — never a duplicate.\nasync function finalizeEnrollmentInScope(scopedDb: Database, input: {\n accountId: string;\n workspaceId: string;\n pubkey: string;\n hasDisplay: boolean;\n allowScreenControl: boolean;\n os: EnrollmentOs;\n arch: string;\n sandboxName: string;\n now: Date;\n}): Promise<{ enrollment: EnrollmentRecord; sandbox: SandboxRecord }> {\n // createEnrollment (idempotent upsert) — whole-machine is mandatory; display +\n // screen-control come from the agent's offer + the consenting decision. We inline\n // the insert here (rather than calling createEnrollment, which opens its OWN\n // scope) so it shares the caller's transaction.\n const [enrollmentRow] = await scopedDb.insert(schema.enrollments).values({\n accountId: input.accountId,\n workspaceId: input.workspaceId,\n pubkey: input.pubkey,\n exposure: \"whole-machine\",\n hasDisplay: input.hasDisplay,\n allowScreenControl: input.allowScreenControl,\n os: input.os,\n arch: input.arch,\n status: \"active\",\n }).onConflictDoUpdate({\n target: [schema.enrollments.workspaceId, schema.enrollments.pubkey],\n set: {\n exposure: \"whole-machine\",\n hasDisplay: input.hasDisplay,\n allowScreenControl: input.allowScreenControl,\n os: input.os,\n arch: input.arch,\n status: \"active\",\n revokedAt: null,\n updatedAt: input.now,\n },\n }).returning();\n if (!enrollmentRow) {\n throw new Error(\"Failed to create enrollment during finalize\");\n }\n const enrollment = mapEnrollment(enrollmentRow);\n\n // Ensure a selfhosted sandbox for this enrollment. A re-finalize of the SAME\n // machine reuses the existing sandbox rather than creating a duplicate.\n const [existingSandbox] = await scopedDb.select().from(schema.sandboxes)\n .where(and(\n eq(schema.sandboxes.workspaceId, input.workspaceId),\n eq(schema.sandboxes.enrollmentId, enrollment.id),\n ))\n .limit(1);\n let sandbox: SandboxRecord;\n if (existingSandbox) {\n sandbox = mapSandbox(existingSandbox);\n } else {\n const [sandboxRow] = await scopedDb.insert(schema.sandboxes).values({\n accountId: input.accountId,\n workspaceId: input.workspaceId,\n kind: \"selfhosted\",\n name: input.sandboxName,\n enrollmentId: enrollment.id,\n }).returning();\n if (!sandboxRow) {\n throw new Error(\"Failed to create sandbox during finalize\");\n }\n sandbox = mapSandbox(sandboxRow);\n }\n return { enrollment, sandbox };\n}\n\n// FINALIZE a headless enroll-token exchange (design 11 §A2.3). Produces the SAME\n// end state as approveDeviceEnrollmentRequest — an enrollments row + a selfhosted\n// sandbox row — but WITHOUT a pending device-flow request (a stateless `oget_`\n// token carries the grant). Idempotent via the shared finalize core's upsert.\nexport async function finalizeEnrollmentByToken(db: Database, input: {\n accountId: string;\n workspaceId: string;\n pubkey: string;\n hasDisplay: boolean;\n allowScreenControl: boolean;\n os: EnrollmentOs;\n arch: string;\n sandboxName: string;\n now?: Date;\n}): Promise<{ enrollment: EnrollmentRecord; sandbox: SandboxRecord }> {\n const now = input.now ?? new Date();\n return await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId }, async (scopedDb) => {\n return await finalizeEnrollmentInScope(scopedDb, {\n accountId: input.accountId,\n workspaceId: input.workspaceId,\n pubkey: input.pubkey,\n hasDisplay: input.hasDisplay,\n allowScreenControl: input.allowScreenControl,\n os: input.os,\n arch: input.arch,\n sandboxName: input.sandboxName,\n now,\n });\n });\n}\n\n// THE LOUD-CONSENT APPROVE (the user's POST /approve). In ONE transaction:\n// 1. re-read the pending row FOR UPDATE (fence against a double-approve / a\n// concurrent expiry),\n// 2. createEnrollment (idempotent upsert: pubkey, whole-machine exposure,\n// has_display from can_offer_display, allow_screen_control per the user's\n// decision, os/arch) → an enrollments row,\n// 3. createSandbox (kind selfhosted, enrollment_id, a generated name) → a\n// sandboxes row (acceptance #2),\n// 4. stamp the request approved + the consent record (WHO approved WHEN to WHAT)\n// + the resulting enrollment_id / sandbox_id.\n// IDEMPOTENT: a re-approve of an ALREADY-approved row (same user_code re-submitted)\n// re-runs the enrollment upsert (M2 reactivate semantics) and returns the existing\n// enrollment/sandbox — never a duplicate. An expired / denied / consumed row is a\n// no-op (approved:false). Returns the enrollment + sandbox so the route echoes them.\nexport async function approveDeviceEnrollmentRequest(db: Database, input: {\n accountId: string;\n workspaceId: string;\n requestId: string;\n allowScreenControl: boolean;\n approvedBySubjectId: string;\n approvedBySubjectLabel?: string | null;\n // A name for the generated sandbox (machine name or a fallback).\n sandboxName: string;\n now?: Date;\n}): Promise<{ approved: boolean; enrollment: EnrollmentRecord | null; sandbox: SandboxRecord | null }> {\n const now = input.now ?? new Date();\n return await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId }, async (scopedDb) => {\n // Re-read FOR UPDATE under the txn so a concurrent approve / expiry can't race.\n const [pending] = await scopedDb.select().from(schema.deviceEnrollmentRequests)\n .where(and(\n eq(schema.deviceEnrollmentRequests.workspaceId, input.workspaceId),\n eq(schema.deviceEnrollmentRequests.id, input.requestId),\n ))\n .for(\"update\")\n .limit(1);\n if (!pending) {\n return { approved: false, enrollment: null, sandbox: null };\n }\n // Already terminally approved → idempotent return of the existing rows (re-run\n // the consent fields in case allow_screen_control changed on re-approve).\n const expired = pending.expiresAt.getTime() <= now.getTime();\n if (pending.status === \"denied\" || pending.status === \"consumed\") {\n return { approved: false, enrollment: null, sandbox: null };\n }\n if (pending.status === \"pending\" && expired) {\n return { approved: false, enrollment: null, sandbox: null };\n }\n\n // The SHARED finalize core: upsert the enrollment (idempotent) + ensure a\n // selfhosted sandbox. RLS is already set on scopedDb's session and this call\n // runs INSIDE this FOR-UPDATE txn, so the re-read fence + the stamp below + the\n // enrollment/sandbox writes all commit atomically (semantics unchanged from the\n // pre-refactor inline block — acceptance #2 stays one machine). The headless\n // token exchange (finalizeEnrollmentByToken) calls the SAME core.\n const { enrollment, sandbox } = await finalizeEnrollmentInScope(scopedDb, {\n accountId: input.accountId,\n workspaceId: input.workspaceId,\n pubkey: pending.pubkey,\n hasDisplay: pending.canOfferDisplay,\n allowScreenControl: input.allowScreenControl,\n os: pending.os as EnrollmentOs,\n arch: pending.arch,\n sandboxName: input.sandboxName,\n now,\n });\n\n // Stamp the request approved + the LOUD CONSENT record (who/when/what).\n await scopedDb.update(schema.deviceEnrollmentRequests)\n .set({\n status: \"approved\",\n allowScreenControl: input.allowScreenControl,\n approvedBySubjectId: input.approvedBySubjectId,\n approvedBySubjectLabel: input.approvedBySubjectLabel ?? null,\n approvedAt: now,\n enrollmentId: enrollment.id,\n sandboxId: sandbox.id,\n updatedAt: now,\n })\n .where(eq(schema.deviceEnrollmentRequests.id, pending.id));\n\n return { approved: true, enrollment, sandbox };\n });\n}\n\n// Mark a pending request DENIED (an explicit user \"no\" at the approve page).\n// Idempotent: a non-pending row is a no-op (denied:false).\nexport async function denyDeviceEnrollmentRequest(db: Database, input: {\n accountId: string; workspaceId: string; requestId: string;\n}): Promise<{ denied: boolean }> {\n return await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId }, async (scopedDb) => {\n const rows = await scopedDb.update(schema.deviceEnrollmentRequests)\n .set({ status: \"denied\", updatedAt: new Date() })\n .where(and(\n eq(schema.deviceEnrollmentRequests.workspaceId, input.workspaceId),\n eq(schema.deviceEnrollmentRequests.id, input.requestId),\n eq(schema.deviceEnrollmentRequests.status, \"pending\"),\n ))\n .returning({ id: schema.deviceEnrollmentRequests.id });\n return { denied: rows.length > 0 };\n });\n}\n\n// Flip an APPROVED request to CONSUMED once the agent has polled its credentials\n// (single-use). Fenced on status='approved' so a double-poll consumes exactly once;\n// a second poll then re-reads the consumed row and still returns credentials (the\n// agent may legitimately retry the same poll) — the route decides. Returns whether\n// THIS call performed the consume transition.\nexport async function consumeDeviceEnrollmentRequest(db: Database, input: {\n accountId: string; workspaceId: string; requestId: string;\n}): Promise<{ consumed: boolean }> {\n return await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId }, async (scopedDb) => {\n const rows = await scopedDb.update(schema.deviceEnrollmentRequests)\n .set({ status: \"consumed\", updatedAt: new Date() })\n .where(and(\n eq(schema.deviceEnrollmentRequests.workspaceId, input.workspaceId),\n eq(schema.deviceEnrollmentRequests.id, input.requestId),\n eq(schema.deviceEnrollmentRequests.status, \"approved\"),\n ))\n .returning({ id: schema.deviceEnrollmentRequests.id });\n return { consumed: rows.length > 0 };\n });\n}\n\n// ---- sandboxes ------------------------------------------------------------\n\n// Create a first-class named sandbox (the pointer target a session swaps to). The\n// DB CHECK pins selfhosted<->enrollment_id: a selfhosted sandbox MUST carry an\n// enrollment; a modal sandbox MUST NOT. We surface that as a typed pre-check so\n// the caller gets a clear error rather than a raw constraint violation.\nexport async function createSandbox(db: Database, input: {\n accountId: string;\n workspaceId: string;\n kind: SandboxKind;\n name: string;\n enrollmentId?: string | null;\n}): Promise<SandboxRecord> {\n const enrollmentId = input.enrollmentId ?? null;\n if (input.kind === \"selfhosted\" && !enrollmentId) {\n throw new Error(\"A selfhosted sandbox requires an enrollmentId.\");\n }\n if (input.kind !== \"selfhosted\" && enrollmentId) {\n throw new Error(`A ${input.kind} sandbox must not carry an enrollmentId.`);\n }\n return await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId }, async (scopedDb) => {\n const [row] = await scopedDb.insert(schema.sandboxes).values({\n accountId: input.accountId,\n workspaceId: input.workspaceId,\n kind: input.kind,\n name: input.name,\n enrollmentId,\n }).returning();\n if (!row) {\n throw new Error(\"Failed to create sandbox\");\n }\n return mapSandbox(row);\n });\n}\n\nexport async function getSandbox(db: Database, workspaceId: string, sandboxId: string): Promise<SandboxRecord | null> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const [row] = await scopedDb.select().from(schema.sandboxes)\n .where(and(eq(schema.sandboxes.workspaceId, workspaceId), eq(schema.sandboxes.id, sandboxId)))\n .limit(1);\n return row ? mapSandbox(row) : null;\n });\n}\n\n// List a workspace's sandboxes, newest first (the sandboxes_list tool surface).\nexport async function listSandboxes(db: Database, workspaceId: string): Promise<SandboxRecord[]> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const rows = await scopedDb.select().from(schema.sandboxes)\n .where(eq(schema.sandboxes.workspaceId, workspaceId))\n .orderBy(desc(schema.sandboxes.createdAt));\n return rows.map(mapSandbox);\n });\n}\n\n// ---- the per-session active-sandbox pointer (epoch-fenced swap) -----------\n\nexport type ActiveSandboxPointer = {\n activeSandboxId: string | null;\n activeEpoch: number;\n // The session's working directory (the path/cwd base for a selfhosted backend),\n // surfaced alongside the pointer. NULL ⇒ the default workspace_root behavior.\n workingDir: string | null;\n};\n\n// Read the session's current pointer (the routing proxy re-reads this PER TOOL\n// CALL). NULL active_sandbox_id == \"use the session's own group sandbox\".\nexport async function readActiveSandbox(db: Database, workspaceId: string, sessionId: string): Promise<ActiveSandboxPointer | null> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const [row] = await scopedDb.select({\n activeSandboxId: schema.sessions.activeSandboxId,\n activeEpoch: schema.sessions.activeEpoch,\n workingDir: schema.sessions.workingDir,\n }).from(schema.sessions)\n .where(and(eq(schema.sessions.workspaceId, workspaceId), eq(schema.sessions.id, sessionId)))\n .limit(1);\n if (!row) {\n return null;\n }\n return { activeSandboxId: row.activeSandboxId ?? null, activeEpoch: Number(row.activeEpoch), workingDir: row.workingDir ?? null };\n });\n}\n\n// THE SWAP. Repoint a session at `targetSandboxId` (NULL == back to the group\n// sandbox) and BUMP active_epoch under a fence: the write is gated on the\n// session's current active_epoch == expectedEpoch, so a concurrent double-swap\n// (two callers both reading epoch N) lets exactly ONE win — the loser sees\n// swapped:false and re-reads. The bumped epoch fences any in-flight op cached\n// against the old pointer, which then retries against the new active sandbox.\n// integer epoch returns a JS number; Number()-coerced defensively (lease lesson).\nexport async function setActiveSandbox(db: Database, input: {\n accountId: string;\n workspaceId: string;\n sessionId: string;\n targetSandboxId: string | null;\n expectedEpoch: number;\n // The session's working directory to write alongside the pointer. OMITTED\n // (undefined) ⇒ the column is left UNCHANGED (a plain swap/attach never touches\n // it); a string sets it; null clears it back to the default. Per-session\n // working dir is seeded create-time through this CAS, not the row INSERT.\n workingDir?: string | null;\n}): Promise<{ swapped: boolean; pointer: ActiveSandboxPointer | null }> {\n return await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId }, async (scopedDb) => {\n const rows = await scopedDb.execute<{ active_sandbox_id: string | null; active_epoch: number | string; working_dir: string | null }>(sql`\n update sessions set\n active_sandbox_id = ${input.targetSandboxId},\n active_epoch = active_epoch + 1,\n working_dir = ${input.workingDir === undefined ? sql`working_dir` : input.workingDir},\n updated_at = now()\n where workspace_id = ${input.workspaceId} and id = ${input.sessionId}\n and active_epoch = ${input.expectedEpoch}\n returning active_sandbox_id, active_epoch, working_dir\n `);\n const row = rows[0];\n if (!row) {\n return { swapped: false, pointer: null };\n }\n return {\n swapped: true,\n pointer: { activeSandboxId: row.active_sandbox_id ?? null, activeEpoch: Number(row.active_epoch), workingDir: row.working_dir ?? null },\n };\n });\n}\n\n// ---- per-machine metrics (§10.7) ------------------------------------------\n\n// The sampled signal set the agent piggybacks on the heartbeat. Every field is\n// optional (a platform/sample may not provide it — no GPU, headless, etc.).\nexport type MachineMetricsSample = {\n cpuPercent?: number | null;\n load1?: number | null;\n load5?: number | null;\n load15?: number | null;\n memUsedBytes?: number | null;\n memTotalBytes?: number | null;\n diskUsedBytes?: number | null;\n diskTotalBytes?: number | null;\n gpuUtilPercent?: number | null;\n gpuMemUsedBytes?: number | null;\n gpuMemTotalBytes?: number | null;\n contention?: number | null;\n sampledAt: Date;\n};\n\nfunction metricColumns(sample: MachineMetricsSample) {\n return {\n cpuPercent: sample.cpuPercent ?? null,\n load1: sample.load1 ?? null,\n load5: sample.load5 ?? null,\n load15: sample.load15 ?? null,\n memUsedBytes: sample.memUsedBytes ?? null,\n memTotalBytes: sample.memTotalBytes ?? null,\n diskUsedBytes: sample.diskUsedBytes ?? null,\n diskTotalBytes: sample.diskTotalBytes ?? null,\n gpuUtilPercent: sample.gpuUtilPercent ?? null,\n gpuMemUsedBytes: sample.gpuMemUsedBytes ?? null,\n gpuMemTotalBytes: sample.gpuMemTotalBytes ?? null,\n contention: sample.contention ?? null,\n sampledAt: sample.sampledAt,\n };\n}\n\n// Last-sample UPSERT: one row per enrollment, overwritten every sample (PK on\n// enrollment_id is the conflict target). The Machines dashboard's \"now\" read.\nexport async function upsertMachineMetricsLatest(db: Database, input: {\n accountId: string; workspaceId: string; enrollmentId: string; sample: MachineMetricsSample;\n}): Promise<void> {\n await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId }, async (scopedDb) => {\n const cols = metricColumns(input.sample);\n await scopedDb.insert(schema.machineMetricsLatest).values({\n enrollmentId: input.enrollmentId,\n accountId: input.accountId,\n workspaceId: input.workspaceId,\n ...cols,\n }).onConflictDoUpdate({\n target: schema.machineMetricsLatest.enrollmentId,\n set: { ...cols, updatedAt: new Date() },\n });\n });\n}\n\n// Append a downsampled (~1/min) series row (the history the dashboard time-range\n// reads + the later retention sweep prune).\nexport async function insertMachineMetricsSeries(db: Database, input: {\n accountId: string; workspaceId: string; enrollmentId: string; sample: MachineMetricsSample;\n}): Promise<void> {\n await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId }, async (scopedDb) => {\n await scopedDb.insert(schema.machineMetricsSeries).values({\n enrollmentId: input.enrollmentId,\n accountId: input.accountId,\n workspaceId: input.workspaceId,\n ...metricColumns(input.sample),\n });\n });\n}\n\n// The target spacing between series rows: the agent heartbeats ~every 5s, but we\n// downsample the long-term history to ~1/min (dossier §10.7). A new series row is\n// appended only when >= this much time has elapsed since the last one.\nexport const MACHINE_METRICS_SERIES_INTERVAL_MS = 60_000;\n\n/**\n * Ingest ONE sampled metrics point for an enrollment (the M10 ingestion seam):\n * 1. UPSERT machine_metrics_latest (the \"now\" row, one per enrollment) — always.\n * 2. APPEND a machine_metrics_series row only when >= ~1/min has elapsed since\n * the last series row (downsample) — so the 5s heartbeat cadence does not\n * flood the history table.\n * Both happen under the same RLS context. Returns whether a series row was\n * appended (the downsample decision) so the caller / tests can assert the ~1/min\n * spacing. A null/absent `sampledAt` on the prior row treats it as \"no prior\" →\n * append.\n */\nexport async function ingestMachineMetricsSample(db: Database, input: {\n accountId: string; workspaceId: string; enrollmentId: string; sample: MachineMetricsSample;\n /** Override the downsample interval (tests). Defaults to ~1/min. */\n seriesIntervalMs?: number;\n}): Promise<{ latestUpserted: true; seriesAppended: boolean }> {\n return await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId }, async (scopedDb) => {\n const cols = metricColumns(input.sample);\n // 1. Latest upsert — always.\n await scopedDb.insert(schema.machineMetricsLatest).values({\n enrollmentId: input.enrollmentId,\n accountId: input.accountId,\n workspaceId: input.workspaceId,\n ...cols,\n }).onConflictDoUpdate({\n target: schema.machineMetricsLatest.enrollmentId,\n set: { ...cols, updatedAt: new Date() },\n });\n\n // 2. Series append — downsampled. Read the most recent series sampled_at and\n // only append when the new sample is >= the interval newer (or there is no\n // prior row). Done in-context so RLS scopes the read to this workspace.\n const intervalMs = input.seriesIntervalMs ?? MACHINE_METRICS_SERIES_INTERVAL_MS;\n const [prior] = await scopedDb.select({ sampledAt: schema.machineMetricsSeries.sampledAt })\n .from(schema.machineMetricsSeries)\n .where(eq(schema.machineMetricsSeries.enrollmentId, input.enrollmentId))\n .orderBy(desc(schema.machineMetricsSeries.sampledAt))\n .limit(1);\n const priorMs = prior?.sampledAt ? prior.sampledAt.getTime() : null;\n const sampleMs = input.sample.sampledAt.getTime();\n const seriesAppended = priorMs === null || sampleMs - priorMs >= intervalMs;\n if (seriesAppended) {\n await scopedDb.insert(schema.machineMetricsSeries).values({\n enrollmentId: input.enrollmentId,\n accountId: input.accountId,\n workspaceId: input.workspaceId,\n ...cols,\n });\n }\n return { latestUpserted: true, seriesAppended };\n });\n}\n\n// The mapped read shape of a stored metrics sample (latest or a series point).\n// numeric columns come back as strings from postgres-js; map them to numbers (or\n// null when never reported). The byte columns are bigint(mode:\"number\").\nexport type MachineMetricsRow = {\n enrollmentId: string;\n cpuPercent: number | null;\n load1: number | null;\n load5: number | null;\n load15: number | null;\n memUsedBytes: number | null;\n memTotalBytes: number | null;\n diskUsedBytes: number | null;\n diskTotalBytes: number | null;\n gpuUtilPercent: number | null;\n gpuMemUsedBytes: number | null;\n gpuMemTotalBytes: number | null;\n contention: number | null;\n sampledAt: string;\n};\n\nfunction numericOrNull(value: unknown): number | null {\n if (value === null || value === undefined) return null;\n const n = typeof value === \"number\" ? value : Number(value);\n return Number.isFinite(n) ? n : null;\n}\n\nfunction mapMetricsRow(row: {\n enrollmentId: string;\n cpuPercent: number | string | null;\n load1: number | string | null;\n load5: number | string | null;\n load15: number | string | null;\n memUsedBytes: number | null;\n memTotalBytes: number | null;\n diskUsedBytes: number | null;\n diskTotalBytes: number | null;\n gpuUtilPercent: number | string | null;\n gpuMemUsedBytes: number | null;\n gpuMemTotalBytes: number | null;\n contention: number | string | null;\n sampledAt: Date;\n}): MachineMetricsRow {\n return {\n enrollmentId: row.enrollmentId,\n cpuPercent: numericOrNull(row.cpuPercent),\n load1: numericOrNull(row.load1),\n load5: numericOrNull(row.load5),\n load15: numericOrNull(row.load15),\n memUsedBytes: row.memUsedBytes ?? null,\n memTotalBytes: row.memTotalBytes ?? null,\n diskUsedBytes: row.diskUsedBytes ?? null,\n diskTotalBytes: row.diskTotalBytes ?? null,\n gpuUtilPercent: numericOrNull(row.gpuUtilPercent),\n gpuMemUsedBytes: row.gpuMemUsedBytes ?? null,\n gpuMemTotalBytes: row.gpuMemTotalBytes ?? null,\n contention: numericOrNull(row.contention),\n sampledAt: row.sampledAt.toISOString(),\n };\n}\n\n// Read the latest sample for ONE enrollment (the dashboard \"now\" read), or null\n// when none has landed (never seen / offline before a first heartbeat).\nexport async function readMachineMetricsLatest(db: Database, workspaceId: string, enrollmentId: string): Promise<MachineMetricsRow | null> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const [row] = await scopedDb.select().from(schema.machineMetricsLatest)\n .where(and(\n eq(schema.machineMetricsLatest.workspaceId, workspaceId),\n eq(schema.machineMetricsLatest.enrollmentId, enrollmentId),\n ))\n .limit(1);\n return row ? mapMetricsRow(row) : null;\n });\n}\n\n// Read the latest sample for EVERY enrollment in a workspace, keyed by\n// enrollmentId — the Machines list joins this onto the fleet entries with ONE\n// query rather than N per-machine reads.\nexport async function readMachineMetricsLatestForWorkspace(db: Database, workspaceId: string): Promise<Map<string, MachineMetricsRow>> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const rows = await scopedDb.select().from(schema.machineMetricsLatest)\n .where(eq(schema.machineMetricsLatest.workspaceId, workspaceId));\n const byEnrollment = new Map<string, MachineMetricsRow>();\n for (const row of rows) {\n byEnrollment.set(row.enrollmentId, mapMetricsRow(row));\n }\n return byEnrollment;\n });\n}\n\n// Read the downsampled series for ONE enrollment over a time window (the\n// dashboard time-range read). `sinceMs` bounds the window (e.g. now - 1h);\n// ordered oldest-first for a left-to-right chart. `limit` caps the row count\n// (defensive against an unbounded window).\nexport async function readMachineMetricsSeries(db: Database, input: {\n workspaceId: string; enrollmentId: string; since: Date; limit?: number;\n}): Promise<MachineMetricsRow[]> {\n return await withWorkspaceRls(db, input.workspaceId, async (scopedDb) => {\n const rows = await scopedDb.select().from(schema.machineMetricsSeries)\n .where(and(\n eq(schema.machineMetricsSeries.workspaceId, input.workspaceId),\n eq(schema.machineMetricsSeries.enrollmentId, input.enrollmentId),\n gte(schema.machineMetricsSeries.sampledAt, input.since),\n ))\n .orderBy(asc(schema.machineMetricsSeries.sampledAt))\n .limit(input.limit ?? 5_000);\n return rows.map(mapMetricsRow);\n });\n}\n\n// ============================================================================\n// P3.2 — the un-redacted-pixel consent gate + viewer revocation.\n//\n// The desktop-stream path is gated behind an explicit acknowledgment that the\n// pixel plane is un-redacted (it can show cloud creds the agent cat's into a\n// terminal — strictly broader than the redacted Channel-A event log). For a\n// SHARED box (the group has >1 session) the principal must additionally consent\n// to the shared-exposure disclosure: watching A's desktop also shows B's agent\n// on the one :0 framebuffer (addendum E.1 / stress g). Consent is per-PRINCIPAL\n// and per-GROUP (one :0 per group), recorded in session_stream_acknowledgments\n// (0019). Reuses the acknowledgment machinery — no new permission beyond\n// stream:acknowledge.\n// ============================================================================\n\nexport interface StreamAcknowledgment {\n acknowledgedUnredacted: boolean;\n acknowledgedShared: boolean;\n}\n\n// Record (or upsert) a principal's acknowledgment of the group's un-redacted\n// pixel plane (and, when shared, the shared-exposure disclosure). Keyed on\n// (workspace, group, subject); a re-ack (e.g. a solo→shared upgrade adding the\n// shared consent) is ON CONFLICT DO UPDATE, never a duplicate row.\nexport async function recordStreamAcknowledgment(db: Database, input: {\n accountId: string;\n workspaceId: string;\n sandboxGroupId: string;\n subjectId: string;\n acknowledgeUnredacted: boolean;\n acknowledgeShared: boolean;\n}): Promise<StreamAcknowledgment> {\n return await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId },\n async (scopedDb) => {\n const rows = await scopedDb.execute<{ acknowledged_unredacted: boolean; acknowledged_shared: boolean }>(sql`\n insert into session_stream_acknowledgments\n (account_id, workspace_id, sandbox_group_id, subject_id,\n acknowledged_unredacted, acknowledged_shared, acknowledged_at, updated_at)\n values\n (${input.accountId}, ${input.workspaceId}, ${input.sandboxGroupId}, ${input.subjectId},\n ${input.acknowledgeUnredacted}, ${input.acknowledgeShared}, now(), now())\n on conflict (workspace_id, sandbox_group_id, subject_id) do update set\n -- Acknowledgment is monotonic: a later ack can ADD the shared consent\n -- but never silently withdraw a prior one (OR the bits in).\n acknowledged_unredacted = session_stream_acknowledgments.acknowledged_unredacted or excluded.acknowledged_unredacted,\n acknowledged_shared = session_stream_acknowledgments.acknowledged_shared or excluded.acknowledged_shared,\n acknowledged_at = now(),\n updated_at = now()\n returning acknowledged_unredacted, acknowledged_shared\n `);\n const row = rows[0]!;\n return { acknowledgedUnredacted: row.acknowledged_unredacted, acknowledgedShared: row.acknowledged_shared };\n });\n}\n\n// Read a principal's recorded acknowledgment for a group, or null if they have\n// never acknowledged the un-redacted pixel plane. The negotiation read + the\n// desktop-stream gate both consult this.\nexport async function getStreamAcknowledgment(db: Database, input: {\n workspaceId: string;\n sandboxGroupId: string;\n subjectId: string;\n}): Promise<StreamAcknowledgment | null> {\n return await withWorkspaceRls(db, input.workspaceId, async (scopedDb) => {\n const rows = await scopedDb.execute<{ acknowledged_unredacted: boolean; acknowledged_shared: boolean }>(sql`\n select acknowledged_unredacted, acknowledged_shared\n from session_stream_acknowledgments\n where workspace_id = ${input.workspaceId}\n and sandbox_group_id = ${input.sandboxGroupId}\n and subject_id = ${input.subjectId}\n limit 1\n `);\n if (!rows[0]) return null;\n return { acknowledgedUnredacted: rows[0].acknowledged_unredacted, acknowledgedShared: rows[0].acknowledged_shared };\n });\n}\n\n// Enumerate the session ids in a group (workspace-scoped). The shared-exposure\n// disclosure surfaces the OTHER sessions' ids ONLY — never their goal/metadata/\n// conversation. The query selects ONLY the id column (id is the disclosure\n// boundary; stress g). RLS-scoped: a foreign-workspace group returns no rows.\nexport async function listSessionIdsInGroup(db: Database, workspaceId: string, sandboxGroupId: string): Promise<string[]> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const rows = await rawRows<{ id: string }>(scopedDb, sql`\n select id from sessions\n where workspace_id = ${workspaceId} and sandbox_group_id = ${sandboxGroupId}\n order by created_at asc\n `);\n return rows.map((r) => r.id);\n });\n}\n\n// OD-6 v1 — revoke a viewer: DROP that viewer's holder from the GROUP lease so\n// refcount recomputes (the box drains iff nothing else holds it — a turn-held or\n// other-viewer-held box survives), AND block its reconnect by recording the\n// revoked subject so a re-attach with the same viewerId is refused. The\n// live-RFB force-disconnect of an already-open socket is a P4 follow-up; the\n// holder-drop (so the box can drain) is here.\n//\n// Returns the post-drop lease liveness/refcount (null if the lease was already\n// cold-and-reaped — a revoke is then an idempotent no-op). A revoked viewer who\n// independently holds a holder on a SIBLING session may still watch via that\n// session (correct — authorized there); this drops ONLY the named viewerId's\n// holder.\nexport async function revokeViewer(db: Database, input: {\n accountId: string;\n workspaceId: string;\n sandboxGroupId: string;\n viewerId: string;\n idleGraceMs: number;\n}): Promise<{ liveness: SandboxLeaseLiveness; refcount: number } | null> {\n // The drop is exactly releaseLeaseHolder's idempotent delete-my-row +\n // recompute (refcount recomputes; warm→draining is guarded refcount=0 AND\n // turn_holders=0, so a turn-held box never drains on a viewer revoke). The\n // reconnect-block is a P4 concern (the holder-drop is the v1 deliverable —\n // the box can now drain); a re-attach mints a fresh viewerId regardless.\n return await releaseLeaseHolder(db, {\n accountId: input.accountId,\n workspaceId: input.workspaceId,\n sandboxGroupId: input.sandboxGroupId,\n kind: \"viewer\",\n holderId: input.viewerId,\n idleGraceMs: input.idleGraceMs,\n });\n}\n\n// ============================================================================\n// Warm-time metering (P2.1) — the COST hole the lease design opens.\n//\n// A box held warm by a viewer with no agent turn running emits ZERO model usage\n// today; the provider bills by wall-clock and OpenGeni meters nothing. Warm-time\n// accrues on TWO stateless ticks: (a) the turn's existing activity heartbeat\n// (while a turn runs); (b) the reaper sweep (for viewer-only boxes between turns).\n//\n// The meter is GROUP-KEYED + epoch-keyed + tick-keyed:\n// idempotencyKey = usage:sandbox.warm_seconds:<group>:<epoch>:<tick>\n// so a SHARED box (N sessions on one group) is metered EXACTLY ONCE per tick\n// (N sessions != N x bill — a session-keyed meter would N x-over-bill), and a\n// re-dispatched/overlapping tick at the same (group,epoch,tick) can never\n// double-charge (recordUsageEvent is onConflictDoNothing on idempotencyKey).\n//\n// Cursor advance + usage insert are ATOMIC: both run inside ONE FOR UPDATE txn on\n// the lease row (the M3 cross-statement-atomicity fix). The insert uses ON\n// CONFLICT DO NOTHING on idempotency_key (matching recordUsageEvent), and the\n// cursor (last_meter_at/last_meter_tick) is advanced in the SAME txn — so the tick\n// index and the metered seconds can never desync, and a partial-failure rollback\n// leaves BOTH the cursor and the event untouched.\n// ============================================================================\n\nexport interface AccrueWarmSecondsResult {\n /** false when nothing was accrued (epoch fenced / not warm / no elapsed / the\n * first tick that only seeds the cursor). */\n accrued: boolean;\n /** Whole seconds metered this tick (0 when accrued:false). */\n seconds: number;\n /** The monotonic tick index this accrual was recorded under. */\n tick: number;\n /** usd_micros charged for this tick (0 when rate is 0). */\n costMicros: number;\n}\n\n/**\n * Accrue warm-seconds for the elapsed wall-clock since the lease's last meter\n * cursor, idempotent on (sandbox_group_id, lease_epoch, tick). EPOCH-FENCED +\n * liveness-guarded (warm only): a stale-epoch tick or a draining/cold lease is a\n * no-op, so a superseded writer that re-fires cannot mis-meter. The FIRST tick on\n * a never-metered lease (last_meter_at IS NULL) only SEEDS the cursor — it\n * accrues nothing (there is no prior cursor to diff against), matching the\n * \"delta since last tick\" contract. warmRateMicrosPerSecond > 0 also records a\n * sandbox.warm_cost event (cost = seconds x rate) AND debits the same micros from\n * the credit balance via applyCreditDebitUpToBalance (the model-cost precedent),\n * idempotent on the SAME (group, epoch, tick) key. The usage event is the\n * REQUESTED cost; the ledger is the ACTUAL debit (they legitimately differ when\n * balance is low — M2). Set debitCredits:false to meter without debiting.\n */\nexport async function accrueWarmSeconds(db: Database, input: {\n accountId: string;\n workspaceId: string;\n sandboxGroupId: string;\n /** The epoch the tick observed; the fence — a stale writer no-ops. */\n expectedEpoch: number;\n /** usd_micros per warm-second for this box's backend (0 = meter only, no cost). */\n warmRateMicrosPerSecond: number;\n /** Optional attribution: the founding/observing session (visibility only — the\n * group meter key makes the workspace charge correct regardless). */\n subjectId?: string | null;\n /** Debit credits for warm-cost (default true). The force-drain at 0 balance\n * depends on this decrementing the balance. */\n debitCredits?: boolean;\n}): Promise<AccrueWarmSecondsResult> {\n const none: AccrueWarmSecondsResult = { accrued: false, seconds: 0, tick: 0, costMicros: 0 };\n const result = await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId },\n async (scopedDb) => await scopedDb.transaction(async (txRaw) => {\n const tx = txRaw as unknown as Database;\n // Lock the group's lease row so the cursor advance + the usage insert are\n // one atomic step (no other tick can interleave between the diff and the\n // cursor write).\n const rows = await tx.execute<LeaseRow & { meter_elapsed_s: number | null }>(sql`\n select *,\n case when last_meter_at is null then null\n else floor(extract(epoch from (now() - last_meter_at)))::int end as meter_elapsed_s\n from sandbox_leases\n where workspace_id = ${input.workspaceId} and sandbox_group_id = ${input.sandboxGroupId}\n for update\n `);\n const row = rows[0];\n if (!row) return none;\n\n // Epoch fence + liveness guard: only a live-epoch warm box meters. A stale\n // (superseded) tick or a draining/cold/warming lease is a no-op.\n if (Number(row.lease_epoch) !== input.expectedEpoch || row.liveness !== \"warm\") {\n return none;\n }\n\n // First tick on a never-metered lease: SEED the cursor, accrue nothing.\n if (row.last_meter_at == null) {\n await tx.execute(sql`\n update sandbox_leases set last_meter_at = now(), updated_at = now()\n where id = ${row.id}\n `);\n return none;\n }\n\n const elapsedS = Number(row.meter_elapsed_s ?? 0);\n if (elapsedS <= 0) {\n // No whole second elapsed yet — leave the cursor untouched so the\n // remainder accrues on the next tick (no silent seconds loss).\n return none;\n }\n\n const tick = Number(row.last_meter_tick) + 1;\n const costMicros = Math.round(elapsedS * Math.max(0, input.warmRateMicrosPerSecond));\n\n // (1) The warm-seconds meter — GROUP+epoch+tick keyed, ON CONFLICT DO\n // NOTHING (the idempotency that makes a shared box one stream + a re-fire a\n // no-op). sourceResourceId is keyed on (group, epoch).\n await tx.execute(sql`\n insert into usage_events\n (account_id, workspace_id, subject_id, event_type, quantity, unit,\n source_resource_type, source_resource_id, idempotency_key, occurred_at)\n values\n (${input.accountId}, ${input.workspaceId}, ${input.subjectId ?? null},\n 'sandbox.warm_seconds', ${elapsedS}, 'seconds',\n 'sandbox_lease', ${`${input.sandboxGroupId}:${input.expectedEpoch}`},\n ${`usage:sandbox.warm_seconds:${input.sandboxGroupId}:${input.expectedEpoch}:${tick}`},\n now())\n on conflict (idempotency_key) do nothing\n `);\n\n // (2) The warm-cost meter (only when a rate is configured). Same keying.\n if (costMicros > 0) {\n await tx.execute(sql`\n insert into usage_events\n (account_id, workspace_id, subject_id, event_type, quantity, unit,\n source_resource_type, source_resource_id, idempotency_key, occurred_at)\n values\n (${input.accountId}, ${input.workspaceId}, ${input.subjectId ?? null},\n 'sandbox.warm_cost', ${costMicros}, 'usd_micros',\n 'sandbox_lease', ${`${input.sandboxGroupId}:${input.expectedEpoch}`},\n ${`usage:sandbox.warm_cost:${input.sandboxGroupId}:${input.expectedEpoch}:${tick}`},\n now())\n on conflict (idempotency_key) do nothing\n `);\n }\n\n // (3) Advance the cursor IN THE SAME TXN — the atomicity that makes the tick\n // index and the metered seconds inseparable.\n await tx.execute(sql`\n update sandbox_leases set\n last_meter_at = now(), last_meter_tick = ${tick}, updated_at = now()\n where id = ${row.id}\n `);\n\n return { accrued: true, seconds: elapsedS, tick, costMicros };\n }));\n\n // Debit credits for the warm-cost OUTSIDE the lease-row txn (applyCreditDebit\n // takes its own per-account advisory lock — never nest it under the lease row\n // lock). Idempotent on the SAME (group, epoch, tick) key so a re-fire of an\n // already-committed tick cannot double-debit. The ledger records the ACTUAL\n // debit (min(requested, balance)); the warm_cost usage event above is the\n // requested cost.\n if (result.accrued && result.costMicros > 0 && (input.debitCredits ?? true)) {\n await applyCreditDebitUpToBalance(db, {\n accountId: input.accountId,\n workspaceId: input.workspaceId,\n type: \"sandbox.warm_cost\",\n requestedAmountMicros: result.costMicros,\n sourceType: \"sandbox_lease\",\n sourceId: `${input.sandboxGroupId}:${input.expectedEpoch}`,\n idempotencyKey: `debit:sandbox.warm_cost:${input.sandboxGroupId}:${input.expectedEpoch}:${result.tick}`,\n }).catch(() => undefined);\n }\n\n return result;\n}\n\n// §2.2/2.3 — the per-workspace warm-cap + force-drain. Under the EXISTING usage\n// lock (withWorkspaceUsageLock — NOT a bare count, so two concurrent ticks in\n// different sessions of one workspace can't both read \"under cap\" and race past\n// it). A workspace at 0 balance OR over its warm-second cap force-drains its\n// VIEWER-ONLY boxes: CAS warm->draining guarded `AND turn_holders = 0` so a box\n// with a running (paying) turn is NEVER killed. The reaper then issues the\n// provider stop() at refcount 0 (this fn is DB-only — no provider call).\n//\n// Group-wide force-drain on workspace balance exhaustion is deliberate (one\n// balance drains a multi-session box): the workspace, not the session, is the\n// billing unit — correctness (charged once) is automatic from the group meter key.\nexport interface ForceDrainResult {\n /** Whether the workspace was over a limit (0 balance or over the warm cap). */\n overLimit: boolean;\n /** The reason, for observability. */\n reason: \"balance\" | \"warm_cap\" | null;\n /** The (workspaceId, sandboxGroupId) viewer-only boxes CASed warm->draining. */\n drained: { workspaceId: string; sandboxGroupId: string }[];\n}\n\n// Start of the current UTC month (the default warm-cap window). Local helper so\n// packages/db has no dependency on a worker/api date util; callers may override\n// via capWindowStart to keep the fn time-source-agnostic for tests.\nfunction startOfUtcMonthDefault(date = new Date()): Date {\n return new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), 1, 0, 0, 0, 0));\n}\n\nexport async function forceDrainOverLimitViewerOnlyBoxes(db: Database, input: {\n workspaceId: string;\n /** account balance gate: when <= 0 (and a billing/managed mode is on) drain. */\n balanceMicros: number;\n enforceBalance: boolean;\n /** warm-second cap (cumulative this UTC month). 0 = unbounded (no cap gate). */\n maxWarmSecondsPerWorkspace: number;\n /** start of the cap window (caller passes startOfUtcMonth() so the fn stays\n * time-source-agnostic for tests). */\n capWindowStart?: Date;\n /** drain-grace horizon stamped on the newly-draining rows (matches the reaper). */\n idleGraceMs: number;\n}): Promise<ForceDrainResult> {\n return await withWorkspaceUsageLock(db, input.workspaceId, async (scopedDb) => {\n // Determine over-limit under the lock (so the cap read + the drain are one\n // serialized critical section per workspace).\n let reason: \"balance\" | \"warm_cap\" | null = null;\n if (input.enforceBalance && input.balanceMicros <= 0) {\n reason = \"balance\";\n } else if (input.maxWarmSecondsPerWorkspace > 0) {\n const since = input.capWindowStart ?? startOfUtcMonthDefault();\n const [{ total } = { total: 0 }] = await scopedDb.select({\n total: sql<number>`coalesce(sum(${schema.usageEvents.quantity}), 0)`,\n }).from(schema.usageEvents).where(and(\n eq(schema.usageEvents.workspaceId, input.workspaceId),\n eq(schema.usageEvents.eventType, \"sandbox.warm_seconds\"),\n gt(schema.usageEvents.occurredAt, since),\n ));\n if (Number(total) >= input.maxWarmSecondsPerWorkspace) {\n reason = \"warm_cap\";\n }\n }\n\n if (!reason) {\n return { overLimit: false, reason: null, drained: [] };\n }\n\n // Force-drain VIEWER-ONLY warm boxes: CAS warm->draining guarded\n // turn_holders = 0 (a paying turn is NEVER killed). Stamp the grace deadline\n // so the reaper terminates at refcount 0 past the grace, exactly as a normal\n // refcount->0 drain would.\n // Drop the viewer holders of every warm VIEWER-ONLY lease (turn_holders=0 — a\n // paying turn is never killed) so refcount → 0 (otherwise the viewer holder\n // pins refcount > 0 and the reaper never terminates at refcount=0, and the\n // holder heartbeat would re-arm the lease). Scoped to the warm viewer-only\n // leases via a subselect so a turn-held box's holders are untouched.\n await scopedDb.execute(sql`\n delete from sandbox_lease_holders h\n where h.kind = 'viewer'\n and h.lease_id in (\n select id from sandbox_leases\n where workspace_id = ${input.workspaceId}\n and liveness = 'warm' and turn_holders = 0\n )\n `);\n // CAS the now-holderless leases warm→draining at refcount 0 with the grace\n // deadline stamped — so the SAME reaper sweep's refcount=0 drain predicate\n // then terminates the box.\n const drained = await rawRows<{ sandbox_group_id: string }>(scopedDb, sql`\n update sandbox_leases set\n liveness = 'draining',\n refcount = 0, turn_holders = 0, viewer_holders = 0,\n expires_at = now() + (${String(input.idleGraceMs)} || ' milliseconds')::interval,\n updated_at = now()\n where workspace_id = ${input.workspaceId}\n and liveness = 'warm' and turn_holders = 0\n returning sandbox_group_id\n `);\n\n return {\n overLimit: true,\n reason,\n drained: drained.map((r) => ({ workspaceId: input.workspaceId, sandboxGroupId: r.sandbox_group_id })),\n };\n });\n}\n\nexport async function saveRunState(db: Database, input: {\n accountId: string;\n workspaceId: string;\n sessionId: string;\n turnId?: string | null;\n serializedRunState: string;\n pendingApprovals: unknown[];\n // The codex account freezing this state (the turn's resolved credential id),\n // or null on a non-codex turn. Stamped so a resume on a DIFFERENT codex\n // account can strip the blob's account-bound reasoning. Defaults null so\n // every legacy caller (and the non-codex path) is byte-identical.\n frozenCodexCredentialId?: string | null;\n}): Promise<void> {\n await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId }, async (scopedDb) => {\n const [{ maxVersion } = { maxVersion: 0 }] = await scopedDb.select({\n maxVersion: sql<number>`coalesce(max(${schema.agentRunStates.stateVersion}), 0)`,\n }).from(schema.agentRunStates).where(and(eq(schema.agentRunStates.workspaceId, input.workspaceId), eq(schema.agentRunStates.sessionId, input.sessionId)));\n await scopedDb.insert(schema.agentRunStates).values({\n accountId: input.accountId,\n workspaceId: input.workspaceId,\n sessionId: input.sessionId,\n turnId: input.turnId ?? null,\n stateVersion: Number(maxVersion) + 1,\n serializedRunState: input.serializedRunState,\n pendingApprovals: input.pendingApprovals,\n frozenCodexCredentialId: input.frozenCodexCredentialId ?? null,\n });\n });\n}\n\nexport type CreateSessionGoalInput = {\n accountId: string;\n workspaceId: string;\n sessionId: string;\n text: string;\n successCriteria?: string | null;\n maxAutoContinuations?: number | null;\n createdBy: SessionGoalCreatedBy;\n};\n\nexport async function createSessionGoal(db: Database, input: CreateSessionGoalInput): Promise<SessionGoal> {\n return await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId }, async (scopedDb) => {\n const [row] = await scopedDb.insert(schema.sessionGoals).values({\n accountId: input.accountId,\n workspaceId: input.workspaceId,\n sessionId: input.sessionId,\n text: input.text,\n successCriteria: input.successCriteria ?? null,\n maxAutoContinuations: input.maxAutoContinuations ?? null,\n createdBy: input.createdBy,\n }).returning();\n if (!row) {\n throw new Error(\"Failed to create session goal\");\n }\n return mapSessionGoal(row);\n });\n}\n\nexport async function getSessionGoal(db: Database, workspaceId: string, sessionId: string): Promise<SessionGoal | null> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const [row] = await scopedDb.select().from(schema.sessionGoals)\n .where(and(eq(schema.sessionGoals.workspaceId, workspaceId), eq(schema.sessionGoals.sessionId, sessionId)))\n .limit(1);\n return row ? mapSessionGoal(row) : null;\n });\n}\n\n/**\n * goal_set semantics: insert, or replace the existing goal in place. A replace\n * re-activates the goal (even when paused or completed), bumps the version,\n * and resets the continuation counters — re-stating the objective re-arms the\n * auto-continuation budget.\n */\nexport async function upsertSessionGoal(db: Database, input: CreateSessionGoalInput): Promise<{ goal: SessionGoal; replaced: boolean }> {\n return await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId }, async (scopedDb) => {\n const [existing] = await scopedDb.select().from(schema.sessionGoals)\n .where(and(eq(schema.sessionGoals.workspaceId, input.workspaceId), eq(schema.sessionGoals.sessionId, input.sessionId)))\n .for(\"update\")\n .limit(1);\n if (!existing) {\n const [row] = await scopedDb.insert(schema.sessionGoals).values({\n accountId: input.accountId,\n workspaceId: input.workspaceId,\n sessionId: input.sessionId,\n text: input.text,\n successCriteria: input.successCriteria ?? null,\n maxAutoContinuations: input.maxAutoContinuations ?? null,\n createdBy: input.createdBy,\n }).returning();\n if (!row) {\n throw new Error(\"Failed to upsert session goal\");\n }\n return { goal: mapSessionGoal(row), replaced: false };\n }\n const [row] = await scopedDb.update(schema.sessionGoals).set({\n status: \"active\",\n text: input.text,\n successCriteria: input.successCriteria ?? null,\n maxAutoContinuations: input.maxAutoContinuations ?? null,\n evidence: null,\n rationale: null,\n pausedReason: null,\n createdBy: input.createdBy,\n version: existing.version + 1,\n autoContinuations: 0,\n noProgressStreak: 0,\n lastContinuationTurnId: null,\n versionAtLastContinuation: null,\n updatedAt: new Date(),\n }).where(eq(schema.sessionGoals.id, existing.id)).returning();\n if (!row) {\n throw new Error(\"Failed to upsert session goal\");\n }\n return { goal: mapSessionGoal(row), replaced: true };\n });\n}\n\n/**\n * goal_update semantics: revise text/criteria without changing status. The\n * version bump counts as progress for the no-progress detector.\n */\nexport async function updateSessionGoal(db: Database, workspaceId: string, sessionId: string, input: {\n text?: string;\n successCriteria?: string | null;\n}): Promise<SessionGoal> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const [row] = await scopedDb.update(schema.sessionGoals).set({\n ...(input.text !== undefined ? { text: input.text } : {}),\n ...(input.successCriteria !== undefined ? { successCriteria: input.successCriteria } : {}),\n version: sql`${schema.sessionGoals.version} + 1`,\n noProgressStreak: 0,\n updatedAt: new Date(),\n }).where(and(eq(schema.sessionGoals.workspaceId, workspaceId), eq(schema.sessionGoals.sessionId, sessionId))).returning();\n if (!row) {\n throw new Error(`Session goal not found: ${sessionId}`);\n }\n return mapSessionGoal(row);\n });\n}\n\n/**\n * Sets a session's display title. The clobber guard lives entirely in this\n * single atomic UPDATE: a user-set title is permanent, so agent/auto writes\n * carry an `AND title_source IS DISTINCT FROM 'user'` guard (NULL-safe in\n * Postgres) while user writes are unconditional. Never read-modify-write.\n * Returns `{ updated, title }`: `updated` is false when an agent write was\n * skipped because a user title already pinned the session, true otherwise;\n * `title` is the resulting title (null when skipped).\n */\nexport async function updateSessionTitle(db: Database, input: {\n workspaceId: string;\n sessionId: string;\n title: string;\n source: \"user\" | \"agent\";\n}): Promise<{ updated: boolean; title: string | null }> {\n return await withWorkspaceRls(db, input.workspaceId, async (scopedDb) => {\n const [row] = await scopedDb.update(schema.sessions).set({\n title: input.title,\n titleSource: input.source,\n updatedAt: new Date(),\n }).where(and(\n eq(schema.sessions.workspaceId, input.workspaceId),\n eq(schema.sessions.id, input.sessionId),\n ...(input.source === \"agent\" ? [sql`${schema.sessions.titleSource} is distinct from 'user'`] : []),\n )).returning({ title: schema.sessions.title });\n return { updated: Boolean(row), title: row?.title ?? null };\n });\n}\n\n/**\n * Status transition helper. Idempotent: requesting the current status returns\n * `changed: false` so callers can skip emitting a duplicate event. `completed`\n * is terminal for transitions; only `upsertSessionGoal` can replace a\n * completed goal. Resuming to `active` clears the pause fields and resets the\n * continuation counters.\n */\nexport async function setSessionGoalStatus(db: Database, workspaceId: string, sessionId: string, input: {\n status: SessionGoalStatus;\n evidence?: string;\n rationale?: string;\n pausedReason?: string;\n}): Promise<{ goal: SessionGoal; changed: boolean }> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const [existing] = await scopedDb.select().from(schema.sessionGoals)\n .where(and(eq(schema.sessionGoals.workspaceId, workspaceId), eq(schema.sessionGoals.sessionId, sessionId)))\n .for(\"update\")\n .limit(1);\n if (!existing) {\n throw new Error(`Session goal not found: ${sessionId}`);\n }\n if (existing.status === input.status) {\n return { goal: mapSessionGoal(existing), changed: false };\n }\n if (existing.status === \"completed\") {\n throw new Error(\"session goal is completed; set a new goal to continue\");\n }\n const [row] = await scopedDb.update(schema.sessionGoals).set({\n status: input.status,\n version: existing.version + 1,\n updatedAt: new Date(),\n ...(input.status === \"completed\" ? {\n evidence: input.evidence ?? null,\n pausedReason: null,\n } : {}),\n ...(input.status === \"paused\" ? {\n rationale: input.rationale ?? null,\n pausedReason: input.pausedReason ?? null,\n } : {}),\n ...(input.status === \"active\" ? {\n rationale: null,\n pausedReason: null,\n autoContinuations: 0,\n noProgressStreak: 0,\n // A re-armed goal starts a fresh continuation epoch; stale pointers to\n // a pre-pause continuation turn must not feed the progress detector.\n lastContinuationTurnId: null,\n versionAtLastContinuation: null,\n } : {}),\n }).where(eq(schema.sessionGoals.id, existing.id)).returning();\n if (!row) {\n throw new Error(`Session goal not found: ${sessionId}`);\n }\n return { goal: mapSessionGoal(row), changed: true };\n });\n}\n\nexport async function setSessionGoalLastContinuationTurn(db: Database, workspaceId: string, sessionId: string, turnId: string): Promise<void> {\n await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n await scopedDb.update(schema.sessionGoals).set({\n lastContinuationTurnId: turnId,\n updatedAt: new Date(),\n }).where(and(eq(schema.sessionGoals.workspaceId, workspaceId), eq(schema.sessionGoals.sessionId, sessionId)));\n });\n}\n\nexport type GoalContinuationDecision =\n | { decision: \"none\" }\n | { decision: \"queue\" }\n | { decision: \"paused\"; reason: \"no_progress\" | \"max_auto_continuations\" | \"limits\"; goal: SessionGoal }\n | { decision: \"continue\"; goal: SessionGoal; autoContinuation: number; cap: number | null };\n\n/**\n * Core continuation decision, taken in one transaction with the goal row\n * locked. Queued work always wins; any non-terminal turn (queued, running, or\n * requires_action awaiting a human approval) blocks auto-continuation. The\n * no-progress and max-continuation guards mutate counters here only, so a\n * replaying workflow re-reads recorded activity results and never recomputes\n * them.\n */\nexport async function evaluateGoalContinuation(db: Database, input: {\n workspaceId: string;\n sessionId: string;\n // Optional: when absent (the default posture) goals are uncapped and length\n // is governed by the no-progress and budget guards only.\n defaultMaxAutoContinuations?: number | null;\n noProgressLimit: number;\n // Caller-computed billing/limits block reason. Applied inside the locked\n // decision (before the counter bump) so a budget pause never consumes\n // continuation budget.\n budgetBlocked?: string | null;\n}): Promise<GoalContinuationDecision> {\n return await withWorkspaceRls(db, input.workspaceId, async (scopedDb) => await scopedDb.transaction(async (tx) => {\n const [row] = await tx.select().from(schema.sessionGoals)\n .where(and(eq(schema.sessionGoals.workspaceId, input.workspaceId), eq(schema.sessionGoals.sessionId, input.sessionId)))\n .for(\"update\")\n .limit(1);\n if (!row || row.status !== \"active\") {\n return { decision: \"none\" } as const;\n }\n const [pendingTurn] = await tx.select({ id: schema.sessionTurns.id, status: schema.sessionTurns.status })\n .from(schema.sessionTurns)\n .where(and(\n eq(schema.sessionTurns.workspaceId, input.workspaceId),\n eq(schema.sessionTurns.sessionId, input.sessionId),\n inArray(schema.sessionTurns.status, [\"queued\", \"running\", \"requires_action\"]),\n ))\n .limit(1);\n if (pendingTurn) {\n // \"queue\" tells the workflow to claim immediately; running/requires_action\n // turns (e.g. a pending approval on a restarted workflow) must not be\n // bypassed by a continuation, so they decline instead.\n return pendingTurn.status === \"queued\" ? { decision: \"queue\" } as const : { decision: \"none\" } as const;\n }\n let autoContinuations = row.autoContinuations;\n let noProgressStreak = row.noProgressStreak;\n // P3: a 429-failover continuation (the last continuation turn carried the `rotated`\n // marker) is a multi-account rotate, not goal progress OR a goal stall — it must not\n // burn the auto-continuation budget while walking accounts. Freezes the increment below,\n // mirroring the budget-pause precedent that a limits pause never consumes budget.\n let rotatedFailover = false;\n if (row.lastContinuationTurnId) {\n const [lastFinished] = await tx.select({ id: schema.sessionTurns.id })\n .from(schema.sessionTurns)\n .where(and(\n eq(schema.sessionTurns.workspaceId, input.workspaceId),\n eq(schema.sessionTurns.sessionId, input.sessionId),\n sql`${schema.sessionTurns.finishedAt} is not null`,\n ))\n .orderBy(desc(schema.sessionTurns.position), desc(schema.sessionTurns.createdAt))\n .limit(1);\n if (lastFinished && lastFinished.id !== row.lastContinuationTurnId) {\n // A user/scheduled turn ran since the last continuation: human\n // re-engagement re-arms the auto-continuation budget.\n autoContinuations = 0;\n noProgressStreak = 0;\n } else if (lastFinished) {\n const [{ rotatedFailures } = { rotatedFailures: 0 }] = await tx.select({\n rotatedFailures: sql<number>`count(*)::int`,\n }).from(schema.sessionEvents)\n .where(and(\n eq(schema.sessionEvents.workspaceId, input.workspaceId),\n eq(schema.sessionEvents.turnId, row.lastContinuationTurnId),\n eq(schema.sessionEvents.type, \"turn.failed\"),\n sql`${schema.sessionEvents.payload} ->> 'rotated' = 'true'`,\n ));\n rotatedFailover = Number(rotatedFailures) > 0;\n const [{ toolCalls } = { toolCalls: 0 }] = await tx.select({\n toolCalls: sql<number>`count(*)::int`,\n }).from(schema.sessionEvents)\n .where(and(\n eq(schema.sessionEvents.workspaceId, input.workspaceId),\n eq(schema.sessionEvents.turnId, row.lastContinuationTurnId),\n eq(schema.sessionEvents.type, \"agent.toolCall.created\"),\n ));\n const goalRevised = row.versionAtLastContinuation !== null && row.version > row.versionAtLastContinuation;\n if (Number(toolCalls) > 0 || goalRevised) {\n noProgressStreak = 0;\n } else {\n // A turn that died on retryable provider backpressure says nothing\n // about whether the goal can progress; freezing the streak keeps a\n // sustained rate-limit window from masquerading as a stuck goal.\n // The auto-continuation cap remains the backstop for a real outage.\n const [{ backpressureFailures } = { backpressureFailures: 0 }] = await tx.select({\n backpressureFailures: sql<number>`count(*)::int`,\n }).from(schema.sessionEvents)\n .where(and(\n eq(schema.sessionEvents.workspaceId, input.workspaceId),\n eq(schema.sessionEvents.turnId, row.lastContinuationTurnId),\n eq(schema.sessionEvents.type, \"turn.failed\"),\n sql`${schema.sessionEvents.payload} ->> 'recovery' = 'goal_continuation'`,\n ));\n if (Number(backpressureFailures) === 0) {\n noProgressStreak = noProgressStreak + 1;\n }\n }\n }\n }\n if (noProgressStreak >= input.noProgressLimit) {\n const [paused] = await tx.update(schema.sessionGoals).set({\n status: \"paused\",\n pausedReason: \"no_progress\",\n autoContinuations,\n noProgressStreak,\n version: row.version + 1,\n updatedAt: new Date(),\n }).where(eq(schema.sessionGoals.id, row.id)).returning();\n return { decision: \"paused\", reason: \"no_progress\", goal: mapSessionGoal(paused!) } as const;\n }\n // No configured default means uncapped: goal length is bounded by the\n // no-progress and budget guards above, never by count. When a default is\n // configured it is a hard ceiling; per-goal overrides can only lower it.\n const capCandidates = [row.maxAutoContinuations, input.defaultMaxAutoContinuations]\n .filter((value): value is number => typeof value === \"number\");\n const cap = capCandidates.length > 0 ? Math.min(...capCandidates) : null;\n if (cap !== null && autoContinuations >= cap) {\n const [paused] = await tx.update(schema.sessionGoals).set({\n status: \"paused\",\n pausedReason: \"max_auto_continuations\",\n autoContinuations,\n noProgressStreak,\n version: row.version + 1,\n updatedAt: new Date(),\n }).where(eq(schema.sessionGoals.id, row.id)).returning();\n return { decision: \"paused\", reason: \"max_auto_continuations\", goal: mapSessionGoal(paused!) } as const;\n }\n if (input.budgetBlocked) {\n // Budget exhaustion pauses the goal visibly without bumping the\n // continuation counter — no turn is synthesized for this pass.\n const [paused] = await tx.update(schema.sessionGoals).set({\n status: \"paused\",\n pausedReason: \"limits\",\n rationale: input.budgetBlocked,\n autoContinuations,\n noProgressStreak,\n version: row.version + 1,\n updatedAt: new Date(),\n }).where(eq(schema.sessionGoals.id, row.id)).returning();\n return { decision: \"paused\", reason: \"limits\", goal: mapSessionGoal(paused!) } as const;\n }\n // Freeze the counter on a rotation failover (invariant: a rotation walk never\n // consumes continuation budget); a normal continuation increments as before.\n const nextAutoContinuations = autoContinuations + (rotatedFailover ? 0 : 1);\n const [updated] = await tx.update(schema.sessionGoals).set({\n autoContinuations: nextAutoContinuations,\n noProgressStreak,\n versionAtLastContinuation: row.version,\n updatedAt: new Date(),\n }).where(eq(schema.sessionGoals.id, row.id)).returning();\n return { decision: \"continue\", goal: mapSessionGoal(updated!), autoContinuation: nextAutoContinuations, cap } as const;\n }));\n}\n\nfunction mapSessionGoal(row: typeof schema.sessionGoals.$inferSelect): SessionGoal {\n return {\n id: row.id,\n accountId: row.accountId,\n workspaceId: row.workspaceId,\n sessionId: row.sessionId,\n status: row.status as SessionGoal[\"status\"],\n text: row.text,\n successCriteria: row.successCriteria,\n evidence: row.evidence,\n rationale: row.rationale,\n pausedReason: row.pausedReason,\n createdBy: row.createdBy as SessionGoal[\"createdBy\"],\n version: row.version,\n autoContinuations: row.autoContinuations,\n noProgressStreak: row.noProgressStreak,\n maxAutoContinuations: row.maxAutoContinuations,\n metadata: row.metadata,\n createdAt: row.createdAt.toISOString(),\n updatedAt: row.updatedAt.toISOString(),\n };\n}\n\nexport async function createTurn(db: Database, input: {\n workspaceId: string;\n sessionId: string;\n triggerEventId: string;\n temporalWorkflowId: string;\n}): Promise<string> {\n return await withWorkspaceRls(db, input.workspaceId, async (scopedDb) => {\n const session = await requireSession(scopedDb, input.workspaceId, input.sessionId);\n const trigger = await getSessionEvent(scopedDb, input.workspaceId, input.triggerEventId);\n const position = await nextTurnPosition(scopedDb, input.workspaceId, input.sessionId);\n const [row] = await scopedDb.insert(schema.sessionTurns).values({\n accountId: session.accountId,\n workspaceId: session.workspaceId,\n sessionId: input.sessionId,\n triggerEventId: input.triggerEventId,\n temporalWorkflowId: input.temporalWorkflowId,\n status: \"running\",\n source: \"user\",\n position,\n prompt: promptFromTrigger(trigger?.payload) ?? session.initialMessage,\n resources: resourcesFromTrigger(trigger?.payload) ?? session.resources,\n tools: toolsFromTrigger(trigger?.payload) ?? session.tools,\n model: session.model,\n reasoningEffort: reasoningEffortFromSession(session),\n sandboxBackend: session.sandboxBackend,\n metadata: {},\n startedAt: new Date(),\n }).returning({ id: schema.sessionTurns.id });\n if (!row) {\n throw new Error(\"Failed to create turn\");\n }\n await scopedDb.update(schema.sessions).set({\n activeTurnId: row.id,\n status: \"running\",\n updatedAt: new Date(),\n }).where(and(eq(schema.sessions.workspaceId, input.workspaceId), eq(schema.sessions.id, input.sessionId)));\n return row.id;\n });\n}\n\nexport async function enqueueSessionTurn(db: Database, input: EnqueueSessionTurnInput): Promise<SessionTurn> {\n return await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId }, async (scopedDb) => await scopedDb.transaction(async (tx) => {\n const position = await nextTurnPosition(tx as unknown as Database, input.workspaceId, input.sessionId);\n const [row] = await tx.insert(schema.sessionTurns).values({\n accountId: input.accountId,\n workspaceId: input.workspaceId,\n sessionId: input.sessionId,\n triggerEventId: input.triggerEventId,\n temporalWorkflowId: input.temporalWorkflowId,\n status: \"queued\",\n source: input.source,\n position,\n prompt: input.prompt,\n resources: input.resources,\n tools: input.tools,\n model: input.model,\n reasoningEffort: input.reasoningEffort,\n sandboxBackend: input.sandboxBackend,\n metadata: input.metadata,\n }).returning();\n if (!row) {\n throw new Error(\"Failed to enqueue session turn\");\n }\n return mapSessionTurn(row);\n }));\n}\n\nexport async function claimNextQueuedTurn(db: Database, workspaceId: string, sessionId: string, workflowId: string): Promise<SessionTurn | null> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => await scopedDb.transaction(async (tx) => {\n const rows = await tx.execute(sql<{ id: string }>`\n select id from session_turns\n where workspace_id = ${workspaceId} and session_id = ${sessionId} and status = 'queued'\n order by position asc, created_at asc, id asc\n for update skip locked\n limit 1\n `);\n const id = rows[0]?.id as string | undefined;\n if (!id) {\n return null;\n }\n const [row] = await tx.update(schema.sessionTurns).set({\n status: \"running\",\n temporalWorkflowId: workflowId,\n startedAt: new Date(),\n updatedAt: new Date(),\n }).where(and(eq(schema.sessionTurns.workspaceId, workspaceId), eq(schema.sessionTurns.id, id))).returning();\n if (!row) {\n throw new Error(`Session turn not found: ${id}`);\n }\n await tx.update(schema.sessions).set({\n status: \"running\",\n activeTurnId: row.id,\n updatedAt: new Date(),\n }).where(and(eq(schema.sessions.workspaceId, workspaceId), eq(schema.sessions.id, sessionId)));\n return mapSessionTurn(row);\n }));\n}\n\nexport async function setSessionStatus(db: Database, workspaceId: string, sessionId: string, status: SessionStatus, activeTurnId?: string | null): Promise<void> {\n await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n await scopedDb.update(schema.sessions).set({\n status,\n activeTurnId: activeTurnId === undefined ? undefined : activeTurnId,\n updatedAt: new Date(),\n }).where(and(eq(schema.sessions.workspaceId, workspaceId), eq(schema.sessions.id, sessionId)));\n });\n}\n\nexport type WakeParentForChildCompletionInput = {\n workspaceId: string;\n parentSessionId: string;\n // Stable per terminal episode, unique across episodes: the idempotency key\n // for exactly-once delivery (a unique session_events.client_event_id).\n clientEventId: string;\n // System-authored wake text rendered to the manager as its next turn input.\n text: string;\n // Structured payload describing the completed child (id, status, goal).\n childCompletion: Record<string, unknown>;\n reasoningEffortFallback: ReasoningEffort;\n};\n\nexport type WakeParentForChildCompletionResult =\n | { delivered: false; reason: \"already_delivered\" | \"parent_cancelled\" }\n | { delivered: true; turn: SessionTurn; triggerEvent: SessionEvent; events: SessionEvent[]; temporalWorkflowId: string };\n\n/**\n * Deliver a one-shot completion wake from a spawned worker into its parent\n * (manager) session: append a system-authored `user.message`, transition the\n * parent idle/failed -> queued (a queued/running parent already has a turn in\n * flight and keeps it), and enqueue the resulting turn. The whole thing runs\n * under the parent's row lock in one transaction, and is idempotent on\n * `clientEventId`: a duplicate call for the same terminal episode (activity\n * retry, the workflow's idle re-check) is a no-op that enqueues no second\n * turn. The caller publishes the returned events and signals the parent's\n * Temporal workflow (signalWithStart) only when `delivered` is true.\n *\n * Mirrors `acceptSessionUserMessage`/`postUserMessageTurn` in the API domain:\n * cancelled is the one parent state that refuses the wake (an explicit stop);\n * failed stays revivable, matching the revivable-failed-sessions contract.\n */\nexport async function wakeParentSessionForChildCompletion(\n db: Database,\n input: WakeParentForChildCompletionInput,\n): Promise<WakeParentForChildCompletionResult> {\n return await withWorkspaceRls(db, input.workspaceId, async (scopedDb) => await scopedDb.transaction(async (tx) => {\n const [parent] = await tx.select().from(schema.sessions)\n .where(and(eq(schema.sessions.workspaceId, input.workspaceId), eq(schema.sessions.id, input.parentSessionId)))\n .for(\"update\")\n .limit(1);\n if (!parent) {\n throw new Error(`Parent session not found: ${input.parentSessionId}`);\n }\n if (parent.status === \"cancelled\") {\n // Cancelled is the one terminal state that refuses new input; a manager a\n // human explicitly stopped is not revived by a worker finishing.\n return { delivered: false, reason: \"parent_cancelled\" as const };\n }\n // Idempotency gate: a wake for this terminal episode was already delivered.\n const [existing] = await tx.select({ id: schema.sessionEvents.id }).from(schema.sessionEvents)\n .where(and(\n eq(schema.sessionEvents.workspaceId, input.workspaceId),\n eq(schema.sessionEvents.sessionId, input.parentSessionId),\n eq(schema.sessionEvents.clientEventId, input.clientEventId),\n ))\n .limit(1);\n if (existing) {\n return { delivered: false, reason: \"already_delivered\" as const };\n }\n\n const shouldQueue = parent.status === \"idle\" || parent.status === \"failed\";\n const workflowId = parent.temporalWorkflowId ?? `session-${parent.id}`;\n let sequence = parent.lastSequence;\n const now = new Date();\n const eventRows = [\n {\n type: \"user.message\",\n payload: { text: input.text, childCompletion: input.childCompletion },\n clientEventId: input.clientEventId,\n },\n ...(shouldQueue ? [{ type: \"session.status.changed\", payload: { status: \"queued\" }, clientEventId: null as string | null }] : []),\n ].map((event) => ({\n accountId: parent.accountId,\n workspaceId: parent.workspaceId,\n sessionId: parent.id,\n sequence: ++sequence,\n type: event.type,\n payload: sanitizeEventPayload(event.payload),\n clientEventId: event.clientEventId ?? null,\n turnId: null,\n producerId: null,\n producerSeq: null,\n occurredAt: now,\n }));\n const inserted = (await tx.insert(schema.sessionEvents).values(eventRows).returning()).map(mapEvent);\n const triggerEvent = inserted[0]!;\n\n const position = await nextTurnPosition(tx as unknown as Database, input.workspaceId, parent.id);\n const [turnRow] = await tx.insert(schema.sessionTurns).values({\n accountId: parent.accountId,\n workspaceId: parent.workspaceId,\n sessionId: parent.id,\n triggerEventId: triggerEvent.id,\n temporalWorkflowId: workflowId,\n status: \"queued\",\n source: \"user\",\n position,\n prompt: input.text,\n resources: [],\n tools: parent.tools as ToolRef[],\n model: parent.model,\n reasoningEffort: reasoningEffortForMetadata(parent.metadata, input.reasoningEffortFallback),\n sandboxBackend: parent.sandboxBackend as SandboxBackend,\n metadata: { childCompletion: input.childCompletion },\n }).returning();\n if (!turnRow) {\n throw new Error(\"Failed to enqueue parent wake turn\");\n }\n const turn = mapSessionTurn(turnRow);\n\n sequence += 1;\n const [queuedEventRow] = await tx.insert(schema.sessionEvents).values({\n accountId: parent.accountId,\n workspaceId: parent.workspaceId,\n sessionId: parent.id,\n sequence,\n type: \"turn.queued\",\n payload: sanitizeEventPayload({ turnId: turn.id, triggerEventId: triggerEvent.id, source: turn.source }),\n clientEventId: null,\n turnId: turn.id,\n producerId: null,\n producerSeq: null,\n occurredAt: now,\n }).returning();\n const events = [...inserted, ...(queuedEventRow ? [mapEvent(queuedEventRow)] : [])];\n\n await tx.update(schema.sessions).set({\n lastSequence: sequence,\n ...(shouldQueue ? { status: \"queued\" as const, activeTurnId: null } : {}),\n updatedAt: now,\n }).where(and(eq(schema.sessions.workspaceId, input.workspaceId), eq(schema.sessions.id, parent.id)));\n\n return { delivered: true as const, turn, triggerEvent, events, temporalWorkflowId: workflowId };\n }));\n}\n\nexport async function setTemporalWorkflowId(db: Database, workspaceId: string, sessionId: string, workflowId: string): Promise<void> {\n await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n await scopedDb.update(schema.sessions).set({\n temporalWorkflowId: workflowId,\n updatedAt: new Date(),\n }).where(and(eq(schema.sessions.workspaceId, workspaceId), eq(schema.sessions.id, sessionId)));\n });\n}\n\nexport async function finishTurn(db: Database, workspaceId: string, turnId: string, status: SessionStatus | SessionTurnStatus): Promise<void> {\n await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n await scopedDb.update(schema.sessionTurns).set({\n status: turnStatusForFinish(status),\n finishedAt: status === \"requires_action\" ? undefined : new Date(),\n updatedAt: new Date(),\n }).where(and(eq(schema.sessionTurns.workspaceId, workspaceId), eq(schema.sessionTurns.id, turnId)));\n });\n}\n\n/**\n * Put a preempted (worker shutdown mid-flight) turn back on the session\n * queue so the workflow's next claim re-dispatches it on a healthy worker.\n * The trigger event is swapped when the resumed attempt should enter\n * through a synthesized resume notice instead of replaying the original\n * trigger (the original input is already part of persisted conversation\n * truth by then). Keeping the original position lets the resumed turn run\n * before any turns queued behind it. Accepts `running` turns and\n * `requires_action` turns: an approval rerun re-dispatches the same turn\n * without a fresh claim, so the row still carries the approval-wait status\n * while the rerun activity executes.\n */\nexport async function requeuePreemptedTurn(db: Database, workspaceId: string, turnId: string, triggerEventId: string): Promise<void> {\n await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const [row] = await scopedDb.update(schema.sessionTurns).set({\n status: \"queued\",\n triggerEventId,\n startedAt: null,\n finishedAt: null,\n updatedAt: new Date(),\n }).where(and(eq(schema.sessionTurns.workspaceId, workspaceId), eq(schema.sessionTurns.id, turnId), inArray(schema.sessionTurns.status, [\"running\", \"requires_action\"]))).returning({ id: schema.sessionTurns.id });\n if (!row) {\n throw new Error(`Preemptible session turn not found: ${turnId}`);\n }\n });\n}\n\n/**\n * Bump the per-turn worker-death redispatch counter and return the new value.\n * Stored in the turn row's metadata (not workflow-local state) so the\n * crash-loop guard is replay-safe: the count survives workflow replay, worker\n * restarts, and even a session-workflow re-run, and the increment is a single\n * atomic statement.\n */\nexport async function incrementTurnWorkerDeathRedispatches(db: Database, workspaceId: string, turnId: string): Promise<number> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const rows = await scopedDb.execute(sql<{ count: number }>`\n update session_turns\n set metadata = jsonb_set(\n coalesce(metadata, '{}'::jsonb),\n '{workerDeathRedispatches}',\n to_jsonb(coalesce((metadata->>'workerDeathRedispatches')::int, 0) + 1),\n true\n ),\n updated_at = now()\n where workspace_id = ${workspaceId} and id = ${turnId}\n returning (metadata->>'workerDeathRedispatches')::int as count\n `);\n const count = rows[0]?.count;\n if (count === undefined || count === null) {\n throw new Error(`Session turn not found: ${turnId}`);\n }\n return Number(count);\n });\n}\n\nexport async function getSessionTurn(db: Database, workspaceId: string, turnId: string): Promise<SessionTurn | null> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const [row] = await scopedDb.select().from(schema.sessionTurns).where(and(eq(schema.sessionTurns.workspaceId, workspaceId), eq(schema.sessionTurns.id, turnId))).limit(1);\n return row ? mapSessionTurn(row) : null;\n });\n}\n\nexport async function listSessionTurns(db: Database, workspaceId: string, sessionId: string, limit = 100): Promise<SessionTurn[]> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const rows = await scopedDb.select().from(schema.sessionTurns)\n .where(and(eq(schema.sessionTurns.workspaceId, workspaceId), eq(schema.sessionTurns.sessionId, sessionId)))\n .orderBy(asc(schema.sessionTurns.position), asc(schema.sessionTurns.createdAt))\n .limit(limit);\n return rows.map(mapSessionTurn);\n });\n}\n\nexport async function updateQueuedSessionTurn(db: Database, workspaceId: string, turnId: string, input: UpdateQueuedSessionTurnInput): Promise<SessionTurn> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const [row] = await scopedDb.update(schema.sessionTurns).set({\n ...(input.prompt !== undefined ? { prompt: input.prompt } : {}),\n ...(input.resources !== undefined ? { resources: input.resources } : {}),\n ...(input.tools !== undefined ? { tools: input.tools } : {}),\n ...(input.model !== undefined ? { model: input.model } : {}),\n ...(input.reasoningEffort !== undefined ? { reasoningEffort: input.reasoningEffort } : {}),\n ...(input.sandboxBackend !== undefined ? { sandboxBackend: input.sandboxBackend } : {}),\n ...(input.metadata !== undefined ? { metadata: input.metadata } : {}),\n updatedAt: new Date(),\n }).where(and(eq(schema.sessionTurns.workspaceId, workspaceId), eq(schema.sessionTurns.id, turnId), eq(schema.sessionTurns.status, \"queued\"))).returning();\n if (!row) {\n throw new Error(`Queued session turn not found: ${turnId}`);\n }\n return mapSessionTurn(row);\n });\n}\n\nexport async function cancelQueuedSessionTurn(db: Database, workspaceId: string, turnId: string): Promise<SessionTurn> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const [row] = await scopedDb.update(schema.sessionTurns).set({\n status: \"cancelled\",\n finishedAt: new Date(),\n updatedAt: new Date(),\n }).where(and(eq(schema.sessionTurns.workspaceId, workspaceId), eq(schema.sessionTurns.id, turnId), eq(schema.sessionTurns.status, \"queued\"))).returning();\n if (!row) {\n throw new Error(`Queued session turn not found: ${turnId}`);\n }\n return mapSessionTurn(row);\n });\n}\n\nexport async function reorderQueuedSessionTurns(db: Database, workspaceId: string, sessionId: string, turnIds: string[]): Promise<SessionTurn[]> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => await scopedDb.transaction(async (tx) => {\n const rows = await tx.select().from(schema.sessionTurns)\n .where(and(eq(schema.sessionTurns.workspaceId, workspaceId), eq(schema.sessionTurns.sessionId, sessionId), eq(schema.sessionTurns.status, \"queued\"), inArray(schema.sessionTurns.id, turnIds)));\n if (rows.length !== turnIds.length) {\n throw new Error(\"All reordered turns must be queued turns in the session\");\n }\n let index = 0;\n for (const turnId of turnIds) {\n index += 1;\n await tx.update(schema.sessionTurns).set({\n position: index,\n updatedAt: new Date(),\n }).where(and(eq(schema.sessionTurns.workspaceId, workspaceId), eq(schema.sessionTurns.id, turnId)));\n }\n const updated = await tx.select().from(schema.sessionTurns)\n .where(and(eq(schema.sessionTurns.workspaceId, workspaceId), eq(schema.sessionTurns.sessionId, sessionId), eq(schema.sessionTurns.status, \"queued\")))\n .orderBy(asc(schema.sessionTurns.position), asc(schema.sessionTurns.createdAt));\n return updated.map(mapSessionTurn);\n }));\n}\n\nexport async function appendSessionEvents(db: Database, workspaceId: string, sessionId: string, inputs: AppendEventInput[]): Promise<SessionEvent[]> {\n if (inputs.length === 0) {\n return [];\n }\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => await scopedDb.transaction(async (tx) => {\n const [row] = await tx.select().from(schema.sessions)\n .where(and(eq(schema.sessions.workspaceId, workspaceId), eq(schema.sessions.id, sessionId)))\n .for(\"update\")\n .limit(1);\n if (!row) {\n throw new Error(`Session not found: ${sessionId}`);\n }\n let sequence = row.lastSequence;\n const values = inputs.map((input) => ({\n accountId: row.accountId,\n workspaceId: row.workspaceId,\n sessionId,\n sequence: ++sequence,\n type: input.type,\n payload: sanitizeEventPayload(input.payload ?? {}),\n clientEventId: input.clientEventId ?? null,\n turnId: input.turnId ?? null,\n producerId: input.producerId ?? null,\n producerSeq: input.producerSeq ?? null,\n occurredAt: input.occurredAt ?? new Date(),\n }));\n const inserted = await tx.insert(schema.sessionEvents).values(values).returning();\n await tx.update(schema.sessions).set({ lastSequence: sequence, updatedAt: new Date() }).where(and(eq(schema.sessions.workspaceId, workspaceId), eq(schema.sessions.id, sessionId)));\n return inserted.map(mapEvent);\n }));\n}\n\nexport async function appendSessionEventsAndUpdateSession(db: Database, workspaceId: string, sessionId: string, inputs: AppendEventInput[], update: {\n resources?: ResourceRef[];\n tools?: ToolRef[];\n model?: string;\n metadata?: Record<string, unknown>;\n status?: SessionStatus;\n activeTurnId?: string | null;\n}): Promise<SessionEvent[]> {\n if (inputs.length === 0) {\n return [];\n }\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => await scopedDb.transaction(async (tx) => {\n const [row] = await tx.select().from(schema.sessions)\n .where(and(eq(schema.sessions.workspaceId, workspaceId), eq(schema.sessions.id, sessionId)))\n .for(\"update\")\n .limit(1);\n if (!row) {\n throw new Error(`Session not found: ${sessionId}`);\n }\n let sequence = row.lastSequence;\n const now = new Date();\n const values = inputs.map((input) => ({\n accountId: row.accountId,\n workspaceId: row.workspaceId,\n sessionId,\n sequence: ++sequence,\n type: input.type,\n payload: sanitizeEventPayload(input.payload ?? {}),\n clientEventId: input.clientEventId ?? null,\n turnId: input.turnId ?? null,\n producerId: input.producerId ?? null,\n producerSeq: input.producerSeq ?? null,\n occurredAt: input.occurredAt ?? now,\n }));\n const inserted = await tx.insert(schema.sessionEvents).values(values).returning();\n await tx.update(schema.sessions).set({\n lastSequence: sequence,\n ...(update.resources !== undefined ? { resources: update.resources } : {}),\n ...(update.tools !== undefined ? { tools: update.tools } : {}),\n ...(update.model !== undefined ? { model: update.model } : {}),\n ...(update.metadata !== undefined ? { metadata: update.metadata } : {}),\n ...(update.status !== undefined ? { status: update.status } : {}),\n ...(update.activeTurnId !== undefined ? { activeTurnId: update.activeTurnId } : {}),\n updatedAt: now,\n }).where(and(eq(schema.sessions.workspaceId, workspaceId), eq(schema.sessions.id, sessionId)));\n return inserted.map(mapEvent);\n }));\n}\n\ntype LockedSessionUpdateContext = {\n updateSessionMcpServerCredentials: (updates: UpdateSessionMcpServerCredentialsInput[]) => Promise<UpdateSessionMcpServerCredentialsResult>;\n};\n\ntype LockedSessionUpdateResult = {\n events: AppendEventInput[];\n update?: {\n resources?: ResourceRef[];\n tools?: ToolRef[];\n model?: string;\n metadata?: Record<string, unknown>;\n status?: SessionStatus;\n activeTurnId?: string | null;\n };\n};\n\nexport async function appendSessionEventsWithLockedSessionUpdate(\n db: Database,\n workspaceId: string,\n sessionId: string,\n build: (session: Session, context: LockedSessionUpdateContext) => LockedSessionUpdateResult | Promise<LockedSessionUpdateResult>,\n): Promise<SessionEvent[]> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => await scopedDb.transaction(async (tx) => {\n const [sessionRow] = await tx.select().from(schema.sessions).where(and(eq(schema.sessions.workspaceId, workspaceId), eq(schema.sessions.id, sessionId))).for(\"update\").limit(1);\n if (!sessionRow) {\n throw new Error(`Session not found: ${sessionId}`);\n }\n const built = await build(mapSession(sessionRow), {\n updateSessionMcpServerCredentials: async (updates) => await updateSessionMcpServerCredentialsInTransaction(tx, { workspaceId, sessionId, updates }),\n });\n if (built.events.length === 0) {\n return [];\n }\n let sequence = sessionRow.lastSequence;\n const now = new Date();\n const values = built.events.map((input) => ({\n accountId: sessionRow.accountId,\n workspaceId: sessionRow.workspaceId,\n sessionId,\n sequence: ++sequence,\n type: input.type,\n payload: sanitizeEventPayload(input.payload ?? {}),\n clientEventId: input.clientEventId ?? null,\n turnId: input.turnId ?? null,\n producerId: input.producerId ?? null,\n producerSeq: input.producerSeq ?? null,\n occurredAt: input.occurredAt ?? now,\n }));\n const inserted = await tx.insert(schema.sessionEvents).values(values).returning();\n const update = built.update ?? {};\n await tx.update(schema.sessions).set({\n lastSequence: sequence,\n ...(update.resources !== undefined ? { resources: update.resources } : {}),\n ...(update.tools !== undefined ? { tools: update.tools } : {}),\n ...(update.model !== undefined ? { model: update.model } : {}),\n ...(update.metadata !== undefined ? { metadata: update.metadata } : {}),\n ...(update.status !== undefined ? { status: update.status } : {}),\n ...(update.activeTurnId !== undefined ? { activeTurnId: update.activeTurnId } : {}),\n updatedAt: now,\n }).where(and(eq(schema.sessions.workspaceId, workspaceId), eq(schema.sessions.id, sessionId)));\n return inserted.map(mapEvent);\n }));\n}\n\nexport function sessionSubject(workspaceId: string, sessionId: string): string {\n return `workspaces.${workspaceId}.sessions.${sessionId}.events`;\n}\n\nfunction mapSession(row: typeof schema.sessions.$inferSelect, mcpServers: SessionMcpServerMetadata[] = []): Session {\n return {\n id: row.id,\n accountId: row.accountId,\n workspaceId: row.workspaceId,\n status: row.status as SessionStatus,\n initialMessage: row.initialMessage,\n title: row.title ?? null,\n titleSource: (row.titleSource as \"user\" | \"agent\" | null) ?? null,\n instructions: row.instructions ?? null,\n resources: row.resources as ResourceRef[],\n tools: row.tools as ToolRef[],\n metadata: row.metadata,\n model: row.model,\n sandboxBackend: row.sandboxBackend as SandboxBackend,\n sandboxOs: row.sandboxOs as SandboxOs,\n sandboxGroupId: row.sandboxGroupId,\n // The first-class swappable-sandbox pointer (M2). null == use the group\n // sandbox; active_epoch is the swap fence. Defensive Number() coercion keeps\n // the fence exact even if the column type ever drifts (the lease-epoch lesson).\n activeSandboxId: row.activeSandboxId ?? null,\n activeEpoch: Number(row.activeEpoch),\n environmentId: row.environmentId,\n firstPartyMcpPermissions: (row.firstPartyMcpPermissions as Permission[] | null) ?? null,\n mcpServers,\n parentSessionId: row.parentSessionId ?? null,\n createIdempotencyKey: row.createIdempotencyKey ?? null,\n temporalWorkflowId: row.temporalWorkflowId,\n activeTurnId: row.activeTurnId,\n lastInputTokens: row.lastInputTokens ?? null,\n lastSequence: row.lastSequence,\n codexPinnedCredentialId: row.codexPinnedCredentialId ?? null,\n codexLastCredentialId: row.codexLastCredentialId ?? null,\n createdAt: row.createdAt.toISOString(),\n updatedAt: row.updatedAt.toISOString(),\n };\n}\n\nfunction mapEvent(row: typeof schema.sessionEvents.$inferSelect): SessionEvent {\n return {\n id: row.id,\n workspaceId: row.workspaceId,\n sessionId: row.sessionId,\n sequence: row.sequence,\n type: row.type as SessionEventType,\n payload: row.payload,\n occurredAt: row.occurredAt.toISOString(),\n clientEventId: row.clientEventId,\n turnId: row.turnId,\n };\n}\n\nfunction mapSessionTurn(row: typeof schema.sessionTurns.$inferSelect): SessionTurn {\n return {\n id: row.id,\n workspaceId: row.workspaceId,\n sessionId: row.sessionId,\n triggerEventId: row.triggerEventId,\n temporalWorkflowId: row.temporalWorkflowId,\n status: row.status as SessionTurnStatus,\n source: row.source as SessionTurnSource,\n position: row.position,\n prompt: row.prompt,\n resources: row.resources as ResourceRef[],\n tools: row.tools as ToolRef[],\n model: row.model,\n reasoningEffort: row.reasoningEffort as ReasoningEffort,\n sandboxBackend: row.sandboxBackend as SandboxBackend,\n sandboxOs: (row.sandboxOs as SandboxOs | null) ?? null,\n metadata: row.metadata,\n startedAt: row.startedAt ? row.startedAt.toISOString() : null,\n finishedAt: row.finishedAt ? row.finishedAt.toISOString() : null,\n createdAt: row.createdAt.toISOString(),\n updatedAt: row.updatedAt.toISOString(),\n };\n}\n\nasync function nextTurnPosition(db: Database, workspaceId: string, sessionId: string): Promise<number> {\n const [{ maxPosition } = { maxPosition: 0 }] = await db.select({\n maxPosition: sql<number>`coalesce(max(${schema.sessionTurns.position}), 0)`,\n }).from(schema.sessionTurns).where(and(eq(schema.sessionTurns.workspaceId, workspaceId), eq(schema.sessionTurns.sessionId, sessionId)));\n return Number(maxPosition) + 1;\n}\n\nfunction turnStatusForFinish(status: SessionStatus | SessionTurnStatus): SessionTurnStatus {\n if (status === \"idle\") {\n return \"completed\";\n }\n if (status === \"queued\") {\n return \"queued\";\n }\n if (status === \"running\") {\n return \"running\";\n }\n return status;\n}\n\nfunction promptFromTrigger(payload: unknown): string | null {\n if (payload && typeof payload === \"object\" && \"text\" in payload && typeof payload.text === \"string\") {\n return payload.text;\n }\n return null;\n}\n\nfunction resourcesFromTrigger(payload: unknown): ResourceRef[] | null {\n if (payload && typeof payload === \"object\" && \"resources\" in payload && Array.isArray(payload.resources)) {\n return payload.resources as ResourceRef[];\n }\n return null;\n}\n\nfunction toolsFromTrigger(payload: unknown): ToolRef[] | null {\n if (payload && typeof payload === \"object\" && \"tools\" in payload && Array.isArray(payload.tools)) {\n return payload.tools as ToolRef[];\n }\n return null;\n}\n\nfunction reasoningEffortFromSession(session: Session): ReasoningEffort {\n const value = session.metadata.reasoningEffort;\n return value === \"none\" || value === \"minimal\" || value === \"low\" || value === \"medium\" || value === \"high\" || value === \"xhigh\"\n ? value\n : \"medium\";\n}\n\nfunction mapFile(row: typeof schema.files.$inferSelect): FileAsset {\n return {\n id: row.id,\n workspaceId: row.workspaceId,\n status: row.status as FileStatus,\n filename: row.filename,\n safeFilename: row.safeFilename,\n contentType: row.contentType,\n sizeBytes: row.sizeBytes,\n sha256: row.sha256,\n bucket: row.bucket,\n objectKey: row.objectKey,\n createdAt: row.createdAt.toISOString(),\n updatedAt: row.updatedAt.toISOString(),\n };\n}\n\nfunction mapScheduledTask(row: typeof schema.scheduledTasks.$inferSelect): ScheduledTask {\n return {\n id: row.id,\n accountId: row.accountId,\n workspaceId: row.workspaceId,\n name: row.name,\n status: row.status as ScheduledTaskStatus,\n schedule: row.schedule as ScheduledTaskScheduleSpec,\n temporalScheduleId: row.temporalScheduleId,\n runMode: row.runMode as ScheduledTaskRunMode,\n overlapPolicy: row.overlapPolicy as ScheduledTaskOverlapPolicy,\n agentConfig: row.agentConfig as ScheduledTaskAgentConfig,\n reusableSessionId: row.reusableSessionId,\n environmentId: row.environmentId,\n metadata: row.metadata,\n createdAt: row.createdAt.toISOString(),\n updatedAt: row.updatedAt.toISOString(),\n };\n}\n\nfunction mapScheduledTaskRun(row: typeof schema.scheduledTaskRuns.$inferSelect): ScheduledTaskRun {\n return {\n id: row.id,\n accountId: row.accountId,\n workspaceId: row.workspaceId,\n taskId: row.taskId,\n status: row.status as ScheduledTaskRunStatus,\n triggerType: row.triggerType as ScheduledTaskTriggerType,\n scheduledAt: row.scheduledAt ? row.scheduledAt.toISOString() : null,\n firedAt: row.firedAt.toISOString(),\n sessionId: row.sessionId,\n triggerEventId: row.triggerEventId,\n error: row.error,\n createdAt: row.createdAt.toISOString(),\n updatedAt: row.updatedAt.toISOString(),\n };\n}\n\nfunction mapAccount(row: typeof schema.managedAccounts.$inferSelect): ManagedAccount {\n return {\n id: row.id,\n name: row.name,\n externalSource: row.externalSource,\n externalId: row.externalId,\n createdAt: row.createdAt.toISOString(),\n updatedAt: row.updatedAt.toISOString(),\n };\n}\n\nfunction mapPackInstallation(row: typeof schema.packInstallations.$inferSelect): PackInstallation {\n return {\n id: row.id,\n accountId: row.accountId,\n workspaceId: row.workspaceId,\n packId: row.packId,\n status: row.status as PackInstallationStatus,\n metadata: row.metadata,\n enabledAt: row.enabledAt.toISOString(),\n updatedAt: row.updatedAt.toISOString(),\n };\n}\n\nfunction mapWorkspacePack(row: typeof schema.workspacePacks.$inferSelect): WorkspaceRegisteredPack {\n return {\n accountId: row.accountId,\n workspaceId: row.workspaceId,\n // Manifests are validated with the CapabilityPack contract at the API\n // boundary before they are stored.\n pack: row.manifest as unknown as CapabilityPack,\n createdAt: row.createdAt.toISOString(),\n updatedAt: row.updatedAt.toISOString(),\n };\n}\n\nfunction mapCapabilityCatalogItem(row: typeof schema.capabilityCatalogItems.$inferSelect): CapabilityCatalogItem {\n const runtime = row.kind === \"mcp\" && row.endpointUrl\n ? {\n available: true,\n mcpServerId: mcpServerIdForCapability(row.id, row.metadata),\n transport: \"streamable-http\",\n notes: row.authModel\n ? \"Requires credential headers supplied in the enable request.\"\n : null,\n }\n : {\n available: false,\n notes: row.kind === \"mcp\"\n ? \"Remote streamable HTTP endpoint is required for runtime use.\"\n : null,\n };\n return {\n id: row.id,\n accountId: row.accountId,\n workspaceId: row.workspaceId,\n kind: row.kind as CapabilityKind,\n source: row.source as CapabilitySource,\n name: row.name,\n description: row.description,\n category: row.category,\n tags: row.tags,\n homepageUrl: row.homepageUrl,\n endpointUrl: row.endpointUrl,\n installUrl: row.installUrl,\n authModel: row.authModel,\n tools: [],\n runtime,\n enabled: false,\n enabledReason: null,\n metadata: row.metadata,\n createdAt: row.createdAt.toISOString(),\n updatedAt: row.updatedAt.toISOString(),\n };\n}\n\nfunction mapWorkspace(row: typeof schema.workspaces.$inferSelect): Workspace {\n return {\n id: row.id,\n accountId: row.accountId,\n name: row.name,\n slug: row.slug,\n externalSource: row.externalSource,\n externalId: row.externalId,\n agentInstructions: row.agentInstructions ?? null,\n createdAt: row.createdAt.toISOString(),\n updatedAt: row.updatedAt.toISOString(),\n };\n}\n\nfunction mapWorkspaceMember(row: typeof schema.workspaceMemberships.$inferSelect): WorkspaceMember {\n return {\n subjectId: row.subjectId,\n subjectLabel: row.subjectLabel,\n role: row.role,\n permissions: row.permissions as Permission[],\n createdAt: row.createdAt.toISOString(),\n };\n}\n\nfunction mapCapabilityInstallation(row: typeof schema.capabilityInstallations.$inferSelect): CapabilityInstallation {\n return {\n id: row.id,\n accountId: row.accountId,\n workspaceId: row.workspaceId,\n capabilityId: row.capabilityId,\n kind: row.kind as CapabilityKind,\n status: row.status as CapabilityInstallationStatus,\n config: redactInstallationConfig(row.config),\n metadata: row.metadata,\n enabledAt: row.enabledAt.toISOString(),\n updatedAt: row.updatedAt.toISOString(),\n };\n}\n\n/**\n * Stored credential-header ciphertext never leaves the database through the\n * generic installation mapping — callers see only the sorted header names.\n * The runtime reads ciphertext through listEnabledMcpCapabilityServers and\n * the enable flow through getStoredCapabilityHeaderCiphertext.\n */\nfunction redactInstallationConfig(config: Record<string, unknown>): Record<string, unknown> {\n const headersEncrypted = encryptedHeadersConfig(config.headersEncrypted);\n if (!headersEncrypted) {\n return config;\n }\n const { headersEncrypted: _omitted, ...rest } = config;\n return { ...rest, headerNames: Object.keys(headersEncrypted).sort() };\n}\n\nfunction mapSocialConnection(row: typeof schema.socialConnections.$inferSelect): SocialConnection {\n return {\n id: row.id,\n accountId: row.accountId,\n workspaceId: row.workspaceId,\n provider: row.provider as SocialProvider,\n accountHandle: row.accountHandle,\n accountName: row.accountName,\n externalAccountId: row.externalAccountId,\n status: row.status as SocialConnectionStatus,\n scopes: row.scopes,\n credentialRef: row.credentialRef,\n tokenMetadata: row.tokenMetadata,\n metadata: row.metadata,\n createdAt: row.createdAt.toISOString(),\n updatedAt: row.updatedAt.toISOString(),\n };\n}\n\nfunction mapApiKey(row: typeof schema.apiKeys.$inferSelect): ApiKey {\n return {\n id: row.id,\n accountId: row.accountId,\n workspaceId: row.workspaceId,\n name: row.name,\n prefix: row.prefix,\n permissions: row.permissions as Permission[],\n expiresAt: row.expiresAt ? row.expiresAt.toISOString() : null,\n revokedAt: row.revokedAt ? row.revokedAt.toISOString() : null,\n lastUsedAt: row.lastUsedAt ? row.lastUsedAt.toISOString() : null,\n createdAt: row.createdAt.toISOString(),\n updatedAt: row.updatedAt.toISOString(),\n };\n}\n\nfunction mapGitHubInstallation(row: typeof schema.githubInstallations.$inferSelect): GitHubInstallation {\n return {\n id: row.id,\n accountId: row.accountId,\n workspaceId: row.workspaceId,\n installationId: row.installationId,\n accountLogin: row.accountLogin,\n accountType: row.accountType,\n createdAt: row.createdAt.toISOString(),\n updatedAt: row.updatedAt.toISOString(),\n };\n}\n\nfunction mapUsageEvent(row: typeof schema.usageEvents.$inferSelect): UsageEvent {\n return {\n id: row.id,\n workspaceId: row.workspaceId,\n accountId: row.accountId,\n subjectId: row.subjectId,\n eventType: row.eventType as UsageEvent[\"eventType\"],\n quantity: row.quantity,\n unit: row.unit,\n sourceResourceType: row.sourceResourceType,\n sourceResourceId: row.sourceResourceId,\n idempotencyKey: row.idempotencyKey,\n occurredAt: row.occurredAt.toISOString(),\n recordedAt: row.recordedAt.toISOString(),\n exportedToBillingAt: row.exportedToBillingAt ? row.exportedToBillingAt.toISOString() : null,\n billingProviderEventId: row.billingProviderEventId,\n };\n}\n\nfunction mapSocialPost(row: typeof schema.socialPosts.$inferSelect): SocialPost {\n return {\n id: row.id,\n accountId: row.accountId,\n workspaceId: row.workspaceId,\n connectionId: row.connectionId,\n provider: row.provider as SocialProvider,\n externalPostId: row.externalPostId,\n url: row.url,\n authorHandle: row.authorHandle,\n text: row.text,\n publishedAt: row.publishedAt.toISOString(),\n metrics: row.metrics,\n raw: row.raw,\n createdAt: row.createdAt.toISOString(),\n };\n}\n\nfunction stringArrayConfig(value: unknown): string[] | undefined {\n if (!Array.isArray(value)) {\n return undefined;\n }\n const values = value.filter((item): item is string => typeof item === \"string\" && item.trim().length > 0);\n return values.length > 0 ? [...new Set(values.map((item) => item.trim()))] : undefined;\n}\n\nfunction positiveIntegerConfig(value: unknown): number | undefined {\n if (typeof value === \"number\" && Number.isInteger(value) && value > 0) {\n return value;\n }\n if (typeof value === \"string\" && /^\\d+$/.test(value) && Number(value) > 0) {\n return Number(value);\n }\n return undefined;\n}\n\nfunction booleanConfig(value: unknown): boolean | undefined {\n return typeof value === \"boolean\" ? value : undefined;\n}\n\nfunction encryptedHeadersConfig(value: unknown): Record<string, string> | undefined {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) {\n return undefined;\n }\n const entries = Object.entries(value as Record<string, unknown>)\n .filter((entry): entry is [string, string] => typeof entry[1] === \"string\" && entry[1].length > 0);\n return entries.length > 0 ? Object.fromEntries(entries) : undefined;\n}\n\nfunction mcpConnectivityOk(metadata: Record<string, unknown>): boolean {\n const value = metadata.mcpConnectivity;\n return !!value && typeof value === \"object\" && \"status\" in value && value.status === \"ok\";\n}\n\nfunction shortHash(value: string): string {\n let hash = 0x811c9dc5;\n for (let index = 0; index < value.length; index += 1) {\n hash ^= value.charCodeAt(index);\n hash = Math.imul(hash, 0x01000193);\n }\n return (hash >>> 0).toString(36).padStart(7, \"0\").slice(0, 7);\n}\n\n// Shared, refreshing, id-addressed Codex token resolver + the per-account usage\n// wrapper (P2). Placed at the END so every accessor it orchestrates\n// (loadCodexCredentialForRun / recordCodexTokenRefresh / setCodexCredentialStatus /\n// recordCodexAccountUsage) is already initialized when its default-deps bag\n// evaluates under the index↔resolver module cycle.\nexport * from \"./codex-token-resolver\";\n","import { createCipheriv, createDecipheriv, randomBytes } from \"node:crypto\";\n\nconst VERSION_PREFIX = \"v1\";\nconst IV_BYTES = 12;\nconst GCM_TAG_BYTES = 16;\nconst KEY_BYTES = 32;\n\n/**\n * Encrypts one workspace environment variable value with AES-256-GCM under an\n * operator key held outside Postgres. Output format: `v1:<b64 iv>:<b64 ciphertext||tag>`.\n */\nexport function encryptEnvironmentValue(key: Uint8Array, plaintext: string): string {\n assertKey(key);\n const iv = randomBytes(IV_BYTES);\n const cipher = createCipheriv(\"aes-256-gcm\", key, iv);\n const ciphertext = Buffer.concat([cipher.update(plaintext, \"utf8\"), cipher.final(), cipher.getAuthTag()]);\n return `${VERSION_PREFIX}:${iv.toString(\"base64\")}:${ciphertext.toString(\"base64\")}`;\n}\n\n/**\n * Decrypts a stored `v1:` value. Error messages never echo plaintext or\n * ciphertext: unknown versions throw \"unsupported environment value format\",\n * auth-tag mismatches throw \"environment value decryption failed\".\n */\nexport function decryptEnvironmentValue(key: Uint8Array, stored: string): string {\n assertKey(key);\n const parts = stored.split(\":\");\n if (parts.length !== 3 || parts[0] !== VERSION_PREFIX) {\n throw new Error(\"unsupported environment value format\");\n }\n const iv = Buffer.from(parts[1]!, \"base64\");\n const payload = Buffer.from(parts[2]!, \"base64\");\n if (iv.length !== IV_BYTES || payload.length <= GCM_TAG_BYTES) {\n throw new Error(\"unsupported environment value format\");\n }\n const tag = payload.subarray(payload.length - GCM_TAG_BYTES);\n const ciphertext = payload.subarray(0, payload.length - GCM_TAG_BYTES);\n const decipher = createDecipheriv(\"aes-256-gcm\", key, iv);\n decipher.setAuthTag(tag);\n try {\n return Buffer.concat([decipher.update(ciphertext), decipher.final()]).toString(\"utf8\");\n } catch {\n throw new Error(\"environment value decryption failed\");\n }\n}\n\nfunction assertKey(key: Uint8Array): void {\n if (key.length !== KEY_BYTES) {\n throw new Error(\"environment encryption key must be exactly 32 bytes\");\n }\n}\n","/**\n * Last line of defense against a session event crashing a whole turn.\n *\n * Postgres `text`/`jsonb` cannot store a NUL byte (U+0000) nor lone UTF-16\n * surrogates. Raw exec output routinely carries both -- chrome/crashpad logs,\n * `cat` of a binary, random bytes -- and the worker persists that output verbatim\n * inside `agent.toolCall.output` / `sandbox.command.output` event payloads. When\n * such a payload reaches `INSERT INTO session_events`, the driver rejects it\n * (\"Failed query: insert into session_events\") and the turn dies.\n *\n * `sanitizeEventPayload` deep-walks any payload value (objects, arrays, nested)\n * and, for every string, strips NUL and rewrites invalid/lone UTF-16 surrogates\n * to the Unicode replacement char (U+FFFD), so the result is always valid UTF-8\n * that jsonb can store. It is cheap and total: only strings are touched, and only\n * the two disallowed classes of code unit -- no meaningful text is lost, no\n * truncation (truncation is handled elsewhere).\n */\n\nconst REPLACEMENT = \"�\";\n\n/**\n * Strip NUL and repair invalid/lone UTF-16 surrogates in a single string.\n * Returns the input unchanged (same reference) when it is already clean, so the\n * common case allocates nothing.\n */\nexport function sanitizeEventString(value: string): string {\n // Fast path: no NUL and no surrogate code unit at all -> nothing to do.\n // Surrogates live in U+D800..U+DFFF; a quick scan avoids the rebuild cost.\n let needsWork = false;\n for (let i = 0; i < value.length; i++) {\n const code = value.charCodeAt(i);\n if (code === 0x0000 || (code >= 0xd800 && code <= 0xdfff)) {\n needsWork = true;\n break;\n }\n }\n if (!needsWork) {\n return value;\n }\n\n let out = \"\";\n for (let i = 0; i < value.length; i++) {\n const code = value.charCodeAt(i);\n if (code === 0x0000) {\n // Drop NUL entirely.\n continue;\n }\n if (code >= 0xd800 && code <= 0xdbff) {\n // High surrogate: valid only when immediately followed by a low surrogate.\n const next = i + 1 < value.length ? value.charCodeAt(i + 1) : 0;\n if (next >= 0xdc00 && next <= 0xdfff) {\n out += value[i]! + value[i + 1]!;\n i += 1;\n continue;\n }\n out += REPLACEMENT;\n continue;\n }\n if (code >= 0xdc00 && code <= 0xdfff) {\n // Lone low surrogate (a valid pair would have been consumed above).\n out += REPLACEMENT;\n continue;\n }\n out += value[i]!;\n }\n return out;\n}\n\n/**\n * Deep-walk a session event payload and sanitize every string value. Mirrors the\n * shape of the worker redaction deep-walk: objects, arrays, and nested\n * combinations are traversed; non-string leaves pass through untouched. Object\n * keys are sanitized too -- they are jsonb-constrained the same as values.\n */\nexport function sanitizeEventPayload<T>(payload: T): T {\n if (typeof payload === \"string\") {\n return sanitizeEventString(payload) as unknown as T;\n }\n if (Array.isArray(payload)) {\n return payload.map((item) => sanitizeEventPayload(item)) as unknown as T;\n }\n if (payload && typeof payload === \"object\") {\n const entries = Object.entries(payload as Record<string, unknown>).map(\n ([key, value]) => [sanitizeEventString(key), sanitizeSensitiveEventField(key, value)] as const,\n );\n return Object.fromEntries(entries) as unknown as T;\n }\n return payload;\n}\n\nfunction sanitizeSensitiveEventField(key: string, value: unknown): unknown {\n if (key === \"mcpServers\") {\n return sanitizeSessionMcpServerList(value);\n }\n if (key === \"mcpCredentialUpdates\") {\n return sanitizeMcpCredentialUpdateList(value);\n }\n return sanitizeEventPayload(value);\n}\n\nfunction sanitizeSessionMcpServerList(value: unknown): unknown {\n if (!Array.isArray(value)) {\n return sanitizeEventPayload(value);\n }\n return value.map((item) => {\n if (!isPlainObject(item)) {\n return sanitizeEventPayload(item);\n }\n const { headers, headersEncrypted, ...rest } = item;\n const cleaned = sanitizeEventPayload(rest) as Record<string, unknown>;\n const headerNames = safeHeaderNames(headers) ?? safeHeaderNames(headersEncrypted);\n if (headerNames) {\n cleaned.headerNames = headerNames;\n }\n return cleaned;\n });\n}\n\nfunction sanitizeMcpCredentialUpdateList(value: unknown): unknown {\n if (!Array.isArray(value)) {\n return sanitizeEventPayload(value);\n }\n return value.map((item) => {\n if (!isPlainObject(item)) {\n return sanitizeEventPayload(item);\n }\n const { headers, headersEncrypted, ...rest } = item;\n const cleaned = sanitizeEventPayload(rest) as Record<string, unknown>;\n const headerNames = safeHeaderNames(headers) ?? safeHeaderNames(headersEncrypted);\n if (headerNames) {\n cleaned.headerNames = headerNames;\n }\n return cleaned;\n });\n}\n\nfunction safeHeaderNames(value: unknown): string[] | null {\n if (!isPlainObject(value)) {\n return null;\n }\n return Object.keys(value).map(sanitizeEventString).sort();\n}\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n return Boolean(value && typeof value === \"object\" && !Array.isArray(value));\n}\n","// Shared, id-addressed, REFRESHING Codex token resolver (P2).\n//\n// Hoisted here from apps/worker/src/activities/codex-auth.ts so BOTH the worker\n// (turn-time bearer for the streamed run) AND the api (the /wham/usage quota-bar\n// reads) drive ONE resolver — no duplicated refresh/CAS/single-flight logic. The\n// worker re-exports buildCodexTokenResolver from this module for back-compat, so\n// the agent-turn.ts call site is unchanged.\n//\n// Why @opengeni/db is the right home: the resolver only orchestrates accessors\n// this package already owns (loadCodexCredentialForRun / recordCodexTokenRefresh /\n// setCodexCredentialStatus / encryptEnvironmentValue) plus pure @opengeni/codex\n// refresh helpers and the @opengeni/config key — keeping the refresh-CAS + RLS\n// invariants co-located with the rows they protect.\n//\n// CROSS-PROCESS SAFETY is preserved unchanged: the single-flight `inflight` map is\n// process-module-scoped, so worker and api each get their own — that is CORRECT\n// (each process coalesces its own concurrent refreshes). The real cross-process\n// guard is the (id, version) CAS inside recordCodexTokenRefresh: if the api\n// refreshes a token while a worker turn refreshes the same account, the loser's\n// CAS writes 0 rows (stale version) and it re-reads the winner's token, so the\n// one-time refresh token is never double-spent. RLS is untouched (every accessor\n// wraps withWorkspaceRls internally).\n\nimport { environmentsEncryptionKeyBytes, type Settings } from \"@opengeni/config\";\nimport {\n accessTokenExpiry,\n CODEX_CLIENT_VERSION,\n CODEX_REFRESH_FALLBACK_MS,\n CODEX_REFRESH_WINDOW_MS,\n CodexReloginRequired,\n type CodexTokenSnapshot,\n type CodexUsagePayload,\n fetchCodexUsage,\n normalizeCodexUsage,\n refreshCodexToken,\n} from \"@opengeni/codex\";\nimport { encryptEnvironmentValue } from \"./environment-crypto\";\nimport {\n loadCodexCredentialForRun,\n recordCodexAccountUsage,\n recordCodexTokenRefresh,\n setCodexCredentialStatus,\n type CodexCredentialForRun,\n type Database,\n} from \"./index\";\n\n// Single-flight per CREDENTIAL INSTANCE (row id + version), process-module scope.\n// Keying by the loaded credential's id+version — NOT by workspaceId alone (P1-b) —\n// is what makes a disconnect→reconnect safe: a post-reconnect getToken loads a\n// DIFFERENT row (new uuid id) and so gets a distinct key, instead of coalescing\n// onto the OLD in-flight refresh and writing stale rotated tokens over the freshly\n// connected credential. Concurrent calls for the SAME credential still coalesce,\n// so the one-time refresh token is never double-spent.\nconst inflight = new Map<string, Promise<CodexTokenSnapshot>>();\n\n// Dependencies are injectable so the lifecycle logic (single-flight, staleness,\n// needs_relogin transition) is unit-testable without a database. Production uses\n// the real db + codex functions via the default bag.\nexport type CodexAuthDeps = {\n loadCredential: typeof loadCodexCredentialForRun;\n recordRefresh: typeof recordCodexTokenRefresh;\n setStatus: typeof setCodexCredentialStatus;\n refresh: typeof refreshCodexToken;\n encrypt: typeof encryptEnvironmentValue;\n keyBytes: typeof environmentsEncryptionKeyBytes;\n};\n\nconst defaultDeps: CodexAuthDeps = {\n loadCredential: loadCodexCredentialForRun,\n recordRefresh: recordCodexTokenRefresh,\n setStatus: setCodexCredentialStatus,\n refresh: refreshCodexToken,\n encrypt: encryptEnvironmentValue,\n keyBytes: environmentsEncryptionKeyBytes,\n};\n\nexport function buildCodexTokenResolver(\n db: Database,\n settings: Settings,\n workspaceId: string,\n // The RESOLVED effective credential id (pin > workspace active), threaded from\n // the worker. A mid-turn switch loads a DIFFERENT row id, gets a distinct\n // single-flight key, and the (id, version) CAS in recordCodexTokenRefresh writes\n // 0 rows against the now-inactive row — so a refresh racing a switch can never\n // clobber the newly-active account. The single-flight map needs zero change.\n credentialId: string,\n deps: CodexAuthDeps = defaultDeps,\n): { getToken: () => Promise<CodexTokenSnapshot>; refresh: () => Promise<CodexTokenSnapshot> } {\n const snapshot = (cred: CodexCredentialForRun): CodexTokenSnapshot => ({\n accessToken: cred.tokens.accessToken,\n chatgptAccountId: cred.chatgptAccountId,\n isFedramp: cred.isFedramp,\n });\n\n const performRefresh = async (cred: CodexCredentialForRun): Promise<CodexTokenSnapshot> => {\n try {\n const next = await deps.refresh(cred.tokens.refreshToken);\n const tokens = {\n access_token: next.accessToken ?? cred.tokens.accessToken,\n refresh_token: next.refreshToken ?? cred.tokens.refreshToken,\n id_token: next.idToken ?? cred.tokens.idToken,\n };\n const key = deps.keyBytes(settings);\n if (!key) {\n throw new Error(\"OPENGENI_ENVIRONMENTS_ENCRYPTION_KEY is not configured\");\n }\n // Compare-and-set on the loaded (id, version): if a disconnect→reconnect\n // replaced the row mid-refresh, this writes 0 rows and we must NOT clobber\n // the new credential with our now-defunct rotated tokens.\n const persisted = await deps.recordRefresh(db, {\n id: cred.id,\n version: cred.version,\n workspaceId,\n credentialEncrypted: deps.encrypt(key, JSON.stringify(tokens)),\n expiresAt: accessTokenExpiry(tokens.access_token),\n lastRefreshAt: new Date(),\n });\n if (!persisted) {\n // The row changed under us. Our rotated tokens belong to a stale family;\n // fall back to whatever is connected NOW (a reconnect leaves an active\n // row). If nothing active remains, a relogin is genuinely required.\n const current = await deps.loadCredential(db, settings, workspaceId, credentialId);\n if (current && current.status === \"active\") {\n return snapshot(current);\n }\n throw new CodexReloginRequired(\"Codex credential changed during token refresh; reconnect required.\");\n }\n return { accessToken: tokens.access_token, chatgptAccountId: cred.chatgptAccountId, isFedramp: cred.isFedramp };\n } catch (error) {\n if (error instanceof CodexReloginRequired) {\n // Stamp needs_relogin ONLY if the row we refreshed is STILL current\n // (compare-and-set on the loaded id+version). A relogin triggered by the\n // OLD token family must never stamp needs_relogin onto a freshly\n // reconnected credential.\n await deps.setStatus(db, workspaceId, \"needs_relogin\", error.message, { id: cred.id, version: cred.version });\n }\n throw error;\n }\n };\n\n // ALL refreshes — whether triggered by proactive staleness (getToken) or by a\n // 401 retry (refresh) — coalesce onto one in-flight promise per credential\n // instance, so concurrent calls can never double-spend the one-time refresh\n // token (which would trigger refresh_token_reused -> needs_relogin).\n const doRefresh = (cred: CodexCredentialForRun): Promise<CodexTokenSnapshot> => {\n const key = `${cred.id}:${cred.version}`;\n const existing = inflight.get(key);\n if (existing) {\n return existing;\n }\n const promise = performRefresh(cred).finally(() => {\n if (inflight.get(key) === promise) {\n inflight.delete(key);\n }\n });\n inflight.set(key, promise);\n return promise;\n };\n\n const resolve = async (force: boolean): Promise<CodexTokenSnapshot> => {\n const cred = await deps.loadCredential(db, settings, workspaceId, credentialId);\n if (!cred) {\n throw new CodexReloginRequired(\"No Codex subscription is connected for this workspace.\");\n }\n const exp = cred.expiresAt ?? accessTokenExpiry(cred.tokens.accessToken);\n const stale =\n force ||\n (exp\n ? exp.getTime() <= Date.now() + CODEX_REFRESH_WINDOW_MS\n : cred.lastRefreshAt\n ? cred.lastRefreshAt.getTime() < Date.now() - CODEX_REFRESH_FALLBACK_MS\n : true);\n return stale ? doRefresh(cred) : snapshot(cred);\n };\n\n return { getToken: () => resolve(false), refresh: () => resolve(true) };\n}\n\nfunction errorUsagePayload(reason?: \"needs_relogin\"): CodexUsagePayload {\n return {\n status: \"error\",\n planType: null,\n fiveHour: null,\n weekly: null,\n limitReached: false,\n fetchedAt: new Date().toISOString(),\n ...(reason ? { reason } : {}),\n };\n}\n\n/**\n * THE single per-account usage path both the api route and an (optional) worker\n * poll call, so the refresh discipline and the cache-write can never drift.\n *\n * 1. resolve a REFRESHING bearer for THIS account (proactive staleness refresh,\n * single-flight, (id,version) CAS-persist) — this is what stops an idle\n * account's expired JWT from 401-ing the usage read.\n * 2. fetch GET /wham/usage with that bearer.\n * 3. normalize (§3) into the P2/P3 contract.\n * 4. on any windows present, write the five usage-cache columns (the TTL clock).\n *\n * A refresh that stamps needs_relogin returns { status:\"error\", reason } and never\n * hits the provider; a transient refresh error returns a plain error payload.\n */\nexport async function fetchCodexUsageForAccount(\n db: Database,\n settings: Settings,\n workspaceId: string,\n credentialId: string,\n): Promise<CodexUsagePayload> {\n const resolver = buildCodexTokenResolver(db, settings, workspaceId, credentialId);\n let token: CodexTokenSnapshot;\n try {\n token = await resolver.getToken();\n } catch (error) {\n return errorUsagePayload(error instanceof CodexReloginRequired ? \"needs_relogin\" : undefined);\n }\n\n let normalized: CodexUsagePayload;\n try {\n const usage = await fetchCodexUsage({\n accessToken: token.accessToken,\n chatgptAccountId: token.chatgptAccountId,\n isFedramp: token.isFedramp,\n clientVersion: CODEX_CLIENT_VERSION,\n });\n normalized = normalizeCodexUsage(usage.status, usage.payload);\n } catch {\n // A network throw on the /wham/usage read must surface as an error PAYLOAD\n // ({status:\"error\"} at 200), never an unhandled 500 from the route.\n return errorUsagePayload();\n }\n\n if (normalized.fiveHour || normalized.weekly) {\n // Cache-write is best-effort: a disconnect under us (false) or a transient\n // write error must NOT sink the freshly-read usage we are about to return.\n await recordCodexAccountUsage(db, workspaceId, credentialId, {\n primaryUsedPercent: normalized.fiveHour?.percent ?? null,\n primaryResetAt: normalized.fiveHour?.resetAt ? new Date(normalized.fiveHour.resetAt) : null,\n secondaryUsedPercent: normalized.weekly?.percent ?? null,\n secondaryResetAt: normalized.weekly?.resetAt ? new Date(normalized.weekly.resetAt) : null,\n checkedAt: new Date(),\n }).catch(() => undefined);\n }\n\n return normalized;\n}\n"],"mappings":"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","names":["environmentsEncryptionKeyBytes","isCodexBilledModel","sql","row","environmentsEncryptionKeyBytes","updated"]}