import type { EnvironmentId } from "@t3tools/contracts"; import type { RelayProtectedError } from "@t3tools/contracts/relay"; import type { ManagedRelayClientError } from "../relay/managedRelay.ts"; import type { RemoteEnvironmentAuthError } from "../authorization/remote.ts"; import { ConnectionBlockedError, type ConnectionAttemptError, ConnectionTransientError, } from "./model.ts"; export function profileMissingError(connectionId: string): ConnectionBlockedError { return new ConnectionBlockedError({ reason: "configuration", detail: `Connection profile ${connectionId} is unavailable.`, }); } export function credentialMissingError(connectionId: string): ConnectionBlockedError { return new ConnectionBlockedError({ reason: "authentication", detail: `Connection credential ${connectionId} is unavailable.`, }); } export function environmentMismatchError(input: { readonly expected: EnvironmentId; readonly actual: EnvironmentId; }): ConnectionBlockedError { return new ConnectionBlockedError({ reason: "configuration", detail: `Connected environment ${input.actual} does not match ${input.expected}.`, }); } function relayProtectedError(error: RelayProtectedError): ConnectionAttemptError { switch (error._tag) { case "RelayAuthInvalidError": case "RelayEnvironmentLinkProofExpiredError": case "RelayAgentActivityPublishProofExpiredError": case "RelayAgentActivityPublishProofInvalidError": return new ConnectionBlockedError({ reason: "authentication", detail: error.message, traceId: error.traceId, }); case "RelayEnvironmentConnectNotAuthorizedError": case "RelayEnvironmentLinkProofInvalidError": return new ConnectionBlockedError({ reason: "permission", detail: error.message, traceId: error.traceId, }); case "RelayEnvironmentEndpointTimedOutError": return new ConnectionTransientError({ reason: "timeout", detail: error.message, traceId: error.traceId, }); case "RelayEnvironmentEndpointUnavailableError": case "RelayEnvironmentLinkUnavailableError": return new ConnectionTransientError({ reason: "endpoint-unavailable", detail: error.message, traceId: error.traceId, }); case "RelayEnvironmentLinkFailedError": case "RelayInternalError": return new ConnectionTransientError({ reason: "relay-unavailable", detail: error.message, traceId: error.traceId, }); } } export function mapManagedRelayError(error: ManagedRelayClientError): ConnectionAttemptError { switch (error._tag) { case "ManagedRelayRequestFailedError": if (error.relayError) { return relayProtectedError(error.relayError); } return new ConnectionTransientError({ reason: "relay-unavailable", detail: error.message, ...(error.traceId ? { traceId: error.traceId } : {}), }); case "ManagedRelayRequestTimeoutError": return new ConnectionTransientError({ reason: "timeout", detail: error.message, }); case "ManagedRelayUrlInvalidError": return new ConnectionBlockedError({ reason: "configuration", detail: error.message, }); case "ManagedRelayAccessTokenScopesUnexpectedError": return new ConnectionBlockedError({ reason: "permission", detail: error.message, }); case "ManagedRelayDpopKeyLoadError": case "ManagedRelayTokenProofCreationError": case "ManagedRelayRequestProofCreationError": return new ConnectionBlockedError({ reason: "authentication", detail: error.message, }); } } export function mapRemoteEnvironmentError( error: RemoteEnvironmentAuthError, ): ConnectionAttemptError { switch (error._tag) { case "EnvironmentAuthInvalidError": return new ConnectionBlockedError({ reason: "authentication", detail: "The environment credential is invalid.", traceId: error.traceId, }); case "EnvironmentScopeRequiredError": case "EnvironmentOperationForbiddenError": return new ConnectionBlockedError({ reason: "permission", detail: "The environment credential does not grant the required access.", traceId: error.traceId, }); case "EnvironmentRequestInvalidError": return new ConnectionBlockedError({ reason: "configuration", detail: "The environment rejected the authentication request.", traceId: error.traceId, }); case "EnvironmentResourceNotFoundError": // Not expected during connection authorization, but the shared request // error type now includes it (used by resource fetches like the thread // snapshot). Treat it as a configuration issue with the endpoint. return new ConnectionBlockedError({ reason: "configuration", detail: "The environment endpoint could not be found.", traceId: error.traceId, }); case "RemoteEnvironmentAuthTimeoutError": return new ConnectionTransientError({ reason: "timeout", detail: error.message, }); case "RemoteEnvironmentAuthFetchError": return new ConnectionTransientError({ reason: "network", detail: error.message, }); case "EnvironmentInternalError": return new ConnectionTransientError({ reason: "remote-unavailable", detail: "The environment could not authorize the connection.", traceId: error.traceId, }); case "RemoteEnvironmentAuthInvalidJsonError": case "RemoteEnvironmentAuthUndeclaredStatusError": return new ConnectionTransientError({ reason: "remote-unavailable", detail: error.message, }); } }