| 1 | // Lazy full-content resolution for snapshot-protocol tabs. A tab wired to the |
| 2 | // unified transcript snapshot registers a resolver here; the transcript store |
| 3 | // then answers content requests from the snapshot client instead of the |
| 4 | // windowed history backend. Tabs without snapshot support fall through to the |
| 5 | // store's HistoryContentForTab path. |
| 6 | |
| 7 | export interface TranscriptContentResolver { |
| 8 | resolve(entryId: string, field: string): Promise<string | undefined>; |
| 9 | enabled(): boolean; |
| 10 | } |
| 11 | |
| 12 | export class TranscriptContentResolverRegistry { |
| 13 | private readonly resolvers = new Map<string, TranscriptContentResolver>(); |
| 14 | |
| 15 | register( |
| 16 | tabId: string, |
| 17 | resolve: (entryId: string, field: string) => Promise<string | undefined>, |
| 18 | enabled: () => boolean = () => true, |
| 19 | ): () => void { |
| 20 | const entry = { resolve, enabled }; |
| 21 | this.resolvers.set(tabId, entry); |
| 22 | return () => { if (this.resolvers.get(tabId) === entry) this.resolvers.delete(tabId); }; |
| 23 | } |
| 24 | |
| 25 | active(tabId: string): TranscriptContentResolver | undefined { |
| 26 | const resolver = this.resolvers.get(tabId); |
| 27 | return resolver?.enabled() ? resolver : undefined; |
| 28 | } |
| 29 | } |
| 30 | |
| 31 | // Snapshot-protocol item ids are `m:<messageId>` while the windowed store keys |
| 32 | // records by backend entryId, so alias them back before lookup. |
| 33 | export function resolveTranscriptEntryAlias( |
| 34 | sessions: Iterable<{ tabId: string; records: ReadonlyArray<{ entryId: string; message: { messageId?: string } }> }>, |
| 35 | tabId: string, |
| 36 | entryId: string, |
| 37 | ): string { |
| 38 | if (!entryId.startsWith("m:")) return entryId; |
| 39 | for (const session of sessions) { |
| 40 | if (session.tabId !== tabId) continue; |
| 41 | const record = session.records.find((candidate) => `m:${candidate.message.messageId}` === entryId); |
| 42 | if (record) return record.entryId; |
| 43 | } |
| 44 | return entryId; |
| 45 | } |
| 46 |