@mcp-rating/gateway 0.2.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/LICENSE +21 -0
- package/README.md +130 -0
- package/dist/ads/ad-tracker.d.ts +63 -0
- package/dist/ads/ad-tracker.js +144 -0
- package/dist/ads/ad-tracker.js.map +1 -0
- package/dist/analytics/usage-tracker.d.ts +67 -0
- package/dist/analytics/usage-tracker.js +148 -0
- package/dist/analytics/usage-tracker.js.map +1 -0
- package/dist/audit/audit-log.d.ts +71 -0
- package/dist/audit/audit-log.js +72 -0
- package/dist/audit/audit-log.js.map +1 -0
- package/dist/config/gateway-config.d.ts +6 -0
- package/dist/config/gateway-config.js +135 -0
- package/dist/config/gateway-config.js.map +1 -0
- package/dist/config/groups.d.ts +29 -0
- package/dist/config/groups.js +102 -0
- package/dist/config/groups.js.map +1 -0
- package/dist/config/profiles.d.ts +42 -0
- package/dist/config/profiles.js +167 -0
- package/dist/config/profiles.js.map +1 -0
- package/dist/config/types.d.ts +76 -0
- package/dist/config/types.js +2 -0
- package/dist/config/types.js.map +1 -0
- package/dist/connection/auto-installer.d.ts +13 -0
- package/dist/connection/auto-installer.js +61 -0
- package/dist/connection/auto-installer.js.map +1 -0
- package/dist/connection/connection-manager.d.ts +106 -0
- package/dist/connection/connection-manager.js +845 -0
- package/dist/connection/connection-manager.js.map +1 -0
- package/dist/connection/downstream-client.d.ts +50 -0
- package/dist/connection/downstream-client.js +170 -0
- package/dist/connection/downstream-client.js.map +1 -0
- package/dist/connection/http-client.d.ts +12 -0
- package/dist/connection/http-client.js +26 -0
- package/dist/connection/http-client.js.map +1 -0
- package/dist/connection/sse-client.d.ts +12 -0
- package/dist/connection/sse-client.js +26 -0
- package/dist/connection/sse-client.js.map +1 -0
- package/dist/connection/transport-factory.d.ts +31 -0
- package/dist/connection/transport-factory.js +67 -0
- package/dist/connection/transport-factory.js.map +1 -0
- package/dist/connection/types.d.ts +134 -0
- package/dist/connection/types.js +5 -0
- package/dist/connection/types.js.map +1 -0
- package/dist/connection/ws-client.d.ts +12 -0
- package/dist/connection/ws-client.js +26 -0
- package/dist/connection/ws-client.js.map +1 -0
- package/dist/discovery/auto-recommender.d.ts +51 -0
- package/dist/discovery/auto-recommender.js +176 -0
- package/dist/discovery/auto-recommender.js.map +1 -0
- package/dist/gateway-server.d.ts +42 -0
- package/dist/gateway-server.js +135 -0
- package/dist/gateway-server.js.map +1 -0
- package/dist/http-daemon.d.ts +26 -0
- package/dist/http-daemon.js +302 -0
- package/dist/http-daemon.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +83 -0
- package/dist/index.js.map +1 -0
- package/dist/meta-tools/ad-status.d.ts +8 -0
- package/dist/meta-tools/ad-status.js +41 -0
- package/dist/meta-tools/ad-status.js.map +1 -0
- package/dist/meta-tools/audit.d.ts +12 -0
- package/dist/meta-tools/audit.js +98 -0
- package/dist/meta-tools/audit.js.map +1 -0
- package/dist/meta-tools/call-tool.d.ts +11 -0
- package/dist/meta-tools/call-tool.js +65 -0
- package/dist/meta-tools/call-tool.js.map +1 -0
- package/dist/meta-tools/connect.d.ts +3 -0
- package/dist/meta-tools/connect.js +105 -0
- package/dist/meta-tools/connect.js.map +1 -0
- package/dist/meta-tools/disconnect.d.ts +3 -0
- package/dist/meta-tools/disconnect.js +30 -0
- package/dist/meta-tools/disconnect.js.map +1 -0
- package/dist/meta-tools/discover.d.ts +3 -0
- package/dist/meta-tools/discover.js +97 -0
- package/dist/meta-tools/discover.js.map +1 -0
- package/dist/meta-tools/groups.d.ts +7 -0
- package/dist/meta-tools/groups.js +237 -0
- package/dist/meta-tools/groups.js.map +1 -0
- package/dist/meta-tools/health.d.ts +4 -0
- package/dist/meta-tools/health.js +76 -0
- package/dist/meta-tools/health.js.map +1 -0
- package/dist/meta-tools/index.d.ts +28 -0
- package/dist/meta-tools/index.js +56 -0
- package/dist/meta-tools/index.js.map +1 -0
- package/dist/meta-tools/list-active.d.ts +3 -0
- package/dist/meta-tools/list-active.js +50 -0
- package/dist/meta-tools/list-active.js.map +1 -0
- package/dist/meta-tools/profiles.d.ts +6 -0
- package/dist/meta-tools/profiles.js +197 -0
- package/dist/meta-tools/profiles.js.map +1 -0
- package/dist/meta-tools/recommend.d.ts +14 -0
- package/dist/meta-tools/recommend.js +74 -0
- package/dist/meta-tools/recommend.js.map +1 -0
- package/dist/meta-tools/sandbox.d.ts +12 -0
- package/dist/meta-tools/sandbox.js +125 -0
- package/dist/meta-tools/sandbox.js.map +1 -0
- package/dist/meta-tools/server-info.d.ts +4 -0
- package/dist/meta-tools/server-info.js +156 -0
- package/dist/meta-tools/server-info.js.map +1 -0
- package/dist/meta-tools/usage.d.ts +6 -0
- package/dist/meta-tools/usage.js +149 -0
- package/dist/meta-tools/usage.js.map +1 -0
- package/dist/permissions/permission-manager.d.ts +26 -0
- package/dist/permissions/permission-manager.js +73 -0
- package/dist/permissions/permission-manager.js.map +1 -0
- package/dist/permissions/trust-tiers.d.ts +18 -0
- package/dist/permissions/trust-tiers.js +42 -0
- package/dist/permissions/trust-tiers.js.map +1 -0
- package/dist/plugins/builtin/logging-plugin.d.ts +6 -0
- package/dist/plugins/builtin/logging-plugin.js +41 -0
- package/dist/plugins/builtin/logging-plugin.js.map +1 -0
- package/dist/plugins/plugin-manager.d.ts +65 -0
- package/dist/plugins/plugin-manager.js +137 -0
- package/dist/plugins/plugin-manager.js.map +1 -0
- package/dist/proxy/prime-handlers.d.ts +27 -0
- package/dist/proxy/prime-handlers.js +47 -0
- package/dist/proxy/prime-handlers.js.map +1 -0
- package/dist/proxy/progress-forwarder.d.ts +44 -0
- package/dist/proxy/progress-forwarder.js +40 -0
- package/dist/proxy/progress-forwarder.js.map +1 -0
- package/dist/proxy/prompt-router.d.ts +25 -0
- package/dist/proxy/prompt-router.js +110 -0
- package/dist/proxy/prompt-router.js.map +1 -0
- package/dist/proxy/resource-router.d.ts +25 -0
- package/dist/proxy/resource-router.js +91 -0
- package/dist/proxy/resource-router.js.map +1 -0
- package/dist/proxy/schema-adapter.d.ts +11 -0
- package/dist/proxy/schema-adapter.js +36 -0
- package/dist/proxy/schema-adapter.js.map +1 -0
- package/dist/proxy/task-proxy.d.ts +28 -0
- package/dist/proxy/task-proxy.js +186 -0
- package/dist/proxy/task-proxy.js.map +1 -0
- package/dist/proxy/tool-router.d.ts +38 -0
- package/dist/proxy/tool-router.js +229 -0
- package/dist/proxy/tool-router.js.map +1 -0
- package/dist/proxy/ui-detect.d.ts +22 -0
- package/dist/proxy/ui-detect.js +30 -0
- package/dist/proxy/ui-detect.js.map +1 -0
- package/dist/registry/registry-client.d.ts +55 -0
- package/dist/registry/registry-client.js +211 -0
- package/dist/registry/registry-client.js.map +1 -0
- package/dist/registry/types.d.ts +69 -0
- package/dist/registry/types.js +2 -0
- package/dist/registry/types.js.map +1 -0
- package/dist/sandbox/container-runtime.d.ts +91 -0
- package/dist/sandbox/container-runtime.js +178 -0
- package/dist/sandbox/container-runtime.js.map +1 -0
- package/dist/sandbox/egress-proxy.d.ts +51 -0
- package/dist/sandbox/egress-proxy.js +146 -0
- package/dist/sandbox/egress-proxy.js.map +1 -0
- package/dist/sandbox/env-scoper.d.ts +29 -0
- package/dist/sandbox/env-scoper.js +60 -0
- package/dist/sandbox/env-scoper.js.map +1 -0
- package/dist/sandbox/manifest-resolver.d.ts +40 -0
- package/dist/sandbox/manifest-resolver.js +185 -0
- package/dist/sandbox/manifest-resolver.js.map +1 -0
- package/dist/sandbox/types.d.ts +88 -0
- package/dist/sandbox/types.js +21 -0
- package/dist/sandbox/types.js.map +1 -0
- package/dist/utils/errors.d.ts +39 -0
- package/dist/utils/errors.js +67 -0
- package/dist/utils/errors.js.map +1 -0
- package/dist/utils/logger.d.ts +16 -0
- package/dist/utils/logger.js +51 -0
- package/dist/utils/logger.js.map +1 -0
- package/package.json +72 -0
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { appendFileSync } from "node:fs";
|
|
2
|
+
import { log } from "../utils/logger.js";
|
|
3
|
+
/**
|
|
4
|
+
* Append-only safety audit log. Recording never throws — a forensics logger
|
|
5
|
+
* must not break the thing it observes.
|
|
6
|
+
*/
|
|
7
|
+
export class AuditLog {
|
|
8
|
+
buffer = [];
|
|
9
|
+
bufferSize;
|
|
10
|
+
filePath;
|
|
11
|
+
counts = {
|
|
12
|
+
connect: 0,
|
|
13
|
+
tool_call: 0,
|
|
14
|
+
tool_blocked: 0,
|
|
15
|
+
egress_blocked: 0,
|
|
16
|
+
egress_allowed: 0,
|
|
17
|
+
disconnect: 0,
|
|
18
|
+
};
|
|
19
|
+
constructor(opts = {}) {
|
|
20
|
+
this.bufferSize = opts.bufferSize ?? 5000;
|
|
21
|
+
this.filePath = opts.filePath;
|
|
22
|
+
}
|
|
23
|
+
/** Record an event. Caller supplies everything except the timestamp. */
|
|
24
|
+
record(event) {
|
|
25
|
+
try {
|
|
26
|
+
const full = { ts: new Date().toISOString(), ...event };
|
|
27
|
+
this.buffer.push(full);
|
|
28
|
+
if (this.buffer.length > this.bufferSize)
|
|
29
|
+
this.buffer.shift();
|
|
30
|
+
this.counts[full.type] = (this.counts[full.type] ?? 0) + 1;
|
|
31
|
+
// Durable append (best-effort). JSONL = one event per line.
|
|
32
|
+
if (this.filePath) {
|
|
33
|
+
try {
|
|
34
|
+
appendFileSync(this.filePath, JSON.stringify(full) + "\n", "utf-8");
|
|
35
|
+
}
|
|
36
|
+
catch (err) {
|
|
37
|
+
log.debug("Audit file append failed", { error: String(err) });
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
catch (err) {
|
|
42
|
+
// A logger must never break the caller.
|
|
43
|
+
log.debug("Audit record failed", { error: String(err) });
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Query recent events, newest first. Filterable by slug, type, and a
|
|
48
|
+
* "security-relevant only" flag (blocks + errors — the events a reviewer
|
|
49
|
+
* actually cares about).
|
|
50
|
+
*/
|
|
51
|
+
query(opts = {}) {
|
|
52
|
+
const limit = opts.limit ?? 100;
|
|
53
|
+
let events = [...this.buffer].reverse();
|
|
54
|
+
if (opts.slug)
|
|
55
|
+
events = events.filter((e) => e.slug === opts.slug);
|
|
56
|
+
if (opts.type)
|
|
57
|
+
events = events.filter((e) => e.type === opts.type);
|
|
58
|
+
if (opts.securityRelevantOnly) {
|
|
59
|
+
events = events.filter((e) => e.type === "tool_blocked" ||
|
|
60
|
+
e.type === "egress_blocked" ||
|
|
61
|
+
(e.type === "tool_call" && e.ok === false));
|
|
62
|
+
}
|
|
63
|
+
return events.slice(0, limit);
|
|
64
|
+
}
|
|
65
|
+
/** Aggregate counts by event type (for the summary view). */
|
|
66
|
+
summary() {
|
|
67
|
+
const total = Object.values(this.counts).reduce((a, b) => a + b, 0);
|
|
68
|
+
const securityEvents = this.counts.tool_blocked + this.counts.egress_blocked;
|
|
69
|
+
return { counts: { ...this.counts }, total, securityEvents };
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=audit-log.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audit-log.js","sourceRoot":"","sources":["../../src/audit/audit-log.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { readFileSync, mkdirSync, existsSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { homedir } from "node:os";
|
|
4
|
+
const GATEWAY_DIR = join(homedir(), ".mcp-gateway");
|
|
5
|
+
const DEFAULT_CONFIG_PATH = join(GATEWAY_DIR, "config.json");
|
|
6
|
+
const DEFAULT_PERMISSIONS_PATH = join(GATEWAY_DIR, "permissions.json");
|
|
7
|
+
const DEFAULT_PROFILES_PATH = join(GATEWAY_DIR, "profiles.json");
|
|
8
|
+
const DEFAULTS = {
|
|
9
|
+
// Public hosted registry. Point at a local instance for development with
|
|
10
|
+
// MCP_GATEWAY_REGISTRY_URL=http://localhost:3000/api/v1
|
|
11
|
+
registryApiUrl: "https://mcprating.io/api/v1",
|
|
12
|
+
proxyTimeoutMs: 30_000,
|
|
13
|
+
maxConnections: 10,
|
|
14
|
+
logLevel: "info",
|
|
15
|
+
permissionsPath: DEFAULT_PERMISSIONS_PATH,
|
|
16
|
+
configPath: DEFAULT_CONFIG_PATH,
|
|
17
|
+
profilesPath: DEFAULT_PROFILES_PATH,
|
|
18
|
+
registryCacheTtlMs: 300_000,
|
|
19
|
+
reconnectMaxAttempts: 5,
|
|
20
|
+
reconnectBaseDelayMs: 1_000,
|
|
21
|
+
healthCheckIntervalMs: 30_000,
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* Load gateway configuration from file + environment variables.
|
|
25
|
+
* Priority: env vars > config file > defaults
|
|
26
|
+
*/
|
|
27
|
+
export function loadConfig() {
|
|
28
|
+
const configPath = process.env.MCP_GATEWAY_CONFIG_PATH || DEFAULT_CONFIG_PATH;
|
|
29
|
+
// Ensure gateway directory exists
|
|
30
|
+
if (!existsSync(GATEWAY_DIR)) {
|
|
31
|
+
mkdirSync(GATEWAY_DIR, { recursive: true });
|
|
32
|
+
}
|
|
33
|
+
// Load config file if it exists
|
|
34
|
+
let fileConfig = {};
|
|
35
|
+
if (existsSync(configPath)) {
|
|
36
|
+
try {
|
|
37
|
+
const raw = readFileSync(configPath, "utf-8");
|
|
38
|
+
fileConfig = JSON.parse(raw);
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
// Ignore malformed config file — use defaults
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
// Merge: defaults < file < env vars
|
|
45
|
+
return {
|
|
46
|
+
registryApiUrl: process.env.MCP_GATEWAY_REGISTRY_URL ||
|
|
47
|
+
fileConfig.registryApiUrl ||
|
|
48
|
+
DEFAULTS.registryApiUrl,
|
|
49
|
+
proxyTimeoutMs: parseIntEnv("MCP_GATEWAY_TIMEOUT") ??
|
|
50
|
+
fileConfig.proxyTimeoutMs ??
|
|
51
|
+
DEFAULTS.proxyTimeoutMs,
|
|
52
|
+
maxConnections: parseIntEnv("MCP_GATEWAY_MAX_CONNECTIONS") ??
|
|
53
|
+
fileConfig.maxConnections ??
|
|
54
|
+
DEFAULTS.maxConnections,
|
|
55
|
+
logLevel: process.env.MCP_GATEWAY_LOG_LEVEL ||
|
|
56
|
+
fileConfig.logLevel ||
|
|
57
|
+
DEFAULTS.logLevel,
|
|
58
|
+
permissionsPath: fileConfig.permissionsPath || DEFAULTS.permissionsPath,
|
|
59
|
+
configPath,
|
|
60
|
+
profilesPath: fileConfig.profilesPath || DEFAULTS.profilesPath,
|
|
61
|
+
registryCacheTtlMs: parseIntEnv("MCP_GATEWAY_CACHE_TTL") ??
|
|
62
|
+
fileConfig.registryCacheTtlMs ??
|
|
63
|
+
DEFAULTS.registryCacheTtlMs,
|
|
64
|
+
reconnectMaxAttempts: fileConfig.reconnectMaxAttempts ?? DEFAULTS.reconnectMaxAttempts,
|
|
65
|
+
reconnectBaseDelayMs: fileConfig.reconnectBaseDelayMs ?? DEFAULTS.reconnectBaseDelayMs,
|
|
66
|
+
healthCheckIntervalMs: fileConfig.healthCheckIntervalMs ?? DEFAULTS.healthCheckIntervalMs,
|
|
67
|
+
partnerKey: process.env.MCP_GATEWAY_PARTNER_KEY ||
|
|
68
|
+
fileConfig.partnerKey ||
|
|
69
|
+
undefined,
|
|
70
|
+
enableAdTracking: process.env.MCP_GATEWAY_AD_TRACKING === "false"
|
|
71
|
+
? false
|
|
72
|
+
: fileConfig.enableAdTracking ?? undefined,
|
|
73
|
+
enableContainerIsolation: process.env.MCP_GATEWAY_CONTAINER_ISOLATION === "true"
|
|
74
|
+
? true
|
|
75
|
+
: process.env.MCP_GATEWAY_CONTAINER_ISOLATION === "false"
|
|
76
|
+
? false
|
|
77
|
+
: fileConfig.enableContainerIsolation ?? undefined,
|
|
78
|
+
auditLogPath: process.env.MCP_GATEWAY_AUDIT_LOG || fileConfig.auditLogPath || undefined,
|
|
79
|
+
httpPort: parseIntEnv("MCP_GATEWAY_HTTP_PORT") ?? fileConfig.httpPort ?? undefined,
|
|
80
|
+
httpHost: process.env.MCP_GATEWAY_HTTP_HOST || fileConfig.httpHost || "127.0.0.1",
|
|
81
|
+
httpToken: process.env.MCP_GATEWAY_HTTP_TOKEN || fileConfig.httpToken || undefined,
|
|
82
|
+
httpTokens: parseTokensEnv("MCP_GATEWAY_HTTP_TOKENS") ??
|
|
83
|
+
fileConfig.httpTokens ??
|
|
84
|
+
undefined,
|
|
85
|
+
httpAllowedHosts: parseCsvEnv("MCP_GATEWAY_HTTP_ALLOWED_HOSTS") ??
|
|
86
|
+
fileConfig.httpAllowedHosts ??
|
|
87
|
+
undefined,
|
|
88
|
+
httpAllowedOrigins: parseCsvEnv("MCP_GATEWAY_HTTP_ALLOWED_ORIGINS") ??
|
|
89
|
+
fileConfig.httpAllowedOrigins ??
|
|
90
|
+
undefined,
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Parse a per-tenant token env var of the form "tenant1:token1,tenant2:token2"
|
|
95
|
+
* into a { tenant: token } record. The token may itself contain colons (only
|
|
96
|
+
* the first colon separates tenant from token). Returns undefined if empty.
|
|
97
|
+
*/
|
|
98
|
+
function parseTokensEnv(name) {
|
|
99
|
+
const val = process.env[name];
|
|
100
|
+
if (!val)
|
|
101
|
+
return undefined;
|
|
102
|
+
const out = {};
|
|
103
|
+
for (const pair of val.split(",")) {
|
|
104
|
+
const trimmed = pair.trim();
|
|
105
|
+
if (!trimmed)
|
|
106
|
+
continue;
|
|
107
|
+
const idx = trimmed.indexOf(":");
|
|
108
|
+
if (idx <= 0)
|
|
109
|
+
continue; // need a non-empty tenant before the colon
|
|
110
|
+
const tenant = trimmed.slice(0, idx).trim();
|
|
111
|
+
const token = trimmed.slice(idx + 1).trim();
|
|
112
|
+
if (tenant && token)
|
|
113
|
+
out[tenant] = token;
|
|
114
|
+
}
|
|
115
|
+
return Object.keys(out).length > 0 ? out : undefined;
|
|
116
|
+
}
|
|
117
|
+
/** Parse a comma-separated env var into a trimmed string array (or undefined). */
|
|
118
|
+
function parseCsvEnv(name) {
|
|
119
|
+
const val = process.env[name];
|
|
120
|
+
if (!val)
|
|
121
|
+
return undefined;
|
|
122
|
+
const items = val
|
|
123
|
+
.split(",")
|
|
124
|
+
.map((s) => s.trim())
|
|
125
|
+
.filter(Boolean);
|
|
126
|
+
return items.length > 0 ? items : undefined;
|
|
127
|
+
}
|
|
128
|
+
function parseIntEnv(name) {
|
|
129
|
+
const val = process.env[name];
|
|
130
|
+
if (val === undefined)
|
|
131
|
+
return undefined;
|
|
132
|
+
const num = parseInt(val, 10);
|
|
133
|
+
return Number.isNaN(num) ? undefined : num;
|
|
134
|
+
}
|
|
135
|
+
//# sourceMappingURL=gateway-config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gateway-config.js","sourceRoot":"","sources":["../../src/config/gateway-config.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { ConnectParams, TransportType } from "../connection/types.js";
|
|
2
|
+
export interface ServerGroupEntry {
|
|
3
|
+
slug?: string;
|
|
4
|
+
command?: string;
|
|
5
|
+
args?: string[];
|
|
6
|
+
env?: Record<string, string>;
|
|
7
|
+
transportType?: TransportType;
|
|
8
|
+
url?: string;
|
|
9
|
+
}
|
|
10
|
+
export interface ServerGroup {
|
|
11
|
+
name: string;
|
|
12
|
+
description?: string;
|
|
13
|
+
servers: ServerGroupEntry[];
|
|
14
|
+
}
|
|
15
|
+
export interface GroupStore {
|
|
16
|
+
groups: Record<string, ServerGroup>;
|
|
17
|
+
}
|
|
18
|
+
export declare function loadGroups(filePath: string): GroupStore;
|
|
19
|
+
export declare function saveGroups(filePath: string, store: GroupStore): void;
|
|
20
|
+
export declare function createGroup(filePath: string, name: string, description?: string): void;
|
|
21
|
+
export declare function deleteGroup(filePath: string, name: string): boolean;
|
|
22
|
+
export declare function listGroups(filePath: string): ServerGroup[];
|
|
23
|
+
export declare function getGroup(filePath: string, name: string): ServerGroup | undefined;
|
|
24
|
+
export declare function addToGroup(filePath: string, groupName: string, server: ServerGroupEntry): void;
|
|
25
|
+
export declare function removeFromGroup(filePath: string, groupName: string, slugOrCommand: string): void;
|
|
26
|
+
/**
|
|
27
|
+
* Convert a group's servers to ConnectParams for connecting.
|
|
28
|
+
*/
|
|
29
|
+
export declare function groupToConnectParams(group: ServerGroup): ConnectParams[];
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { readFileSync, writeFileSync, existsSync } from "node:fs";
|
|
2
|
+
import { log } from "../utils/logger.js";
|
|
3
|
+
const EMPTY_STORE = { groups: {} };
|
|
4
|
+
// ── Load / Save ──────────────────────────────────────────────────────────────
|
|
5
|
+
export function loadGroups(filePath) {
|
|
6
|
+
if (!existsSync(filePath))
|
|
7
|
+
return { ...EMPTY_STORE, groups: {} };
|
|
8
|
+
try {
|
|
9
|
+
const raw = readFileSync(filePath, "utf-8");
|
|
10
|
+
const data = JSON.parse(raw);
|
|
11
|
+
if (!data.groups || typeof data.groups !== "object") {
|
|
12
|
+
return { ...EMPTY_STORE, groups: {} };
|
|
13
|
+
}
|
|
14
|
+
return data;
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
17
|
+
log.warn("Failed to load groups file, using empty store");
|
|
18
|
+
return { ...EMPTY_STORE, groups: {} };
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
export function saveGroups(filePath, store) {
|
|
22
|
+
try {
|
|
23
|
+
writeFileSync(filePath, JSON.stringify(store, null, 2), "utf-8");
|
|
24
|
+
}
|
|
25
|
+
catch (err) {
|
|
26
|
+
log.warn("Failed to save groups", { error: String(err) });
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
// ── Group CRUD ───────────────────────────────────────────────────────────────
|
|
30
|
+
export function createGroup(filePath, name, description) {
|
|
31
|
+
const store = loadGroups(filePath);
|
|
32
|
+
if (store.groups[name]) {
|
|
33
|
+
log.warn("Group already exists, overwriting", { name });
|
|
34
|
+
}
|
|
35
|
+
store.groups[name] = {
|
|
36
|
+
name,
|
|
37
|
+
description,
|
|
38
|
+
servers: [],
|
|
39
|
+
};
|
|
40
|
+
saveGroups(filePath, store);
|
|
41
|
+
log.info("Server group created", { name });
|
|
42
|
+
}
|
|
43
|
+
export function deleteGroup(filePath, name) {
|
|
44
|
+
const store = loadGroups(filePath);
|
|
45
|
+
if (!store.groups[name])
|
|
46
|
+
return false;
|
|
47
|
+
delete store.groups[name];
|
|
48
|
+
saveGroups(filePath, store);
|
|
49
|
+
log.info("Server group deleted", { name });
|
|
50
|
+
return true;
|
|
51
|
+
}
|
|
52
|
+
export function listGroups(filePath) {
|
|
53
|
+
const store = loadGroups(filePath);
|
|
54
|
+
return Object.values(store.groups);
|
|
55
|
+
}
|
|
56
|
+
export function getGroup(filePath, name) {
|
|
57
|
+
const store = loadGroups(filePath);
|
|
58
|
+
return store.groups[name];
|
|
59
|
+
}
|
|
60
|
+
export function addToGroup(filePath, groupName, server) {
|
|
61
|
+
const store = loadGroups(filePath);
|
|
62
|
+
const group = store.groups[groupName];
|
|
63
|
+
if (!group) {
|
|
64
|
+
throw new Error(`Server group "${groupName}" does not exist.`);
|
|
65
|
+
}
|
|
66
|
+
const identifier = server.slug || server.command || server.url;
|
|
67
|
+
// Don't duplicate
|
|
68
|
+
const existing = group.servers.findIndex((s) => (s.slug && s.slug === server.slug) ||
|
|
69
|
+
(s.command && s.command === server.command) ||
|
|
70
|
+
(s.url && s.url === server.url));
|
|
71
|
+
if (existing >= 0) {
|
|
72
|
+
group.servers[existing] = server;
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
group.servers.push(server);
|
|
76
|
+
}
|
|
77
|
+
saveGroups(filePath, store);
|
|
78
|
+
log.debug("Server added to group", { group: groupName, identifier });
|
|
79
|
+
}
|
|
80
|
+
export function removeFromGroup(filePath, groupName, slugOrCommand) {
|
|
81
|
+
const store = loadGroups(filePath);
|
|
82
|
+
const group = store.groups[groupName];
|
|
83
|
+
if (!group)
|
|
84
|
+
return;
|
|
85
|
+
group.servers = group.servers.filter((s) => s.slug !== slugOrCommand && s.command !== slugOrCommand && s.url !== slugOrCommand);
|
|
86
|
+
saveGroups(filePath, store);
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Convert a group's servers to ConnectParams for connecting.
|
|
90
|
+
*/
|
|
91
|
+
export function groupToConnectParams(group) {
|
|
92
|
+
return group.servers.map((s) => ({
|
|
93
|
+
slug: s.slug,
|
|
94
|
+
command: s.command,
|
|
95
|
+
args: s.args,
|
|
96
|
+
env: s.env,
|
|
97
|
+
transportType: s.transportType,
|
|
98
|
+
url: s.url,
|
|
99
|
+
confirmed: true,
|
|
100
|
+
}));
|
|
101
|
+
}
|
|
102
|
+
//# sourceMappingURL=groups.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"groups.js","sourceRoot":"","sources":["../../src/config/groups.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { ConnectParams, TransportType } from "../connection/types.js";
|
|
2
|
+
export interface ConnectionProfile {
|
|
3
|
+
slug?: string;
|
|
4
|
+
command?: string;
|
|
5
|
+
args?: string[];
|
|
6
|
+
env?: Record<string, string>;
|
|
7
|
+
confirmed: boolean;
|
|
8
|
+
transportType?: TransportType;
|
|
9
|
+
url?: string;
|
|
10
|
+
}
|
|
11
|
+
export interface NamedProfile {
|
|
12
|
+
name: string;
|
|
13
|
+
description?: string;
|
|
14
|
+
connections: ConnectionProfile[];
|
|
15
|
+
}
|
|
16
|
+
export interface ProfileStore {
|
|
17
|
+
/** Legacy flat list (also serves as the "default" profile) */
|
|
18
|
+
connections: ConnectionProfile[];
|
|
19
|
+
/** Named presets ("work", "personal", etc.) */
|
|
20
|
+
profiles?: Record<string, NamedProfile>;
|
|
21
|
+
/** Currently active named profile */
|
|
22
|
+
activeProfile?: string;
|
|
23
|
+
}
|
|
24
|
+
export declare function loadProfiles(filePath: string): ProfileStore;
|
|
25
|
+
export declare function saveProfiles(filePath: string, store: ProfileStore): void;
|
|
26
|
+
export declare function addProfile(filePath: string, params: ConnectParams): void;
|
|
27
|
+
export declare function removeProfile(filePath: string, slug: string): void;
|
|
28
|
+
export declare function listNamedProfiles(filePath: string): NamedProfile[];
|
|
29
|
+
export declare function getActiveProfileName(filePath: string): string | undefined;
|
|
30
|
+
export declare function createNamedProfile(filePath: string, name: string, description?: string): void;
|
|
31
|
+
export declare function deleteNamedProfile(filePath: string, name: string): boolean;
|
|
32
|
+
export declare function addToNamedProfile(filePath: string, profileName: string, params: ConnectParams): void;
|
|
33
|
+
export declare function removeFromNamedProfile(filePath: string, profileName: string, slug: string): void;
|
|
34
|
+
/**
|
|
35
|
+
* Get the connections for a named profile.
|
|
36
|
+
* Returns the default connections if no profile name is given.
|
|
37
|
+
*/
|
|
38
|
+
export declare function getProfileConnections(filePath: string, profileName?: string): ConnectionProfile[];
|
|
39
|
+
/**
|
|
40
|
+
* Set the active profile name.
|
|
41
|
+
*/
|
|
42
|
+
export declare function setActiveProfile(filePath: string, profileName: string | undefined): void;
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import { readFileSync, writeFileSync, existsSync } from "node:fs";
|
|
2
|
+
import { log } from "../utils/logger.js";
|
|
3
|
+
const EMPTY_STORE = { connections: [] };
|
|
4
|
+
// ── Load / Save ──────────────────────────────────────────────────────────────
|
|
5
|
+
export function loadProfiles(filePath) {
|
|
6
|
+
if (!existsSync(filePath))
|
|
7
|
+
return { ...EMPTY_STORE, connections: [] };
|
|
8
|
+
try {
|
|
9
|
+
const raw = readFileSync(filePath, "utf-8");
|
|
10
|
+
const data = JSON.parse(raw);
|
|
11
|
+
if (!Array.isArray(data.connections)) {
|
|
12
|
+
return { ...EMPTY_STORE, connections: [] };
|
|
13
|
+
}
|
|
14
|
+
log.debug("Loaded connection profiles", {
|
|
15
|
+
count: data.connections.length,
|
|
16
|
+
namedProfiles: data.profiles ? Object.keys(data.profiles).length : 0,
|
|
17
|
+
});
|
|
18
|
+
return data;
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
log.warn("Failed to load profiles file, using empty store");
|
|
22
|
+
return { ...EMPTY_STORE, connections: [] };
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
export function saveProfiles(filePath, store) {
|
|
26
|
+
try {
|
|
27
|
+
writeFileSync(filePath, JSON.stringify(store, null, 2), "utf-8");
|
|
28
|
+
}
|
|
29
|
+
catch (err) {
|
|
30
|
+
log.warn("Failed to save profiles", { error: String(err) });
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
// ── Connection Profile CRUD ──────────────────────────────────────────────────
|
|
34
|
+
export function addProfile(filePath, params) {
|
|
35
|
+
const store = loadProfiles(filePath);
|
|
36
|
+
const identifier = params.slug || params.command || params.url;
|
|
37
|
+
// Don't duplicate — update existing
|
|
38
|
+
const idx = store.connections.findIndex((p) => (p.slug && p.slug === params.slug) ||
|
|
39
|
+
(p.command && p.command === params.command) ||
|
|
40
|
+
(p.url && p.url === params.url));
|
|
41
|
+
const profile = {
|
|
42
|
+
slug: params.slug,
|
|
43
|
+
command: params.command,
|
|
44
|
+
args: params.args,
|
|
45
|
+
env: params.env,
|
|
46
|
+
confirmed: params.confirmed ?? true,
|
|
47
|
+
transportType: params.transportType,
|
|
48
|
+
url: params.url,
|
|
49
|
+
};
|
|
50
|
+
if (idx >= 0) {
|
|
51
|
+
store.connections[idx] = profile;
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
store.connections.push(profile);
|
|
55
|
+
}
|
|
56
|
+
saveProfiles(filePath, store);
|
|
57
|
+
log.debug("Profile saved", { identifier });
|
|
58
|
+
}
|
|
59
|
+
export function removeProfile(filePath, slug) {
|
|
60
|
+
const store = loadProfiles(filePath);
|
|
61
|
+
const before = store.connections.length;
|
|
62
|
+
store.connections = store.connections.filter((p) => p.slug !== slug && p.command !== slug);
|
|
63
|
+
if (store.connections.length < before) {
|
|
64
|
+
saveProfiles(filePath, store);
|
|
65
|
+
log.debug("Profile removed", { slug });
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
// ── Named Profile Management ─────────────────────────────────────────────────
|
|
69
|
+
export function listNamedProfiles(filePath) {
|
|
70
|
+
const store = loadProfiles(filePath);
|
|
71
|
+
if (!store.profiles)
|
|
72
|
+
return [];
|
|
73
|
+
return Object.values(store.profiles);
|
|
74
|
+
}
|
|
75
|
+
export function getActiveProfileName(filePath) {
|
|
76
|
+
const store = loadProfiles(filePath);
|
|
77
|
+
return store.activeProfile;
|
|
78
|
+
}
|
|
79
|
+
export function createNamedProfile(filePath, name, description) {
|
|
80
|
+
const store = loadProfiles(filePath);
|
|
81
|
+
if (!store.profiles)
|
|
82
|
+
store.profiles = {};
|
|
83
|
+
if (store.profiles[name]) {
|
|
84
|
+
log.warn("Named profile already exists, overwriting", { name });
|
|
85
|
+
}
|
|
86
|
+
store.profiles[name] = {
|
|
87
|
+
name,
|
|
88
|
+
description,
|
|
89
|
+
connections: [],
|
|
90
|
+
};
|
|
91
|
+
saveProfiles(filePath, store);
|
|
92
|
+
log.info("Named profile created", { name });
|
|
93
|
+
}
|
|
94
|
+
export function deleteNamedProfile(filePath, name) {
|
|
95
|
+
const store = loadProfiles(filePath);
|
|
96
|
+
if (!store.profiles || !store.profiles[name])
|
|
97
|
+
return false;
|
|
98
|
+
delete store.profiles[name];
|
|
99
|
+
// Clear active profile if it was deleted
|
|
100
|
+
if (store.activeProfile === name) {
|
|
101
|
+
store.activeProfile = undefined;
|
|
102
|
+
}
|
|
103
|
+
saveProfiles(filePath, store);
|
|
104
|
+
log.info("Named profile deleted", { name });
|
|
105
|
+
return true;
|
|
106
|
+
}
|
|
107
|
+
export function addToNamedProfile(filePath, profileName, params) {
|
|
108
|
+
const store = loadProfiles(filePath);
|
|
109
|
+
if (!store.profiles?.[profileName]) {
|
|
110
|
+
throw new Error(`Named profile "${profileName}" does not exist.`);
|
|
111
|
+
}
|
|
112
|
+
const profile = store.profiles[profileName];
|
|
113
|
+
// Don't duplicate
|
|
114
|
+
const idx = profile.connections.findIndex((p) => (p.slug && p.slug === params.slug) ||
|
|
115
|
+
(p.command && p.command === params.command) ||
|
|
116
|
+
(p.url && p.url === params.url));
|
|
117
|
+
const connection = {
|
|
118
|
+
slug: params.slug,
|
|
119
|
+
command: params.command,
|
|
120
|
+
args: params.args,
|
|
121
|
+
env: params.env,
|
|
122
|
+
confirmed: params.confirmed ?? true,
|
|
123
|
+
transportType: params.transportType,
|
|
124
|
+
url: params.url,
|
|
125
|
+
};
|
|
126
|
+
if (idx >= 0) {
|
|
127
|
+
profile.connections[idx] = connection;
|
|
128
|
+
}
|
|
129
|
+
else {
|
|
130
|
+
profile.connections.push(connection);
|
|
131
|
+
}
|
|
132
|
+
saveProfiles(filePath, store);
|
|
133
|
+
}
|
|
134
|
+
export function removeFromNamedProfile(filePath, profileName, slug) {
|
|
135
|
+
const store = loadProfiles(filePath);
|
|
136
|
+
if (!store.profiles?.[profileName])
|
|
137
|
+
return;
|
|
138
|
+
const profile = store.profiles[profileName];
|
|
139
|
+
profile.connections = profile.connections.filter((p) => p.slug !== slug && p.command !== slug);
|
|
140
|
+
saveProfiles(filePath, store);
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Get the connections for a named profile.
|
|
144
|
+
* Returns the default connections if no profile name is given.
|
|
145
|
+
*/
|
|
146
|
+
export function getProfileConnections(filePath, profileName) {
|
|
147
|
+
const store = loadProfiles(filePath);
|
|
148
|
+
if (!profileName) {
|
|
149
|
+
return store.connections;
|
|
150
|
+
}
|
|
151
|
+
if (!store.profiles?.[profileName]) {
|
|
152
|
+
throw new Error(`Named profile "${profileName}" does not exist.`);
|
|
153
|
+
}
|
|
154
|
+
return store.profiles[profileName].connections;
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Set the active profile name.
|
|
158
|
+
*/
|
|
159
|
+
export function setActiveProfile(filePath, profileName) {
|
|
160
|
+
const store = loadProfiles(filePath);
|
|
161
|
+
if (profileName && (!store.profiles || !store.profiles[profileName])) {
|
|
162
|
+
throw new Error(`Named profile "${profileName}" does not exist.`);
|
|
163
|
+
}
|
|
164
|
+
store.activeProfile = profileName;
|
|
165
|
+
saveProfiles(filePath, store);
|
|
166
|
+
}
|
|
167
|
+
//# sourceMappingURL=profiles.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"profiles.js","sourceRoot":"","sources":["../../src/config/profiles.ts"],"names":[],"mappings":"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"}
|