@kryptosai/mcp-observatory 0.12.0 → 0.14.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.
@@ -0,0 +1,301 @@
1
+ /**
2
+ * Smithery Registry Integration
3
+ *
4
+ * Generates health-score submissions for the Smithery MCP server registry
5
+ * and resolves Smithery server listings into Observatory target configs.
6
+ */
7
+ import { generateBadgeSvg } from "../badge.js";
8
+ import { computeHealthScore } from "../score.js";
9
+ // ── Constants ───────────────────────────────────────────────────────────────
10
+ const DEFAULT_BASE_URL = "https://registry.smithery.ai";
11
+ const REQUEST_TIMEOUT_MS = 15_000;
12
+ const RATE_LIMIT_DELAY_MS = 1_500;
13
+ // ── Helpers ─────────────────────────────────────────────────────────────────
14
+ function baseUrl(config) {
15
+ return config?.baseUrl?.replace(/\/+$/, "") ?? DEFAULT_BASE_URL;
16
+ }
17
+ function buildHeaders(config) {
18
+ const headers = {
19
+ Accept: "application/json",
20
+ "User-Agent": "mcp-observatory/smithery-integration",
21
+ };
22
+ if (config?.apiKey) {
23
+ headers["Authorization"] = `Bearer ${config.apiKey}`;
24
+ }
25
+ return headers;
26
+ }
27
+ async function fetchJson(url, config) {
28
+ const controller = new AbortController();
29
+ const timer = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);
30
+ try {
31
+ const response = await fetch(url, {
32
+ headers: buildHeaders(config),
33
+ signal: controller.signal,
34
+ });
35
+ if (response.status === 429) {
36
+ throw new SmitheryRateLimitError("Smithery API rate limit exceeded. Please wait before retrying.");
37
+ }
38
+ if (!response.ok) {
39
+ throw new SmitheryApiError(`Smithery API returned ${response.status}: ${response.statusText}`, response.status);
40
+ }
41
+ return (await response.json());
42
+ }
43
+ finally {
44
+ clearTimeout(timer);
45
+ }
46
+ }
47
+ /** Sleep helper for rate-limiting between batch requests. */
48
+ function sleep(ms) {
49
+ return new Promise((resolve) => setTimeout(resolve, ms));
50
+ }
51
+ // ── Errors ──────────────────────────────────────────────────────────────────
52
+ export class SmitheryApiError extends Error {
53
+ statusCode;
54
+ constructor(message, statusCode) {
55
+ super(message);
56
+ this.statusCode = statusCode;
57
+ this.name = "SmitheryApiError";
58
+ }
59
+ }
60
+ export class SmitheryRateLimitError extends SmitheryApiError {
61
+ constructor(message) {
62
+ super(message, 429);
63
+ this.name = "SmitheryRateLimitError";
64
+ }
65
+ }
66
+ // ── Core Functions ──────────────────────────────────────────────────────────
67
+ /**
68
+ * Generate a submission report for a server.
69
+ * Creates a structured JSON report that could be submitted to Smithery's API
70
+ * or included in a PR to their repository.
71
+ */
72
+ export function generateSubmission(qualifiedName, artifact) {
73
+ const score = artifact.healthScore ?? computeHealthScore(artifact.checks, artifact.performanceMetrics);
74
+ const badgeSvg = generateBadgeSvg({
75
+ label: "MCP Health",
76
+ score: score.overall,
77
+ grade: score.grade,
78
+ });
79
+ return {
80
+ qualifiedName,
81
+ artifact,
82
+ score,
83
+ badgeSvg,
84
+ submittedAt: new Date().toISOString(),
85
+ };
86
+ }
87
+ /**
88
+ * Render a submission as markdown suitable for a Smithery integration PR.
89
+ */
90
+ export function renderSubmissionMarkdown(submission) {
91
+ const { qualifiedName, artifact, score } = submission;
92
+ const lines = [];
93
+ lines.push(`# MCP Observatory Report: ${qualifiedName}`);
94
+ lines.push("");
95
+ lines.push(`> Scanned at ${artifact.createdAt} by MCP Observatory v${artifact.toolVersion}`);
96
+ lines.push("");
97
+ // Badge (data URI)
98
+ const encodedSvg = Buffer.from(submission.badgeSvg).toString("base64");
99
+ lines.push(`![MCP Health Score](data:image/svg+xml;base64,${encodedSvg})`);
100
+ lines.push("");
101
+ // Overall score
102
+ lines.push("## Health Score");
103
+ lines.push("");
104
+ lines.push(`| Metric | Value |`);
105
+ lines.push(`|--------|-------|`);
106
+ lines.push(`| **Overall Score** | ${score.overall}/100 |`);
107
+ lines.push(`| **Grade** | ${score.grade} |`);
108
+ lines.push(`| **Gate** | ${artifact.gate} |`);
109
+ lines.push("");
110
+ // Dimensions
111
+ lines.push("## Score Breakdown");
112
+ lines.push("");
113
+ lines.push("| Dimension | Weight | Score | Details |");
114
+ lines.push("|-----------|--------|-------|---------|");
115
+ for (const dim of score.dimensions) {
116
+ const details = dim.details.join("; ");
117
+ lines.push(`| ${dim.name} | ${Math.round(dim.weight * 100)}% | ${dim.score}/100 | ${details} |`);
118
+ }
119
+ lines.push("");
120
+ // Individual checks
121
+ lines.push("## Check Results");
122
+ lines.push("");
123
+ lines.push("| Check | Status | Duration | Message |");
124
+ lines.push("|-------|--------|----------|---------|");
125
+ for (const check of artifact.checks) {
126
+ const icon = check.status === "pass" ? "pass" : check.status === "fail" ? "FAIL" : check.status;
127
+ lines.push(`| ${check.id} | ${icon} | ${check.durationMs}ms | ${check.message} |`);
128
+ }
129
+ lines.push("");
130
+ // Performance metrics
131
+ if (artifact.performanceMetrics) {
132
+ const pm = artifact.performanceMetrics;
133
+ lines.push("## Performance");
134
+ lines.push("");
135
+ lines.push(`- **Connect:** ${Math.round(pm.connectMs)}ms`);
136
+ if (pm.toolsListMs !== undefined)
137
+ lines.push(`- **tools/list:** ${Math.round(pm.toolsListMs)}ms`);
138
+ if (pm.promptsListMs !== undefined)
139
+ lines.push(`- **prompts/list:** ${Math.round(pm.promptsListMs)}ms`);
140
+ if (pm.resourcesListMs !== undefined)
141
+ lines.push(`- **resources/list:** ${Math.round(pm.resourcesListMs)}ms`);
142
+ lines.push("");
143
+ }
144
+ // Server info
145
+ lines.push("## Server Information");
146
+ lines.push("");
147
+ lines.push(`| Field | Value |`);
148
+ lines.push(`|-------|-------|`);
149
+ lines.push(`| **Target ID** | ${artifact.target.targetId} |`);
150
+ lines.push(`| **Adapter** | ${artifact.target.adapter} |`);
151
+ if (artifact.target.serverName) {
152
+ lines.push(`| **Server Name** | ${artifact.target.serverName} |`);
153
+ }
154
+ if (artifact.target.serverVersion) {
155
+ lines.push(`| **Server Version** | ${artifact.target.serverVersion} |`);
156
+ }
157
+ lines.push(`| **Platform** | ${artifact.environment.platform} |`);
158
+ lines.push(`| **Node** | ${artifact.environment.nodeVersion} |`);
159
+ lines.push("");
160
+ // Fatal errors
161
+ if (artifact.fatalError) {
162
+ lines.push("## Fatal Error");
163
+ lines.push("");
164
+ lines.push("```");
165
+ lines.push(artifact.fatalError);
166
+ lines.push("```");
167
+ lines.push("");
168
+ }
169
+ lines.push("---");
170
+ lines.push("*Generated by [MCP Observatory](https://github.com/anthropics/mcp-observatory)*");
171
+ return lines.join("\n");
172
+ }
173
+ /**
174
+ * Resolve a Smithery server listing to an Observatory target config.
175
+ * Fetches server metadata from Smithery and converts to TargetConfig.
176
+ */
177
+ export async function resolveSmitheryTarget(qualifiedName, config) {
178
+ const url = `${baseUrl(config)}/api/servers/${encodeURIComponent(qualifiedName)}`;
179
+ const entry = await fetchJson(url, config);
180
+ return serverEntryToTarget(entry);
181
+ }
182
+ /**
183
+ * Fetch a page of servers from the Smithery registry.
184
+ */
185
+ export async function listSmitheryServers(config, options) {
186
+ const params = new URLSearchParams();
187
+ if (options?.page !== undefined)
188
+ params.set("page", String(options.page));
189
+ if (options?.pageSize !== undefined)
190
+ params.set("pageSize", String(options.pageSize));
191
+ const qs = params.toString();
192
+ const url = `${baseUrl(config)}/api/servers${qs ? `?${qs}` : ""}`;
193
+ return fetchJson(url, config);
194
+ }
195
+ /**
196
+ * Batch-scan top N servers from the Smithery registry.
197
+ * Returns an array of submission results (or errors for individual servers).
198
+ */
199
+ export async function batchScanServers(runTargetFn, config, options) {
200
+ const top = options?.top ?? 10;
201
+ const listResponse = await listSmitheryServers(config, { pageSize: top });
202
+ const servers = listResponse.servers.slice(0, top);
203
+ const results = [];
204
+ for (const server of servers) {
205
+ try {
206
+ const target = serverEntryToTarget(server);
207
+ const artifact = await runTargetFn(target);
208
+ const submission = generateSubmission(server.qualifiedName, artifact);
209
+ results.push({ qualifiedName: server.qualifiedName, submission });
210
+ }
211
+ catch (err) {
212
+ results.push({
213
+ qualifiedName: server.qualifiedName,
214
+ error: err instanceof Error ? err.message : String(err),
215
+ });
216
+ }
217
+ // Rate-limit between scans
218
+ await sleep(RATE_LIMIT_DELAY_MS);
219
+ }
220
+ return results;
221
+ }
222
+ /**
223
+ * Render a batch scan report as markdown.
224
+ */
225
+ export function renderBatchReportMarkdown(results) {
226
+ const lines = [];
227
+ lines.push("# MCP Observatory — Smithery Batch Scan Report");
228
+ lines.push("");
229
+ lines.push(`> Scanned ${results.length} servers at ${new Date().toISOString()}`);
230
+ lines.push("");
231
+ // Summary table
232
+ const successful = results.filter((r) => r.submission);
233
+ const failed = results.filter((r) => r.error);
234
+ lines.push("## Summary");
235
+ lines.push("");
236
+ lines.push(`- **Scanned:** ${results.length}`);
237
+ lines.push(`- **Successful:** ${successful.length}`);
238
+ lines.push(`- **Failed:** ${failed.length}`);
239
+ lines.push("");
240
+ if (successful.length > 0) {
241
+ // Leaderboard
242
+ const sorted = successful
243
+ .map((r) => ({
244
+ name: r.qualifiedName,
245
+ score: r.submission.score.overall,
246
+ grade: r.submission.score.grade,
247
+ gate: r.submission.artifact.gate,
248
+ }))
249
+ .sort((a, b) => b.score - a.score);
250
+ lines.push("## Leaderboard");
251
+ lines.push("");
252
+ lines.push("| Rank | Server | Score | Grade | Gate |");
253
+ lines.push("|------|--------|-------|-------|------|");
254
+ sorted.forEach((s, i) => {
255
+ lines.push(`| ${i + 1} | ${s.name} | ${s.score}/100 | ${s.grade} | ${s.gate} |`);
256
+ });
257
+ lines.push("");
258
+ }
259
+ if (failed.length > 0) {
260
+ lines.push("## Errors");
261
+ lines.push("");
262
+ for (const f of failed) {
263
+ lines.push(`- **${f.qualifiedName}:** ${f.error}`);
264
+ }
265
+ lines.push("");
266
+ }
267
+ lines.push("---");
268
+ lines.push("*Generated by [MCP Observatory](https://github.com/anthropics/mcp-observatory)*");
269
+ return lines.join("\n");
270
+ }
271
+ // ── Internal Helpers ────────────────────────────────────────────────────────
272
+ function serverEntryToTarget(entry) {
273
+ // Check for HTTP/SSE connections first
274
+ const httpConn = entry.connections?.find((c) => c.type === "http" || c.type === "sse" || c.url);
275
+ if (httpConn?.url) {
276
+ return {
277
+ targetId: entry.qualifiedName,
278
+ adapter: "http",
279
+ url: httpConn.url,
280
+ timeoutMs: 15_000,
281
+ metadata: {
282
+ smitheryName: entry.qualifiedName,
283
+ ...(entry.displayName ? { displayName: entry.displayName } : {}),
284
+ },
285
+ };
286
+ }
287
+ // Fall back to npx-based local-process target using the qualified name.
288
+ // Smithery packages typically run via `npx @scope/package-name`.
289
+ return {
290
+ targetId: entry.qualifiedName,
291
+ adapter: "local-process",
292
+ command: "npx",
293
+ args: ["-y", entry.qualifiedName],
294
+ timeoutMs: 30_000,
295
+ metadata: {
296
+ smitheryName: entry.qualifiedName,
297
+ ...(entry.displayName ? { displayName: entry.displayName } : {}),
298
+ },
299
+ };
300
+ }
301
+ //# sourceMappingURL=smithery.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"smithery.js","sourceRoot":"","sources":["../../../src/integrations/smithery.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export { ObservatoryMonitor, type MonitorOptions, type MonitoredServer, type ServerStatus, } from "./monitor.js";
2
+ export { withObservatory, type WrapperOptions, } from "./wrapper.js";
@@ -0,0 +1,3 @@
1
+ export { ObservatoryMonitor, } from "./monitor.js";
2
+ export { withObservatory, } from "./wrapper.js";
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/runtime/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kBAAkB,GAInB,MAAM,cAAc,CAAC;AAEtB,OAAO,EACL,eAAe,GAEhB,MAAM,cAAc,CAAC"}
@@ -0,0 +1,68 @@
1
+ import { EventEmitter } from "node:events";
2
+ import type { ScoreWeights } from "../score.js";
3
+ import type { HealthGrade, HealthScore, TargetConfig } from "../types.js";
4
+ /** Options for configuring the ObservatoryMonitor. */
5
+ export interface MonitorOptions {
6
+ /** How often to check health (ms). Default: 60000 (1 min) */
7
+ intervalMs?: number;
8
+ /** Minimum score before triggering onDegraded. Default: 70 */
9
+ degradedThreshold?: number;
10
+ /** Minimum score before triggering onUnhealthy. Default: 40 */
11
+ unhealthyThreshold?: number;
12
+ /** Callback when score drops below degradedThreshold */
13
+ onDegraded?: (score: HealthScore, server: string) => void;
14
+ /** Callback when score drops below unhealthyThreshold */
15
+ onUnhealthy?: (score: HealthScore, server: string) => void;
16
+ /** Callback when score recovers above degradedThreshold */
17
+ onRecovered?: (score: HealthScore, server: string) => void;
18
+ /** Optional: report scores to a remote endpoint */
19
+ reportTo?: string;
20
+ /** Custom score weights */
21
+ weights?: Partial<ScoreWeights>;
22
+ }
23
+ export type ServerStatus = "healthy" | "degraded" | "unhealthy" | "unknown";
24
+ /** Represents a server being monitored with its current state and history. */
25
+ export interface MonitoredServer {
26
+ targetId: string;
27
+ lastScore?: HealthScore;
28
+ lastCheck?: Date;
29
+ status: ServerStatus;
30
+ history: Array<{
31
+ timestamp: Date;
32
+ score: number;
33
+ grade: HealthGrade;
34
+ }>;
35
+ }
36
+ /**
37
+ * Real-time monitor for MCP server health.
38
+ *
39
+ * Uses `runTarget()` and `computeHealthScore()` under the hood to periodically
40
+ * check servers and fire callbacks when health changes.
41
+ */
42
+ export declare class ObservatoryMonitor extends EventEmitter {
43
+ private readonly servers;
44
+ private readonly options;
45
+ private timer;
46
+ private disposed;
47
+ constructor(options?: MonitorOptions);
48
+ /** Add a server to monitor. */
49
+ addServer(target: TargetConfig): void;
50
+ /** Remove a server from monitoring. */
51
+ removeServer(targetId: string): void;
52
+ /** Get current status of all monitored servers. */
53
+ getStatus(): MonitoredServer[];
54
+ /** Get status of a specific server. */
55
+ getServerStatus(targetId: string): MonitoredServer | undefined;
56
+ /** Run an immediate health check on all servers. */
57
+ checkNow(): Promise<Map<string, HealthScore>>;
58
+ /** Start periodic monitoring. */
59
+ start(): void;
60
+ /** Stop periodic monitoring. */
61
+ stop(): void;
62
+ /** Dispose and clean up. */
63
+ dispose(): void;
64
+ private checkServer;
65
+ private classifyScore;
66
+ private fireCallbacks;
67
+ private reportScore;
68
+ }
@@ -0,0 +1,162 @@
1
+ import { EventEmitter } from "node:events";
2
+ import { runTarget } from "../runner.js";
3
+ import { computeHealthScore } from "../score.js";
4
+ const MAX_HISTORY = 100;
5
+ const DEFAULT_INTERVAL_MS = 60_000;
6
+ const DEFAULT_DEGRADED_THRESHOLD = 70;
7
+ const DEFAULT_UNHEALTHY_THRESHOLD = 40;
8
+ /**
9
+ * Real-time monitor for MCP server health.
10
+ *
11
+ * Uses `runTarget()` and `computeHealthScore()` under the hood to periodically
12
+ * check servers and fire callbacks when health changes.
13
+ */
14
+ export class ObservatoryMonitor extends EventEmitter {
15
+ servers = new Map();
16
+ options;
17
+ timer = null;
18
+ disposed = false;
19
+ constructor(options) {
20
+ super();
21
+ this.options = {
22
+ intervalMs: options?.intervalMs ?? DEFAULT_INTERVAL_MS,
23
+ degradedThreshold: options?.degradedThreshold ?? DEFAULT_DEGRADED_THRESHOLD,
24
+ unhealthyThreshold: options?.unhealthyThreshold ?? DEFAULT_UNHEALTHY_THRESHOLD,
25
+ ...options,
26
+ };
27
+ }
28
+ /** Add a server to monitor. */
29
+ addServer(target) {
30
+ if (this.disposed)
31
+ return;
32
+ if (this.servers.has(target.targetId))
33
+ return;
34
+ const state = {
35
+ targetId: target.targetId,
36
+ status: "unknown",
37
+ history: [],
38
+ };
39
+ this.servers.set(target.targetId, { target, state });
40
+ this.emit("serverAdded", target.targetId);
41
+ }
42
+ /** Remove a server from monitoring. */
43
+ removeServer(targetId) {
44
+ this.servers.delete(targetId);
45
+ this.emit("serverRemoved", targetId);
46
+ }
47
+ /** Get current status of all monitored servers. */
48
+ getStatus() {
49
+ return [...this.servers.values()].map((e) => ({ ...e.state }));
50
+ }
51
+ /** Get status of a specific server. */
52
+ getServerStatus(targetId) {
53
+ const entry = this.servers.get(targetId);
54
+ return entry ? { ...entry.state } : undefined;
55
+ }
56
+ /** Run an immediate health check on all servers. */
57
+ async checkNow() {
58
+ const results = new Map();
59
+ const entries = [...this.servers.values()];
60
+ await Promise.all(entries.map(async (entry) => {
61
+ const score = await this.checkServer(entry);
62
+ if (score) {
63
+ results.set(entry.target.targetId, score);
64
+ }
65
+ }));
66
+ return results;
67
+ }
68
+ /** Start periodic monitoring. */
69
+ start() {
70
+ if (this.disposed || this.timer !== null)
71
+ return;
72
+ this.timer = setInterval(() => {
73
+ void this.checkNow();
74
+ }, this.options.intervalMs);
75
+ this.emit("started");
76
+ }
77
+ /** Stop periodic monitoring. */
78
+ stop() {
79
+ if (this.timer !== null) {
80
+ clearInterval(this.timer);
81
+ this.timer = null;
82
+ this.emit("stopped");
83
+ }
84
+ }
85
+ /** Dispose and clean up. */
86
+ dispose() {
87
+ this.stop();
88
+ this.disposed = true;
89
+ this.servers.clear();
90
+ this.removeAllListeners();
91
+ }
92
+ // ---- internal ----
93
+ async checkServer(entry) {
94
+ const { target, state } = entry;
95
+ const previousStatus = state.status;
96
+ try {
97
+ const artifact = await runTarget(target);
98
+ const score = artifact.healthScore ??
99
+ computeHealthScore(artifact.checks, artifact.performanceMetrics, this.options.weights);
100
+ state.lastScore = score;
101
+ state.lastCheck = new Date();
102
+ // Append to history (capped at MAX_HISTORY)
103
+ state.history.push({
104
+ timestamp: state.lastCheck,
105
+ score: score.overall,
106
+ grade: score.grade,
107
+ });
108
+ if (state.history.length > MAX_HISTORY) {
109
+ state.history.splice(0, state.history.length - MAX_HISTORY);
110
+ }
111
+ // Determine new status
112
+ const newStatus = this.classifyScore(score.overall);
113
+ state.status = newStatus;
114
+ // Fire callbacks
115
+ this.fireCallbacks(previousStatus, newStatus, score, target.targetId);
116
+ // Report if configured
117
+ if (this.options.reportTo) {
118
+ void this.reportScore(score, target.targetId).catch(() => {
119
+ /* best-effort */
120
+ });
121
+ }
122
+ this.emit("check", target.targetId, score);
123
+ return score;
124
+ }
125
+ catch {
126
+ state.status = "unhealthy";
127
+ state.lastCheck = new Date();
128
+ this.emit("checkError", target.targetId);
129
+ return undefined;
130
+ }
131
+ }
132
+ classifyScore(overall) {
133
+ if (overall >= this.options.degradedThreshold)
134
+ return "healthy";
135
+ if (overall >= this.options.unhealthyThreshold)
136
+ return "degraded";
137
+ return "unhealthy";
138
+ }
139
+ fireCallbacks(previousStatus, newStatus, score, targetId) {
140
+ if (newStatus === "degraded" && previousStatus !== "degraded") {
141
+ this.options.onDegraded?.(score, targetId);
142
+ }
143
+ if (newStatus === "unhealthy" && previousStatus !== "unhealthy") {
144
+ this.options.onUnhealthy?.(score, targetId);
145
+ }
146
+ if (newStatus === "healthy" &&
147
+ (previousStatus === "degraded" || previousStatus === "unhealthy")) {
148
+ this.options.onRecovered?.(score, targetId);
149
+ }
150
+ }
151
+ async reportScore(score, targetId) {
152
+ const url = this.options.reportTo;
153
+ if (!url)
154
+ return;
155
+ await fetch(url, {
156
+ method: "POST",
157
+ headers: { "Content-Type": "application/json" },
158
+ body: JSON.stringify({ targetId, score, timestamp: new Date().toISOString() }),
159
+ });
160
+ }
161
+ }
162
+ //# sourceMappingURL=monitor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"monitor.js","sourceRoot":"","sources":["../../../src/runtime/monitor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ import type { TargetConfig } from "../types.js";
2
+ import { ObservatoryMonitor } from "./monitor.js";
3
+ import type { MonitorOptions } from "./monitor.js";
4
+ /** Options for the Observatory wrapper, extending monitor options with fallback support. */
5
+ export interface WrapperOptions extends MonitorOptions {
6
+ /** Automatically switch to fallback server if primary degrades */
7
+ fallbackTargets?: TargetConfig[];
8
+ }
9
+ /**
10
+ * Wrap a target with observatory monitoring.
11
+ *
12
+ * Returns an `ObservatoryMonitor` instance pre-configured with the target and
13
+ * optional fallback targets. The monitor is NOT started automatically; call
14
+ * `.monitor.start()` when ready.
15
+ *
16
+ * @example
17
+ * ```ts
18
+ * const { monitor, target } = withObservatory(
19
+ * { targetId: "my-server", adapter: "http", url: "http://localhost:3000" },
20
+ * { intervalMs: 30_000, onDegraded: (score) => console.warn("degraded", score) }
21
+ * );
22
+ * monitor.start();
23
+ * ```
24
+ */
25
+ export declare function withObservatory(target: TargetConfig, options?: WrapperOptions): {
26
+ monitor: ObservatoryMonitor;
27
+ target: TargetConfig;
28
+ };
@@ -0,0 +1,30 @@
1
+ import { ObservatoryMonitor } from "./monitor.js";
2
+ /**
3
+ * Wrap a target with observatory monitoring.
4
+ *
5
+ * Returns an `ObservatoryMonitor` instance pre-configured with the target and
6
+ * optional fallback targets. The monitor is NOT started automatically; call
7
+ * `.monitor.start()` when ready.
8
+ *
9
+ * @example
10
+ * ```ts
11
+ * const { monitor, target } = withObservatory(
12
+ * { targetId: "my-server", adapter: "http", url: "http://localhost:3000" },
13
+ * { intervalMs: 30_000, onDegraded: (score) => console.warn("degraded", score) }
14
+ * );
15
+ * monitor.start();
16
+ * ```
17
+ */
18
+ export function withObservatory(target, options) {
19
+ const monitor = new ObservatoryMonitor(options);
20
+ // Add the primary target
21
+ monitor.addServer(target);
22
+ // Add any fallback targets
23
+ if (options?.fallbackTargets) {
24
+ for (const fallback of options.fallbackTargets) {
25
+ monitor.addServer(fallback);
26
+ }
27
+ }
28
+ return { monitor, target };
29
+ }
30
+ //# sourceMappingURL=wrapper.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wrapper.js","sourceRoot":"","sources":["../../../src/runtime/wrapper.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AASlD;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,eAAe,CAC7B,MAAoB,EACpB,OAAwB;IAExB,MAAM,OAAO,GAAG,IAAI,kBAAkB,CAAC,OAAO,CAAC,CAAC;IAEhD,yBAAyB;IACzB,OAAO,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;IAE1B,2BAA2B;IAC3B,IAAI,OAAO,EAAE,eAAe,EAAE,CAAC;QAC7B,KAAK,MAAM,QAAQ,IAAI,OAAO,CAAC,eAAe,EAAE,CAAC;YAC/C,OAAO,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;QAC9B,CAAC;IACH,CAAC;IAED,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC;AAC7B,CAAC"}