/** * Central registry of markwhen source factories. * * Each rApp that has date-bearing records registers a factory here. * The composite viewer (rSaga) and per-module timeline applets pull * from this registry. */ import type { MarkwhenSourceFactory, MwSource } from './types'; import { renderMarkwhen, type RenderOptions } from './projection'; const factories: Map = new Map(); export function registerMarkwhenSource(factory: MarkwhenSourceFactory): void { factories.set(factory.module, factory); } export function listMarkwhenSources(): MarkwhenSourceFactory[] { return [...factories.values()]; } export function getMarkwhenSource(module: string): MarkwhenSourceFactory | undefined { return factories.get(module); } export interface ProjectOptions extends RenderOptions { /** Module ids to include. If omitted, projects all registered sources. */ modules?: string[]; from?: number; to?: number; } export async function projectSpace(space: string, opts: ProjectOptions = {}) { const chosen = opts.modules ? opts.modules.map(m => factories.get(m)).filter((f): f is MarkwhenSourceFactory => !!f) : [...factories.values()]; const sources: MwSource[] = []; for (const f of chosen) { try { const src = await f.build({ space, from: opts.from, to: opts.to }); if (src && src.events.length > 0) sources.push(src); } catch (err) { console.warn(`[markwhen] source ${f.module} failed:`, err); } } return renderMarkwhen(sources, opts); }