@vaultcompass/vault-guard 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/dist/__tests__/integration/proxy-test-helpers.d.ts +47 -0
- package/dist/__tests__/integration/proxy-test-helpers.d.ts.map +1 -0
- package/dist/__tests__/integration/proxy-test-helpers.js +146 -0
- package/dist/__tests__/integration/proxy-test-helpers.js.map +1 -0
- package/dist/cli-entry.d.ts +3 -0
- package/dist/cli-entry.d.ts.map +1 -0
- package/dist/cli-entry.js +15 -0
- package/dist/cli-entry.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +241 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/check.d.ts +2 -0
- package/dist/commands/check.d.ts.map +1 -0
- package/dist/commands/check.js +40 -0
- package/dist/commands/check.js.map +1 -0
- package/dist/commands/config.d.ts +6 -0
- package/dist/commands/config.d.ts.map +1 -0
- package/dist/commands/config.js +57 -0
- package/dist/commands/config.js.map +1 -0
- package/dist/commands/data.d.ts +67 -0
- package/dist/commands/data.d.ts.map +1 -0
- package/dist/commands/data.js +294 -0
- package/dist/commands/data.js.map +1 -0
- package/dist/commands/fix.d.ts +2 -0
- package/dist/commands/fix.d.ts.map +1 -0
- package/dist/commands/fix.js +80 -0
- package/dist/commands/fix.js.map +1 -0
- package/dist/commands/index.d.ts +11 -0
- package/dist/commands/index.d.ts.map +1 -0
- package/dist/commands/index.js +26 -0
- package/dist/commands/index.js.map +1 -0
- package/dist/commands/install-hook.d.ts +3 -0
- package/dist/commands/install-hook.d.ts.map +1 -0
- package/dist/commands/install-hook.js +31 -0
- package/dist/commands/install-hook.js.map +1 -0
- package/dist/commands/monitor.d.ts +2 -0
- package/dist/commands/monitor.d.ts.map +1 -0
- package/dist/commands/monitor.js +23 -0
- package/dist/commands/monitor.js.map +1 -0
- package/dist/commands/proxy.d.ts +68 -0
- package/dist/commands/proxy.d.ts.map +1 -0
- package/dist/commands/proxy.js +445 -0
- package/dist/commands/proxy.js.map +1 -0
- package/dist/commands/scan.d.ts +3 -0
- package/dist/commands/scan.d.ts.map +1 -0
- package/dist/commands/scan.js +156 -0
- package/dist/commands/scan.js.map +1 -0
- package/dist/commands/statusline.d.ts +2 -0
- package/dist/commands/statusline.d.ts.map +1 -0
- package/dist/commands/statusline.js +34 -0
- package/dist/commands/statusline.js.map +1 -0
- package/dist/commands/suggest-model.d.ts +6 -0
- package/dist/commands/suggest-model.d.ts.map +1 -0
- package/dist/commands/suggest-model.js +38 -0
- package/dist/commands/suggest-model.js.map +1 -0
- package/dist/commands/tokens.d.ts +2 -0
- package/dist/commands/tokens.d.ts.map +1 -0
- package/dist/commands/tokens.js +22 -0
- package/dist/commands/tokens.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +21 -0
- package/dist/index.js.map +1 -0
- package/dist/utils/index.d.ts +2 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +18 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/scan-utils.d.ts +65 -0
- package/dist/utils/scan-utils.d.ts.map +1 -0
- package/dist/utils/scan-utils.js +333 -0
- package/dist/utils/scan-utils.js.map +1 -0
- package/package.json +56 -0
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import * as http from 'http';
|
|
2
|
+
import { TelemetryStore } from '@vaultcompass/vault-guard-telemetry';
|
|
3
|
+
export interface ProxyOptions {
|
|
4
|
+
/**
|
|
5
|
+
* Bind address in `host:port` form, e.g. `127.0.0.1:8765`.
|
|
6
|
+
*
|
|
7
|
+
* @remarks
|
|
8
|
+
* Use loopback hosts unless you explicitly want LAN exposure.
|
|
9
|
+
*/
|
|
10
|
+
listen: string;
|
|
11
|
+
/**
|
|
12
|
+
* If true, requests with no `x-api-key` header fall back to the
|
|
13
|
+
* `ANTHROPIC_API_KEY` env var on the proxy host.
|
|
14
|
+
*
|
|
15
|
+
* **Security:** Default is `false`. Without this flag any local process
|
|
16
|
+
* that can connect to the proxy (other CLIs, browser fetch from a phishing
|
|
17
|
+
* page, malicious npm postinstall) could spend the operator's Anthropic
|
|
18
|
+
* budget. With it enabled, you accept that risk in exchange for being able
|
|
19
|
+
* to point existing tools at the proxy without rewriting their auth.
|
|
20
|
+
*/
|
|
21
|
+
allowEnvFallback?: boolean;
|
|
22
|
+
/**
|
|
23
|
+
* If true, the proxy is allowed to bind a non-loopback address
|
|
24
|
+
* (anything other than `127.0.0.1`, `localhost`, `::1`, `::ffff:127.0.0.1`).
|
|
25
|
+
*
|
|
26
|
+
* **Security:** Default is `false`. Binding `0.0.0.0` or a LAN IP exposes
|
|
27
|
+
* the proxy to anyone reachable on the network — combined with the
|
|
28
|
+
* env-fallback path above, this is a credit-card-draining footgun. Refuse
|
|
29
|
+
* by default and require explicit opt-in.
|
|
30
|
+
*/
|
|
31
|
+
allowPublic?: boolean;
|
|
32
|
+
/**
|
|
33
|
+
* Optional cap on forwarded requests per rolling 60-second window (per process).
|
|
34
|
+
* When exceeded, the proxy responds with HTTP 429 until the window slides.
|
|
35
|
+
*/
|
|
36
|
+
maxRpm?: number;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Returned from `proxyCommand` so the caller (cli.ts) can register signal
|
|
40
|
+
* handlers and unit tests can drive a clean shutdown without sending real
|
|
41
|
+
* signals.
|
|
42
|
+
*/
|
|
43
|
+
export interface ProxyHandle {
|
|
44
|
+
/** Active HTTP server instance backing the proxy. */
|
|
45
|
+
server: http.Server;
|
|
46
|
+
/** Telemetry store used for usage event recording. */
|
|
47
|
+
store: TelemetryStore;
|
|
48
|
+
/**
|
|
49
|
+
* Cleanly stop accepting connections, drain inflight, and checkpoint DB.
|
|
50
|
+
*
|
|
51
|
+
* @param reason - Optional shutdown cause for stderr logs.
|
|
52
|
+
*/
|
|
53
|
+
shutdown(reason?: string): Promise<void>;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Minimal opt-in Anthropic forwarder: POST /v1/messages → api.anthropic.com.
|
|
57
|
+
*
|
|
58
|
+
* - Authentication: requires `x-api-key` from the caller. Falls back to
|
|
59
|
+
* `ANTHROPIC_API_KEY` only when `allowEnvFallback === true`.
|
|
60
|
+
* - Bind: refuses non-loopback addresses unless `allowPublic === true`.
|
|
61
|
+
* - Streaming requests: forwarded byte-for-byte; usage logged with token
|
|
62
|
+
* counts of 0 (real SSE usage parsing is a Phase 8 follow-up).
|
|
63
|
+
* - Non-streaming requests: response is **piped** to the client immediately
|
|
64
|
+
* and **teed** (capped at 1 MB) for `usage` parsing into local SQLite.
|
|
65
|
+
* The tee never blocks the wire; on overflow it is silently abandoned.
|
|
66
|
+
*/
|
|
67
|
+
export declare function proxyCommand(opts: ProxyOptions | string): Promise<ProxyHandle>;
|
|
68
|
+
//# sourceMappingURL=proxy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"proxy.d.ts","sourceRoot":"","sources":["../../src/commands/proxy.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAG7B,OAAO,EAAE,cAAc,EAAE,MAAM,qCAAqC,CAAC;AA4BrE,MAAM,WAAW,YAAY;IAC3B;;;;;OAKG;IACH,MAAM,EAAE,MAAM,CAAC;IAEf;;;;;;;;;OASG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAE3B;;;;;;;;OAQG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IAEtB;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;GAIG;AACH,MAAM,WAAW,WAAW;IAC1B,qDAAqD;IACrD,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC;IACpB,sDAAsD;IACtD,KAAK,EAAE,cAAc,CAAC;IACtB;;;;OAIG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1C;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,YAAY,CAAC,IAAI,EAAE,YAAY,GAAG,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAkHpF"}
|
|
@@ -0,0 +1,445 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.proxyCommand = proxyCommand;
|
|
40
|
+
const http = __importStar(require("http"));
|
|
41
|
+
const https = __importStar(require("https"));
|
|
42
|
+
const path_1 = __importDefault(require("path"));
|
|
43
|
+
const vault_guard_telemetry_1 = require("@vaultcompass/vault-guard-telemetry");
|
|
44
|
+
/**
|
|
45
|
+
* Bound inbound request buffering. 32 MB is a generous ceiling for
|
|
46
|
+
* Anthropic-shaped JSON bodies (multi-megabyte system prompts, large
|
|
47
|
+
* conversation histories) without enabling trivial OOM amplification.
|
|
48
|
+
*/
|
|
49
|
+
const MAX_REQUEST_BYTES = 32 * 1024 * 1024;
|
|
50
|
+
/**
|
|
51
|
+
* Hard cap on the in-memory **tee** of the upstream response body, used only
|
|
52
|
+
* for usage-token parsing on non-streaming responses. The wire response is
|
|
53
|
+
* piped to the client independently and is **not** bounded here — backpressure
|
|
54
|
+
* is handled by the OS pipe.
|
|
55
|
+
*
|
|
56
|
+
* If a response exceeds this cap before `end`, we abandon the tee (the user
|
|
57
|
+
* still gets their full response) and record a `proxy-tee-overflow` telemetry
|
|
58
|
+
* row so the operator can see usage data is missing for that request.
|
|
59
|
+
*/
|
|
60
|
+
const MAX_TEE_BYTES = 1 * 1024 * 1024;
|
|
61
|
+
/**
|
|
62
|
+
* Grace period for inflight requests during shutdown. After this, any
|
|
63
|
+
* lingering connections are force-closed via `server.closeAllConnections()`
|
|
64
|
+
* (Node ≥ 18.2).
|
|
65
|
+
*/
|
|
66
|
+
const SHUTDOWN_GRACE_MS = 5_000;
|
|
67
|
+
/**
|
|
68
|
+
* Minimal opt-in Anthropic forwarder: POST /v1/messages → api.anthropic.com.
|
|
69
|
+
*
|
|
70
|
+
* - Authentication: requires `x-api-key` from the caller. Falls back to
|
|
71
|
+
* `ANTHROPIC_API_KEY` only when `allowEnvFallback === true`.
|
|
72
|
+
* - Bind: refuses non-loopback addresses unless `allowPublic === true`.
|
|
73
|
+
* - Streaming requests: forwarded byte-for-byte; usage logged with token
|
|
74
|
+
* counts of 0 (real SSE usage parsing is a Phase 8 follow-up).
|
|
75
|
+
* - Non-streaming requests: response is **piped** to the client immediately
|
|
76
|
+
* and **teed** (capped at 1 MB) for `usage` parsing into local SQLite.
|
|
77
|
+
* The tee never blocks the wire; on overflow it is silently abandoned.
|
|
78
|
+
*/
|
|
79
|
+
async function proxyCommand(opts) {
|
|
80
|
+
// Backwards-compatible call shape: previous signature accepted a bare
|
|
81
|
+
// `listen` string. Tests and external callers may still pass that.
|
|
82
|
+
const options = typeof opts === 'string' ? { listen: opts } : opts;
|
|
83
|
+
const [host, portStr] = parseListen(options.listen);
|
|
84
|
+
const port = Number(portStr);
|
|
85
|
+
if (!Number.isFinite(port) || port < 0 || port > 65535) {
|
|
86
|
+
throw new Error(`Invalid port in --listen "${options.listen}"`);
|
|
87
|
+
}
|
|
88
|
+
if (!isLoopbackHost(host) && options.allowPublic !== true) {
|
|
89
|
+
throw new Error(`Refusing to bind non-loopback address "${host}". This would expose the proxy ` +
|
|
90
|
+
`to anyone reachable on the network. Re-run with --allow-public to override ` +
|
|
91
|
+
`(see SECURITY.md → "vault-guard proxy" before doing so).`);
|
|
92
|
+
}
|
|
93
|
+
const store = new vault_guard_telemetry_1.TelemetryStore();
|
|
94
|
+
const takeRateSlot = createRollingMinuteLimiter(options.maxRpm);
|
|
95
|
+
// Track inflight requests so shutdown() can drain them before force-closing.
|
|
96
|
+
let inflightCount = 0;
|
|
97
|
+
let drainResolve = null;
|
|
98
|
+
const server = http.createServer((req, res) => {
|
|
99
|
+
inflightCount++;
|
|
100
|
+
let settled = false;
|
|
101
|
+
const onDone = () => {
|
|
102
|
+
if (settled)
|
|
103
|
+
return;
|
|
104
|
+
settled = true;
|
|
105
|
+
inflightCount--;
|
|
106
|
+
if (inflightCount === 0 && drainResolve) {
|
|
107
|
+
drainResolve();
|
|
108
|
+
drainResolve = null;
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
res.on('finish', onDone);
|
|
112
|
+
res.on('close', onDone);
|
|
113
|
+
handleRequest(req, res, store, options, takeRateSlot).catch(err => {
|
|
114
|
+
// Defence-in-depth: surface unexpected handler errors as 502 rather than
|
|
115
|
+
// crashing the server. The handler should not throw on its own; if it
|
|
116
|
+
// does, that's a bug we want to know about (logged) but not one that
|
|
117
|
+
// takes down the proxy for other inflight requests.
|
|
118
|
+
try {
|
|
119
|
+
if (!res.headersSent) {
|
|
120
|
+
res.statusCode = 502;
|
|
121
|
+
res.setHeader('content-type', 'text/plain; charset=utf-8');
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
catch {
|
|
125
|
+
/* response may already be torn down */
|
|
126
|
+
}
|
|
127
|
+
try {
|
|
128
|
+
res.end(`vault-guard proxy: handler error: ${String(err)}`);
|
|
129
|
+
}
|
|
130
|
+
catch {
|
|
131
|
+
/* same */
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
});
|
|
135
|
+
await new Promise((resolve, reject) => {
|
|
136
|
+
server.listen(port, host, () => resolve());
|
|
137
|
+
server.on('error', reject);
|
|
138
|
+
});
|
|
139
|
+
process.stderr.write(`vault-guard proxy listening on http://${host}:${port}\n` +
|
|
140
|
+
`Forward Anthropic traffic here (e.g. ANTHROPIC_BASE_URL=http://${host}:${port}). ` +
|
|
141
|
+
`Non-stream JSON responses log usage to ${path_1.default.join('~', '.vault-guard', 'usage.sqlite')}.\n`);
|
|
142
|
+
if (options.allowEnvFallback) {
|
|
143
|
+
process.stderr.write(`⚠️ --allow-env-fallback is active: requests without x-api-key will use ` +
|
|
144
|
+
`ANTHROPIC_API_KEY from the proxy host's environment.\n`);
|
|
145
|
+
}
|
|
146
|
+
let shuttingDown = false;
|
|
147
|
+
const shutdown = async (reason) => {
|
|
148
|
+
if (shuttingDown)
|
|
149
|
+
return;
|
|
150
|
+
shuttingDown = true;
|
|
151
|
+
if (reason) {
|
|
152
|
+
process.stderr.write(`\nvault-guard proxy: ${reason} received, shutting down...\n`);
|
|
153
|
+
}
|
|
154
|
+
// Stop accepting new connections immediately.
|
|
155
|
+
server.close();
|
|
156
|
+
// Wait for inflight requests to drain, up to the grace window.
|
|
157
|
+
await new Promise(resolve => {
|
|
158
|
+
if (inflightCount === 0) {
|
|
159
|
+
resolve();
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
drainResolve = resolve;
|
|
163
|
+
setTimeout(() => {
|
|
164
|
+
drainResolve = null;
|
|
165
|
+
// Force-close any connections still open after the grace window.
|
|
166
|
+
const closer = server.closeAllConnections;
|
|
167
|
+
if (typeof closer === 'function')
|
|
168
|
+
closer.call(server);
|
|
169
|
+
resolve();
|
|
170
|
+
}, SHUTDOWN_GRACE_MS).unref();
|
|
171
|
+
});
|
|
172
|
+
try {
|
|
173
|
+
store.closeAndCheckpoint();
|
|
174
|
+
}
|
|
175
|
+
catch {
|
|
176
|
+
/* best-effort */
|
|
177
|
+
}
|
|
178
|
+
};
|
|
179
|
+
return { server, store, shutdown };
|
|
180
|
+
}
|
|
181
|
+
function createRollingMinuteLimiter(maxRpm) {
|
|
182
|
+
if (maxRpm === undefined || !Number.isFinite(maxRpm) || maxRpm < 1) {
|
|
183
|
+
return () => true;
|
|
184
|
+
}
|
|
185
|
+
const cap = Math.floor(maxRpm);
|
|
186
|
+
const windowMs = 60_000;
|
|
187
|
+
const stamps = [];
|
|
188
|
+
return () => {
|
|
189
|
+
const now = Date.now();
|
|
190
|
+
while (stamps.length > 0) {
|
|
191
|
+
const head = stamps[0];
|
|
192
|
+
if (head === undefined || now - head < windowMs)
|
|
193
|
+
break;
|
|
194
|
+
stamps.shift();
|
|
195
|
+
}
|
|
196
|
+
if (stamps.length >= cap)
|
|
197
|
+
return false;
|
|
198
|
+
stamps.push(now);
|
|
199
|
+
return true;
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
async function handleRequest(req, res, store, options, takeRateSlot) {
|
|
203
|
+
const u = req.url ?? '/';
|
|
204
|
+
if (req.method !== 'POST' || !u.startsWith('/v1/messages')) {
|
|
205
|
+
res.statusCode = 404;
|
|
206
|
+
res.setHeader('content-type', 'text/plain; charset=utf-8');
|
|
207
|
+
res.end('vault-guard proxy (MVP): only POST /v1/messages is forwarded to https://api.anthropic.com\n');
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
if (!takeRateSlot()) {
|
|
211
|
+
res.statusCode = 429;
|
|
212
|
+
res.setHeader('content-type', 'application/json; charset=utf-8');
|
|
213
|
+
res.end(JSON.stringify({
|
|
214
|
+
error: 'rate_limited',
|
|
215
|
+
message: `Exceeded --max-rpm (${options.maxRpm}) for the rolling 60s window`,
|
|
216
|
+
}));
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
const bodyBuf = await readRequestBody(req, res);
|
|
220
|
+
if (bodyBuf === null)
|
|
221
|
+
return; // 413 already sent
|
|
222
|
+
let bodyJson = {};
|
|
223
|
+
try {
|
|
224
|
+
bodyJson = JSON.parse(bodyBuf.toString('utf8'));
|
|
225
|
+
}
|
|
226
|
+
catch {
|
|
227
|
+
/* forward raw body; some Anthropic endpoints accept non-JSON bodies */
|
|
228
|
+
}
|
|
229
|
+
// ----- Authentication ----------------------------------------------------
|
|
230
|
+
// Caller-provided x-api-key always wins. Env fallback is opt-in.
|
|
231
|
+
const callerKey = typeof req.headers['x-api-key'] === 'string' ? req.headers['x-api-key'] : undefined;
|
|
232
|
+
let apiKey = callerKey;
|
|
233
|
+
if (!apiKey && options.allowEnvFallback) {
|
|
234
|
+
apiKey = process.env.ANTHROPIC_API_KEY ?? undefined;
|
|
235
|
+
}
|
|
236
|
+
if (!apiKey) {
|
|
237
|
+
res.statusCode = 401;
|
|
238
|
+
res.setHeader('content-type', 'application/json');
|
|
239
|
+
res.end(JSON.stringify({
|
|
240
|
+
error: 'missing_api_key',
|
|
241
|
+
message: options.allowEnvFallback
|
|
242
|
+
? 'send x-api-key, or set ANTHROPIC_API_KEY in the proxy host environment'
|
|
243
|
+
: 'send x-api-key, or restart proxy with --allow-env-fallback to use ANTHROPIC_API_KEY',
|
|
244
|
+
}));
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
const anthropicVersion = (typeof req.headers['anthropic-version'] === 'string'
|
|
248
|
+
? req.headers['anthropic-version']
|
|
249
|
+
: undefined) ?? '2023-06-01';
|
|
250
|
+
const cwd = process.cwd();
|
|
251
|
+
const upstreamOpts = {
|
|
252
|
+
hostname: 'api.anthropic.com',
|
|
253
|
+
port: 443,
|
|
254
|
+
path: u.startsWith('/') ? u : `/${u}`,
|
|
255
|
+
method: 'POST',
|
|
256
|
+
headers: {
|
|
257
|
+
'content-type': req.headers['content-type'] ?? 'application/json',
|
|
258
|
+
'x-api-key': apiKey,
|
|
259
|
+
'anthropic-version': anthropicVersion,
|
|
260
|
+
'content-length': String(bodyBuf.length),
|
|
261
|
+
},
|
|
262
|
+
};
|
|
263
|
+
await new Promise(resolve => {
|
|
264
|
+
const preq = https.request(upstreamOpts, pres => {
|
|
265
|
+
const stream = Boolean(bodyJson.stream);
|
|
266
|
+
const headers = { ...pres.headers };
|
|
267
|
+
res.writeHead(pres.statusCode ?? 502, headers);
|
|
268
|
+
if (stream) {
|
|
269
|
+
pres.pipe(res);
|
|
270
|
+
pres.on('end', () => {
|
|
271
|
+
store.recordUsage({
|
|
272
|
+
provider: 'anthropic',
|
|
273
|
+
model: typeof bodyJson.model === 'string' ? bodyJson.model : null,
|
|
274
|
+
cwd,
|
|
275
|
+
inputTokens: 0,
|
|
276
|
+
outputTokens: 0,
|
|
277
|
+
estCostUsd: 0,
|
|
278
|
+
source: 'proxy-stream',
|
|
279
|
+
});
|
|
280
|
+
resolve();
|
|
281
|
+
});
|
|
282
|
+
pres.on('error', () => resolve());
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
285
|
+
// ----- Non-streaming path ------------------------------------------
|
|
286
|
+
// Pipe upstream -> client immediately so memory use is bounded by the
|
|
287
|
+
// OS pipe, not by us. Tee a *separate* PassThrough for usage parsing,
|
|
288
|
+
// capped at MAX_TEE_BYTES. If the tee overflows, drop it: the wire
|
|
289
|
+
// pipe is not affected.
|
|
290
|
+
const isJsonResponse = typeof pres.headers['content-type'] === 'string' &&
|
|
291
|
+
pres.headers['content-type'].includes('application/json');
|
|
292
|
+
pres.pipe(res);
|
|
293
|
+
if (!isJsonResponse) {
|
|
294
|
+
// Non-JSON response (e.g. error HTML) — no usage to extract.
|
|
295
|
+
pres.on('end', () => {
|
|
296
|
+
store.recordUsage({
|
|
297
|
+
provider: 'anthropic',
|
|
298
|
+
model: typeof bodyJson.model === 'string' ? bodyJson.model : null,
|
|
299
|
+
cwd,
|
|
300
|
+
inputTokens: 0,
|
|
301
|
+
outputTokens: 0,
|
|
302
|
+
source: 'proxy-non-json',
|
|
303
|
+
});
|
|
304
|
+
resolve();
|
|
305
|
+
});
|
|
306
|
+
pres.on('error', () => resolve());
|
|
307
|
+
return;
|
|
308
|
+
}
|
|
309
|
+
const teeChunks = [];
|
|
310
|
+
let teeLen = 0;
|
|
311
|
+
let teeAbandoned = false;
|
|
312
|
+
pres.on('data', chunk => {
|
|
313
|
+
if (teeAbandoned)
|
|
314
|
+
return;
|
|
315
|
+
const b = chunk;
|
|
316
|
+
teeLen += b.length;
|
|
317
|
+
if (teeLen > MAX_TEE_BYTES) {
|
|
318
|
+
teeAbandoned = true;
|
|
319
|
+
// Drop accumulated chunks so we release the memory immediately.
|
|
320
|
+
teeChunks.length = 0;
|
|
321
|
+
return;
|
|
322
|
+
}
|
|
323
|
+
teeChunks.push(b);
|
|
324
|
+
});
|
|
325
|
+
pres.on('end', () => {
|
|
326
|
+
if (teeAbandoned) {
|
|
327
|
+
store.recordUsage({
|
|
328
|
+
provider: 'anthropic',
|
|
329
|
+
model: typeof bodyJson.model === 'string' ? bodyJson.model : null,
|
|
330
|
+
cwd,
|
|
331
|
+
inputTokens: 0,
|
|
332
|
+
outputTokens: 0,
|
|
333
|
+
source: 'proxy-tee-overflow',
|
|
334
|
+
});
|
|
335
|
+
resolve();
|
|
336
|
+
return;
|
|
337
|
+
}
|
|
338
|
+
try {
|
|
339
|
+
const raw = Buffer.concat(teeChunks);
|
|
340
|
+
const parsed = JSON.parse(raw.toString('utf8'));
|
|
341
|
+
const input = parsed.usage?.input_tokens ?? 0;
|
|
342
|
+
const output = parsed.usage?.output_tokens ?? 0;
|
|
343
|
+
const model = parsed.model ?? (typeof bodyJson.model === 'string' ? bodyJson.model : null);
|
|
344
|
+
store.recordUsage({
|
|
345
|
+
provider: 'anthropic',
|
|
346
|
+
model,
|
|
347
|
+
cwd,
|
|
348
|
+
inputTokens: input,
|
|
349
|
+
outputTokens: output,
|
|
350
|
+
source: 'proxy',
|
|
351
|
+
});
|
|
352
|
+
}
|
|
353
|
+
catch {
|
|
354
|
+
store.recordUsage({
|
|
355
|
+
provider: 'anthropic',
|
|
356
|
+
model: typeof bodyJson.model === 'string' ? bodyJson.model : null,
|
|
357
|
+
cwd,
|
|
358
|
+
inputTokens: 0,
|
|
359
|
+
outputTokens: 0,
|
|
360
|
+
source: 'proxy-parse-failed',
|
|
361
|
+
});
|
|
362
|
+
}
|
|
363
|
+
resolve();
|
|
364
|
+
});
|
|
365
|
+
pres.on('error', () => resolve());
|
|
366
|
+
});
|
|
367
|
+
preq.on('error', e => {
|
|
368
|
+
if (!res.headersSent) {
|
|
369
|
+
res.statusCode = 502;
|
|
370
|
+
res.setHeader('content-type', 'text/plain; charset=utf-8');
|
|
371
|
+
}
|
|
372
|
+
try {
|
|
373
|
+
res.end(String(e));
|
|
374
|
+
}
|
|
375
|
+
catch {
|
|
376
|
+
/* response may already be torn down */
|
|
377
|
+
}
|
|
378
|
+
resolve();
|
|
379
|
+
});
|
|
380
|
+
preq.write(bodyBuf);
|
|
381
|
+
preq.end();
|
|
382
|
+
});
|
|
383
|
+
}
|
|
384
|
+
/**
|
|
385
|
+
* Read the inbound request body up to `MAX_REQUEST_BYTES`. Returns `null` if
|
|
386
|
+
* the cap was exceeded (a 413 has already been written to `res`).
|
|
387
|
+
*/
|
|
388
|
+
function readRequestBody(req, res) {
|
|
389
|
+
return new Promise((resolve, reject) => {
|
|
390
|
+
const chunks = [];
|
|
391
|
+
let received = 0;
|
|
392
|
+
let aborted = false;
|
|
393
|
+
req.on('data', c => {
|
|
394
|
+
if (aborted)
|
|
395
|
+
return;
|
|
396
|
+
const b = c;
|
|
397
|
+
received += b.length;
|
|
398
|
+
if (received > MAX_REQUEST_BYTES) {
|
|
399
|
+
aborted = true;
|
|
400
|
+
res.statusCode = 413;
|
|
401
|
+
res.setHeader('content-type', 'application/json');
|
|
402
|
+
res.end(JSON.stringify({ error: 'payload_too_large', max_bytes: MAX_REQUEST_BYTES }));
|
|
403
|
+
// Drain the remaining body bytes so the connection isn't torn down
|
|
404
|
+
// abruptly before the client receives the 413 response.
|
|
405
|
+
req.resume();
|
|
406
|
+
resolve(null);
|
|
407
|
+
return;
|
|
408
|
+
}
|
|
409
|
+
chunks.push(b);
|
|
410
|
+
});
|
|
411
|
+
req.on('end', () => {
|
|
412
|
+
if (aborted)
|
|
413
|
+
return;
|
|
414
|
+
resolve(Buffer.concat(chunks));
|
|
415
|
+
});
|
|
416
|
+
req.on('error', reject);
|
|
417
|
+
});
|
|
418
|
+
}
|
|
419
|
+
function parseListen(listen) {
|
|
420
|
+
const m = /^(.*):(\d+)$/.exec(listen.trim());
|
|
421
|
+
if (!m) {
|
|
422
|
+
throw new Error(`Invalid --listen "${listen}" (expected host:port, e.g. 127.0.0.1:8765)`);
|
|
423
|
+
}
|
|
424
|
+
return [m[1], m[2]];
|
|
425
|
+
}
|
|
426
|
+
/**
|
|
427
|
+
* Loopback host detector. Recognises:
|
|
428
|
+
* - `127.0.0.1`, `localhost`
|
|
429
|
+
* - `::1`, `[::1]`
|
|
430
|
+
* - `::ffff:127.0.0.1` (IPv4-mapped IPv6 loopback — Linux/macOS dual-stack
|
|
431
|
+
* sockets sometimes report this)
|
|
432
|
+
*
|
|
433
|
+
* Anything else (including `0.0.0.0`, `::`, the empty string, LAN IPs) is
|
|
434
|
+
* treated as non-loopback and refused unless `--allow-public` is set.
|
|
435
|
+
*/
|
|
436
|
+
function isLoopbackHost(host) {
|
|
437
|
+
const h = host.toLowerCase().trim();
|
|
438
|
+
return (h === '127.0.0.1' ||
|
|
439
|
+
h === 'localhost' ||
|
|
440
|
+
h === '::1' ||
|
|
441
|
+
h === '[::1]' ||
|
|
442
|
+
h === '::ffff:127.0.0.1' ||
|
|
443
|
+
h === '[::ffff:127.0.0.1]');
|
|
444
|
+
}
|
|
445
|
+
//# sourceMappingURL=proxy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"proxy.js","sourceRoot":"","sources":["../../src/commands/proxy.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAoGA,oCAkHC;AAtND,2CAA6B;AAC7B,6CAA+B;AAC/B,gDAAwB;AACxB,+EAAqE;AAErE;;;;GAIG;AACH,MAAM,iBAAiB,GAAG,EAAE,GAAG,IAAI,GAAG,IAAI,CAAC;AAE3C;;;;;;;;;GASG;AACH,MAAM,aAAa,GAAG,CAAC,GAAG,IAAI,GAAG,IAAI,CAAC;AAEtC;;;;GAIG;AACH,MAAM,iBAAiB,GAAG,KAAK,CAAC;AA2DhC;;;;;;;;;;;GAWG;AACI,KAAK,UAAU,YAAY,CAAC,IAA2B;IAC5D,sEAAsE;IACtE,mEAAmE;IACnE,MAAM,OAAO,GAAiB,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;IAEjF,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,WAAW,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IACpD,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC;IAC7B,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,IAAI,GAAG,CAAC,IAAI,IAAI,GAAG,KAAK,EAAE,CAAC;QACvD,MAAM,IAAI,KAAK,CAAC,6BAA6B,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC;IAClE,CAAC;IAED,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,OAAO,CAAC,WAAW,KAAK,IAAI,EAAE,CAAC;QAC1D,MAAM,IAAI,KAAK,CACb,0CAA0C,IAAI,iCAAiC;YAC7E,6EAA6E;YAC7E,0DAA0D,CAC7D,CAAC;IACJ,CAAC;IAED,MAAM,KAAK,GAAG,IAAI,sCAAc,EAAE,CAAC;IACnC,MAAM,YAAY,GAAG,0BAA0B,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IAEhE,6EAA6E;IAC7E,IAAI,aAAa,GAAG,CAAC,CAAC;IACtB,IAAI,YAAY,GAAwB,IAAI,CAAC;IAE7C,MAAM,MAAM,GAAG,IAAI,CAAC,YAAY,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE;QAC5C,aAAa,EAAE,CAAC;QAChB,IAAI,OAAO,GAAG,KAAK,CAAC;QACpB,MAAM,MAAM,GAAG,GAAG,EAAE;YAClB,IAAI,OAAO;gBAAE,OAAO;YACpB,OAAO,GAAG,IAAI,CAAC;YACf,aAAa,EAAE,CAAC;YAChB,IAAI,aAAa,KAAK,CAAC,IAAI,YAAY,EAAE,CAAC;gBACxC,YAAY,EAAE,CAAC;gBACf,YAAY,GAAG,IAAI,CAAC;YACtB,CAAC;QACH,CAAC,CAAC;QACF,GAAG,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;QACzB,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QAExB,aAAa,CAAC,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,OAAO,EAAE,YAAY,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE;YAChE,yEAAyE;YACzE,sEAAsE;YACtE,qEAAqE;YACrE,oDAAoD;YACpD,IAAI,CAAC;gBACH,IAAI,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC;oBACrB,GAAG,CAAC,UAAU,GAAG,GAAG,CAAC;oBACrB,GAAG,CAAC,SAAS,CAAC,cAAc,EAAE,2BAA2B,CAAC,CAAC;gBAC7D,CAAC;YACH,CAAC;YAAC,MAAM,CAAC;gBACP,uCAAuC;YACzC,CAAC;YACD,IAAI,CAAC;gBACH,GAAG,CAAC,GAAG,CAAC,qCAAqC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YAC9D,CAAC;YAAC,MAAM,CAAC;gBACP,UAAU;YACZ,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QAC1C,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC;QAC3C,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IAC7B,CAAC,CAAC,CAAC;IAEH,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,yCAAyC,IAAI,IAAI,IAAI,IAAI;QACvD,kEAAkE,IAAI,IAAI,IAAI,KAAK;QACnF,0CAA0C,cAAI,CAAC,IAAI,CAAC,GAAG,EAAE,cAAc,EAAE,cAAc,CAAC,KAAK,CAChG,CAAC;IACF,IAAI,OAAO,CAAC,gBAAgB,EAAE,CAAC;QAC7B,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,0EAA0E;YACxE,wDAAwD,CAC3D,CAAC;IACJ,CAAC;IAED,IAAI,YAAY,GAAG,KAAK,CAAC;IACzB,MAAM,QAAQ,GAAG,KAAK,EAAE,MAAe,EAAiB,EAAE;QACxD,IAAI,YAAY;YAAE,OAAO;QACzB,YAAY,GAAG,IAAI,CAAC;QACpB,IAAI,MAAM,EAAE,CAAC;YACX,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,wBAAwB,MAAM,+BAA+B,CAAC,CAAC;QACtF,CAAC;QAED,8CAA8C;QAC9C,MAAM,CAAC,KAAK,EAAE,CAAC;QAEf,+DAA+D;QAC/D,MAAM,IAAI,OAAO,CAAO,OAAO,CAAC,EAAE;YAChC,IAAI,aAAa,KAAK,CAAC,EAAE,CAAC;gBACxB,OAAO,EAAE,CAAC;gBACV,OAAO;YACT,CAAC;YACD,YAAY,GAAG,OAAO,CAAC;YACvB,UAAU,CAAC,GAAG,EAAE;gBACd,YAAY,GAAG,IAAI,CAAC;gBACpB,iEAAiE;gBACjE,MAAM,MAAM,GAAI,MAA0D,CAAC,mBAAmB,CAAC;gBAC/F,IAAI,OAAO,MAAM,KAAK,UAAU;oBAAE,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;gBACtD,OAAO,EAAE,CAAC;YACZ,CAAC,EAAE,iBAAiB,CAAC,CAAC,KAAK,EAAE,CAAC;QAChC,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC;YACH,KAAK,CAAC,kBAAkB,EAAE,CAAC;QAC7B,CAAC;QAAC,MAAM,CAAC;YACP,iBAAiB;QACnB,CAAC;IACH,CAAC,CAAC;IAEF,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC;AACrC,CAAC;AAED,SAAS,0BAA0B,CAAC,MAA0B;IAC5D,IAAI,MAAM,KAAK,SAAS,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,MAAM,GAAG,CAAC,EAAE,CAAC;QACnE,OAAO,GAAG,EAAE,CAAC,IAAI,CAAC;IACpB,CAAC;IACD,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IAC/B,MAAM,QAAQ,GAAG,MAAM,CAAC;IACxB,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,OAAO,GAAY,EAAE;QACnB,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,OAAO,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACzB,MAAM,IAAI,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;YACvB,IAAI,IAAI,KAAK,SAAS,IAAI,GAAG,GAAG,IAAI,GAAG,QAAQ;gBAAE,MAAM;YACvD,MAAM,CAAC,KAAK,EAAE,CAAC;QACjB,CAAC;QACD,IAAI,MAAM,CAAC,MAAM,IAAI,GAAG;YAAE,OAAO,KAAK,CAAC;QACvC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACjB,OAAO,IAAI,CAAC;IACd,CAAC,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,aAAa,CAC1B,GAAyB,EACzB,GAAwB,EACxB,KAAqB,EACrB,OAAqB,EACrB,YAA2B;IAE3B,MAAM,CAAC,GAAG,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC;IACzB,IAAI,GAAG,CAAC,MAAM,KAAK,MAAM,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,cAAc,CAAC,EAAE,CAAC;QAC3D,GAAG,CAAC,UAAU,GAAG,GAAG,CAAC;QACrB,GAAG,CAAC,SAAS,CAAC,cAAc,EAAE,2BAA2B,CAAC,CAAC;QAC3D,GAAG,CAAC,GAAG,CACL,6FAA6F,CAC9F,CAAC;QACF,OAAO;IACT,CAAC;IAED,IAAI,CAAC,YAAY,EAAE,EAAE,CAAC;QACpB,GAAG,CAAC,UAAU,GAAG,GAAG,CAAC;QACrB,GAAG,CAAC,SAAS,CAAC,cAAc,EAAE,iCAAiC,CAAC,CAAC;QACjE,GAAG,CAAC,GAAG,CACL,IAAI,CAAC,SAAS,CAAC;YACb,KAAK,EAAE,cAAc;YACrB,OAAO,EAAE,uBAAuB,OAAO,CAAC,MAAM,8BAA8B;SAC7E,CAAC,CACH,CAAC;QACF,OAAO;IACT,CAAC;IAED,MAAM,OAAO,GAAG,MAAM,eAAe,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;IAChD,IAAI,OAAO,KAAK,IAAI;QAAE,OAAO,CAAC,mBAAmB;IAEjD,IAAI,QAAQ,GAAyC,EAAE,CAAC;IACxD,IAAI,CAAC;QACH,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAoB,CAAC;IACrE,CAAC;IAAC,MAAM,CAAC;QACP,uEAAuE;IACzE,CAAC;IAED,4EAA4E;IAC5E,iEAAiE;IACjE,MAAM,SAAS,GACb,OAAO,GAAG,CAAC,OAAO,CAAC,WAAW,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IACtF,IAAI,MAAM,GAAG,SAAS,CAAC;IACvB,IAAI,CAAC,MAAM,IAAI,OAAO,CAAC,gBAAgB,EAAE,CAAC;QACxC,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,iBAAiB,IAAI,SAAS,CAAC;IACtD,CAAC;IACD,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,GAAG,CAAC,UAAU,GAAG,GAAG,CAAC;QACrB,GAAG,CAAC,SAAS,CAAC,cAAc,EAAE,kBAAkB,CAAC,CAAC;QAClD,GAAG,CAAC,GAAG,CACL,IAAI,CAAC,SAAS,CAAC;YACb,KAAK,EAAE,iBAAiB;YACxB,OAAO,EAAE,OAAO,CAAC,gBAAgB;gBAC/B,CAAC,CAAC,wEAAwE;gBAC1E,CAAC,CAAC,qFAAqF;SAC1F,CAAC,CACH,CAAC;QACF,OAAO;IACT,CAAC;IAED,MAAM,gBAAgB,GACpB,CAAC,OAAO,GAAG,CAAC,OAAO,CAAC,mBAAmB,CAAC,KAAK,QAAQ;QACnD,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,mBAAmB,CAAC;QAClC,CAAC,CAAC,SAAS,CAAC,IAAI,YAAY,CAAC;IAEjC,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;IAC1B,MAAM,YAAY,GAAyB;QACzC,QAAQ,EAAE,mBAAmB;QAC7B,IAAI,EAAE,GAAG;QACT,IAAI,EAAE,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE;QACrC,MAAM,EAAE,MAAM;QACd,OAAO,EAAE;YACP,cAAc,EAAG,GAAG,CAAC,OAAO,CAAC,cAAc,CAAY,IAAI,kBAAkB;YAC7E,WAAW,EAAE,MAAM;YACnB,mBAAmB,EAAE,gBAAgB;YACrC,gBAAgB,EAAE,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC;SACzC;KACF,CAAC;IAEF,MAAM,IAAI,OAAO,CAAO,OAAO,CAAC,EAAE;QAChC,MAAM,IAAI,GAAG,KAAK,CAAC,OAAO,CAAC,YAAY,EAAE,IAAI,CAAC,EAAE;YAC9C,MAAM,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;YACxC,MAAM,OAAO,GAAG,EAAE,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC;YACpC,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC,UAAU,IAAI,GAAG,EAAE,OAAO,CAAC,CAAC;YAE/C,IAAI,MAAM,EAAE,CAAC;gBACX,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;gBACf,IAAI,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE;oBAClB,KAAK,CAAC,WAAW,CAAC;wBAChB,QAAQ,EAAE,WAAW;wBACrB,KAAK,EAAE,OAAO,QAAQ,CAAC,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI;wBACjE,GAAG;wBACH,WAAW,EAAE,CAAC;wBACd,YAAY,EAAE,CAAC;wBACf,UAAU,EAAE,CAAC;wBACb,MAAM,EAAE,cAAc;qBACvB,CAAC,CAAC;oBACH,OAAO,EAAE,CAAC;gBACZ,CAAC,CAAC,CAAC;gBACH,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC;gBAClC,OAAO;YACT,CAAC;YAED,sEAAsE;YACtE,sEAAsE;YACtE,sEAAsE;YACtE,mEAAmE;YACnE,wBAAwB;YACxB,MAAM,cAAc,GAClB,OAAO,IAAI,CAAC,OAAO,CAAC,cAAc,CAAC,KAAK,QAAQ;gBAChD,IAAI,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC,QAAQ,CAAC,kBAAkB,CAAC,CAAC;YAE5D,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YAEf,IAAI,CAAC,cAAc,EAAE,CAAC;gBACpB,6DAA6D;gBAC7D,IAAI,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE;oBAClB,KAAK,CAAC,WAAW,CAAC;wBAChB,QAAQ,EAAE,WAAW;wBACrB,KAAK,EAAE,OAAO,QAAQ,CAAC,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI;wBACjE,GAAG;wBACH,WAAW,EAAE,CAAC;wBACd,YAAY,EAAE,CAAC;wBACf,MAAM,EAAE,gBAAgB;qBACzB,CAAC,CAAC;oBACH,OAAO,EAAE,CAAC;gBACZ,CAAC,CAAC,CAAC;gBACH,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC;gBAClC,OAAO;YACT,CAAC;YAED,MAAM,SAAS,GAAa,EAAE,CAAC;YAC/B,IAAI,MAAM,GAAG,CAAC,CAAC;YACf,IAAI,YAAY,GAAG,KAAK,CAAC;YAEzB,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,KAAK,CAAC,EAAE;gBACtB,IAAI,YAAY;oBAAE,OAAO;gBACzB,MAAM,CAAC,GAAG,KAAe,CAAC;gBAC1B,MAAM,IAAI,CAAC,CAAC,MAAM,CAAC;gBACnB,IAAI,MAAM,GAAG,aAAa,EAAE,CAAC;oBAC3B,YAAY,GAAG,IAAI,CAAC;oBACpB,gEAAgE;oBAChE,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC;oBACrB,OAAO;gBACT,CAAC;gBACD,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YACpB,CAAC,CAAC,CAAC;YAEH,IAAI,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE;gBAClB,IAAI,YAAY,EAAE,CAAC;oBACjB,KAAK,CAAC,WAAW,CAAC;wBAChB,QAAQ,EAAE,WAAW;wBACrB,KAAK,EAAE,OAAO,QAAQ,CAAC,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI;wBACjE,GAAG;wBACH,WAAW,EAAE,CAAC;wBACd,YAAY,EAAE,CAAC;wBACf,MAAM,EAAE,oBAAoB;qBAC7B,CAAC,CAAC;oBACH,OAAO,EAAE,CAAC;oBACV,OAAO;gBACT,CAAC;gBACD,IAAI,CAAC;oBACH,MAAM,GAAG,GAAG,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;oBACrC,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,CAG7C,CAAC;oBACF,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,EAAE,YAAY,IAAI,CAAC,CAAC;oBAC9C,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,EAAE,aAAa,IAAI,CAAC,CAAC;oBAChD,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,IAAI,CAAC,OAAO,QAAQ,CAAC,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;oBAC3F,KAAK,CAAC,WAAW,CAAC;wBAChB,QAAQ,EAAE,WAAW;wBACrB,KAAK;wBACL,GAAG;wBACH,WAAW,EAAE,KAAK;wBAClB,YAAY,EAAE,MAAM;wBACpB,MAAM,EAAE,OAAO;qBAChB,CAAC,CAAC;gBACL,CAAC;gBAAC,MAAM,CAAC;oBACP,KAAK,CAAC,WAAW,CAAC;wBAChB,QAAQ,EAAE,WAAW;wBACrB,KAAK,EAAE,OAAO,QAAQ,CAAC,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI;wBACjE,GAAG;wBACH,WAAW,EAAE,CAAC;wBACd,YAAY,EAAE,CAAC;wBACf,MAAM,EAAE,oBAAoB;qBAC7B,CAAC,CAAC;gBACL,CAAC;gBACD,OAAO,EAAE,CAAC;YACZ,CAAC,CAAC,CAAC;YAEH,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC;QACpC,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC,EAAE;YACnB,IAAI,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC;gBACrB,GAAG,CAAC,UAAU,GAAG,GAAG,CAAC;gBACrB,GAAG,CAAC,SAAS,CAAC,cAAc,EAAE,2BAA2B,CAAC,CAAC;YAC7D,CAAC;YACD,IAAI,CAAC;gBACH,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;YACrB,CAAC;YAAC,MAAM,CAAC;gBACP,uCAAuC;YACzC,CAAC;YACD,OAAO,EAAE,CAAC;QACZ,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QACpB,IAAI,CAAC,GAAG,EAAE,CAAC;IACb,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;GAGG;AACH,SAAS,eAAe,CACtB,GAAyB,EACzB,GAAwB;IAExB,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,MAAM,MAAM,GAAa,EAAE,CAAC;QAC5B,IAAI,QAAQ,GAAG,CAAC,CAAC;QACjB,IAAI,OAAO,GAAG,KAAK,CAAC;QAEpB,GAAG,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,CAAC,EAAE;YACjB,IAAI,OAAO;gBAAE,OAAO;YACpB,MAAM,CAAC,GAAG,CAAW,CAAC;YACtB,QAAQ,IAAI,CAAC,CAAC,MAAM,CAAC;YACrB,IAAI,QAAQ,GAAG,iBAAiB,EAAE,CAAC;gBACjC,OAAO,GAAG,IAAI,CAAC;gBACf,GAAG,CAAC,UAAU,GAAG,GAAG,CAAC;gBACrB,GAAG,CAAC,SAAS,CAAC,cAAc,EAAE,kBAAkB,CAAC,CAAC;gBAClD,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,mBAAmB,EAAE,SAAS,EAAE,iBAAiB,EAAE,CAAC,CAAC,CAAC;gBACtF,mEAAmE;gBACnE,wDAAwD;gBACxD,GAAG,CAAC,MAAM,EAAE,CAAC;gBACb,OAAO,CAAC,IAAI,CAAC,CAAC;gBACd,OAAO;YACT,CAAC;YACD,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACjB,CAAC,CAAC,CAAC;QACH,GAAG,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE;YACjB,IAAI,OAAO;gBAAE,OAAO;YACpB,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC;QACjC,CAAC,CAAC,CAAC;QACH,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IAC1B,CAAC,CAAC,CAAC;AACL,CAAC;AAED,SAAS,WAAW,CAAC,MAAc;IACjC,MAAM,CAAC,GAAG,cAAc,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC;IAC7C,IAAI,CAAC,CAAC,EAAE,CAAC;QACP,MAAM,IAAI,KAAK,CAAC,qBAAqB,MAAM,6CAA6C,CAAC,CAAC;IAC5F,CAAC;IACD,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACtB,CAAC;AAED;;;;;;;;;GASG;AACH,SAAS,cAAc,CAAC,IAAY;IAClC,MAAM,CAAC,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC,IAAI,EAAE,CAAC;IACpC,OAAO,CACL,CAAC,KAAK,WAAW;QACjB,CAAC,KAAK,WAAW;QACjB,CAAC,KAAK,KAAK;QACX,CAAC,KAAK,OAAO;QACb,CAAC,KAAK,kBAAkB;QACxB,CAAC,KAAK,oBAAoB,CAC3B,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scan.d.ts","sourceRoot":"","sources":["../../src/commands/scan.ts"],"names":[],"mappings":"AA4BA,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;AAErD,wBAAsB,WAAW,CAC/B,UAAU,EAAE,MAAM,EAClB,MAAM,GAAE,YAAqB,EAC7B,MAAM,UAAQ,GACb,OAAO,CAAC,MAAM,CAAC,CA2LjB"}
|