import { EnvironmentId } from "@t3tools/contracts";import * as Schema from "effect/Schema"; const ConnectionTargetBase = { environmentId: EnvironmentId, label: Schema.String,}; export class PrimaryConnectionTarget extends Schema.TaggedClass<PrimaryConnectionTarget>()( "PrimaryConnectionTarget", { ...ConnectionTargetBase, httpBaseUrl: Schema.String, wsBaseUrl: Schema.String, },) {} export class BearerConnectionTarget extends Schema.TaggedClass<BearerConnectionTarget>()( "BearerConnectionTarget", { ...ConnectionTargetBase, connectionId: Schema.String, },) {} export class RelayConnectionTarget extends Schema.TaggedClass<RelayConnectionTarget>()( "RelayConnectionTarget", { ...ConnectionTargetBase, },) {} export class SshConnectionTarget extends Schema.TaggedClass<SshConnectionTarget>()( "SshConnectionTarget", { ...ConnectionTargetBase, connectionId: Schema.String, },) {} export const ConnectionTarget = Schema.Union([ PrimaryConnectionTarget, BearerConnectionTarget, RelayConnectionTarget, SshConnectionTarget,]);export type ConnectionTarget = typeof ConnectionTarget.Type; export const PersistedConnectionTarget = Schema.Union([ BearerConnectionTarget, RelayConnectionTarget, SshConnectionTarget,]);export type PersistedConnectionTarget = typeof PersistedConnectionTarget.Type; export type ConnectionTargetKind = ConnectionTarget["_tag"]; export type NetworkStatus = "unknown" | "offline" | "online"; export const ConnectionTransientReason = Schema.Literals([ "network", "timeout", "transport", "endpoint-unavailable", "relay-unavailable", "remote-unavailable",]);export type ConnectionTransientReason = typeof ConnectionTransientReason.Type; export const ConnectionBlockedReason = Schema.Literals([ "authentication", "configuration", "permission", "unsupported",]);export type ConnectionBlockedReason = typeof ConnectionBlockedReason.Type; export class ConnectionTransientError extends Schema.TaggedErrorClass<ConnectionTransientError>()( "ConnectionTransientError", { reason: ConnectionTransientReason, detail: Schema.String, traceId: Schema.optionalKey(Schema.String), },) { override get message(): string { return this.detail; }} export class ConnectionBlockedError extends Schema.TaggedErrorClass<ConnectionBlockedError>()( "ConnectionBlockedError", { reason: ConnectionBlockedReason, detail: Schema.String, traceId: Schema.optionalKey(Schema.String), },) { override get message(): string { return this.detail; }} export type ConnectionAttemptError = ConnectionTransientError | ConnectionBlockedError; export const DPOP_ACCESS_TOKEN_REFRESH_SKEW_MS = 60_000; export type PreparedHttpAuthorization = | { readonly _tag: "Bearer"; readonly token: string; } | { readonly _tag: "Dpop"; readonly accessToken: string; readonly expiresAtEpochMs: number; }; export interface PreparedConnection { readonly environmentId: EnvironmentId; readonly label: string; readonly httpBaseUrl: string; readonly socketUrl: string; readonly httpAuthorization: PreparedHttpAuthorization | null; readonly target: ConnectionTarget;} export type SupervisorConnectionPhase = | "available" | "offline" | "connecting" | "backoff" | "connected" | "blocked"; export type ConnectionAttemptStage = "preparing" | "opening" | "synchronizing"; export interface SupervisorConnectionState { readonly desired: boolean; readonly network: NetworkStatus; readonly phase: SupervisorConnectionPhase; readonly stage: ConnectionAttemptStage | null; readonly attempt: number; readonly generation: number; readonly lastFailure: ConnectionAttemptError | null; readonly retryAt: number | null;} export type ConnectionProjectionPhase = "disconnected" | "synchronizing" | "ready"; export function connectionProjectionPhase( state: SupervisorConnectionState,): ConnectionProjectionPhase { switch (state.phase) { case "connecting": return "synchronizing"; case "connected": return "ready"; case "available": case "offline": case "backoff": case "blocked": return "disconnected"; }} export const AVAILABLE_CONNECTION_STATE: SupervisorConnectionState = Object.freeze({ desired: false, network: "unknown", phase: "available", stage: null, attempt: 0, generation: 0, lastFailure: null, retryAt: null,});
import { EnvironmentId } from "@t3tools/contracts";
import * as Schema from "effect/Schema";
const ConnectionTargetBase = {
environmentId: EnvironmentId,
label: Schema.String,
};
export class PrimaryConnectionTarget extends Schema.TaggedClass<PrimaryConnectionTarget>()(
"PrimaryConnectionTarget",
{
...ConnectionTargetBase,
httpBaseUrl: Schema.String,
wsBaseUrl: Schema.String,
},
) {}
export class BearerConnectionTarget extends Schema.TaggedClass<BearerConnectionTarget>()(
"BearerConnectionTarget",
{
...ConnectionTargetBase,
connectionId: Schema.String,
},
) {}
export class RelayConnectionTarget extends Schema.TaggedClass<RelayConnectionTarget>()(
"RelayConnectionTarget",
{
...ConnectionTargetBase,
},
) {}
export class SshConnectionTarget extends Schema.TaggedClass<SshConnectionTarget>()(
"SshConnectionTarget",
{
...ConnectionTargetBase,
connectionId: Schema.String,
},
) {}
export const ConnectionTarget = Schema.Union([
PrimaryConnectionTarget,
BearerConnectionTarget,
RelayConnectionTarget,
SshConnectionTarget,
]);
export type ConnectionTarget = typeof ConnectionTarget.Type;
export const PersistedConnectionTarget = Schema.Union([
BearerConnectionTarget,
RelayConnectionTarget,
SshConnectionTarget,
]);
export type PersistedConnectionTarget = typeof PersistedConnectionTarget.Type;
export type ConnectionTargetKind = ConnectionTarget["_tag"];
export type NetworkStatus = "unknown" | "offline" | "online";
export const ConnectionTransientReason = Schema.Literals([
"network",
"timeout",
"transport",
"endpoint-unavailable",
"relay-unavailable",
"remote-unavailable",
]);
export type ConnectionTransientReason = typeof ConnectionTransientReason.Type;
export const ConnectionBlockedReason = Schema.Literals([
"authentication",
"configuration",
"permission",
"unsupported",
]);
export type ConnectionBlockedReason = typeof ConnectionBlockedReason.Type;
export class ConnectionTransientError extends Schema.TaggedErrorClass<ConnectionTransientError>()(
"ConnectionTransientError",
{
reason: ConnectionTransientReason,
detail: Schema.String,
traceId: Schema.optionalKey(Schema.String),
},
) {
override get message(): string {
return this.detail;
}
}
export class ConnectionBlockedError extends Schema.TaggedErrorClass<ConnectionBlockedError>()(
"ConnectionBlockedError",
{
reason: ConnectionBlockedReason,
detail: Schema.String,
traceId: Schema.optionalKey(Schema.String),
},
) {
override get message(): string {
return this.detail;
}
}
export type ConnectionAttemptError = ConnectionTransientError | ConnectionBlockedError;
export const DPOP_ACCESS_TOKEN_REFRESH_SKEW_MS = 60_000;
export type PreparedHttpAuthorization =
| {
readonly _tag: "Bearer";
readonly token: string;
}
| {
readonly _tag: "Dpop";
readonly accessToken: string;
readonly expiresAtEpochMs: number;
};
export interface PreparedConnection {
readonly environmentId: EnvironmentId;
readonly label: string;
readonly httpBaseUrl: string;
readonly socketUrl: string;
readonly httpAuthorization: PreparedHttpAuthorization | null;
readonly target: ConnectionTarget;
}
export type SupervisorConnectionPhase =
| "available"
| "offline"
| "connecting"
| "backoff"
| "connected"
| "blocked";
export type ConnectionAttemptStage = "preparing" | "opening" | "synchronizing";
export interface SupervisorConnectionState {
readonly desired: boolean;
readonly network: NetworkStatus;
readonly phase: SupervisorConnectionPhase;
readonly stage: ConnectionAttemptStage | null;
readonly attempt: number;
readonly generation: number;
readonly lastFailure: ConnectionAttemptError | null;
readonly retryAt: number | null;
}
export type ConnectionProjectionPhase = "disconnected" | "synchronizing" | "ready";
export function connectionProjectionPhase(
state: SupervisorConnectionState,
): ConnectionProjectionPhase {
switch (state.phase) {
case "connecting":
return "synchronizing";
case "connected":
return "ready";
case "available":
case "offline":
case "backoff":
case "blocked":
return "disconnected";
}
}
export const AVAILABLE_CONNECTION_STATE: SupervisorConnectionState = Object.freeze({
desired: false,
network: "unknown",
phase: "available",
stage: null,
attempt: 0,
generation: 0,
lastFailure: null,
retryAt: null,
});