1import type { EnvironmentConnectionPhase } from "@t3tools/client-runtime/connection";
2import type { AssetUrlState as SharedAssetUrlState } from "@t3tools/client-runtime/state/assets";
3
4export type AssetUrlFailureReason = "disconnected" | "failed" | "missing-file-access";
5
6/** The shared state plus a reason on failure, so previews can offer the right retry. */
7export type AssetUrlState =
8 | { readonly _tag: "Loading" }
9 | { readonly _tag: "Failure"; readonly reason: AssetUrlFailureReason }
10 | Extract<SharedAssetUrlState, { readonly _tag: "Success" }>;
11
12/**
13 * Folds the shared asset URL state with the environment connection phase. A
14 * dead environment wins over everything else: even a resolved URL is
15 * unreachable there, and a failed query is caused by the outage, not the file.
16 */
17export function deriveAssetUrlState(input: {
18 readonly connectionPhase: EnvironmentConnectionPhase;
19 readonly shared: SharedAssetUrlState;
20}): AssetUrlState {
21 if (
22 input.connectionPhase === "offline" ||
23 input.connectionPhase === "reconnecting" ||
24 input.connectionPhase === "error" ||
25 input.connectionPhase === "unsupported"
26 ) {
27 return { _tag: "Failure", reason: "disconnected" };
28 }
29 if (input.shared._tag === "Success") {
30 return input.shared;
31 }
32 switch (input.connectionPhase) {
33 // "available" is the idle, not yet dialled state. A pending query there is
34 // still on its way, but the query atom fails at once while idle, so a
35 // failure means the environment is not connected rather than the file is
36 // missing.
37 case "available":
38 return input.shared._tag === "Failure"
39 ? { _tag: "Failure", reason: "disconnected" }
40 : { _tag: "Loading" };
41 case "connecting":
42 return { _tag: "Loading" };
43 case "connected":
44 return input.shared._tag === "Failure"
45 ? { _tag: "Failure", reason: input.shared.reason ?? "failed" }
46 : { _tag: "Loading" };
47 }
48}