| 73 | } |
| 74 | |
| 75 | export class WorkerGraphStore implements GraphStore { |
| 76 | private worker: Worker; |
| 77 | private pending = new Map<number, PendingRequest>(); |
| 78 | private nextSeq = 1; |
| 79 | private embedder: Embedder | null = null; |
| 80 | // The LadybugDB engine is owned here, on the main thread, so its internal |
| 81 | // worker is a top-level worker rather than one nested inside storeWorker |
| 82 | // (which broke on browsers without worker-in-worker support — Sentry |
| 83 | // OSS-OPENTRACE-1G). storeWorker reaches it via `engine-request` messages. |
| 84 | private engine: LbugEngine = createLbugEngine(); |
| 85 | private nodesImportedSinceClear = 0; |
| 86 | |
| 87 | constructor() { |
| 88 | this.worker = new Worker(new URL('./storeWorker.ts', import.meta.url), { |
| 89 | type: 'module', |
| 90 | }); |
| 91 | this.worker.onmessage = (e: MessageEvent<InMessage>) => |
| 92 | this.onMessage(e.data); |
| 93 | this.worker.onerror = (e) => { |
| 94 | const err = new Error(e.message || 'store worker error'); |
| 95 | for (const req of this.pending.values()) req.reject(err); |
| 96 | this.pending.clear(); |
| 97 | }; |
| 98 | // The inner store used to read these from localStorage during init, but |
| 99 | // Workers don't expose localStorage. Read them here and push them in once. |
| 100 | try { |
| 101 | const savedNodes = localStorage.getItem('ot:maxVisNodes'); |
| 102 | const savedEdges = localStorage.getItem('ot:maxVisEdges'); |
| 103 | if (savedNodes || savedEdges) { |
| 104 | const maxN = savedNodes ? Number(savedNodes) : 2000; |
| 105 | const maxE = savedEdges ? Number(savedEdges) : 5000; |
| 106 | if (Number.isFinite(maxN) && Number.isFinite(maxE)) { |
| 107 | void this.setLimits(maxN, maxE); |
| 108 | } |
| 109 | } |
| 110 | } catch { |
| 111 | // localStorage may be unavailable (SSR, sandboxed iframe) — limits keep |
| 112 | // their defaults in that case. |
| 113 | } |
| 114 | } |
| 115 | |
| 116 | // --- GraphStore interface --- |
| 117 | |
| 118 | hasData(): boolean { |
| 119 | return this.nodesImportedSinceClear > 0; |
| 120 | } |
| 121 | |
| 122 | ensureReady(): Promise<void> { |
| 123 | return this.call<void>('ensureReady', []); |
| 124 | } |
| 125 | |
| 126 | fetchGraph(query?: string, hops?: number): Promise<GraphData> { |
| 127 | return this.call<GraphData>('fetchGraph', [query, hops]); |
| 128 | } |
| 129 | |
| 130 | fetchStats(): Promise<GraphStats> { |
| 131 | return this.call<GraphStats>('fetchStats', []); |
| 132 | } |
nothing calls this directly
no test coverage detected