import { type Settings } from "@opengeni/config"; import type { Session } from "@opengeni/contracts"; import { type Database, type LeaseSnapshot } from "@opengeni/db"; import { type EventBus } from "@opengeni/events"; import { type Observability } from "@opengeni/observability"; import type { ObjectStorage } from "@opengeni/storage"; import { SandboxChannelAService, type ChannelASession, type EstablishedSandboxSession, type RoutingSandboxSession } from "@opengeni/runtime/sandbox"; export type ChannelAServices = { db: Database; settings: Settings; bus: EventBus; objectStorage?: ObjectStorage | null; observability?: Observability | undefined; }; export type ChannelAOperation = "fs.list" | "fs.list-batch" | "fs.read" | "artifact.publish" | "fs.write" | "fs.delete" | "fs.move" | "fs.mkdir" | "git.status" | "git.diff" | "git.read-batch" | "git.log" | "git.show" | "terminal.exec" | "terminal.pty.open" | "terminal.pty.write" | "terminal.pty.resize" | "terminal.pty.close" | "browser.create" | "browser.resume" | "browser.suspend" | "browser.end" | "browser.read" | "browser.action" | "browser.control" | "browser.download.save" | "browser.attach" | "computer.create" | "computer.end" | "computer.read" | "computer.action" | "computer.control" | "computer.attach"; export type ChannelAContext = { accountId: string; workspaceId: string; session: Session; subjectId: string; /** Cancel lifecycle waiting when the originating HTTP request disconnects. */ waitSignal?: AbortSignal | undefined; /** Bounded route identity for metrics and safe operator diagnostics. */ operation?: ChannelAOperation | undefined; /** The callback is an interaction-controller read or an exactly-once action. * A controller transport failure may therefore rebuild the exact fenced * provider handle and replay the request. Tab/lifecycle mutations that lack * a controller operation id must never opt into this recovery. */ retryControllerTransport?: boolean | undefined; }; export type ChannelAOperationFailureReason = "request_cancelled" | "provider_read_busy" | "provider_unavailable" | "lifecycle_conflict" | "request_rejected" | "unexpected"; export type ChannelAOperationFailureDiagnostic = { reason: ChannelAOperationFailureReason; status: number; errorCode: "sandbox_channel_a_cancelled" | "sandbox_channel_a_provider_busy" | "sandbox_channel_a_provider_unavailable" | "sandbox_channel_a_lifecycle_conflict" | "sandbox_channel_a_operation_failed"; }; export type ChannelAHandle = { service: SandboxChannelAService; /** Connected Machine homes deliberately have no cloud lease. Durable PTYs * require a real home-provider lease and reject this null case. */ lease: LeaseSnapshot | null; /** Exact placement-home session established under this request's lease or * Connected Machine fence. Unlike routingSession, this never follows a later * active-sandbox pointer and is safe for placement-bound controllers. */ homeSession: ChannelASession; routingSession: RoutingSandboxSession; requestId: string; }; export type EstablishedHandleCacheKind = "read" | "process" | "none"; export declare function isChannelAHandleCacheEntryFresh(lastUsedAtMonotonicMs: number, nowMonotonicMs: number, idleTtlMs?: number): boolean; export declare function isChannelAProcessHandleCacheEntryFresh(lastUsedAtMonotonicMs: number, nowMonotonicMs: number, idleTtlMs?: number): boolean; /** Reuse the exact lease-fenced provider handle across API-direct surfaces. * Stream capability negotiation and the first Files/Changes reads commonly run * back-to-back; sharing this handle avoids paying the same Modal resume twice. */ export declare function establishCachedChannelAHandle(workspaceId: string, sessionId: string, lease: LeaseSnapshot, establish: () => Promise): Promise; /** * Run independent, side-effect-free Channel-A reads concurrently without * releasing the direct-request holder while sibling provider commands are * still settling. A typed temporary-unavailable failure is retried exactly * once after every first attempt has settled; validation, conflict, not-found, * and unknown failures are never replayed. */ export declare function runConcurrentChannelAReads(operations: readonly (() => Promise)[]): Promise; type ChannelAReadRecoveryOptions = { /** Modal may expose one more stale command-router route after the first * successful handle rebuild. Keep this closed and statically bounded. */ maxFreshHandleRetries?: 1 | 2; /** Never start another provider attempt after the originating request ends. */ waitSignal?: AbortSignal | undefined; /** Additional callback-specific failure that is safe to replay. */ retryableError?: ((error: unknown) => boolean) | undefined; }; /** Retry a side-effect-free Channel-A read only after the caller has discarded * and freshly re-established its provider handle. The ordinary provider-neutral * contract allows one retry; Modal opts into one additional rebuild because a * command-router rollover can outlive the first replacement handle. Provider * commands are never replayed for validation/conflict/unknown errors, mutation * routes never call this helper, and request cancellation stops recovery before * another provider command begins. */ export declare function runChannelAReadWithFreshHandleRetry(run: () => Promise, refreshHandle: (attempt: 1 | 2) => Promise, options?: ChannelAReadRecoveryOptions): Promise; export declare function shouldEvictChannelAHandleAfterError(error: unknown, cacheKind: EstablishedHandleCacheKind): boolean; /** * Run a Channel-A op against a live box, API-direct. Acquires an exact direct holder * (warming the box when cold), resumes by id, builds the service, runs `fn`, and * ALWAYS releases the holder + drops the handle in `finally`. Maps the service's * typed errors to HTTP status (the route never sees a raw ChannelA*Error). * * Gated behind sandboxOwnershipEnabled at the route (the lease is dormant * otherwise). A `backend:none` session has no box -> 409 before touching it. */ export declare function withChannelA(services: ChannelAServices, ctx: ChannelAContext, fn: (handle: ChannelAHandle) => Promise): Promise; /** Read-only API-direct seam. Separate requests for the same exact live Modal * instance are serialized across API replicas; each request's batched reads * remain concurrent behind that one distributed boundary. A typed temporary * provider-channel failure gets one retry only after rebuilding the exact * lease-fenced handle. */ export declare function withChannelARead(services: ChannelAServices, ctx: ChannelAContext, fn: (handle: ChannelAHandle) => Promise): Promise; /** Map the service's typed errors to HTTP status (the ยง5.3 matrix). Re-throws an * already-HTTPException unchanged. */ export declare function mapChannelAError(error: unknown, waitSignal?: AbortSignal): unknown; export declare function isChannelARequestCancellation(error: unknown, waitSignal?: AbortSignal): boolean; /** Structural classification only: exact provider exception text, codes, URLs, * and identifiers never cross the telemetry boundary. */ export declare function channelAOperationFailureDiagnostic(error: unknown, waitSignal?: AbortSignal): ChannelAOperationFailureDiagnostic; /** Exported for the telemetry contract tests; not a route surface. */ export declare function observeChannelAOperationFailure(services: ChannelAServices, input: { workspaceId: string; sandboxGroupId: string; backend: string; operation: string; durationMs: number; error: unknown; waitSignal?: AbortSignal | undefined; }): void; export {};