@adonis-agora/telescope 0.4.0 → 0.5.0
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.
- package/CHANGELOG.md +10 -0
- package/dist/configure.d.ts.map +1 -1
- package/dist/configure.js +6 -0
- package/dist/configure.js.map +1 -1
- package/dist/providers/telescope_ai_provider.d.ts +9 -1
- package/dist/providers/telescope_ai_provider.d.ts.map +1 -1
- package/dist/providers/telescope_ai_provider.js +22 -2
- package/dist/providers/telescope_ai_provider.js.map +1 -1
- package/dist/providers/telescope_alerts_provider.d.ts +1 -0
- package/dist/providers/telescope_alerts_provider.d.ts.map +1 -1
- package/dist/providers/telescope_alerts_provider.js +37 -1
- package/dist/providers/telescope_alerts_provider.js.map +1 -1
- package/dist/providers/telescope_mcp_provider.d.ts +26 -0
- package/dist/providers/telescope_mcp_provider.d.ts.map +1 -0
- package/dist/providers/telescope_mcp_provider.js +114 -0
- package/dist/providers/telescope_mcp_provider.js.map +1 -0
- package/dist/providers/telescope_provider.d.ts +8 -0
- package/dist/providers/telescope_provider.d.ts.map +1 -1
- package/dist/providers/telescope_provider.js +56 -1
- package/dist/providers/telescope_provider.js.map +1 -1
- package/dist/providers/telescope_ui_provider.d.ts +2 -0
- package/dist/providers/telescope_ui_provider.d.ts.map +1 -1
- package/dist/providers/telescope_ui_provider.js +106 -22
- package/dist/providers/telescope_ui_provider.js.map +1 -1
- package/dist/providers/telescope_watchers_provider.d.ts +13 -2
- package/dist/providers/telescope_watchers_provider.d.ts.map +1 -1
- package/dist/providers/telescope_watchers_provider.js +57 -7
- package/dist/providers/telescope_watchers_provider.js.map +1 -1
- package/dist/src/ai/define_config.d.ts +39 -7
- package/dist/src/ai/define_config.d.ts.map +1 -1
- package/dist/src/ai/define_config.js +14 -4
- package/dist/src/ai/define_config.js.map +1 -1
- package/dist/src/ai/diagnosis_coordinator.d.ts +106 -0
- package/dist/src/ai/diagnosis_coordinator.d.ts.map +1 -0
- package/dist/src/ai/diagnosis_coordinator.js +143 -0
- package/dist/src/ai/diagnosis_coordinator.js.map +1 -0
- package/dist/src/ai/factory.d.ts +8 -5
- package/dist/src/ai/factory.d.ts.map +1 -1
- package/dist/src/ai/factory.js +20 -8
- package/dist/src/ai/factory.js.map +1 -1
- package/dist/src/ai/index.d.ts +3 -1
- package/dist/src/ai/index.d.ts.map +1 -1
- package/dist/src/ai/index.js +3 -1
- package/dist/src/ai/index.js.map +1 -1
- package/dist/src/alerts/alert_rule.d.ts +79 -11
- package/dist/src/alerts/alert_rule.d.ts.map +1 -1
- package/dist/src/alerts/alerter.d.ts +11 -1
- package/dist/src/alerts/alerter.d.ts.map +1 -1
- package/dist/src/alerts/alerter.js +21 -1
- package/dist/src/alerts/alerter.js.map +1 -1
- package/dist/src/alerts/alerter_service.d.ts +103 -0
- package/dist/src/alerts/alerter_service.d.ts.map +1 -0
- package/dist/src/alerts/alerter_service.js +215 -0
- package/dist/src/alerts/alerter_service.js.map +1 -0
- package/dist/src/alerts/index.d.ts +4 -2
- package/dist/src/alerts/index.d.ts.map +1 -1
- package/dist/src/alerts/index.js +4 -2
- package/dist/src/alerts/index.js.map +1 -1
- package/dist/src/alerts/slack_format.d.ts.map +1 -1
- package/dist/src/alerts/slack_format.js +35 -2
- package/dist/src/alerts/slack_format.js.map +1 -1
- package/dist/src/client_errors/config.d.ts +66 -0
- package/dist/src/client_errors/config.d.ts.map +1 -0
- package/dist/src/client_errors/config.js +17 -0
- package/dist/src/client_errors/config.js.map +1 -0
- package/dist/src/client_errors/index.d.ts +5 -0
- package/dist/src/client_errors/index.d.ts.map +1 -0
- package/dist/src/client_errors/index.js +5 -0
- package/dist/src/client_errors/index.js.map +1 -0
- package/dist/src/client_errors/ingestor.d.ts +87 -0
- package/dist/src/client_errors/ingestor.d.ts.map +1 -0
- package/dist/src/client_errors/ingestor.js +135 -0
- package/dist/src/client_errors/ingestor.js.map +1 -0
- package/dist/src/client_errors/rate_limiter.d.ts +53 -0
- package/dist/src/client_errors/rate_limiter.d.ts.map +1 -0
- package/dist/src/client_errors/rate_limiter.js +83 -0
- package/dist/src/client_errors/rate_limiter.js.map +1 -0
- package/dist/src/client_errors/validation.d.ts +62 -0
- package/dist/src/client_errors/validation.d.ts.map +1 -0
- package/dist/src/client_errors/validation.js +109 -0
- package/dist/src/client_errors/validation.js.map +1 -0
- package/dist/src/define_config.d.ts +120 -0
- package/dist/src/define_config.d.ts.map +1 -1
- package/dist/src/define_config.js +41 -0
- package/dist/src/define_config.js.map +1 -1
- package/dist/src/entry.d.ts +20 -0
- package/dist/src/entry.d.ts.map +1 -1
- package/dist/src/entry.js +20 -0
- package/dist/src/entry.js.map +1 -1
- package/dist/src/index.d.ts +16 -3
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +15 -2
- package/dist/src/index.js.map +1 -1
- package/dist/src/mcp/define_config.d.ts +57 -0
- package/dist/src/mcp/define_config.d.ts.map +1 -0
- package/dist/src/mcp/define_config.js +35 -0
- package/dist/src/mcp/define_config.js.map +1 -0
- package/dist/src/mcp/index.d.ts +7 -0
- package/dist/src/mcp/index.d.ts.map +1 -0
- package/dist/src/mcp/index.js +7 -0
- package/dist/src/mcp/index.js.map +1 -0
- package/dist/src/mcp/server.d.ts +89 -0
- package/dist/src/mcp/server.d.ts.map +1 -0
- package/dist/src/mcp/server.js +279 -0
- package/dist/src/mcp/server.js.map +1 -0
- package/dist/src/metrics/pulse.d.ts +158 -0
- package/dist/src/metrics/pulse.d.ts.map +1 -0
- package/dist/src/metrics/pulse.js +414 -0
- package/dist/src/metrics/pulse.js.map +1 -0
- package/dist/src/overload_guard.d.ts +77 -0
- package/dist/src/overload_guard.d.ts.map +1 -0
- package/dist/src/overload_guard.js +134 -0
- package/dist/src/overload_guard.js.map +1 -0
- package/dist/src/pruner.d.ts +93 -0
- package/dist/src/pruner.d.ts.map +1 -0
- package/dist/src/pruner.js +120 -0
- package/dist/src/pruner.js.map +1 -0
- package/dist/src/registry.d.ts +26 -0
- package/dist/src/registry.d.ts.map +1 -1
- package/dist/src/registry.js +19 -0
- package/dist/src/registry.js.map +1 -1
- package/dist/src/service.d.ts +16 -1
- package/dist/src/service.d.ts.map +1 -1
- package/dist/src/service.js +19 -1
- package/dist/src/service.js.map +1 -1
- package/dist/src/telescope_middleware.d.ts.map +1 -1
- package/dist/src/telescope_middleware.js +3 -1
- package/dist/src/telescope_middleware.js.map +1 -1
- package/dist/src/ui/api.d.ts +9 -1
- package/dist/src/ui/api.d.ts.map +1 -1
- package/dist/src/ui/api.js +23 -1
- package/dist/src/ui/api.js.map +1 -1
- package/dist/src/ui/auth.d.ts +112 -0
- package/dist/src/ui/auth.d.ts.map +1 -0
- package/dist/src/ui/auth.js +130 -0
- package/dist/src/ui/auth.js.map +1 -0
- package/dist/src/ui/dashboard_auth.d.ts +34 -0
- package/dist/src/ui/dashboard_auth.d.ts.map +1 -0
- package/dist/src/ui/dashboard_auth.js +57 -0
- package/dist/src/ui/dashboard_auth.js.map +1 -0
- package/dist/src/ui/define_config.d.ts +15 -0
- package/dist/src/ui/define_config.d.ts.map +1 -1
- package/dist/src/ui/define_config.js +4 -0
- package/dist/src/ui/define_config.js.map +1 -1
- package/dist/src/ui/index.d.ts +7 -1
- package/dist/src/ui/index.d.ts.map +1 -1
- package/dist/src/ui/index.js +6 -1
- package/dist/src/ui/index.js.map +1 -1
- package/dist/src/ui/login_page.d.ts +23 -0
- package/dist/src/ui/login_page.d.ts.map +1 -0
- package/dist/src/ui/login_page.js +170 -0
- package/dist/src/ui/login_page.js.map +1 -0
- package/dist/src/ui/session_cookie.d.ts +42 -0
- package/dist/src/ui/session_cookie.d.ts.map +1 -0
- package/dist/src/ui/session_cookie.js +97 -0
- package/dist/src/ui/session_cookie.js.map +1 -0
- package/dist/src/watchers/define_config.d.ts +115 -12
- package/dist/src/watchers/define_config.d.ts.map +1 -1
- package/dist/src/watchers/define_config.js +48 -11
- package/dist/src/watchers/define_config.js.map +1 -1
- package/dist/src/watchers/http_client_watcher.d.ts +91 -31
- package/dist/src/watchers/http_client_watcher.d.ts.map +1 -1
- package/dist/src/watchers/http_client_watcher.js +161 -53
- package/dist/src/watchers/http_client_watcher.js.map +1 -1
- package/dist/src/watchers/index.d.ts +9 -5
- package/dist/src/watchers/index.d.ts.map +1 -1
- package/dist/src/watchers/index.js +6 -2
- package/dist/src/watchers/index.js.map +1 -1
- package/dist/src/watchers/lucid_query_watcher.d.ts +20 -2
- package/dist/src/watchers/lucid_query_watcher.d.ts.map +1 -1
- package/dist/src/watchers/lucid_query_watcher.js +44 -10
- package/dist/src/watchers/lucid_query_watcher.js.map +1 -1
- package/dist/src/watchers/profiling_watcher.d.ts +144 -0
- package/dist/src/watchers/profiling_watcher.d.ts.map +1 -0
- package/dist/src/watchers/profiling_watcher.js +231 -0
- package/dist/src/watchers/profiling_watcher.js.map +1 -0
- package/dist/src/watchers/query_family_hash.d.ts +7 -2
- package/dist/src/watchers/query_family_hash.d.ts.map +1 -1
- package/dist/src/watchers/query_family_hash.js +8 -3
- package/dist/src/watchers/query_family_hash.js.map +1 -1
- package/dist/src/watchers/record.d.ts.map +1 -1
- package/dist/src/watchers/record.js +4 -0
- package/dist/src/watchers/record.js.map +1 -1
- package/dist/src/watchers/schedule_watcher.d.ts +143 -0
- package/dist/src/watchers/schedule_watcher.d.ts.map +1 -0
- package/dist/src/watchers/schedule_watcher.js +195 -0
- package/dist/src/watchers/schedule_watcher.js.map +1 -0
- package/dist/stubs/config/telescope.stub +0 -65
- package/dist/stubs/config/telescope_ai.stub +0 -36
- package/dist/stubs/config/telescope_alerts.stub +0 -47
- package/dist/stubs/config/telescope_mcp.stub +0 -0
- package/dist/stubs/config/telescope_ui.stub +0 -53
- package/dist/stubs/config/telescope_watchers.stub +0 -41
- package/dist/stubs/database/migrations/create_telescope_entries_table.stub +2 -2
- package/package.json +12 -2
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { type Entry } from '../entry.js';
|
|
2
|
+
import type { MetricsService } from '../metrics/metrics_service.js';
|
|
3
|
+
import type { TelescopeService } from '../service.js';
|
|
4
|
+
import { type McpToolName } from './define_config.js';
|
|
5
|
+
/** JSON-RPC error code for an unauthorized request (there is no transport 401 in MCP). */
|
|
6
|
+
export declare const MCP_UNAUTHORIZED = -32001;
|
|
7
|
+
/** JSON-RPC "method not found". */
|
|
8
|
+
export declare const MCP_METHOD_NOT_FOUND = -32601;
|
|
9
|
+
/** JSON-RPC "internal error" — a tool handler threw. */
|
|
10
|
+
export declare const MCP_INTERNAL_ERROR = -32603;
|
|
11
|
+
/** One entry in the MCP tool catalogue (name + human description + JSON-Schema for args). */
|
|
12
|
+
export interface McpToolSpec {
|
|
13
|
+
name: McpToolName;
|
|
14
|
+
description: string;
|
|
15
|
+
inputSchema: {
|
|
16
|
+
type: 'object';
|
|
17
|
+
properties: Record<string, unknown>;
|
|
18
|
+
required?: string[];
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* The full tool catalogue. `tools/list` returns the subset the config enables;
|
|
23
|
+
* `tools/call` dispatches on `name`. Keep the descriptions agent-facing — they are
|
|
24
|
+
* what a coding agent (Claude Code, Cursor, …) reads to decide which tool to call.
|
|
25
|
+
*/
|
|
26
|
+
export declare const MCP_TOOLS: readonly McpToolSpec[];
|
|
27
|
+
/** A parsed JSON-RPC request body (all fields optional so a malformed body is handled, not thrown). */
|
|
28
|
+
export interface JsonRpcRequest {
|
|
29
|
+
jsonrpc?: string;
|
|
30
|
+
id?: string | number | null;
|
|
31
|
+
method?: string;
|
|
32
|
+
params?: {
|
|
33
|
+
protocolVersion?: string;
|
|
34
|
+
name?: string;
|
|
35
|
+
arguments?: Record<string, unknown>;
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
/** Optional AI diagnosis hook — resolves the diagnosis markdown, or `null` when AI is off. */
|
|
39
|
+
export type DiagnoseExceptionHook = (entry: Entry) => Promise<string | null> | string | null;
|
|
40
|
+
/** Construction deps for {@link TelescopeMcpServer}. */
|
|
41
|
+
export interface TelescopeMcpServerOptions {
|
|
42
|
+
/** Which tools this server exposes. Omit for all. */
|
|
43
|
+
tools?: ReadonlySet<McpToolName>;
|
|
44
|
+
/** `serverInfo` reported on `initialize`. */
|
|
45
|
+
serverInfo?: {
|
|
46
|
+
name: string;
|
|
47
|
+
version: string;
|
|
48
|
+
};
|
|
49
|
+
/**
|
|
50
|
+
* AI diagnosis hook backing `diagnose_exception`. When omitted, the tool reports
|
|
51
|
+
* that AI diagnosis is not configured (rather than failing), mirroring the
|
|
52
|
+
* default-open dashboard posture.
|
|
53
|
+
*/
|
|
54
|
+
diagnose?: DiagnoseExceptionHook;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* MCP (Model Context Protocol) server — a stateless JSON-RPC surface — so a coding
|
|
58
|
+
* agent can query the app's captured telemetry: "why is POST /checkout slow?" → the
|
|
59
|
+
* agent lists slow requests, pulls the trace waterfall, reads the queries.
|
|
60
|
+
*
|
|
61
|
+
* Hand-rolled JSON-RPC (no SDK dependency), backed by the SAME
|
|
62
|
+
* {@link TelescopeService} / {@link MetricsService} / Pulse APIs the dashboard uses,
|
|
63
|
+
* so analysis reads already-redacted, already-sampled stored entries — redaction is
|
|
64
|
+
* never bypassed. Idiomatic Adonis: a plain, testable class with no framework
|
|
65
|
+
* coupling; the provider owns the HTTP transport and the auth guard, and hands this
|
|
66
|
+
* server a pre-computed `authorized` flag per call.
|
|
67
|
+
*/
|
|
68
|
+
export declare class TelescopeMcpServer {
|
|
69
|
+
private readonly service;
|
|
70
|
+
private readonly metrics;
|
|
71
|
+
private readonly tools;
|
|
72
|
+
private readonly serverInfo;
|
|
73
|
+
private readonly diagnose;
|
|
74
|
+
constructor(service: TelescopeService, metrics: MetricsService, options?: TelescopeMcpServerOptions);
|
|
75
|
+
/** The enabled tool catalogue (what `tools/list` returns), in declaration order. */
|
|
76
|
+
toolCatalogue(): McpToolSpec[];
|
|
77
|
+
/**
|
|
78
|
+
* Handle one JSON-RPC request. `authorized` is the outcome of the transport's
|
|
79
|
+
* auth guard: when `false`, every method is refused with a JSON-RPC `-32001`
|
|
80
|
+
* error (MCP has no transport-level 401, so the denial rides inside the RPC
|
|
81
|
+
* envelope where a compliant client can read it). Notifications (no `id`) resolve
|
|
82
|
+
* to `null` — the caller answers `202` with no body.
|
|
83
|
+
*/
|
|
84
|
+
handle(body: JsonRpcRequest, authorized: boolean): Promise<unknown>;
|
|
85
|
+
private respond;
|
|
86
|
+
private fail;
|
|
87
|
+
private callTool;
|
|
88
|
+
}
|
|
89
|
+
//# sourceMappingURL=server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../../src/mcp/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,KAAK,KAAK,EAAE,MAAM,aAAa,CAAC;AACpD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AACpE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAEtD,OAAO,EAAkB,KAAK,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAQtE,0FAA0F;AAC1F,eAAO,MAAM,gBAAgB,SAAS,CAAC;AACvC,mCAAmC;AACnC,eAAO,MAAM,oBAAoB,SAAS,CAAC;AAC3C,wDAAwD;AACxD,eAAO,MAAM,kBAAkB,SAAS,CAAC;AAEzC,6FAA6F;AAC7F,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,WAAW,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE;QAAE,IAAI,EAAE,QAAQ,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;CAC3F;AAED;;;;GAIG;AACH,eAAO,MAAM,SAAS,EAAE,SAAS,WAAW,EAuE3C,CAAC;AAEF,uGAAuG;AACvG,MAAM,WAAW,cAAc;IAC7B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE;QACP,eAAe,CAAC,EAAE,MAAM,CAAC;QACzB,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;KACrC,CAAC;CACH;AAYD,8FAA8F;AAC9F,MAAM,MAAM,qBAAqB,GAAG,CAAC,KAAK,EAAE,KAAK,KAAK,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,GAAG,MAAM,GAAG,IAAI,CAAC;AAE7F,wDAAwD;AACxD,MAAM,WAAW,yBAAyB;IACxC,qDAAqD;IACrD,KAAK,CAAC,EAAE,WAAW,CAAC,WAAW,CAAC,CAAC;IACjC,6CAA6C;IAC7C,UAAU,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IAC/C;;;;OAIG;IACH,QAAQ,CAAC,EAAE,qBAAqB,CAAC;CAClC;AAED;;;;;;;;;;;GAWG;AACH,qBAAa,kBAAkB;IAM3B,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,OAAO;IAN1B,OAAO,CAAC,QAAQ,CAAC,KAAK,CAA2B;IACjD,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAoC;IAC/D,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAoC;gBAG1C,OAAO,EAAE,gBAAgB,EACzB,OAAO,EAAE,cAAc,EACxC,OAAO,GAAE,yBAA8B;IAOzC,oFAAoF;IACpF,aAAa,IAAI,WAAW,EAAE;IAI9B;;;;;;OAMG;IACG,MAAM,CAAC,IAAI,EAAE,cAAc,EAAE,UAAU,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC;IAgCzE,OAAO,CAAC,OAAO;IAIf,OAAO,CAAC,IAAI;YAIE,QAAQ;CAmEvB"}
|
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
import { EntryType } from '../entry.js';
|
|
2
|
+
import { MCP_TOOL_NAMES } from './define_config.js';
|
|
3
|
+
/** The MCP protocol revision this server advertises when a client omits its own. */
|
|
4
|
+
const PROTOCOL_VERSION = '2025-06-18';
|
|
5
|
+
const DEFAULT_LIST_LIMIT = 20;
|
|
6
|
+
const MAX_LIST_LIMIT = 100;
|
|
7
|
+
const DEFAULT_HEALTH_WINDOW_MS = 60 * 60_000;
|
|
8
|
+
/** JSON-RPC error code for an unauthorized request (there is no transport 401 in MCP). */
|
|
9
|
+
export const MCP_UNAUTHORIZED = -32001;
|
|
10
|
+
/** JSON-RPC "method not found". */
|
|
11
|
+
export const MCP_METHOD_NOT_FOUND = -32601;
|
|
12
|
+
/** JSON-RPC "internal error" — a tool handler threw. */
|
|
13
|
+
export const MCP_INTERNAL_ERROR = -32603;
|
|
14
|
+
/**
|
|
15
|
+
* The full tool catalogue. `tools/list` returns the subset the config enables;
|
|
16
|
+
* `tools/call` dispatches on `name`. Keep the descriptions agent-facing — they are
|
|
17
|
+
* what a coding agent (Claude Code, Cursor, …) reads to decide which tool to call.
|
|
18
|
+
*/
|
|
19
|
+
export const MCP_TOOLS = [
|
|
20
|
+
{
|
|
21
|
+
name: 'list_entries',
|
|
22
|
+
description: 'List recent telescope entries (requests, queries, exceptions, diagnostics, jobs, logs, …). Filter by type, full-text search, tag, or time window. Returns newest first.',
|
|
23
|
+
inputSchema: {
|
|
24
|
+
type: 'object',
|
|
25
|
+
properties: {
|
|
26
|
+
type: {
|
|
27
|
+
type: 'string',
|
|
28
|
+
description: 'Entry type: request, query, exception, client_exception, log, event, mail, job, cache, http-client, redis, diagnostic…',
|
|
29
|
+
},
|
|
30
|
+
search: { type: 'string', description: 'Case-insensitive substring over entry content + tags' },
|
|
31
|
+
tag: { type: 'string', description: 'Exact tag match, e.g. "status:500" or "lib:billing"' },
|
|
32
|
+
sinceMinutes: { type: 'number', description: 'Only entries from the last N minutes' },
|
|
33
|
+
limit: { type: 'number', description: 'Max entries (default 20, max 100)' },
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
name: 'get_entry',
|
|
39
|
+
description: 'Get one entry by id, together with the other entries recorded in the same trace (its siblings) — the request/job waterfall context.',
|
|
40
|
+
inputSchema: {
|
|
41
|
+
type: 'object',
|
|
42
|
+
properties: { id: { type: 'string', description: 'Entry id' } },
|
|
43
|
+
required: ['id'],
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
name: 'get_trace',
|
|
48
|
+
description: 'Get every entry recorded under one trace id (one request/job execution), newest-first — queries, logs, diagnostics, the request itself.',
|
|
49
|
+
inputSchema: {
|
|
50
|
+
type: 'object',
|
|
51
|
+
properties: { traceId: { type: 'string', description: 'Trace id' } },
|
|
52
|
+
required: ['traceId'],
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
name: 'get_waterfall',
|
|
57
|
+
description: 'Get the span waterfall for one trace: each recorded operation as a start/duration span, ordered, so you can see what ran (and how long) inside a request.',
|
|
58
|
+
inputSchema: {
|
|
59
|
+
type: 'object',
|
|
60
|
+
properties: { traceId: { type: 'string', description: 'Trace id' } },
|
|
61
|
+
required: ['traceId'],
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
name: 'get_health',
|
|
66
|
+
description: 'Aggregate Pulse health snapshot over a trailing window (default 1h): request throughput + latency percentiles, slowest requests/queries, slow-route/outgoing/job hotspots, N+1 suspects, top exception families, cache hit rate, load-by-user.',
|
|
67
|
+
inputSchema: {
|
|
68
|
+
type: 'object',
|
|
69
|
+
properties: {
|
|
70
|
+
sinceMinutes: { type: 'number', description: 'Trailing window in minutes (default 60)' },
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
name: 'diagnose_exception',
|
|
76
|
+
description: 'Run the AI diagnosis on an exception entry (probable cause, where to look, suggested fix). Only available when AI diagnosis is configured on this telescope.',
|
|
77
|
+
inputSchema: {
|
|
78
|
+
type: 'object',
|
|
79
|
+
properties: { id: { type: 'string', description: 'Exception entry id' } },
|
|
80
|
+
required: ['id'],
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
];
|
|
84
|
+
/**
|
|
85
|
+
* MCP (Model Context Protocol) server — a stateless JSON-RPC surface — so a coding
|
|
86
|
+
* agent can query the app's captured telemetry: "why is POST /checkout slow?" → the
|
|
87
|
+
* agent lists slow requests, pulls the trace waterfall, reads the queries.
|
|
88
|
+
*
|
|
89
|
+
* Hand-rolled JSON-RPC (no SDK dependency), backed by the SAME
|
|
90
|
+
* {@link TelescopeService} / {@link MetricsService} / Pulse APIs the dashboard uses,
|
|
91
|
+
* so analysis reads already-redacted, already-sampled stored entries — redaction is
|
|
92
|
+
* never bypassed. Idiomatic Adonis: a plain, testable class with no framework
|
|
93
|
+
* coupling; the provider owns the HTTP transport and the auth guard, and hands this
|
|
94
|
+
* server a pre-computed `authorized` flag per call.
|
|
95
|
+
*/
|
|
96
|
+
export class TelescopeMcpServer {
|
|
97
|
+
service;
|
|
98
|
+
metrics;
|
|
99
|
+
tools;
|
|
100
|
+
serverInfo;
|
|
101
|
+
diagnose;
|
|
102
|
+
constructor(service, metrics, options = {}) {
|
|
103
|
+
this.service = service;
|
|
104
|
+
this.metrics = metrics;
|
|
105
|
+
this.tools = options.tools ?? new Set(MCP_TOOL_NAMES);
|
|
106
|
+
this.serverInfo = options.serverInfo ?? { name: 'adonis-telescope', version: '0.0.0' };
|
|
107
|
+
this.diagnose = options.diagnose;
|
|
108
|
+
}
|
|
109
|
+
/** The enabled tool catalogue (what `tools/list` returns), in declaration order. */
|
|
110
|
+
toolCatalogue() {
|
|
111
|
+
return MCP_TOOLS.filter((tool) => this.tools.has(tool.name));
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Handle one JSON-RPC request. `authorized` is the outcome of the transport's
|
|
115
|
+
* auth guard: when `false`, every method is refused with a JSON-RPC `-32001`
|
|
116
|
+
* error (MCP has no transport-level 401, so the denial rides inside the RPC
|
|
117
|
+
* envelope where a compliant client can read it). Notifications (no `id`) resolve
|
|
118
|
+
* to `null` — the caller answers `202` with no body.
|
|
119
|
+
*/
|
|
120
|
+
async handle(body, authorized) {
|
|
121
|
+
const { id, method, params } = body ?? {};
|
|
122
|
+
if (!authorized) {
|
|
123
|
+
return this.fail(id, MCP_UNAUTHORIZED, 'Unauthorized: telescope MCP access was denied.');
|
|
124
|
+
}
|
|
125
|
+
try {
|
|
126
|
+
switch (method) {
|
|
127
|
+
case 'initialize':
|
|
128
|
+
return this.respond(id, {
|
|
129
|
+
protocolVersion: params?.protocolVersion ?? PROTOCOL_VERSION,
|
|
130
|
+
capabilities: { tools: {} },
|
|
131
|
+
serverInfo: this.serverInfo,
|
|
132
|
+
});
|
|
133
|
+
case 'notifications/initialized':
|
|
134
|
+
case 'notifications/cancelled':
|
|
135
|
+
return null;
|
|
136
|
+
case 'ping':
|
|
137
|
+
return this.respond(id, {});
|
|
138
|
+
case 'tools/list':
|
|
139
|
+
return this.respond(id, { tools: this.toolCatalogue() });
|
|
140
|
+
case 'tools/call': {
|
|
141
|
+
const text = await this.callTool(params?.name, (params?.arguments ?? {}));
|
|
142
|
+
return this.respond(id, { content: [{ type: 'text', text }] });
|
|
143
|
+
}
|
|
144
|
+
default:
|
|
145
|
+
return this.fail(id, MCP_METHOD_NOT_FOUND, `Method not found: ${String(method)}`);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
catch (error) {
|
|
149
|
+
return this.fail(id, MCP_INTERNAL_ERROR, error instanceof Error ? error.message : String(error));
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
respond(id, result) {
|
|
153
|
+
return id === undefined || id === null ? null : { jsonrpc: '2.0', id, result };
|
|
154
|
+
}
|
|
155
|
+
fail(id, code, message) {
|
|
156
|
+
return id === undefined || id === null ? null : { jsonrpc: '2.0', id, error: { code, message } };
|
|
157
|
+
}
|
|
158
|
+
async callTool(name, args) {
|
|
159
|
+
if (name !== undefined && !this.tools.has(name)) {
|
|
160
|
+
throw new Error(`Tool not enabled: ${name}`);
|
|
161
|
+
}
|
|
162
|
+
switch (name) {
|
|
163
|
+
case 'list_entries': {
|
|
164
|
+
const query = {
|
|
165
|
+
...(args.type !== undefined ? { type: args.type } : {}),
|
|
166
|
+
...(args.search !== undefined && args.search !== '' ? { search: args.search } : {}),
|
|
167
|
+
...(args.tag !== undefined ? { tag: args.tag } : {}),
|
|
168
|
+
...(typeof args.sinceMinutes === 'number'
|
|
169
|
+
? { after: new Date(Date.now() - args.sinceMinutes * 60_000) }
|
|
170
|
+
: {}),
|
|
171
|
+
limit: clampLimit(args.limit),
|
|
172
|
+
};
|
|
173
|
+
const entries = await this.service.list(query);
|
|
174
|
+
return json({ entries: entries.map(slim) });
|
|
175
|
+
}
|
|
176
|
+
case 'get_entry': {
|
|
177
|
+
if (typeof args.id !== 'string')
|
|
178
|
+
throw new Error('`id` is required.');
|
|
179
|
+
const entry = await this.service.find(args.id);
|
|
180
|
+
if (entry === null)
|
|
181
|
+
return 'Entry not found (it may have been pruned).';
|
|
182
|
+
const siblings = entry.traceId !== null
|
|
183
|
+
? (await this.service.byTrace(entry.traceId)).filter((e) => e.id !== entry.id)
|
|
184
|
+
: [];
|
|
185
|
+
return json({ entry, trace: siblings.map(slim) });
|
|
186
|
+
}
|
|
187
|
+
case 'get_trace': {
|
|
188
|
+
if (typeof args.traceId !== 'string')
|
|
189
|
+
throw new Error('`traceId` is required.');
|
|
190
|
+
const entries = await this.service.byTrace(args.traceId);
|
|
191
|
+
if (entries.length === 0)
|
|
192
|
+
return 'Trace not found (it may have been pruned).';
|
|
193
|
+
return json({ entries });
|
|
194
|
+
}
|
|
195
|
+
case 'get_waterfall': {
|
|
196
|
+
if (typeof args.traceId !== 'string')
|
|
197
|
+
throw new Error('`traceId` is required.');
|
|
198
|
+
const waterfall = await this.metrics.getWaterfall(args.traceId);
|
|
199
|
+
if (waterfall === null)
|
|
200
|
+
return 'Trace not found (it may have been pruned).';
|
|
201
|
+
return json(waterfall);
|
|
202
|
+
}
|
|
203
|
+
case 'get_health': {
|
|
204
|
+
const windowMs = typeof args.sinceMinutes === 'number' && args.sinceMinutes > 0
|
|
205
|
+
? args.sinceMinutes * 60_000
|
|
206
|
+
: DEFAULT_HEALTH_WINDOW_MS;
|
|
207
|
+
const health = await this.service.getHealth({ windowMs });
|
|
208
|
+
return json(health);
|
|
209
|
+
}
|
|
210
|
+
case 'diagnose_exception': {
|
|
211
|
+
if (typeof args.id !== 'string')
|
|
212
|
+
throw new Error('`id` is required.');
|
|
213
|
+
if (this.diagnose === undefined) {
|
|
214
|
+
return 'AI diagnosis is not configured on this telescope.';
|
|
215
|
+
}
|
|
216
|
+
const entry = await this.service.find(args.id);
|
|
217
|
+
if (entry === null ||
|
|
218
|
+
(entry.type !== EntryType.Exception && entry.type !== EntryType.ClientException)) {
|
|
219
|
+
return 'No exception entry with that id.';
|
|
220
|
+
}
|
|
221
|
+
const markdown = await this.diagnose(entry);
|
|
222
|
+
return markdown ?? 'AI diagnosis returned no result.';
|
|
223
|
+
}
|
|
224
|
+
default:
|
|
225
|
+
throw new Error(`Unknown tool: ${String(name)}`);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
function json(value) {
|
|
230
|
+
return JSON.stringify(value, null, 2);
|
|
231
|
+
}
|
|
232
|
+
function clampLimit(limit) {
|
|
233
|
+
if (typeof limit !== 'number' || !Number.isFinite(limit))
|
|
234
|
+
return DEFAULT_LIST_LIMIT;
|
|
235
|
+
return Math.max(1, Math.min(Math.floor(limit), MAX_LIST_LIMIT));
|
|
236
|
+
}
|
|
237
|
+
/** Compact projection for list payloads — agents drill in via `get_entry`/`get_trace`. */
|
|
238
|
+
function slim(entry) {
|
|
239
|
+
const c = (entry.content ?? {});
|
|
240
|
+
let summary;
|
|
241
|
+
switch (entry.type) {
|
|
242
|
+
case EntryType.Request:
|
|
243
|
+
summary = `${String(c.method)} ${String(c.url)} → ${String(c.status)}`;
|
|
244
|
+
break;
|
|
245
|
+
case EntryType.Query:
|
|
246
|
+
summary = String(c.sql ?? '').slice(0, 200);
|
|
247
|
+
break;
|
|
248
|
+
case EntryType.Exception:
|
|
249
|
+
case EntryType.ClientException:
|
|
250
|
+
summary = `${String(c.name ?? c.class)}: ${String(c.message)}`;
|
|
251
|
+
break;
|
|
252
|
+
case EntryType.Log:
|
|
253
|
+
summary = `${String(c.level)}: ${String(c.message)}`;
|
|
254
|
+
break;
|
|
255
|
+
case EntryType.Job:
|
|
256
|
+
summary = `${String(c.name)} (${String(c.status)})`;
|
|
257
|
+
break;
|
|
258
|
+
default:
|
|
259
|
+
summary = safeSummary(c, entry.type);
|
|
260
|
+
}
|
|
261
|
+
return {
|
|
262
|
+
id: entry.id,
|
|
263
|
+
type: entry.type,
|
|
264
|
+
traceId: entry.traceId,
|
|
265
|
+
durationMs: entry.durationMs,
|
|
266
|
+
createdAt: entry.createdAt instanceof Date ? entry.createdAt.toISOString() : entry.createdAt,
|
|
267
|
+
tags: entry.tags,
|
|
268
|
+
summary,
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
function safeSummary(content, type) {
|
|
272
|
+
try {
|
|
273
|
+
return JSON.stringify(content).slice(0, 200);
|
|
274
|
+
}
|
|
275
|
+
catch {
|
|
276
|
+
return type;
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../../src/mcp/server.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import { type Entry } from '../entry.js';
|
|
2
|
+
import type { TelescopeStore } from '../store.js';
|
|
3
|
+
import { type CacheStats, type LatencyStats, type StatusBreakdown } from './stats.js';
|
|
4
|
+
import { type TimeseriesReport } from './timeseries.js';
|
|
5
|
+
/** The togglable pulse cards. `counts` and the window meta are always present. */
|
|
6
|
+
export declare const PULSE_CARDS: readonly ["throughput", "requests", "cache", "slowest", "slowRoutes", "slowOutgoing", "slowJobs", "exceptions", "nPlusOne", "loadByUser"];
|
|
7
|
+
export type PulseCardName = (typeof PULSE_CARDS)[number];
|
|
8
|
+
/** A single slow entry across all types, labelled from its content. */
|
|
9
|
+
export interface PulseSlowEntry {
|
|
10
|
+
id: string;
|
|
11
|
+
type: string;
|
|
12
|
+
durationMs: number;
|
|
13
|
+
label: string;
|
|
14
|
+
traceId: string | null;
|
|
15
|
+
}
|
|
16
|
+
/** A grouped exception family (mirrors {@link summarizeStats}'s exception groups). */
|
|
17
|
+
export interface PulseExceptionGroup {
|
|
18
|
+
key: string;
|
|
19
|
+
class: string;
|
|
20
|
+
message: string;
|
|
21
|
+
count: number;
|
|
22
|
+
/** ISO timestamp of the most recent occurrence in the window. */
|
|
23
|
+
lastSeen: string;
|
|
24
|
+
}
|
|
25
|
+
/** A consistently-slow family (request route, outgoing target, or job), by p99. */
|
|
26
|
+
export interface PulseHotspot {
|
|
27
|
+
/** The family label — the entry's `familyHash` (or a content-derived fallback). */
|
|
28
|
+
route: string;
|
|
29
|
+
count: number;
|
|
30
|
+
p99: number;
|
|
31
|
+
p50: number;
|
|
32
|
+
}
|
|
33
|
+
/** An N+1 query hotspot aggregated across traces. */
|
|
34
|
+
export interface PulseNPlusOne {
|
|
35
|
+
familyHash: string;
|
|
36
|
+
sql: string;
|
|
37
|
+
/** Worst (max) repetition count of this family within a single trace. */
|
|
38
|
+
perRequest: number;
|
|
39
|
+
/** Number of distinct traces where this family tripped the threshold. */
|
|
40
|
+
traces: number;
|
|
41
|
+
/** Sum of repetition counts across those traces. */
|
|
42
|
+
total: number;
|
|
43
|
+
/** Total duration (ms) spent across all occurrences — the time "wasted" in the loop. */
|
|
44
|
+
totalDurationMs: number;
|
|
45
|
+
/** One trace id (the worst) to deep-link to. */
|
|
46
|
+
sampleTraceId: string;
|
|
47
|
+
}
|
|
48
|
+
/** A user's share of the load in the window (from the `user:<id>` request tag). */
|
|
49
|
+
export interface PulseUserLoad {
|
|
50
|
+
user: string;
|
|
51
|
+
count: number;
|
|
52
|
+
totalDurationMs: number;
|
|
53
|
+
}
|
|
54
|
+
/** Overall throughput over the window. */
|
|
55
|
+
export interface PulseThroughput {
|
|
56
|
+
/** Entries recorded in the window. */
|
|
57
|
+
total: number;
|
|
58
|
+
/** Entries per minute across the window. */
|
|
59
|
+
perMinute: number;
|
|
60
|
+
/** Per-bucket throughput — reuses {@link bucketTimeseries}. */
|
|
61
|
+
overTime: TimeseriesReport;
|
|
62
|
+
}
|
|
63
|
+
/** Request health: volume, error rate, HTTP status breakdown, and latency. */
|
|
64
|
+
export interface PulseRequestHealth {
|
|
65
|
+
total: number;
|
|
66
|
+
/** Share of requests that returned a 4xx or 5xx (`0`–`1`). */
|
|
67
|
+
errorRate: number;
|
|
68
|
+
status: StatusBreakdown;
|
|
69
|
+
/** Present only when at least one request carried a `durationMs`. */
|
|
70
|
+
latency?: LatencyStats;
|
|
71
|
+
}
|
|
72
|
+
/** The aggregated pulse rollup returned by {@link PulseService.getHealth}. */
|
|
73
|
+
export interface PulseSummary {
|
|
74
|
+
windowStart: string;
|
|
75
|
+
windowEnd: string;
|
|
76
|
+
windowMs: number;
|
|
77
|
+
/** Per-type entry counts over the window. */
|
|
78
|
+
counts: Record<string, number>;
|
|
79
|
+
throughput: PulseThroughput;
|
|
80
|
+
requests: PulseRequestHealth;
|
|
81
|
+
/** Present only when the `cache` card is enabled and cache entries exist. */
|
|
82
|
+
cache?: CacheStats;
|
|
83
|
+
slowest: PulseSlowEntry[];
|
|
84
|
+
slowRoutes: PulseHotspot[];
|
|
85
|
+
slowOutgoing: PulseHotspot[];
|
|
86
|
+
slowJobs: PulseHotspot[];
|
|
87
|
+
topExceptions: PulseExceptionGroup[];
|
|
88
|
+
nPlusOne: PulseNPlusOne[];
|
|
89
|
+
loadByUser: PulseUserLoad[];
|
|
90
|
+
/** Entries scanned to build this summary. */
|
|
91
|
+
scanned: number;
|
|
92
|
+
/** Whether the scan hit its cap (results may be incomplete). */
|
|
93
|
+
truncated: boolean;
|
|
94
|
+
}
|
|
95
|
+
/** Fully-resolved pulse options the pure aggregator acts on. */
|
|
96
|
+
export interface PulseOptions {
|
|
97
|
+
topN: number;
|
|
98
|
+
buckets: number;
|
|
99
|
+
slowMs: number;
|
|
100
|
+
slowRouteMs: number;
|
|
101
|
+
hotspotMinCount: number;
|
|
102
|
+
nPlusOneThreshold: number;
|
|
103
|
+
cards: ReadonlySet<PulseCardName>;
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Aggregate a window of entries — each carrying its `content` — into a
|
|
107
|
+
* {@link PulseSummary}. Pure: callers fetch the windowed entries and supply the
|
|
108
|
+
* window bounds. Reuses {@link summarizeStats}, {@link bucketTimeseries},
|
|
109
|
+
* {@link percentile}, and {@link detectNPlusOne} for the heavy lifting.
|
|
110
|
+
*/
|
|
111
|
+
export declare function summarizePulse(entries: Entry[], windowStart: Date, windowEnd: Date, options: PulseOptions, truncated?: boolean): PulseSummary;
|
|
112
|
+
/** Per-call / per-instance pulse tuning (all optional; sensible defaults). */
|
|
113
|
+
export interface PulseServiceOptions {
|
|
114
|
+
/** Trailing window (ms) the summary aggregates over. Default 3_600_000 (1h). */
|
|
115
|
+
windowMs?: number;
|
|
116
|
+
/** How many rows each top-N list returns. Default 5. */
|
|
117
|
+
topN?: number;
|
|
118
|
+
/** Throughput/over-time bucket count. Default 60 (clamped 1–500). */
|
|
119
|
+
buckets?: number;
|
|
120
|
+
/** Latency "slow" threshold (ms). Default 100. */
|
|
121
|
+
slowMs?: number;
|
|
122
|
+
/** Min p99 (ms) for a route/outgoing family to count as a hotspot. Default 1000. */
|
|
123
|
+
slowRouteMs?: number;
|
|
124
|
+
/** Min samples a family needs to rank as a hotspot. Default 1. */
|
|
125
|
+
hotspotMinCount?: number;
|
|
126
|
+
/** Min repetitions of one query template within a trace to flag N+1. Default 5. */
|
|
127
|
+
nPlusOneThreshold?: number;
|
|
128
|
+
/** Which cards to compute. Omit for all. */
|
|
129
|
+
cards?: readonly PulseCardName[];
|
|
130
|
+
/** Safety cap on entries scanned per pulse. Default 50000. */
|
|
131
|
+
scanCap?: number;
|
|
132
|
+
}
|
|
133
|
+
/** A per-call override of the window (and, optionally, top-N). */
|
|
134
|
+
export interface PulseQuery {
|
|
135
|
+
windowMs?: number;
|
|
136
|
+
topN?: number;
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Read-only Pulse rollup over a {@link TelescopeStore}. Storage-agnostic — it
|
|
140
|
+
* reads the store (the source of truth) on demand through the newest-first
|
|
141
|
+
* {@link TelescopeStore.list} contract, never a specific provider, and never a
|
|
142
|
+
* live counter. Analysis reads ALREADY-redacted stored entries, so redaction is
|
|
143
|
+
* never bypassed. Idiomatic Adonis: a plain class, no DI decorators (constructed
|
|
144
|
+
* by the provider / {@link TelescopeService}, exactly like {@link import('./metrics_service.js').MetricsService}).
|
|
145
|
+
*/
|
|
146
|
+
export declare class PulseService {
|
|
147
|
+
private readonly store;
|
|
148
|
+
private readonly windowMs;
|
|
149
|
+
private readonly scanCap;
|
|
150
|
+
private readonly base;
|
|
151
|
+
constructor(store: TelescopeStore, options?: PulseServiceOptions);
|
|
152
|
+
/**
|
|
153
|
+
* Build the health snapshot over the trailing window. `query.windowMs` /
|
|
154
|
+
* `query.topN` override the configured defaults for a single call.
|
|
155
|
+
*/
|
|
156
|
+
getHealth(query?: PulseQuery): Promise<PulseSummary>;
|
|
157
|
+
}
|
|
158
|
+
//# sourceMappingURL=pulse.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pulse.d.ts","sourceRoot":"","sources":["../../../src/metrics/pulse.ts"],"names":[],"mappings":"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"}
|