@nkmc/gateway 0.1.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/dist/chunk-56RA53VS.js +37 -0
- package/dist/chunk-CZJ75YTV.js +969 -0
- package/dist/chunk-QGM4M3NI.js +37 -0
- package/dist/http.cjs +1772 -0
- package/dist/http.d.cts +49 -0
- package/dist/http.d.ts +49 -0
- package/dist/http.js +748 -0
- package/dist/index.cjs +2436 -0
- package/dist/index.d.cts +436 -0
- package/dist/index.d.ts +436 -0
- package/dist/index.js +1434 -0
- package/dist/proxy-ClPcDgsO.d.cts +283 -0
- package/dist/proxy-qpda1ANS.d.ts +283 -0
- package/dist/proxy.cjs +148 -0
- package/dist/proxy.d.cts +6 -0
- package/dist/proxy.d.ts +6 -0
- package/dist/proxy.js +90 -0
- package/dist/testing.cjs +865 -0
- package/dist/testing.d.cts +12 -0
- package/dist/testing.d.ts +12 -0
- package/dist/testing.js +831 -0
- package/dist/tunnels-BviBEaih.d.cts +12 -0
- package/dist/tunnels-DFHNgmN7.d.ts +12 -0
- package/dist/types-C6JC9oTm.d.cts +21 -0
- package/dist/types-C6JC9oTm.d.ts +21 -0
- package/package.json +47 -0
- package/src/__tests__/sqlite-integration.test.ts +384 -0
- package/src/credential/d1-vault.ts +134 -0
- package/src/credential/memory-vault.ts +50 -0
- package/src/credential/types.ts +16 -0
- package/src/d1/__tests__/sqlite-adapter.test.ts +75 -0
- package/src/d1/sqlite-adapter.ts +59 -0
- package/src/d1/types.ts +22 -0
- package/src/federation/__tests__/d1-peer-store.test.ts +218 -0
- package/src/federation/__tests__/peer-client.test.ts +205 -0
- package/src/federation/__tests__/peer-store.test.ts +114 -0
- package/src/federation/d1-peer-store.ts +164 -0
- package/src/federation/peer-backend.ts +60 -0
- package/src/federation/peer-client.ts +122 -0
- package/src/federation/peer-store.ts +45 -0
- package/src/federation/types.ts +39 -0
- package/src/http/app.ts +152 -0
- package/src/http/lib/dns.ts +30 -0
- package/src/http/middleware/admin-auth.ts +18 -0
- package/src/http/middleware/agent-auth.ts +27 -0
- package/src/http/middleware/publish-auth.ts +39 -0
- package/src/http/routes/__tests__/federation.test.ts +364 -0
- package/src/http/routes/__tests__/peers.test.ts +290 -0
- package/src/http/routes/__tests__/proxy.test.ts +159 -0
- package/src/http/routes/auth.ts +39 -0
- package/src/http/routes/byok.ts +62 -0
- package/src/http/routes/credentials.ts +40 -0
- package/src/http/routes/domains.ts +174 -0
- package/src/http/routes/federation.ts +170 -0
- package/src/http/routes/fs.ts +89 -0
- package/src/http/routes/peers.ts +103 -0
- package/src/http/routes/proxy.ts +57 -0
- package/src/http/routes/registry.ts +222 -0
- package/src/http/routes/tunnels.ts +124 -0
- package/src/http.ts +9 -0
- package/src/index.ts +63 -0
- package/src/metering/d1-store.ts +123 -0
- package/src/metering/memory-store.ts +29 -0
- package/src/metering/pricing-guard.ts +68 -0
- package/src/metering/types.ts +25 -0
- package/src/onboard/apis-guru.ts +64 -0
- package/src/onboard/index.ts +4 -0
- package/src/onboard/manifest.ts +362 -0
- package/src/onboard/pipeline.ts +214 -0
- package/src/onboard/types.ts +72 -0
- package/src/proxy/__tests__/tool-registry.test.ts +93 -0
- package/src/proxy/tool-registry.ts +122 -0
- package/src/proxy.ts +12 -0
- package/src/registry/context7-backend.ts +93 -0
- package/src/registry/context7.ts +54 -0
- package/src/registry/d1-store.ts +242 -0
- package/src/registry/memory-store.ts +101 -0
- package/src/registry/openapi-compiler.ts +284 -0
- package/src/registry/resolver.ts +196 -0
- package/src/registry/rpc-compiler.ts +142 -0
- package/src/registry/skill-parser.ts +119 -0
- package/src/registry/skill-to-config.ts +239 -0
- package/src/registry/source-refresher.ts +83 -0
- package/src/registry/types.ts +129 -0
- package/src/registry/virtual-files.ts +76 -0
- package/src/testing/sqlite-d1.ts +64 -0
- package/src/testing.ts +2 -0
- package/src/tunnel/__tests__/cloudflare-provider.test.ts +255 -0
- package/src/tunnel/__tests__/tunnel.test.ts +542 -0
- package/src/tunnel/cloudflare-provider.ts +121 -0
- package/src/tunnel/memory-store.ts +30 -0
- package/src/tunnel/types.ts +28 -0
- package/test/credential/d1-vault.test.ts +127 -0
- package/test/credential/injection.test.ts +67 -0
- package/test/credential/memory-vault.test.ts +63 -0
- package/test/http/app.test.ts +300 -0
- package/test/http/byok-e2e.test.ts +240 -0
- package/test/http/byok.test.ts +115 -0
- package/test/http/credentials.test.ts +57 -0
- package/test/http/e2e.test.ts +260 -0
- package/test/integration/authenticated-apis.test.ts +185 -0
- package/test/integration/free-apis-e2e.test.ts +222 -0
- package/test/metering/d1-store.test.ts +82 -0
- package/test/metering/memory-store.test.ts +76 -0
- package/test/metering/pricing-guard.test.ts +108 -0
- package/test/onboard/apis-guru.test.ts +57 -0
- package/test/onboard/e2e.test.ts +70 -0
- package/test/onboard/pipeline.test.ts +318 -0
- package/test/onboard/real-apis.test.ts +483 -0
- package/test/registry/compilation-correctness.test.ts +132 -0
- package/test/registry/context7-backend.test.ts +88 -0
- package/test/registry/context7-e2e.test.ts +92 -0
- package/test/registry/context7.test.ts +73 -0
- package/test/registry/d1-store.test.ts +184 -0
- package/test/registry/integration.test.ts +129 -0
- package/test/registry/lazy-mount.test.ts +138 -0
- package/test/registry/memory-store.test.ts +171 -0
- package/test/registry/openapi-compiler.test.ts +267 -0
- package/test/registry/openapi-e2e.test.ts +154 -0
- package/test/registry/passthrough-e2e.test.ts +109 -0
- package/test/registry/resolver-peer.test.ts +299 -0
- package/test/registry/resolver.test.ts +228 -0
- package/test/registry/rpc-compiler.test.ts +112 -0
- package/test/registry/skill-parser.test.ts +151 -0
- package/test/registry/skill-to-config.test.ts +151 -0
- package/test/registry/skill-to-rpc-config.test.ts +142 -0
- package/test/registry/source-refresher.test.ts +90 -0
- package/test/registry/virtual-files.test.ts +96 -0
- package/tsconfig.json +4 -0
- package/tsup.config.ts +8 -0
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
import { HttpAuth } from '@nkmc/agent-fs';
|
|
2
|
+
import * as hono_types from 'hono/types';
|
|
3
|
+
import { Hono } from 'hono';
|
|
4
|
+
import { JWK } from 'jose';
|
|
5
|
+
import { D as D1Database } from './types-C6JC9oTm.cjs';
|
|
6
|
+
|
|
7
|
+
type ServiceStatus = "active" | "deprecated" | "sunset";
|
|
8
|
+
interface EndpointPricing {
|
|
9
|
+
cost: number;
|
|
10
|
+
currency: string;
|
|
11
|
+
per: "call" | "byte" | "minute";
|
|
12
|
+
}
|
|
13
|
+
interface EndpointAnnotations {
|
|
14
|
+
rateLimit?: number;
|
|
15
|
+
cacheTtl?: number;
|
|
16
|
+
tags?: string[];
|
|
17
|
+
}
|
|
18
|
+
interface EndpointParam {
|
|
19
|
+
name: string;
|
|
20
|
+
in: "path" | "query" | "header";
|
|
21
|
+
required: boolean;
|
|
22
|
+
type: string;
|
|
23
|
+
description?: string;
|
|
24
|
+
}
|
|
25
|
+
interface SchemaProperty {
|
|
26
|
+
name: string;
|
|
27
|
+
type: string;
|
|
28
|
+
required: boolean;
|
|
29
|
+
description?: string;
|
|
30
|
+
}
|
|
31
|
+
interface EndpointRecord {
|
|
32
|
+
method: string;
|
|
33
|
+
path: string;
|
|
34
|
+
description: string;
|
|
35
|
+
price?: string;
|
|
36
|
+
pricing?: EndpointPricing;
|
|
37
|
+
annotations?: EndpointAnnotations;
|
|
38
|
+
parameters?: EndpointParam[];
|
|
39
|
+
requestBody?: {
|
|
40
|
+
contentType: string;
|
|
41
|
+
required: boolean;
|
|
42
|
+
properties: SchemaProperty[];
|
|
43
|
+
};
|
|
44
|
+
responses?: {
|
|
45
|
+
status: number;
|
|
46
|
+
description: string;
|
|
47
|
+
properties?: SchemaProperty[];
|
|
48
|
+
}[];
|
|
49
|
+
}
|
|
50
|
+
/** @deprecated Use EndpointRecord instead */
|
|
51
|
+
type EndpointSummary = EndpointRecord;
|
|
52
|
+
interface RpcSourceMeta {
|
|
53
|
+
rpcUrl: string;
|
|
54
|
+
convention: "crud" | "evm" | "raw";
|
|
55
|
+
resources: Array<{
|
|
56
|
+
name: string;
|
|
57
|
+
idField?: string;
|
|
58
|
+
methods: Record<string, string>;
|
|
59
|
+
}>;
|
|
60
|
+
}
|
|
61
|
+
interface SourceConfig {
|
|
62
|
+
type: "skillmd" | "openapi" | "wellknown" | "jsonrpc";
|
|
63
|
+
url?: string;
|
|
64
|
+
basePath?: string;
|
|
65
|
+
refreshInterval?: number;
|
|
66
|
+
lastRefresh?: number;
|
|
67
|
+
rpc?: RpcSourceMeta;
|
|
68
|
+
}
|
|
69
|
+
interface ServiceRecord {
|
|
70
|
+
domain: string;
|
|
71
|
+
name: string;
|
|
72
|
+
description: string;
|
|
73
|
+
version: string;
|
|
74
|
+
roles: string[];
|
|
75
|
+
skillMd: string;
|
|
76
|
+
endpoints: EndpointRecord[];
|
|
77
|
+
isFirstParty: boolean;
|
|
78
|
+
createdAt: number;
|
|
79
|
+
updatedAt: number;
|
|
80
|
+
status: ServiceStatus;
|
|
81
|
+
isDefault: boolean;
|
|
82
|
+
sunsetDate?: number;
|
|
83
|
+
source?: SourceConfig;
|
|
84
|
+
authMode?: "nkmc-jwt";
|
|
85
|
+
}
|
|
86
|
+
interface ServiceSummary {
|
|
87
|
+
domain: string;
|
|
88
|
+
name: string;
|
|
89
|
+
description: string;
|
|
90
|
+
isFirstParty: boolean;
|
|
91
|
+
}
|
|
92
|
+
interface SearchResult {
|
|
93
|
+
domain: string;
|
|
94
|
+
name: string;
|
|
95
|
+
description: string;
|
|
96
|
+
isFirstParty: boolean;
|
|
97
|
+
matchedEndpoints: Pick<EndpointRecord, "method" | "path" | "description">[];
|
|
98
|
+
}
|
|
99
|
+
interface VersionSummary {
|
|
100
|
+
version: string;
|
|
101
|
+
status: ServiceStatus;
|
|
102
|
+
isDefault: boolean;
|
|
103
|
+
createdAt: number;
|
|
104
|
+
updatedAt: number;
|
|
105
|
+
}
|
|
106
|
+
interface RegistryStats {
|
|
107
|
+
serviceCount: number;
|
|
108
|
+
endpointCount: number;
|
|
109
|
+
}
|
|
110
|
+
interface RegistryStore {
|
|
111
|
+
get(domain: string): Promise<ServiceRecord | null>;
|
|
112
|
+
getVersion(domain: string, version: string): Promise<ServiceRecord | null>;
|
|
113
|
+
listVersions(domain: string): Promise<VersionSummary[]>;
|
|
114
|
+
put(domain: string, record: ServiceRecord): Promise<void>;
|
|
115
|
+
delete(domain: string): Promise<void>;
|
|
116
|
+
list(): Promise<ServiceSummary[]>;
|
|
117
|
+
search(query: string): Promise<SearchResult[]>;
|
|
118
|
+
stats?(): Promise<RegistryStats>;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
interface StoredCredential {
|
|
122
|
+
domain: string;
|
|
123
|
+
auth: HttpAuth;
|
|
124
|
+
scope: "pool" | "byok";
|
|
125
|
+
developerId?: string;
|
|
126
|
+
}
|
|
127
|
+
interface CredentialVault {
|
|
128
|
+
get(domain: string, developerId?: string): Promise<StoredCredential | null>;
|
|
129
|
+
putPool(domain: string, auth: HttpAuth): Promise<void>;
|
|
130
|
+
putByok(domain: string, developerId: string, auth: HttpAuth): Promise<void>;
|
|
131
|
+
delete(domain: string, developerId?: string): Promise<void>;
|
|
132
|
+
listDomains(): Promise<string[]>;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/** Field names that can be extracted from an HttpAuth credential. */
|
|
136
|
+
type AuthField = "token" | "key" | "username" | "password";
|
|
137
|
+
/**
|
|
138
|
+
* Defines how a CLI tool maps to a credential domain and which
|
|
139
|
+
* environment variables should be injected at runtime.
|
|
140
|
+
*/
|
|
141
|
+
interface ToolDefinition {
|
|
142
|
+
/** CLI tool name, e.g. "gh", "stripe" */
|
|
143
|
+
name: string;
|
|
144
|
+
/** Domain used to look up credentials in the vault */
|
|
145
|
+
credentialDomain: string;
|
|
146
|
+
/** Maps env var name → field to extract from HttpAuth */
|
|
147
|
+
envMapping: Record<string, AuthField>;
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Registry of CLI tools that can be proxied through the gateway.
|
|
151
|
+
* Each tool declares the credential domain it needs and how to
|
|
152
|
+
* translate stored credentials into environment variables.
|
|
153
|
+
*/
|
|
154
|
+
declare class ToolRegistry {
|
|
155
|
+
private tools;
|
|
156
|
+
/** Register a tool definition. Overwrites any existing entry with the same name. */
|
|
157
|
+
register(tool: ToolDefinition): void;
|
|
158
|
+
/** Look up a tool by name. Returns null if not found. */
|
|
159
|
+
get(name: string): ToolDefinition | null;
|
|
160
|
+
/** Return all registered tool definitions. */
|
|
161
|
+
list(): ToolDefinition[];
|
|
162
|
+
/**
|
|
163
|
+
* Build a record of environment variables for the given tool by
|
|
164
|
+
* extracting the requested fields from the HttpAuth credential.
|
|
165
|
+
*
|
|
166
|
+
* If the auth type does not contain the requested field (e.g.
|
|
167
|
+
* requesting "token" from a basic-auth credential), that env var
|
|
168
|
+
* is silently omitted.
|
|
169
|
+
*/
|
|
170
|
+
buildEnv(tool: ToolDefinition, auth: HttpAuth): Record<string, string>;
|
|
171
|
+
}
|
|
172
|
+
/** Create a ToolRegistry pre-populated with common CLI tools. */
|
|
173
|
+
declare function createDefaultToolRegistry(): ToolRegistry;
|
|
174
|
+
|
|
175
|
+
interface ExecResult {
|
|
176
|
+
stdout: string;
|
|
177
|
+
stderr: string;
|
|
178
|
+
exitCode: number;
|
|
179
|
+
}
|
|
180
|
+
interface ProxyRouteOptions {
|
|
181
|
+
vault: CredentialVault;
|
|
182
|
+
toolRegistry: ToolRegistry;
|
|
183
|
+
exec: (tool: string, args: string[], env: Record<string, string>) => Promise<ExecResult>;
|
|
184
|
+
}
|
|
185
|
+
declare function proxyRoutes(options: ProxyRouteOptions): Hono<Env, hono_types.BlankSchema, "/">;
|
|
186
|
+
|
|
187
|
+
interface PeerGateway {
|
|
188
|
+
id: string;
|
|
189
|
+
name: string;
|
|
190
|
+
url: string;
|
|
191
|
+
sharedSecret: string;
|
|
192
|
+
status: "active" | "inactive";
|
|
193
|
+
advertisedDomains: string[];
|
|
194
|
+
lastSeen: number;
|
|
195
|
+
createdAt: number;
|
|
196
|
+
}
|
|
197
|
+
interface LendingRule {
|
|
198
|
+
domain: string;
|
|
199
|
+
allow: boolean;
|
|
200
|
+
peers: string[] | "*";
|
|
201
|
+
pricing: {
|
|
202
|
+
mode: "free" | "per-request" | "per-token";
|
|
203
|
+
amount?: number;
|
|
204
|
+
};
|
|
205
|
+
rateLimit?: {
|
|
206
|
+
requests: number;
|
|
207
|
+
window: "minute" | "hour" | "day";
|
|
208
|
+
};
|
|
209
|
+
createdAt: number;
|
|
210
|
+
updatedAt: number;
|
|
211
|
+
}
|
|
212
|
+
interface PeerStore {
|
|
213
|
+
getPeer(id: string): Promise<PeerGateway | null>;
|
|
214
|
+
putPeer(peer: PeerGateway): Promise<void>;
|
|
215
|
+
deletePeer(id: string): Promise<void>;
|
|
216
|
+
listPeers(): Promise<PeerGateway[]>;
|
|
217
|
+
updateLastSeen(id: string, timestamp: number): Promise<void>;
|
|
218
|
+
getRule(domain: string): Promise<LendingRule | null>;
|
|
219
|
+
putRule(rule: LendingRule): Promise<void>;
|
|
220
|
+
deleteRule(domain: string): Promise<void>;
|
|
221
|
+
listRules(): Promise<LendingRule[]>;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
interface TunnelRecord {
|
|
225
|
+
id: string;
|
|
226
|
+
agentId: string;
|
|
227
|
+
tunnelId: string;
|
|
228
|
+
publicUrl: string;
|
|
229
|
+
status: "active" | "deleted";
|
|
230
|
+
createdAt: number;
|
|
231
|
+
/** Domains this gateway has credentials for (for discovery) */
|
|
232
|
+
advertisedDomains: string[];
|
|
233
|
+
/** Display name for the gateway */
|
|
234
|
+
gatewayName?: string;
|
|
235
|
+
/** Last heartbeat timestamp (ms since epoch) */
|
|
236
|
+
lastSeen: number;
|
|
237
|
+
}
|
|
238
|
+
interface TunnelStore {
|
|
239
|
+
get(id: string): Promise<TunnelRecord | null>;
|
|
240
|
+
getByAgent(agentId: string): Promise<TunnelRecord | null>;
|
|
241
|
+
put(record: TunnelRecord): Promise<void>;
|
|
242
|
+
delete(id: string): Promise<void>;
|
|
243
|
+
list(): Promise<TunnelRecord[]>;
|
|
244
|
+
}
|
|
245
|
+
/** Interface for Cloudflare Tunnel API operations */
|
|
246
|
+
interface TunnelProvider {
|
|
247
|
+
create(name: string, hostname: string): Promise<{
|
|
248
|
+
tunnelId: string;
|
|
249
|
+
tunnelToken: string;
|
|
250
|
+
}>;
|
|
251
|
+
delete(tunnelId: string): Promise<void>;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
type Env = {
|
|
255
|
+
Variables: {
|
|
256
|
+
agent: {
|
|
257
|
+
id: string;
|
|
258
|
+
roles: string[];
|
|
259
|
+
};
|
|
260
|
+
};
|
|
261
|
+
};
|
|
262
|
+
interface GatewayOptions {
|
|
263
|
+
store: RegistryStore;
|
|
264
|
+
gatewayPrivateKey: JWK;
|
|
265
|
+
gatewayPublicKey: JWK;
|
|
266
|
+
adminToken: string;
|
|
267
|
+
db?: D1Database;
|
|
268
|
+
vault?: CredentialVault;
|
|
269
|
+
context7ApiKey?: string;
|
|
270
|
+
peerStore?: PeerStore;
|
|
271
|
+
proxy?: {
|
|
272
|
+
toolRegistry: ToolRegistry;
|
|
273
|
+
exec: (tool: string, args: string[], env: Record<string, string>) => Promise<ExecResult>;
|
|
274
|
+
};
|
|
275
|
+
tunnel?: {
|
|
276
|
+
store: TunnelStore;
|
|
277
|
+
provider: TunnelProvider;
|
|
278
|
+
domain: string;
|
|
279
|
+
};
|
|
280
|
+
}
|
|
281
|
+
declare function createGateway(options: GatewayOptions): Hono<Env>;
|
|
282
|
+
|
|
283
|
+
export { type AuthField as A, type CredentialVault as C, type Env as E, type GatewayOptions as G, type LendingRule as L, type PeerGateway as P, type RegistryStore as R, type ServiceRecord as S, type TunnelStore as T, type VersionSummary as V, type TunnelProvider as a, type ServiceSummary as b, createGateway as c, type SearchResult as d, type RegistryStats as e, type EndpointPricing as f, type EndpointRecord as g, type StoredCredential as h, type PeerStore as i, type TunnelRecord as j, type EndpointAnnotations as k, type EndpointSummary as l, type ServiceStatus as m, type SourceConfig as n, type ExecResult as o, type ProxyRouteOptions as p, type ToolDefinition as q, ToolRegistry as r, createDefaultToolRegistry as s, proxyRoutes as t };
|
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
import { HttpAuth } from '@nkmc/agent-fs';
|
|
2
|
+
import * as hono_types from 'hono/types';
|
|
3
|
+
import { Hono } from 'hono';
|
|
4
|
+
import { JWK } from 'jose';
|
|
5
|
+
import { D as D1Database } from './types-C6JC9oTm.js';
|
|
6
|
+
|
|
7
|
+
type ServiceStatus = "active" | "deprecated" | "sunset";
|
|
8
|
+
interface EndpointPricing {
|
|
9
|
+
cost: number;
|
|
10
|
+
currency: string;
|
|
11
|
+
per: "call" | "byte" | "minute";
|
|
12
|
+
}
|
|
13
|
+
interface EndpointAnnotations {
|
|
14
|
+
rateLimit?: number;
|
|
15
|
+
cacheTtl?: number;
|
|
16
|
+
tags?: string[];
|
|
17
|
+
}
|
|
18
|
+
interface EndpointParam {
|
|
19
|
+
name: string;
|
|
20
|
+
in: "path" | "query" | "header";
|
|
21
|
+
required: boolean;
|
|
22
|
+
type: string;
|
|
23
|
+
description?: string;
|
|
24
|
+
}
|
|
25
|
+
interface SchemaProperty {
|
|
26
|
+
name: string;
|
|
27
|
+
type: string;
|
|
28
|
+
required: boolean;
|
|
29
|
+
description?: string;
|
|
30
|
+
}
|
|
31
|
+
interface EndpointRecord {
|
|
32
|
+
method: string;
|
|
33
|
+
path: string;
|
|
34
|
+
description: string;
|
|
35
|
+
price?: string;
|
|
36
|
+
pricing?: EndpointPricing;
|
|
37
|
+
annotations?: EndpointAnnotations;
|
|
38
|
+
parameters?: EndpointParam[];
|
|
39
|
+
requestBody?: {
|
|
40
|
+
contentType: string;
|
|
41
|
+
required: boolean;
|
|
42
|
+
properties: SchemaProperty[];
|
|
43
|
+
};
|
|
44
|
+
responses?: {
|
|
45
|
+
status: number;
|
|
46
|
+
description: string;
|
|
47
|
+
properties?: SchemaProperty[];
|
|
48
|
+
}[];
|
|
49
|
+
}
|
|
50
|
+
/** @deprecated Use EndpointRecord instead */
|
|
51
|
+
type EndpointSummary = EndpointRecord;
|
|
52
|
+
interface RpcSourceMeta {
|
|
53
|
+
rpcUrl: string;
|
|
54
|
+
convention: "crud" | "evm" | "raw";
|
|
55
|
+
resources: Array<{
|
|
56
|
+
name: string;
|
|
57
|
+
idField?: string;
|
|
58
|
+
methods: Record<string, string>;
|
|
59
|
+
}>;
|
|
60
|
+
}
|
|
61
|
+
interface SourceConfig {
|
|
62
|
+
type: "skillmd" | "openapi" | "wellknown" | "jsonrpc";
|
|
63
|
+
url?: string;
|
|
64
|
+
basePath?: string;
|
|
65
|
+
refreshInterval?: number;
|
|
66
|
+
lastRefresh?: number;
|
|
67
|
+
rpc?: RpcSourceMeta;
|
|
68
|
+
}
|
|
69
|
+
interface ServiceRecord {
|
|
70
|
+
domain: string;
|
|
71
|
+
name: string;
|
|
72
|
+
description: string;
|
|
73
|
+
version: string;
|
|
74
|
+
roles: string[];
|
|
75
|
+
skillMd: string;
|
|
76
|
+
endpoints: EndpointRecord[];
|
|
77
|
+
isFirstParty: boolean;
|
|
78
|
+
createdAt: number;
|
|
79
|
+
updatedAt: number;
|
|
80
|
+
status: ServiceStatus;
|
|
81
|
+
isDefault: boolean;
|
|
82
|
+
sunsetDate?: number;
|
|
83
|
+
source?: SourceConfig;
|
|
84
|
+
authMode?: "nkmc-jwt";
|
|
85
|
+
}
|
|
86
|
+
interface ServiceSummary {
|
|
87
|
+
domain: string;
|
|
88
|
+
name: string;
|
|
89
|
+
description: string;
|
|
90
|
+
isFirstParty: boolean;
|
|
91
|
+
}
|
|
92
|
+
interface SearchResult {
|
|
93
|
+
domain: string;
|
|
94
|
+
name: string;
|
|
95
|
+
description: string;
|
|
96
|
+
isFirstParty: boolean;
|
|
97
|
+
matchedEndpoints: Pick<EndpointRecord, "method" | "path" | "description">[];
|
|
98
|
+
}
|
|
99
|
+
interface VersionSummary {
|
|
100
|
+
version: string;
|
|
101
|
+
status: ServiceStatus;
|
|
102
|
+
isDefault: boolean;
|
|
103
|
+
createdAt: number;
|
|
104
|
+
updatedAt: number;
|
|
105
|
+
}
|
|
106
|
+
interface RegistryStats {
|
|
107
|
+
serviceCount: number;
|
|
108
|
+
endpointCount: number;
|
|
109
|
+
}
|
|
110
|
+
interface RegistryStore {
|
|
111
|
+
get(domain: string): Promise<ServiceRecord | null>;
|
|
112
|
+
getVersion(domain: string, version: string): Promise<ServiceRecord | null>;
|
|
113
|
+
listVersions(domain: string): Promise<VersionSummary[]>;
|
|
114
|
+
put(domain: string, record: ServiceRecord): Promise<void>;
|
|
115
|
+
delete(domain: string): Promise<void>;
|
|
116
|
+
list(): Promise<ServiceSummary[]>;
|
|
117
|
+
search(query: string): Promise<SearchResult[]>;
|
|
118
|
+
stats?(): Promise<RegistryStats>;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
interface StoredCredential {
|
|
122
|
+
domain: string;
|
|
123
|
+
auth: HttpAuth;
|
|
124
|
+
scope: "pool" | "byok";
|
|
125
|
+
developerId?: string;
|
|
126
|
+
}
|
|
127
|
+
interface CredentialVault {
|
|
128
|
+
get(domain: string, developerId?: string): Promise<StoredCredential | null>;
|
|
129
|
+
putPool(domain: string, auth: HttpAuth): Promise<void>;
|
|
130
|
+
putByok(domain: string, developerId: string, auth: HttpAuth): Promise<void>;
|
|
131
|
+
delete(domain: string, developerId?: string): Promise<void>;
|
|
132
|
+
listDomains(): Promise<string[]>;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/** Field names that can be extracted from an HttpAuth credential. */
|
|
136
|
+
type AuthField = "token" | "key" | "username" | "password";
|
|
137
|
+
/**
|
|
138
|
+
* Defines how a CLI tool maps to a credential domain and which
|
|
139
|
+
* environment variables should be injected at runtime.
|
|
140
|
+
*/
|
|
141
|
+
interface ToolDefinition {
|
|
142
|
+
/** CLI tool name, e.g. "gh", "stripe" */
|
|
143
|
+
name: string;
|
|
144
|
+
/** Domain used to look up credentials in the vault */
|
|
145
|
+
credentialDomain: string;
|
|
146
|
+
/** Maps env var name → field to extract from HttpAuth */
|
|
147
|
+
envMapping: Record<string, AuthField>;
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Registry of CLI tools that can be proxied through the gateway.
|
|
151
|
+
* Each tool declares the credential domain it needs and how to
|
|
152
|
+
* translate stored credentials into environment variables.
|
|
153
|
+
*/
|
|
154
|
+
declare class ToolRegistry {
|
|
155
|
+
private tools;
|
|
156
|
+
/** Register a tool definition. Overwrites any existing entry with the same name. */
|
|
157
|
+
register(tool: ToolDefinition): void;
|
|
158
|
+
/** Look up a tool by name. Returns null if not found. */
|
|
159
|
+
get(name: string): ToolDefinition | null;
|
|
160
|
+
/** Return all registered tool definitions. */
|
|
161
|
+
list(): ToolDefinition[];
|
|
162
|
+
/**
|
|
163
|
+
* Build a record of environment variables for the given tool by
|
|
164
|
+
* extracting the requested fields from the HttpAuth credential.
|
|
165
|
+
*
|
|
166
|
+
* If the auth type does not contain the requested field (e.g.
|
|
167
|
+
* requesting "token" from a basic-auth credential), that env var
|
|
168
|
+
* is silently omitted.
|
|
169
|
+
*/
|
|
170
|
+
buildEnv(tool: ToolDefinition, auth: HttpAuth): Record<string, string>;
|
|
171
|
+
}
|
|
172
|
+
/** Create a ToolRegistry pre-populated with common CLI tools. */
|
|
173
|
+
declare function createDefaultToolRegistry(): ToolRegistry;
|
|
174
|
+
|
|
175
|
+
interface ExecResult {
|
|
176
|
+
stdout: string;
|
|
177
|
+
stderr: string;
|
|
178
|
+
exitCode: number;
|
|
179
|
+
}
|
|
180
|
+
interface ProxyRouteOptions {
|
|
181
|
+
vault: CredentialVault;
|
|
182
|
+
toolRegistry: ToolRegistry;
|
|
183
|
+
exec: (tool: string, args: string[], env: Record<string, string>) => Promise<ExecResult>;
|
|
184
|
+
}
|
|
185
|
+
declare function proxyRoutes(options: ProxyRouteOptions): Hono<Env, hono_types.BlankSchema, "/">;
|
|
186
|
+
|
|
187
|
+
interface PeerGateway {
|
|
188
|
+
id: string;
|
|
189
|
+
name: string;
|
|
190
|
+
url: string;
|
|
191
|
+
sharedSecret: string;
|
|
192
|
+
status: "active" | "inactive";
|
|
193
|
+
advertisedDomains: string[];
|
|
194
|
+
lastSeen: number;
|
|
195
|
+
createdAt: number;
|
|
196
|
+
}
|
|
197
|
+
interface LendingRule {
|
|
198
|
+
domain: string;
|
|
199
|
+
allow: boolean;
|
|
200
|
+
peers: string[] | "*";
|
|
201
|
+
pricing: {
|
|
202
|
+
mode: "free" | "per-request" | "per-token";
|
|
203
|
+
amount?: number;
|
|
204
|
+
};
|
|
205
|
+
rateLimit?: {
|
|
206
|
+
requests: number;
|
|
207
|
+
window: "minute" | "hour" | "day";
|
|
208
|
+
};
|
|
209
|
+
createdAt: number;
|
|
210
|
+
updatedAt: number;
|
|
211
|
+
}
|
|
212
|
+
interface PeerStore {
|
|
213
|
+
getPeer(id: string): Promise<PeerGateway | null>;
|
|
214
|
+
putPeer(peer: PeerGateway): Promise<void>;
|
|
215
|
+
deletePeer(id: string): Promise<void>;
|
|
216
|
+
listPeers(): Promise<PeerGateway[]>;
|
|
217
|
+
updateLastSeen(id: string, timestamp: number): Promise<void>;
|
|
218
|
+
getRule(domain: string): Promise<LendingRule | null>;
|
|
219
|
+
putRule(rule: LendingRule): Promise<void>;
|
|
220
|
+
deleteRule(domain: string): Promise<void>;
|
|
221
|
+
listRules(): Promise<LendingRule[]>;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
interface TunnelRecord {
|
|
225
|
+
id: string;
|
|
226
|
+
agentId: string;
|
|
227
|
+
tunnelId: string;
|
|
228
|
+
publicUrl: string;
|
|
229
|
+
status: "active" | "deleted";
|
|
230
|
+
createdAt: number;
|
|
231
|
+
/** Domains this gateway has credentials for (for discovery) */
|
|
232
|
+
advertisedDomains: string[];
|
|
233
|
+
/** Display name for the gateway */
|
|
234
|
+
gatewayName?: string;
|
|
235
|
+
/** Last heartbeat timestamp (ms since epoch) */
|
|
236
|
+
lastSeen: number;
|
|
237
|
+
}
|
|
238
|
+
interface TunnelStore {
|
|
239
|
+
get(id: string): Promise<TunnelRecord | null>;
|
|
240
|
+
getByAgent(agentId: string): Promise<TunnelRecord | null>;
|
|
241
|
+
put(record: TunnelRecord): Promise<void>;
|
|
242
|
+
delete(id: string): Promise<void>;
|
|
243
|
+
list(): Promise<TunnelRecord[]>;
|
|
244
|
+
}
|
|
245
|
+
/** Interface for Cloudflare Tunnel API operations */
|
|
246
|
+
interface TunnelProvider {
|
|
247
|
+
create(name: string, hostname: string): Promise<{
|
|
248
|
+
tunnelId: string;
|
|
249
|
+
tunnelToken: string;
|
|
250
|
+
}>;
|
|
251
|
+
delete(tunnelId: string): Promise<void>;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
type Env = {
|
|
255
|
+
Variables: {
|
|
256
|
+
agent: {
|
|
257
|
+
id: string;
|
|
258
|
+
roles: string[];
|
|
259
|
+
};
|
|
260
|
+
};
|
|
261
|
+
};
|
|
262
|
+
interface GatewayOptions {
|
|
263
|
+
store: RegistryStore;
|
|
264
|
+
gatewayPrivateKey: JWK;
|
|
265
|
+
gatewayPublicKey: JWK;
|
|
266
|
+
adminToken: string;
|
|
267
|
+
db?: D1Database;
|
|
268
|
+
vault?: CredentialVault;
|
|
269
|
+
context7ApiKey?: string;
|
|
270
|
+
peerStore?: PeerStore;
|
|
271
|
+
proxy?: {
|
|
272
|
+
toolRegistry: ToolRegistry;
|
|
273
|
+
exec: (tool: string, args: string[], env: Record<string, string>) => Promise<ExecResult>;
|
|
274
|
+
};
|
|
275
|
+
tunnel?: {
|
|
276
|
+
store: TunnelStore;
|
|
277
|
+
provider: TunnelProvider;
|
|
278
|
+
domain: string;
|
|
279
|
+
};
|
|
280
|
+
}
|
|
281
|
+
declare function createGateway(options: GatewayOptions): Hono<Env>;
|
|
282
|
+
|
|
283
|
+
export { type AuthField as A, type CredentialVault as C, type Env as E, type GatewayOptions as G, type LendingRule as L, type PeerGateway as P, type RegistryStore as R, type ServiceRecord as S, type TunnelStore as T, type VersionSummary as V, type TunnelProvider as a, type ServiceSummary as b, createGateway as c, type SearchResult as d, type RegistryStats as e, type EndpointPricing as f, type EndpointRecord as g, type StoredCredential as h, type PeerStore as i, type TunnelRecord as j, type EndpointAnnotations as k, type EndpointSummary as l, type ServiceStatus as m, type SourceConfig as n, type ExecResult as o, type ProxyRouteOptions as p, type ToolDefinition as q, ToolRegistry as r, createDefaultToolRegistry as s, proxyRoutes as t };
|
package/dist/proxy.cjs
ADDED
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/proxy.ts
|
|
21
|
+
var proxy_exports = {};
|
|
22
|
+
__export(proxy_exports, {
|
|
23
|
+
ToolRegistry: () => ToolRegistry,
|
|
24
|
+
createDefaultToolRegistry: () => createDefaultToolRegistry,
|
|
25
|
+
proxyRoutes: () => proxyRoutes
|
|
26
|
+
});
|
|
27
|
+
module.exports = __toCommonJS(proxy_exports);
|
|
28
|
+
|
|
29
|
+
// src/proxy/tool-registry.ts
|
|
30
|
+
var ToolRegistry = class {
|
|
31
|
+
tools = /* @__PURE__ */ new Map();
|
|
32
|
+
/** Register a tool definition. Overwrites any existing entry with the same name. */
|
|
33
|
+
register(tool) {
|
|
34
|
+
this.tools.set(tool.name, tool);
|
|
35
|
+
}
|
|
36
|
+
/** Look up a tool by name. Returns null if not found. */
|
|
37
|
+
get(name) {
|
|
38
|
+
return this.tools.get(name) ?? null;
|
|
39
|
+
}
|
|
40
|
+
/** Return all registered tool definitions. */
|
|
41
|
+
list() {
|
|
42
|
+
return [...this.tools.values()];
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Build a record of environment variables for the given tool by
|
|
46
|
+
* extracting the requested fields from the HttpAuth credential.
|
|
47
|
+
*
|
|
48
|
+
* If the auth type does not contain the requested field (e.g.
|
|
49
|
+
* requesting "token" from a basic-auth credential), that env var
|
|
50
|
+
* is silently omitted.
|
|
51
|
+
*/
|
|
52
|
+
buildEnv(tool, auth) {
|
|
53
|
+
const env = {};
|
|
54
|
+
for (const [envVar, field] of Object.entries(tool.envMapping)) {
|
|
55
|
+
const value = extractField(auth, field);
|
|
56
|
+
if (value !== void 0) {
|
|
57
|
+
env[envVar] = value;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return env;
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
function extractField(auth, field) {
|
|
64
|
+
switch (field) {
|
|
65
|
+
case "token":
|
|
66
|
+
return auth.type === "bearer" ? auth.token : void 0;
|
|
67
|
+
case "key":
|
|
68
|
+
return auth.type === "api-key" ? auth.key : void 0;
|
|
69
|
+
case "username":
|
|
70
|
+
return auth.type === "basic" ? auth.username : void 0;
|
|
71
|
+
case "password":
|
|
72
|
+
return auth.type === "basic" ? auth.password : void 0;
|
|
73
|
+
default:
|
|
74
|
+
return void 0;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
function createDefaultToolRegistry() {
|
|
78
|
+
const registry = new ToolRegistry();
|
|
79
|
+
registry.register({
|
|
80
|
+
name: "gh",
|
|
81
|
+
credentialDomain: "github.com",
|
|
82
|
+
envMapping: { GH_TOKEN: "token" }
|
|
83
|
+
});
|
|
84
|
+
registry.register({
|
|
85
|
+
name: "stripe",
|
|
86
|
+
credentialDomain: "api.stripe.com",
|
|
87
|
+
envMapping: { STRIPE_API_KEY: "key" }
|
|
88
|
+
});
|
|
89
|
+
registry.register({
|
|
90
|
+
name: "openai",
|
|
91
|
+
credentialDomain: "api.openai.com",
|
|
92
|
+
envMapping: { OPENAI_API_KEY: "key" }
|
|
93
|
+
});
|
|
94
|
+
registry.register({
|
|
95
|
+
name: "anthropic",
|
|
96
|
+
credentialDomain: "api.anthropic.com",
|
|
97
|
+
envMapping: { ANTHROPIC_API_KEY: "key" }
|
|
98
|
+
});
|
|
99
|
+
registry.register({
|
|
100
|
+
name: "aws",
|
|
101
|
+
credentialDomain: "aws.amazon.com",
|
|
102
|
+
envMapping: {
|
|
103
|
+
AWS_ACCESS_KEY_ID: "username",
|
|
104
|
+
AWS_SECRET_ACCESS_KEY: "password"
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
return registry;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// src/http/routes/proxy.ts
|
|
111
|
+
var import_hono = require("hono");
|
|
112
|
+
function proxyRoutes(options) {
|
|
113
|
+
const { vault, toolRegistry, exec } = options;
|
|
114
|
+
const app = new import_hono.Hono();
|
|
115
|
+
app.post("/exec", async (c) => {
|
|
116
|
+
const body = await c.req.json();
|
|
117
|
+
if (!body.tool || typeof body.tool !== "string") {
|
|
118
|
+
return c.json({ error: "Missing 'tool' field" }, 400);
|
|
119
|
+
}
|
|
120
|
+
const toolDef = toolRegistry.get(body.tool);
|
|
121
|
+
if (!toolDef) {
|
|
122
|
+
return c.json({ error: `Unknown tool: ${body.tool}` }, 404);
|
|
123
|
+
}
|
|
124
|
+
const agent = c.get("agent");
|
|
125
|
+
const credential = await vault.get(toolDef.credentialDomain, agent.id);
|
|
126
|
+
if (!credential) {
|
|
127
|
+
return c.json({ error: `No credential for domain: ${toolDef.credentialDomain}` }, 401);
|
|
128
|
+
}
|
|
129
|
+
const env = toolRegistry.buildEnv(toolDef, credential.auth);
|
|
130
|
+
const args = body.args ?? [];
|
|
131
|
+
const result = await exec(body.tool, args, env);
|
|
132
|
+
return c.json(result);
|
|
133
|
+
});
|
|
134
|
+
app.get("/tools", (c) => {
|
|
135
|
+
const tools = toolRegistry.list().map((t) => ({
|
|
136
|
+
name: t.name,
|
|
137
|
+
credentialDomain: t.credentialDomain
|
|
138
|
+
}));
|
|
139
|
+
return c.json({ tools });
|
|
140
|
+
});
|
|
141
|
+
return app;
|
|
142
|
+
}
|
|
143
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
144
|
+
0 && (module.exports = {
|
|
145
|
+
ToolRegistry,
|
|
146
|
+
createDefaultToolRegistry,
|
|
147
|
+
proxyRoutes
|
|
148
|
+
});
|