@copilotkit/aimock 1.7.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/.claude-plugin/marketplace.json +17 -0
- package/.claude-plugin/plugin.json +12 -0
- package/LICENSE +21 -0
- package/README.md +82 -0
- package/dist/_virtual/_rolldown/runtime.cjs +29 -0
- package/dist/a2a-handler.cjs +203 -0
- package/dist/a2a-handler.cjs.map +1 -0
- package/dist/a2a-handler.js +199 -0
- package/dist/a2a-handler.js.map +1 -0
- package/dist/a2a-mock.cjs +292 -0
- package/dist/a2a-mock.cjs.map +1 -0
- package/dist/a2a-mock.d.cts +41 -0
- package/dist/a2a-mock.d.cts.map +1 -0
- package/dist/a2a-mock.d.ts +41 -0
- package/dist/a2a-mock.d.ts.map +1 -0
- package/dist/a2a-mock.js +290 -0
- package/dist/a2a-mock.js.map +1 -0
- package/dist/a2a-stub.cjs +4 -0
- package/dist/a2a-stub.d.cts +3 -0
- package/dist/a2a-stub.d.ts +3 -0
- package/dist/a2a-stub.js +3 -0
- package/dist/a2a-types.d.cts +68 -0
- package/dist/a2a-types.d.cts.map +1 -0
- package/dist/a2a-types.d.ts +68 -0
- package/dist/a2a-types.d.ts.map +1 -0
- package/dist/aimock-cli.cjs +112 -0
- package/dist/aimock-cli.cjs.map +1 -0
- package/dist/aimock-cli.d.cts +19 -0
- package/dist/aimock-cli.d.cts.map +1 -0
- package/dist/aimock-cli.d.ts +19 -0
- package/dist/aimock-cli.d.ts.map +1 -0
- package/dist/aimock-cli.js +110 -0
- package/dist/aimock-cli.js.map +1 -0
- package/dist/aws-event-stream.cjs +117 -0
- package/dist/aws-event-stream.cjs.map +1 -0
- package/dist/aws-event-stream.d.cts +38 -0
- package/dist/aws-event-stream.d.cts.map +1 -0
- package/dist/aws-event-stream.d.ts +38 -0
- package/dist/aws-event-stream.d.ts.map +1 -0
- package/dist/aws-event-stream.js +114 -0
- package/dist/aws-event-stream.js.map +1 -0
- package/dist/bedrock-converse.cjs +445 -0
- package/dist/bedrock-converse.cjs.map +1 -0
- package/dist/bedrock-converse.d.cts +50 -0
- package/dist/bedrock-converse.d.cts.map +1 -0
- package/dist/bedrock-converse.d.ts +50 -0
- package/dist/bedrock-converse.d.ts.map +1 -0
- package/dist/bedrock-converse.js +443 -0
- package/dist/bedrock-converse.js.map +1 -0
- package/dist/bedrock.cjs +557 -0
- package/dist/bedrock.cjs.map +1 -0
- package/dist/bedrock.d.cts +41 -0
- package/dist/bedrock.d.cts.map +1 -0
- package/dist/bedrock.d.ts +41 -0
- package/dist/bedrock.d.ts.map +1 -0
- package/dist/bedrock.js +553 -0
- package/dist/bedrock.js.map +1 -0
- package/dist/chaos.cjs +114 -0
- package/dist/chaos.cjs.map +1 -0
- package/dist/chaos.d.cts +27 -0
- package/dist/chaos.d.cts.map +1 -0
- package/dist/chaos.d.ts +27 -0
- package/dist/chaos.d.ts.map +1 -0
- package/dist/chaos.js +113 -0
- package/dist/chaos.js.map +1 -0
- package/dist/cli.cjs +268 -0
- package/dist/cli.cjs.map +1 -0
- package/dist/cli.d.cts +1 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +268 -0
- package/dist/cli.js.map +1 -0
- package/dist/cohere.cjs +434 -0
- package/dist/cohere.cjs.map +1 -0
- package/dist/cohere.d.cts +34 -0
- package/dist/cohere.d.cts.map +1 -0
- package/dist/cohere.d.ts +34 -0
- package/dist/cohere.d.ts.map +1 -0
- package/dist/cohere.js +433 -0
- package/dist/cohere.js.map +1 -0
- package/dist/config-loader.cjs +111 -0
- package/dist/config-loader.cjs.map +1 -0
- package/dist/config-loader.d.cts +100 -0
- package/dist/config-loader.d.cts.map +1 -0
- package/dist/config-loader.d.ts +100 -0
- package/dist/config-loader.d.ts.map +1 -0
- package/dist/config-loader.js +107 -0
- package/dist/config-loader.js.map +1 -0
- package/dist/embeddings.cjs +150 -0
- package/dist/embeddings.cjs.map +1 -0
- package/dist/embeddings.d.cts +12 -0
- package/dist/embeddings.d.cts.map +1 -0
- package/dist/embeddings.d.ts +12 -0
- package/dist/embeddings.d.ts.map +1 -0
- package/dist/embeddings.js +150 -0
- package/dist/embeddings.js.map +1 -0
- package/dist/fixture-loader.cjs +269 -0
- package/dist/fixture-loader.cjs.map +1 -0
- package/dist/fixture-loader.d.cts +17 -0
- package/dist/fixture-loader.d.cts.map +1 -0
- package/dist/fixture-loader.d.ts +17 -0
- package/dist/fixture-loader.d.ts.map +1 -0
- package/dist/fixture-loader.js +265 -0
- package/dist/fixture-loader.js.map +1 -0
- package/dist/gemini.cjs +403 -0
- package/dist/gemini.cjs.map +1 -0
- package/dist/gemini.d.cts +10 -0
- package/dist/gemini.d.cts.map +1 -0
- package/dist/gemini.d.ts +10 -0
- package/dist/gemini.d.ts.map +1 -0
- package/dist/gemini.js +403 -0
- package/dist/gemini.js.map +1 -0
- package/dist/helpers.cjs +276 -0
- package/dist/helpers.cjs.map +1 -0
- package/dist/helpers.d.cts +39 -0
- package/dist/helpers.d.cts.map +1 -0
- package/dist/helpers.d.ts +39 -0
- package/dist/helpers.d.ts.map +1 -0
- package/dist/helpers.js +259 -0
- package/dist/helpers.js.map +1 -0
- package/dist/index.cjs +113 -0
- package/dist/index.d.cts +42 -0
- package/dist/index.d.ts +42 -0
- package/dist/index.js +39 -0
- package/dist/interruption.cjs +40 -0
- package/dist/interruption.cjs.map +1 -0
- package/dist/interruption.d.cts +15 -0
- package/dist/interruption.d.cts.map +1 -0
- package/dist/interruption.d.ts +15 -0
- package/dist/interruption.d.ts.map +1 -0
- package/dist/interruption.js +39 -0
- package/dist/interruption.js.map +1 -0
- package/dist/journal.cjs +65 -0
- package/dist/journal.cjs.map +1 -0
- package/dist/journal.d.cts +23 -0
- package/dist/journal.d.cts.map +1 -0
- package/dist/journal.d.ts +23 -0
- package/dist/journal.d.ts.map +1 -0
- package/dist/journal.js +65 -0
- package/dist/journal.js.map +1 -0
- package/dist/jsonrpc.cjs +91 -0
- package/dist/jsonrpc.cjs.map +1 -0
- package/dist/jsonrpc.d.cts +24 -0
- package/dist/jsonrpc.d.cts.map +1 -0
- package/dist/jsonrpc.d.ts +24 -0
- package/dist/jsonrpc.d.ts.map +1 -0
- package/dist/jsonrpc.js +90 -0
- package/dist/jsonrpc.js.map +1 -0
- package/dist/llmock.cjs +223 -0
- package/dist/llmock.cjs.map +1 -0
- package/dist/llmock.d.cts +70 -0
- package/dist/llmock.d.cts.map +1 -0
- package/dist/llmock.d.ts +70 -0
- package/dist/llmock.d.ts.map +1 -0
- package/dist/llmock.js +223 -0
- package/dist/llmock.js.map +1 -0
- package/dist/logger.cjs +29 -0
- package/dist/logger.cjs.map +1 -0
- package/dist/logger.d.cts +14 -0
- package/dist/logger.d.cts.map +1 -0
- package/dist/logger.d.ts +14 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +28 -0
- package/dist/logger.js.map +1 -0
- package/dist/mcp-handler.cjs +189 -0
- package/dist/mcp-handler.cjs.map +1 -0
- package/dist/mcp-handler.js +188 -0
- package/dist/mcp-handler.js.map +1 -0
- package/dist/mcp-mock.cjs +169 -0
- package/dist/mcp-mock.cjs.map +1 -0
- package/dist/mcp-mock.d.cts +40 -0
- package/dist/mcp-mock.d.cts.map +1 -0
- package/dist/mcp-mock.d.ts +40 -0
- package/dist/mcp-mock.d.ts.map +1 -0
- package/dist/mcp-mock.js +167 -0
- package/dist/mcp-mock.js.map +1 -0
- package/dist/mcp-stub.cjs +4 -0
- package/dist/mcp-stub.d.cts +3 -0
- package/dist/mcp-stub.d.ts +3 -0
- package/dist/mcp-stub.js +3 -0
- package/dist/mcp-types.d.cts +65 -0
- package/dist/mcp-types.d.cts.map +1 -0
- package/dist/mcp-types.d.ts +65 -0
- package/dist/mcp-types.d.ts.map +1 -0
- package/dist/messages.cjs +489 -0
- package/dist/messages.cjs.map +1 -0
- package/dist/messages.d.cts +10 -0
- package/dist/messages.d.cts.map +1 -0
- package/dist/messages.d.ts +10 -0
- package/dist/messages.d.ts.map +1 -0
- package/dist/messages.js +489 -0
- package/dist/messages.js.map +1 -0
- package/dist/metrics.cjs +160 -0
- package/dist/metrics.cjs.map +1 -0
- package/dist/metrics.d.cts +24 -0
- package/dist/metrics.d.cts.map +1 -0
- package/dist/metrics.d.ts +24 -0
- package/dist/metrics.d.ts.map +1 -0
- package/dist/metrics.js +158 -0
- package/dist/metrics.js.map +1 -0
- package/dist/moderation.cjs +91 -0
- package/dist/moderation.cjs.map +1 -0
- package/dist/moderation.d.cts +23 -0
- package/dist/moderation.d.cts.map +1 -0
- package/dist/moderation.d.ts +23 -0
- package/dist/moderation.d.ts.map +1 -0
- package/dist/moderation.js +91 -0
- package/dist/moderation.js.map +1 -0
- package/dist/ndjson-writer.cjs +31 -0
- package/dist/ndjson-writer.cjs.map +1 -0
- package/dist/ndjson-writer.d.cts +17 -0
- package/dist/ndjson-writer.d.cts.map +1 -0
- package/dist/ndjson-writer.d.ts +17 -0
- package/dist/ndjson-writer.d.ts.map +1 -0
- package/dist/ndjson-writer.js +31 -0
- package/dist/ndjson-writer.js.map +1 -0
- package/dist/ollama.cjs +519 -0
- package/dist/ollama.cjs.map +1 -0
- package/dist/ollama.d.cts +34 -0
- package/dist/ollama.d.cts.map +1 -0
- package/dist/ollama.d.ts +34 -0
- package/dist/ollama.d.ts.map +1 -0
- package/dist/ollama.js +517 -0
- package/dist/ollama.js.map +1 -0
- package/dist/recorder.cjs +311 -0
- package/dist/recorder.cjs.map +1 -0
- package/dist/recorder.d.cts +23 -0
- package/dist/recorder.d.cts.map +1 -0
- package/dist/recorder.d.ts +23 -0
- package/dist/recorder.d.ts.map +1 -0
- package/dist/recorder.js +305 -0
- package/dist/recorder.js.map +1 -0
- package/dist/rerank.cjs +71 -0
- package/dist/rerank.cjs.map +1 -0
- package/dist/rerank.d.cts +22 -0
- package/dist/rerank.d.cts.map +1 -0
- package/dist/rerank.d.ts +22 -0
- package/dist/rerank.d.ts.map +1 -0
- package/dist/rerank.js +71 -0
- package/dist/rerank.js.map +1 -0
- package/dist/responses.cjs +637 -0
- package/dist/responses.cjs.map +1 -0
- package/dist/responses.d.cts +16 -0
- package/dist/responses.d.cts.map +1 -0
- package/dist/responses.d.ts +16 -0
- package/dist/responses.d.ts.map +1 -0
- package/dist/responses.js +634 -0
- package/dist/responses.js.map +1 -0
- package/dist/router.cjs +68 -0
- package/dist/router.cjs.map +1 -0
- package/dist/router.d.cts +16 -0
- package/dist/router.d.cts.map +1 -0
- package/dist/router.d.ts +16 -0
- package/dist/router.d.ts.map +1 -0
- package/dist/router.js +65 -0
- package/dist/router.js.map +1 -0
- package/dist/search.cjs +59 -0
- package/dist/search.cjs.map +1 -0
- package/dist/search.d.cts +23 -0
- package/dist/search.d.cts.map +1 -0
- package/dist/search.d.ts +23 -0
- package/dist/search.d.ts.map +1 -0
- package/dist/search.js +59 -0
- package/dist/search.js.map +1 -0
- package/dist/server.cjs +935 -0
- package/dist/server.cjs.map +1 -0
- package/dist/server.d.cts +28 -0
- package/dist/server.d.cts.map +1 -0
- package/dist/server.d.ts +28 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +933 -0
- package/dist/server.js.map +1 -0
- package/dist/sse-writer.cjs +59 -0
- package/dist/sse-writer.cjs.map +1 -0
- package/dist/sse-writer.d.cts +19 -0
- package/dist/sse-writer.d.cts.map +1 -0
- package/dist/sse-writer.d.ts +19 -0
- package/dist/sse-writer.d.ts.map +1 -0
- package/dist/sse-writer.js +55 -0
- package/dist/sse-writer.js.map +1 -0
- package/dist/stream-collapse.cjs +496 -0
- package/dist/stream-collapse.cjs.map +1 -0
- package/dist/stream-collapse.d.cts +70 -0
- package/dist/stream-collapse.d.cts.map +1 -0
- package/dist/stream-collapse.d.ts +70 -0
- package/dist/stream-collapse.d.ts.map +1 -0
- package/dist/stream-collapse.js +489 -0
- package/dist/stream-collapse.js.map +1 -0
- package/dist/suite.cjs +46 -0
- package/dist/suite.cjs.map +1 -0
- package/dist/suite.d.cts +31 -0
- package/dist/suite.d.cts.map +1 -0
- package/dist/suite.d.ts +31 -0
- package/dist/suite.d.ts.map +1 -0
- package/dist/suite.js +46 -0
- package/dist/suite.js.map +1 -0
- package/dist/types.d.cts +243 -0
- package/dist/types.d.cts.map +1 -0
- package/dist/types.d.ts +243 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/url.cjs +21 -0
- package/dist/url.cjs.map +1 -0
- package/dist/url.d.cts +16 -0
- package/dist/url.d.cts.map +1 -0
- package/dist/url.d.ts +16 -0
- package/dist/url.d.ts.map +1 -0
- package/dist/url.js +20 -0
- package/dist/url.js.map +1 -0
- package/dist/vector-handler.cjs +239 -0
- package/dist/vector-handler.cjs.map +1 -0
- package/dist/vector-handler.js +238 -0
- package/dist/vector-handler.js.map +1 -0
- package/dist/vector-mock.cjs +229 -0
- package/dist/vector-mock.cjs.map +1 -0
- package/dist/vector-mock.d.cts +39 -0
- package/dist/vector-mock.d.cts.map +1 -0
- package/dist/vector-mock.d.ts +39 -0
- package/dist/vector-mock.d.ts.map +1 -0
- package/dist/vector-mock.js +227 -0
- package/dist/vector-mock.js.map +1 -0
- package/dist/vector-stub.cjs +4 -0
- package/dist/vector-stub.d.cts +3 -0
- package/dist/vector-stub.d.ts +3 -0
- package/dist/vector-stub.js +3 -0
- package/dist/vector-types.d.cts +32 -0
- package/dist/vector-types.d.cts.map +1 -0
- package/dist/vector-types.d.ts +32 -0
- package/dist/vector-types.d.ts.map +1 -0
- package/dist/watcher.cjs +59 -0
- package/dist/watcher.cjs.map +1 -0
- package/dist/watcher.js +58 -0
- package/dist/watcher.js.map +1 -0
- package/dist/ws-framing.cjs +187 -0
- package/dist/ws-framing.cjs.map +1 -0
- package/dist/ws-framing.d.cts +26 -0
- package/dist/ws-framing.d.cts.map +1 -0
- package/dist/ws-framing.d.ts +26 -0
- package/dist/ws-framing.d.ts.map +1 -0
- package/dist/ws-framing.js +184 -0
- package/dist/ws-framing.js.map +1 -0
- package/dist/ws-gemini-live.cjs +364 -0
- package/dist/ws-gemini-live.cjs.map +1 -0
- package/dist/ws-gemini-live.d.cts +18 -0
- package/dist/ws-gemini-live.d.cts.map +1 -0
- package/dist/ws-gemini-live.d.ts +18 -0
- package/dist/ws-gemini-live.d.ts.map +1 -0
- package/dist/ws-gemini-live.js +364 -0
- package/dist/ws-gemini-live.js.map +1 -0
- package/dist/ws-realtime.cjs +435 -0
- package/dist/ws-realtime.cjs.map +1 -0
- package/dist/ws-realtime.d.cts +17 -0
- package/dist/ws-realtime.d.cts.map +1 -0
- package/dist/ws-realtime.d.ts +17 -0
- package/dist/ws-realtime.d.ts.map +1 -0
- package/dist/ws-realtime.js +435 -0
- package/dist/ws-realtime.js.map +1 -0
- package/dist/ws-responses.cjs +164 -0
- package/dist/ws-responses.cjs.map +1 -0
- package/dist/ws-responses.d.cts +18 -0
- package/dist/ws-responses.d.cts.map +1 -0
- package/dist/ws-responses.d.ts +18 -0
- package/dist/ws-responses.d.ts.map +1 -0
- package/dist/ws-responses.js +164 -0
- package/dist/ws-responses.js.map +1 -0
- package/fixtures/example-greeting.json +12 -0
- package/fixtures/example-multi-turn.json +14 -0
- package/fixtures/example-tool-call.json +15 -0
- package/package.json +118 -0
- package/skills/write-fixtures/SKILL.md +625 -0
package/dist/chaos.cjs
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
const require_sse_writer = require('./sse-writer.cjs');
|
|
2
|
+
|
|
3
|
+
//#region src/chaos.ts
|
|
4
|
+
/**
|
|
5
|
+
* Resolve chaos config from headers, fixture, and server defaults.
|
|
6
|
+
* Header values override fixture values, which override server defaults.
|
|
7
|
+
*/
|
|
8
|
+
function resolveChaosConfig(fixture, serverDefaults, rawHeaders, logger) {
|
|
9
|
+
const base = { ...serverDefaults };
|
|
10
|
+
if (fixture?.chaos) {
|
|
11
|
+
if (fixture.chaos.dropRate !== void 0) base.dropRate = fixture.chaos.dropRate;
|
|
12
|
+
if (fixture.chaos.malformedRate !== void 0) base.malformedRate = fixture.chaos.malformedRate;
|
|
13
|
+
if (fixture.chaos.disconnectRate !== void 0) base.disconnectRate = fixture.chaos.disconnectRate;
|
|
14
|
+
}
|
|
15
|
+
if (rawHeaders) {
|
|
16
|
+
const dropHeader = rawHeaders["x-aimock-chaos-drop"];
|
|
17
|
+
const malformedHeader = rawHeaders["x-aimock-chaos-malformed"];
|
|
18
|
+
const disconnectHeader = rawHeaders["x-aimock-chaos-disconnect"];
|
|
19
|
+
if (typeof dropHeader === "string") {
|
|
20
|
+
const val = parseFloat(dropHeader);
|
|
21
|
+
if (isNaN(val)) logger?.warn(`[chaos] x-aimock-chaos-drop: invalid value "${dropHeader}", ignoring`);
|
|
22
|
+
else {
|
|
23
|
+
if (val < 0 || val > 1) logger?.warn(`[chaos] x-aimock-chaos-drop: value ${val} out of range [0,1], clamping`);
|
|
24
|
+
base.dropRate = Math.min(1, Math.max(0, val));
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
if (typeof malformedHeader === "string") {
|
|
28
|
+
const val = parseFloat(malformedHeader);
|
|
29
|
+
if (isNaN(val)) logger?.warn(`[chaos] x-aimock-chaos-malformed: invalid value "${malformedHeader}", ignoring`);
|
|
30
|
+
else {
|
|
31
|
+
if (val < 0 || val > 1) logger?.warn(`[chaos] x-aimock-chaos-malformed: value ${val} out of range [0,1], clamping`);
|
|
32
|
+
base.malformedRate = Math.min(1, Math.max(0, val));
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
if (typeof disconnectHeader === "string") {
|
|
36
|
+
const val = parseFloat(disconnectHeader);
|
|
37
|
+
if (isNaN(val)) logger?.warn(`[chaos] x-aimock-chaos-disconnect: invalid value "${disconnectHeader}", ignoring`);
|
|
38
|
+
else {
|
|
39
|
+
if (val < 0 || val > 1) logger?.warn(`[chaos] x-aimock-chaos-disconnect: value ${val} out of range [0,1], clamping`);
|
|
40
|
+
base.disconnectRate = Math.min(1, Math.max(0, val));
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
if (base.dropRate !== void 0) base.dropRate = Math.min(1, Math.max(0, base.dropRate));
|
|
45
|
+
if (base.malformedRate !== void 0) base.malformedRate = Math.min(1, Math.max(0, base.malformedRate));
|
|
46
|
+
if (base.disconnectRate !== void 0) base.disconnectRate = Math.min(1, Math.max(0, base.disconnectRate));
|
|
47
|
+
return base;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Evaluate chaos config and return the triggered action, or null if none.
|
|
51
|
+
* Checks in order: drop, malformed, disconnect — first hit wins.
|
|
52
|
+
*/
|
|
53
|
+
function evaluateChaos(fixture, serverDefaults, rawHeaders, logger) {
|
|
54
|
+
const config = resolveChaosConfig(fixture, serverDefaults, rawHeaders, logger);
|
|
55
|
+
if (config.dropRate !== void 0 && config.dropRate > 0 && Math.random() < config.dropRate) return "drop";
|
|
56
|
+
if (config.malformedRate !== void 0 && config.malformedRate > 0 && Math.random() < config.malformedRate) return "malformed";
|
|
57
|
+
if (config.disconnectRate !== void 0 && config.disconnectRate > 0 && Math.random() < config.disconnectRate) return "disconnect";
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Apply chaos to a request. Returns true if chaos was applied (caller should
|
|
62
|
+
* return early), false if the request should proceed normally.
|
|
63
|
+
*/
|
|
64
|
+
function applyChaos(res, fixture, serverDefaults, rawHeaders, journal, context, registry, logger) {
|
|
65
|
+
const action = evaluateChaos(fixture, serverDefaults, rawHeaders, logger);
|
|
66
|
+
if (!action) return false;
|
|
67
|
+
if (registry) registry.incrementCounter("aimock_chaos_triggered_total", { action });
|
|
68
|
+
switch (action) {
|
|
69
|
+
case "drop":
|
|
70
|
+
journal.add({
|
|
71
|
+
...context,
|
|
72
|
+
response: {
|
|
73
|
+
status: 500,
|
|
74
|
+
fixture,
|
|
75
|
+
chaosAction: "drop"
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
require_sse_writer.writeErrorResponse(res, 500, JSON.stringify({ error: {
|
|
79
|
+
message: "Chaos: request dropped",
|
|
80
|
+
type: "server_error",
|
|
81
|
+
code: "chaos_drop"
|
|
82
|
+
} }));
|
|
83
|
+
return true;
|
|
84
|
+
case "malformed":
|
|
85
|
+
journal.add({
|
|
86
|
+
...context,
|
|
87
|
+
response: {
|
|
88
|
+
status: 200,
|
|
89
|
+
fixture,
|
|
90
|
+
chaosAction: "malformed"
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
94
|
+
res.end("{malformed json: <<<chaos>>>");
|
|
95
|
+
return true;
|
|
96
|
+
case "disconnect":
|
|
97
|
+
journal.add({
|
|
98
|
+
...context,
|
|
99
|
+
response: {
|
|
100
|
+
status: 0,
|
|
101
|
+
fixture,
|
|
102
|
+
chaosAction: "disconnect"
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
res.destroy();
|
|
106
|
+
return true;
|
|
107
|
+
default: return false;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
//#endregion
|
|
112
|
+
exports.applyChaos = applyChaos;
|
|
113
|
+
exports.evaluateChaos = evaluateChaos;
|
|
114
|
+
//# sourceMappingURL=chaos.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chaos.cjs","names":[],"sources":["../src/chaos.ts"],"sourcesContent":["/**\n * Chaos testing support for LLMock.\n *\n * Provides probabilistic failure injection — requests can be dropped (500),\n * returned with malformed JSON, or have the connection forcibly disconnected.\n *\n * Precedence: per-request headers > fixture-level config > server-level defaults.\n */\n\nimport type * as http from \"node:http\";\nimport type { ChaosAction, ChaosConfig, ChatCompletionRequest, Fixture } from \"./types.js\";\nimport { writeErrorResponse } from \"./sse-writer.js\";\nimport type { Journal } from \"./journal.js\";\nimport type { Logger } from \"./logger.js\";\nimport type { MetricsRegistry } from \"./metrics.js\";\n\n/**\n * Resolve chaos config from headers, fixture, and server defaults.\n * Header values override fixture values, which override server defaults.\n */\nfunction resolveChaosConfig(\n fixture: Fixture | null,\n serverDefaults?: ChaosConfig,\n rawHeaders?: http.IncomingHttpHeaders,\n logger?: Logger,\n): ChaosConfig {\n const base: ChaosConfig = { ...serverDefaults };\n\n // Fixture-level overrides server defaults\n if (fixture?.chaos) {\n if (fixture.chaos.dropRate !== undefined) base.dropRate = fixture.chaos.dropRate;\n if (fixture.chaos.malformedRate !== undefined) base.malformedRate = fixture.chaos.malformedRate;\n if (fixture.chaos.disconnectRate !== undefined)\n base.disconnectRate = fixture.chaos.disconnectRate;\n }\n\n // Header overrides everything\n if (rawHeaders) {\n const dropHeader = rawHeaders[\"x-aimock-chaos-drop\"];\n const malformedHeader = rawHeaders[\"x-aimock-chaos-malformed\"];\n const disconnectHeader = rawHeaders[\"x-aimock-chaos-disconnect\"];\n\n if (typeof dropHeader === \"string\") {\n const val = parseFloat(dropHeader);\n if (isNaN(val)) {\n logger?.warn(`[chaos] x-aimock-chaos-drop: invalid value \"${dropHeader}\", ignoring`);\n } else {\n if (val < 0 || val > 1) {\n logger?.warn(`[chaos] x-aimock-chaos-drop: value ${val} out of range [0,1], clamping`);\n }\n base.dropRate = Math.min(1, Math.max(0, val));\n }\n }\n if (typeof malformedHeader === \"string\") {\n const val = parseFloat(malformedHeader);\n if (isNaN(val)) {\n logger?.warn(\n `[chaos] x-aimock-chaos-malformed: invalid value \"${malformedHeader}\", ignoring`,\n );\n } else {\n if (val < 0 || val > 1) {\n logger?.warn(\n `[chaos] x-aimock-chaos-malformed: value ${val} out of range [0,1], clamping`,\n );\n }\n base.malformedRate = Math.min(1, Math.max(0, val));\n }\n }\n if (typeof disconnectHeader === \"string\") {\n const val = parseFloat(disconnectHeader);\n if (isNaN(val)) {\n logger?.warn(\n `[chaos] x-aimock-chaos-disconnect: invalid value \"${disconnectHeader}\", ignoring`,\n );\n } else {\n if (val < 0 || val > 1) {\n logger?.warn(\n `[chaos] x-aimock-chaos-disconnect: value ${val} out of range [0,1], clamping`,\n );\n }\n base.disconnectRate = Math.min(1, Math.max(0, val));\n }\n }\n }\n\n // Clamp all resolved rates to [0, 1] regardless of source.\n // Header values are already clamped above; this covers fixture-level and server defaults.\n if (base.dropRate !== undefined) base.dropRate = Math.min(1, Math.max(0, base.dropRate));\n if (base.malformedRate !== undefined)\n base.malformedRate = Math.min(1, Math.max(0, base.malformedRate));\n if (base.disconnectRate !== undefined)\n base.disconnectRate = Math.min(1, Math.max(0, base.disconnectRate));\n\n return base;\n}\n\n/**\n * Evaluate chaos config and return the triggered action, or null if none.\n * Checks in order: drop, malformed, disconnect — first hit wins.\n */\nexport function evaluateChaos(\n fixture: Fixture | null,\n serverDefaults?: ChaosConfig,\n rawHeaders?: http.IncomingHttpHeaders,\n logger?: Logger,\n): ChaosAction | null {\n const config = resolveChaosConfig(fixture, serverDefaults, rawHeaders, logger);\n\n if (config.dropRate !== undefined && config.dropRate > 0 && Math.random() < config.dropRate) {\n return \"drop\";\n }\n if (\n config.malformedRate !== undefined &&\n config.malformedRate > 0 &&\n Math.random() < config.malformedRate\n ) {\n return \"malformed\";\n }\n if (\n config.disconnectRate !== undefined &&\n config.disconnectRate > 0 &&\n Math.random() < config.disconnectRate\n ) {\n return \"disconnect\";\n }\n\n return null;\n}\n\ninterface ChaosJournalContext {\n method: string;\n path: string;\n headers: Record<string, string>;\n body: ChatCompletionRequest;\n}\n\n/**\n * Apply chaos to a request. Returns true if chaos was applied (caller should\n * return early), false if the request should proceed normally.\n */\nexport function applyChaos(\n res: http.ServerResponse,\n fixture: Fixture | null,\n serverDefaults: ChaosConfig | undefined,\n rawHeaders: http.IncomingHttpHeaders,\n journal: Journal,\n context: ChaosJournalContext,\n registry?: MetricsRegistry,\n logger?: Logger,\n): boolean {\n const action = evaluateChaos(fixture, serverDefaults, rawHeaders, logger);\n if (!action) return false;\n\n if (registry) {\n registry.incrementCounter(\"aimock_chaos_triggered_total\", { action });\n }\n\n switch (action) {\n case \"drop\": {\n journal.add({\n ...context,\n response: { status: 500, fixture, chaosAction: \"drop\" },\n });\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({\n error: {\n message: \"Chaos: request dropped\",\n type: \"server_error\",\n code: \"chaos_drop\",\n },\n }),\n );\n return true;\n }\n case \"malformed\": {\n journal.add({\n ...context,\n response: { status: 200, fixture, chaosAction: \"malformed\" },\n });\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(\"{malformed json: <<<chaos>>>\");\n return true;\n }\n case \"disconnect\": {\n journal.add({\n ...context,\n response: { status: 0, fixture, chaosAction: \"disconnect\" },\n });\n res.destroy();\n return true;\n }\n default: {\n const _exhaustive: never = action;\n void _exhaustive;\n return false;\n }\n }\n}\n"],"mappings":";;;;;;;AAoBA,SAAS,mBACP,SACA,gBACA,YACA,QACa;CACb,MAAM,OAAoB,EAAE,GAAG,gBAAgB;AAG/C,KAAI,SAAS,OAAO;AAClB,MAAI,QAAQ,MAAM,aAAa,OAAW,MAAK,WAAW,QAAQ,MAAM;AACxE,MAAI,QAAQ,MAAM,kBAAkB,OAAW,MAAK,gBAAgB,QAAQ,MAAM;AAClF,MAAI,QAAQ,MAAM,mBAAmB,OACnC,MAAK,iBAAiB,QAAQ,MAAM;;AAIxC,KAAI,YAAY;EACd,MAAM,aAAa,WAAW;EAC9B,MAAM,kBAAkB,WAAW;EACnC,MAAM,mBAAmB,WAAW;AAEpC,MAAI,OAAO,eAAe,UAAU;GAClC,MAAM,MAAM,WAAW,WAAW;AAClC,OAAI,MAAM,IAAI,CACZ,SAAQ,KAAK,+CAA+C,WAAW,aAAa;QAC/E;AACL,QAAI,MAAM,KAAK,MAAM,EACnB,SAAQ,KAAK,sCAAsC,IAAI,+BAA+B;AAExF,SAAK,WAAW,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,IAAI,CAAC;;;AAGjD,MAAI,OAAO,oBAAoB,UAAU;GACvC,MAAM,MAAM,WAAW,gBAAgB;AACvC,OAAI,MAAM,IAAI,CACZ,SAAQ,KACN,oDAAoD,gBAAgB,aACrE;QACI;AACL,QAAI,MAAM,KAAK,MAAM,EACnB,SAAQ,KACN,2CAA2C,IAAI,+BAChD;AAEH,SAAK,gBAAgB,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,IAAI,CAAC;;;AAGtD,MAAI,OAAO,qBAAqB,UAAU;GACxC,MAAM,MAAM,WAAW,iBAAiB;AACxC,OAAI,MAAM,IAAI,CACZ,SAAQ,KACN,qDAAqD,iBAAiB,aACvE;QACI;AACL,QAAI,MAAM,KAAK,MAAM,EACnB,SAAQ,KACN,4CAA4C,IAAI,+BACjD;AAEH,SAAK,iBAAiB,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,IAAI,CAAC;;;;AAOzD,KAAI,KAAK,aAAa,OAAW,MAAK,WAAW,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,KAAK,SAAS,CAAC;AACxF,KAAI,KAAK,kBAAkB,OACzB,MAAK,gBAAgB,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,KAAK,cAAc,CAAC;AACnE,KAAI,KAAK,mBAAmB,OAC1B,MAAK,iBAAiB,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,KAAK,eAAe,CAAC;AAErE,QAAO;;;;;;AAOT,SAAgB,cACd,SACA,gBACA,YACA,QACoB;CACpB,MAAM,SAAS,mBAAmB,SAAS,gBAAgB,YAAY,OAAO;AAE9E,KAAI,OAAO,aAAa,UAAa,OAAO,WAAW,KAAK,KAAK,QAAQ,GAAG,OAAO,SACjF,QAAO;AAET,KACE,OAAO,kBAAkB,UACzB,OAAO,gBAAgB,KACvB,KAAK,QAAQ,GAAG,OAAO,cAEvB,QAAO;AAET,KACE,OAAO,mBAAmB,UAC1B,OAAO,iBAAiB,KACxB,KAAK,QAAQ,GAAG,OAAO,eAEvB,QAAO;AAGT,QAAO;;;;;;AAcT,SAAgB,WACd,KACA,SACA,gBACA,YACA,SACA,SACA,UACA,QACS;CACT,MAAM,SAAS,cAAc,SAAS,gBAAgB,YAAY,OAAO;AACzE,KAAI,CAAC,OAAQ,QAAO;AAEpB,KAAI,SACF,UAAS,iBAAiB,gCAAgC,EAAE,QAAQ,CAAC;AAGvE,SAAQ,QAAR;EACE,KAAK;AACH,WAAQ,IAAI;IACV,GAAG;IACH,UAAU;KAAE,QAAQ;KAAK;KAAS,aAAa;KAAQ;IACxD,CAAC;AACF,yCACE,KACA,KACA,KAAK,UAAU,EACb,OAAO;IACL,SAAS;IACT,MAAM;IACN,MAAM;IACP,EACF,CAAC,CACH;AACD,UAAO;EAET,KAAK;AACH,WAAQ,IAAI;IACV,GAAG;IACH,UAAU;KAAE,QAAQ;KAAK;KAAS,aAAa;KAAa;IAC7D,CAAC;AACF,OAAI,UAAU,KAAK,EAAE,gBAAgB,oBAAoB,CAAC;AAC1D,OAAI,IAAI,+BAA+B;AACvC,UAAO;EAET,KAAK;AACH,WAAQ,IAAI;IACV,GAAG;IACH,UAAU;KAAE,QAAQ;KAAG;KAAS,aAAa;KAAc;IAC5D,CAAC;AACF,OAAI,SAAS;AACb,UAAO;EAET,QAGE,QAAO"}
|
package/dist/chaos.d.cts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { Journal } from "./journal.cjs";
|
|
2
|
+
import { Logger } from "./logger.cjs";
|
|
3
|
+
import { MetricsRegistry } from "./metrics.cjs";
|
|
4
|
+
import { ChaosAction, ChaosConfig, ChatCompletionRequest, Fixture } from "./types.cjs";
|
|
5
|
+
import * as http from "node:http";
|
|
6
|
+
|
|
7
|
+
//#region src/chaos.d.ts
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Evaluate chaos config and return the triggered action, or null if none.
|
|
11
|
+
* Checks in order: drop, malformed, disconnect — first hit wins.
|
|
12
|
+
*/
|
|
13
|
+
declare function evaluateChaos(fixture: Fixture | null, serverDefaults?: ChaosConfig, rawHeaders?: http.IncomingHttpHeaders, logger?: Logger): ChaosAction | null;
|
|
14
|
+
interface ChaosJournalContext {
|
|
15
|
+
method: string;
|
|
16
|
+
path: string;
|
|
17
|
+
headers: Record<string, string>;
|
|
18
|
+
body: ChatCompletionRequest;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Apply chaos to a request. Returns true if chaos was applied (caller should
|
|
22
|
+
* return early), false if the request should proceed normally.
|
|
23
|
+
*/
|
|
24
|
+
declare function applyChaos(res: http.ServerResponse, fixture: Fixture | null, serverDefaults: ChaosConfig | undefined, rawHeaders: http.IncomingHttpHeaders, journal: Journal, context: ChaosJournalContext, registry?: MetricsRegistry, logger?: Logger): boolean;
|
|
25
|
+
//#endregion
|
|
26
|
+
export { applyChaos, evaluateChaos };
|
|
27
|
+
//# sourceMappingURL=chaos.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chaos.d.cts","names":[],"sources":["../src/chaos.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;AA+HC;;AAKU,iBAhCK,aAAA,CAgCL,OAAA,EA/BA,OA+BA,GAAA,IAAA,EAAA,cAAA,CAAA,EA9BQ,WA8BR,EAAA,UAAA,CAAA,EA7BI,IAAA,CAAK,mBA6BT,EAAA,MAAA,CAAA,EA5BA,MA4BA,CAAA,EA3BR,WA2BQ,GAAA,IAAA;UAHD,mBAAA,CAIF;EAAqB,MAAA,EAAA,MAAA;EAOb,IAAA,EAAA,MAAA;EAAU,OAAA,EARf,MAQe,CAAA,MAAA,EAAA,MAAA,CAAA;MACnB,EARC,qBAQI;;;;;;AAMC,iBAPG,UAAA,CAOH,GAAA,EANN,IAAA,CAAK,cAMC,EAAA,OAAA,EALF,OAKE,GAAA,IAAA,EAAA,cAAA,EAJK,WAIL,GAAA,SAAA,EAAA,UAAA,EAHC,IAAA,CAAK,mBAGN,EAAA,OAAA,EAFF,OAEE,EAAA,OAAA,EADF,mBACE,EAAA,QAAA,CAAA,EAAA,eAAA,EAAA,MAAA,CAAA,EACF,MADE,CAAA,EAAA,OAAA"}
|
package/dist/chaos.d.ts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { Journal } from "./journal.js";
|
|
2
|
+
import { Logger } from "./logger.js";
|
|
3
|
+
import { MetricsRegistry } from "./metrics.js";
|
|
4
|
+
import { ChaosAction, ChaosConfig, ChatCompletionRequest, Fixture } from "./types.js";
|
|
5
|
+
import * as http from "node:http";
|
|
6
|
+
|
|
7
|
+
//#region src/chaos.d.ts
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Evaluate chaos config and return the triggered action, or null if none.
|
|
11
|
+
* Checks in order: drop, malformed, disconnect — first hit wins.
|
|
12
|
+
*/
|
|
13
|
+
declare function evaluateChaos(fixture: Fixture | null, serverDefaults?: ChaosConfig, rawHeaders?: http.IncomingHttpHeaders, logger?: Logger): ChaosAction | null;
|
|
14
|
+
interface ChaosJournalContext {
|
|
15
|
+
method: string;
|
|
16
|
+
path: string;
|
|
17
|
+
headers: Record<string, string>;
|
|
18
|
+
body: ChatCompletionRequest;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Apply chaos to a request. Returns true if chaos was applied (caller should
|
|
22
|
+
* return early), false if the request should proceed normally.
|
|
23
|
+
*/
|
|
24
|
+
declare function applyChaos(res: http.ServerResponse, fixture: Fixture | null, serverDefaults: ChaosConfig | undefined, rawHeaders: http.IncomingHttpHeaders, journal: Journal, context: ChaosJournalContext, registry?: MetricsRegistry, logger?: Logger): boolean;
|
|
25
|
+
//#endregion
|
|
26
|
+
export { applyChaos, evaluateChaos };
|
|
27
|
+
//# sourceMappingURL=chaos.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chaos.d.ts","names":[],"sources":["../src/chaos.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;AA+HC;;AAKU,iBAhCK,aAAA,CAgCL,OAAA,EA/BA,OA+BA,GAAA,IAAA,EAAA,cAAA,CAAA,EA9BQ,WA8BR,EAAA,UAAA,CAAA,EA7BI,IAAA,CAAK,mBA6BT,EAAA,MAAA,CAAA,EA5BA,MA4BA,CAAA,EA3BR,WA2BQ,GAAA,IAAA;UAHD,mBAAA,CAIF;EAAqB,MAAA,EAAA,MAAA;EAOb,IAAA,EAAA,MAAA;EAAU,OAAA,EARf,MAQe,CAAA,MAAA,EAAA,MAAA,CAAA;MACnB,EARC,qBAQI;;;;;;AAMC,iBAPG,UAAA,CAOH,GAAA,EANN,IAAA,CAAK,cAMC,EAAA,OAAA,EALF,OAKE,GAAA,IAAA,EAAA,cAAA,EAJK,WAIL,GAAA,SAAA,EAAA,UAAA,EAHC,IAAA,CAAK,mBAGN,EAAA,OAAA,EAFF,OAEE,EAAA,OAAA,EADF,mBACE,EAAA,QAAA,CAAA,EAAA,eAAA,EAAA,MAAA,CAAA,EACF,MADE,CAAA,EAAA,OAAA"}
|
package/dist/chaos.js
ADDED
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { writeErrorResponse } from "./sse-writer.js";
|
|
2
|
+
|
|
3
|
+
//#region src/chaos.ts
|
|
4
|
+
/**
|
|
5
|
+
* Resolve chaos config from headers, fixture, and server defaults.
|
|
6
|
+
* Header values override fixture values, which override server defaults.
|
|
7
|
+
*/
|
|
8
|
+
function resolveChaosConfig(fixture, serverDefaults, rawHeaders, logger) {
|
|
9
|
+
const base = { ...serverDefaults };
|
|
10
|
+
if (fixture?.chaos) {
|
|
11
|
+
if (fixture.chaos.dropRate !== void 0) base.dropRate = fixture.chaos.dropRate;
|
|
12
|
+
if (fixture.chaos.malformedRate !== void 0) base.malformedRate = fixture.chaos.malformedRate;
|
|
13
|
+
if (fixture.chaos.disconnectRate !== void 0) base.disconnectRate = fixture.chaos.disconnectRate;
|
|
14
|
+
}
|
|
15
|
+
if (rawHeaders) {
|
|
16
|
+
const dropHeader = rawHeaders["x-aimock-chaos-drop"];
|
|
17
|
+
const malformedHeader = rawHeaders["x-aimock-chaos-malformed"];
|
|
18
|
+
const disconnectHeader = rawHeaders["x-aimock-chaos-disconnect"];
|
|
19
|
+
if (typeof dropHeader === "string") {
|
|
20
|
+
const val = parseFloat(dropHeader);
|
|
21
|
+
if (isNaN(val)) logger?.warn(`[chaos] x-aimock-chaos-drop: invalid value "${dropHeader}", ignoring`);
|
|
22
|
+
else {
|
|
23
|
+
if (val < 0 || val > 1) logger?.warn(`[chaos] x-aimock-chaos-drop: value ${val} out of range [0,1], clamping`);
|
|
24
|
+
base.dropRate = Math.min(1, Math.max(0, val));
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
if (typeof malformedHeader === "string") {
|
|
28
|
+
const val = parseFloat(malformedHeader);
|
|
29
|
+
if (isNaN(val)) logger?.warn(`[chaos] x-aimock-chaos-malformed: invalid value "${malformedHeader}", ignoring`);
|
|
30
|
+
else {
|
|
31
|
+
if (val < 0 || val > 1) logger?.warn(`[chaos] x-aimock-chaos-malformed: value ${val} out of range [0,1], clamping`);
|
|
32
|
+
base.malformedRate = Math.min(1, Math.max(0, val));
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
if (typeof disconnectHeader === "string") {
|
|
36
|
+
const val = parseFloat(disconnectHeader);
|
|
37
|
+
if (isNaN(val)) logger?.warn(`[chaos] x-aimock-chaos-disconnect: invalid value "${disconnectHeader}", ignoring`);
|
|
38
|
+
else {
|
|
39
|
+
if (val < 0 || val > 1) logger?.warn(`[chaos] x-aimock-chaos-disconnect: value ${val} out of range [0,1], clamping`);
|
|
40
|
+
base.disconnectRate = Math.min(1, Math.max(0, val));
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
if (base.dropRate !== void 0) base.dropRate = Math.min(1, Math.max(0, base.dropRate));
|
|
45
|
+
if (base.malformedRate !== void 0) base.malformedRate = Math.min(1, Math.max(0, base.malformedRate));
|
|
46
|
+
if (base.disconnectRate !== void 0) base.disconnectRate = Math.min(1, Math.max(0, base.disconnectRate));
|
|
47
|
+
return base;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Evaluate chaos config and return the triggered action, or null if none.
|
|
51
|
+
* Checks in order: drop, malformed, disconnect — first hit wins.
|
|
52
|
+
*/
|
|
53
|
+
function evaluateChaos(fixture, serverDefaults, rawHeaders, logger) {
|
|
54
|
+
const config = resolveChaosConfig(fixture, serverDefaults, rawHeaders, logger);
|
|
55
|
+
if (config.dropRate !== void 0 && config.dropRate > 0 && Math.random() < config.dropRate) return "drop";
|
|
56
|
+
if (config.malformedRate !== void 0 && config.malformedRate > 0 && Math.random() < config.malformedRate) return "malformed";
|
|
57
|
+
if (config.disconnectRate !== void 0 && config.disconnectRate > 0 && Math.random() < config.disconnectRate) return "disconnect";
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Apply chaos to a request. Returns true if chaos was applied (caller should
|
|
62
|
+
* return early), false if the request should proceed normally.
|
|
63
|
+
*/
|
|
64
|
+
function applyChaos(res, fixture, serverDefaults, rawHeaders, journal, context, registry, logger) {
|
|
65
|
+
const action = evaluateChaos(fixture, serverDefaults, rawHeaders, logger);
|
|
66
|
+
if (!action) return false;
|
|
67
|
+
if (registry) registry.incrementCounter("aimock_chaos_triggered_total", { action });
|
|
68
|
+
switch (action) {
|
|
69
|
+
case "drop":
|
|
70
|
+
journal.add({
|
|
71
|
+
...context,
|
|
72
|
+
response: {
|
|
73
|
+
status: 500,
|
|
74
|
+
fixture,
|
|
75
|
+
chaosAction: "drop"
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
writeErrorResponse(res, 500, JSON.stringify({ error: {
|
|
79
|
+
message: "Chaos: request dropped",
|
|
80
|
+
type: "server_error",
|
|
81
|
+
code: "chaos_drop"
|
|
82
|
+
} }));
|
|
83
|
+
return true;
|
|
84
|
+
case "malformed":
|
|
85
|
+
journal.add({
|
|
86
|
+
...context,
|
|
87
|
+
response: {
|
|
88
|
+
status: 200,
|
|
89
|
+
fixture,
|
|
90
|
+
chaosAction: "malformed"
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
94
|
+
res.end("{malformed json: <<<chaos>>>");
|
|
95
|
+
return true;
|
|
96
|
+
case "disconnect":
|
|
97
|
+
journal.add({
|
|
98
|
+
...context,
|
|
99
|
+
response: {
|
|
100
|
+
status: 0,
|
|
101
|
+
fixture,
|
|
102
|
+
chaosAction: "disconnect"
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
res.destroy();
|
|
106
|
+
return true;
|
|
107
|
+
default: return false;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
//#endregion
|
|
112
|
+
export { applyChaos, evaluateChaos };
|
|
113
|
+
//# sourceMappingURL=chaos.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chaos.js","names":[],"sources":["../src/chaos.ts"],"sourcesContent":["/**\n * Chaos testing support for LLMock.\n *\n * Provides probabilistic failure injection — requests can be dropped (500),\n * returned with malformed JSON, or have the connection forcibly disconnected.\n *\n * Precedence: per-request headers > fixture-level config > server-level defaults.\n */\n\nimport type * as http from \"node:http\";\nimport type { ChaosAction, ChaosConfig, ChatCompletionRequest, Fixture } from \"./types.js\";\nimport { writeErrorResponse } from \"./sse-writer.js\";\nimport type { Journal } from \"./journal.js\";\nimport type { Logger } from \"./logger.js\";\nimport type { MetricsRegistry } from \"./metrics.js\";\n\n/**\n * Resolve chaos config from headers, fixture, and server defaults.\n * Header values override fixture values, which override server defaults.\n */\nfunction resolveChaosConfig(\n fixture: Fixture | null,\n serverDefaults?: ChaosConfig,\n rawHeaders?: http.IncomingHttpHeaders,\n logger?: Logger,\n): ChaosConfig {\n const base: ChaosConfig = { ...serverDefaults };\n\n // Fixture-level overrides server defaults\n if (fixture?.chaos) {\n if (fixture.chaos.dropRate !== undefined) base.dropRate = fixture.chaos.dropRate;\n if (fixture.chaos.malformedRate !== undefined) base.malformedRate = fixture.chaos.malformedRate;\n if (fixture.chaos.disconnectRate !== undefined)\n base.disconnectRate = fixture.chaos.disconnectRate;\n }\n\n // Header overrides everything\n if (rawHeaders) {\n const dropHeader = rawHeaders[\"x-aimock-chaos-drop\"];\n const malformedHeader = rawHeaders[\"x-aimock-chaos-malformed\"];\n const disconnectHeader = rawHeaders[\"x-aimock-chaos-disconnect\"];\n\n if (typeof dropHeader === \"string\") {\n const val = parseFloat(dropHeader);\n if (isNaN(val)) {\n logger?.warn(`[chaos] x-aimock-chaos-drop: invalid value \"${dropHeader}\", ignoring`);\n } else {\n if (val < 0 || val > 1) {\n logger?.warn(`[chaos] x-aimock-chaos-drop: value ${val} out of range [0,1], clamping`);\n }\n base.dropRate = Math.min(1, Math.max(0, val));\n }\n }\n if (typeof malformedHeader === \"string\") {\n const val = parseFloat(malformedHeader);\n if (isNaN(val)) {\n logger?.warn(\n `[chaos] x-aimock-chaos-malformed: invalid value \"${malformedHeader}\", ignoring`,\n );\n } else {\n if (val < 0 || val > 1) {\n logger?.warn(\n `[chaos] x-aimock-chaos-malformed: value ${val} out of range [0,1], clamping`,\n );\n }\n base.malformedRate = Math.min(1, Math.max(0, val));\n }\n }\n if (typeof disconnectHeader === \"string\") {\n const val = parseFloat(disconnectHeader);\n if (isNaN(val)) {\n logger?.warn(\n `[chaos] x-aimock-chaos-disconnect: invalid value \"${disconnectHeader}\", ignoring`,\n );\n } else {\n if (val < 0 || val > 1) {\n logger?.warn(\n `[chaos] x-aimock-chaos-disconnect: value ${val} out of range [0,1], clamping`,\n );\n }\n base.disconnectRate = Math.min(1, Math.max(0, val));\n }\n }\n }\n\n // Clamp all resolved rates to [0, 1] regardless of source.\n // Header values are already clamped above; this covers fixture-level and server defaults.\n if (base.dropRate !== undefined) base.dropRate = Math.min(1, Math.max(0, base.dropRate));\n if (base.malformedRate !== undefined)\n base.malformedRate = Math.min(1, Math.max(0, base.malformedRate));\n if (base.disconnectRate !== undefined)\n base.disconnectRate = Math.min(1, Math.max(0, base.disconnectRate));\n\n return base;\n}\n\n/**\n * Evaluate chaos config and return the triggered action, or null if none.\n * Checks in order: drop, malformed, disconnect — first hit wins.\n */\nexport function evaluateChaos(\n fixture: Fixture | null,\n serverDefaults?: ChaosConfig,\n rawHeaders?: http.IncomingHttpHeaders,\n logger?: Logger,\n): ChaosAction | null {\n const config = resolveChaosConfig(fixture, serverDefaults, rawHeaders, logger);\n\n if (config.dropRate !== undefined && config.dropRate > 0 && Math.random() < config.dropRate) {\n return \"drop\";\n }\n if (\n config.malformedRate !== undefined &&\n config.malformedRate > 0 &&\n Math.random() < config.malformedRate\n ) {\n return \"malformed\";\n }\n if (\n config.disconnectRate !== undefined &&\n config.disconnectRate > 0 &&\n Math.random() < config.disconnectRate\n ) {\n return \"disconnect\";\n }\n\n return null;\n}\n\ninterface ChaosJournalContext {\n method: string;\n path: string;\n headers: Record<string, string>;\n body: ChatCompletionRequest;\n}\n\n/**\n * Apply chaos to a request. Returns true if chaos was applied (caller should\n * return early), false if the request should proceed normally.\n */\nexport function applyChaos(\n res: http.ServerResponse,\n fixture: Fixture | null,\n serverDefaults: ChaosConfig | undefined,\n rawHeaders: http.IncomingHttpHeaders,\n journal: Journal,\n context: ChaosJournalContext,\n registry?: MetricsRegistry,\n logger?: Logger,\n): boolean {\n const action = evaluateChaos(fixture, serverDefaults, rawHeaders, logger);\n if (!action) return false;\n\n if (registry) {\n registry.incrementCounter(\"aimock_chaos_triggered_total\", { action });\n }\n\n switch (action) {\n case \"drop\": {\n journal.add({\n ...context,\n response: { status: 500, fixture, chaosAction: \"drop\" },\n });\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({\n error: {\n message: \"Chaos: request dropped\",\n type: \"server_error\",\n code: \"chaos_drop\",\n },\n }),\n );\n return true;\n }\n case \"malformed\": {\n journal.add({\n ...context,\n response: { status: 200, fixture, chaosAction: \"malformed\" },\n });\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(\"{malformed json: <<<chaos>>>\");\n return true;\n }\n case \"disconnect\": {\n journal.add({\n ...context,\n response: { status: 0, fixture, chaosAction: \"disconnect\" },\n });\n res.destroy();\n return true;\n }\n default: {\n const _exhaustive: never = action;\n void _exhaustive;\n return false;\n }\n }\n}\n"],"mappings":"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"}
|
package/dist/cli.cjs
ADDED
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
const require_runtime = require('./_virtual/_rolldown/runtime.cjs');
|
|
3
|
+
const require_fixture_loader = require('./fixture-loader.cjs');
|
|
4
|
+
const require_logger = require('./logger.cjs');
|
|
5
|
+
const require_server = require('./server.cjs');
|
|
6
|
+
const require_watcher = require('./watcher.cjs');
|
|
7
|
+
let node_util = require("node:util");
|
|
8
|
+
let node_path = require("node:path");
|
|
9
|
+
let node_fs = require("node:fs");
|
|
10
|
+
|
|
11
|
+
//#region src/cli.ts
|
|
12
|
+
const HELP = `
|
|
13
|
+
Usage: llmock [options]
|
|
14
|
+
|
|
15
|
+
Options:
|
|
16
|
+
-p, --port <number> Port to listen on (default: 4010)
|
|
17
|
+
-h, --host <string> Host to bind to (default: 127.0.0.1)
|
|
18
|
+
-f, --fixtures <path> Path to fixtures directory or file (default: ./fixtures)
|
|
19
|
+
-l, --latency <ms> Latency in ms between SSE chunks (default: 0)
|
|
20
|
+
-c, --chunk-size <chars> Chunk size in characters (default: 20)
|
|
21
|
+
-w, --watch Watch fixture path for changes and reload
|
|
22
|
+
--log-level <level> Log verbosity: silent, info, debug (default: info)
|
|
23
|
+
--validate-on-load Validate fixture schemas at startup
|
|
24
|
+
--metrics Enable Prometheus metrics at GET /metrics
|
|
25
|
+
--record Record mode: proxy unmatched requests to real APIs
|
|
26
|
+
--strict Strict mode: fail on unmatched requests
|
|
27
|
+
--provider-openai <url> Upstream URL for OpenAI (used with --record)
|
|
28
|
+
--provider-anthropic <url> Upstream URL for Anthropic
|
|
29
|
+
--provider-gemini <url> Upstream URL for Gemini
|
|
30
|
+
--provider-vertexai <url> Upstream URL for Vertex AI
|
|
31
|
+
--provider-bedrock <url> Upstream URL for Bedrock
|
|
32
|
+
--provider-azure <url> Upstream URL for Azure OpenAI
|
|
33
|
+
--provider-ollama <url> Upstream URL for Ollama
|
|
34
|
+
--provider-cohere <url> Upstream URL for Cohere
|
|
35
|
+
--chaos-drop <rate> Probability (0-1) of dropping requests with 500
|
|
36
|
+
--chaos-malformed <rate> Probability (0-1) of returning malformed JSON
|
|
37
|
+
--chaos-disconnect <rate> Probability (0-1) of destroying connection
|
|
38
|
+
--help Show this help message
|
|
39
|
+
`.trim();
|
|
40
|
+
const { values } = (0, node_util.parseArgs)({
|
|
41
|
+
options: {
|
|
42
|
+
port: {
|
|
43
|
+
type: "string",
|
|
44
|
+
short: "p",
|
|
45
|
+
default: "4010"
|
|
46
|
+
},
|
|
47
|
+
host: {
|
|
48
|
+
type: "string",
|
|
49
|
+
short: "h",
|
|
50
|
+
default: "127.0.0.1"
|
|
51
|
+
},
|
|
52
|
+
fixtures: {
|
|
53
|
+
type: "string",
|
|
54
|
+
short: "f",
|
|
55
|
+
default: "./fixtures"
|
|
56
|
+
},
|
|
57
|
+
latency: {
|
|
58
|
+
type: "string",
|
|
59
|
+
short: "l",
|
|
60
|
+
default: "0"
|
|
61
|
+
},
|
|
62
|
+
"chunk-size": {
|
|
63
|
+
type: "string",
|
|
64
|
+
short: "c",
|
|
65
|
+
default: "20"
|
|
66
|
+
},
|
|
67
|
+
watch: {
|
|
68
|
+
type: "boolean",
|
|
69
|
+
short: "w",
|
|
70
|
+
default: false
|
|
71
|
+
},
|
|
72
|
+
"log-level": {
|
|
73
|
+
type: "string",
|
|
74
|
+
default: "info"
|
|
75
|
+
},
|
|
76
|
+
"validate-on-load": {
|
|
77
|
+
type: "boolean",
|
|
78
|
+
default: false
|
|
79
|
+
},
|
|
80
|
+
metrics: {
|
|
81
|
+
type: "boolean",
|
|
82
|
+
default: false
|
|
83
|
+
},
|
|
84
|
+
record: {
|
|
85
|
+
type: "boolean",
|
|
86
|
+
default: false
|
|
87
|
+
},
|
|
88
|
+
strict: {
|
|
89
|
+
type: "boolean",
|
|
90
|
+
default: false
|
|
91
|
+
},
|
|
92
|
+
"provider-openai": { type: "string" },
|
|
93
|
+
"provider-anthropic": { type: "string" },
|
|
94
|
+
"provider-gemini": { type: "string" },
|
|
95
|
+
"provider-vertexai": { type: "string" },
|
|
96
|
+
"provider-bedrock": { type: "string" },
|
|
97
|
+
"provider-azure": { type: "string" },
|
|
98
|
+
"provider-ollama": { type: "string" },
|
|
99
|
+
"provider-cohere": { type: "string" },
|
|
100
|
+
"chaos-drop": { type: "string" },
|
|
101
|
+
"chaos-malformed": { type: "string" },
|
|
102
|
+
"chaos-disconnect": { type: "string" },
|
|
103
|
+
help: {
|
|
104
|
+
type: "boolean",
|
|
105
|
+
default: false
|
|
106
|
+
}
|
|
107
|
+
},
|
|
108
|
+
strict: true
|
|
109
|
+
});
|
|
110
|
+
if (values.help) {
|
|
111
|
+
console.log(HELP);
|
|
112
|
+
process.exit(0);
|
|
113
|
+
}
|
|
114
|
+
const port = Number(values.port);
|
|
115
|
+
const host = values.host;
|
|
116
|
+
const latency = Number(values.latency);
|
|
117
|
+
const chunkSize = Number(values["chunk-size"]);
|
|
118
|
+
const fixturePath = (0, node_path.resolve)(values.fixtures);
|
|
119
|
+
const watchMode = values.watch;
|
|
120
|
+
const validateOnLoad = values["validate-on-load"];
|
|
121
|
+
const logLevelStr = values["log-level"];
|
|
122
|
+
if (![
|
|
123
|
+
"silent",
|
|
124
|
+
"info",
|
|
125
|
+
"debug"
|
|
126
|
+
].includes(logLevelStr)) {
|
|
127
|
+
console.error(`Invalid log-level: ${logLevelStr} (must be silent, info, or debug)`);
|
|
128
|
+
process.exit(1);
|
|
129
|
+
}
|
|
130
|
+
const logLevel = logLevelStr;
|
|
131
|
+
if (Number.isNaN(port) || port < 0 || port > 65535) {
|
|
132
|
+
console.error(`Invalid port: ${values.port}`);
|
|
133
|
+
process.exit(1);
|
|
134
|
+
}
|
|
135
|
+
if (Number.isNaN(latency) || latency < 0) {
|
|
136
|
+
console.error(`Invalid latency: ${values.latency}`);
|
|
137
|
+
process.exit(1);
|
|
138
|
+
}
|
|
139
|
+
if (Number.isNaN(chunkSize) || chunkSize < 1) {
|
|
140
|
+
console.error(`Invalid chunk-size: ${values["chunk-size"]}`);
|
|
141
|
+
process.exit(1);
|
|
142
|
+
}
|
|
143
|
+
const logger = new require_logger.Logger(logLevel);
|
|
144
|
+
let chaos;
|
|
145
|
+
{
|
|
146
|
+
const dropStr = values["chaos-drop"];
|
|
147
|
+
const malformedStr = values["chaos-malformed"];
|
|
148
|
+
const disconnectStr = values["chaos-disconnect"];
|
|
149
|
+
if (dropStr !== void 0 || malformedStr !== void 0 || disconnectStr !== void 0) {
|
|
150
|
+
chaos = {};
|
|
151
|
+
if (dropStr !== void 0) {
|
|
152
|
+
const val = parseFloat(dropStr);
|
|
153
|
+
if (isNaN(val) || val < 0 || val > 1) {
|
|
154
|
+
console.error(`Invalid chaos-drop: ${dropStr} (must be 0-1)`);
|
|
155
|
+
process.exit(1);
|
|
156
|
+
}
|
|
157
|
+
chaos.dropRate = val;
|
|
158
|
+
}
|
|
159
|
+
if (malformedStr !== void 0) {
|
|
160
|
+
const val = parseFloat(malformedStr);
|
|
161
|
+
if (isNaN(val) || val < 0 || val > 1) {
|
|
162
|
+
console.error(`Invalid chaos-malformed: ${malformedStr} (must be 0-1)`);
|
|
163
|
+
process.exit(1);
|
|
164
|
+
}
|
|
165
|
+
chaos.malformedRate = val;
|
|
166
|
+
}
|
|
167
|
+
if (disconnectStr !== void 0) {
|
|
168
|
+
const val = parseFloat(disconnectStr);
|
|
169
|
+
if (isNaN(val) || val < 0 || val > 1) {
|
|
170
|
+
console.error(`Invalid chaos-disconnect: ${disconnectStr} (must be 0-1)`);
|
|
171
|
+
process.exit(1);
|
|
172
|
+
}
|
|
173
|
+
chaos.disconnectRate = val;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
let record;
|
|
178
|
+
if (values.record) {
|
|
179
|
+
const providers = {};
|
|
180
|
+
if (values["provider-openai"]) providers.openai = values["provider-openai"];
|
|
181
|
+
if (values["provider-anthropic"]) providers.anthropic = values["provider-anthropic"];
|
|
182
|
+
if (values["provider-gemini"]) providers.gemini = values["provider-gemini"];
|
|
183
|
+
if (values["provider-vertexai"]) providers.vertexai = values["provider-vertexai"];
|
|
184
|
+
if (values["provider-bedrock"]) providers.bedrock = values["provider-bedrock"];
|
|
185
|
+
if (values["provider-azure"]) providers.azure = values["provider-azure"];
|
|
186
|
+
if (values["provider-ollama"]) providers.ollama = values["provider-ollama"];
|
|
187
|
+
if (values["provider-cohere"]) providers.cohere = values["provider-cohere"];
|
|
188
|
+
if (Object.keys(providers).length === 0) {
|
|
189
|
+
console.error("Error: --record requires at least one --provider-* flag");
|
|
190
|
+
process.exit(1);
|
|
191
|
+
}
|
|
192
|
+
record = {
|
|
193
|
+
providers,
|
|
194
|
+
fixturePath: (0, node_path.resolve)(fixturePath, "recorded")
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
async function main() {
|
|
198
|
+
let isDir;
|
|
199
|
+
let fixtures;
|
|
200
|
+
try {
|
|
201
|
+
isDir = (0, node_fs.statSync)(fixturePath).isDirectory();
|
|
202
|
+
if (isDir) fixtures = require_fixture_loader.loadFixturesFromDir(fixturePath, logger);
|
|
203
|
+
else fixtures = require_fixture_loader.loadFixtureFile(fixturePath, logger);
|
|
204
|
+
} catch (err) {
|
|
205
|
+
if (err.code === "ENOENT") console.error(`Fixtures path not found: ${fixturePath}`);
|
|
206
|
+
else {
|
|
207
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
208
|
+
console.error(`Failed to load fixtures from ${fixturePath}: ${msg}`);
|
|
209
|
+
}
|
|
210
|
+
process.exit(1);
|
|
211
|
+
}
|
|
212
|
+
if (fixtures.length === 0) {
|
|
213
|
+
if (validateOnLoad || values.strict) {
|
|
214
|
+
console.error("Error: No fixtures loaded and validation/strict mode is enabled — aborting.");
|
|
215
|
+
process.exit(1);
|
|
216
|
+
}
|
|
217
|
+
console.warn("Warning: No fixtures loaded. The server will return 404 for all requests.");
|
|
218
|
+
}
|
|
219
|
+
logger.info(`Loaded ${fixtures.length} fixture(s) from ${fixturePath}`);
|
|
220
|
+
if (validateOnLoad) {
|
|
221
|
+
const results = require_fixture_loader.validateFixtures(fixtures);
|
|
222
|
+
const errors = results.filter((r) => r.severity === "error");
|
|
223
|
+
const warnings = results.filter((r) => r.severity === "warning");
|
|
224
|
+
for (const w of warnings) logger.warn(`Fixture ${w.fixtureIndex}: ${w.message}`);
|
|
225
|
+
for (const e of errors) logger.error(`Fixture ${e.fixtureIndex}: ${e.message}`);
|
|
226
|
+
if (errors.length > 0) {
|
|
227
|
+
console.error(`Validation failed: ${errors.length} error(s), ${warnings.length} warning(s)`);
|
|
228
|
+
process.exit(1);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
const instance = await require_server.createServer(fixtures, {
|
|
232
|
+
port,
|
|
233
|
+
host,
|
|
234
|
+
latency,
|
|
235
|
+
chunkSize,
|
|
236
|
+
logLevel,
|
|
237
|
+
chaos,
|
|
238
|
+
metrics: values.metrics,
|
|
239
|
+
record,
|
|
240
|
+
strict: values.strict
|
|
241
|
+
});
|
|
242
|
+
logger.info(`aimock server listening on ${instance.url}`);
|
|
243
|
+
let watcher = null;
|
|
244
|
+
if (watchMode) {
|
|
245
|
+
watcher = require_watcher.watchFixtures(fixturePath, fixtures, isDir ? () => require_fixture_loader.loadFixturesFromDir(fixturePath, logger) : () => require_fixture_loader.loadFixtureFile(fixturePath, logger), {
|
|
246
|
+
logger,
|
|
247
|
+
validate: validateOnLoad,
|
|
248
|
+
validateFn: require_fixture_loader.validateFixtures
|
|
249
|
+
});
|
|
250
|
+
logger.info(`Watching ${fixturePath} for changes`);
|
|
251
|
+
}
|
|
252
|
+
function shutdown() {
|
|
253
|
+
logger.info("Shutting down...");
|
|
254
|
+
if (watcher) watcher.close();
|
|
255
|
+
instance.server.close(() => {
|
|
256
|
+
process.exit(0);
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
process.on("SIGINT", shutdown);
|
|
260
|
+
process.on("SIGTERM", shutdown);
|
|
261
|
+
}
|
|
262
|
+
main().catch((err) => {
|
|
263
|
+
console.error(err);
|
|
264
|
+
process.exit(1);
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
//#endregion
|
|
268
|
+
//# sourceMappingURL=cli.cjs.map
|
package/dist/cli.cjs.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.cjs","names":["Logger","loadFixturesFromDir","loadFixtureFile","validateFixtures","createServer","watchFixtures"],"sources":["../src/cli.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { parseArgs } from \"node:util\";\nimport { statSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport { createServer } from \"./server.js\";\nimport { loadFixtureFile, loadFixturesFromDir, validateFixtures } from \"./fixture-loader.js\";\nimport { Logger, type LogLevel } from \"./logger.js\";\nimport { watchFixtures } from \"./watcher.js\";\nimport type { ChaosConfig, RecordConfig } from \"./types.js\";\n\nconst HELP = `\nUsage: llmock [options]\n\nOptions:\n -p, --port <number> Port to listen on (default: 4010)\n -h, --host <string> Host to bind to (default: 127.0.0.1)\n -f, --fixtures <path> Path to fixtures directory or file (default: ./fixtures)\n -l, --latency <ms> Latency in ms between SSE chunks (default: 0)\n -c, --chunk-size <chars> Chunk size in characters (default: 20)\n -w, --watch Watch fixture path for changes and reload\n --log-level <level> Log verbosity: silent, info, debug (default: info)\n --validate-on-load Validate fixture schemas at startup\n --metrics Enable Prometheus metrics at GET /metrics\n --record Record mode: proxy unmatched requests to real APIs\n --strict Strict mode: fail on unmatched requests\n --provider-openai <url> Upstream URL for OpenAI (used with --record)\n --provider-anthropic <url> Upstream URL for Anthropic\n --provider-gemini <url> Upstream URL for Gemini\n --provider-vertexai <url> Upstream URL for Vertex AI\n --provider-bedrock <url> Upstream URL for Bedrock\n --provider-azure <url> Upstream URL for Azure OpenAI\n --provider-ollama <url> Upstream URL for Ollama\n --provider-cohere <url> Upstream URL for Cohere\n --chaos-drop <rate> Probability (0-1) of dropping requests with 500\n --chaos-malformed <rate> Probability (0-1) of returning malformed JSON\n --chaos-disconnect <rate> Probability (0-1) of destroying connection\n --help Show this help message\n`.trim();\n\nconst { values } = parseArgs({\n options: {\n port: { type: \"string\", short: \"p\", default: \"4010\" },\n host: { type: \"string\", short: \"h\", default: \"127.0.0.1\" },\n fixtures: { type: \"string\", short: \"f\", default: \"./fixtures\" },\n latency: { type: \"string\", short: \"l\", default: \"0\" },\n \"chunk-size\": { type: \"string\", short: \"c\", default: \"20\" },\n watch: { type: \"boolean\", short: \"w\", default: false },\n \"log-level\": { type: \"string\", default: \"info\" },\n \"validate-on-load\": { type: \"boolean\", default: false },\n metrics: { type: \"boolean\", default: false },\n record: { type: \"boolean\", default: false },\n strict: { type: \"boolean\", default: false },\n \"provider-openai\": { type: \"string\" },\n \"provider-anthropic\": { type: \"string\" },\n \"provider-gemini\": { type: \"string\" },\n \"provider-vertexai\": { type: \"string\" },\n \"provider-bedrock\": { type: \"string\" },\n \"provider-azure\": { type: \"string\" },\n \"provider-ollama\": { type: \"string\" },\n \"provider-cohere\": { type: \"string\" },\n \"chaos-drop\": { type: \"string\" },\n \"chaos-malformed\": { type: \"string\" },\n \"chaos-disconnect\": { type: \"string\" },\n help: { type: \"boolean\", default: false },\n },\n strict: true,\n});\n\nif (values.help) {\n console.log(HELP);\n process.exit(0);\n}\n\nconst port = Number(values.port);\nconst host = values.host!;\nconst latency = Number(values.latency);\nconst chunkSize = Number(values[\"chunk-size\"]);\nconst fixturePath = resolve(values.fixtures!);\nconst watchMode = values.watch!;\nconst validateOnLoad = values[\"validate-on-load\"]!;\nconst logLevelStr = values[\"log-level\"]!;\n\nif (![\"silent\", \"info\", \"debug\"].includes(logLevelStr)) {\n console.error(`Invalid log-level: ${logLevelStr} (must be silent, info, or debug)`);\n process.exit(1);\n}\nconst logLevel = logLevelStr as LogLevel;\n\nif (Number.isNaN(port) || port < 0 || port > 65535) {\n console.error(`Invalid port: ${values.port}`);\n process.exit(1);\n}\n\nif (Number.isNaN(latency) || latency < 0) {\n console.error(`Invalid latency: ${values.latency}`);\n process.exit(1);\n}\n\nif (Number.isNaN(chunkSize) || chunkSize < 1) {\n console.error(`Invalid chunk-size: ${values[\"chunk-size\"]}`);\n process.exit(1);\n}\n\nconst logger = new Logger(logLevel);\n\n// Parse chaos config from CLI flags\nlet chaos: ChaosConfig | undefined;\n{\n const dropStr = values[\"chaos-drop\"];\n const malformedStr = values[\"chaos-malformed\"];\n const disconnectStr = values[\"chaos-disconnect\"];\n\n if (dropStr !== undefined || malformedStr !== undefined || disconnectStr !== undefined) {\n chaos = {};\n if (dropStr !== undefined) {\n const val = parseFloat(dropStr);\n if (isNaN(val) || val < 0 || val > 1) {\n console.error(`Invalid chaos-drop: ${dropStr} (must be 0-1)`);\n process.exit(1);\n }\n chaos.dropRate = val;\n }\n if (malformedStr !== undefined) {\n const val = parseFloat(malformedStr);\n if (isNaN(val) || val < 0 || val > 1) {\n console.error(`Invalid chaos-malformed: ${malformedStr} (must be 0-1)`);\n process.exit(1);\n }\n chaos.malformedRate = val;\n }\n if (disconnectStr !== undefined) {\n const val = parseFloat(disconnectStr);\n if (isNaN(val) || val < 0 || val > 1) {\n console.error(`Invalid chaos-disconnect: ${disconnectStr} (must be 0-1)`);\n process.exit(1);\n }\n chaos.disconnectRate = val;\n }\n }\n}\n\n// Parse record config from CLI flags\nlet record: RecordConfig | undefined;\nif (values.record) {\n const providers: RecordConfig[\"providers\"] = {};\n if (values[\"provider-openai\"]) providers.openai = values[\"provider-openai\"];\n if (values[\"provider-anthropic\"]) providers.anthropic = values[\"provider-anthropic\"];\n if (values[\"provider-gemini\"]) providers.gemini = values[\"provider-gemini\"];\n if (values[\"provider-vertexai\"]) providers.vertexai = values[\"provider-vertexai\"];\n if (values[\"provider-bedrock\"]) providers.bedrock = values[\"provider-bedrock\"];\n if (values[\"provider-azure\"]) providers.azure = values[\"provider-azure\"];\n if (values[\"provider-ollama\"]) providers.ollama = values[\"provider-ollama\"];\n if (values[\"provider-cohere\"]) providers.cohere = values[\"provider-cohere\"];\n\n if (Object.keys(providers).length === 0) {\n console.error(\"Error: --record requires at least one --provider-* flag\");\n process.exit(1);\n }\n\n record = { providers, fixturePath: resolve(fixturePath, \"recorded\") };\n}\n\nasync function main() {\n // Load fixtures from path (detect file vs directory)\n let isDir: boolean;\n let fixtures;\n try {\n const stat = statSync(fixturePath);\n isDir = stat.isDirectory();\n if (isDir) {\n fixtures = loadFixturesFromDir(fixturePath, logger);\n } else {\n fixtures = loadFixtureFile(fixturePath, logger);\n }\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === \"ENOENT\") {\n console.error(`Fixtures path not found: ${fixturePath}`);\n } else {\n const msg = err instanceof Error ? err.message : String(err);\n console.error(`Failed to load fixtures from ${fixturePath}: ${msg}`);\n }\n process.exit(1);\n }\n\n if (fixtures.length === 0) {\n if (validateOnLoad || values.strict) {\n console.error(\"Error: No fixtures loaded and validation/strict mode is enabled — aborting.\");\n process.exit(1);\n }\n console.warn(\"Warning: No fixtures loaded. The server will return 404 for all requests.\");\n }\n\n logger.info(`Loaded ${fixtures.length} fixture(s) from ${fixturePath}`);\n\n // Validate fixtures if requested\n if (validateOnLoad) {\n const results = validateFixtures(fixtures);\n const errors = results.filter((r) => r.severity === \"error\");\n const warnings = results.filter((r) => r.severity === \"warning\");\n\n for (const w of warnings) {\n logger.warn(`Fixture ${w.fixtureIndex}: ${w.message}`);\n }\n for (const e of errors) {\n logger.error(`Fixture ${e.fixtureIndex}: ${e.message}`);\n }\n\n if (errors.length > 0) {\n console.error(`Validation failed: ${errors.length} error(s), ${warnings.length} warning(s)`);\n process.exit(1);\n }\n }\n\n const instance = await createServer(fixtures, {\n port,\n host,\n latency,\n chunkSize,\n logLevel,\n chaos,\n metrics: values.metrics,\n record,\n strict: values.strict,\n });\n\n logger.info(`aimock server listening on ${instance.url}`);\n\n // Start file watcher if requested\n let watcher: { close: () => void } | null = null;\n if (watchMode) {\n const loadFn = isDir!\n ? () => loadFixturesFromDir(fixturePath, logger)\n : () => loadFixtureFile(fixturePath, logger);\n\n watcher = watchFixtures(fixturePath, fixtures, loadFn, {\n logger,\n validate: validateOnLoad,\n validateFn: validateFixtures,\n });\n logger.info(`Watching ${fixturePath} for changes`);\n }\n\n function shutdown() {\n logger.info(\"Shutting down...\");\n if (watcher) watcher.close();\n instance.server.close(() => {\n process.exit(0);\n });\n }\n\n process.on(\"SIGINT\", shutdown);\n process.on(\"SIGTERM\", shutdown);\n}\n\nmain().catch((err) => {\n console.error(err);\n process.exit(1);\n});\n"],"mappings":"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"}
|
package/dist/cli.d.cts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|