@varnir/agent-server 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/LICENSE +20 -0
- package/README.md +282 -0
- package/dist/bearer.d.ts +5 -0
- package/dist/bearer.d.ts.map +1 -0
- package/dist/bearer.js +12 -0
- package/dist/bearer.js.map +1 -0
- package/dist/config.d.ts +36 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +151 -0
- package/dist/config.js.map +1 -0
- package/dist/guard.d.ts +28 -0
- package/dist/guard.d.ts.map +1 -0
- package/dist/guard.js +56 -0
- package/dist/guard.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +79 -0
- package/dist/index.js.map +1 -0
- package/dist/key-match.d.ts +2 -0
- package/dist/key-match.d.ts.map +1 -0
- package/dist/key-match.js +33 -0
- package/dist/key-match.js.map +1 -0
- package/dist/log.d.ts +8 -0
- package/dist/log.d.ts.map +1 -0
- package/dist/log.js +30 -0
- package/dist/log.js.map +1 -0
- package/dist/mcp-http.d.ts +58 -0
- package/dist/mcp-http.d.ts.map +1 -0
- package/dist/mcp-http.js +121 -0
- package/dist/mcp-http.js.map +1 -0
- package/dist/mcp-stdio.d.ts +11 -0
- package/dist/mcp-stdio.d.ts.map +1 -0
- package/dist/mcp-stdio.js +14 -0
- package/dist/mcp-stdio.js.map +1 -0
- package/dist/mcp.d.ts +10 -0
- package/dist/mcp.d.ts.map +1 -0
- package/dist/mcp.js +18 -0
- package/dist/mcp.js.map +1 -0
- package/dist/rest-methods.d.ts +31 -0
- package/dist/rest-methods.d.ts.map +1 -0
- package/dist/rest-methods.js +66 -0
- package/dist/rest-methods.js.map +1 -0
- package/dist/rest.d.ts +17 -0
- package/dist/rest.d.ts.map +1 -0
- package/dist/rest.js +84 -0
- package/dist/rest.js.map +1 -0
- package/dist/tool-error.d.ts +31 -0
- package/dist/tool-error.d.ts.map +1 -0
- package/dist/tool-error.js +66 -0
- package/dist/tool-error.js.map +1 -0
- package/dist/tools.d.ts +31 -0
- package/dist/tools.d.ts.map +1 -0
- package/dist/tools.js +223 -0
- package/dist/tools.js.map +1 -0
- package/package.json +47 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { VarnirClient, onWirePublicKey } from '@varnir/chain-client';
|
|
3
|
+
import { loadConfig, ConfigError } from './config.js';
|
|
4
|
+
import { log, registerSecret } from './log.js';
|
|
5
|
+
import { classifyKey } from './guard.js';
|
|
6
|
+
import { buildTools } from './tools.js';
|
|
7
|
+
import { serveStdio } from './mcp-stdio.js';
|
|
8
|
+
import { serveMcpHttp } from './mcp-http.js';
|
|
9
|
+
import { createRestApp } from './rest.js';
|
|
10
|
+
async function main() {
|
|
11
|
+
const config = loadConfig(process.env);
|
|
12
|
+
registerSecret(config.privateKeyHex);
|
|
13
|
+
const client = new VarnirClient({
|
|
14
|
+
privateKeyHex: config.privateKeyHex,
|
|
15
|
+
identity: config.identity,
|
|
16
|
+
network: config.network,
|
|
17
|
+
});
|
|
18
|
+
// The UNTAGGED on-wire form, which is what meta.authorities[].public holds
|
|
19
|
+
// and therefore what listLedgerKeys() reports. publicKeyForPrivateKey()
|
|
20
|
+
// would tag a PQ key as 'falcon-512:<pk>' and never match. See key-match.ts.
|
|
21
|
+
const publicKeyHex = onWirePublicKey(config.privateKeyHex).publicKey;
|
|
22
|
+
// The unscoped-key guard. See guard.ts for why this exists.
|
|
23
|
+
let mode;
|
|
24
|
+
try {
|
|
25
|
+
mode = classifyKey(await client.listLedgerKeys(), publicKeyHex, config.allowUnscopedKey);
|
|
26
|
+
}
|
|
27
|
+
catch (e) {
|
|
28
|
+
log.error(`Could not read this identity's keys from the ledger, so the key behind VARNIR_PRIVATE_KEY could not be checked: ${e.message}`);
|
|
29
|
+
process.exit(1);
|
|
30
|
+
}
|
|
31
|
+
if (mode.mode === 'refuse') {
|
|
32
|
+
log.error(mode.reason);
|
|
33
|
+
process.exit(1);
|
|
34
|
+
}
|
|
35
|
+
if (mode.mode === 'read-only')
|
|
36
|
+
log.warn(mode.reason);
|
|
37
|
+
else
|
|
38
|
+
log.info(mode.reason);
|
|
39
|
+
const tools = buildTools({ client, identity: config.identity, publicKeyHex, mode: mode.mode, reason: mode.reason });
|
|
40
|
+
log.info(`Varnir agent server ready: identity ${config.identity} on ${config.network}, ${tools.length} tools, mode ${mode.mode}.`);
|
|
41
|
+
if (config.restApi.enabled) {
|
|
42
|
+
const { host, port, remote, writes } = config.restApi;
|
|
43
|
+
if (remote) {
|
|
44
|
+
log.warn(`The REST API is bound to ${host}:${port}, which is REACHABLE FROM THE NETWORK. Anyone who can reach it and holds the token can move funds within this key's policy.`);
|
|
45
|
+
}
|
|
46
|
+
const restServer = createRestApp({ client, config, mode: mode.mode }).listen(port, host, () => {
|
|
47
|
+
log.info(`REST SecureAPI listening on ${host}:${port} (writes ${writes ? 'ENABLED' : 'disabled'}).`);
|
|
48
|
+
});
|
|
49
|
+
restServer.once('error', (err) => {
|
|
50
|
+
if (err.code === 'EADDRINUSE') {
|
|
51
|
+
log.error(`REST API bind failed on ${host}:${port}: address already in use (another process may be listening on that port).`);
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
log.error(`REST API bind failed on ${host}:${port}: ${err.message}`);
|
|
55
|
+
}
|
|
56
|
+
process.exit(1);
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
if (config.mcpHttp.enabled) {
|
|
60
|
+
const { host, port, remote } = config.mcpHttp;
|
|
61
|
+
if (remote) {
|
|
62
|
+
log.warn(`The MCP HTTP server is bound to ${host}:${port}, which is REACHABLE FROM THE NETWORK. Anyone who can reach it and holds the token can move funds within this key's policy.`);
|
|
63
|
+
}
|
|
64
|
+
await serveMcpHttp(tools, { port, host, token: config.mcpHttp.token });
|
|
65
|
+
}
|
|
66
|
+
// stdio last and never awaited alongside a log line: from here stdout is the
|
|
67
|
+
// protocol channel.
|
|
68
|
+
if (config.mcpStdio)
|
|
69
|
+
await serveStdio(tools);
|
|
70
|
+
}
|
|
71
|
+
main().catch((e) => {
|
|
72
|
+
if (e instanceof ConfigError) {
|
|
73
|
+
log.error(e.message);
|
|
74
|
+
process.exit(1);
|
|
75
|
+
}
|
|
76
|
+
log.error(`Fatal: ${e.message}`);
|
|
77
|
+
process.exit(1);
|
|
78
|
+
});
|
|
79
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"key-match.d.ts","sourceRoot":"","sources":["../src/key-match.ts"],"names":[],"mappings":"AAqBA,wBAAgB,aAAa,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAS3D"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Compare two public keys as the ledger stores them.
|
|
3
|
+
*
|
|
4
|
+
* This is fiddly for one reason: Varnir carries two key types with two
|
|
5
|
+
* encodings. A secp256k1 public key is hex - case-insensitive, sometimes
|
|
6
|
+
* 0x-prefixed. A post-quantum (Falcon) public key is base64, which is
|
|
7
|
+
* CASE-SENSITIVE and whose alphabet includes '+', '/' and '='. Case-folding a
|
|
8
|
+
* base64 key to "normalise" it corrupts it, and Falcon is the default key type
|
|
9
|
+
* for new keys, so a naive comparison fails on exactly the keys this server is
|
|
10
|
+
* meant to run behind.
|
|
11
|
+
*
|
|
12
|
+
* So: compare exactly first, which is always correct; only fall back to a
|
|
13
|
+
* case-insensitive compare when BOTH sides are unambiguously hex.
|
|
14
|
+
*/
|
|
15
|
+
const HEX = /^[0-9a-fA-F]+$/;
|
|
16
|
+
function stripPrefix(s) {
|
|
17
|
+
const t = s.trim();
|
|
18
|
+
return t.startsWith('0x') || t.startsWith('0X') ? t.slice(2) : t;
|
|
19
|
+
}
|
|
20
|
+
export function samePublicKey(a, b) {
|
|
21
|
+
const x = a.trim();
|
|
22
|
+
const y = b.trim();
|
|
23
|
+
if (!x || !y)
|
|
24
|
+
return false;
|
|
25
|
+
if (x === y)
|
|
26
|
+
return true;
|
|
27
|
+
const hx = stripPrefix(x);
|
|
28
|
+
const hy = stripPrefix(y);
|
|
29
|
+
if (!HEX.test(hx) || !HEX.test(hy))
|
|
30
|
+
return false;
|
|
31
|
+
return hx.toLowerCase() === hy.toLowerCase();
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=key-match.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"key-match.js","sourceRoot":"","sources":["../src/key-match.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,MAAM,GAAG,GAAG,gBAAgB,CAAC;AAE7B,SAAS,WAAW,CAAC,CAAS;IAC5B,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;IACnB,OAAO,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACnE,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,CAAS,EAAE,CAAS;IAChD,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;IACnB,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;IACnB,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC;QAAE,OAAO,KAAK,CAAC;IAC3B,IAAI,CAAC,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACzB,MAAM,EAAE,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC;IAC1B,MAAM,EAAE,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC;IAC1B,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;QAAE,OAAO,KAAK,CAAC;IACjD,OAAO,EAAE,CAAC,WAAW,EAAE,KAAK,EAAE,CAAC,WAAW,EAAE,CAAC;AAC/C,CAAC"}
|
package/dist/log.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export declare function registerSecret(value: string): void;
|
|
2
|
+
export declare function redact(input: string, against?: string[]): string;
|
|
3
|
+
export declare const log: {
|
|
4
|
+
info: (m: string) => void;
|
|
5
|
+
warn: (m: string) => void;
|
|
6
|
+
error: (m: string) => void;
|
|
7
|
+
};
|
|
8
|
+
//# sourceMappingURL=log.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"log.d.ts","sourceRoot":"","sources":["../src/log.ts"],"names":[],"mappings":"AASA,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAElD;AAED,wBAAgB,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,GAAE,MAAM,EAAY,GAAG,MAAM,CAOzE;AAMD,eAAO,MAAM,GAAG;cACJ,MAAM;cACN,MAAM;eACL,MAAM;CAClB,CAAC"}
|
package/dist/log.js
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Logging that cannot leak the signing key. Every message passes through
|
|
3
|
+
* `redact` against the process's registered secrets before it is written.
|
|
4
|
+
*
|
|
5
|
+
* Everything goes to STDERR, never stdout: when this server speaks MCP over
|
|
6
|
+
* stdio, stdout IS the protocol channel and a stray log line corrupts it.
|
|
7
|
+
*/
|
|
8
|
+
const secrets = [];
|
|
9
|
+
export function registerSecret(value) {
|
|
10
|
+
if (value)
|
|
11
|
+
secrets.push(value);
|
|
12
|
+
}
|
|
13
|
+
export function redact(input, against = secrets) {
|
|
14
|
+
let out = input;
|
|
15
|
+
for (const s of against) {
|
|
16
|
+
if (!s)
|
|
17
|
+
continue;
|
|
18
|
+
out = out.split(s).join('[redacted]');
|
|
19
|
+
}
|
|
20
|
+
return out;
|
|
21
|
+
}
|
|
22
|
+
function write(level, message) {
|
|
23
|
+
process.stderr.write(`${new Date().toISOString()} ${level} ${redact(message)}\n`);
|
|
24
|
+
}
|
|
25
|
+
export const log = {
|
|
26
|
+
info: (m) => write('INFO', m),
|
|
27
|
+
warn: (m) => write('WARN', m),
|
|
28
|
+
error: (m) => write('ERROR', m),
|
|
29
|
+
};
|
|
30
|
+
//# sourceMappingURL=log.js.map
|
package/dist/log.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"log.js","sourceRoot":"","sources":["../src/log.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,MAAM,OAAO,GAAa,EAAE,CAAC;AAE7B,MAAM,UAAU,cAAc,CAAC,KAAa;IAC1C,IAAI,KAAK;QAAE,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AACjC,CAAC;AAED,MAAM,UAAU,MAAM,CAAC,KAAa,EAAE,UAAoB,OAAO;IAC/D,IAAI,GAAG,GAAG,KAAK,CAAC;IAChB,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;QACxB,IAAI,CAAC,CAAC;YAAE,SAAS;QACjB,GAAG,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;IACxC,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,SAAS,KAAK,CAAC,KAAa,EAAE,OAAe;IAC3C,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,IAAI,KAAK,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;AACpF,CAAC;AAED,MAAM,CAAC,MAAM,GAAG,GAAG;IACjB,IAAI,EAAE,CAAC,CAAS,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;IACrC,IAAI,EAAE,CAAC,CAAS,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;IACrC,KAAK,EAAE,CAAC,CAAS,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;CACxC,CAAC"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import express from 'express';
|
|
2
|
+
import type { ToolDef } from './tools.js';
|
|
3
|
+
/**
|
|
4
|
+
* Streamable HTTP, for clients that cannot launch a local process - notably
|
|
5
|
+
* ChatGPT, which requires a publicly reachable HTTPS endpoint. Stateless
|
|
6
|
+
* (`sessionIdGenerator: undefined`): a fresh server and transport per request,
|
|
7
|
+
* so there is no session state to leak between callers.
|
|
8
|
+
*
|
|
9
|
+
* `opts.token` is mandatory here (see config.ts's I4 fix): VARNIR_MCP_HTTP=on
|
|
10
|
+
* alone used to put the full write set on loopback with no authentication at
|
|
11
|
+
* all - any other local user or process on a shared host could move funds.
|
|
12
|
+
*
|
|
13
|
+
* There is deliberately no `enableDnsRebindingProtection`/`allowedHosts`
|
|
14
|
+
* here. That option was tried and removed - not patched - for a specific
|
|
15
|
+
* reason:
|
|
16
|
+
*
|
|
17
|
+
* The SDK's `allowedHosts` check is an exact `includes(hostHeader)` match
|
|
18
|
+
* against the literal `Host` header a client sends
|
|
19
|
+
* (@modelcontextprotocol/sdk/dist/esm/server/webStandardStreamableHttp.js).
|
|
20
|
+
* Such a list can only ever be built from what THIS PROCESS is bound to
|
|
21
|
+
* (`opts.host`/`opts.port`) - and for the loopback deployments this was
|
|
22
|
+
* meant to guard, that is provably not what every legitimate client sends:
|
|
23
|
+
*
|
|
24
|
+
* - `::1` needs the bracketed form `[::1]:port` in the list - fixable,
|
|
25
|
+
* and was simply missing.
|
|
26
|
+
* - a client talking to port 80/443 omits the default port in its Host
|
|
27
|
+
* header - also fixable, and also simply missing.
|
|
28
|
+
* - a client reaching this process through a remapped or tunnelled port
|
|
29
|
+
* (`docker -p 9000:8787`, `ssh -L 9000:localhost:8787`) sends
|
|
30
|
+
* `Host: localhost:9000`. This process is bound to 8787 and has no
|
|
31
|
+
* channel to learn that "9000" exists anywhere - Docker's port mapping
|
|
32
|
+
* and a raw ssh -L tunnel both happen entirely outside this process.
|
|
33
|
+
* No `allowedHosts` list built from `opts.host`/`opts.port` can ever
|
|
34
|
+
* contain the port such a client will present; this is not a derivation
|
|
35
|
+
* bug to fix, it is information the server does not have and cannot
|
|
36
|
+
* obtain.
|
|
37
|
+
*
|
|
38
|
+
* Since that third case can never be fixed by any allowlist derived this
|
|
39
|
+
* way, and a bare 403 with nothing beyond "Invalid Host header" in the
|
|
40
|
+
* JSON-RPC response is a worse failure mode than no DNS-rebinding guard at
|
|
41
|
+
* all (silent, undiagnosable breakage of an otherwise fully-supported
|
|
42
|
+
* deployment), the option is removed rather than patched. What actually
|
|
43
|
+
* gates this endpoint is the mandatory bearer token (config.ts's I4 fix:
|
|
44
|
+
* timing-safe, >=32 characters, required even on loopback) - and unlike the
|
|
45
|
+
* ambient/cookie authority DNS-rebinding protection exists to defend, a
|
|
46
|
+
* bearer token is never attached automatically by a browser. A rebinding
|
|
47
|
+
* attacker's page has no way to obtain it, so the token already denies the
|
|
48
|
+
* attack this option existed to guard against.
|
|
49
|
+
*/
|
|
50
|
+
export declare function createMcpHttpApp(tools: ToolDef[], opts: {
|
|
51
|
+
token: string;
|
|
52
|
+
}): express.Express;
|
|
53
|
+
export declare function serveMcpHttp(tools: ToolDef[], opts: {
|
|
54
|
+
port: number;
|
|
55
|
+
host: string;
|
|
56
|
+
token: string;
|
|
57
|
+
}): Promise<void>;
|
|
58
|
+
//# sourceMappingURL=mcp-http.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-http.d.ts","sourceRoot":"","sources":["../src/mcp-http.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,SAAS,CAAC;AAO9B,OAAO,KAAK,EAAC,OAAO,EAAC,MAAM,YAAY,CAAC;AAExC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8CG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE;IAAC,KAAK,EAAE,MAAM,CAAA;CAAC,GAAG,OAAO,CAAC,OAAO,CAiDzF;AAED,wBAAsB,YAAY,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAgBrH"}
|
package/dist/mcp-http.js
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import express from 'express';
|
|
2
|
+
import { randomUUID } from 'node:crypto';
|
|
3
|
+
import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
|
|
4
|
+
import { createMcpServer } from './mcp.js';
|
|
5
|
+
import { tokenMatches } from './bearer.js';
|
|
6
|
+
import { classifyBodyError } from './tool-error.js';
|
|
7
|
+
import { log } from './log.js';
|
|
8
|
+
/**
|
|
9
|
+
* Streamable HTTP, for clients that cannot launch a local process - notably
|
|
10
|
+
* ChatGPT, which requires a publicly reachable HTTPS endpoint. Stateless
|
|
11
|
+
* (`sessionIdGenerator: undefined`): a fresh server and transport per request,
|
|
12
|
+
* so there is no session state to leak between callers.
|
|
13
|
+
*
|
|
14
|
+
* `opts.token` is mandatory here (see config.ts's I4 fix): VARNIR_MCP_HTTP=on
|
|
15
|
+
* alone used to put the full write set on loopback with no authentication at
|
|
16
|
+
* all - any other local user or process on a shared host could move funds.
|
|
17
|
+
*
|
|
18
|
+
* There is deliberately no `enableDnsRebindingProtection`/`allowedHosts`
|
|
19
|
+
* here. That option was tried and removed - not patched - for a specific
|
|
20
|
+
* reason:
|
|
21
|
+
*
|
|
22
|
+
* The SDK's `allowedHosts` check is an exact `includes(hostHeader)` match
|
|
23
|
+
* against the literal `Host` header a client sends
|
|
24
|
+
* (@modelcontextprotocol/sdk/dist/esm/server/webStandardStreamableHttp.js).
|
|
25
|
+
* Such a list can only ever be built from what THIS PROCESS is bound to
|
|
26
|
+
* (`opts.host`/`opts.port`) - and for the loopback deployments this was
|
|
27
|
+
* meant to guard, that is provably not what every legitimate client sends:
|
|
28
|
+
*
|
|
29
|
+
* - `::1` needs the bracketed form `[::1]:port` in the list - fixable,
|
|
30
|
+
* and was simply missing.
|
|
31
|
+
* - a client talking to port 80/443 omits the default port in its Host
|
|
32
|
+
* header - also fixable, and also simply missing.
|
|
33
|
+
* - a client reaching this process through a remapped or tunnelled port
|
|
34
|
+
* (`docker -p 9000:8787`, `ssh -L 9000:localhost:8787`) sends
|
|
35
|
+
* `Host: localhost:9000`. This process is bound to 8787 and has no
|
|
36
|
+
* channel to learn that "9000" exists anywhere - Docker's port mapping
|
|
37
|
+
* and a raw ssh -L tunnel both happen entirely outside this process.
|
|
38
|
+
* No `allowedHosts` list built from `opts.host`/`opts.port` can ever
|
|
39
|
+
* contain the port such a client will present; this is not a derivation
|
|
40
|
+
* bug to fix, it is information the server does not have and cannot
|
|
41
|
+
* obtain.
|
|
42
|
+
*
|
|
43
|
+
* Since that third case can never be fixed by any allowlist derived this
|
|
44
|
+
* way, and a bare 403 with nothing beyond "Invalid Host header" in the
|
|
45
|
+
* JSON-RPC response is a worse failure mode than no DNS-rebinding guard at
|
|
46
|
+
* all (silent, undiagnosable breakage of an otherwise fully-supported
|
|
47
|
+
* deployment), the option is removed rather than patched. What actually
|
|
48
|
+
* gates this endpoint is the mandatory bearer token (config.ts's I4 fix:
|
|
49
|
+
* timing-safe, >=32 characters, required even on loopback) - and unlike the
|
|
50
|
+
* ambient/cookie authority DNS-rebinding protection exists to defend, a
|
|
51
|
+
* bearer token is never attached automatically by a browser. A rebinding
|
|
52
|
+
* attacker's page has no way to obtain it, so the token already denies the
|
|
53
|
+
* attack this option existed to guard against.
|
|
54
|
+
*/
|
|
55
|
+
export function createMcpHttpApp(tools, opts) {
|
|
56
|
+
const app = express();
|
|
57
|
+
// Auth before the body parser: an unauthenticated caller must not be able
|
|
58
|
+
// to reach express.json() at all, and a malformed body from an
|
|
59
|
+
// unauthenticated caller must never reach express's default error handler
|
|
60
|
+
// (which echoes err.stack whenever NODE_ENV isn't 'production' - nothing
|
|
61
|
+
// here sets it). See rest.ts for the same ordering.
|
|
62
|
+
const authorise = (req, res, next) => {
|
|
63
|
+
const header = req.header('authorization') ?? '';
|
|
64
|
+
const presented = header.startsWith('Bearer ') ? header.slice(7) : '';
|
|
65
|
+
if (!presented || !tokenMatches(presented, opts.token)) {
|
|
66
|
+
res.status(401).json({ error: 'unauthorized' });
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
next();
|
|
70
|
+
};
|
|
71
|
+
app.post('/mcp', authorise, express.json({ limit: '1mb' }), async (req, res, next) => {
|
|
72
|
+
try {
|
|
73
|
+
// Stateless: a fresh server+transport per request, so there is no
|
|
74
|
+
// session state to leak between callers.
|
|
75
|
+
const transport = new StreamableHTTPServerTransport({ sessionIdGenerator: undefined });
|
|
76
|
+
res.on('close', () => { void transport.close(); });
|
|
77
|
+
await createMcpServer(tools).connect(transport);
|
|
78
|
+
await transport.handleRequest(req, res, req.body);
|
|
79
|
+
}
|
|
80
|
+
catch (e) {
|
|
81
|
+
// Express 4 does not forward a rejection from an async handler to
|
|
82
|
+
// error middleware on its own - an uncaught one here becomes an
|
|
83
|
+
// unhandled rejection and kills the process (e.g. the SDK's own
|
|
84
|
+
// "Stateless transport cannot be reused across requests").
|
|
85
|
+
next(e);
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
app.get('/health', (_req, res) => { res.json({ ok: true, id: randomUUID() }); });
|
|
89
|
+
// Structured JSON errors, never express's default HTML/stack-trace handler.
|
|
90
|
+
// Must be declared after the routes/middleware it protects.
|
|
91
|
+
app.use((err, _req, res, next) => {
|
|
92
|
+
// Once a response has started, express's contract is to delegate to the
|
|
93
|
+
// default handler rather than write again - calling res.status() after
|
|
94
|
+
// headers are sent throws and drops the socket opaquely.
|
|
95
|
+
if (res.headersSent) {
|
|
96
|
+
next(err);
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
const { status, code, message } = classifyBodyError(err);
|
|
100
|
+
res.status(status).json({ error: { code, message } });
|
|
101
|
+
});
|
|
102
|
+
return app;
|
|
103
|
+
}
|
|
104
|
+
export async function serveMcpHttp(tools, opts) {
|
|
105
|
+
const app = createMcpHttpApp(tools, { token: opts.token });
|
|
106
|
+
await new Promise((resolve, reject) => {
|
|
107
|
+
const server = app.listen(opts.port, opts.host, () => {
|
|
108
|
+
log.info(`MCP Streamable HTTP listening on ${opts.host}:${opts.port}/mcp (bearer required)`);
|
|
109
|
+
resolve();
|
|
110
|
+
});
|
|
111
|
+
server.once('error', (err) => {
|
|
112
|
+
if (err.code === 'EADDRINUSE') {
|
|
113
|
+
reject(new Error(`MCP HTTP bind failed on ${opts.host}:${opts.port}: address already in use (another process may be listening on that port).`));
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
reject(new Error(`MCP HTTP bind failed on ${opts.host}:${opts.port}: ${err.message}`));
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
//# sourceMappingURL=mcp-http.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-http.js","sourceRoot":"","sources":["../src/mcp-http.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { ToolDef } from './tools.js';
|
|
2
|
+
/**
|
|
3
|
+
* stdio needs no authentication: the client is a local process the operator
|
|
4
|
+
* launched, and the credential is the environment it was given. The MCP spec
|
|
5
|
+
* says as much - stdio servers take credentials from the environment rather
|
|
6
|
+
* than implementing the OAuth framework.
|
|
7
|
+
*
|
|
8
|
+
* Nothing may write to stdout while this is running; stdout IS the protocol.
|
|
9
|
+
*/
|
|
10
|
+
export declare function serveStdio(tools: ToolDef[]): Promise<void>;
|
|
11
|
+
//# sourceMappingURL=mcp-stdio.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-stdio.d.ts","sourceRoot":"","sources":["../src/mcp-stdio.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAC,OAAO,EAAC,MAAM,YAAY,CAAC;AAExC;;;;;;;GAOG;AACH,wBAAsB,UAAU,CAAC,KAAK,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAEhE"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
2
|
+
import { createMcpServer } from './mcp.js';
|
|
3
|
+
/**
|
|
4
|
+
* stdio needs no authentication: the client is a local process the operator
|
|
5
|
+
* launched, and the credential is the environment it was given. The MCP spec
|
|
6
|
+
* says as much - stdio servers take credentials from the environment rather
|
|
7
|
+
* than implementing the OAuth framework.
|
|
8
|
+
*
|
|
9
|
+
* Nothing may write to stdout while this is running; stdout IS the protocol.
|
|
10
|
+
*/
|
|
11
|
+
export async function serveStdio(tools) {
|
|
12
|
+
await createMcpServer(tools).connect(new StdioServerTransport());
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=mcp-stdio.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-stdio.js","sourceRoot":"","sources":["../src/mcp-stdio.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,oBAAoB,EAAC,MAAM,2CAA2C,CAAC;AAC/E,OAAO,EAAC,eAAe,EAAC,MAAM,UAAU,CAAC;AAGzC;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,KAAgB;IAC/C,MAAM,eAAe,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,IAAI,oBAAoB,EAAE,CAAC,CAAC;AACnE,CAAC"}
|
package/dist/mcp.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
import type { ToolDef } from './tools.js';
|
|
3
|
+
/**
|
|
4
|
+
* Adapt the tool layer to MCP. Every handler already returns a structured
|
|
5
|
+
* result or a structured failure, so this only has to serialise: a tool never
|
|
6
|
+
* throws past here, which is what keeps a policy rejection legible to the
|
|
7
|
+
* assistant instead of surfacing as a transport error.
|
|
8
|
+
*/
|
|
9
|
+
export declare function createMcpServer(tools: ToolDef[]): McpServer;
|
|
10
|
+
//# sourceMappingURL=mcp.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp.d.ts","sourceRoot":"","sources":["../src/mcp.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,SAAS,EAAC,MAAM,yCAAyC,CAAC;AAClE,OAAO,KAAK,EAAC,OAAO,EAAC,MAAM,YAAY,CAAC;AAExC;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,GAAG,SAAS,CAa3D"}
|
package/dist/mcp.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
/**
|
|
3
|
+
* Adapt the tool layer to MCP. Every handler already returns a structured
|
|
4
|
+
* result or a structured failure, so this only has to serialise: a tool never
|
|
5
|
+
* throws past here, which is what keeps a policy rejection legible to the
|
|
6
|
+
* assistant instead of surfacing as a transport error.
|
|
7
|
+
*/
|
|
8
|
+
export function createMcpServer(tools) {
|
|
9
|
+
const server = new McpServer({ name: 'varnir', version: '0.1.0' });
|
|
10
|
+
for (const t of tools) {
|
|
11
|
+
server.registerTool(t.name, { title: t.title, description: t.description, inputSchema: t.inputSchema }, async (args) => {
|
|
12
|
+
const result = await t.handler(args ?? {});
|
|
13
|
+
return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
return server;
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=mcp.js.map
|
package/dist/mcp.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp.js","sourceRoot":"","sources":["../src/mcp.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,SAAS,EAAC,MAAM,yCAAyC,CAAC;AAGlE;;;;;GAKG;AACH,MAAM,UAAU,eAAe,CAAC,KAAgB;IAC9C,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC,EAAC,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAC,CAAC,CAAC;IACjE,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;QACtB,MAAM,CAAC,YAAY,CACjB,CAAC,CAAC,IAAI,EACN,EAAC,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,WAAW,EAAE,CAAC,CAAC,WAAW,EAAE,WAAW,EAAE,CAAC,CAAC,WAAW,EAAC,EACxE,KAAK,EAAE,IAA6B,EAAE,EAAE;YACtC,MAAM,MAAM,GAAG,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC;YAC3C,OAAO,EAAC,OAAO,EAAE,CAAC,EAAC,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC;QACrF,CAAC,CACF,CAAC;IACJ,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { VarnirClient } from '@varnir/chain-client';
|
|
2
|
+
/**
|
|
3
|
+
* The REST surface, as an explicit table rather than reflection over the
|
|
4
|
+
* client. Reflection plus a denylist would auto-expose anything added to the
|
|
5
|
+
* SDK later - including future key-management methods - so the denylist would
|
|
6
|
+
* silently stop being complete. This is broad but closed by default: a new SDK
|
|
7
|
+
* method appears here only when someone adds it deliberately.
|
|
8
|
+
*
|
|
9
|
+
* addKey, removeKey, setApprovalThreshold, registerApiKey and revokeApiKey are
|
|
10
|
+
* absent on purpose and must stay absent. Nothing reachable from an assistant
|
|
11
|
+
* may widen that assistant's own authority.
|
|
12
|
+
*
|
|
13
|
+
* confirmTransfer and listPendingApprovals are ALSO absent on purpose, for the
|
|
14
|
+
* same reason even though they don't look like key management: a `verifier`
|
|
15
|
+
* or `dual` key (both stake 80) can hit the co-sign band on a proposal it did
|
|
16
|
+
* not itself raise, which the contract (Varnir.CryptoTransfer.ts) treats as a
|
|
17
|
+
* genuine co-sign confirmation and releases WITHOUT re-checking that key's own
|
|
18
|
+
* spend policy - policy checking happens only when the proposal is raised.
|
|
19
|
+
* Exposing listPendingApprovals to enumerate held proposals plus
|
|
20
|
+
* confirmTransfer to release any one of them lets an agent key escape its own
|
|
21
|
+
* per-tx ceiling, period cap and allowlist: exactly the authority a co-sign
|
|
22
|
+
* threshold exists to withhold. Neither has an MCP tool sibling, so removing
|
|
23
|
+
* both from REST regresses nothing. Must stay absent.
|
|
24
|
+
*/
|
|
25
|
+
export interface RestMethod {
|
|
26
|
+
name: string;
|
|
27
|
+
write: boolean;
|
|
28
|
+
call(client: VarnirClient, body: Record<string, unknown>): Promise<unknown>;
|
|
29
|
+
}
|
|
30
|
+
export declare const REST_METHODS: RestMethod[];
|
|
31
|
+
//# sourceMappingURL=rest-methods.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rest-methods.d.ts","sourceRoot":"","sources":["../src/rest-methods.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,sBAAsB,CAAC;AAEvD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,OAAO,CAAC;IACf,IAAI,CAAC,MAAM,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CAC7E;AAID,eAAO,MAAM,YAAY,EAAE,UAAU,EAwEpC,CAAC"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
const b = (v) => v;
|
|
2
|
+
export const REST_METHODS = [
|
|
3
|
+
// ---- identity / registry (read) ----
|
|
4
|
+
{ name: 'getIdentityStream', write: false, call: c => c.getIdentityStream() },
|
|
5
|
+
{ name: 'identityExists', write: false, call: (c, o) => c.identityExists(b(o.identity)) },
|
|
6
|
+
{ name: 'listTokens', write: false, call: c => c.listTokens() },
|
|
7
|
+
{ name: 'getToken', write: false, call: (c, o) => c.getToken(b(o.network), b(o.address)) },
|
|
8
|
+
// ---- wallets / balances (read) ----
|
|
9
|
+
// listWallets is the non-mutating way to enumerate wallets; getWallet is
|
|
10
|
+
// NOT here - see the money-movement section below for why.
|
|
11
|
+
{ name: 'listWallets', write: false, call: c => c.listWallets() },
|
|
12
|
+
{ name: 'getBalances', write: false, call: c => c.getBalances() },
|
|
13
|
+
{ name: 'getWalletL1Balances', write: false, call: (c, o) => c.getWalletL1Balances(b(o.chain)) },
|
|
14
|
+
{ name: 'getDeposit', write: false, call: (c, o) => c.getDeposit(b(o.chain), b(o.txHash)) },
|
|
15
|
+
// ---- transactions (read) ----
|
|
16
|
+
{ name: 'listTransactions', write: false, call: (c, o) => c.listTransactions(b(o)) },
|
|
17
|
+
{ name: 'getTransfer', write: false, call: (c, o) => c.getTransfer(b(o.umid)) },
|
|
18
|
+
{ name: 'getTransferProposal', write: false, call: (c, o) => c.getTransferProposal(b(o.id)) },
|
|
19
|
+
// listPendingApprovals is deliberately absent - see the file preamble.
|
|
20
|
+
// ---- exchange (read) ----
|
|
21
|
+
{ name: 'getOrderBook', write: false, call: c => c.getOrderBook() },
|
|
22
|
+
// ---- invoices (read) ----
|
|
23
|
+
{ name: 'listInvoices', write: false, call: c => c.listInvoices() },
|
|
24
|
+
{ name: 'getInvoice', write: false, call: (c, o) => c.getInvoice(b(o.id)) },
|
|
25
|
+
// ---- keys: READ ONLY. Mutation is deliberately absent. ----
|
|
26
|
+
{ name: 'listLedgerKeys', write: false, call: c => c.listLedgerKeys() },
|
|
27
|
+
{ name: 'listApiKeys', write: false, call: c => c.listApiKeys() },
|
|
28
|
+
// ---- webhooks ----
|
|
29
|
+
{ name: 'getWebhookSettings', write: false, call: c => c.getWebhookSettings() },
|
|
30
|
+
{ name: 'setWebhookUrl', write: true, call: (c, o) => c.setWebhookUrl(b(o.callbackUrl)) },
|
|
31
|
+
{ name: 'deleteWebhookUrl', write: true, call: c => c.deleteWebhookUrl() },
|
|
32
|
+
// ---- money movement (write) ----
|
|
33
|
+
{ name: 'createWallet', write: true, call: (c, o) => c.createWallet(b(o.chain), b(o.options)) },
|
|
34
|
+
// getWallet LOOKS like a read - it is not. When this identity has no
|
|
35
|
+
// wallet yet on the chain, it falls through to createWallet: claims a
|
|
36
|
+
// pregenerated L1 wallet from the pool and signs a Varnir.AssignOwner
|
|
37
|
+
// transaction to establish ownership. That is a ledger-mutating write on
|
|
38
|
+
// its first call for a chain, regardless of what the name suggests - do
|
|
39
|
+
// not reclassify this back to write: false.
|
|
40
|
+
{ name: 'getWallet', write: true, call: (c, o) => c.getWallet(b(o.chain), b(o.options)) },
|
|
41
|
+
{
|
|
42
|
+
name: 'send',
|
|
43
|
+
write: true,
|
|
44
|
+
call: async (c, o) => {
|
|
45
|
+
const wallet = o.wallet ?? (await c.getWallet(b(o.chain)));
|
|
46
|
+
return c.send({
|
|
47
|
+
wallet: b(wallet), to: b(o.to),
|
|
48
|
+
amount: b(o.amount), token: b(o.token),
|
|
49
|
+
});
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
{ name: 'transferOnLedger', write: true, call: (c, o) => c.transferOnLedger(b(o)) },
|
|
53
|
+
{ name: 'consolidate', write: true, call: (c, o) => c.consolidate(b(o)) },
|
|
54
|
+
// confirmTransfer is deliberately absent - see the file preamble. It also
|
|
55
|
+
// has no `approve`/reject parameter on the SDK; a caller trying to decline
|
|
56
|
+
// a held transfer over this method would have released it instead.
|
|
57
|
+
// ---- exchange (write) ----
|
|
58
|
+
{ name: 'createOrder', write: true, call: (c, o) => c.createOrder(b(o)) },
|
|
59
|
+
{ name: 'postOrder', write: true, call: (c, o) => c.postOrder(b(o.signed)) },
|
|
60
|
+
{ name: 'fillOrder', write: true, call: (c, o) => c.fillOrder(b(o.signed), b(o.opts)) },
|
|
61
|
+
{ name: 'marketOrder', write: true, call: (c, o) => c.marketOrder(b(o)) },
|
|
62
|
+
{ name: 'cancelOrder', write: true, call: (c, o) => c.cancelOrder(b(o.orderHash)) },
|
|
63
|
+
// ---- invoices (write) ----
|
|
64
|
+
{ name: 'createInvoice', write: true, call: (c, o) => c.createInvoice(b(o)) },
|
|
65
|
+
];
|
|
66
|
+
//# sourceMappingURL=rest-methods.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rest-methods.js","sourceRoot":"","sources":["../src/rest-methods.ts"],"names":[],"mappings":"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"}
|
package/dist/rest.d.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import express from 'express';
|
|
2
|
+
import type { VarnirClient } from '@varnir/chain-client';
|
|
3
|
+
import type { ServerConfig } from './config.js';
|
|
4
|
+
import type { GuardMode } from './guard.js';
|
|
5
|
+
/**
|
|
6
|
+
* The SecureAPI: the TypeScript SDK's methods mapped to HTTP, for integrating
|
|
7
|
+
* software that can only call HTTP endpoints. This is the surface that can move
|
|
8
|
+
* money, so its gates are all here and all tested: off unless enabled, a
|
|
9
|
+
* mandatory bearer token, and writes behind their own flag on top of the
|
|
10
|
+
* boot-time key guard.
|
|
11
|
+
*/
|
|
12
|
+
export declare function createRestApp(deps: {
|
|
13
|
+
client: VarnirClient;
|
|
14
|
+
config: ServerConfig;
|
|
15
|
+
mode: GuardMode;
|
|
16
|
+
}): express.Express;
|
|
17
|
+
//# sourceMappingURL=rest.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rest.d.ts","sourceRoot":"","sources":["../src/rest.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,sBAAsB,CAAC;AACvD,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,aAAa,CAAC;AAC9C,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,YAAY,CAAC;AAM1C;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE;IAAC,MAAM,EAAE,YAAY,CAAC;IAAC,MAAM,EAAE,YAAY,CAAC;IAAC,IAAI,EAAE,SAAS,CAAA;CAAC,GAAG,OAAO,CAAC,OAAO,CAyElH"}
|