| 1 | import { scopeThreadRef } from "@t3tools/client-runtime/environment"; |
| 2 | import type { EnvironmentShellStatus } from "@t3tools/client-runtime/state/shell"; |
| 3 | import type { EnvironmentId, ScopedThreadRef, ThreadId } from "@t3tools/contracts"; |
| 4 | import type { DraftId } from "./composerDraftStore"; |
| 5 | |
| 6 | export type ThreadRouteTarget = |
| 7 | | { |
| 8 | kind: "server"; |
| 9 | threadRef: ScopedThreadRef; |
| 10 | } |
| 11 | | { |
| 12 | kind: "draft"; |
| 13 | draftId: DraftId; |
| 14 | }; |
| 15 | |
| 16 | type DraftThreadRouteState = { |
| 17 | environmentId: EnvironmentId; |
| 18 | threadId: ThreadId; |
| 19 | promotedTo?: ScopedThreadRef | null; |
| 20 | }; |
| 21 | |
| 22 | export type ThreadRouteRenderState = "loading" | "ready" | "missing"; |
| 23 | |
| 24 | export function isThreadRouteSnapshotAuthoritative( |
| 25 | status: EnvironmentShellStatus | undefined, |
| 26 | ): boolean { |
| 27 | return status === "live"; |
| 28 | } |
| 29 | |
| 30 | export 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 | |
| 45 | export function buildThreadRouteParams(ref: ScopedThreadRef): { |
| 46 | environmentId: EnvironmentId; |
| 47 | threadId: ThreadId; |
| 48 | } { |
| 49 | return { |
| 50 | environmentId: ref.environmentId, |
| 51 | threadId: ref.threadId, |
| 52 | }; |
| 53 | } |
| 54 | |
| 55 | export function buildDraftThreadRouteParams(draftId: DraftId): { |
| 56 | draftId: DraftId; |
| 57 | } { |
| 58 | return { draftId }; |
| 59 | } |
| 60 | |
| 61 | export 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 | |
| 71 | export 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 | */ |
| 95 | export 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 | } |