@wolpertingerlabs/drawlatch 1.0.0-alpha.2 → 1.0.0-alpha.29
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/CONNECTIONS.md +3 -0
- package/README.md +395 -465
- package/bin/drawlatch.js +1018 -49
- package/dist/auth/auth.d.ts +10 -0
- package/dist/auth/auth.js +146 -0
- package/dist/auth/env-writer.d.ts +6 -0
- package/dist/auth/env-writer.js +52 -0
- package/dist/auth/password.d.ts +8 -0
- package/dist/auth/password.js +28 -0
- package/dist/auth/sessions.d.ts +13 -0
- package/dist/auth/sessions.js +85 -0
- package/dist/cli/generate-keys.d.ts +4 -4
- package/dist/cli/generate-keys.js +30 -25
- package/dist/connections/{anthropic.json → ai/anthropic.json} +19 -1
- package/dist/connections/{devin.json → ai/devin.json} +7 -1
- package/dist/connections/{google-ai.json → ai/google-ai.json} +7 -1
- package/dist/connections/{openai.json → ai/openai.json} +7 -1
- package/dist/connections/{openrouter.json → ai/openrouter.json} +7 -1
- package/dist/connections/developer-tools/github.json +138 -0
- package/dist/connections/{hex.json → developer-tools/hex.json} +7 -1
- package/dist/connections/developer-tools/linear.json +75 -0
- package/dist/connections/{lichess.json → gaming/lichess.json} +7 -1
- package/dist/connections/messaging/agentmail.json +21 -0
- package/dist/connections/messaging/discord-bot.json +114 -0
- package/dist/connections/{discord-oauth.json → messaging/discord-oauth.json} +7 -1
- package/dist/connections/messaging/slack.json +75 -0
- package/dist/connections/messaging/telegram.json +66 -0
- package/dist/connections/{google.json → productivity/google.json} +7 -1
- package/dist/connections/productivity/notion.json +75 -0
- package/dist/connections/productivity/stripe.json +74 -0
- package/dist/connections/productivity/trello.json +113 -0
- package/dist/connections/{bluesky.json → social-media/bluesky.json} +41 -0
- package/dist/connections/social-media/mastodon.json +65 -0
- package/dist/connections/social-media/reddit.json +80 -0
- package/dist/connections/{twitch.json → social-media/twitch.json} +40 -0
- package/dist/connections/social-media/x.json +67 -0
- package/dist/mcp/server.js +544 -31
- package/dist/remote/admin-mutations.d.ts +37 -0
- package/dist/remote/admin-mutations.js +251 -0
- package/dist/remote/admin-types.d.ts +149 -0
- package/dist/remote/admin-types.js +11 -0
- package/dist/remote/admin.d.ts +37 -0
- package/dist/remote/admin.js +316 -0
- package/dist/remote/caller-bootstrap.d.ts +71 -0
- package/dist/remote/caller-bootstrap.js +141 -0
- package/dist/remote/ingestors/base-ingestor.d.ts +19 -3
- package/dist/remote/ingestors/base-ingestor.js +27 -6
- package/dist/remote/ingestors/discord/discord-gateway.d.ts +2 -2
- package/dist/remote/ingestors/discord/discord-gateway.js +29 -6
- package/dist/remote/ingestors/e2e/setup.d.ts +69 -0
- package/dist/remote/ingestors/e2e/setup.js +147 -0
- package/dist/remote/ingestors/manager.d.ts +110 -10
- package/dist/remote/ingestors/manager.js +449 -42
- package/dist/remote/ingestors/poll/poll-ingestor.d.ts +4 -2
- package/dist/remote/ingestors/poll/poll-ingestor.js +26 -5
- package/dist/remote/ingestors/registry.d.ts +2 -2
- package/dist/remote/ingestors/registry.js +2 -2
- package/dist/remote/ingestors/slack/socket-mode.d.ts +2 -2
- package/dist/remote/ingestors/slack/socket-mode.js +28 -6
- package/dist/remote/ingestors/types.d.ts +25 -0
- package/dist/remote/ingestors/webhook/base-webhook-ingestor.d.ts +46 -7
- package/dist/remote/ingestors/webhook/base-webhook-ingestor.js +115 -10
- package/dist/remote/ingestors/webhook/github-webhook-ingestor.d.ts +30 -0
- package/dist/remote/ingestors/webhook/github-webhook-ingestor.js +73 -2
- package/dist/remote/ingestors/webhook/lifecycle-types.d.ts +63 -0
- package/dist/remote/ingestors/webhook/lifecycle-types.js +12 -0
- package/dist/remote/ingestors/webhook/stripe-webhook-ingestor.js +2 -2
- package/dist/remote/ingestors/webhook/trello-webhook-ingestor.d.ts +17 -5
- package/dist/remote/ingestors/webhook/trello-webhook-ingestor.js +32 -26
- package/dist/remote/ingestors/webhook/webhook-lifecycle-manager.d.ts +46 -0
- package/dist/remote/ingestors/webhook/webhook-lifecycle-manager.js +261 -0
- package/dist/remote/server.d.ts +25 -33
- package/dist/remote/server.js +681 -195
- package/dist/remote/tool-dispatch.d.ts +84 -0
- package/dist/remote/tool-dispatch.js +910 -0
- package/dist/remote/triggers/rule-engine.d.ts +40 -0
- package/dist/remote/triggers/rule-engine.js +228 -0
- package/dist/remote/triggers/types.d.ts +69 -0
- package/dist/remote/triggers/types.js +10 -0
- package/dist/remote/tunnel-state.d.ts +14 -0
- package/dist/remote/tunnel-state.js +20 -0
- package/dist/remote/tunnel.d.ts +53 -0
- package/dist/remote/tunnel.js +149 -0
- package/dist/shared/config.d.ts +97 -25
- package/dist/shared/config.js +48 -35
- package/dist/shared/connections.d.ts +21 -5
- package/dist/shared/connections.js +56 -14
- package/dist/shared/crypto/index.d.ts +1 -0
- package/dist/shared/crypto/index.js +1 -0
- package/dist/shared/crypto/key-manager.d.ts +67 -0
- package/dist/shared/crypto/key-manager.js +152 -0
- package/dist/shared/env-utils.d.ts +42 -0
- package/dist/shared/env-utils.js +150 -0
- package/dist/shared/listener-config.d.ts +157 -0
- package/dist/shared/listener-config.js +10 -0
- package/dist/shared/migrations.d.ts +40 -0
- package/dist/shared/migrations.js +122 -0
- package/dist/shared/protocol/handshake.js +14 -1
- package/dist/shared/protocol/index.d.ts +2 -0
- package/dist/shared/protocol/index.js +2 -0
- package/dist/shared/protocol/sync-client.d.ts +52 -0
- package/dist/shared/protocol/sync-client.js +99 -0
- package/dist/shared/protocol/sync.d.ts +71 -0
- package/dist/shared/protocol/sync.js +176 -0
- package/frontend/dist/assets/index-D4k5QKBP.css +1 -0
- package/frontend/dist/assets/index-IzwnSOmu.js +267 -0
- package/frontend/dist/index.html +15 -0
- package/package.json +66 -13
- package/dist/connections/discord-bot.json +0 -24
- package/dist/connections/github.json +0 -25
- package/dist/connections/linear.json +0 -29
- package/dist/connections/mastodon.json +0 -25
- package/dist/connections/notion.json +0 -33
- package/dist/connections/reddit.json +0 -28
- package/dist/connections/slack.json +0 -23
- package/dist/connections/stripe.json +0 -25
- package/dist/connections/telegram.json +0 -26
- package/dist/connections/trello.json +0 -25
- package/dist/connections/x.json +0 -27
package/dist/shared/config.d.ts
CHANGED
|
@@ -11,6 +11,10 @@
|
|
|
11
11
|
* Keys directory: ~/.drawlatch/keys/
|
|
12
12
|
*/
|
|
13
13
|
import type { IngestorConfig } from '../remote/ingestors/types.js';
|
|
14
|
+
import type { TriggerRule } from '../remote/triggers/types.js';
|
|
15
|
+
import type { TestConnectionConfig, TestIngestorConfig, ListenerConfigSchema } from './listener-config.js';
|
|
16
|
+
export type { TestConnectionConfig, TestIngestorConfig, ListenerConfigSchema, } from './listener-config.js';
|
|
17
|
+
export type { ListenerConfigField, ListenerConfigOption } from './listener-config.js';
|
|
14
18
|
/** Resolve the base config directory at call time (not import time).
|
|
15
19
|
* Defaults to ~/.drawlatch in the user's home directory.
|
|
16
20
|
* Override with MCP_CONFIG_DIR env var for custom deployments.
|
|
@@ -23,22 +27,16 @@ export declare function getConfigPath(): string;
|
|
|
23
27
|
export declare function getProxyConfigPath(): string;
|
|
24
28
|
export declare function getRemoteConfigPath(): string;
|
|
25
29
|
export declare function getKeysDir(): string;
|
|
26
|
-
export declare function
|
|
27
|
-
export declare function
|
|
28
|
-
export declare function getPeerKeysDir(): string;
|
|
30
|
+
export declare function getCallerKeysDir(): string;
|
|
31
|
+
export declare function getServerKeysDir(): string;
|
|
29
32
|
export declare function getEnvFilePath(): string;
|
|
33
|
+
/** Category grouping for built-in connection templates.
|
|
34
|
+
* Matches the subdirectory name under src/connections/. */
|
|
35
|
+
export type ConnectionCategory = 'ai' | 'developer-tools' | 'gaming' | 'messaging' | 'productivity' | 'social-media';
|
|
30
36
|
/** MCP proxy (local) configuration */
|
|
31
37
|
export interface ProxyConfig {
|
|
32
38
|
/** Remote server URL */
|
|
33
39
|
remoteUrl: string;
|
|
34
|
-
/** Key alias — resolved to keys/local/<alias>/.
|
|
35
|
-
* Overridden by the MCP_KEY_ALIAS env var at runtime.
|
|
36
|
-
* When set, takes precedence over localKeysDir. */
|
|
37
|
-
localKeyAlias?: string;
|
|
38
|
-
/** Path to our own key bundle (full-path override; ignored when alias is set) */
|
|
39
|
-
localKeysDir: string;
|
|
40
|
-
/** Path to the remote server's public keys */
|
|
41
|
-
remotePublicKeysDir: string;
|
|
42
40
|
/** Connection timeout (ms) */
|
|
43
41
|
connectTimeout: number;
|
|
44
42
|
/** Request timeout (ms) */
|
|
@@ -61,6 +59,14 @@ export interface Route {
|
|
|
61
59
|
/** URL to an OpenAPI / Swagger spec (JSON or YAML) for this route's API.
|
|
62
60
|
* Optional — provides more structured, agent-friendly documentation. */
|
|
63
61
|
openApiUrl?: string;
|
|
62
|
+
/** Stability level of this connection: "stable", "beta", or "dev".
|
|
63
|
+
* Defaults to "dev" if omitted. Helps agents and UIs communicate
|
|
64
|
+
* whether a connection is production-ready, in testing, or experimental. */
|
|
65
|
+
stability?: 'stable' | 'beta' | 'dev';
|
|
66
|
+
/** Category grouping for this connection template (e.g., "ai", "messaging").
|
|
67
|
+
* Matches the subdirectory under src/connections/. Only present on built-in
|
|
68
|
+
* connection templates; custom connectors may omit it. */
|
|
69
|
+
category?: ConnectionCategory;
|
|
64
70
|
/** Headers to inject automatically into outgoing requests for this route.
|
|
65
71
|
* These MUST NOT conflict with client-provided headers (request is rejected on conflict).
|
|
66
72
|
* Values may contain ${VAR} placeholders resolved against this route's secrets. */
|
|
@@ -79,9 +85,22 @@ export interface Route {
|
|
|
79
85
|
* When present, the remote server can start a long-lived ingestor
|
|
80
86
|
* (WebSocket, webhook listener, or poller) for this connection. */
|
|
81
87
|
ingestor?: IngestorConfig;
|
|
88
|
+
/** Pre-configured test request for verifying connection credentials.
|
|
89
|
+
* Must be a non-destructive, read-only endpoint with zero side effects. */
|
|
90
|
+
testConnection?: TestConnectionConfig;
|
|
91
|
+
/** Pre-configured test for verifying ingestor / event listener configuration.
|
|
92
|
+
* Set to null to explicitly indicate this listener cannot be tested.
|
|
93
|
+
* Omitted if the connection has no ingestor. */
|
|
94
|
+
testIngestor?: TestIngestorConfig | null;
|
|
95
|
+
/** Schema describing configurable fields for this connection's event listener.
|
|
96
|
+
* Used by UIs and management tools to render configuration forms.
|
|
97
|
+
* Only present on connections that have an ingestor. */
|
|
98
|
+
listenerConfig?: ListenerConfigSchema;
|
|
82
99
|
}
|
|
83
100
|
/** A route after secret/header resolution — used at runtime */
|
|
84
101
|
export interface ResolvedRoute {
|
|
102
|
+
/** Connection alias (e.g., "github", "discord-bot"). Populated during caller route resolution. */
|
|
103
|
+
alias?: string;
|
|
85
104
|
/** Human-readable name for this route (carried from config) */
|
|
86
105
|
name?: string;
|
|
87
106
|
/** Short description of this route's purpose (carried from config) */
|
|
@@ -90,11 +109,23 @@ export interface ResolvedRoute {
|
|
|
90
109
|
docsUrl?: string;
|
|
91
110
|
/** URL to an OpenAPI / Swagger spec for this route's API (carried from config) */
|
|
92
111
|
openApiUrl?: string;
|
|
112
|
+
/** Stability level (carried from config) */
|
|
113
|
+
stability?: 'stable' | 'beta' | 'dev';
|
|
114
|
+
/** Category grouping (carried from config) */
|
|
115
|
+
category?: ConnectionCategory;
|
|
93
116
|
headers: Record<string, string>;
|
|
94
117
|
secrets: Record<string, string>;
|
|
95
118
|
allowedEndpoints: string[];
|
|
96
119
|
/** Whether to resolve ${VAR} placeholders in request bodies (default: false) */
|
|
97
120
|
resolveSecretsInBody: boolean;
|
|
121
|
+
/** Pre-configured test request for verifying connection credentials (carried from config) */
|
|
122
|
+
testConnection?: TestConnectionConfig;
|
|
123
|
+
/** Pre-configured test for verifying ingestor / event listener (carried from config) */
|
|
124
|
+
testIngestor?: TestIngestorConfig | null;
|
|
125
|
+
/** Listener configuration schema for UI rendering (carried from config) */
|
|
126
|
+
listenerConfig?: ListenerConfigSchema;
|
|
127
|
+
/** Raw ingestor configuration (carried from config, needed by tool handlers) */
|
|
128
|
+
ingestorConfig?: IngestorConfig;
|
|
98
129
|
}
|
|
99
130
|
/** Per-connection ingestor overrides (all fields optional — omitted fields inherit from template). */
|
|
100
131
|
export interface IngestorOverrides {
|
|
@@ -114,13 +145,16 @@ export interface IngestorOverrides {
|
|
|
114
145
|
disabled?: boolean;
|
|
115
146
|
/** Override the poll interval in milliseconds (poll ingestors only). */
|
|
116
147
|
intervalMs?: number;
|
|
148
|
+
/** Generic parameter bag for listener configuration.
|
|
149
|
+
* Keys correspond to ListenerConfigField.key values from the connection's
|
|
150
|
+
* listenerConfig schema. Values are mapped to typed ingestor config fields
|
|
151
|
+
* during mergeIngestorConfig(). */
|
|
152
|
+
params?: Record<string, unknown>;
|
|
117
153
|
}
|
|
118
154
|
/** Per-caller access configuration */
|
|
119
155
|
export interface CallerConfig {
|
|
120
156
|
/** Human-readable name for this caller (used in audit logs) */
|
|
121
157
|
name?: string;
|
|
122
|
-
/** Path to this caller's public key files (signing.pub.pem + exchange.pub.pem) */
|
|
123
|
-
peerKeyDir: string;
|
|
124
158
|
/** List of connection aliases — references built-in templates (e.g., "github")
|
|
125
159
|
* or custom connector aliases defined in the top-level connectors array. */
|
|
126
160
|
connections: string[];
|
|
@@ -133,6 +167,26 @@ export interface CallerConfig {
|
|
|
133
167
|
* Allows callers to customize intents, event filters, guild/channel/user ID filters,
|
|
134
168
|
* buffer size, or disable an ingestor without modifying the connection template. */
|
|
135
169
|
ingestorOverrides?: Record<string, IngestorOverrides>;
|
|
170
|
+
/** Multi-instance listener definitions keyed by connection alias.
|
|
171
|
+
* Value is a map of instanceId → IngestorOverrides.
|
|
172
|
+
* When present for a connection, spawns one ingestor per instanceId instead of
|
|
173
|
+
* a single default instance. Takes precedence over ingestorOverrides for that connection.
|
|
174
|
+
* Instance IDs must match /^[a-zA-Z0-9_-]+$/.
|
|
175
|
+
*
|
|
176
|
+
* Example:
|
|
177
|
+
* ```json
|
|
178
|
+
* {
|
|
179
|
+
* "trello": {
|
|
180
|
+
* "project-board": { "params": { "boardId": "abc123" } },
|
|
181
|
+
* "sprint-board": { "params": { "boardId": "def456" } }
|
|
182
|
+
* }
|
|
183
|
+
* }
|
|
184
|
+
* ``` */
|
|
185
|
+
listenerInstances?: Record<string, Record<string, IngestorOverrides>>;
|
|
186
|
+
/** Trigger rules that map ingestor events to Claude Code remote trigger invocations.
|
|
187
|
+
* When an ingestor event matches a rule's criteria (source, event type, filter),
|
|
188
|
+
* the engine dispatches the event to the configured remote trigger. */
|
|
189
|
+
triggerRules?: TriggerRule[];
|
|
136
190
|
}
|
|
137
191
|
/** Remote server configuration */
|
|
138
192
|
export interface RemoteServerConfig {
|
|
@@ -140,16 +194,21 @@ export interface RemoteServerConfig {
|
|
|
140
194
|
host: string;
|
|
141
195
|
/** Port to listen on */
|
|
142
196
|
port: number;
|
|
143
|
-
/** Path to our own key bundle */
|
|
144
|
-
localKeysDir: string;
|
|
145
197
|
/** Custom connector definitions — a reusable pool referenced by alias from callers.
|
|
146
198
|
* Each connector scopes secrets and headers to endpoint patterns. */
|
|
147
199
|
connectors?: Route[];
|
|
148
200
|
/** Per-caller access control. Keys are caller aliases (used in audit logs).
|
|
149
|
-
* Each caller specifies
|
|
201
|
+
* Each caller specifies which connections they can use.
|
|
202
|
+
* Caller public keys are loaded from keys/callers/<alias>/. */
|
|
150
203
|
callers: Record<string, CallerConfig>;
|
|
151
204
|
/** Rate limit: max requests per minute per session */
|
|
152
205
|
rateLimitPerMinute: number;
|
|
206
|
+
/** When true, drawlatch brings up and supervises its own cloudflared quick
|
|
207
|
+
* tunnel on startup, injecting the public URL into callback-dependent
|
|
208
|
+
* connection configs before secret resolution and ingestor start (item C).
|
|
209
|
+
* Equivalent to setting DRAWLATCH_TUNNEL=1. Not a control surface — just a
|
|
210
|
+
* config flag. Default: false. */
|
|
211
|
+
tunnel?: boolean;
|
|
153
212
|
}
|
|
154
213
|
/**
|
|
155
214
|
* Load the MCP proxy (local) config.
|
|
@@ -159,13 +218,17 @@ export interface RemoteServerConfig {
|
|
|
159
218
|
* 2. config.json → .proxy section (legacy combined format)
|
|
160
219
|
* 3. Built-in defaults
|
|
161
220
|
*
|
|
162
|
-
* Key
|
|
163
|
-
*
|
|
164
|
-
*
|
|
165
|
-
* 3. localKeysDir in config file (explicit full path)
|
|
166
|
-
* 4. Default: keys/local/default
|
|
221
|
+
* Key paths are derived automatically:
|
|
222
|
+
* - Caller keys: keys/callers/{MCP_KEY_ALIAS || "default"}/
|
|
223
|
+
* - Server keys: keys/server/
|
|
167
224
|
*/
|
|
168
225
|
export declare function loadProxyConfig(): ProxyConfig;
|
|
226
|
+
/**
|
|
227
|
+
* Resolve the caller key alias for the MCP proxy.
|
|
228
|
+
*
|
|
229
|
+
* Resolution: MCP_KEY_ALIAS env var > "default"
|
|
230
|
+
*/
|
|
231
|
+
export declare function resolveCallerKeyAlias(): string;
|
|
169
232
|
/**
|
|
170
233
|
* Load the remote server config.
|
|
171
234
|
*
|
|
@@ -199,16 +262,25 @@ export declare function resolvePlaceholders(str: string, secretsMap: Record<stri
|
|
|
199
262
|
* Load secrets from the config's secrets map, resolving from environment
|
|
200
263
|
* variables. Value can be a literal string or "${VAR_NAME}" to read from env.
|
|
201
264
|
*
|
|
202
|
-
*
|
|
203
|
-
*
|
|
265
|
+
* Resolution order for each ${VAR} reference:
|
|
266
|
+
* 1. `envOverrides[VAR]` — caller's explicit env mapping (pre-resolved)
|
|
267
|
+
* 2. `process.env[PREFIX_VAR]` — prefixed env var (e.g., ALICE_GITHUB_TOKEN)
|
|
268
|
+
* 3. Warning if not found (bare process.env fallback intentionally removed
|
|
269
|
+
* to prevent cross-caller secret leakage)
|
|
270
|
+
*
|
|
271
|
+
* When `callerAlias` is omitted, step 2 is skipped (used for resolving
|
|
272
|
+
* the caller's own env mapping where prefixing doesn't apply).
|
|
204
273
|
*/
|
|
205
|
-
export declare function resolveSecrets(secretsMap: Record<string, string>, envOverrides?: Record<string, string
|
|
274
|
+
export declare function resolveSecrets(secretsMap: Record<string, string>, envOverrides?: Record<string, string>, callerAlias?: string): Record<string, string>;
|
|
206
275
|
/**
|
|
207
276
|
* Resolve all routes: resolve secrets from env vars, then resolve header
|
|
208
277
|
* placeholders against each route's own resolved secrets.
|
|
209
278
|
*
|
|
210
279
|
* When `envOverrides` is provided, those pre-resolved values are checked
|
|
211
280
|
* before process.env during secret resolution (used for per-caller env).
|
|
281
|
+
*
|
|
282
|
+
* When `callerAlias` is provided, prefixed env vars (e.g., ALICE_GITHUB_TOKEN)
|
|
283
|
+
* are checked as a fallback before giving up on a ${VAR} reference.
|
|
212
284
|
*/
|
|
213
|
-
export declare function resolveRoutes(routes: Route[], envOverrides?: Record<string, string
|
|
285
|
+
export declare function resolveRoutes(routes: Route[], envOverrides?: Record<string, string>, callerAlias?: string): ResolvedRoute[];
|
|
214
286
|
//# sourceMappingURL=config.d.ts.map
|
package/dist/shared/config.js
CHANGED
|
@@ -36,14 +36,11 @@ export function getRemoteConfigPath() {
|
|
|
36
36
|
export function getKeysDir() {
|
|
37
37
|
return path.join(getConfigDir(), 'keys');
|
|
38
38
|
}
|
|
39
|
-
export function
|
|
40
|
-
return path.join(getKeysDir(), '
|
|
39
|
+
export function getCallerKeysDir() {
|
|
40
|
+
return path.join(getKeysDir(), 'callers');
|
|
41
41
|
}
|
|
42
|
-
export function
|
|
43
|
-
return path.join(getKeysDir(), '
|
|
44
|
-
}
|
|
45
|
-
export function getPeerKeysDir() {
|
|
46
|
-
return path.join(getKeysDir(), 'peers');
|
|
42
|
+
export function getServerKeysDir() {
|
|
43
|
+
return path.join(getKeysDir(), 'server');
|
|
47
44
|
}
|
|
48
45
|
export function getEnvFilePath() {
|
|
49
46
|
return path.join(getConfigDir(), '.env');
|
|
@@ -52,8 +49,6 @@ export function getEnvFilePath() {
|
|
|
52
49
|
function proxyDefaults() {
|
|
53
50
|
return {
|
|
54
51
|
remoteUrl: 'http://localhost:9999',
|
|
55
|
-
localKeysDir: path.join(getLocalKeysDir(), 'default'),
|
|
56
|
-
remotePublicKeysDir: path.join(getPeerKeysDir(), 'remote-server'),
|
|
57
52
|
connectTimeout: 10_000,
|
|
58
53
|
requestTimeout: 30_000,
|
|
59
54
|
};
|
|
@@ -62,7 +57,6 @@ function remoteDefaults() {
|
|
|
62
57
|
return {
|
|
63
58
|
host: '127.0.0.1',
|
|
64
59
|
port: 9999,
|
|
65
|
-
localKeysDir: getRemoteKeysDir(),
|
|
66
60
|
callers: {},
|
|
67
61
|
rateLimitPerMinute: 60,
|
|
68
62
|
};
|
|
@@ -76,11 +70,9 @@ function remoteDefaults() {
|
|
|
76
70
|
* 2. config.json → .proxy section (legacy combined format)
|
|
77
71
|
* 3. Built-in defaults
|
|
78
72
|
*
|
|
79
|
-
* Key
|
|
80
|
-
*
|
|
81
|
-
*
|
|
82
|
-
* 3. localKeysDir in config file (explicit full path)
|
|
83
|
-
* 4. Default: keys/local/default
|
|
73
|
+
* Key paths are derived automatically:
|
|
74
|
+
* - Caller keys: keys/callers/{MCP_KEY_ALIAS || "default"}/
|
|
75
|
+
* - Server keys: keys/server/
|
|
84
76
|
*/
|
|
85
77
|
export function loadProxyConfig() {
|
|
86
78
|
const def = proxyDefaults();
|
|
@@ -98,15 +90,17 @@ export function loadProxyConfig() {
|
|
|
98
90
|
else {
|
|
99
91
|
config = def;
|
|
100
92
|
}
|
|
101
|
-
// Alias resolution: env var > config alias > localKeysDir > default
|
|
102
|
-
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing -- intentionally coerces empty string to undefined
|
|
103
|
-
const envAlias = process.env.MCP_KEY_ALIAS?.trim() || undefined;
|
|
104
|
-
const alias = envAlias ?? config.localKeyAlias;
|
|
105
|
-
if (alias) {
|
|
106
|
-
config.localKeysDir = path.join(getLocalKeysDir(), alias);
|
|
107
|
-
}
|
|
108
93
|
return config;
|
|
109
94
|
}
|
|
95
|
+
/**
|
|
96
|
+
* Resolve the caller key alias for the MCP proxy.
|
|
97
|
+
*
|
|
98
|
+
* Resolution: MCP_KEY_ALIAS env var > "default"
|
|
99
|
+
*/
|
|
100
|
+
export function resolveCallerKeyAlias() {
|
|
101
|
+
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing -- intentionally coerces empty string
|
|
102
|
+
return process.env.MCP_KEY_ALIAS?.trim() || 'default';
|
|
103
|
+
}
|
|
110
104
|
/**
|
|
111
105
|
* Load the remote server config.
|
|
112
106
|
*
|
|
@@ -142,7 +136,6 @@ export function loadRemoteConfig() {
|
|
|
142
136
|
'Migrating to caller-centric format. Please update your remote.config.json.');
|
|
143
137
|
const legacyRoutes = rawConfig.routes;
|
|
144
138
|
const legacyConnections = rawConfig.connections ?? [];
|
|
145
|
-
const legacyPeersDir = rawConfig.authorizedPeersDir ?? path.join(getPeerKeysDir(), 'authorized-clients');
|
|
146
139
|
// Auto-assign aliases to unnamed routes for the default caller
|
|
147
140
|
const connectors = legacyRoutes.map((r, i) => ({
|
|
148
141
|
...r,
|
|
@@ -153,11 +146,9 @@ export function loadRemoteConfig() {
|
|
|
153
146
|
...def,
|
|
154
147
|
host: config.host,
|
|
155
148
|
port: config.port,
|
|
156
|
-
localKeysDir: config.localKeysDir,
|
|
157
149
|
connectors,
|
|
158
150
|
callers: {
|
|
159
151
|
default: {
|
|
160
|
-
peerKeyDir: legacyPeersDir,
|
|
161
152
|
connections: allConnectionNames,
|
|
162
153
|
},
|
|
163
154
|
},
|
|
@@ -198,9 +189,9 @@ export function resolveCallerRoutes(config, callerAlias) {
|
|
|
198
189
|
return caller.connections.map((name) => {
|
|
199
190
|
// Custom connectors take precedence over built-in templates
|
|
200
191
|
const custom = connectorsByAlias.get(name);
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
return
|
|
192
|
+
const route = custom ?? loadConnection(name);
|
|
193
|
+
// Ensure every route carries its alias so it survives resolution
|
|
194
|
+
return route.alias === name ? route : { ...route, alias: name };
|
|
204
195
|
});
|
|
205
196
|
}
|
|
206
197
|
// ── Secret / placeholder resolution ──────────────────────────────────────────
|
|
@@ -220,21 +211,33 @@ export function resolvePlaceholders(str, secretsMap) {
|
|
|
220
211
|
* Load secrets from the config's secrets map, resolving from environment
|
|
221
212
|
* variables. Value can be a literal string or "${VAR_NAME}" to read from env.
|
|
222
213
|
*
|
|
223
|
-
*
|
|
224
|
-
*
|
|
214
|
+
* Resolution order for each ${VAR} reference:
|
|
215
|
+
* 1. `envOverrides[VAR]` — caller's explicit env mapping (pre-resolved)
|
|
216
|
+
* 2. `process.env[PREFIX_VAR]` — prefixed env var (e.g., ALICE_GITHUB_TOKEN)
|
|
217
|
+
* 3. Warning if not found (bare process.env fallback intentionally removed
|
|
218
|
+
* to prevent cross-caller secret leakage)
|
|
219
|
+
*
|
|
220
|
+
* When `callerAlias` is omitted, step 2 is skipped (used for resolving
|
|
221
|
+
* the caller's own env mapping where prefixing doesn't apply).
|
|
225
222
|
*/
|
|
226
|
-
export function resolveSecrets(secretsMap, envOverrides) {
|
|
223
|
+
export function resolveSecrets(secretsMap, envOverrides, callerAlias) {
|
|
227
224
|
const resolved = {};
|
|
228
225
|
for (const [key, value] of Object.entries(secretsMap)) {
|
|
229
226
|
const envMatch = /^\$\{(.+)\}$/.exec(value);
|
|
230
227
|
if (envMatch) {
|
|
231
228
|
const varName = envMatch[1];
|
|
232
|
-
|
|
229
|
+
// 1. Caller's explicit env mapping (pre-resolved values)
|
|
230
|
+
let envVal = envOverrides?.[varName];
|
|
231
|
+
// 2. Prefixed env var (e.g., ALICE_GITHUB_TOKEN for caller "alice" + var "GITHUB_TOKEN")
|
|
232
|
+
if (envVal === undefined && callerAlias) {
|
|
233
|
+
const prefix = callerAlias.toUpperCase().replace(/-/g, '_');
|
|
234
|
+
envVal = process.env[`${prefix}_${varName}`];
|
|
235
|
+
}
|
|
233
236
|
if (envVal !== undefined) {
|
|
234
237
|
resolved[key] = envVal;
|
|
235
238
|
}
|
|
236
239
|
else {
|
|
237
|
-
console.error(`[secrets] Warning: env var ${varName} not found for key ${key}`);
|
|
240
|
+
console.error(`[secrets] Warning: env var ${varName} not found for key ${key}${callerAlias ? ` (caller: ${callerAlias})` : ''}`);
|
|
238
241
|
}
|
|
239
242
|
}
|
|
240
243
|
else {
|
|
@@ -249,23 +252,33 @@ export function resolveSecrets(secretsMap, envOverrides) {
|
|
|
249
252
|
*
|
|
250
253
|
* When `envOverrides` is provided, those pre-resolved values are checked
|
|
251
254
|
* before process.env during secret resolution (used for per-caller env).
|
|
255
|
+
*
|
|
256
|
+
* When `callerAlias` is provided, prefixed env vars (e.g., ALICE_GITHUB_TOKEN)
|
|
257
|
+
* are checked as a fallback before giving up on a ${VAR} reference.
|
|
252
258
|
*/
|
|
253
|
-
export function resolveRoutes(routes, envOverrides) {
|
|
259
|
+
export function resolveRoutes(routes, envOverrides, callerAlias) {
|
|
254
260
|
return routes.map((route) => {
|
|
255
|
-
const resolvedSecrets = resolveSecrets(route.secrets ?? {}, envOverrides);
|
|
261
|
+
const resolvedSecrets = resolveSecrets(route.secrets ?? {}, envOverrides, callerAlias);
|
|
256
262
|
const resolvedHeaders = {};
|
|
257
263
|
for (const [key, value] of Object.entries(route.headers ?? {})) {
|
|
258
264
|
resolvedHeaders[key] = resolvePlaceholders(value, resolvedSecrets);
|
|
259
265
|
}
|
|
260
266
|
return {
|
|
267
|
+
...(route.alias !== undefined && { alias: route.alias }),
|
|
261
268
|
...(route.name !== undefined && { name: route.name }),
|
|
262
269
|
...(route.description !== undefined && { description: route.description }),
|
|
263
270
|
...(route.docsUrl !== undefined && { docsUrl: route.docsUrl }),
|
|
264
271
|
...(route.openApiUrl !== undefined && { openApiUrl: route.openApiUrl }),
|
|
272
|
+
...(route.stability !== undefined && { stability: route.stability }),
|
|
273
|
+
...(route.category !== undefined && { category: route.category }),
|
|
265
274
|
headers: resolvedHeaders,
|
|
266
275
|
secrets: resolvedSecrets,
|
|
267
276
|
allowedEndpoints: route.allowedEndpoints,
|
|
268
277
|
resolveSecretsInBody: route.resolveSecretsInBody ?? false,
|
|
278
|
+
...(route.testConnection !== undefined && { testConnection: route.testConnection }),
|
|
279
|
+
...(route.testIngestor !== undefined && { testIngestor: route.testIngestor }),
|
|
280
|
+
...(route.listenerConfig !== undefined && { listenerConfig: route.listenerConfig }),
|
|
281
|
+
...(route.ingestor !== undefined && { ingestorConfig: route.ingestor }),
|
|
269
282
|
};
|
|
270
283
|
});
|
|
271
284
|
}
|
|
@@ -2,13 +2,13 @@
|
|
|
2
2
|
* Connection template loading.
|
|
3
3
|
*
|
|
4
4
|
* Connections are pre-built Route templates (JSON files) that ship with
|
|
5
|
-
* the package in the connections/ directory
|
|
6
|
-
*
|
|
5
|
+
* the package in the connections/ directory, organized into category
|
|
6
|
+
* subdirectories (ai/, messaging/, social-media/, etc.).
|
|
7
7
|
*
|
|
8
8
|
* At runtime, templates are loaded from disk relative to this module's
|
|
9
9
|
* location, so they work from both src/ (dev via tsx) and dist/ (production).
|
|
10
10
|
*/
|
|
11
|
-
import type { Route } from './config.js';
|
|
11
|
+
import type { Route, ConnectionCategory } from './config.js';
|
|
12
12
|
/** Metadata about a built-in connection template — used by UIs to render
|
|
13
13
|
* connection cards, form fields, and badges without parsing raw JSON. */
|
|
14
14
|
export interface ConnectionTemplateInfo {
|
|
@@ -22,6 +22,10 @@ export interface ConnectionTemplateInfo {
|
|
|
22
22
|
docsUrl?: string;
|
|
23
23
|
/** URL to an OpenAPI / Swagger spec. */
|
|
24
24
|
openApiUrl?: string;
|
|
25
|
+
/** Stability level: "stable", "beta", or "dev". */
|
|
26
|
+
stability: 'stable' | 'beta' | 'dev';
|
|
27
|
+
/** Category grouping (e.g., "ai", "messaging", "social-media"). */
|
|
28
|
+
category: ConnectionCategory;
|
|
25
29
|
/** Secret names referenced in route headers — these are auto-injected
|
|
26
30
|
* into every request, so they must always be configured. */
|
|
27
31
|
requiredSecrets: string[];
|
|
@@ -32,9 +36,20 @@ export interface ConnectionTemplateInfo {
|
|
|
32
36
|
hasIngestor: boolean;
|
|
33
37
|
/** Ingestor type, when present. */
|
|
34
38
|
ingestorType?: 'websocket' | 'webhook' | 'poll';
|
|
39
|
+
/** Whether this connection has a pre-configured test request. */
|
|
40
|
+
hasTestConnection: boolean;
|
|
41
|
+
/** Whether this connection's ingestor has a pre-configured test. */
|
|
42
|
+
hasTestIngestor: boolean;
|
|
43
|
+
/** Whether this connection has a listener configuration schema. */
|
|
44
|
+
hasListenerConfig: boolean;
|
|
45
|
+
/** Whether this connection's listener supports multiple concurrent instances
|
|
46
|
+
* (e.g., watching multiple Trello boards or Reddit subreddits simultaneously). */
|
|
47
|
+
supportsMultiInstance: boolean;
|
|
35
48
|
/** Allowlisted URL patterns (glob). */
|
|
36
49
|
allowedEndpoints: string[];
|
|
37
50
|
}
|
|
51
|
+
/** Invalidate the cached index. Exported for testing only. */
|
|
52
|
+
export declare function _resetConnectionIndex(): void;
|
|
38
53
|
/**
|
|
39
54
|
* Load a single connection template by name.
|
|
40
55
|
*
|
|
@@ -47,8 +62,9 @@ export declare function loadConnection(name: string): Route;
|
|
|
47
62
|
/**
|
|
48
63
|
* List all available connection template names.
|
|
49
64
|
*
|
|
50
|
-
* Scans the connections directory
|
|
51
|
-
* basenames (without extension), sorted
|
|
65
|
+
* Scans the connections directory (including category subdirectories) for
|
|
66
|
+
* .json files and returns their basenames (without extension), sorted
|
|
67
|
+
* alphabetically.
|
|
52
68
|
*/
|
|
53
69
|
export declare function listAvailableConnections(): string[];
|
|
54
70
|
/**
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
* Connection template loading.
|
|
3
3
|
*
|
|
4
4
|
* Connections are pre-built Route templates (JSON files) that ship with
|
|
5
|
-
* the package in the connections/ directory
|
|
6
|
-
*
|
|
5
|
+
* the package in the connections/ directory, organized into category
|
|
6
|
+
* subdirectories (ai/, messaging/, social-media/, etc.).
|
|
7
7
|
*
|
|
8
8
|
* At runtime, templates are loaded from disk relative to this module's
|
|
9
9
|
* location, so they work from both src/ (dev via tsx) and dist/ (production).
|
|
@@ -13,6 +13,46 @@ import path from 'node:path';
|
|
|
13
13
|
import { fileURLToPath } from 'node:url';
|
|
14
14
|
/** Directory containing connection template JSON files. */
|
|
15
15
|
const CONNECTIONS_DIR = path.join(path.dirname(fileURLToPath(import.meta.url)), '..', 'connections');
|
|
16
|
+
// ── Lazy-cached alias→filepath index ──────────────────────────────────────
|
|
17
|
+
/** Cached alias → absolute filepath index. Built lazily on first access.
|
|
18
|
+
* Supports both flat files (connections/foo.json) and category
|
|
19
|
+
* subdirectories (connections/ai/anthropic.json). */
|
|
20
|
+
let connectionIndex = null;
|
|
21
|
+
/** Build the alias→filepath index by scanning CONNECTIONS_DIR.
|
|
22
|
+
* Files at the top level and files in one level of subdirectories are
|
|
23
|
+
* both indexed. The alias is always the filename without .json. */
|
|
24
|
+
function getConnectionIndex() {
|
|
25
|
+
if (connectionIndex)
|
|
26
|
+
return connectionIndex;
|
|
27
|
+
connectionIndex = new Map();
|
|
28
|
+
if (!fs.existsSync(CONNECTIONS_DIR))
|
|
29
|
+
return connectionIndex;
|
|
30
|
+
const entries = fs.readdirSync(CONNECTIONS_DIR, { withFileTypes: true });
|
|
31
|
+
for (const entry of entries) {
|
|
32
|
+
if (entry.isFile() && entry.name.endsWith('.json')) {
|
|
33
|
+
// Top-level JSON file (backward compat)
|
|
34
|
+
const alias = entry.name.replace(/\.json$/, '');
|
|
35
|
+
connectionIndex.set(alias, path.join(CONNECTIONS_DIR, entry.name));
|
|
36
|
+
}
|
|
37
|
+
else if (entry.isDirectory()) {
|
|
38
|
+
// Category subdirectory — scan one level deep
|
|
39
|
+
const subdir = path.join(CONNECTIONS_DIR, entry.name);
|
|
40
|
+
const subEntries = fs.readdirSync(subdir, 'utf-8');
|
|
41
|
+
for (const subFile of subEntries) {
|
|
42
|
+
if (subFile.endsWith('.json')) {
|
|
43
|
+
const alias = subFile.replace(/\.json$/, '');
|
|
44
|
+
connectionIndex.set(alias, path.join(subdir, subFile));
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return connectionIndex;
|
|
50
|
+
}
|
|
51
|
+
/** Invalidate the cached index. Exported for testing only. */
|
|
52
|
+
export function _resetConnectionIndex() {
|
|
53
|
+
connectionIndex = null;
|
|
54
|
+
}
|
|
55
|
+
// ── Public API ────────────────────────────────────────────────────────────
|
|
16
56
|
/**
|
|
17
57
|
* Load a single connection template by name.
|
|
18
58
|
*
|
|
@@ -22,8 +62,9 @@ const CONNECTIONS_DIR = path.join(path.dirname(fileURLToPath(import.meta.url)),
|
|
|
22
62
|
* @throws If the template file does not exist or contains invalid JSON.
|
|
23
63
|
*/
|
|
24
64
|
export function loadConnection(name) {
|
|
25
|
-
const
|
|
26
|
-
|
|
65
|
+
const index = getConnectionIndex();
|
|
66
|
+
const filePath = index.get(name);
|
|
67
|
+
if (!filePath) {
|
|
27
68
|
const available = listAvailableConnections();
|
|
28
69
|
throw new Error(`Unknown connection "${name}". Available connections: ${available.join(', ') || '(none)'}`);
|
|
29
70
|
}
|
|
@@ -33,18 +74,13 @@ export function loadConnection(name) {
|
|
|
33
74
|
/**
|
|
34
75
|
* List all available connection template names.
|
|
35
76
|
*
|
|
36
|
-
* Scans the connections directory
|
|
37
|
-
* basenames (without extension), sorted
|
|
77
|
+
* Scans the connections directory (including category subdirectories) for
|
|
78
|
+
* .json files and returns their basenames (without extension), sorted
|
|
79
|
+
* alphabetically.
|
|
38
80
|
*/
|
|
39
81
|
export function listAvailableConnections() {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
}
|
|
43
|
-
return fs
|
|
44
|
-
.readdirSync(CONNECTIONS_DIR, 'utf-8')
|
|
45
|
-
.filter((f) => f.endsWith('.json'))
|
|
46
|
-
.map((f) => f.replace(/\.json$/, ''))
|
|
47
|
-
.sort();
|
|
82
|
+
const index = getConnectionIndex();
|
|
83
|
+
return [...index.keys()].sort();
|
|
48
84
|
}
|
|
49
85
|
// ── Template introspection ────────────────────────────────────────────────
|
|
50
86
|
/** Extract ${VAR} placeholder names from a string. */
|
|
@@ -92,10 +128,16 @@ export function listConnectionTemplates() {
|
|
|
92
128
|
...(route.description !== undefined && { description: route.description }),
|
|
93
129
|
...(route.docsUrl !== undefined && { docsUrl: route.docsUrl }),
|
|
94
130
|
...(route.openApiUrl !== undefined && { openApiUrl: route.openApiUrl }),
|
|
131
|
+
stability: route.stability ?? 'dev',
|
|
132
|
+
category: route.category,
|
|
95
133
|
requiredSecrets,
|
|
96
134
|
optionalSecrets,
|
|
97
135
|
hasIngestor: route.ingestor !== undefined,
|
|
98
136
|
...(route.ingestor !== undefined && { ingestorType: route.ingestor.type }),
|
|
137
|
+
hasTestConnection: route.testConnection !== undefined,
|
|
138
|
+
hasTestIngestor: route.testIngestor !== undefined && route.testIngestor !== null,
|
|
139
|
+
hasListenerConfig: route.listenerConfig !== undefined,
|
|
140
|
+
supportsMultiInstance: route.listenerConfig?.supportsMultiInstance ?? false,
|
|
99
141
|
allowedEndpoints: route.allowedEndpoints,
|
|
100
142
|
};
|
|
101
143
|
});
|
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
export { type KeyBundle, type SerializedKeyBundle, type PublicKeyBundle, type SerializedPublicKeys, generateKeyBundle, extractPublicKeys, serializeKeyBundle, deserializeKeyBundle, serializePublicKeys, deserializePublicKeys, saveKeyBundle, loadKeyBundle, loadPublicKeys, fingerprint, } from './keys.js';
|
|
2
2
|
export { type DirectionalKey, type SessionKeys, deriveSessionKeys, EncryptedChannel, } from './channel.js';
|
|
3
|
+
export { type CreateCallerResult, createCaller, exportCallerPublicKeys, exportServerPublicKeys, importCallerPublicKeys, saveServerPublicKeys, listCallers, callerExists, serverExists, callerFingerprint, serverFingerprint, } from './key-manager.js';
|
|
3
4
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
export { generateKeyBundle, extractPublicKeys, serializeKeyBundle, deserializeKeyBundle, serializePublicKeys, deserializePublicKeys, saveKeyBundle, loadKeyBundle, loadPublicKeys, fingerprint, } from './keys.js';
|
|
2
2
|
export { deriveSessionKeys, EncryptedChannel, } from './channel.js';
|
|
3
|
+
export { createCaller, exportCallerPublicKeys, exportServerPublicKeys, importCallerPublicKeys, saveServerPublicKeys, listCallers, callerExists, serverExists, callerFingerprint, serverFingerprint, } from './key-manager.js';
|
|
3
4
|
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* High-level key management API.
|
|
3
|
+
*
|
|
4
|
+
* Provides CRUD operations over the drawlatch key directory structure
|
|
5
|
+
* so that callboard (and other consumers) can manage keys programmatically
|
|
6
|
+
* without touching the filesystem directly.
|
|
7
|
+
*
|
|
8
|
+
* Key layout:
|
|
9
|
+
* keys/callers/<alias>/ — Caller keypairs (one per alias)
|
|
10
|
+
* keys/server/ — Server keypair (single, flat)
|
|
11
|
+
*/
|
|
12
|
+
import { type SerializedPublicKeys } from './keys.js';
|
|
13
|
+
export interface CreateCallerResult {
|
|
14
|
+
publicKeys: SerializedPublicKeys;
|
|
15
|
+
fingerprint: string;
|
|
16
|
+
}
|
|
17
|
+
interface KeyManagerOpts {
|
|
18
|
+
configDir?: string;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Create a new caller identity (Ed25519 + X25519 keypairs).
|
|
22
|
+
* Saves under `keys/callers/<alias>/`.
|
|
23
|
+
* Throws if the alias already exists.
|
|
24
|
+
*/
|
|
25
|
+
export declare function createCaller(alias: string, opts?: KeyManagerOpts): CreateCallerResult;
|
|
26
|
+
/**
|
|
27
|
+
* Export public keys for a caller identity.
|
|
28
|
+
* Reads from `keys/callers/<alias>/`.
|
|
29
|
+
*/
|
|
30
|
+
export declare function exportCallerPublicKeys(alias: string, opts?: KeyManagerOpts): SerializedPublicKeys;
|
|
31
|
+
/**
|
|
32
|
+
* Export public keys for the server.
|
|
33
|
+
* Reads from `keys/server/`.
|
|
34
|
+
*/
|
|
35
|
+
export declare function exportServerPublicKeys(opts?: KeyManagerOpts): SerializedPublicKeys;
|
|
36
|
+
/**
|
|
37
|
+
* Import a caller's public keys. Saves under `keys/callers/<alias>/`.
|
|
38
|
+
* Used by the server to store received caller public keys (e.g., via sync).
|
|
39
|
+
*/
|
|
40
|
+
export declare function importCallerPublicKeys(alias: string, keys: SerializedPublicKeys, opts?: KeyManagerOpts): void;
|
|
41
|
+
/**
|
|
42
|
+
* Save server public keys. Writes to `keys/server/`.
|
|
43
|
+
* Used by callboard to store the remote server's public keys (e.g., via sync).
|
|
44
|
+
*/
|
|
45
|
+
export declare function saveServerPublicKeys(keys: SerializedPublicKeys, opts?: KeyManagerOpts): void;
|
|
46
|
+
/**
|
|
47
|
+
* List all caller aliases (scans `keys/callers/`).
|
|
48
|
+
*/
|
|
49
|
+
export declare function listCallers(opts?: KeyManagerOpts): string[];
|
|
50
|
+
/**
|
|
51
|
+
* Check if a caller identity exists (has at least public keys).
|
|
52
|
+
*/
|
|
53
|
+
export declare function callerExists(alias: string, opts?: KeyManagerOpts): boolean;
|
|
54
|
+
/**
|
|
55
|
+
* Check if server keys exist.
|
|
56
|
+
*/
|
|
57
|
+
export declare function serverExists(opts?: KeyManagerOpts): boolean;
|
|
58
|
+
/**
|
|
59
|
+
* Get the fingerprint of a caller's keys.
|
|
60
|
+
*/
|
|
61
|
+
export declare function callerFingerprint(alias: string, opts?: KeyManagerOpts): string;
|
|
62
|
+
/**
|
|
63
|
+
* Get the fingerprint of the server's keys.
|
|
64
|
+
*/
|
|
65
|
+
export declare function serverFingerprint(opts?: KeyManagerOpts): string;
|
|
66
|
+
export {};
|
|
67
|
+
//# sourceMappingURL=key-manager.d.ts.map
|