UNPKG

@dudousxd/nestjs-telescope

Version:

Laravel Telescope-style observability console for NestJS — core: watchers, recorder, correlation, SQLite store, headless API.

92 lines 3.63 kB
/** * Resolves the registered extensions once at module init. Each multi-hook runs for * every extension and the results accumulate; an id/name claimed twice is a hard * error naming both owners (mirrors nestjs-codegen's `mergeExclusive`). Resolution is * eager so collisions fail at boot, not on first request. */ export class ExtensionRegistry { _watchers = []; _entryTypes = []; _dashboards = []; _providers = new Map(); /** Provider name → the `name` of the extension that contributed it. */ _providerOwners = new Map(); _recordObservers = []; _flushObservers = []; constructor(extensions, ctx) { const entryOwners = new Map(); const dashOwners = new Map(); const provOwners = this._providerOwners; for (const ext of extensions) { for (const w of ext.watchers?.(ctx) ?? []) this._watchers.push(w); for (const et of ext.entryTypes?.(ctx) ?? []) { const prev = entryOwners.get(et.id); if (prev !== undefined) { throw new Error(`Telescope entry type "${et.id}" is contributed by both "${prev}" and "${ext.name}". Entry-type ids must be unique.`); } entryOwners.set(et.id, ext.name); this._entryTypes.push(et); } for (const d of ext.dashboards?.(ctx) ?? []) { const prev = dashOwners.get(d.id); if (prev !== undefined) { throw new Error(`Telescope dashboard "${d.id}" is contributed by both "${prev}" and "${ext.name}". Dashboard ids must be unique.`); } dashOwners.set(d.id, ext.name); this._dashboards.push(d); } for (const p of ext.dataProviders?.(ctx) ?? []) { const prev = provOwners.get(p.name); if (prev !== undefined) { throw new Error(`Telescope data provider "${p.name}" is contributed by both "${prev}" and "${ext.name}". Provider names must be unique.`); } provOwners.set(p.name, ext.name); this._providers.set(p.name, p); } if (ext.observeRecord) this._recordObservers.push(ext.observeRecord.bind(ext)); if (ext.observeFlush) this._flushObservers.push(ext.observeFlush.bind(ext)); } } /** Fan out a recorded input to every observer; isolate throwers (hot path). */ notifyRecord(input) { for (const observe of this._recordObservers) { try { observe(input); } catch { // Best-effort; one observer's bug must not affect capture or the others. } } } /** Await every flush observer; isolate throwers/rejections (off the host path). */ async notifyFlush(entries) { for (const observe of this._flushObservers) { try { await observe(entries); } catch { // Best-effort; never break the flush. } } } watchers() { return [...this._watchers]; } entryTypes() { return [...this._entryTypes]; } dashboards() { return [...this._dashboards]; } findProvider(name) { return this._providers.get(name); } /** The `name` of the extension that contributed the given provider, or undefined. */ providerOwner(name) { return this._providerOwners.get(name); } } //# sourceMappingURL=registry.js.map