1import { scopeThreadRef } from "@t3tools/client-runtime/environment";
2import type { EnvironmentShellStatus } from "@t3tools/client-runtime/state/shell";
3import type { EnvironmentId, ScopedThreadRef, ThreadId } from "@t3tools/contracts";
4import type { DraftId } from "./composerDraftStore";
5
6export type ThreadRouteTarget =
7 | {
8 kind: "server";
9 threadRef: ScopedThreadRef;
10 }
11 | {
12 kind: "draft";
13 draftId: DraftId;
14 };
15
16type DraftThreadRouteState = {
17 environmentId: EnvironmentId;
18 threadId: ThreadId;
19 promotedTo?: ScopedThreadRef | null;
20};
21
22export type ThreadRouteRenderState = "loading" | "ready" | "missing";
23
24export function isThreadRouteSnapshotAuthoritative(
25 status: EnvironmentShellStatus | undefined,
26): boolean {
27 return status === "live";
28}
29
30export function resolveThreadRouteRenderState(input: {
31 bootstrapComplete: boolean;
32 serverThreadExists: boolean;
33 serverThreadDeleted: boolean;
34 draftThreadExists: boolean;
35}): ThreadRouteRenderState {
36 if (input.draftThreadExists || (input.serverThreadExists && !input.serverThreadDeleted)) {
37 return "ready";
38 }
39 if (!input.bootstrapComplete) {
40 return "loading";
41 }
42 return "missing";
43}
44
45export function buildThreadRouteParams(ref: ScopedThreadRef): {
46 environmentId: EnvironmentId;
47 threadId: ThreadId;
48} {
49 return {
50 environmentId: ref.environmentId,
51 threadId: ref.threadId,
52 };
53}
54
55export function buildDraftThreadRouteParams(draftId: DraftId): {
56 draftId: DraftId;
57} {
58 return { draftId };
59}
60
61export function resolveThreadRouteRef(
62 params: Partial<Record<"environmentId" | "threadId", string | undefined>>,
63): ScopedThreadRef | null {
64 if (!params.environmentId || !params.threadId) {
65 return null;
66 }
67
68 return scopeThreadRef(params.environmentId as EnvironmentId, params.threadId as ThreadId);
69}
70
71export function resolveThreadRouteTarget(
72 params: Partial<Record<"environmentId" | "threadId" | "draftId", string | undefined>>,
73): ThreadRouteTarget | null {
74 if (params.environmentId && params.threadId) {
75 return {
76 kind: "server",
77 threadRef: scopeThreadRef(params.environmentId as EnvironmentId, params.threadId as ThreadId),
78 };
79 }
80
81 if (!params.draftId) {
82 return null;
83 }
84
85 return {
86 kind: "draft",
87 draftId: params.draftId as DraftId,
88 };
89}
90
91/**
92 * Resolves the thread represented by either a canonical thread route or a
93 * draft route whose promotion to a server thread has been recorded.
94 */
95export function resolveActiveThreadRouteRef(
96 target: ThreadRouteTarget | null,
97 draftThread: DraftThreadRouteState | null,
98): ScopedThreadRef | null {
99 if (target?.kind === "server") {
100 return target.threadRef;
101 }
102 if (target?.kind !== "draft" || !draftThread?.promotedTo) {
103 return null;
104 }
105 return draftThread.promotedTo;
106}