| 1 | import type { State } from "./useController"; |
| 2 | import type { RemoteSessionApi } from "./useRemoteSession"; |
| 3 | |
| 4 | export type SessionAvailability = { |
| 5 | kind: "ready" | "loading" | "error" | "pending"; |
| 6 | source: "history" | "connection" | "runtime"; |
| 7 | detail?: string; |
| 8 | }; |
| 9 | |
| 10 | type LocalSession = Pick<State, "meta" | "backendActivationPending" | "hydrating" | "hydrateError">; |
| 11 | type RemoteSession = Pick<RemoteSessionApi, "state" | "hydrated" | "error">; |
| 12 | |
| 13 | /** Navigation, welcome and recovery must agree on the active source's readiness. */ |
| 14 | export function projectSessionAvailability(input: { local?: LocalSession; remote?: RemoteSession }): SessionAvailability { |
| 15 | const { local, remote } = input; |
| 16 | if (remote) { |
| 17 | if (["error", "serve_down", "disconnected"].includes(remote.state)) { |
| 18 | return { kind: "error", source: "connection", detail: remote.error }; |
| 19 | } |
| 20 | if (!remote.hydrated && remote.error) return { kind: "error", source: "history", detail: remote.error }; |
| 21 | if (remote.state !== "ready") return { kind: "loading", source: "connection" }; |
| 22 | return { kind: remote.hydrated ? "ready" : "loading", source: "history" }; |
| 23 | } |
| 24 | if (local?.meta?.historicalSource) return { kind: "pending", source: "runtime" }; |
| 25 | if (local?.hydrateError) return { kind: "error", source: "history", detail: local.hydrateError }; |
| 26 | if (local?.meta?.startupErr) return { kind: "error", source: "runtime", detail: local.meta.startupErr }; |
| 27 | if (local?.hydrating) return { kind: "loading", source: "history" }; |
| 28 | const ready = local?.meta?.ready === true && !local.backendActivationPending |
| 29 | && (!local.meta.runtime || local.meta.runtime.phase === "ready"); |
| 30 | return { kind: ready ? "ready" : "loading", source: "runtime" }; |
| 31 | } |
| 32 |