@composed-di/observability 0.5.0-alpha

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/dist/cli.d.ts +3 -0
  2. package/dist/cli.d.ts.map +1 -0
  3. package/dist/cli.js +50 -0
  4. package/dist/cli.js.map +1 -0
  5. package/dist/dashboardClient.d.ts +67 -0
  6. package/dist/dashboardClient.d.ts.map +1 -0
  7. package/dist/dashboardClient.js +168 -0
  8. package/dist/dashboardClient.js.map +1 -0
  9. package/dist/dashboardEventListener.d.ts +32 -0
  10. package/dist/dashboardEventListener.d.ts.map +1 -0
  11. package/dist/dashboardEventListener.js +88 -0
  12. package/dist/dashboardEventListener.js.map +1 -0
  13. package/dist/dashboardHtml.d.ts +11 -0
  14. package/dist/dashboardHtml.d.ts.map +1 -0
  15. package/dist/dashboardHtml.js +662 -0
  16. package/dist/dashboardHtml.js.map +1 -0
  17. package/dist/dashboardServer.d.ts +99 -0
  18. package/dist/dashboardServer.d.ts.map +1 -0
  19. package/dist/dashboardServer.js +360 -0
  20. package/dist/dashboardServer.js.map +1 -0
  21. package/dist/events.d.ts +80 -0
  22. package/dist/events.d.ts.map +1 -0
  23. package/dist/events.js +7 -0
  24. package/dist/events.js.map +1 -0
  25. package/dist/index.d.ts +6 -0
  26. package/dist/index.d.ts.map +1 -0
  27. package/dist/index.js +22 -0
  28. package/dist/index.js.map +1 -0
  29. package/dist/moduleGraph.d.ts +13 -0
  30. package/dist/moduleGraph.d.ts.map +1 -0
  31. package/dist/moduleGraph.js +25 -0
  32. package/dist/moduleGraph.js.map +1 -0
  33. package/package.json +47 -0
  34. package/src/cli.ts +42 -0
  35. package/src/dashboardClient.ts +189 -0
  36. package/src/dashboardEventListener.ts +104 -0
  37. package/src/dashboardHtml.ts +659 -0
  38. package/src/dashboardServer.ts +391 -0
  39. package/src/events.ts +94 -0
  40. package/src/index.ts +5 -0
  41. package/src/moduleGraph.ts +37 -0
