@copilotkit/aimock 1.37.4 → 1.39.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.
Files changed (175) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/CHANGELOG.md +48 -0
  4. package/README.md +50 -11
  5. package/dist/agui-handler.cjs +20 -18
  6. package/dist/agui-handler.cjs.map +1 -1
  7. package/dist/agui-handler.d.cts +8 -1
  8. package/dist/agui-handler.d.cts.map +1 -1
  9. package/dist/agui-handler.d.ts +8 -1
  10. package/dist/agui-handler.d.ts.map +1 -1
  11. package/dist/agui-handler.js +20 -18
  12. package/dist/agui-handler.js.map +1 -1
  13. package/dist/agui-recorder.cjs +6 -0
  14. package/dist/agui-recorder.cjs.map +1 -1
  15. package/dist/agui-recorder.d.cts.map +1 -1
  16. package/dist/agui-recorder.d.ts.map +1 -1
  17. package/dist/agui-recorder.js +6 -0
  18. package/dist/agui-recorder.js.map +1 -1
  19. package/dist/agui-stub.d.cts +2 -2
  20. package/dist/agui-stub.d.ts +2 -2
  21. package/dist/agui-types.d.cts +19 -1
  22. package/dist/agui-types.d.cts.map +1 -1
  23. package/dist/agui-types.d.ts +19 -1
  24. package/dist/agui-types.d.ts.map +1 -1
  25. package/dist/aimock-cli.cjs +1 -1
  26. package/dist/aimock-cli.cjs.map +1 -1
  27. package/dist/aimock-cli.js +1 -1
  28. package/dist/aimock-cli.js.map +1 -1
  29. package/dist/api-key-auth.cjs +166 -0
  30. package/dist/api-key-auth.cjs.map +1 -0
  31. package/dist/api-key-auth.d.cts +17 -0
  32. package/dist/api-key-auth.d.cts.map +1 -0
  33. package/dist/api-key-auth.d.ts +17 -0
  34. package/dist/api-key-auth.d.ts.map +1 -0
  35. package/dist/api-key-auth.js +158 -0
  36. package/dist/api-key-auth.js.map +1 -0
  37. package/dist/cli.cjs +14 -11
  38. package/dist/cli.cjs.map +1 -1
  39. package/dist/cli.js +14 -11
  40. package/dist/cli.js.map +1 -1
  41. package/dist/config-loader.cjs +4 -2
  42. package/dist/config-loader.cjs.map +1 -1
  43. package/dist/config-loader.d.cts +2 -1
  44. package/dist/config-loader.d.cts.map +1 -1
  45. package/dist/config-loader.d.ts +2 -1
  46. package/dist/config-loader.d.ts.map +1 -1
  47. package/dist/config-loader.js +5 -3
  48. package/dist/config-loader.js.map +1 -1
  49. package/dist/fal-audio.cjs +2 -0
  50. package/dist/fal-audio.cjs.map +1 -1
  51. package/dist/fal-audio.d.cts.map +1 -1
  52. package/dist/fal-audio.d.ts.map +1 -1
  53. package/dist/fal-audio.js +2 -0
  54. package/dist/fal-audio.js.map +1 -1
  55. package/dist/fal.cjs +4 -1
  56. package/dist/fal.cjs.map +1 -1
  57. package/dist/fal.d.cts.map +1 -1
  58. package/dist/fal.d.ts.map +1 -1
  59. package/dist/fal.js +4 -1
  60. package/dist/fal.js.map +1 -1
  61. package/dist/fixture-loader.cjs +0 -0
  62. package/dist/fixture-loader.cjs.map +1 -1
  63. package/dist/fixture-loader.d.cts +3 -1
  64. package/dist/fixture-loader.d.cts.map +1 -1
  65. package/dist/fixture-loader.d.ts +3 -1
  66. package/dist/fixture-loader.d.ts.map +1 -1
  67. package/dist/fixture-loader.js +0 -0
  68. package/dist/fixture-loader.js.map +1 -1
  69. package/dist/grok-video.cjs +9 -2
  70. package/dist/grok-video.cjs.map +1 -1
  71. package/dist/grok-video.js +10 -3
  72. package/dist/grok-video.js.map +1 -1
  73. package/dist/helpers.cjs +16 -22
  74. package/dist/helpers.cjs.map +1 -1
  75. package/dist/helpers.d.cts.map +1 -1
  76. package/dist/helpers.d.ts.map +1 -1
  77. package/dist/helpers.js +16 -21
  78. package/dist/helpers.js.map +1 -1
  79. package/dist/index.d.cts +3 -3
  80. package/dist/index.d.ts +3 -3
  81. package/dist/llmock.cjs +37 -12
  82. package/dist/llmock.cjs.map +1 -1
  83. package/dist/llmock.d.cts +26 -2
  84. package/dist/llmock.d.cts.map +1 -1
  85. package/dist/llmock.d.ts +26 -2
  86. package/dist/llmock.d.ts.map +1 -1
  87. package/dist/llmock.js +39 -15
  88. package/dist/llmock.js.map +1 -1
  89. package/dist/openrouter-chat.cjs +333 -0
  90. package/dist/openrouter-chat.cjs.map +1 -0
  91. package/dist/openrouter-chat.js +325 -0
  92. package/dist/openrouter-chat.js.map +1 -0
  93. package/dist/openrouter-video.cjs +24 -7
  94. package/dist/openrouter-video.cjs.map +1 -1
  95. package/dist/openrouter-video.d.cts.map +1 -1
  96. package/dist/openrouter-video.d.ts.map +1 -1
  97. package/dist/openrouter-video.js +25 -8
  98. package/dist/openrouter-video.js.map +1 -1
  99. package/dist/provider-auth.cjs +20 -0
  100. package/dist/provider-auth.cjs.map +1 -1
  101. package/dist/provider-auth.js +20 -1
  102. package/dist/provider-auth.js.map +1 -1
  103. package/dist/recorder.cjs +50 -8
  104. package/dist/recorder.cjs.map +1 -1
  105. package/dist/recorder.d.cts.map +1 -1
  106. package/dist/recorder.d.ts.map +1 -1
  107. package/dist/recorder.js +50 -10
  108. package/dist/recorder.js.map +1 -1
  109. package/dist/responses.cjs +200 -89
  110. package/dist/responses.cjs.map +1 -1
  111. package/dist/responses.d.cts +18 -3
  112. package/dist/responses.d.cts.map +1 -1
  113. package/dist/responses.d.ts +18 -3
  114. package/dist/responses.d.ts.map +1 -1
  115. package/dist/responses.js +199 -90
  116. package/dist/responses.js.map +1 -1
  117. package/dist/server.cjs +190 -83
  118. package/dist/server.cjs.map +1 -1
  119. package/dist/server.d.cts +7 -2
  120. package/dist/server.d.cts.map +1 -1
  121. package/dist/server.d.ts +7 -2
  122. package/dist/server.d.ts.map +1 -1
  123. package/dist/server.js +190 -85
  124. package/dist/server.js.map +1 -1
  125. package/dist/sse-writer.cjs +3 -0
  126. package/dist/sse-writer.cjs.map +1 -1
  127. package/dist/sse-writer.d.cts +8 -0
  128. package/dist/sse-writer.d.cts.map +1 -1
  129. package/dist/sse-writer.d.ts +8 -0
  130. package/dist/sse-writer.d.ts.map +1 -1
  131. package/dist/sse-writer.js +3 -0
  132. package/dist/sse-writer.js.map +1 -1
  133. package/dist/stream-collapse.cjs +103 -0
  134. package/dist/stream-collapse.cjs.map +1 -1
  135. package/dist/stream-collapse.d.cts +7 -0
  136. package/dist/stream-collapse.d.cts.map +1 -1
  137. package/dist/stream-collapse.d.ts +7 -0
  138. package/dist/stream-collapse.d.ts.map +1 -1
  139. package/dist/stream-collapse.js +103 -0
  140. package/dist/stream-collapse.js.map +1 -1
  141. package/dist/transcription.cjs +49 -2
  142. package/dist/transcription.cjs.map +1 -1
  143. package/dist/transcription.d.cts.map +1 -1
  144. package/dist/transcription.d.ts.map +1 -1
  145. package/dist/transcription.js +50 -3
  146. package/dist/transcription.js.map +1 -1
  147. package/dist/types.d.cts +187 -5
  148. package/dist/types.d.cts.map +1 -1
  149. package/dist/types.d.ts +187 -5
  150. package/dist/types.d.ts.map +1 -1
  151. package/dist/vector-types.d.ts.map +1 -1
  152. package/dist/veo-video.cjs +9 -2
  153. package/dist/veo-video.cjs.map +1 -1
  154. package/dist/veo-video.js +10 -3
  155. package/dist/veo-video.js.map +1 -1
  156. package/dist/ws-gemini-live.cjs +41 -6
  157. package/dist/ws-gemini-live.cjs.map +1 -1
  158. package/dist/ws-gemini-live.js +41 -6
  159. package/dist/ws-gemini-live.js.map +1 -1
  160. package/dist/ws-realtime.cjs +306 -57
  161. package/dist/ws-realtime.cjs.map +1 -1
  162. package/dist/ws-realtime.d.cts +1 -0
  163. package/dist/ws-realtime.d.cts.map +1 -1
  164. package/dist/ws-realtime.d.ts +1 -0
  165. package/dist/ws-realtime.d.ts.map +1 -1
  166. package/dist/ws-realtime.js +307 -58
  167. package/dist/ws-realtime.js.map +1 -1
  168. package/dist/ws-responses.cjs +11 -6
  169. package/dist/ws-responses.cjs.map +1 -1
  170. package/dist/ws-responses.d.cts.map +1 -1
  171. package/dist/ws-responses.d.ts.map +1 -1
  172. package/dist/ws-responses.js +12 -7
  173. package/dist/ws-responses.js.map +1 -1
  174. package/package.json +3 -2
  175. package/skills/write-fixtures/SKILL.md +53 -19
@@ -18,11 +18,13 @@ interface AGUIRunFinishedEvent extends AGUIBaseEvent {
18
18
  runId: string;
19
19
  result?: unknown;
20
20
  outcome?: AGUIRunFinishedOutcome;
21
+ usage?: AGUITokenUsage[];
21
22
  }
22
23
  interface AGUIRunErrorEvent extends AGUIBaseEvent {
23
24
  type: "RUN_ERROR";
24
25
  message: string;
25
26
  code?: string;
27
+ usage?: AGUITokenUsage[];
26
28
  }
