| 1 | import { type ConnectionCatalogEntry, hasRelayRoute } from "@t3tools/client-runtime/connection"; |
| 2 | import type { EnvironmentId } from "@t3tools/contracts"; |
| 3 | |
| 4 | interface OnboardingEnvironment { |
| 5 | readonly environmentId: EnvironmentId; |
| 6 | readonly connection: { readonly phase: string }; |
| 7 | readonly entry: Pick<ConnectionCatalogEntry, "target" | "alternateRoutes">; |
| 8 | } |
| 9 | |
| 10 | export function isOnboardingRelayEnvironment( |
| 11 | environment: Pick<OnboardingEnvironment, "entry">, |
| 12 | ): boolean { |
| 13 | return hasRelayRoute(environment.entry); |
| 14 | } |
| 15 | |
| 16 | /** Keep a directly paired machine pinned while its initial connection completes. */ |
| 17 | export function resolveOnboardingTargetEnvironment<TEnvironment extends OnboardingEnvironment>({ |
| 18 | mode, |
| 19 | environments, |
| 20 | primaryEnvironment, |
| 21 | pairedEnvironmentId, |
| 22 | }: { |
| 23 | readonly mode: "local" | "connect" | "direct"; |
| 24 | readonly environments: ReadonlyArray<TEnvironment>; |
| 25 | readonly primaryEnvironment: TEnvironment | null; |
| 26 | readonly pairedEnvironmentId: EnvironmentId | null; |
| 27 | }): TEnvironment | null { |
| 28 | if (mode === "direct" && pairedEnvironmentId !== null) { |
| 29 | const pairedEnvironment = environments.find( |
| 30 | (environment) => environment.environmentId === pairedEnvironmentId, |
| 31 | ); |
| 32 | return pairedEnvironment?.connection.phase === "connected" ? pairedEnvironment : null; |
| 33 | } |
| 34 | |
| 35 | const connectedRelayEnvironments = environments.filter( |
| 36 | (environment) => |
| 37 | environment.connection.phase === "connected" && isOnboardingRelayEnvironment(environment), |
| 38 | ); |
| 39 | |
| 40 | if (mode === "connect" && connectedRelayEnvironments.length > 0) { |
| 41 | return connectedRelayEnvironments[connectedRelayEnvironments.length - 1] ?? null; |
| 42 | } |
| 43 | |
| 44 | if (primaryEnvironment?.connection.phase === "connected") { |
| 45 | return primaryEnvironment; |
| 46 | } |
| 47 | |
| 48 | return mode === "local" ? null : (connectedRelayEnvironments[0] ?? null); |
| 49 | } |
| 50 | |
| 51 | /** |
| 52 | * The computers the wizard sets up from the user's selection. Continue waits |
| 53 | * only on a first connection attempt, which settles on its own. Selected |
| 54 | * computers that are switched off, offline, failing, or unsupported are skipped |
| 55 | * so they can never lock the user out of onboarding. |
| 56 | */ |
| 57 | export function resolveOnboardingSetup( |
| 58 | environments: ReadonlyArray<Pick<OnboardingEnvironment, "environmentId" | "connection">>, |
| 59 | selectedIds: ReadonlySet<EnvironmentId>, |
| 60 | ): { |
| 61 | readonly ready: boolean; |
| 62 | readonly environmentIds: ReadonlyArray<EnvironmentId>; |
| 63 | readonly skippedIds: ReadonlyArray<EnvironmentId>; |
| 64 | } { |
| 65 | const selected = environments.filter((environment) => selectedIds.has(environment.environmentId)); |
| 66 | const idsInPhase = (keep: (phase: string) => boolean) => |
| 67 | selected |
| 68 | .filter((environment) => keep(environment.connection.phase)) |
| 69 | .map((environment) => environment.environmentId); |
| 70 | const environmentIds = idsInPhase((phase) => phase === "connected"); |
| 71 | const settling = selected.some((environment) => environment.connection.phase === "connecting"); |
| 72 | return { |
| 73 | ready: environmentIds.length > 0 && !settling, |
| 74 | environmentIds, |
| 75 | skippedIds: idsInPhase((phase) => phase !== "connected" && phase !== "connecting"), |
| 76 | }; |
| 77 | } |