@@ -0,0 +1,99 @@
1
+ import { ServiceModule } from '@composed-di/core';
2
+ import { DashboardEventListener } from './dashboardEventListener';
3
+ import { ModuleGraph } from './moduleGraph';
4
+ import { DashboardSnapshot, SpanEvent } from './events';
5
+ export interface ServiceDashboardOptions {
6
+ /** How many recent events to keep for late-joining clients. Default 200. */
7
+ recentEventLimit?: number;
8
+ }
9
+ /**
10
+ * A realtime dashboard server for observed ServiceModules.
11
+ *
12
+ * Serves a self-contained HTML page that renders the dependency graph and
13
+ * streams service initialization, disposal, and method-call activity to it
14
+ * over Server-Sent Events. Uses only Node.js built-ins.
15
+ *
16
+ * Two ways to feed it, mirroring how OpenTelemetry separates SDK and
17
+ * collector:
18
+ *
19
+ * **Standalone (recommended):** run the server on its own — `npx
20
+ * composed-di-dashboard` or `new ServiceDashboard().listen(4321)` — and have
21
+ * the application export to it with a {@link DashboardClient}. The server
22
+ * accepts `POST /v1/graph` (the dependency graph) and `POST /v1/events`
23
+ * (batched span events).
24
+ *
25
+ * **In-process:** create the module with `dashboard.listener`, call
26
+ * `dashboard.attach(module)`, and `listen` from the same process.
27
+ *
28
+ * @example
29
+ * ```ts
30
+ * // dashboard process
31
+ * const dashboard = new ServiceDashboard();
32
+ * await dashboard.listen(4321);
33
+ *
34
+ * // application process
35
+ * const client = new DashboardClient({ url: 'http://localhost:4321' });
36
+ * const module = ServiceModule.from(factories, client.listener);
37
+ * client.attach(module);
38
+ * ```
39
+ */
40
+ export declare class ServiceDashboard {
41
+ /** Pass this as the second argument to ServiceModule.from. */
42
+ readonly listener: DashboardEventListener;
43
+ private nodes;
44
+ private edges;
45
+ private services;
46
+ /** Open spans, so end events can be resolved to their start metadata. */
47
+ private openSpans;
48
+ private recent;
49
+ private readonly recentEventLimit;
50
+ /** Whether any graph was registered; ingest is refused (409) before that. */
51
+ private graphRegistered;
52
+ private clients;
53
+ private server;
54
+ private heartbeat;
55
+ constructor({ recentEventLimit }?: ServiceDashboardOptions);
56
+ /**
57
+ * In-process mode: reads the dependency graph out of the module. Call
58
+ * this with the module that was created with this dashboard's listener.
59
+ */
60
+ attach(module: ServiceModule): this;
61
+ /**
62
+ * Registers a dependency graph, resetting all aggregated state (a new
63
+ * registration means a new application run). Remote applications call this
64
+ * through `POST /v1/graph`.
65
+ */
66
+ registerGraph(graph: ModuleGraph): void;
67
+ /**
68
+ * Applies span events, e.g. exported by a remote DashboardClient through
69
+ * `POST /v1/events`. Services not present in the registered graph are
70
+ * added as standalone nodes rather than dropped.
71
+ */
72
+ ingest(events: SpanEvent[]): void;
73
+ /** The current full dashboard state, as sent to newly connected clients. */
74
+ snapshot(): DashboardSnapshot;
75
+ /**
76
+ * Starts the HTTP server.
77
+ *
78
+ * @param port The port to listen on; 0 picks a free port. Default 4321.
79
+ * @param host The host to bind. Default 127.0.0.1.
80
+ * @returns The URL the dashboard is reachable at.
81
+ */
82
+ listen(port?: number, host?: string): Promise<string>;
83
+ /** Stops the server and disconnects all clients. */
84
+ close(): Promise<void>;
85
+ private route;
86
+ private acceptEventStream;
87
+ /**
88
+ * Applies a raw span event to the aggregated per-service state and
89
+ * broadcasts the enriched event to connected clients.
90
+ */
91
+ private onSpanEvent;
92
+ private applyStart;
93
+ private applyEnd;
94
+ /** Walks to the parent span to find which service triggered this one. */
95
+ private parentServiceOf;
96
+ /** Pushes the full state to all connected clients, e.g. on graph changes. */
97
+ private broadcastSnapshot;
98
+ }
99
+ //# sourceMappingURL=dashboardServer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dashboardServer.d.ts","sourceRoot":"","sources":["../src/dashboardServer.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,EAAE,WAAW,EAAe,MAAM,eAAe,CAAC;AAEzD,OAAO,EACL,iBAAiB,EAIjB,SAAS,EAIV,MAAM,UAAU,CAAC;AAElB,MAAM,WAAW,uBAAuB;IACtC,4EAA4E;IAC5E,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAID;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,qBAAa,gBAAgB;IAC3B,8DAA8D;IAC9D,QAAQ,CAAC,QAAQ,yBAAgC;IAEjD,OAAO,CAAC,KAAK,CAAmB;IAChC,OAAO,CAAC,KAAK,CAAmB;IAChC,OAAO,CAAC,QAAQ,CAAmC;IACnD,yEAAyE;IACzE,OAAO,CAAC,SAAS,CAAgC;IACjD,OAAO,CAAC,MAAM,CAAmB;IACjC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAS;IAC1C,6EAA6E;IAC7E,OAAO,CAAC,eAAe,CAAS;IAEhC,OAAO,CAAC,OAAO,CAA6B;IAC5C,OAAO,CAAC,MAAM,CAAuB;IACrC,OAAO,CAAC,SAAS,CAA+B;gBAEpC,EAAE,gBAAsB,EAAE,GAAE,uBAA4B;IAKpE;;;OAGG;IACH,MAAM,CAAC,MAAM,EAAE,aAAa,GAAG,IAAI;IAKnC;;;;OAIG;IACH,aAAa,CAAC,KAAK,EAAE,WAAW,GAAG,IAAI;IAYvC;;;;OAIG;IACH,MAAM,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,IAAI;IAejC,4EAA4E;IAC5E,QAAQ,IAAI,iBAAiB;IAS7B;;;;;;OAMG;IACH,MAAM,CAAC,IAAI,SAAO,EAAE,IAAI,SAAc,GAAG,OAAO,CAAC,MAAM,CAAC;IAyBxD,oDAAoD;IAC9C,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;YAgBd,KAAK;IA6DnB,OAAO,CAAC,iBAAiB;IAWzB;;;OAGG;IACH,OAAO,CAAC,WAAW;IAqCnB,OAAO,CAAC,UAAU;IASlB,OAAO,CAAC,QAAQ;IA2BhB,yEAAyE;IACzE,OAAO,CAAC,eAAe;IAKvB,6EAA6E;IAC7E,OAAO,CAAC,iBAAiB;CAI1B"}
@@ -0,0 +1,360 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.ServiceDashboard = void 0;
13
+ const node_http_1 = require("node:http");
14
+ const dashboardEventListener_1 = require("./dashboardEventListener");
15
+ const moduleGraph_1 = require("./moduleGraph");
16
+ const dashboardHtml_1 = require("./dashboardHtml");
17
+ const HEARTBEAT_INTERVAL_MS = 15000;
18
+ /**
19
+ * A realtime dashboard server for observed ServiceModules.
20
+ *
21
+ * Serves a self-contained HTML page that renders the dependency graph and
22
+ * streams service initialization, disposal, and method-call activity to it
23
+ * over Server-Sent Events. Uses only Node.js built-ins.
24
+ *
25
+ * Two ways to feed it, mirroring how OpenTelemetry separates SDK and
26
+ * collector:
27
+ *
28
+ * **Standalone (recommended):** run the server on its own — `npx
29
+ * composed-di-dashboard` or `new ServiceDashboard().listen(4321)` — and have
30
+ * the application export to it with a {@link DashboardClient}. The server
31
+ * accepts `POST /v1/graph` (the dependency graph) and `POST /v1/events`
32
+ * (batched span events).
33
+ *
34
+ * **In-process:** create the module with `dashboard.listener`, call
35
+ * `dashboard.attach(module)`, and `listen` from the same process.
36
+ *
37
+ * @example
38
+ * ```ts
39
+ * // dashboard process
40
+ * const dashboard = new ServiceDashboard();
41
+ * await dashboard.listen(4321);
42
+ *
43
+ * // application process
44
+ * const client = new DashboardClient({ url: 'http://localhost:4321' });
45
+ * const module = ServiceModule.from(factories, client.listener);
46
+ * client.attach(module);
47
+ * ```
48
+ */
49
+ class ServiceDashboard {
50
+ constructor({ recentEventLimit = 200 } = {}) {
51
+ /** Pass this as the second argument to ServiceModule.from. */
52
+ this.listener = new dashboardEventListener_1.DashboardEventListener();
53
+ this.nodes = [];
54
+ this.edges = [];
55
+ this.services = new Map();
56
+ /** Open spans, so end events can be resolved to their start metadata. */
57
+ this.openSpans = new Map();
58
+ this.recent = [];
59
+ /** Whether any graph was registered; ingest is refused (409) before that. */
60
+ this.graphRegistered = false;
61
+ this.clients = new Set();
62
+ this.server = null;
63
+ this.heartbeat = null;
64
+ this.recentEventLimit = recentEventLimit;
65
+ this.listener.subscribe((event) => this.onSpanEvent(event));
66
+ }
67
+ /**
68
+ * In-process mode: reads the dependency graph out of the module. Call
69
+ * this with the module that was created with this dashboard's listener.
70
+ */
71
+ attach(module) {
72
+ this.registerGraph((0, moduleGraph_1.moduleGraph)(module));
73
+ return this;
74
+ }
75
+ /**
76
+ * Registers a dependency graph, resetting all aggregated state (a new
77
+ * registration means a new application run). Remote applications call this
78
+ * through `POST /v1/graph`.
79
+ */
80
+ registerGraph(graph) {
81
+ this.graphRegistered = true;
82
+ this.nodes = graph.nodes;
83
+ this.edges = graph.edges;
84
+ this.services = new Map(this.nodes.map((node) => [node.name, freshStats()]));
85
+ this.openSpans.clear();
86
+ this.recent = [];
87
+ this.broadcastSnapshot();
88
+ }
89
+ /**
90
+ * Applies span events, e.g. exported by a remote DashboardClient through
91
+ * `POST /v1/events`. Services not present in the registered graph are
92
+ * added as standalone nodes rather than dropped.
93
+ */
94
+ ingest(events) {
95
+ for (const event of events) {
96
+ if (event.type === 'start' &&
97
+ event.service !== null &&
98
+ !this.services.has(event.service)) {
99
+ this.nodes.push({ name: event.service });
100
+ this.services.set(event.service, freshStats());
101
+ this.broadcastSnapshot();
102
+ }
103
+ this.onSpanEvent(event);
104
+ }
105
+ }
106
+ /** The current full dashboard state, as sent to newly connected clients. */
107
+ snapshot() {
108
+ return {
109
+ nodes: this.nodes,
110
+ edges: this.edges,
111
+ services: Object.fromEntries(this.services),
112
+ recent: this.recent,
113
+ };
114
+ }
115
+ /**
116
+ * Starts the HTTP server.
117
+ *
118
+ * @param port The port to listen on; 0 picks a free port. Default 4321.
119
+ * @param host The host to bind. Default 127.0.0.1.
120
+ * @returns The URL the dashboard is reachable at.
121
+ */
122
+ listen(port = 4321, host = '127.0.0.1') {
123
+ if (this.server) {
124
+ throw new Error('Dashboard server is already listening');
125
+ }
126
+ const server = (0, node_http_1.createServer)((request, response) => {
127
+ void this.route(request, response);
128
+ });
129
+ this.server = server;
130
+ this.heartbeat = setInterval(() => {
131
+ this.clients.forEach((client) => client.write(': ping\n\n'));
132
+ }, HEARTBEAT_INTERVAL_MS);
133
+ // Don't let an idle dashboard keep the process alive on its own.
134
+ this.heartbeat.unref();
135
+ return new Promise((resolve, reject) => {
136
+ server.once('error', reject);
137
+ server.listen(port, host, () => {
138
+ const address = server.address();
139
+ const shownHost = host === '0.0.0.0' || host === '::' ? 'localhost' : host;
140
+ resolve(`http://${shownHost}:${address.port}`);
141
+ });
142
+ });
143
+ }
144
+ /** Stops the server and disconnects all clients. */
145
+ close() {
146
+ return __awaiter(this, void 0, void 0, function* () {
147
+ if (this.heartbeat) {
148
+ clearInterval(this.heartbeat);
149
+ this.heartbeat = null;
150
+ }
151
+ this.clients.forEach((client) => client.end());
152
+ this.clients.clear();
153
+ const server = this.server;
154
+ this.server = null;
155
+ if (server) {
156
+ yield new Promise((resolve, reject) => {
157
+ server.close((error) => (error ? reject(error) : resolve()));
158
+ });
159
+ }
160
+ });
161
+ }
162
+ route(request, response) {
163
+ return __awaiter(this, void 0, void 0, function* () {
164
+ var _a;
165
+ const path = (_a = request.url) === null || _a === void 0 ? void 0 : _a.split('?')[0];
166
+ const route = `${request.method} ${path}`;
167
+ try {
168
+ switch (route) {
169
+ case 'GET /':
170
+ response.writeHead(200, {
171
+ 'content-type': 'text/html; charset=utf-8',
172
+ });
173
+ response.end((0, dashboardHtml_1.renderDashboardHtml)());
174
+ return;
175
+ case 'GET /events':
176
+ this.acceptEventStream(response);
177
+ return;
178
+ case 'GET /snapshot':
179
+ response.writeHead(200, { 'content-type': 'application/json' });
180
+ response.end(JSON.stringify(this.snapshot()));
181
+ return;
182
+ case 'POST /v1/graph': {
183
+ const graph = yield readJsonBody(request);
184
+ if (!Array.isArray(graph === null || graph === void 0 ? void 0 : graph.nodes) || !Array.isArray(graph === null || graph === void 0 ? void 0 : graph.edges)) {
185
+ throw new BadRequestError('expected { nodes: [], edges: [] }');
186
+ }
187
+ this.registerGraph(graph);
188
+ response.writeHead(204);
189
+ response.end();
190
+ return;
191
+ }
192
+ case 'POST /v1/events': {
193
+ const body = yield readJsonBody(request);
194
+ if (!Array.isArray(body === null || body === void 0 ? void 0 : body.events)) {
195
+ throw new BadRequestError('expected { events: [] }');
196
+ }
197
+ // A restarted server has no graph; tell the client to re-register
198
+ // before it sends events, so context isn't rendered nodeless.
199
+ if (!this.graphRegistered) {
200
+ response.writeHead(409, { 'content-type': 'text/plain' });
201
+ response.end('no graph registered; POST /v1/graph first');
202
+ return;
203
+ }
204
+ this.ingest(body.events);
205
+ response.writeHead(204);
206
+ response.end();
207
+ return;
208
+ }
209
+ default:
210
+ response.writeHead(404, { 'content-type': 'text/plain' });
211
+ response.end('Not found');
212
+ }
213
+ }
214
+ catch (error) {
215
+ const badRequest = error instanceof BadRequestError;
216
+ response.writeHead(badRequest ? 400 : 500, {
217
+ 'content-type': 'text/plain',
218
+ });
219
+ response.end(badRequest ? error.message : 'Internal error');
220
+ }
221
+ });
222
+ }
223
+ acceptEventStream(response) {
224
+ response.writeHead(200, {
225
+ 'content-type': 'text/event-stream',
226
+ 'cache-control': 'no-cache',
227
+ connection: 'keep-alive',
228
+ });
229
+ response.write(sseMessage('snapshot', this.snapshot()));
230
+ this.clients.add(response);
231
+ response.on('close', () => this.clients.delete(response));
232
+ }
233
+ /**
234
+ * Applies a raw span event to the aggregated per-service state and
235
+ * broadcasts the enriched event to connected clients.
236
+ */
237
+ onSpanEvent(event) {
238
+ var _a, _b, _c;
239
+ let wire;
240
+ if (event.type === 'start') {
241
+ this.openSpans.set(event.id, event);
242
+ const stats = this.applyStart(event);
243
+ wire = {
244
+ span: event,
245
+ service: event.service,
246
+ method: event.method,
247
+ kind: event.kind,
248
+ parentService: this.parentServiceOf(event),
249
+ // Copy so the recent-events buffer keeps at-the-time values.
250
+ stats: stats ? Object.assign({}, stats) : null,
251
+ };
252
+ }
253
+ else {
254
+ const start = this.openSpans.get(event.id);
255
+ this.openSpans.delete(event.id);
256
+ const stats = start ? this.applyEnd(start, event) : null;
257
+ wire = {
258
+ span: event,
259
+ service: (_a = start === null || start === void 0 ? void 0 : start.service) !== null && _a !== void 0 ? _a : null,
260
+ method: (_b = start === null || start === void 0 ? void 0 : start.method) !== null && _b !== void 0 ? _b : '?',
261
+ kind: (_c = start === null || start === void 0 ? void 0 : start.kind) !== null && _c !== void 0 ? _c : 'call',
262
+ parentService: start ? this.parentServiceOf(start) : null,
263
+ stats: stats ? Object.assign({}, stats) : null,
264
+ };
265
+ }
266
+ this.recent.push(wire);
267
+ if (this.recent.length > this.recentEventLimit) {
268
+ this.recent.splice(0, this.recent.length - this.recentEventLimit);
269
+ }
270
+ const message = sseMessage('span', wire);
271
+ this.clients.forEach((client) => client.write(message));
272
+ }
273
+ applyStart(event) {
274
+ const stats = event.service ? this.services.get(event.service) : undefined;
275
+ if (!stats)
276
+ return null;
277
+ if (event.kind === 'initialize') {
278
+ stats.status = 'initializing';
279
+ }
280
+ return stats;
281
+ }
282
+ applyEnd(start, event) {
283
+ const stats = start.service ? this.services.get(start.service) : undefined;
284
+ if (!stats)
285
+ return null;
286
+ if (event.error !== null) {
287
+ stats.errors += 1;
288
+ }
289
+ const transitions = {
290
+ initialize: () => {
291
+ stats.status = event.error !== null ? 'error' : 'ready';
292
+ if (event.error === null)
293
+ stats.initMs = event.durationMs;
294
+ },
295
+ dispose: () => {
296
+ if (event.error === null)
297
+ stats.status = 'disposed';
298
+ },
299
+ call: () => {
300
+ stats.calls += 1;
301
+ stats.totalCallMs += event.durationMs;
302
+ },
303
+ };
304
+ transitions[start.kind]();
305
+ return stats;
306
+ }
307
+ /** Walks to the parent span to find which service triggered this one. */
308
+ parentServiceOf(event) {
309
+ var _a, _b;
310
+ if (event.parentId === null)
311
+ return null;
312
+ return (_b = (_a = this.openSpans.get(event.parentId)) === null || _a === void 0 ? void 0 : _a.service) !== null && _b !== void 0 ? _b : null;
313
+ }
314
+ /** Pushes the full state to all connected clients, e.g. on graph changes. */
315
+ broadcastSnapshot() {
316
+ const message = sseMessage('snapshot', this.snapshot());
317
+ this.clients.forEach((client) => client.write(message));
318
+ }
319
+ }
320
+ exports.ServiceDashboard = ServiceDashboard;
321
+ function freshStats() {
322
+ return {
323
+ status: 'pending',
324
+ initMs: null,
325
+ calls: 0,
326
+ errors: 0,
327
+ totalCallMs: 0,
328
+ };
329
+ }
330
+ class BadRequestError extends Error {
331
+ }
332
+ const MAX_BODY_BYTES = 5 * 1024 * 1024;
333
+ function readJsonBody(request) {
334
+ return new Promise((resolve, reject) => {
335
+ const chunks = [];
336
+ let size = 0;
337
+ request.on('data', (chunk) => {
338
+ size += chunk.length;
339
+ if (size > MAX_BODY_BYTES) {
340
+ reject(new BadRequestError('request body too large'));
341
+ request.destroy();
342
+ return;
343
+ }
344
+ chunks.push(chunk);
345
+ });
346
+ request.on('end', () => {
347
+ try {
348
+ resolve(JSON.parse(Buffer.concat(chunks).toString('utf8')));
349
+ }
350
+ catch (_a) {
351
+ reject(new BadRequestError('invalid JSON body'));
352
+ }
353
+ });
354
+ request.on('error', reject);
355
+ });
356
+ }
357
+ function sseMessage(event, data) {
358
+ return `event: ${event}\ndata: ${JSON.stringify(data)}\n\n`;
359
+ }
360
+ //# sourceMappingURL=dashboardServer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dashboardServer.js","sourceRoot":"","sources":["../src/dashboardServer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,80 @@
1
+ /**
2
+ * Event and state types shared between the dashboard event listener, the
3
+ * dashboard server, and the browser client (over the SSE wire).
4
+ */
5
+ /** Classifies what a span represents in the service lifecycle. */
6
+ export type SpanKind = 'initialize' | 'dispose' | 'call';
7
+ /** Emitted when a traced function starts executing. */
8
+ export interface SpanStart {
9
+ type: 'start';
10
+ /** Monotonically increasing span id, unique per tracer. */
11
+ id: number;
12
+ /** Id of the span that was active when this one started, if any. */
13
+ parentId: number | null;
14
+ /** The qualified span name, e.g. "Database.query". */
15
+ name: string;
16
+ /** The service the span belongs to, or null if it could not be attributed. */
17
+ service: string | null;
18
+ /** The method or lifecycle step, e.g. "query" or "initialize". */
19
+ method: string;
20
+ kind: SpanKind;
21
+ /** Epoch milliseconds. */
22
+ time: number;
23
+ }
24
+ /** Emitted when a traced function finishes (or throws/rejects). */
25
+ export interface SpanEnd {
26
+ type: 'end';
27
+ /** Matches the id of the corresponding SpanStart. */
28
+ id: number;
29
+ /** Epoch milliseconds. */
30
+ time: number;
31
+ durationMs: number;
32
+ /** The error message when the traced function threw or rejected. */
33
+ error: string | null;
34
+ }
35
+ export type SpanEvent = SpanStart | SpanEnd;
36
+ export type ServiceStatus = 'pending' | 'initializing' | 'ready' | 'error' | 'disposed';
37
+ /** Aggregated per-service counters maintained by the dashboard. */
38
+ export interface ServiceStats {
39
+ status: ServiceStatus;
40
+ /** Duration of the last successful initialization, if any. */
41
+ initMs: number | null;
42
+ /** Number of completed method-call spans. */
43
+ calls: number;
44
+ /** Number of spans (of any kind) that ended with an error. */
45
+ errors: number;
46
+ /** Sum of completed method-call durations, for averaging. */
47
+ totalCallMs: number;
48
+ }
49
+ export interface GraphNode {
50
+ name: string;
51
+ }
52
+ /** A dependency edge: `from` depends on `to`. */
53
+ export interface GraphEdge {
54
+ from: string;
55
+ to: string;
56
+ }
57
+ /**
58
+ * The enriched event broadcast to dashboard clients. The server resolves
59
+ * cross-span context (parent service, span metadata on end events) and the
60
+ * updated per-service stats so the client needs no correlation logic.
61
+ */
62
+ export interface WireEvent {
63
+ span: SpanEvent;
64
+ /** Service of the span; on end events resolved from the matching start. */
65
+ service: string | null;
66
+ method: string;
67
+ kind: SpanKind;
68
+ /** Service of the parent span, when the span was started by another service. */
69
+ parentService: string | null;
70
+ /** Updated stats for `service`, present when the event changed them. */
71
+ stats: ServiceStats | null;
72
+ }
73
+ /** Full state sent to a client when it connects. */
74
+ export interface DashboardSnapshot {
75
+ nodes: GraphNode[];
76
+ edges: GraphEdge[];
77
+ services: Record<string, ServiceStats>;
78
+ recent: WireEvent[];
79
+ }
80
+ //# sourceMappingURL=events.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../src/events.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,kEAAkE;AAClE,MAAM,MAAM,QAAQ,GAAG,YAAY,GAAG,SAAS,GAAG,MAAM,CAAC;AAEzD,uDAAuD;AACvD,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,OAAO,CAAC;IACd,2DAA2D;IAC3D,EAAE,EAAE,MAAM,CAAC;IACX,oEAAoE;IACpE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,sDAAsD;IACtD,IAAI,EAAE,MAAM,CAAC;IACb,8EAA8E;IAC9E,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,kEAAkE;IAClE,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,QAAQ,CAAC;IACf,0BAA0B;IAC1B,IAAI,EAAE,MAAM,CAAC;CACd;AAED,mEAAmE;AACnE,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,KAAK,CAAC;IACZ,qDAAqD;IACrD,EAAE,EAAE,MAAM,CAAC;IACX,0BAA0B;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,oEAAoE;IACpE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB;AAED,MAAM,MAAM,SAAS,GAAG,SAAS,GAAG,OAAO,CAAC;AAE5C,MAAM,MAAM,aAAa,GACrB,SAAS,GACT,cAAc,GACd,OAAO,GACP,OAAO,GACP,UAAU,CAAC;AAEf,mEAAmE;AACnE,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,aAAa,CAAC;IACtB,8DAA8D;IAC9D,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,6CAA6C;IAC7C,KAAK,EAAE,MAAM,CAAC;IACd,8DAA8D;IAC9D,MAAM,EAAE,MAAM,CAAC;IACf,6DAA6D;IAC7D,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,iDAAiD;AACjD,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;CACZ;AAED;;;;GAIG;AACH,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,SAAS,CAAC;IAChB,2EAA2E;IAC3E,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,QAAQ,CAAC;IACf,gFAAgF;IAChF,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,wEAAwE;IACxE,KAAK,EAAE,YAAY,GAAG,IAAI,CAAC;CAC5B;AAED,oDAAoD;AACpD,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,SAAS,EAAE,CAAC;IACnB,KAAK,EAAE,SAAS,EAAE,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IACvC,MAAM,EAAE,SAAS,EAAE,CAAC;CACrB"}
package/dist/events.js ADDED
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ /**
3
+ * Event and state types shared between the dashboard event listener, the
4
+ * dashboard server, and the browser client (over the SSE wire).
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ //# sourceMappingURL=events.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"events.js","sourceRoot":"","sources":["../src/events.ts"],"names":[],"mappings":";AAAA;;;GAGG"}
@@ -0,0 +1,6 @@
1
+ export * from './events';
2
+ export * from './dashboardEventListener';
3
+ export * from './dashboardClient';
4
+ export * from './dashboardServer';
5
+ export * from './moduleGraph';
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAC;AACzB,cAAc,0BAA0B,CAAC;AACzC,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC;AAClC,cAAc,eAAe,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./events"), exports);
18
+ __exportStar(require("./dashboardEventListener"), exports);
19
+ __exportStar(require("./dashboardClient"), exports);
20
+ __exportStar(require("./dashboardServer"), exports);
21
+ __exportStar(require("./moduleGraph"), exports);
22
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,2CAAyB;AACzB,2DAAyC;AACzC,oDAAkC;AAClC,oDAAkC;AAClC,gDAA8B"}
@@ -0,0 +1,13 @@
1
+ import { ServiceModule } from '@composed-di/core';
2
+ import { GraphEdge, GraphNode } from './events';
3
+ export interface ModuleGraph {
4
+ nodes: GraphNode[];
5
+ edges: GraphEdge[];
6
+ }
7
+ /**
8
+ * Extracts the dependency graph of a module: one node per factory, one edge
9
+ * per dependency. Selector dependencies expand to an edge per grouped key
10
+ * ("may resolve any of these").
11
+ */
12
+ export declare function moduleGraph(module: ServiceModule): ModuleGraph;
13
+ //# sourceMappingURL=moduleGraph.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"moduleGraph.d.ts","sourceRoot":"","sources":["../src/moduleGraph.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,aAAa,EAEd,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAEhD,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,SAAS,EAAE,CAAC;IACnB,KAAK,EAAE,SAAS,EAAE,CAAC;CACpB;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,aAAa,GAAG,WAAW,CAmB9D"}
@@ -0,0 +1,25 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.moduleGraph = moduleGraph;
4
+ const core_1 = require("@composed-di/core");
5
+ /**
6
+ * Extracts the dependency graph of a module: one node per factory, one edge
7
+ * per dependency. Selector dependencies expand to an edge per grouped key
8
+ * ("may resolve any of these").
9
+ */
10
+ function moduleGraph(module) {
11
+ const nodes = module.factories.map((factory) => ({
12
+ name: factory.provides.name,
13
+ }));
14
+ const edges = module.factories.flatMap((factory) => factory.dependsOn.flatMap((dependency) => {
15
+ const targets = dependency instanceof core_1.ServiceSelectorKey
16
+ ? dependency.values
17
+ : [dependency];
18
+ return targets.map((target) => ({
19
+ from: factory.provides.name,
20
+ to: target.name,
21
+ }));
22
+ }));
23
+ return { nodes, edges };
24
+ }
25
+ //# sourceMappingURL=moduleGraph.js.map