27
29
  interface AGUIStepStartedEvent extends AGUIBaseEvent {
28
30
  type: "STEP_STARTED";
@@ -192,6 +194,22 @@ type AGUIRunFinishedOutcome = {
192
194
  type: "interrupt";
193
195
  interrupts: AGUIInterrupt[];
194
196
  };
197
+ /**
198
+ * Numeric-only token usage summary, mirroring `TokenUsageSchema` in
199
+ * `@ag-ui/core`. Deliberately carries no content-bearing or identifying
200
+ * fields — only provider/model labels and non-negative integer token counts.
201
+ * Carried as an array on RUN_FINISHED / RUN_ERROR so a run that invokes
202
+ * multiple models keeps them separate.
203
+ */
204
+ interface AGUITokenUsage {
205
+ provider?: string;
206
+ model?: string;
207
+ inputTokens?: number;
208
+ outputTokens?: number;
209
+ totalTokens?: number;
210
+ reasoningTokens?: number;
211
+ cachedInputTokens?: number;
212
+ }
195
213
  interface AGUIRunAgentInput {
196
214
  threadId: string;
197
215
  runId: string;
@@ -275,5 +293,5 @@ interface AGUIRecordConfig {
275
293
  }
276
294
  //# sourceMappingURL=agui-types.d.ts.map
277
295
  //#endregion
278
- export { AGUIActivityDeltaEvent, AGUIActivitySnapshotEvent, AGUIBaseEvent, AGUICustomEvent, AGUIEvent, AGUIEventType, AGUIFixture, AGUIFixtureMatch, AGUIInterrupt, AGUIMessage, AGUIMessageContentPart, AGUIMessageRole, AGUIMessagesSnapshotEvent, AGUIMockOptions, AGUIRawEvent, AGUIReasoningEncryptedValueEvent, AGUIReasoningEncryptedValueSubtype, AGUIReasoningEndEvent, AGUIReasoningMessageChunkEvent, AGUIReasoningMessageContentEvent, AGUIReasoningMessageEndEvent, AGUIReasoningMessageStartEvent, AGUIReasoningStartEvent, AGUIRecordConfig, AGUIResumeEntry, AGUIRunAgentInput, AGUIRunErrorEvent, AGUIRunFinishedEvent, AGUIRunFinishedOutcome, AGUIRunStartedEvent, AGUIStateDeltaEvent, AGUIStateSnapshotEvent, AGUIStepFinishedEvent, AGUIStepStartedEvent, AGUITextMessageChunkEvent, AGUITextMessageContentEvent, AGUITextMessageEndEvent, AGUITextMessageRole, AGUITextMessageStartEvent, AGUIThinkingEndEvent, AGUIThinkingStartEvent, AGUIThinkingTextMessageContentEvent, AGUIThinkingTextMessageEndEvent, AGUIThinkingTextMessageStartEvent, AGUIToolCall, AGUIToolCallArgsEvent, AGUIToolCallChunkEvent, AGUIToolCallEndEvent, AGUIToolCallResultEvent, AGUIToolCallStartEvent, AGUIToolDefinition };
296
+ export { AGUIActivityDeltaEvent, AGUIActivitySnapshotEvent, AGUIBaseEvent, AGUICustomEvent, AGUIEvent, AGUIEventType, AGUIFixture, AGUIFixtureMatch, AGUIInterrupt, AGUIMessage, AGUIMessageContentPart, AGUIMessageRole, AGUIMessagesSnapshotEvent, AGUIMockOptions, AGUIRawEvent, AGUIReasoningEncryptedValueEvent, AGUIReasoningEncryptedValueSubtype, AGUIReasoningEndEvent, AGUIReasoningMessageChunkEvent, AGUIReasoningMessageContentEvent, AGUIReasoningMessageEndEvent, AGUIReasoningMessageStartEvent, AGUIReasoningStartEvent, AGUIRecordConfig, AGUIResumeEntry, AGUIRunAgentInput, AGUIRunErrorEvent, AGUIRunFinishedEvent, AGUIRunFinishedOutcome, AGUIRunStartedEvent, AGUIStateDeltaEvent, AGUIStateSnapshotEvent, AGUIStepFinishedEvent, AGUIStepStartedEvent, AGUITextMessageChunkEvent, AGUITextMessageContentEvent, AGUITextMessageEndEvent, AGUITextMessageRole, AGUITextMessageStartEvent, AGUIThinkingEndEvent, AGUIThinkingStartEvent, AGUIThinkingTextMessageContentEvent, AGUIThinkingTextMessageEndEvent, AGUIThinkingTextMessageStartEvent, AGUITokenUsage, AGUIToolCall, AGUIToolCallArgsEvent, AGUIToolCallChunkEvent, AGUIToolCallEndEvent, AGUIToolCallResultEvent, AGUIToolCallStartEvent, AGUIToolDefinition };
279
297
  //# sourceMappingURL=agui-types.d.cts.map
@@ -1 +1 @@
1
- {"version":3,"file":"agui-types.d.cts","names":[],"sources":["../src/agui-types.ts"],"sourcesContent":[],"mappings":"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"}
1
+ {"version":3,"file":"agui-types.d.cts","names":[],"sources":["../src/agui-types.ts"],"sourcesContent":[],"mappings":"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"}
@@ -18,11 +18,13 @@ interface AGUIRunFinishedEvent extends AGUIBaseEvent {
18
18
  runId: string;
19
19
  result?: unknown;
20
20
  outcome?: AGUIRunFinishedOutcome;
21
+ usage?: AGUITokenUsage[];
21
22
  }
22
23
  interface AGUIRunErrorEvent extends AGUIBaseEvent {
23
24
  type: "RUN_ERROR";
24
25
  message: string;
25
26
  code?: string;
27
+ usage?: AGUITokenUsage[];
26
28
  }
27
29
  interface AGUIStepStartedEvent extends AGUIBaseEvent {
28
30
  type: "STEP_STARTED";
@@ -192,6 +194,22 @@ type AGUIRunFinishedOutcome = {
192
194
  type: "interrupt";
193
195
  interrupts: AGUIInterrupt[];
194
196
  };
197
+ /**
198
+ * Numeric-only token usage summary, mirroring `TokenUsageSchema` in
199
+ * `@ag-ui/core`. Deliberately carries no content-bearing or identifying
200
+ * fields — only provider/model labels and non-negative integer token counts.
201
+ * Carried as an array on RUN_FINISHED / RUN_ERROR so a run that invokes
202
+ * multiple models keeps them separate.
203
+ */
204
+ interface AGUITokenUsage {
205
+ provider?: string;
206
+ model?: string;
207
+ inputTokens?: number;
208
+ outputTokens?: number;
209
+ totalTokens?: number;
210
+ reasoningTokens?: number;
211
+ cachedInputTokens?: number;
212
+ }
195
213
  interface AGUIRunAgentInput {
196
214
  threadId: string;
197
215
  runId: string;
@@ -275,5 +293,5 @@ interface AGUIRecordConfig {
275
293
  }
276
294
  //# sourceMappingURL=agui-types.d.ts.map
277
295
  //#endregion
278
- export { AGUIActivityDeltaEvent, AGUIActivitySnapshotEvent, AGUIBaseEvent, AGUICustomEvent, AGUIEvent, AGUIEventType, AGUIFixture, AGUIFixtureMatch, AGUIInterrupt, AGUIMessage, AGUIMessageContentPart, AGUIMessageRole, AGUIMessagesSnapshotEvent, AGUIMockOptions, AGUIRawEvent, AGUIReasoningEncryptedValueEvent, AGUIReasoningEncryptedValueSubtype, AGUIReasoningEndEvent, AGUIReasoningMessageChunkEvent, AGUIReasoningMessageContentEvent, AGUIReasoningMessageEndEvent, AGUIReasoningMessageStartEvent, AGUIReasoningStartEvent, AGUIRecordConfig, AGUIResumeEntry, AGUIRunAgentInput, AGUIRunErrorEvent, AGUIRunFinishedEvent, AGUIRunFinishedOutcome, AGUIRunStartedEvent, AGUIStateDeltaEvent, AGUIStateSnapshotEvent, AGUIStepFinishedEvent, AGUIStepStartedEvent, AGUITextMessageChunkEvent, AGUITextMessageContentEvent, AGUITextMessageEndEvent, AGUITextMessageRole, AGUITextMessageStartEvent, AGUIThinkingEndEvent, AGUIThinkingStartEvent, AGUIThinkingTextMessageContentEvent, AGUIThinkingTextMessageEndEvent, AGUIThinkingTextMessageStartEvent, AGUIToolCall, AGUIToolCallArgsEvent, AGUIToolCallChunkEvent, AGUIToolCallEndEvent, AGUIToolCallResultEvent, AGUIToolCallStartEvent, AGUIToolDefinition };
296
+ export { AGUIActivityDeltaEvent, AGUIActivitySnapshotEvent, AGUIBaseEvent, AGUICustomEvent, AGUIEvent, AGUIEventType, AGUIFixture, AGUIFixtureMatch, AGUIInterrupt, AGUIMessage, AGUIMessageContentPart, AGUIMessageRole, AGUIMessagesSnapshotEvent, AGUIMockOptions, AGUIRawEvent, AGUIReasoningEncryptedValueEvent, AGUIReasoningEncryptedValueSubtype, AGUIReasoningEndEvent, AGUIReasoningMessageChunkEvent, AGUIReasoningMessageContentEvent, AGUIReasoningMessageEndEvent, AGUIReasoningMessageStartEvent, AGUIReasoningStartEvent, AGUIRecordConfig, AGUIResumeEntry, AGUIRunAgentInput, AGUIRunErrorEvent, AGUIRunFinishedEvent, AGUIRunFinishedOutcome, AGUIRunStartedEvent, AGUIStateDeltaEvent, AGUIStateSnapshotEvent, AGUIStepFinishedEvent, AGUIStepStartedEvent, AGUITextMessageChunkEvent, AGUITextMessageContentEvent, AGUITextMessageEndEvent, AGUITextMessageRole, AGUITextMessageStartEvent, AGUIThinkingEndEvent, AGUIThinkingStartEvent, AGUIThinkingTextMessageContentEvent, AGUIThinkingTextMessageEndEvent, AGUIThinkingTextMessageStartEvent, AGUITokenUsage, AGUIToolCall, AGUIToolCallArgsEvent, AGUIToolCallChunkEvent, AGUIToolCallEndEvent, AGUIToolCallResultEvent, AGUIToolCallStartEvent, AGUIToolDefinition };
279
297
  //# sourceMappingURL=agui-types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"agui-types.d.ts","names":[],"sources":["../src/agui-types.ts"],"sourcesContent":[],"mappings":"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"}
1
+ {"version":3,"file":"agui-types.d.ts","names":[],"sources":["../src/agui-types.ts"],"sourcesContent":[],"mappings":"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"}
@@ -99,7 +99,6 @@ function runAimockCli(deps = {}) {
99
99
  port,
100
100
  host
101
101
  });
102
- log(`aimock server listening on ${url}`);
103
102
  function shutdown() {
104
103
  log("Shutting down...");
105
104
  process.removeListener("SIGINT", shutdown);
@@ -111,6 +110,7 @@ function runAimockCli(deps = {}) {
111
110
  }
112
111
  process.on("SIGINT", shutdown);
113
112
  process.on("SIGTERM", shutdown);
113
+ log(`aimock server listening on ${url}`);
114
114
  if (deps.onReady) deps.onReady({ shutdown });
115
115
  }
116
116
  main().catch((err) => {
@@ -1 +1 @@
1
- {"version":3,"file":"aimock-cli.cjs","names":["loadConfig","startFromConfig"],"sources":["../src/aimock-cli.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { parseArgs } from \"node:util\";\nimport { resolve, basename } from \"node:path\";\nimport { loadConfig, startFromConfig } from \"./config-loader.js\";\nimport { runConvertCli, type ConvertCliDeps } from \"./convert.js\";\n\nconst HELP = `\nUsage: aimock [options]\n aimock convert <format> <input> [output]\n\nOptions:\n -c, --config <path> Path to aimock config JSON file (required)\n -p, --port <number> Port override (default: from config or 0)\n -h, --host <string> Host override (default: from config or 127.0.0.1)\n --help Show this help message\n\nSubcommands:\n convert Convert third-party mock configs to aimock format\n Run \"aimock convert --help\" for details\n`.trim();\n\nexport interface AimockCliDeps {\n argv?: string[];\n log?: (msg: string) => void;\n logError?: (msg: string) => void;\n exit?: (code: number) => void;\n loadConfigFn?: typeof loadConfig;\n startFromConfigFn?: typeof startFromConfig;\n onReady?: (ctx: { shutdown: () => void }) => void;\n convertDeps?: Partial<ConvertCliDeps>;\n}\n\nexport function runAimockCli(deps: AimockCliDeps = {}): void {\n /* v8 ignore next 6 -- defaults used only when called from CLI entry point */\n const argv = deps.argv ?? process.argv.slice(2);\n const log = deps.log ?? console.log.bind(console);\n const logError = deps.logError ?? console.error.bind(console);\n const exit = deps.exit ?? process.exit.bind(process);\n const loadConfigFn = deps.loadConfigFn ?? loadConfig;\n const startFromConfigFn = deps.startFromConfigFn ?? startFromConfig;\n\n // Intercept \"convert\" subcommand before parseArgs (which uses strict mode)\n if (argv[0] === \"convert\") {\n runConvertCli({\n argv: argv.slice(1),\n log,\n logError,\n exit,\n ...deps.convertDeps,\n });\n return;\n }\n\n let values;\n try {\n ({ values } = parseArgs({\n args: argv,\n options: {\n config: { type: \"string\", short: \"c\" },\n port: { type: \"string\", short: \"p\" },\n host: { type: \"string\", short: \"h\" },\n help: { type: \"boolean\", default: false },\n },\n strict: true,\n }));\n } catch (err) {\n /* v8 ignore next -- parseArgs always throws Error subclasses */\n const msg = err instanceof Error ? err.message : String(err);\n logError(`Error: ${msg}\\n\\n${HELP}`);\n exit(1);\n return;\n }\n\n if (values.help) {\n log(HELP);\n exit(0);\n return;\n }\n if (!values.config) {\n logError(\"Error: --config is required.\\n\\n\" + HELP);\n exit(1);\n return;\n }\n\n const configPath = resolve(values.config);\n let config;\n try {\n config = loadConfigFn(configPath);\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n logError(`Failed to load config from ${configPath}: ${msg}`);\n exit(1);\n return;\n }\n\n const port = values.port ? Number(values.port) : undefined;\n if (\n port !== undefined &&\n (Number.isNaN(port) || !Number.isInteger(port) || port < 0 || port > 65535)\n ) {\n logError(`Error: invalid port \"${values.port}\".\\n\\n${HELP}`);\n exit(1);\n return;\n }\n const host = values.host;\n\n async function main() {\n const { llmock, url } = await startFromConfigFn(config!, { port, host });\n log(`aimock server listening on ${url}`);\n\n function shutdown() {\n log(\"Shutting down...\");\n process.removeListener(\"SIGINT\", shutdown);\n process.removeListener(\"SIGTERM\", shutdown);\n llmock.stop().then(\n () => exit(0),\n (err) => {\n logError(`Shutdown error: ${err instanceof Error ? err.message : String(err)}`);\n exit(1);\n },\n );\n }\n process.on(\"SIGINT\", shutdown);\n process.on(\"SIGTERM\", shutdown);\n\n if (deps.onReady) {\n deps.onReady({ shutdown });\n }\n }\n\n main().catch((err) => {\n logError(err instanceof Error ? err.message : String(err));\n exit(1);\n });\n}\n\n// Run when executed as a script (not when imported for testing).\n/* v8 ignore start -- entry-point guard, exercised by integration tests */\nconst scriptName = process.argv[1] ?? \"\";\nconst base = basename(scriptName);\nif (base === \"aimock\" || base === \"aimock-cli.js\" || base === \"aimock-cli.ts\") {\n runAimockCli();\n}\n/* v8 ignore stop */\n"],"mappings":";;;;;;;;;AAMA,MAAM,OAAO;;;;;;;;;;;;;EAaX,MAAM;AAaR,SAAgB,aAAa,OAAsB,EAAE,EAAQ;;CAE3D,MAAM,OAAO,KAAK,QAAQ,QAAQ,KAAK,MAAM,EAAE;CAC/C,MAAM,MAAM,KAAK,OAAO,QAAQ,IAAI,KAAK,QAAQ;CACjD,MAAM,WAAW,KAAK,YAAY,QAAQ,MAAM,KAAK,QAAQ;CAC7D,MAAM,OAAO,KAAK,QAAQ,QAAQ,KAAK,KAAK,QAAQ;CACpD,MAAM,eAAe,KAAK,gBAAgBA;CAC1C,MAAM,oBAAoB,KAAK,qBAAqBC;AAGpD,KAAI,KAAK,OAAO,WAAW;AACzB,gCAAc;GACZ,MAAM,KAAK,MAAM,EAAE;GACnB;GACA;GACA;GACA,GAAG,KAAK;GACT,CAAC;AACF;;CAGF,IAAI;AACJ,KAAI;AACF,GAAC,CAAE,mCAAqB;GACtB,MAAM;GACN,SAAS;IACP,QAAQ;KAAE,MAAM;KAAU,OAAO;KAAK;IACtC,MAAM;KAAE,MAAM;KAAU,OAAO;KAAK;IACpC,MAAM;KAAE,MAAM;KAAU,OAAO;KAAK;IACpC,MAAM;KAAE,MAAM;KAAW,SAAS;KAAO;IAC1C;GACD,QAAQ;GACT,CAAC;UACK,KAAK;AAGZ,WAAS,UADG,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI,CACrC,MAAM,OAAO;AACpC,OAAK,EAAE;AACP;;AAGF,KAAI,OAAO,MAAM;AACf,MAAI,KAAK;AACT,OAAK,EAAE;AACP;;AAEF,KAAI,CAAC,OAAO,QAAQ;AAClB,WAAS,qCAAqC,KAAK;AACnD,OAAK,EAAE;AACP;;CAGF,MAAM,oCAAqB,OAAO,OAAO;CACzC,IAAI;AACJ,KAAI;AACF,WAAS,aAAa,WAAW;UAC1B,KAAK;AAEZ,WAAS,8BAA8B,WAAW,IADtC,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI,GACA;AAC5D,OAAK,EAAE;AACP;;CAGF,MAAM,OAAO,OAAO,OAAO,OAAO,OAAO,KAAK,GAAG;AACjD,KACE,SAAS,WACR,OAAO,MAAM,KAAK,IAAI,CAAC,OAAO,UAAU,KAAK,IAAI,OAAO,KAAK,OAAO,QACrE;AACA,WAAS,wBAAwB,OAAO,KAAK,QAAQ,OAAO;AAC5D,OAAK,EAAE;AACP;;CAEF,MAAM,OAAO,OAAO;CAEpB,eAAe,OAAO;EACpB,MAAM,EAAE,QAAQ,QAAQ,MAAM,kBAAkB,QAAS;GAAE;GAAM;GAAM,CAAC;AACxE,MAAI,8BAA8B,MAAM;EAExC,SAAS,WAAW;AAClB,OAAI,mBAAmB;AACvB,WAAQ,eAAe,UAAU,SAAS;AAC1C,WAAQ,eAAe,WAAW,SAAS;AAC3C,UAAO,MAAM,CAAC,WACN,KAAK,EAAE,GACZ,QAAQ;AACP,aAAS,mBAAmB,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI,GAAG;AAC/E,SAAK,EAAE;KAEV;;AAEH,UAAQ,GAAG,UAAU,SAAS;AAC9B,UAAQ,GAAG,WAAW,SAAS;AAE/B,MAAI,KAAK,QACP,MAAK,QAAQ,EAAE,UAAU,CAAC;;AAI9B,OAAM,CAAC,OAAO,QAAQ;AACpB,WAAS,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI,CAAC;AAC1D,OAAK,EAAE;GACP;;AAMJ,MAAM,+BADa,QAAQ,KAAK,MAAM,GACL;AACjC,IAAI,SAAS,YAAY,SAAS,mBAAmB,SAAS,gBAC5D,eAAc"}
1
+ {"version":3,"file":"aimock-cli.cjs","names":["loadConfig","startFromConfig"],"sources":["../src/aimock-cli.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { parseArgs } from \"node:util\";\nimport { resolve, basename } from \"node:path\";\nimport { loadConfig, startFromConfig } from \"./config-loader.js\";\nimport { runConvertCli, type ConvertCliDeps } from \"./convert.js\";\n\nconst HELP = `\nUsage: aimock [options]\n aimock convert <format> <input> [output]\n\nOptions:\n -c, --config <path> Path to aimock config JSON file (required)\n -p, --port <number> Port override (default: from config or 0)\n -h, --host <string> Host override (default: from config or 127.0.0.1)\n --help Show this help message\n\nSubcommands:\n convert Convert third-party mock configs to aimock format\n Run \"aimock convert --help\" for details\n`.trim();\n\nexport interface AimockCliDeps {\n argv?: string[];\n log?: (msg: string) => void;\n logError?: (msg: string) => void;\n exit?: (code: number) => void;\n loadConfigFn?: typeof loadConfig;\n startFromConfigFn?: typeof startFromConfig;\n onReady?: (ctx: { shutdown: () => void }) => void;\n convertDeps?: Partial<ConvertCliDeps>;\n}\n\nexport function runAimockCli(deps: AimockCliDeps = {}): void {\n /* v8 ignore next 6 -- defaults used only when called from CLI entry point */\n const argv = deps.argv ?? process.argv.slice(2);\n const log = deps.log ?? console.log.bind(console);\n const logError = deps.logError ?? console.error.bind(console);\n const exit = deps.exit ?? process.exit.bind(process);\n const loadConfigFn = deps.loadConfigFn ?? loadConfig;\n const startFromConfigFn = deps.startFromConfigFn ?? startFromConfig;\n\n // Intercept \"convert\" subcommand before parseArgs (which uses strict mode)\n if (argv[0] === \"convert\") {\n runConvertCli({\n argv: argv.slice(1),\n log,\n logError,\n exit,\n ...deps.convertDeps,\n });\n return;\n }\n\n let values;\n try {\n ({ values } = parseArgs({\n args: argv,\n options: {\n config: { type: \"string\", short: \"c\" },\n port: { type: \"string\", short: \"p\" },\n host: { type: \"string\", short: \"h\" },\n help: { type: \"boolean\", default: false },\n },\n strict: true,\n }));\n } catch (err) {\n /* v8 ignore next -- parseArgs always throws Error subclasses */\n const msg = err instanceof Error ? err.message : String(err);\n logError(`Error: ${msg}\\n\\n${HELP}`);\n exit(1);\n return;\n }\n\n if (values.help) {\n log(HELP);\n exit(0);\n return;\n }\n if (!values.config) {\n logError(\"Error: --config is required.\\n\\n\" + HELP);\n exit(1);\n return;\n }\n\n const configPath = resolve(values.config);\n let config;\n try {\n config = loadConfigFn(configPath);\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n logError(`Failed to load config from ${configPath}: ${msg}`);\n exit(1);\n return;\n }\n\n const port = values.port ? Number(values.port) : undefined;\n if (\n port !== undefined &&\n (Number.isNaN(port) || !Number.isInteger(port) || port < 0 || port > 65535)\n ) {\n logError(`Error: invalid port \"${values.port}\".\\n\\n${HELP}`);\n exit(1);\n return;\n }\n const host = values.host;\n\n async function main() {\n const { llmock, url } = await startFromConfigFn(config!, { port, host });\n\n function shutdown() {\n log(\"Shutting down...\");\n process.removeListener(\"SIGINT\", shutdown);\n process.removeListener(\"SIGTERM\", shutdown);\n llmock.stop().then(\n () => exit(0),\n (err) => {\n logError(`Shutdown error: ${err instanceof Error ? err.message : String(err)}`);\n exit(1);\n },\n );\n }\n // Register BEFORE announcing readiness — see the note in src/cli.ts. A supervisor\n // that reacts to the readiness line must never win a race against this listener.\n process.on(\"SIGINT\", shutdown);\n process.on(\"SIGTERM\", shutdown);\n\n log(`aimock server listening on ${url}`);\n\n if (deps.onReady) {\n deps.onReady({ shutdown });\n }\n }\n\n main().catch((err) => {\n logError(err instanceof Error ? err.message : String(err));\n exit(1);\n });\n}\n\n// Run when executed as a script (not when imported for testing).\n/* v8 ignore start -- entry-point guard, exercised by integration tests */\nconst scriptName = process.argv[1] ?? \"\";\nconst base = basename(scriptName);\nif (base === \"aimock\" || base === \"aimock-cli.js\" || base === \"aimock-cli.ts\") {\n runAimockCli();\n}\n/* v8 ignore stop */\n"],"mappings":";;;;;;;;;AAMA,MAAM,OAAO;;;;;;;;;;;;;EAaX,MAAM;AAaR,SAAgB,aAAa,OAAsB,EAAE,EAAQ;;CAE3D,MAAM,OAAO,KAAK,QAAQ,QAAQ,KAAK,MAAM,EAAE;CAC/C,MAAM,MAAM,KAAK,OAAO,QAAQ,IAAI,KAAK,QAAQ;CACjD,MAAM,WAAW,KAAK,YAAY,QAAQ,MAAM,KAAK,QAAQ;CAC7D,MAAM,OAAO,KAAK,QAAQ,QAAQ,KAAK,KAAK,QAAQ;CACpD,MAAM,eAAe,KAAK,gBAAgBA;CAC1C,MAAM,oBAAoB,KAAK,qBAAqBC;AAGpD,KAAI,KAAK,OAAO,WAAW;AACzB,gCAAc;GACZ,MAAM,KAAK,MAAM,EAAE;GACnB;GACA;GACA;GACA,GAAG,KAAK;GACT,CAAC;AACF;;CAGF,IAAI;AACJ,KAAI;AACF,GAAC,CAAE,mCAAqB;GACtB,MAAM;GACN,SAAS;IACP,QAAQ;KAAE,MAAM;KAAU,OAAO;KAAK;IACtC,MAAM;KAAE,MAAM;KAAU,OAAO;KAAK;IACpC,MAAM;KAAE,MAAM;KAAU,OAAO;KAAK;IACpC,MAAM;KAAE,MAAM;KAAW,SAAS;KAAO;IAC1C;GACD,QAAQ;GACT,CAAC;UACK,KAAK;AAGZ,WAAS,UADG,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI,CACrC,MAAM,OAAO;AACpC,OAAK,EAAE;AACP;;AAGF,KAAI,OAAO,MAAM;AACf,MAAI,KAAK;AACT,OAAK,EAAE;AACP;;AAEF,KAAI,CAAC,OAAO,QAAQ;AAClB,WAAS,qCAAqC,KAAK;AACnD,OAAK,EAAE;AACP;;CAGF,MAAM,oCAAqB,OAAO,OAAO;CACzC,IAAI;AACJ,KAAI;AACF,WAAS,aAAa,WAAW;UAC1B,KAAK;AAEZ,WAAS,8BAA8B,WAAW,IADtC,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI,GACA;AAC5D,OAAK,EAAE;AACP;;CAGF,MAAM,OAAO,OAAO,OAAO,OAAO,OAAO,KAAK,GAAG;AACjD,KACE,SAAS,WACR,OAAO,MAAM,KAAK,IAAI,CAAC,OAAO,UAAU,KAAK,IAAI,OAAO,KAAK,OAAO,QACrE;AACA,WAAS,wBAAwB,OAAO,KAAK,QAAQ,OAAO;AAC5D,OAAK,EAAE;AACP;;CAEF,MAAM,OAAO,OAAO;CAEpB,eAAe,OAAO;EACpB,MAAM,EAAE,QAAQ,QAAQ,MAAM,kBAAkB,QAAS;GAAE;GAAM;GAAM,CAAC;EAExE,SAAS,WAAW;AAClB,OAAI,mBAAmB;AACvB,WAAQ,eAAe,UAAU,SAAS;AAC1C,WAAQ,eAAe,WAAW,SAAS;AAC3C,UAAO,MAAM,CAAC,WACN,KAAK,EAAE,GACZ,QAAQ;AACP,aAAS,mBAAmB,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI,GAAG;AAC/E,SAAK,EAAE;KAEV;;AAIH,UAAQ,GAAG,UAAU,SAAS;AAC9B,UAAQ,GAAG,WAAW,SAAS;AAE/B,MAAI,8BAA8B,MAAM;AAExC,MAAI,KAAK,QACP,MAAK,QAAQ,EAAE,UAAU,CAAC;;AAI9B,OAAM,CAAC,OAAO,QAAQ;AACpB,WAAS,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI,CAAC;AAC1D,OAAK,EAAE;GACP;;AAMJ,MAAM,+BADa,QAAQ,KAAK,MAAM,GACL;AACjC,IAAI,SAAS,YAAY,SAAS,mBAAmB,SAAS,gBAC5D,eAAc"}
@@ -97,7 +97,6 @@ function runAimockCli(deps = {}) {
97
97
  port,
98
98
  host
99
99
  });
100
- log(`aimock server listening on ${url}`);
101
100
  function shutdown() {
102
101
  log("Shutting down...");
103
102
  process.removeListener("SIGINT", shutdown);
@@ -109,6 +108,7 @@ function runAimockCli(deps = {}) {
109
108
  }
110
109
  process.on("SIGINT", shutdown);
111
110
  process.on("SIGTERM", shutdown);
111
+ log(`aimock server listening on ${url}`);
112
112
  if (deps.onReady) deps.onReady({ shutdown });
113
113
  }
114
114
  main().catch((err) => {
@@ -1 +1 @@
1
- {"version":3,"file":"aimock-cli.js","names":[],"sources":["../src/aimock-cli.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { parseArgs } from \"node:util\";\nimport { resolve, basename } from \"node:path\";\nimport { loadConfig, startFromConfig } from \"./config-loader.js\";\nimport { runConvertCli, type ConvertCliDeps } from \"./convert.js\";\n\nconst HELP = `\nUsage: aimock [options]\n aimock convert <format> <input> [output]\n\nOptions:\n -c, --config <path> Path to aimock config JSON file (required)\n -p, --port <number> Port override (default: from config or 0)\n -h, --host <string> Host override (default: from config or 127.0.0.1)\n --help Show this help message\n\nSubcommands:\n convert Convert third-party mock configs to aimock format\n Run \"aimock convert --help\" for details\n`.trim();\n\nexport interface AimockCliDeps {\n argv?: string[];\n log?: (msg: string) => void;\n logError?: (msg: string) => void;\n exit?: (code: number) => void;\n loadConfigFn?: typeof loadConfig;\n startFromConfigFn?: typeof startFromConfig;\n onReady?: (ctx: { shutdown: () => void }) => void;\n convertDeps?: Partial<ConvertCliDeps>;\n}\n\nexport function runAimockCli(deps: AimockCliDeps = {}): void {\n /* v8 ignore next 6 -- defaults used only when called from CLI entry point */\n const argv = deps.argv ?? process.argv.slice(2);\n const log = deps.log ?? console.log.bind(console);\n const logError = deps.logError ?? console.error.bind(console);\n const exit = deps.exit ?? process.exit.bind(process);\n const loadConfigFn = deps.loadConfigFn ?? loadConfig;\n const startFromConfigFn = deps.startFromConfigFn ?? startFromConfig;\n\n // Intercept \"convert\" subcommand before parseArgs (which uses strict mode)\n if (argv[0] === \"convert\") {\n runConvertCli({\n argv: argv.slice(1),\n log,\n logError,\n exit,\n ...deps.convertDeps,\n });\n return;\n }\n\n let values;\n try {\n ({ values } = parseArgs({\n args: argv,\n options: {\n config: { type: \"string\", short: \"c\" },\n port: { type: \"string\", short: \"p\" },\n host: { type: \"string\", short: \"h\" },\n help: { type: \"boolean\", default: false },\n },\n strict: true,\n }));\n } catch (err) {\n /* v8 ignore next -- parseArgs always throws Error subclasses */\n const msg = err instanceof Error ? err.message : String(err);\n logError(`Error: ${msg}\\n\\n${HELP}`);\n exit(1);\n return;\n }\n\n if (values.help) {\n log(HELP);\n exit(0);\n return;\n }\n if (!values.config) {\n logError(\"Error: --config is required.\\n\\n\" + HELP);\n exit(1);\n return;\n }\n\n const configPath = resolve(values.config);\n let config;\n try {\n config = loadConfigFn(configPath);\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n logError(`Failed to load config from ${configPath}: ${msg}`);\n exit(1);\n return;\n }\n\n const port = values.port ? Number(values.port) : undefined;\n if (\n port !== undefined &&\n (Number.isNaN(port) || !Number.isInteger(port) || port < 0 || port > 65535)\n ) {\n logError(`Error: invalid port \"${values.port}\".\\n\\n${HELP}`);\n exit(1);\n return;\n }\n const host = values.host;\n\n async function main() {\n const { llmock, url } = await startFromConfigFn(config!, { port, host });\n log(`aimock server listening on ${url}`);\n\n function shutdown() {\n log(\"Shutting down...\");\n process.removeListener(\"SIGINT\", shutdown);\n process.removeListener(\"SIGTERM\", shutdown);\n llmock.stop().then(\n () => exit(0),\n (err) => {\n logError(`Shutdown error: ${err instanceof Error ? err.message : String(err)}`);\n exit(1);\n },\n );\n }\n process.on(\"SIGINT\", shutdown);\n process.on(\"SIGTERM\", shutdown);\n\n if (deps.onReady) {\n deps.onReady({ shutdown });\n }\n }\n\n main().catch((err) => {\n logError(err instanceof Error ? err.message : String(err));\n exit(1);\n });\n}\n\n// Run when executed as a script (not when imported for testing).\n/* v8 ignore start -- entry-point guard, exercised by integration tests */\nconst scriptName = process.argv[1] ?? \"\";\nconst base = basename(scriptName);\nif (base === \"aimock\" || base === \"aimock-cli.js\" || base === \"aimock-cli.ts\") {\n runAimockCli();\n}\n/* v8 ignore stop */\n"],"mappings":";;;;;;;AAMA,MAAM,OAAO;;;;;;;;;;;;;EAaX,MAAM;AAaR,SAAgB,aAAa,OAAsB,EAAE,EAAQ;;CAE3D,MAAM,OAAO,KAAK,QAAQ,QAAQ,KAAK,MAAM,EAAE;CAC/C,MAAM,MAAM,KAAK,OAAO,QAAQ,IAAI,KAAK,QAAQ;CACjD,MAAM,WAAW,KAAK,YAAY,QAAQ,MAAM,KAAK,QAAQ;CAC7D,MAAM,OAAO,KAAK,QAAQ,QAAQ,KAAK,KAAK,QAAQ;CACpD,MAAM,eAAe,KAAK,gBAAgB;CAC1C,MAAM,oBAAoB,KAAK,qBAAqB;AAGpD,KAAI,KAAK,OAAO,WAAW;AACzB,gBAAc;GACZ,MAAM,KAAK,MAAM,EAAE;GACnB;GACA;GACA;GACA,GAAG,KAAK;GACT,CAAC;AACF;;CAGF,IAAI;AACJ,KAAI;AACF,GAAC,CAAE,UAAW,UAAU;GACtB,MAAM;GACN,SAAS;IACP,QAAQ;KAAE,MAAM;KAAU,OAAO;KAAK;IACtC,MAAM;KAAE,MAAM;KAAU,OAAO;KAAK;IACpC,MAAM;KAAE,MAAM;KAAU,OAAO;KAAK;IACpC,MAAM;KAAE,MAAM;KAAW,SAAS;KAAO;IAC1C;GACD,QAAQ;GACT,CAAC;UACK,KAAK;AAGZ,WAAS,UADG,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI,CACrC,MAAM,OAAO;AACpC,OAAK,EAAE;AACP;;AAGF,KAAI,OAAO,MAAM;AACf,MAAI,KAAK;AACT,OAAK,EAAE;AACP;;AAEF,KAAI,CAAC,OAAO,QAAQ;AAClB,WAAS,qCAAqC,KAAK;AACnD,OAAK,EAAE;AACP;;CAGF,MAAM,aAAa,QAAQ,OAAO,OAAO;CACzC,IAAI;AACJ,KAAI;AACF,WAAS,aAAa,WAAW;UAC1B,KAAK;AAEZ,WAAS,8BAA8B,WAAW,IADtC,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI,GACA;AAC5D,OAAK,EAAE;AACP;;CAGF,MAAM,OAAO,OAAO,OAAO,OAAO,OAAO,KAAK,GAAG;AACjD,KACE,SAAS,WACR,OAAO,MAAM,KAAK,IAAI,CAAC,OAAO,UAAU,KAAK,IAAI,OAAO,KAAK,OAAO,QACrE;AACA,WAAS,wBAAwB,OAAO,KAAK,QAAQ,OAAO;AAC5D,OAAK,EAAE;AACP;;CAEF,MAAM,OAAO,OAAO;CAEpB,eAAe,OAAO;EACpB,MAAM,EAAE,QAAQ,QAAQ,MAAM,kBAAkB,QAAS;GAAE;GAAM;GAAM,CAAC;AACxE,MAAI,8BAA8B,MAAM;EAExC,SAAS,WAAW;AAClB,OAAI,mBAAmB;AACvB,WAAQ,eAAe,UAAU,SAAS;AAC1C,WAAQ,eAAe,WAAW,SAAS;AAC3C,UAAO,MAAM,CAAC,WACN,KAAK,EAAE,GACZ,QAAQ;AACP,aAAS,mBAAmB,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI,GAAG;AAC/E,SAAK,EAAE;KAEV;;AAEH,UAAQ,GAAG,UAAU,SAAS;AAC9B,UAAQ,GAAG,WAAW,SAAS;AAE/B,MAAI,KAAK,QACP,MAAK,QAAQ,EAAE,UAAU,CAAC;;AAI9B,OAAM,CAAC,OAAO,QAAQ;AACpB,WAAS,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI,CAAC;AAC1D,OAAK,EAAE;GACP;;AAMJ,MAAM,OAAO,SADM,QAAQ,KAAK,MAAM,GACL;AACjC,IAAI,SAAS,YAAY,SAAS,mBAAmB,SAAS,gBAC5D,eAAc"}
1
+ {"version":3,"file":"aimock-cli.js","names":[],"sources":["../src/aimock-cli.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { parseArgs } from \"node:util\";\nimport { resolve, basename } from \"node:path\";\nimport { loadConfig, startFromConfig } from \"./config-loader.js\";\nimport { runConvertCli, type ConvertCliDeps } from \"./convert.js\";\n\nconst HELP = `\nUsage: aimock [options]\n aimock convert <format> <input> [output]\n\nOptions:\n -c, --config <path> Path to aimock config JSON file (required)\n -p, --port <number> Port override (default: from config or 0)\n -h, --host <string> Host override (default: from config or 127.0.0.1)\n --help Show this help message\n\nSubcommands:\n convert Convert third-party mock configs to aimock format\n Run \"aimock convert --help\" for details\n`.trim();\n\nexport interface AimockCliDeps {\n argv?: string[];\n log?: (msg: string) => void;\n logError?: (msg: string) => void;\n exit?: (code: number) => void;\n loadConfigFn?: typeof loadConfig;\n startFromConfigFn?: typeof startFromConfig;\n onReady?: (ctx: { shutdown: () => void }) => void;\n convertDeps?: Partial<ConvertCliDeps>;\n}\n\nexport function runAimockCli(deps: AimockCliDeps = {}): void {\n /* v8 ignore next 6 -- defaults used only when called from CLI entry point */\n const argv = deps.argv ?? process.argv.slice(2);\n const log = deps.log ?? console.log.bind(console);\n const logError = deps.logError ?? console.error.bind(console);\n const exit = deps.exit ?? process.exit.bind(process);\n const loadConfigFn = deps.loadConfigFn ?? loadConfig;\n const startFromConfigFn = deps.startFromConfigFn ?? startFromConfig;\n\n // Intercept \"convert\" subcommand before parseArgs (which uses strict mode)\n if (argv[0] === \"convert\") {\n runConvertCli({\n argv: argv.slice(1),\n log,\n logError,\n exit,\n ...deps.convertDeps,\n });\n return;\n }\n\n let values;\n try {\n ({ values } = parseArgs({\n args: argv,\n options: {\n config: { type: \"string\", short: \"c\" },\n port: { type: \"string\", short: \"p\" },\n host: { type: \"string\", short: \"h\" },\n help: { type: \"boolean\", default: false },\n },\n strict: true,\n }));\n } catch (err) {\n /* v8 ignore next -- parseArgs always throws Error subclasses */\n const msg = err instanceof Error ? err.message : String(err);\n logError(`Error: ${msg}\\n\\n${HELP}`);\n exit(1);\n return;\n }\n\n if (values.help) {\n log(HELP);\n exit(0);\n return;\n }\n if (!values.config) {\n logError(\"Error: --config is required.\\n\\n\" + HELP);\n exit(1);\n return;\n }\n\n const configPath = resolve(values.config);\n let config;\n try {\n config = loadConfigFn(configPath);\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n logError(`Failed to load config from ${configPath}: ${msg}`);\n exit(1);\n return;\n }\n\n const port = values.port ? Number(values.port) : undefined;\n if (\n port !== undefined &&\n (Number.isNaN(port) || !Number.isInteger(port) || port < 0 || port > 65535)\n ) {\n logError(`Error: invalid port \"${values.port}\".\\n\\n${HELP}`);\n exit(1);\n return;\n }\n const host = values.host;\n\n async function main() {\n const { llmock, url } = await startFromConfigFn(config!, { port, host });\n\n function shutdown() {\n log(\"Shutting down...\");\n process.removeListener(\"SIGINT\", shutdown);\n process.removeListener(\"SIGTERM\", shutdown);\n llmock.stop().then(\n () => exit(0),\n (err) => {\n logError(`Shutdown error: ${err instanceof Error ? err.message : String(err)}`);\n exit(1);\n },\n );\n }\n // Register BEFORE announcing readiness — see the note in src/cli.ts. A supervisor\n // that reacts to the readiness line must never win a race against this listener.\n process.on(\"SIGINT\", shutdown);\n process.on(\"SIGTERM\", shutdown);\n\n log(`aimock server listening on ${url}`);\n\n if (deps.onReady) {\n deps.onReady({ shutdown });\n }\n }\n\n main().catch((err) => {\n logError(err instanceof Error ? err.message : String(err));\n exit(1);\n });\n}\n\n// Run when executed as a script (not when imported for testing).\n/* v8 ignore start -- entry-point guard, exercised by integration tests */\nconst scriptName = process.argv[1] ?? \"\";\nconst base = basename(scriptName);\nif (base === \"aimock\" || base === \"aimock-cli.js\" || base === \"aimock-cli.ts\") {\n runAimockCli();\n}\n/* v8 ignore stop */\n"],"mappings":";;;;;;;AAMA,MAAM,OAAO;;;;;;;;;;;;;EAaX,MAAM;AAaR,SAAgB,aAAa,OAAsB,EAAE,EAAQ;;CAE3D,MAAM,OAAO,KAAK,QAAQ,QAAQ,KAAK,MAAM,EAAE;CAC/C,MAAM,MAAM,KAAK,OAAO,QAAQ,IAAI,KAAK,QAAQ;CACjD,MAAM,WAAW,KAAK,YAAY,QAAQ,MAAM,KAAK,QAAQ;CAC7D,MAAM,OAAO,KAAK,QAAQ,QAAQ,KAAK,KAAK,QAAQ;CACpD,MAAM,eAAe,KAAK,gBAAgB;CAC1C,MAAM,oBAAoB,KAAK,qBAAqB;AAGpD,KAAI,KAAK,OAAO,WAAW;AACzB,gBAAc;GACZ,MAAM,KAAK,MAAM,EAAE;GACnB;GACA;GACA;GACA,GAAG,KAAK;GACT,CAAC;AACF;;CAGF,IAAI;AACJ,KAAI;AACF,GAAC,CAAE,UAAW,UAAU;GACtB,MAAM;GACN,SAAS;IACP,QAAQ;KAAE,MAAM;KAAU,OAAO;KAAK;IACtC,MAAM;KAAE,MAAM;KAAU,OAAO;KAAK;IACpC,MAAM;KAAE,MAAM;KAAU,OAAO;KAAK;IACpC,MAAM;KAAE,MAAM;KAAW,SAAS;KAAO;IAC1C;GACD,QAAQ;GACT,CAAC;UACK,KAAK;AAGZ,WAAS,UADG,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI,CACrC,MAAM,OAAO;AACpC,OAAK,EAAE;AACP;;AAGF,KAAI,OAAO,MAAM;AACf,MAAI,KAAK;AACT,OAAK,EAAE;AACP;;AAEF,KAAI,CAAC,OAAO,QAAQ;AAClB,WAAS,qCAAqC,KAAK;AACnD,OAAK,EAAE;AACP;;CAGF,MAAM,aAAa,QAAQ,OAAO,OAAO;CACzC,IAAI;AACJ,KAAI;AACF,WAAS,aAAa,WAAW;UAC1B,KAAK;AAEZ,WAAS,8BAA8B,WAAW,IADtC,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI,GACA;AAC5D,OAAK,EAAE;AACP;;CAGF,MAAM,OAAO,OAAO,OAAO,OAAO,OAAO,KAAK,GAAG;AACjD,KACE,SAAS,WACR,OAAO,MAAM,KAAK,IAAI,CAAC,OAAO,UAAU,KAAK,IAAI,OAAO,KAAK,OAAO,QACrE;AACA,WAAS,wBAAwB,OAAO,KAAK,QAAQ,OAAO;AAC5D,OAAK,EAAE;AACP;;CAEF,MAAM,OAAO,OAAO;CAEpB,eAAe,OAAO;EACpB,MAAM,EAAE,QAAQ,QAAQ,MAAM,kBAAkB,QAAS;GAAE;GAAM;GAAM,CAAC;EAExE,SAAS,WAAW;AAClB,OAAI,mBAAmB;AACvB,WAAQ,eAAe,UAAU,SAAS;AAC1C,WAAQ,eAAe,WAAW,SAAS;AAC3C,UAAO,MAAM,CAAC,WACN,KAAK,EAAE,GACZ,QAAQ;AACP,aAAS,mBAAmB,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI,GAAG;AAC/E,SAAK,EAAE;KAEV;;AAIH,UAAQ,GAAG,UAAU,SAAS;AAC9B,UAAQ,GAAG,WAAW,SAAS;AAE/B,MAAI,8BAA8B,MAAM;AAExC,MAAI,KAAK,QACP,MAAK,QAAQ,EAAE,UAAU,CAAC;;AAI9B,OAAM,CAAC,OAAO,QAAQ;AACpB,WAAS,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI,CAAC;AAC1D,OAAK,EAAE;GACP;;AAMJ,MAAM,OAAO,SADM,QAAQ,KAAK,MAAM,GACL;AACjC,IAAI,SAAS,YAAY,SAAS,mBAAmB,SAAS,gBAC5D,eAAc"}
@@ -0,0 +1,166 @@
1
+ const require_runtime = require('./_virtual/_rolldown/runtime.cjs');
2
+ let node_crypto = require("node:crypto");
3
+
4
+ //#region src/api-key-auth.ts
5
+ const INBOUND_API_KEY_HEADERS = [
6
+ "authorization",
7
+ "x-api-key",
8
+ "x-goog-api-key",
9
+ "api-key",
10
+ "xi-api-key"
11
+ ];
12
+ const RECOGNIZED_HEADERS = new Set(INBOUND_API_KEY_HEADERS);
13
+ const API_KEY_ERROR_BODY = JSON.stringify({ error: {
14
+ message: "Invalid API key",
15
+ type: "authentication_error",
16
+ code: "invalid_api_key"
17
+ } });
18
+ const DISABLED_POLICY = {
19
+ enabled: false,
20
+ keys: []
21
+ };
22
+ const authenticatedRequests = /* @__PURE__ */ new WeakSet();
23
+ const OWS_EDGES = /^[ \t]+|[ \t]+$/g;
24
+ function fail(label, suffix) {
25
+ throw new Error(`${label}${suffix}`);
26
+ }
27
+ function hasControl(value) {
28
+ for (let index = 0; index < value.length; index += 1) {
29
+ const code = value.charCodeAt(index);
30
+ if (code <= 31 || code === 127) return true;
31
+ }
32
+ return false;
33
+ }
34
+ function normalizeKey(value, label) {
35
+ if (typeof value !== "string") fail(label, " must be a string");
36
+ const normalized = value.replace(OWS_EDGES, "");
37
+ if (normalized.length === 0) fail(label, " must not be empty");
38
+ if (hasControl(normalized)) fail(label, " must not contain control characters");
39
+ return normalized;
40
+ }
41
+ /** Parse a public auth source once and construct its private server policy. */
42
+ function resolveInboundAuth(source) {
43
+ if (source.value === void 0) return { policy: DISABLED_POLICY };
44
+ if (source.value === null || typeof source.value !== "object" || Array.isArray(source.value)) fail(source.label, " must be an object");
45
+ const apiKeys = source.value.apiKeys;
46
+ if (!Array.isArray(apiKeys)) fail(`${source.label}.apiKeys`, " must be an array");
47
+ if (apiKeys.length === 0) fail(`${source.label}.apiKeys`, " must not be empty");
48
+ const keys = apiKeys.map((value, index) => normalizeKey(value, `${source.label}.apiKeys[${index}]`));
49
+ const seen = /* @__PURE__ */ new Set();
50
+ for (const key of keys) {
51
+ if (seen.has(key)) fail(source.label, " must not contain duplicate API keys");
52
+ seen.add(key);
53
+ }
54
+ return {
55
+ publicConfig: { apiKeys: keys },
56
+ policy: {
57
+ enabled: true,
58
+ keys: keys.map((key) => Buffer.from(key, "utf8"))
59
+ }
60
+ };
61
+ }
62
+ /** Select configuration without parsing it, so an environment override bypasses malformed JSON auth. */
63
+ function selectInboundAuthSource(configAuth, env = process.env) {
64
+ if (Object.prototype.hasOwnProperty.call(env, "AIMOCK_API_KEYS")) return {
65
+ value: { apiKeys: (env.AIMOCK_API_KEYS ?? "").split(",") },
66
+ label: "AIMOCK_API_KEYS"
67
+ };
68
+ return {
69
+ value: configAuth,
70
+ label: "aimock.json.auth"
71
+ };
72
+ }
73
+ function isRecognizedApiKeyHeader(name) {
74
+ return RECOGNIZED_HEADERS.has(name.toLowerCase());
75
+ }
76
+ function rawCandidates(req) {
77
+ const candidates = [];
78
+ for (let index = 0; index < req.rawHeaders.length; index += 2) {
79
+ const name = req.rawHeaders[index];
80
+ const value = req.rawHeaders[index + 1] ?? "";
81
+ const lower = name.toLowerCase();
82
+ if (!isRecognizedApiKeyHeader(lower)) continue;
83
+ if (hasControl(value)) return { reason: "invalid" };
84
+ if (lower === "authorization") {
85
+ const match = /^(?:Bearer|Key)[ \t]+(.+)$/i.exec(value.replace(OWS_EDGES, ""));
86
+ if (!match) return { reason: "invalid" };
87
+ const candidate = match[1].replace(OWS_EDGES, "");
88
+ if (candidate.length === 0 || hasControl(candidate)) return { reason: "invalid" };
89
+ candidates.push(candidate);
90
+ } else {
91
+ const candidate = value.replace(OWS_EDGES, "");
92
+ if (candidate.length === 0) return { reason: "invalid" };
93
+ candidates.push(candidate);
94
+ }
95
+ }
96
+ return candidates.length > 0 ? { candidates } : { reason: "missing" };
97
+ }
98
+ function matchingIndex(candidate, keys) {
99
+ const encoded = Buffer.from(candidate, "utf8");
100
+ for (let index = 0; index < keys.length; index += 1) {
101
+ const key = keys[index];
102
+ if (encoded.length === key.length && (0, node_crypto.timingSafeEqual)(encoded, key)) return index;
103
+ }
104
+ }
105
+ function validateRequestApiKey(req, policy) {
106
+ if (!policy.enabled) return { ok: true };
107
+ const extracted = rawCandidates(req);
108
+ if (!extracted.candidates) return {
109
+ ok: false,
110
+ reason: extracted.reason
111
+ };
112
+ let resolved;
113
+ for (const candidate of extracted.candidates) {
114
+ const index = matchingIndex(candidate, policy.keys);
115
+ if (index === void 0) return {
116
+ ok: false,
117
+ reason: "invalid"
118
+ };
119
+ if (resolved !== void 0 && resolved !== index) return {
120
+ ok: false,
121
+ reason: "conflict"
122
+ };
123
+ resolved = index;
124
+ }
125
+ return { ok: true };
126
+ }
127
+ /** @internal Opaque egress marker; it deliberately carries no key material. */
128
+ function markAuthenticatedRequest(req, policy) {
129
+ if (policy.enabled) authenticatedRequests.add(req);
130
+ }
131
+ /** @internal Used by egress paths to select safe credential handling. */
132
+ function isAuthenticatedRequest(req) {
133
+ return authenticatedRequests.has(req);
134
+ }
135
+ function writeApiKeyHttpRejection(res, setCorsHeaders) {
136
+ setCorsHeaders(res);
137
+ res.writeHead(401, {
138
+ "Content-Type": "application/json",
139
+ "Content-Length": Buffer.byteLength(API_KEY_ERROR_BODY),
140
+ "WWW-Authenticate": "Bearer realm=\"aimock\""
141
+ });
142
+ res.end(API_KEY_ERROR_BODY);
143
+ }
144
+ function writeApiKeyUpgradeRejection(socket) {
145
+ socket.write([
146
+ "HTTP/1.1 401 Unauthorized",
147
+ "Content-Type: application/json",
148
+ `Content-Length: ${Buffer.byteLength(API_KEY_ERROR_BODY)}`,
149
+ "WWW-Authenticate: Bearer realm=\"aimock\"",
150
+ "Connection: close",
151
+ "",
152
+ API_KEY_ERROR_BODY
153
+ ].join("\r\n"));
154
+ socket.destroy();
155
+ }
156
+
157
+ //#endregion
158
+ exports.isAuthenticatedRequest = isAuthenticatedRequest;
159
+ exports.isRecognizedApiKeyHeader = isRecognizedApiKeyHeader;
160
+ exports.markAuthenticatedRequest = markAuthenticatedRequest;
161
+ exports.resolveInboundAuth = resolveInboundAuth;
162
+ exports.selectInboundAuthSource = selectInboundAuthSource;
163
+ exports.validateRequestApiKey = validateRequestApiKey;
164
+ exports.writeApiKeyHttpRejection = writeApiKeyHttpRejection;
165
+ exports.writeApiKeyUpgradeRejection = writeApiKeyUpgradeRejection;
166
+ //# sourceMappingURL=api-key-auth.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api-key-auth.cjs","names":[],"sources":["../src/api-key-auth.ts"],"sourcesContent":["import { timingSafeEqual } from \"node:crypto\";\nimport type * as http from \"node:http\";\nimport type * as net from \"node:net\";\nimport type { ApiKeyAuthConfig } from \"./types.js\";\n\nexport const INBOUND_API_KEY_HEADERS = [\n \"authorization\",\n \"x-api-key\",\n \"x-goog-api-key\",\n \"api-key\",\n \"xi-api-key\",\n] as const;\n\nconst RECOGNIZED_HEADERS = new Set<string>(INBOUND_API_KEY_HEADERS);\n\nexport const API_KEY_ERROR_BODY = JSON.stringify({\n error: {\n message: \"Invalid API key\",\n type: \"authentication_error\",\n code: \"invalid_api_key\",\n },\n});\n\n/** @internal */\nexport interface ApiKeyPolicy {\n readonly enabled: boolean;\n readonly keys: readonly Buffer[];\n}\n\n/** @internal */\nexport interface ResolvedInboundAuth {\n readonly publicConfig?: ApiKeyAuthConfig;\n readonly policy: ApiKeyPolicy;\n}\n\nexport interface AuthResult {\n readonly ok: boolean;\n readonly reason?: \"missing\" | \"invalid\" | \"conflict\";\n}\n\nconst DISABLED_POLICY: ApiKeyPolicy = { enabled: false, keys: [] };\nconst authenticatedRequests = new WeakSet<http.IncomingMessage>();\nconst OWS_EDGES = /^[ \\t]+|[ \\t]+$/g;\n\nfunction fail(label: string, suffix: string): never {\n throw new Error(`${label}${suffix}`);\n}\n\nfunction hasControl(value: string): boolean {\n for (let index = 0; index < value.length; index += 1) {\n const code = value.charCodeAt(index);\n if (code <= 0x1f || code === 0x7f) return true;\n }\n return false;\n}\n\nfunction normalizeKey(value: unknown, label: string): string {\n if (typeof value !== \"string\") fail(label, \" must be a string\");\n const normalized = value.replace(OWS_EDGES, \"\");\n if (normalized.length === 0) fail(label, \" must not be empty\");\n if (hasControl(normalized)) fail(label, \" must not contain control characters\");\n return normalized;\n}\n\n/** Parse a public auth source once and construct its private server policy. */\nexport function resolveInboundAuth(source: { value: unknown; label: string }): ResolvedInboundAuth {\n if (source.value === undefined) return { policy: DISABLED_POLICY };\n if (source.value === null || typeof source.value !== \"object\" || Array.isArray(source.value)) {\n fail(source.label, \" must be an object\");\n }\n const apiKeys = (source.value as { apiKeys?: unknown }).apiKeys;\n if (!Array.isArray(apiKeys)) fail(`${source.label}.apiKeys`, \" must be an array\");\n if (apiKeys.length === 0) fail(`${source.label}.apiKeys`, \" must not be empty\");\n const keys = apiKeys.map((value, index) =>\n normalizeKey(value, `${source.label}.apiKeys[${index}]`),\n );\n const seen = new Set<string>();\n for (const key of keys) {\n if (seen.has(key)) fail(source.label, \" must not contain duplicate API keys\");\n seen.add(key);\n }\n return {\n publicConfig: { apiKeys: keys },\n policy: { enabled: true, keys: keys.map((key) => Buffer.from(key, \"utf8\")) },\n };\n}\n\n/** Select configuration without parsing it, so an environment override bypasses malformed JSON auth. */\nexport function selectInboundAuthSource(\n configAuth: unknown,\n env: NodeJS.ProcessEnv = process.env,\n): { value: unknown; label: string } {\n if (Object.prototype.hasOwnProperty.call(env, \"AIMOCK_API_KEYS\")) {\n return { value: { apiKeys: (env.AIMOCK_API_KEYS ?? \"\").split(\",\") }, label: \"AIMOCK_API_KEYS\" };\n }\n return { value: configAuth, label: \"aimock.json.auth\" };\n}\n\nexport function isRecognizedApiKeyHeader(name: string): boolean {\n return RECOGNIZED_HEADERS.has(name.toLowerCase());\n}\n\nfunction rawCandidates(req: http.IncomingMessage): {\n candidates?: string[];\n reason?: \"missing\" | \"invalid\";\n} {\n const candidates: string[] = [];\n for (let index = 0; index < req.rawHeaders.length; index += 2) {\n const name = req.rawHeaders[index];\n const value = req.rawHeaders[index + 1] ?? \"\";\n const lower = name.toLowerCase();\n if (!isRecognizedApiKeyHeader(lower)) continue;\n if (hasControl(value)) return { reason: \"invalid\" };\n if (lower === \"authorization\") {\n const match = /^(?:Bearer|Key)[ \\t]+(.+)$/i.exec(value.replace(OWS_EDGES, \"\"));\n if (!match) return { reason: \"invalid\" };\n const candidate = match[1].replace(OWS_EDGES, \"\");\n if (candidate.length === 0 || hasControl(candidate)) return { reason: \"invalid\" };\n candidates.push(candidate);\n } else {\n const candidate = value.replace(OWS_EDGES, \"\");\n if (candidate.length === 0) return { reason: \"invalid\" };\n candidates.push(candidate);\n }\n }\n return candidates.length > 0 ? { candidates } : { reason: \"missing\" };\n}\n\nfunction matchingIndex(candidate: string, keys: readonly Buffer[]): number | undefined {\n const encoded = Buffer.from(candidate, \"utf8\");\n for (let index = 0; index < keys.length; index += 1) {\n const key = keys[index];\n if (encoded.length === key.length && timingSafeEqual(encoded, key)) return index;\n }\n return undefined;\n}\n\nexport function validateRequestApiKey(req: http.IncomingMessage, policy: ApiKeyPolicy): AuthResult {\n if (!policy.enabled) return { ok: true };\n const extracted = rawCandidates(req);\n if (!extracted.candidates) return { ok: false, reason: extracted.reason };\n let resolved: number | undefined;\n for (const candidate of extracted.candidates) {\n const index = matchingIndex(candidate, policy.keys);\n if (index === undefined) return { ok: false, reason: \"invalid\" };\n if (resolved !== undefined && resolved !== index) return { ok: false, reason: \"conflict\" };\n resolved = index;\n }\n return { ok: true };\n}\n\n/** @internal Opaque egress marker; it deliberately carries no key material. */\nexport function markAuthenticatedRequest(req: http.IncomingMessage, policy: ApiKeyPolicy): void {\n if (policy.enabled) authenticatedRequests.add(req);\n}\n\n/** @internal Used by egress paths to select safe credential handling. */\nexport function isAuthenticatedRequest(req: http.IncomingMessage): boolean {\n return authenticatedRequests.has(req);\n}\n\nexport function writeApiKeyHttpRejection(\n res: http.ServerResponse,\n setCorsHeaders: (res: http.ServerResponse) => void,\n): void {\n setCorsHeaders(res);\n res.writeHead(401, {\n \"Content-Type\": \"application/json\",\n \"Content-Length\": Buffer.byteLength(API_KEY_ERROR_BODY),\n \"WWW-Authenticate\": 'Bearer realm=\"aimock\"',\n });\n res.end(API_KEY_ERROR_BODY);\n}\n\nexport function writeApiKeyUpgradeRejection(socket: net.Socket): void {\n socket.write(\n [\n \"HTTP/1.1 401 Unauthorized\",\n \"Content-Type: application/json\",\n `Content-Length: ${Buffer.byteLength(API_KEY_ERROR_BODY)}`,\n 'WWW-Authenticate: Bearer realm=\"aimock\"',\n \"Connection: close\",\n \"\",\n API_KEY_ERROR_BODY,\n ].join(\"\\r\\n\"),\n );\n socket.destroy();\n}\n"],"mappings":";;;;AAKA,MAAa,0BAA0B;CACrC;CACA;CACA;CACA;CACA;CACD;AAED,MAAM,qBAAqB,IAAI,IAAY,wBAAwB;AAEnE,MAAa,qBAAqB,KAAK,UAAU,EAC/C,OAAO;CACL,SAAS;CACT,MAAM;CACN,MAAM;CACP,EACF,CAAC;AAmBF,MAAM,kBAAgC;CAAE,SAAS;CAAO,MAAM,EAAE;CAAE;AAClE,MAAM,wCAAwB,IAAI,SAA+B;AACjE,MAAM,YAAY;AAElB,SAAS,KAAK,OAAe,QAAuB;AAClD,OAAM,IAAI,MAAM,GAAG,QAAQ,SAAS;;AAGtC,SAAS,WAAW,OAAwB;AAC1C,MAAK,IAAI,QAAQ,GAAG,QAAQ,MAAM,QAAQ,SAAS,GAAG;EACpD,MAAM,OAAO,MAAM,WAAW,MAAM;AACpC,MAAI,QAAQ,MAAQ,SAAS,IAAM,QAAO;;AAE5C,QAAO;;AAGT,SAAS,aAAa,OAAgB,OAAuB;AAC3D,KAAI,OAAO,UAAU,SAAU,MAAK,OAAO,oBAAoB;CAC/D,MAAM,aAAa,MAAM,QAAQ,WAAW,GAAG;AAC/C,KAAI,WAAW,WAAW,EAAG,MAAK,OAAO,qBAAqB;AAC9D,KAAI,WAAW,WAAW,CAAE,MAAK,OAAO,uCAAuC;AAC/E,QAAO;;;AAIT,SAAgB,mBAAmB,QAAgE;AACjG,KAAI,OAAO,UAAU,OAAW,QAAO,EAAE,QAAQ,iBAAiB;AAClE,KAAI,OAAO,UAAU,QAAQ,OAAO,OAAO,UAAU,YAAY,MAAM,QAAQ,OAAO,MAAM,CAC1F,MAAK,OAAO,OAAO,qBAAqB;CAE1C,MAAM,UAAW,OAAO,MAAgC;AACxD,KAAI,CAAC,MAAM,QAAQ,QAAQ,CAAE,MAAK,GAAG,OAAO,MAAM,WAAW,oBAAoB;AACjF,KAAI,QAAQ,WAAW,EAAG,MAAK,GAAG,OAAO,MAAM,WAAW,qBAAqB;CAC/E,MAAM,OAAO,QAAQ,KAAK,OAAO,UAC/B,aAAa,OAAO,GAAG,OAAO,MAAM,WAAW,MAAM,GAAG,CACzD;CACD,MAAM,uBAAO,IAAI,KAAa;AAC9B,MAAK,MAAM,OAAO,MAAM;AACtB,MAAI,KAAK,IAAI,IAAI,CAAE,MAAK,OAAO,OAAO,uCAAuC;AAC7E,OAAK,IAAI,IAAI;;AAEf,QAAO;EACL,cAAc,EAAE,SAAS,MAAM;EAC/B,QAAQ;GAAE,SAAS;GAAM,MAAM,KAAK,KAAK,QAAQ,OAAO,KAAK,KAAK,OAAO,CAAC;GAAE;EAC7E;;;AAIH,SAAgB,wBACd,YACA,MAAyB,QAAQ,KACE;AACnC,KAAI,OAAO,UAAU,eAAe,KAAK,KAAK,kBAAkB,CAC9D,QAAO;EAAE,OAAO,EAAE,UAAU,IAAI,mBAAmB,IAAI,MAAM,IAAI,EAAE;EAAE,OAAO;EAAmB;AAEjG,QAAO;EAAE,OAAO;EAAY,OAAO;EAAoB;;AAGzD,SAAgB,yBAAyB,MAAuB;AAC9D,QAAO,mBAAmB,IAAI,KAAK,aAAa,CAAC;;AAGnD,SAAS,cAAc,KAGrB;CACA,MAAM,aAAuB,EAAE;AAC/B,MAAK,IAAI,QAAQ,GAAG,QAAQ,IAAI,WAAW,QAAQ,SAAS,GAAG;EAC7D,MAAM,OAAO,IAAI,WAAW;EAC5B,MAAM,QAAQ,IAAI,WAAW,QAAQ,MAAM;EAC3C,MAAM,QAAQ,KAAK,aAAa;AAChC,MAAI,CAAC,yBAAyB,MAAM,CAAE;AACtC,MAAI,WAAW,MAAM,CAAE,QAAO,EAAE,QAAQ,WAAW;AACnD,MAAI,UAAU,iBAAiB;GAC7B,MAAM,QAAQ,8BAA8B,KAAK,MAAM,QAAQ,WAAW,GAAG,CAAC;AAC9E,OAAI,CAAC,MAAO,QAAO,EAAE,QAAQ,WAAW;GACxC,MAAM,YAAY,MAAM,GAAG,QAAQ,WAAW,GAAG;AACjD,OAAI,UAAU,WAAW,KAAK,WAAW,UAAU,CAAE,QAAO,EAAE,QAAQ,WAAW;AACjF,cAAW,KAAK,UAAU;SACrB;GACL,MAAM,YAAY,MAAM,QAAQ,WAAW,GAAG;AAC9C,OAAI,UAAU,WAAW,EAAG,QAAO,EAAE,QAAQ,WAAW;AACxD,cAAW,KAAK,UAAU;;;AAG9B,QAAO,WAAW,SAAS,IAAI,EAAE,YAAY,GAAG,EAAE,QAAQ,WAAW;;AAGvE,SAAS,cAAc,WAAmB,MAA6C;CACrF,MAAM,UAAU,OAAO,KAAK,WAAW,OAAO;AAC9C,MAAK,IAAI,QAAQ,GAAG,QAAQ,KAAK,QAAQ,SAAS,GAAG;EACnD,MAAM,MAAM,KAAK;AACjB,MAAI,QAAQ,WAAW,IAAI,2CAA0B,SAAS,IAAI,CAAE,QAAO;;;AAK/E,SAAgB,sBAAsB,KAA2B,QAAkC;AACjG,KAAI,CAAC,OAAO,QAAS,QAAO,EAAE,IAAI,MAAM;CACxC,MAAM,YAAY,cAAc,IAAI;AACpC,KAAI,CAAC,UAAU,WAAY,QAAO;EAAE,IAAI;EAAO,QAAQ,UAAU;EAAQ;CACzE,IAAI;AACJ,MAAK,MAAM,aAAa,UAAU,YAAY;EAC5C,MAAM,QAAQ,cAAc,WAAW,OAAO,KAAK;AACnD,MAAI,UAAU,OAAW,QAAO;GAAE,IAAI;GAAO,QAAQ;GAAW;AAChE,MAAI,aAAa,UAAa,aAAa,MAAO,QAAO;GAAE,IAAI;GAAO,QAAQ;GAAY;AAC1F,aAAW;;AAEb,QAAO,EAAE,IAAI,MAAM;;;AAIrB,SAAgB,yBAAyB,KAA2B,QAA4B;AAC9F,KAAI,OAAO,QAAS,uBAAsB,IAAI,IAAI;;;AAIpD,SAAgB,uBAAuB,KAAoC;AACzE,QAAO,sBAAsB,IAAI,IAAI;;AAGvC,SAAgB,yBACd,KACA,gBACM;AACN,gBAAe,IAAI;AACnB,KAAI,UAAU,KAAK;EACjB,gBAAgB;EAChB,kBAAkB,OAAO,WAAW,mBAAmB;EACvD,oBAAoB;EACrB,CAAC;AACF,KAAI,IAAI,mBAAmB;;AAG7B,SAAgB,4BAA4B,QAA0B;AACpE,QAAO,MACL;EACE;EACA;EACA,mBAAmB,OAAO,WAAW,mBAAmB;EACxD;EACA;EACA;EACA;EACD,CAAC,KAAK,OAAO,CACf;AACD,QAAO,SAAS"}
@@ -0,0 +1,17 @@
1
+ import { ApiKeyAuthConfig } from "./types.cjs";
2
+
3
+ //#region src/api-key-auth.d.ts
4
+
5
+ /** @internal */
6
+ interface ApiKeyPolicy {
7
+ readonly enabled: boolean;
8
+ readonly keys: readonly Buffer[];
9
+ }
10
+ /** @internal */
11
+ interface ResolvedInboundAuth {
12
+ readonly publicConfig?: ApiKeyAuthConfig;
13
+ readonly policy: ApiKeyPolicy;
14
+ }
15
+ //#endregion
16
+ export { ResolvedInboundAuth };
17
+ //# sourceMappingURL=api-key-auth.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api-key-auth.d.cts","names":[],"sources":["../src/api-key-auth.ts"],"sourcesContent":[],"mappings":";;;;;AA+B0B,UAPT,YAAA,CAOS;WACP,OAAA,EAAA,OAAA;EAAY,SAAA,IAAA,EAAA,SANL,MAMK,EAAA;;;UAFd,mBAAA;0BACS;mBACP"}
@@ -0,0 +1,17 @@
1
+ import { ApiKeyAuthConfig } from "./types.js";
2
+
3
+ //#region src/api-key-auth.d.ts
4
+
5
+ /** @internal */
6
+ interface ApiKeyPolicy {
7
+ readonly enabled: boolean;
8
+ readonly keys: readonly Buffer[];
9
+ }
10
+ /** @internal */
11
+ interface ResolvedInboundAuth {
12
+ readonly publicConfig?: ApiKeyAuthConfig;
13
+ readonly policy: ApiKeyPolicy;
14
+ }
15
+ //#endregion
16
+ export { ResolvedInboundAuth };
17
+ //# sourceMappingURL=api-key-auth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api-key-auth.d.ts","names":[],"sources":["../src/api-key-auth.ts"],"sourcesContent":[],"mappings":";;;;;AA+B0B,UAPT,YAAA,CAOS;WACP,OAAA,EAAA,OAAA;EAAY,SAAA,IAAA,EAAA,SANL,MAMK,EAAA;;;UAFd,mBAAA;0BACS;mBACP"}
@@ -0,0 +1,158 @@
1
+ import { timingSafeEqual } from "node:crypto";
2
+
3
+ //#region src/api-key-auth.ts
4
+ const INBOUND_API_KEY_HEADERS = [
5
+ "authorization",
6
+ "x-api-key",
7
+ "x-goog-api-key",
8
+ "api-key",
9
+ "xi-api-key"
10
+ ];
11
+ const RECOGNIZED_HEADERS = new Set(INBOUND_API_KEY_HEADERS);
12
+ const API_KEY_ERROR_BODY = JSON.stringify({ error: {
13
+ message: "Invalid API key",
14
+ type: "authentication_error",
15
+ code: "invalid_api_key"
16
+ } });
17
+ const DISABLED_POLICY = {
18
+ enabled: false,
19
+ keys: []
20
+ };
21
+ const authenticatedRequests = /* @__PURE__ */ new WeakSet();
22
+ const OWS_EDGES = /^[ \t]+|[ \t]+$/g;
23
+ function fail(label, suffix) {
24
+ throw new Error(`${label}${suffix}`);
25
+ }
26
+ function hasControl(value) {
27
+ for (let index = 0; index < value.length; index += 1) {
28
+ const code = value.charCodeAt(index);
29
+ if (code <= 31 || code === 127) return true;
30
+ }
31
+ return false;
32
+ }
33
+ function normalizeKey(value, label) {
34
+ if (typeof value !== "string") fail(label, " must be a string");
35
+ const normalized = value.replace(OWS_EDGES, "");
36
+ if (normalized.length === 0) fail(label, " must not be empty");
37
+ if (hasControl(normalized)) fail(label, " must not contain control characters");
38
+ return normalized;
39
+ }
40
+ /** Parse a public auth source once and construct its private server policy. */
41
+ function resolveInboundAuth(source) {
42
+ if (source.value === void 0) return { policy: DISABLED_POLICY };
43
+ if (source.value === null || typeof source.value !== "object" || Array.isArray(source.value)) fail(source.label, " must be an object");
44
+ const apiKeys = source.value.apiKeys;
45
+ if (!Array.isArray(apiKeys)) fail(`${source.label}.apiKeys`, " must be an array");
46
+ if (apiKeys.length === 0) fail(`${source.label}.apiKeys`, " must not be empty");
47
+ const keys = apiKeys.map((value, index) => normalizeKey(value, `${source.label}.apiKeys[${index}]`));
48
+ const seen = /* @__PURE__ */ new Set();
49
+ for (const key of keys) {
50
+ if (seen.has(key)) fail(source.label, " must not contain duplicate API keys");
51
+ seen.add(key);
52
+ }
53
+ return {
54
+ publicConfig: { apiKeys: keys },
55
+ policy: {
56
+ enabled: true,
57
+ keys: keys.map((key) => Buffer.from(key, "utf8"))
58
+ }
59
+ };
60
+ }
61
+ /** Select configuration without parsing it, so an environment override bypasses malformed JSON auth. */
62
+ function selectInboundAuthSource(configAuth, env = process.env) {
63
+ if (Object.prototype.hasOwnProperty.call(env, "AIMOCK_API_KEYS")) return {
64
+ value: { apiKeys: (env.AIMOCK_API_KEYS ?? "").split(",") },
65
+ label: "AIMOCK_API_KEYS"
66
+ };
67
+ return {
68
+ value: configAuth,
69
+ label: "aimock.json.auth"
70
+ };
71
+ }
72
+ function isRecognizedApiKeyHeader(name) {
73
+ return RECOGNIZED_HEADERS.has(name.toLowerCase());
74
+ }
75
+ function rawCandidates(req) {
76
+ const candidates = [];
77
+ for (let index = 0; index < req.rawHeaders.length; index += 2) {
78
+ const name = req.rawHeaders[index];
79
+ const value = req.rawHeaders[index + 1] ?? "";
80
+ const lower = name.toLowerCase();
81
+ if (!isRecognizedApiKeyHeader(lower)) continue;
82
+ if (hasControl(value)) return { reason: "invalid" };
83
+ if (lower === "authorization") {
84
+ const match = /^(?:Bearer|Key)[ \t]+(.+)$/i.exec(value.replace(OWS_EDGES, ""));
85
+ if (!match) return { reason: "invalid" };
86
+ const candidate = match[1].replace(OWS_EDGES, "");
87
+ if (candidate.length === 0 || hasControl(candidate)) return { reason: "invalid" };
88
+ candidates.push(candidate);
89
+ } else {
90
+ const candidate = value.replace(OWS_EDGES, "");
91
+ if (candidate.length === 0) return { reason: "invalid" };
92
+ candidates.push(candidate);
93
+ }
94
+ }
95
+ return candidates.length > 0 ? { candidates } : { reason: "missing" };
96
+ }
97
+ function matchingIndex(candidate, keys) {
98
+ const encoded = Buffer.from(candidate, "utf8");
99
+ for (let index = 0; index < keys.length; index += 1) {
100
+ const key = keys[index];
101
+ if (encoded.length === key.length && timingSafeEqual(encoded, key)) return index;
102
+ }
103
+ }
104
+ function validateRequestApiKey(req, policy) {
105
+ if (!policy.enabled) return { ok: true };
106
+ const extracted = rawCandidates(req);
107
+ if (!extracted.candidates) return {
108
+ ok: false,
109
+ reason: extracted.reason
110
+ };
111
+ let resolved;
112
+ for (const candidate of extracted.candidates) {
113
+ const index = matchingIndex(candidate, policy.keys);
114
+ if (index === void 0) return {
115
+ ok: false,
116
+ reason: "invalid"
117
+ };
118
+ if (resolved !== void 0 && resolved !== index) return {
119
+ ok: false,
120
+ reason: "conflict"
121
+ };
122
+ resolved = index;
123
+ }
124
+ return { ok: true };
125
+ }
126
+ /** @internal Opaque egress marker; it deliberately carries no key material. */
127
+ function markAuthenticatedRequest(req, policy) {
128
+ if (policy.enabled) authenticatedRequests.add(req);
129
+ }
130
+ /** @internal Used by egress paths to select safe credential handling. */
131
+ function isAuthenticatedRequest(req) {
132
+ return authenticatedRequests.has(req);
133
+ }
134
+ function writeApiKeyHttpRejection(res, setCorsHeaders) {
135
+ setCorsHeaders(res);
136
+ res.writeHead(401, {
137
+ "Content-Type": "application/json",
138
+ "Content-Length": Buffer.byteLength(API_KEY_ERROR_BODY),
139
+ "WWW-Authenticate": "Bearer realm=\"aimock\""
140
+ });
141
+ res.end(API_KEY_ERROR_BODY);
142
+ }
143
+ function writeApiKeyUpgradeRejection(socket) {
144
+ socket.write([
145
+ "HTTP/1.1 401 Unauthorized",
146
+ "Content-Type: application/json",
147
+ `Content-Length: ${Buffer.byteLength(API_KEY_ERROR_BODY)}`,
148
+ "WWW-Authenticate: Bearer realm=\"aimock\"",
149
+ "Connection: close",
150
+ "",
151
+ API_KEY_ERROR_BODY
152
+ ].join("\r\n"));
153
+ socket.destroy();
154
+ }
155
+
156
+ //#endregion
157
+ export { isAuthenticatedRequest, isRecognizedApiKeyHeader, markAuthenticatedRequest, resolveInboundAuth, selectInboundAuthSource, validateRequestApiKey, writeApiKeyHttpRejection, writeApiKeyUpgradeRejection };
158
+ //# sourceMappingURL=api-key-auth.js.map