export type KeyedDocumentRoute = { immediately: boolean; key: string; }; declare const documentRouteIdentityBrand: unique symbol; export type DocumentRouteIdentity = string & { readonly [documentRouteIdentityBrand]: true; }; export type DocumentRouteIdentitySource = | { id: string; page: "channel" } | { owner: string; page: "document"; repository: string; slug: string } | { owner: string; page: "research"; repository: string; slug: string; workspaceId: string; }; export function documentRouteIdentity(source: DocumentRouteIdentitySource): DocumentRouteIdentity { switch (source.page) { case "channel": return `channel:${source.id}` as DocumentRouteIdentity; case "document": return `document:${source.owner}/${source.repository}/${source.slug}` as DocumentRouteIdentity; case "research": return ( `research:${source.owner}/${source.repository}/${source.slug}/${source.workspaceId}` ) as DocumentRouteIdentity; } } type ReadyDocumentRoute = T & { resolution?: R }; export type DocumentRouteSwap = { current: ReadyDocumentRoute; pending?: ReadyDocumentRoute; previous?: ReadyDocumentRoute; }; export type DocumentRouteAction = | { route: T; type: "requested" } | { key: string; resolution?: R; type: "ready" } | { key: string; type: "closed" }; export function transitionDocumentRoute( state: DocumentRouteSwap, action: DocumentRouteAction, ): DocumentRouteSwap { if (action.type === "requested") { let requested = action.route; let reverse = ( route: ReadyDocumentRoute, ): ReadyDocumentRoute => ({ ...route, immediately: requested.immediately }); if (requested.key === state.current.key) { return state.pending ? { current: reverse(state.current), previous: state.previous, } : state; } if (requested.key === state.previous?.key) { return { current: reverse(state.previous), previous: state.current, }; } return { ...state, pending: requested }; } if (action.type === "ready") { let ready = (route: ReadyDocumentRoute): ReadyDocumentRoute => action.resolution === undefined ? route : { ...route, resolution: action.resolution }; if (state.pending?.key === action.key) { return { current: ready(state.pending), previous: state.current }; } if (state.current.key === action.key && action.resolution !== undefined) { if (state.current.resolution === action.resolution) return state; return { ...state, current: ready(state.current) }; } if (state.previous?.key === action.key && action.resolution !== undefined) { if (state.previous.resolution === action.resolution) return state; return { ...state, previous: ready(state.previous) }; } return state; } return state.previous?.key === action.key ? { current: state.current, pending: state.pending } : state; }