import { EnvironmentId, type OrchestrationThread, type OrchestrationShellSnapshot, ThreadId, } from "@t3tools/contracts"; import * as Context from "effect/Context"; import * as Effect from "effect/Effect"; import * as Option from "effect/Option"; import * as Schema from "effect/Schema"; import type { ConnectionRegistration } from "../connection/catalog.ts"; import { type ConnectionStorageOperation, ConnectionStorageOperationError, type ConnectionTarget, type ConnectionTransientError, } from "../connection/model.ts"; const isConnectionStorageOperationError = Schema.is(ConnectionStorageOperationError); export class ConnectionPersistenceError extends Schema.TaggedErrorClass()( "ConnectionPersistenceError", { operation: Schema.Literals([ "list-targets", "register-connection", "remove-connection", "load-shell", "save-shell", "load-thread", "save-thread", "remove-thread", "clear-environment", ]), stage: Schema.Literals([ "resolve", "read", "parse", "decode", "encode", "migrate", "write", "remove", ]), resource: Schema.Literals([ "connection-catalog", "shell-cache", "legacy-shell-cache", "thread-cache", ]), environmentId: Schema.optionalKey(EnvironmentId), threadId: Schema.optionalKey(ThreadId), cause: Schema.Defect(), }, ) { static fromStorageFailure(input: { readonly operation: ConnectionPersistenceError["operation"]; readonly fallbackStage: ConnectionPersistenceError["stage"]; readonly resource: ConnectionPersistenceError["resource"]; readonly environmentId?: EnvironmentId; readonly threadId?: ThreadId; readonly cause: ConnectionTransientError; }) { const { cause, fallbackStage, ...attributes } = input; const storageCause = cause.cause; const stage = isConnectionStorageOperationError(storageCause) ? ConnectionPersistenceError.storageOperationStage(storageCause.operation) : fallbackStage; return new ConnectionPersistenceError({ ...attributes, stage, cause, }); } private static storageOperationStage( operation: ConnectionStorageOperation, ): ConnectionPersistenceError["stage"] { switch (operation) { case "open": return "resolve"; case "read": case "load": return "read"; case "decode": return "decode"; case "encode": return "encode"; case "migrate": return "migrate"; case "write": case "save": return "write"; case "delete": case "remove": return "remove"; } } override get message(): string { const environment = this.environmentId === undefined ? "" : ` for environment ${this.environmentId}`; const thread = this.threadId === undefined ? "" : ` and thread ${this.threadId}`; return `Could not ${this.operation.replaceAll("-", " ")}: ${this.resource.replaceAll("-", " ")} ${this.stage} failed${environment}${thread}.`; } } export class ConnectionTargetStore extends Context.Service< ConnectionTargetStore, { readonly list: Effect.Effect, ConnectionPersistenceError>; } >()("@t3tools/client-runtime/platform/persistence/ConnectionTargetStore") {} export class ConnectionRegistrationStore extends Context.Service< ConnectionRegistrationStore, { readonly register: ( registration: ConnectionRegistration, ) => Effect.Effect; readonly remove: (target: ConnectionTarget) => Effect.Effect; } >()("@t3tools/client-runtime/platform/persistence/ConnectionRegistrationStore") {} export class EnvironmentCacheStore extends Context.Service< EnvironmentCacheStore, { readonly loadShell: ( environmentId: EnvironmentId, ) => Effect.Effect, ConnectionPersistenceError>; readonly saveShell: ( environmentId: EnvironmentId, snapshot: OrchestrationShellSnapshot, ) => Effect.Effect; readonly loadThread: ( environmentId: EnvironmentId, threadId: ThreadId, ) => Effect.Effect, ConnectionPersistenceError>; readonly saveThread: ( environmentId: EnvironmentId, thread: OrchestrationThread, ) => Effect.Effect; readonly removeThread: ( environmentId: EnvironmentId, threadId: ThreadId, ) => Effect.Effect; readonly clear: ( environmentId: EnvironmentId, ) => Effect.Effect; } >()("@t3tools/client-runtime/platform/persistence/EnvironmentCacheStore") {} export class EnvironmentOwnedDataCleanup extends Context.Reference<{ readonly clear: (environmentId: EnvironmentId) => Effect.Effect; }>("@t3tools/client-runtime/platform/persistence/EnvironmentOwnedDataCleanup", { defaultValue: () => ({ clear: () => Effect.void, }), }) {}