From 3290c43bfb5e705e6b468d93480922d870c6884e Mon Sep 17 00:00:00 2001 From: Jordan Ritter Date: Wed, 15 Apr 2026 16:38:16 -0700 Subject: [PATCH 1/4] feat: response template merging with JSON auto-stringify MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add ResponseOverrides interface for overriding envelope fields (id, created, model, usage, finishReason, role, systemFingerprint) in fixture responses. Thread overrides through all 4 provider handlers (OpenAI Chat, Responses API, Claude Messages, Gemini) for both streaming and non-streaming paths. Add normalizeResponse() for auto-stringifying object-valued content and toolCalls[].arguments in fixtures — lets authors write plain JSON objects instead of escaped strings. FixtureFile* types accept relaxed input while runtime types remain strict. Type safety improvements: - Add system_fingerprint to SSEChunk/ChatCompletion types - Make type guards mutually exclusive (isTextResponse excludes toolCalls) - Narrow extractOverrides parameter type - Remove unnecessary as-casts Cross-provider consistency: - finishReason mappings: length, content_filter for all providers - Usage auto-sum: total_tokens computed from components when omitted - Reasoning support for ContentWithToolCallsResponse in all providers - webSearches warnings for unsupported providers Validation: ResponseOverrides field type checks, unknown field detection, unknown usage key detection, ContentWithToolCallsResponse validation. --- src/fixture-loader.ts | 255 +++++++++++++++++++++++++++++++++++------- src/gemini.ts | 164 +++++++++++++++++---------- src/helpers.ts | 212 +++++++++++++++++++++++++++-------- src/index.ts | 23 +++- src/llmock.ts | 14 ++- src/messages.ts | 137 +++++++++++++++++------ src/responses.ts | 121 ++++++++++++++------ src/server.ts | 37 +++++- src/types.ts | 93 +++++++++++++-- 9 files changed, 822 insertions(+), 234 deletions(-) diff --git a/src/fixture-loader.ts b/src/fixture-loader.ts index 452ce14..40d2ddb 100644 --- a/src/fixture-loader.ts +++ b/src/fixture-loader.ts @@ -1,14 +1,53 @@ import { readFileSync, readdirSync, statSync } from "node:fs"; import { join } from "node:path"; -import type { Fixture, FixtureFile, FixtureFileEntry } from "./types.js"; +import type { + Fixture, + FixtureFile, + FixtureFileEntry, + FixtureFileResponse, + FixtureResponse, + ResponseOverrides, +} from "./types.js"; import { isTextResponse, isToolCallResponse, + isContentWithToolCallsResponse, isErrorResponse, isEmbeddingResponse, + isImageResponse, + isAudioResponse, + isTranscriptionResponse, + isVideoResponse, } from "./helpers.js"; import type { Logger } from "./logger.js"; +/** + * Auto-stringify object-valued `content` and `toolCalls[].arguments` fields. + * This lets fixture authors write plain JSON objects instead of escaped strings. + * All other fields (including ResponseOverrides) pass through unmodified. + */ +export function normalizeResponse(raw: FixtureFileResponse): FixtureResponse { + // Shallow-clone so we don't mutate the parsed JSON input. + const response = { ...raw } as Record; + + // Auto-stringify object content (e.g. structured output) + if (typeof response.content === "object" && response.content !== null) { + response.content = JSON.stringify(response.content); + } + + // Auto-stringify object arguments in toolCalls + if (Array.isArray(response.toolCalls)) { + response.toolCalls = (response.toolCalls as Array>).map((tc) => { + if (typeof tc.arguments === "object" && tc.arguments !== null) { + return { ...tc, arguments: JSON.stringify(tc.arguments) }; + } + return tc; + }); + } + + return response as unknown as FixtureResponse; +} + export function entryToFixture(entry: FixtureFileEntry): Fixture { return { match: { @@ -21,7 +60,7 @@ export function entryToFixture(entry: FixtureFileEntry): Fixture { endpoint: entry.match.endpoint, ...(entry.match.sequenceIndex !== undefined && { sequenceIndex: entry.match.sequenceIndex }), }, - response: entry.response, + response: normalizeResponse(entry.response), ...(entry.latency !== undefined && { latency: entry.latency }), ...(entry.chunkSize !== undefined && { chunkSize: entry.chunkSize }), ...(entry.truncateAfterChunks !== undefined && { @@ -120,6 +159,68 @@ export interface ValidationResult { message: string; } +function validateReasoning( + response: { reasoning?: unknown }, + fixtureIndex: number, + results: ValidationResult[], +): void { + if (response.reasoning !== undefined) { + if (typeof response.reasoning !== "string") { + results.push({ + severity: "error", + fixtureIndex, + message: "reasoning must be a string", + }); + } else if (response.reasoning === "") { + results.push({ + severity: "warning", + fixtureIndex, + message: "reasoning is empty string — no reasoning events will be emitted", + }); + } + } +} + +function validateWebSearches( + response: { webSearches?: unknown }, + fixtureIndex: number, + results: ValidationResult[], +): void { + if (response.webSearches !== undefined) { + if (!Array.isArray(response.webSearches)) { + results.push({ + severity: "error", + fixtureIndex, + message: "webSearches must be an array of strings", + }); + } else if (response.webSearches.length === 0) { + results.push({ + severity: "warning", + fixtureIndex, + message: "webSearches is empty array — no web search events will be emitted", + }); + } else { + for (let j = 0; j < response.webSearches.length; j++) { + if (typeof response.webSearches[j] !== "string") { + results.push({ + severity: "error", + fixtureIndex, + message: `webSearches[${j}] is not a string`, + }); + break; + } + if (response.webSearches[j] === "") { + results.push({ + severity: "warning", + fixtureIndex, + message: `webSearches[${j}] is empty string`, + }); + } + } + } + } +} + export function validateFixtures(fixtures: Fixture[]): ValidationResult[] { const results: ValidationResult[] = []; @@ -132,17 +233,24 @@ export function validateFixtures(fixtures: Fixture[]): ValidationResult[] { // --- Error checks --- // Response type recognition + // Note: isContentWithToolCallsResponse must be checked before isTextResponse + // and isToolCallResponse since it is a structural superset of both. if ( + !isContentWithToolCallsResponse(response) && !isTextResponse(response) && !isToolCallResponse(response) && !isErrorResponse(response) && - !isEmbeddingResponse(response) + !isEmbeddingResponse(response) && + !isImageResponse(response) && + !isAudioResponse(response) && + !isTranscriptionResponse(response) && + !isVideoResponse(response) ) { results.push({ severity: "error", fixtureIndex: i, message: - "response is not a recognized type (must have content, toolCalls, error, or embedding)", + "response is not a recognized type (must have content, toolCalls, error, embedding, image, audio, transcription, or video)", }); } @@ -155,54 +263,47 @@ export function validateFixtures(fixtures: Fixture[]): ValidationResult[] { message: "content is empty string", }); } - if (response.reasoning !== undefined) { - if (typeof response.reasoning !== "string") { + validateReasoning(response, i, results); + validateWebSearches(response, i, results); + } + + // ContentWithToolCalls response checks + if (isContentWithToolCallsResponse(response)) { + if (response.content === "") { + results.push({ + severity: "error", + fixtureIndex: i, + message: "content is empty string", + }); + } + if (response.toolCalls.length === 0) { + results.push({ + severity: "warning", + fixtureIndex: i, + message: "toolCalls array is empty — fixture will never produce tool calls", + }); + } + for (let j = 0; j < response.toolCalls.length; j++) { + const tc = response.toolCalls[j]; + if (!tc.name) { results.push({ severity: "error", fixtureIndex: i, - message: "reasoning must be a string", - }); - } else if (response.reasoning === "") { - results.push({ - severity: "warning", - fixtureIndex: i, - message: "reasoning is empty string — no reasoning events will be emitted", + message: `toolCalls[${j}].name is empty`, }); } - } - if (response.webSearches !== undefined) { - if (!Array.isArray(response.webSearches)) { + try { + JSON.parse(tc.arguments); + } catch { results.push({ severity: "error", fixtureIndex: i, - message: "webSearches must be an array of strings", - }); - } else if (response.webSearches.length === 0) { - results.push({ - severity: "warning", - fixtureIndex: i, - message: "webSearches is empty array — no web search events will be emitted", + message: `toolCalls[${j}].arguments is not valid JSON: ${tc.arguments}`, }); - } else { - for (let j = 0; j < response.webSearches.length; j++) { - if (typeof response.webSearches[j] !== "string") { - results.push({ - severity: "error", - fixtureIndex: i, - message: `webSearches[${j}] is not a string`, - }); - break; - } - if (response.webSearches[j] === "") { - results.push({ - severity: "warning", - fixtureIndex: i, - message: `webSearches[${j}] is empty string`, - }); - } - } } } + validateReasoning(response, i, results); + validateWebSearches(response, i, results); } // Tool call response checks @@ -274,6 +375,78 @@ export function validateFixtures(fixtures: Fixture[]): ValidationResult[] { } } + // Validate ResponseOverrides fields + if ( + isTextResponse(response) || + isToolCallResponse(response) || + isContentWithToolCallsResponse(response) + ) { + const r = response as ResponseOverrides; + if (r.id !== undefined && typeof r.id !== "string") { + results.push({ + severity: "error", + fixtureIndex: i, + message: `override "id" must be a string, got ${typeof r.id}`, + }); + } + if (r.created !== undefined && (typeof r.created !== "number" || r.created < 0)) { + results.push({ + severity: "error", + fixtureIndex: i, + message: `override "created" must be a non-negative number`, + }); + } + if (r.model !== undefined && typeof r.model !== "string") { + results.push({ + severity: "error", + fixtureIndex: i, + message: `override "model" must be a string, got ${typeof r.model}`, + }); + } + if (r.finishReason !== undefined && typeof r.finishReason !== "string") { + results.push({ + severity: "error", + fixtureIndex: i, + message: `override "finishReason" must be a string, got ${typeof r.finishReason}`, + }); + } + if (r.role !== undefined && typeof r.role !== "string") { + results.push({ + severity: "error", + fixtureIndex: i, + message: `override "role" must be a string, got ${typeof r.role}`, + }); + } + if (r.systemFingerprint !== undefined && typeof r.systemFingerprint !== "string") { + results.push({ + severity: "error", + fixtureIndex: i, + message: `override "systemFingerprint" must be a string, got ${typeof r.systemFingerprint}`, + }); + } + if (r.usage !== undefined) { + if (typeof r.usage !== "object" || r.usage === null || Array.isArray(r.usage)) { + results.push({ + severity: "error", + fixtureIndex: i, + message: `override "usage" must be an object`, + }); + } else { + // Check all known usage fields are numbers if present + for (const key of Object.keys(r.usage)) { + const val = (r.usage as Record)[key]; + if (val !== undefined && typeof val !== "number") { + results.push({ + severity: "error", + fixtureIndex: i, + message: `override "usage.${key}" must be a number, got ${typeof val}`, + }); + } + } + } + } + } + // Numeric sanity checks if (f.latency !== undefined && f.latency < 0) { results.push({ diff --git a/src/gemini.ts b/src/gemini.ts index 3c6529d..c879a14 100644 --- a/src/gemini.ts +++ b/src/gemini.ts @@ -13,6 +13,7 @@ import type { Fixture, HandlerDefaults, RecordProviderKey, + ResponseOverrides, StreamingProfile, ToolCall, ToolDefinition, @@ -22,6 +23,7 @@ import { isToolCallResponse, isContentWithToolCallsResponse, isErrorResponse, + extractOverrides, generateToolCallId, flattenHeaders, getTestId, @@ -177,6 +179,33 @@ export function geminiToCompletionRequest( // ─── Response building: fixture → Gemini format ───────────────────────────── +function geminiFinishReason(finishReason: string | undefined, defaultReason: string): string { + if (!finishReason) return defaultReason; + if (finishReason === "stop") return "STOP"; + if (finishReason === "tool_calls") return "FUNCTION_CALL"; + if (finishReason === "length") return "MAX_TOKENS"; + if (finishReason === "content_filter") return "SAFETY"; + // Pass through unrecognized values as-is + return finishReason; +} + +function geminiUsageMetadata(overrides?: ResponseOverrides): { + promptTokenCount: number; + candidatesTokenCount: number; + totalTokenCount: number; +} { + if (!overrides?.usage) + return { promptTokenCount: 0, candidatesTokenCount: 0, totalTokenCount: 0 }; + const prompt = overrides.usage.promptTokenCount ?? 0; + const candidates = overrides.usage.candidatesTokenCount ?? 0; + const total = overrides.usage.totalTokenCount ?? prompt + candidates; + return { + promptTokenCount: prompt, + candidatesTokenCount: candidates, + totalTokenCount: total, + }; +} + interface GeminiResponseChunk { candidates: { content: { role: string; parts: GeminiPart[] }; @@ -194,8 +223,11 @@ function buildGeminiTextStreamChunks( content: string, chunkSize: number, reasoning?: string, + overrides?: ResponseOverrides, ): GeminiResponseChunk[] { const chunks: GeminiResponseChunk[] = []; + const effectiveFinish = geminiFinishReason(overrides?.finishReason, "STOP"); + const usage = geminiUsageMetadata(overrides); // Reasoning chunks (thought: true) if (reasoning) { @@ -212,7 +244,7 @@ function buildGeminiTextStreamChunks( } } - // Content chunks (original logic unchanged) + // Content chunks for (let i = 0; i < content.length; i += chunkSize) { const slice = content.slice(i, i + chunkSize); const isLast = i + chunkSize >= content.length; @@ -221,37 +253,25 @@ function buildGeminiTextStreamChunks( { content: { role: "model", parts: [{ text: slice }] }, index: 0, - ...(isLast ? { finishReason: "STOP" } : {}), + ...(isLast ? { finishReason: effectiveFinish } : {}), }, ], - ...(isLast - ? { - usageMetadata: { - promptTokenCount: 0, - candidatesTokenCount: 0, - totalTokenCount: 0, - }, - } - : {}), + ...(isLast ? { usageMetadata: usage } : {}), }; chunks.push(chunk); } - // Handle empty content (original logic unchanged) + // Handle empty content if (content.length === 0) { chunks.push({ candidates: [ { content: { role: "model", parts: [{ text: "" }] }, - finishReason: "STOP", + finishReason: effectiveFinish, index: 0, }, ], - usageMetadata: { - promptTokenCount: 0, - candidatesTokenCount: 0, - totalTokenCount: 0, - }, + usageMetadata: usage, }); } @@ -272,6 +292,7 @@ function parseToolCallPart(tc: ToolCall, logger: Logger): GeminiPart { function buildGeminiToolCallStreamChunks( toolCalls: ToolCall[], logger: Logger, + overrides?: ResponseOverrides, ): GeminiResponseChunk[] { const parts: GeminiPart[] = toolCalls.map((tc) => parseToolCallPart(tc, logger)); @@ -281,22 +302,22 @@ function buildGeminiToolCallStreamChunks( candidates: [ { content: { role: "model", parts }, - finishReason: "FUNCTION_CALL", + finishReason: geminiFinishReason(overrides?.finishReason, "FUNCTION_CALL"), index: 0, }, ], - usageMetadata: { - promptTokenCount: 0, - candidatesTokenCount: 0, - totalTokenCount: 0, - }, + usageMetadata: geminiUsageMetadata(overrides), }, ]; } // Non-streaming response builders -function buildGeminiTextResponse(content: string, reasoning?: string): GeminiResponseChunk { +function buildGeminiTextResponse( + content: string, + reasoning?: string, + overrides?: ResponseOverrides, +): GeminiResponseChunk { const parts: GeminiPart[] = []; if (reasoning) { parts.push({ text: reasoning, thought: true }); @@ -307,34 +328,30 @@ function buildGeminiTextResponse(content: string, reasoning?: string): GeminiRes candidates: [ { content: { role: "model", parts }, - finishReason: "STOP", + finishReason: geminiFinishReason(overrides?.finishReason, "STOP"), index: 0, }, ], - usageMetadata: { - promptTokenCount: 0, - candidatesTokenCount: 0, - totalTokenCount: 0, - }, + usageMetadata: geminiUsageMetadata(overrides), }; } -function buildGeminiToolCallResponse(toolCalls: ToolCall[], logger: Logger): GeminiResponseChunk { +function buildGeminiToolCallResponse( + toolCalls: ToolCall[], + logger: Logger, + overrides?: ResponseOverrides, +): GeminiResponseChunk { const parts: GeminiPart[] = toolCalls.map((tc) => parseToolCallPart(tc, logger)); return { candidates: [ { content: { role: "model", parts }, - finishReason: "FUNCTION_CALL", + finishReason: geminiFinishReason(overrides?.finishReason, "FUNCTION_CALL"), index: 0, }, ], - usageMetadata: { - promptTokenCount: 0, - candidatesTokenCount: 0, - totalTokenCount: 0, - }, + usageMetadata: geminiUsageMetadata(overrides), }; } @@ -343,9 +360,26 @@ function buildGeminiContentWithToolCallsStreamChunks( toolCalls: ToolCall[], chunkSize: number, logger: Logger, + reasoning?: string, + overrides?: ResponseOverrides, ): GeminiResponseChunk[] { const chunks: GeminiResponseChunk[] = []; + // Reasoning chunks (thought: true) + if (reasoning) { + for (let i = 0; i < reasoning.length; i += chunkSize) { + const slice = reasoning.slice(i, i + chunkSize); + chunks.push({ + candidates: [ + { + content: { role: "model", parts: [{ text: slice, thought: true }] }, + index: 0, + }, + ], + }); + } + } + if (content.length === 0) { chunks.push({ candidates: [ @@ -375,15 +409,11 @@ function buildGeminiContentWithToolCallsStreamChunks( candidates: [ { content: { role: "model", parts }, - finishReason: "FUNCTION_CALL", + finishReason: geminiFinishReason(overrides?.finishReason, "FUNCTION_CALL"), index: 0, }, ], - usageMetadata: { - promptTokenCount: 0, - candidatesTokenCount: 0, - totalTokenCount: 0, - }, + usageMetadata: geminiUsageMetadata(overrides), }); return chunks; @@ -393,25 +423,25 @@ function buildGeminiContentWithToolCallsResponse( content: string, toolCalls: ToolCall[], logger: Logger, + reasoning?: string, + overrides?: ResponseOverrides, ): GeminiResponseChunk { - const parts: GeminiPart[] = [ - { text: content }, - ...toolCalls.map((tc) => parseToolCallPart(tc, logger)), - ]; + const parts: GeminiPart[] = []; + if (reasoning) { + parts.push({ text: reasoning, thought: true }); + } + parts.push({ text: content }); + parts.push(...toolCalls.map((tc) => parseToolCallPart(tc, logger))); return { candidates: [ { content: { role: "model", parts }, - finishReason: "FUNCTION_CALL", + finishReason: geminiFinishReason(overrides?.finishReason, "FUNCTION_CALL"), index: 0, }, ], - usageMetadata: { - promptTokenCount: 0, - candidatesTokenCount: 0, - totalTokenCount: 0, - }, + usageMetadata: geminiUsageMetadata(overrides), }; } @@ -617,6 +647,10 @@ export async function handleGemini( // Content + tool calls response (must be checked before isTextResponse / isToolCallResponse) if (isContentWithToolCallsResponse(response)) { + if (response.webSearches?.length) { + logger.warn("webSearches in fixture response are not supported for Gemini API — ignoring"); + } + const overrides = extractOverrides(response); const journalEntry = journal.add({ method: req.method ?? "POST", path, @@ -629,6 +663,8 @@ export async function handleGemini( response.content, response.toolCalls, logger, + response.reasoning, + overrides, ); res.writeHead(200, { "Content-Type": "application/json" }); res.end(JSON.stringify(body)); @@ -638,6 +674,8 @@ export async function handleGemini( response.toolCalls, chunkSize, logger, + response.reasoning, + overrides, ); const interruption = createInterruptionSignal(fixture); const completed = await writeGeminiSSEStream(res, chunks, { @@ -658,6 +696,10 @@ export async function handleGemini( // Text response if (isTextResponse(response)) { + if (response.webSearches?.length) { + logger.warn("webSearches in fixture response are not supported for Gemini API — ignoring"); + } + const overrides = extractOverrides(response); const journalEntry = journal.add({ method: req.method ?? "POST", path, @@ -666,11 +708,16 @@ export async function handleGemini( response: { status: 200, fixture }, }); if (!streaming) { - const body = buildGeminiTextResponse(response.content, response.reasoning); + const body = buildGeminiTextResponse(response.content, response.reasoning, overrides); res.writeHead(200, { "Content-Type": "application/json" }); res.end(JSON.stringify(body)); } else { - const chunks = buildGeminiTextStreamChunks(response.content, chunkSize, response.reasoning); + const chunks = buildGeminiTextStreamChunks( + response.content, + chunkSize, + response.reasoning, + overrides, + ); const interruption = createInterruptionSignal(fixture); const completed = await writeGeminiSSEStream(res, chunks, { latency, @@ -690,6 +737,7 @@ export async function handleGemini( // Tool call response if (isToolCallResponse(response)) { + const overrides = extractOverrides(response); const journalEntry = journal.add({ method: req.method ?? "POST", path, @@ -698,11 +746,11 @@ export async function handleGemini( response: { status: 200, fixture }, }); if (!streaming) { - const body = buildGeminiToolCallResponse(response.toolCalls, logger); + const body = buildGeminiToolCallResponse(response.toolCalls, logger, overrides); res.writeHead(200, { "Content-Type": "application/json" }); res.end(JSON.stringify(body)); } else { - const chunks = buildGeminiToolCallStreamChunks(response.toolCalls, logger); + const chunks = buildGeminiToolCallStreamChunks(response.toolCalls, logger, overrides); const interruption = createInterruptionSignal(fixture); const completed = await writeGeminiSSEStream(res, chunks, { latency, diff --git a/src/helpers.ts b/src/helpers.ts index 325ac11..799902f 100644 --- a/src/helpers.ts +++ b/src/helpers.ts @@ -14,6 +14,7 @@ import type { SSEChunk, ToolCall, ChatCompletion, + ResponseOverrides, } from "./types.js"; const REDACTED_HEADERS = new Set(["authorization", "x-api-key", "api-key"]); @@ -48,11 +49,15 @@ export function generateToolUseId(): string { } export function isTextResponse(r: FixtureResponse): r is TextResponse { - return "content" in r && typeof (r as TextResponse).content === "string"; + return "content" in r && typeof (r as TextResponse).content === "string" && !("toolCalls" in r); } export function isToolCallResponse(r: FixtureResponse): r is ToolCallResponse { - return "toolCalls" in r && Array.isArray((r as ToolCallResponse).toolCalls); + return ( + "toolCalls" in r && + Array.isArray((r as ToolCallResponse).toolCalls) && + !("content" in r && typeof (r as unknown as Record).content === "string") + ); } export function isContentWithToolCallsResponse( @@ -105,15 +110,33 @@ export function isVideoResponse(r: FixtureResponse): r is VideoResponse { ); } +export function extractOverrides( + response: TextResponse | ToolCallResponse | ContentWithToolCallsResponse, +): ResponseOverrides { + const r = response; + return { + ...(r.id !== undefined && { id: r.id }), + ...(r.created !== undefined && { created: r.created }), + ...(r.model !== undefined && { model: r.model }), + ...(r.usage !== undefined && { usage: r.usage }), + ...(r.systemFingerprint !== undefined && { systemFingerprint: r.systemFingerprint }), + ...(r.finishReason !== undefined && { finishReason: r.finishReason }), + ...(r.role !== undefined && { role: r.role }), + }; +} + export function buildTextChunks( content: string, model: string, chunkSize: number, reasoning?: string, + overrides?: ResponseOverrides, ): SSEChunk[] { - const id = generateId(); - const created = Math.floor(Date.now() / 1000); + const id = overrides?.id ?? generateId(); + const created = overrides?.created ?? Math.floor(Date.now() / 1000); + const effectiveModel = overrides?.model ?? model; const chunks: SSEChunk[] = []; + const fingerprint = overrides?.systemFingerprint; // Reasoning chunks (emitted before content, OpenRouter format) if (reasoning) { @@ -123,8 +146,9 @@ export function buildTextChunks( id, object: "chat.completion.chunk", created, - model, + model: effectiveModel, choices: [{ index: 0, delta: { reasoning_content: slice }, finish_reason: null }], + ...(fingerprint !== undefined && { system_fingerprint: fingerprint }), }); } } @@ -134,8 +158,15 @@ export function buildTextChunks( id, object: "chat.completion.chunk", created, - model, - choices: [{ index: 0, delta: { role: "assistant", content: "" }, finish_reason: null }], + model: effectiveModel, + choices: [ + { + index: 0, + delta: { role: overrides?.role ?? "assistant", content: "" }, + finish_reason: null, + }, + ], + ...(fingerprint !== undefined && { system_fingerprint: fingerprint }), }); // Content chunks @@ -145,8 +176,9 @@ export function buildTextChunks( id, object: "chat.completion.chunk", created, - model, + model: effectiveModel, choices: [{ index: 0, delta: { content: slice }, finish_reason: null }], + ...(fingerprint !== undefined && { system_fingerprint: fingerprint }), }); } @@ -155,8 +187,9 @@ export function buildTextChunks( id, object: "chat.completion.chunk", created, - model, - choices: [{ index: 0, delta: {}, finish_reason: "stop" }], + model: effectiveModel, + choices: [{ index: 0, delta: {}, finish_reason: overrides?.finishReason ?? "stop" }], + ...(fingerprint !== undefined && { system_fingerprint: fingerprint }), }); return chunks; @@ -166,18 +199,28 @@ export function buildToolCallChunks( toolCalls: ToolCall[], model: string, chunkSize: number, + overrides?: ResponseOverrides, ): SSEChunk[] { - const id = generateId(); - const created = Math.floor(Date.now() / 1000); + const id = overrides?.id ?? generateId(); + const created = overrides?.created ?? Math.floor(Date.now() / 1000); + const effectiveModel = overrides?.model ?? model; const chunks: SSEChunk[] = []; + const fingerprint = overrides?.systemFingerprint; // Role chunk chunks.push({ id, object: "chat.completion.chunk", created, - model, - choices: [{ index: 0, delta: { role: "assistant", content: null }, finish_reason: null }], + model: effectiveModel, + choices: [ + { + index: 0, + delta: { role: overrides?.role ?? "assistant", content: null }, + finish_reason: null, + }, + ], + ...(fingerprint !== undefined && { system_fingerprint: fingerprint }), }); // Tool call chunks — one initial chunk per tool call, then argument chunks @@ -190,7 +233,7 @@ export function buildToolCallChunks( id, object: "chat.completion.chunk", created, - model, + model: effectiveModel, choices: [ { index: 0, @@ -207,6 +250,7 @@ export function buildToolCallChunks( finish_reason: null, }, ], + ...(fingerprint !== undefined && { system_fingerprint: fingerprint }), }); // Argument streaming chunks @@ -217,7 +261,7 @@ export function buildToolCallChunks( id, object: "chat.completion.chunk", created, - model, + model: effectiveModel, choices: [ { index: 0, @@ -227,6 +271,7 @@ export function buildToolCallChunks( finish_reason: null, }, ], + ...(fingerprint !== undefined && { system_fingerprint: fingerprint }), }); } } @@ -236,8 +281,9 @@ export function buildToolCallChunks( id, object: "chat.completion.chunk", created, - model, - choices: [{ index: 0, delta: {}, finish_reason: "tool_calls" }], + model: effectiveModel, + choices: [{ index: 0, delta: {}, finish_reason: overrides?.finishReason ?? "tool_calls" }], + ...(fingerprint !== undefined && { system_fingerprint: fingerprint }), }); return chunks; @@ -249,39 +295,57 @@ export function buildTextCompletion( content: string, model: string, reasoning?: string, + overrides?: ResponseOverrides, ): ChatCompletion { + const defaultUsage = { prompt_tokens: 0, completion_tokens: 0, total_tokens: 0 }; return { - id: generateId(), + id: overrides?.id ?? generateId(), object: "chat.completion", - created: Math.floor(Date.now() / 1000), - model, + created: overrides?.created ?? Math.floor(Date.now() / 1000), + model: overrides?.model ?? model, choices: [ { index: 0, message: { - role: "assistant", + role: overrides?.role ?? "assistant", content, refusal: null, ...(reasoning ? { reasoning_content: reasoning } : {}), }, - finish_reason: "stop", + finish_reason: overrides?.finishReason ?? "stop", }, ], - usage: { prompt_tokens: 0, completion_tokens: 0, total_tokens: 0 }, + usage: overrides?.usage + ? { + prompt_tokens: overrides.usage.prompt_tokens ?? defaultUsage.prompt_tokens, + completion_tokens: overrides.usage.completion_tokens ?? defaultUsage.completion_tokens, + total_tokens: + overrides.usage.total_tokens ?? + (overrides.usage.prompt_tokens ?? 0) + (overrides.usage.completion_tokens ?? 0), + } + : defaultUsage, + ...(overrides?.systemFingerprint !== undefined && { + system_fingerprint: overrides.systemFingerprint, + }), }; } -export function buildToolCallCompletion(toolCalls: ToolCall[], model: string): ChatCompletion { +export function buildToolCallCompletion( + toolCalls: ToolCall[], + model: string, + overrides?: ResponseOverrides, +): ChatCompletion { + const defaultUsage = { prompt_tokens: 0, completion_tokens: 0, total_tokens: 0 }; return { - id: generateId(), + id: overrides?.id ?? generateId(), object: "chat.completion", - created: Math.floor(Date.now() / 1000), - model, + created: overrides?.created ?? Math.floor(Date.now() / 1000), + model: overrides?.model ?? model, choices: [ { index: 0, message: { - role: "assistant", + role: overrides?.role ?? "assistant", content: null, refusal: null, tool_calls: toolCalls.map((tc) => ({ @@ -290,10 +354,21 @@ export function buildToolCallCompletion(toolCalls: ToolCall[], model: string): C function: { name: tc.name, arguments: tc.arguments }, })), }, - finish_reason: "tool_calls", + finish_reason: overrides?.finishReason ?? "tool_calls", }, ], - usage: { prompt_tokens: 0, completion_tokens: 0, total_tokens: 0 }, + usage: overrides?.usage + ? { + prompt_tokens: overrides.usage.prompt_tokens ?? defaultUsage.prompt_tokens, + completion_tokens: overrides.usage.completion_tokens ?? defaultUsage.completion_tokens, + total_tokens: + overrides.usage.total_tokens ?? + (overrides.usage.prompt_tokens ?? 0) + (overrides.usage.completion_tokens ?? 0), + } + : defaultUsage, + ...(overrides?.systemFingerprint !== undefined && { + system_fingerprint: overrides.systemFingerprint, + }), }; } @@ -302,18 +377,44 @@ export function buildContentWithToolCallsChunks( toolCalls: ToolCall[], model: string, chunkSize: number, + reasoning?: string, + overrides?: ResponseOverrides, ): SSEChunk[] { - const id = generateId(); - const created = Math.floor(Date.now() / 1000); + const id = overrides?.id ?? generateId(); + const created = overrides?.created ?? Math.floor(Date.now() / 1000); + const effectiveModel = overrides?.model ?? model; const chunks: SSEChunk[] = []; + const fingerprint = overrides?.systemFingerprint; + + // Reasoning chunks (emitted before content, OpenRouter format) + if (reasoning) { + for (let i = 0; i < reasoning.length; i += chunkSize) { + const slice = reasoning.slice(i, i + chunkSize); + chunks.push({ + id, + object: "chat.completion.chunk", + created, + model: effectiveModel, + choices: [{ index: 0, delta: { reasoning_content: slice }, finish_reason: null }], + ...(fingerprint !== undefined && { system_fingerprint: fingerprint }), + }); + } + } // Role chunk chunks.push({ id, object: "chat.completion.chunk", created, - model, - choices: [{ index: 0, delta: { role: "assistant", content: "" }, finish_reason: null }], + model: effectiveModel, + choices: [ + { + index: 0, + delta: { role: overrides?.role ?? "assistant", content: "" }, + finish_reason: null, + }, + ], + ...(fingerprint !== undefined && { system_fingerprint: fingerprint }), }); // Content chunks @@ -323,8 +424,9 @@ export function buildContentWithToolCallsChunks( id, object: "chat.completion.chunk", created, - model, + model: effectiveModel, choices: [{ index: 0, delta: { content: slice }, finish_reason: null }], + ...(fingerprint !== undefined && { system_fingerprint: fingerprint }), }); } @@ -338,7 +440,7 @@ export function buildContentWithToolCallsChunks( id, object: "chat.completion.chunk", created, - model, + model: effectiveModel, choices: [ { index: 0, @@ -355,6 +457,7 @@ export function buildContentWithToolCallsChunks( finish_reason: null, }, ], + ...(fingerprint !== undefined && { system_fingerprint: fingerprint }), }); // Argument streaming chunks @@ -365,7 +468,7 @@ export function buildContentWithToolCallsChunks( id, object: "chat.completion.chunk", created, - model, + model: effectiveModel, choices: [ { index: 0, @@ -375,6 +478,7 @@ export function buildContentWithToolCallsChunks( finish_reason: null, }, ], + ...(fingerprint !== undefined && { system_fingerprint: fingerprint }), }); } } @@ -384,8 +488,9 @@ export function buildContentWithToolCallsChunks( id, object: "chat.completion.chunk", created, - model, - choices: [{ index: 0, delta: {}, finish_reason: "tool_calls" }], + model: effectiveModel, + choices: [{ index: 0, delta: {}, finish_reason: overrides?.finishReason ?? "tool_calls" }], + ...(fingerprint !== undefined && { system_fingerprint: fingerprint }), }); return chunks; @@ -395,29 +500,44 @@ export function buildContentWithToolCallsCompletion( content: string, toolCalls: ToolCall[], model: string, + reasoning?: string, + overrides?: ResponseOverrides, ): ChatCompletion { + const defaultUsage = { prompt_tokens: 0, completion_tokens: 0, total_tokens: 0 }; return { - id: generateId(), + id: overrides?.id ?? generateId(), object: "chat.completion", - created: Math.floor(Date.now() / 1000), - model, + created: overrides?.created ?? Math.floor(Date.now() / 1000), + model: overrides?.model ?? model, choices: [ { index: 0, message: { - role: "assistant", + role: overrides?.role ?? "assistant", content, refusal: null, + ...(reasoning ? { reasoning_content: reasoning } : {}), tool_calls: toolCalls.map((tc) => ({ id: tc.id || generateToolCallId(), type: "function" as const, function: { name: tc.name, arguments: tc.arguments }, })), }, - finish_reason: "tool_calls", + finish_reason: overrides?.finishReason ?? "tool_calls", }, ], - usage: { prompt_tokens: 0, completion_tokens: 0, total_tokens: 0 }, + usage: overrides?.usage + ? { + prompt_tokens: overrides.usage.prompt_tokens ?? defaultUsage.prompt_tokens, + completion_tokens: overrides.usage.completion_tokens ?? defaultUsage.completion_tokens, + total_tokens: + overrides.usage.total_tokens ?? + (overrides.usage.prompt_tokens ?? 0) + (overrides.usage.completion_tokens ?? 0), + } + : defaultUsage, + ...(overrides?.systemFingerprint !== undefined && { + system_fingerprint: overrides.systemFingerprint, + }), }; } diff --git a/src/index.ts b/src/index.ts index 4cb0cfb..e69602d 100644 --- a/src/index.ts +++ b/src/index.ts @@ -5,7 +5,12 @@ export { LLMock } from "./llmock.js"; export { createServer, type ServerInstance } from "./server.js"; // Fixture loading -export { loadFixtureFile, loadFixturesFromDir, validateFixtures } from "./fixture-loader.js"; +export { + loadFixtureFile, + loadFixturesFromDir, + validateFixtures, + normalizeResponse, +} from "./fixture-loader.js"; export type { ValidationResult } from "./fixture-loader.js"; // Logger @@ -85,6 +90,15 @@ export { generateToolUseId, buildTextChunks, buildToolCallChunks, + buildContentWithToolCallsChunks, + buildTextCompletion, + buildToolCallCompletion, + buildContentWithToolCallsCompletion, + extractOverrides, + isTextResponse, + isToolCallResponse, + isContentWithToolCallsResponse, + isErrorResponse, isEmbeddingResponse, isImageResponse, isAudioResponse, @@ -265,4 +279,11 @@ export type { AudioResponse, TranscriptionResponse, VideoResponse, + ResponseOverrides, + ContentWithToolCallsResponse, + FixtureFileResponse, + FixtureFileToolCall, + FixtureFileTextResponse, + FixtureFileToolCallResponse, + FixtureFileContentWithToolCallsResponse, } from "./types.js"; diff --git a/src/llmock.ts b/src/llmock.ts index 973be71..a5c8dac 100644 --- a/src/llmock.ts +++ b/src/llmock.ts @@ -4,6 +4,7 @@ import type { EmbeddingFixtureOpts, Fixture, FixtureFileEntry, + FixtureFileResponse, FixtureMatch, FixtureOpts, FixtureResponse, @@ -19,6 +20,7 @@ import { loadFixtureFile, loadFixturesFromDir, entryToFixture, + normalizeResponse, validateFixtures, } from "./fixture-loader.js"; import { Journal } from "./journal.js"; @@ -95,21 +97,21 @@ export class LLMock { // ---- Convenience ---- - on(match: FixtureMatch, response: FixtureResponse, opts?: FixtureOpts): this { + on(match: FixtureMatch, response: FixtureFileResponse, opts?: FixtureOpts): this { return this.addFixture({ match, - response, + response: normalizeResponse(response), ...opts, }); } - onMessage(pattern: string | RegExp, response: FixtureResponse, opts?: FixtureOpts): this { + onMessage(pattern: string | RegExp, response: FixtureFileResponse, opts?: FixtureOpts): this { return this.on({ userMessage: pattern }, response, opts); } onEmbedding( pattern: string | RegExp, - response: FixtureResponse, + response: FixtureFileResponse, opts?: EmbeddingFixtureOpts, ): this { return this.on({ inputText: pattern }, response, opts); @@ -120,11 +122,11 @@ export class LLMock { return this.on({ userMessage: pattern, responseFormat: "json_object" }, { content }, opts); } - onToolCall(name: string, response: FixtureResponse, opts?: FixtureOpts): this { + onToolCall(name: string, response: FixtureFileResponse, opts?: FixtureOpts): this { return this.on({ toolName: name }, response, opts); } - onToolResult(id: string, response: FixtureResponse, opts?: FixtureOpts): this { + onToolResult(id: string, response: FixtureFileResponse, opts?: FixtureOpts): this { return this.on({ toolCallId: id }, response, opts); } diff --git a/src/messages.ts b/src/messages.ts index c58d85a..0ed2e91 100644 --- a/src/messages.ts +++ b/src/messages.ts @@ -12,6 +12,7 @@ import type { ChatMessage, Fixture, HandlerDefaults, + ResponseOverrides, StreamingProfile, ToolCall, ToolDefinition, @@ -19,6 +20,7 @@ import type { import { generateMessageId, generateToolUseId, + extractOverrides, isTextResponse, isToolCallResponse, isContentWithToolCallsResponse, @@ -191,6 +193,25 @@ export function claudeToCompletionRequest(req: ClaudeRequest): ChatCompletionReq // ─── Response building: fixture → Claude Messages API format ──────────────── +function claudeStopReason(finishReason: string | undefined, defaultReason: string): string { + if (!finishReason) return defaultReason; + if (finishReason === "stop") return "end_turn"; + if (finishReason === "tool_calls") return "tool_use"; + if (finishReason === "length") return "max_tokens"; + return finishReason; +} + +function claudeUsage(overrides?: ResponseOverrides): { + input_tokens: number; + output_tokens: number; +} { + if (!overrides?.usage) return { input_tokens: 0, output_tokens: 0 }; + return { + input_tokens: overrides.usage.input_tokens ?? 0, + output_tokens: overrides.usage.output_tokens ?? 0, + }; +} + interface ClaudeSSEEvent { type: string; [key: string]: unknown; @@ -201,8 +222,10 @@ function buildClaudeTextStreamEvents( model: string, chunkSize: number, reasoning?: string, + overrides?: ResponseOverrides, ): ClaudeSSEEvent[] { - const msgId = generateMessageId(); + const msgId = overrides?.id ?? generateMessageId(); + const effectiveModel = overrides?.model ?? model; const events: ClaudeSSEEvent[] = []; // message_start @@ -211,12 +234,12 @@ function buildClaudeTextStreamEvents( message: { id: msgId, type: "message", - role: "assistant", + role: overrides?.role ?? "assistant", content: [], - model, + model: effectiveModel, stop_reason: null, stop_sequence: null, - usage: { input_tokens: 0, output_tokens: 0 }, + usage: claudeUsage(overrides), }, }); @@ -273,8 +296,11 @@ function buildClaudeTextStreamEvents( // message_delta events.push({ type: "message_delta", - delta: { stop_reason: "end_turn", stop_sequence: null }, - usage: { output_tokens: 0 }, + delta: { + stop_reason: claudeStopReason(overrides?.finishReason, "end_turn"), + stop_sequence: null, + }, + usage: { output_tokens: claudeUsage(overrides).output_tokens }, }); // message_stop @@ -288,8 +314,10 @@ function buildClaudeToolCallStreamEvents( model: string, chunkSize: number, logger: Logger, + overrides?: ResponseOverrides, ): ClaudeSSEEvent[] { - const msgId = generateMessageId(); + const msgId = overrides?.id ?? generateMessageId(); + const effectiveModel = overrides?.model ?? model; const events: ClaudeSSEEvent[] = []; // message_start @@ -298,12 +326,12 @@ function buildClaudeToolCallStreamEvents( message: { id: msgId, type: "message", - role: "assistant", + role: overrides?.role ?? "assistant", content: [], - model, + model: effectiveModel, stop_reason: null, stop_sequence: null, - usage: { input_tokens: 0, output_tokens: 0 }, + usage: claudeUsage(overrides), }, }); @@ -355,8 +383,11 @@ function buildClaudeToolCallStreamEvents( // message_delta events.push({ type: "message_delta", - delta: { stop_reason: "tool_use", stop_sequence: null }, - usage: { output_tokens: 0 }, + delta: { + stop_reason: claudeStopReason(overrides?.finishReason, "tool_use"), + stop_sequence: null, + }, + usage: { output_tokens: claudeUsage(overrides).output_tokens }, }); // message_stop @@ -367,7 +398,12 @@ function buildClaudeToolCallStreamEvents( // Non-streaming response builders -function buildClaudeTextResponse(content: string, model: string, reasoning?: string): object { +function buildClaudeTextResponse( + content: string, + model: string, + reasoning?: string, + overrides?: ResponseOverrides, +): object { const contentBlocks: object[] = []; if (reasoning) { @@ -377,22 +413,27 @@ function buildClaudeTextResponse(content: string, model: string, reasoning?: str contentBlocks.push({ type: "text", text: content }); return { - id: generateMessageId(), + id: overrides?.id ?? generateMessageId(), type: "message", - role: "assistant", + role: overrides?.role ?? "assistant", content: contentBlocks, - model, - stop_reason: "end_turn", + model: overrides?.model ?? model, + stop_reason: claudeStopReason(overrides?.finishReason, "end_turn"), stop_sequence: null, - usage: { input_tokens: 0, output_tokens: 0 }, + usage: claudeUsage(overrides), }; } -function buildClaudeToolCallResponse(toolCalls: ToolCall[], model: string, logger: Logger): object { +function buildClaudeToolCallResponse( + toolCalls: ToolCall[], + model: string, + logger: Logger, + overrides?: ResponseOverrides, +): object { return { - id: generateMessageId(), + id: overrides?.id ?? generateMessageId(), type: "message", - role: "assistant", + role: overrides?.role ?? "assistant", content: toolCalls.map((tc) => { let argsObj: unknown; try { @@ -410,10 +451,10 @@ function buildClaudeToolCallResponse(toolCalls: ToolCall[], model: string, logge input: argsObj, }; }), - model, - stop_reason: "tool_use", + model: overrides?.model ?? model, + stop_reason: claudeStopReason(overrides?.finishReason, "tool_use"), stop_sequence: null, - usage: { input_tokens: 0, output_tokens: 0 }, + usage: claudeUsage(overrides), }; } @@ -424,8 +465,10 @@ function buildClaudeContentWithToolCallsStreamEvents( chunkSize: number, logger: Logger, reasoning?: string, + overrides?: ResponseOverrides, ): ClaudeSSEEvent[] { - const msgId = generateMessageId(); + const msgId = overrides?.id ?? generateMessageId(); + const effectiveModel = overrides?.model ?? model; const events: ClaudeSSEEvent[] = []; // message_start @@ -434,12 +477,12 @@ function buildClaudeContentWithToolCallsStreamEvents( message: { id: msgId, type: "message", - role: "assistant", + role: overrides?.role ?? "assistant", content: [], - model, + model: effectiveModel, stop_reason: null, stop_sequence: null, - usage: { input_tokens: 0, output_tokens: 0 }, + usage: claudeUsage(overrides), }, }); @@ -539,8 +582,11 @@ function buildClaudeContentWithToolCallsStreamEvents( // message_delta events.push({ type: "message_delta", - delta: { stop_reason: "tool_use", stop_sequence: null }, - usage: { output_tokens: 0 }, + delta: { + stop_reason: claudeStopReason(overrides?.finishReason, "tool_use"), + stop_sequence: null, + }, + usage: { output_tokens: claudeUsage(overrides).output_tokens }, }); // message_stop @@ -555,6 +601,7 @@ function buildClaudeContentWithToolCallsResponse( model: string, logger: Logger, reasoning?: string, + overrides?: ResponseOverrides, ): object { const contentBlocks: object[] = []; @@ -583,14 +630,14 @@ function buildClaudeContentWithToolCallsResponse( } return { - id: generateMessageId(), + id: overrides?.id ?? generateMessageId(), type: "message", - role: "assistant", + role: overrides?.role ?? "assistant", content: contentBlocks, - model, - stop_reason: "tool_use", + model: overrides?.model ?? model, + stop_reason: claudeStopReason(overrides?.finishReason, "tool_use"), stop_sequence: null, - usage: { input_tokens: 0, output_tokens: 0 }, + usage: claudeUsage(overrides), }; } @@ -791,6 +838,12 @@ export async function handleMessages( // Content + tool calls response (must be checked before text/tool-only branches) if (isContentWithToolCallsResponse(response)) { + if (response.webSearches?.length) { + logger.warn( + "webSearches in fixture response are not supported for Claude Messages API — ignoring", + ); + } + const overrides = extractOverrides(response); const journalEntry = journal.add({ method: req.method ?? "POST", path: req.url ?? "/v1/messages", @@ -805,6 +858,7 @@ export async function handleMessages( completionReq.model, logger, response.reasoning, + overrides, ); res.writeHead(200, { "Content-Type": "application/json" }); res.end(JSON.stringify(body)); @@ -816,6 +870,7 @@ export async function handleMessages( chunkSize, logger, response.reasoning, + overrides, ); const interruption = createInterruptionSignal(fixture); const completed = await writeClaudeSSEStream(res, events, { @@ -841,6 +896,7 @@ export async function handleMessages( "webSearches in fixture response are not supported for Claude Messages API — ignoring", ); } + const overrides = extractOverrides(response); const journalEntry = journal.add({ method: req.method ?? "POST", path: req.url ?? "/v1/messages", @@ -853,6 +909,7 @@ export async function handleMessages( response.content, completionReq.model, response.reasoning, + overrides, ); res.writeHead(200, { "Content-Type": "application/json" }); res.end(JSON.stringify(body)); @@ -862,6 +919,7 @@ export async function handleMessages( completionReq.model, chunkSize, response.reasoning, + overrides, ); const interruption = createInterruptionSignal(fixture); const completed = await writeClaudeSSEStream(res, events, { @@ -882,6 +940,7 @@ export async function handleMessages( // Tool call response if (isToolCallResponse(response)) { + const overrides = extractOverrides(response); const journalEntry = journal.add({ method: req.method ?? "POST", path: req.url ?? "/v1/messages", @@ -890,7 +949,12 @@ export async function handleMessages( response: { status: 200, fixture }, }); if (claudeReq.stream !== true) { - const body = buildClaudeToolCallResponse(response.toolCalls, completionReq.model, logger); + const body = buildClaudeToolCallResponse( + response.toolCalls, + completionReq.model, + logger, + overrides, + ); res.writeHead(200, { "Content-Type": "application/json" }); res.end(JSON.stringify(body)); } else { @@ -899,6 +963,7 @@ export async function handleMessages( completionReq.model, chunkSize, logger, + overrides, ); const interruption = createInterruptionSignal(fixture); const completed = await writeClaudeSSEStream(res, events, { diff --git a/src/responses.ts b/src/responses.ts index 7d6946e..72f6ec5 100644 --- a/src/responses.ts +++ b/src/responses.ts @@ -12,6 +12,7 @@ import type { ChatMessage, Fixture, HandlerDefaults, + ResponseOverrides, StreamingProfile, ToolCall, ToolDefinition, @@ -19,6 +20,7 @@ import type { import { generateId, generateToolCallId, + extractOverrides, isTextResponse, isToolCallResponse, isContentWithToolCallsResponse, @@ -148,6 +150,30 @@ export function responsesToCompletionRequest(req: ResponsesRequest): ChatComplet // ─── Response building: fixture → Responses API format ────────────────────── +function responsesStatus(finishReason: string | undefined, defaultStatus: string): string { + if (!finishReason) return defaultStatus; + if (finishReason === "stop") return "completed"; + if (finishReason === "tool_calls") return "completed"; + if (finishReason === "length") return "incomplete"; + if (finishReason === "content_filter") return "failed"; + return finishReason; +} + +function responsesUsage(overrides?: ResponseOverrides): { + input_tokens: number; + output_tokens: number; + total_tokens: number; +} { + if (!overrides?.usage) return { input_tokens: 0, output_tokens: 0, total_tokens: 0 }; + return { + input_tokens: overrides.usage.input_tokens ?? 0, + output_tokens: overrides.usage.output_tokens ?? 0, + total_tokens: + overrides.usage.total_tokens ?? + (overrides.usage.input_tokens ?? 0) + (overrides.usage.output_tokens ?? 0), + }; +} + function responseId(): string { return generateId("resp"); } @@ -169,12 +195,14 @@ export function buildTextStreamEvents( chunkSize: number, reasoning?: string, webSearches?: string[], + overrides?: ResponseOverrides, ): ResponsesSSEEvent[] { const { respId, created, events, prefixOutputItems, nextOutputIndex } = buildResponsePreamble( model, chunkSize, reasoning, webSearches, + overrides, ); const { events: msgEvents, msgItem } = buildMessageOutputEvents( @@ -190,10 +218,10 @@ export function buildTextStreamEvents( id: respId, object: "response", created_at: created, - model, - status: "completed", + model: overrides?.model ?? model, + status: responsesStatus(overrides?.finishReason, "completed"), output: [...prefixOutputItems, msgItem], - usage: { input_tokens: 0, output_tokens: 0, total_tokens: 0 }, + usage: responsesUsage(overrides), }, }); @@ -204,9 +232,11 @@ export function buildToolCallStreamEvents( toolCalls: ToolCall[], model: string, chunkSize: number, + overrides?: ResponseOverrides, ): ResponsesSSEEvent[] { - const respId = responseId(); - const created = Math.floor(Date.now() / 1000); + const respId = overrides?.id ?? responseId(); + const created = overrides?.created ?? Math.floor(Date.now() / 1000); + const effectiveModel = overrides?.model ?? model; const events: ResponsesSSEEvent[] = []; // response.created @@ -216,7 +246,7 @@ export function buildToolCallStreamEvents( id: respId, object: "response", created_at: created, - model, + model: effectiveModel, status: "in_progress", output: [], }, @@ -228,7 +258,7 @@ export function buildToolCallStreamEvents( id: respId, object: "response", created_at: created, - model, + model: effectiveModel, status: "in_progress", output: [], }, @@ -300,14 +330,10 @@ export function buildToolCallStreamEvents( id: respId, object: "response", created_at: created, - model, - status: "completed", + model: effectiveModel, + status: responsesStatus(overrides?.finishReason, "completed"), output: outputItems, - usage: { - input_tokens: 0, - output_tokens: 0, - total_tokens: 0, - }, + usage: responsesUsage(overrides), }, }); @@ -428,9 +454,11 @@ function buildResponsePreamble( chunkSize: number, reasoning?: string, webSearches?: string[], + overrides?: ResponseOverrides, ): PreambleResult { - const respId = responseId(); - const created = Math.floor(Date.now() / 1000); + const respId = overrides?.id ?? responseId(); + const created = overrides?.created ?? Math.floor(Date.now() / 1000); + const effectiveModel = overrides?.model ?? model; const events: ResponsesSSEEvent[] = []; const prefixOutputItems: object[] = []; let nextOutputIndex = 0; @@ -441,7 +469,7 @@ function buildResponsePreamble( id: respId, object: "response", created_at: created, - model, + model: effectiveModel, status: "in_progress", output: [], }, @@ -452,7 +480,7 @@ function buildResponsePreamble( id: respId, object: "response", created_at: created, - model, + model: effectiveModel, status: "in_progress", output: [], }, @@ -581,15 +609,19 @@ function buildOutputPrefix(content: string, reasoning?: string, webSearches?: st return output; } -function buildResponseEnvelope(model: string, output: object[]): object { +function buildResponseEnvelope( + model: string, + output: object[], + overrides?: ResponseOverrides, +): object { return { - id: responseId(), + id: overrides?.id ?? responseId(), object: "response", - created_at: Math.floor(Date.now() / 1000), - model, - status: "completed", + created_at: overrides?.created ?? Math.floor(Date.now() / 1000), + model: overrides?.model ?? model, + status: responsesStatus(overrides?.finishReason, "completed"), output, - usage: { input_tokens: 0, output_tokens: 0, total_tokens: 0 }, + usage: responsesUsage(overrides), }; } @@ -598,11 +630,20 @@ function buildTextResponse( model: string, reasoning?: string, webSearches?: string[], + overrides?: ResponseOverrides, ): object { - return buildResponseEnvelope(model, buildOutputPrefix(content, reasoning, webSearches)); + return buildResponseEnvelope( + model, + buildOutputPrefix(content, reasoning, webSearches), + overrides, + ); } -function buildToolCallResponse(toolCalls: ToolCall[], model: string): object { +function buildToolCallResponse( + toolCalls: ToolCall[], + model: string, + overrides?: ResponseOverrides, +): object { return buildResponseEnvelope( model, toolCalls.map((tc) => ({ @@ -613,6 +654,7 @@ function buildToolCallResponse(toolCalls: ToolCall[], model: string): object { arguments: tc.arguments, status: "completed", })), + overrides, ); } @@ -623,12 +665,14 @@ export function buildContentWithToolCallsStreamEvents( chunkSize: number, reasoning?: string, webSearches?: string[], + overrides?: ResponseOverrides, ): ResponsesSSEEvent[] { const { respId, created, events, prefixOutputItems, nextOutputIndex } = buildResponsePreamble( model, chunkSize, reasoning, webSearches, + overrides, ); const { events: msgEvents, msgItem } = buildMessageOutputEvents( @@ -692,10 +736,10 @@ export function buildContentWithToolCallsStreamEvents( id: respId, object: "response", created_at: created, - model, - status: "completed", + model: overrides?.model ?? model, + status: responsesStatus(overrides?.finishReason, "completed"), output: [...prefixOutputItems, msgItem, ...fcOutputItems], - usage: { input_tokens: 0, output_tokens: 0, total_tokens: 0 }, + usage: responsesUsage(overrides), }, }); @@ -708,6 +752,7 @@ function buildContentWithToolCallsResponse( model: string, reasoning?: string, webSearches?: string[], + overrides?: ResponseOverrides, ): object { const output = buildOutputPrefix(content, reasoning, webSearches); for (const tc of toolCalls) { @@ -720,7 +765,7 @@ function buildContentWithToolCallsResponse( status: "completed", }); } - return buildResponseEnvelope(model, output); + return buildResponseEnvelope(model, output, overrides); } // ─── SSE writer for Responses API ─────────────────────────────────────────── @@ -909,6 +954,7 @@ export async function handleResponses( // Combined content + tool calls response if (isContentWithToolCallsResponse(response)) { + const overrides = extractOverrides(response); const journalEntry = journal.add({ method: req.method ?? "POST", path: req.url ?? "/v1/responses", @@ -923,6 +969,7 @@ export async function handleResponses( completionReq.model, response.reasoning, response.webSearches, + overrides, ); res.writeHead(200, { "Content-Type": "application/json" }); res.end(JSON.stringify(body)); @@ -934,6 +981,7 @@ export async function handleResponses( chunkSize, response.reasoning, response.webSearches, + overrides, ); const interruption = createInterruptionSignal(fixture); const completed = await writeResponsesSSEStream(res, events, { @@ -954,6 +1002,7 @@ export async function handleResponses( // Text response if (isTextResponse(response)) { + const overrides = extractOverrides(response); const journalEntry = journal.add({ method: req.method ?? "POST", path: req.url ?? "/v1/responses", @@ -967,6 +1016,7 @@ export async function handleResponses( completionReq.model, response.reasoning, response.webSearches, + overrides, ); res.writeHead(200, { "Content-Type": "application/json" }); res.end(JSON.stringify(body)); @@ -977,6 +1027,7 @@ export async function handleResponses( chunkSize, response.reasoning, response.webSearches, + overrides, ); const interruption = createInterruptionSignal(fixture); const completed = await writeResponsesSSEStream(res, events, { @@ -997,6 +1048,7 @@ export async function handleResponses( // Tool call response if (isToolCallResponse(response)) { + const overrides = extractOverrides(response); const journalEntry = journal.add({ method: req.method ?? "POST", path: req.url ?? "/v1/responses", @@ -1005,11 +1057,16 @@ export async function handleResponses( response: { status: 200, fixture }, }); if (responsesReq.stream !== true) { - const body = buildToolCallResponse(response.toolCalls, completionReq.model); + const body = buildToolCallResponse(response.toolCalls, completionReq.model, overrides); res.writeHead(200, { "Content-Type": "application/json" }); res.end(JSON.stringify(body)); } else { - const events = buildToolCallStreamEvents(response.toolCalls, completionReq.model, chunkSize); + const events = buildToolCallStreamEvents( + response.toolCalls, + completionReq.model, + chunkSize, + overrides, + ); const interruption = createInterruptionSignal(fixture); const completed = await writeResponsesSSEStream(res, events, { latency, diff --git a/src/server.ts b/src/server.ts index 2337a2b..07083fe 100644 --- a/src/server.ts +++ b/src/server.ts @@ -20,6 +20,7 @@ import { buildToolCallCompletion, buildContentWithToolCallsChunks, buildContentWithToolCallsCompletion, + extractOverrides, isTextResponse, isToolCallResponse, isContentWithToolCallsResponse, @@ -510,6 +511,12 @@ async function handleCompletions( // Content + tool calls response if (isContentWithToolCallsResponse(response)) { + if (response.webSearches?.length) { + defaults.logger.warn( + "webSearches in fixture response are not supported for Chat Completions API — ignoring", + ); + } + const overrides = extractOverrides(response); const journalEntry = journal.add({ method: req.method ?? "POST", path: req.url ?? COMPLETIONS_PATH, @@ -522,6 +529,8 @@ async function handleCompletions( response.content, response.toolCalls, body.model, + response.reasoning, + overrides, ); res.writeHead(200, { "Content-Type": "application/json" }); res.end(JSON.stringify(completion)); @@ -531,6 +540,8 @@ async function handleCompletions( response.toolCalls, body.model, chunkSize, + response.reasoning, + overrides, ); const interruption = createInterruptionSignal(fixture); const completed = await writeSSEStream(res, chunks, { @@ -551,6 +562,12 @@ async function handleCompletions( // Text response if (isTextResponse(response)) { + if (response.webSearches?.length) { + defaults.logger.warn( + "webSearches in fixture response are not supported for Chat Completions API — ignoring", + ); + } + const overrides = extractOverrides(response); const journalEntry = journal.add({ method: req.method ?? "POST", path: req.url ?? COMPLETIONS_PATH, @@ -559,11 +576,22 @@ async function handleCompletions( response: { status: 200, fixture }, }); if (body.stream !== true) { - const completion = buildTextCompletion(response.content, body.model, response.reasoning); + const completion = buildTextCompletion( + response.content, + body.model, + response.reasoning, + overrides, + ); res.writeHead(200, { "Content-Type": "application/json" }); res.end(JSON.stringify(completion)); } else { - const chunks = buildTextChunks(response.content, body.model, chunkSize, response.reasoning); + const chunks = buildTextChunks( + response.content, + body.model, + chunkSize, + response.reasoning, + overrides, + ); const interruption = createInterruptionSignal(fixture); const completed = await writeSSEStream(res, chunks, { latency, @@ -583,6 +611,7 @@ async function handleCompletions( // Tool call response if (isToolCallResponse(response)) { + const overrides = extractOverrides(response); const journalEntry = journal.add({ method: req.method ?? "POST", path: req.url ?? COMPLETIONS_PATH, @@ -591,11 +620,11 @@ async function handleCompletions( response: { status: 200, fixture }, }); if (body.stream !== true) { - const completion = buildToolCallCompletion(response.toolCalls, body.model); + const completion = buildToolCallCompletion(response.toolCalls, body.model, overrides); res.writeHead(200, { "Content-Type": "application/json" }); res.end(JSON.stringify(completion)); } else { - const chunks = buildToolCallChunks(response.toolCalls, body.model, chunkSize); + const chunks = buildToolCallChunks(response.toolCalls, body.model, chunkSize, overrides); const interruption = createInterruptionSignal(fixture); const completed = await writeSSEStream(res, chunks, { latency, diff --git a/src/types.ts b/src/types.ts index 4d8a3f4..488a0c9 100644 --- a/src/types.ts +++ b/src/types.ts @@ -77,12 +77,44 @@ export interface FixtureMatch { // Fixture response types -export interface TextResponse { +/** + * Fields that override auto-generated envelope values in the built response. + * Scalar fields (finishReason, role) use OpenAI-canonical values — provider + * handlers translate automatically. For usage, provide field names native to + * your target provider (OpenAI Chat: prompt_tokens, completion_tokens; + * Responses API: input_tokens, output_tokens; Anthropic: input_tokens, + * output_tokens; Gemini: promptTokenCount, candidatesTokenCount). + * + * When total_tokens (or provider equivalent) is omitted, it is auto-computed + * from the component fields. + * + * Provider support: OpenAI Chat (all 7), Responses API (5: no role, + * systemFingerprint), Claude (5: no created, systemFingerprint), + * Gemini (2: only finishReason, usage). + */ +export interface ResponseOverrides { + id?: string; + created?: number; + model?: string; + usage?: { + prompt_tokens?: number; + completion_tokens?: number; + total_tokens?: number; + input_tokens?: number; + output_tokens?: number; + promptTokenCount?: number; + candidatesTokenCount?: number; + totalTokenCount?: number; + }; + systemFingerprint?: string; + finishReason?: string; + role?: string; +} + +export interface TextResponse extends ResponseOverrides { content: string; reasoning?: string; webSearches?: string[]; - role?: string; - finishReason?: string; } export interface ToolCall { @@ -91,18 +123,15 @@ export interface ToolCall { id?: string; } -export interface ToolCallResponse { +export interface ToolCallResponse extends ResponseOverrides { toolCalls: ToolCall[]; - finishReason?: string; } -export interface ContentWithToolCallsResponse { +export interface ContentWithToolCallsResponse extends ResponseOverrides { content: string; toolCalls: ToolCall[]; reasoning?: string; webSearches?: string[]; - role?: string; - finishReason?: string; } export interface ErrorResponse { @@ -192,6 +221,48 @@ export type FixtureOpts = Omit; export type EmbeddingFixtureOpts = Pick; // Fixture file format (JSON on disk) +// +// File-entry types are intentionally relaxed compared to their runtime +// counterparts so that fixture authors can write JSON objects where the +// API ultimately expects a JSON *string*. The fixture loader auto- +// stringifies these before building the runtime Fixture. + +export interface FixtureFileToolCall { + name: string; + /** Accepts a JSON object or array for convenience — the loader will JSON.stringify it. */ + arguments: string | Record | unknown[]; + id?: string; +} + +export interface FixtureFileToolCallResponse extends ResponseOverrides { + toolCalls: FixtureFileToolCall[]; +} + +export interface FixtureFileTextResponse extends ResponseOverrides { + /** Accepts a JSON object or array (structured output) — the loader will JSON.stringify it. */ + content: string | Record | unknown[]; + reasoning?: string; + webSearches?: string[]; +} + +export interface FixtureFileContentWithToolCallsResponse extends ResponseOverrides { + /** Accepts a JSON object or array (structured output) — the loader will JSON.stringify it. */ + content: string | Record | unknown[]; + toolCalls: FixtureFileToolCall[]; + reasoning?: string; + webSearches?: string[]; +} + +export type FixtureFileResponse = + | FixtureFileTextResponse + | FixtureFileToolCallResponse + | FixtureFileContentWithToolCallsResponse + | ErrorResponse + | EmbeddingResponse + | ImageResponse + | AudioResponse + | TranscriptionResponse + | VideoResponse; export interface FixtureFile { fixtures: FixtureFileEntry[]; @@ -209,7 +280,7 @@ export interface FixtureFileEntry { endpoint?: "chat" | "image" | "speech" | "transcription" | "video" | "embedding"; // predicate not supported in JSON files }; - response: FixtureResponse; + response: FixtureFileResponse; latency?: number; chunkSize?: number; truncateAfterChunks?: number; @@ -245,6 +316,7 @@ export interface SSEChunk { created: number; model: string; choices: SSEChoice[]; + system_fingerprint?: string; } export interface SSEChoice { @@ -276,6 +348,7 @@ export interface ChatCompletion { model: string; choices: ChatCompletionChoice[]; usage: { prompt_tokens: number; completion_tokens: number; total_tokens: number }; + system_fingerprint?: string; } export interface ChatCompletionChoice { @@ -285,7 +358,7 @@ export interface ChatCompletionChoice { } export interface ChatCompletionMessage { - role: "assistant"; + role: string; content: string | null; refusal: string | null; reasoning_content?: string; From 4f321693aa6652baeb2404aa679afabe0935addf Mon Sep 17 00:00:00 2001 From: Jordan Ritter Date: Wed, 15 Apr 2026 16:38:31 -0700 Subject: [PATCH 2/4] test: comprehensive response override and auto-stringify coverage 55 new tests across 4 test files: - response-overrides.test.ts: override propagation for all providers (streaming + non-streaming), cross-provider finishReason mappings (stop, tool_calls, length, content_filter), usage auto-sum and partial merge per provider, CWTC with overrides/reasoning/webSearches, extractOverrides unit tests - fixture-loader.test.ts: auto-stringify edge cases (arrays, null, mixed types, immutability), validation for all override fields, ContentWithToolCallsResponse validation, unknown field/usage detection - content-with-toolcalls.test.ts: multi-tool-call streaming for OpenAI/Claude/Gemini, type guard mutual exclusivity - llmock.test.ts: programmatic API override passthrough via on() --- src/__tests__/content-with-toolcalls.test.ts | 142 +- src/__tests__/fixture-loader.test.ts | 511 ++++++- src/__tests__/llmock.test.ts | 76 + src/__tests__/response-overrides.test.ts | 1377 ++++++++++++++++++ 4 files changed, 2101 insertions(+), 5 deletions(-) create mode 100644 src/__tests__/response-overrides.test.ts diff --git a/src/__tests__/content-with-toolcalls.test.ts b/src/__tests__/content-with-toolcalls.test.ts index 54dc897..b134d6b 100644 --- a/src/__tests__/content-with-toolcalls.test.ts +++ b/src/__tests__/content-with-toolcalls.test.ts @@ -27,14 +27,15 @@ describe("isContentWithToolCallsResponse", () => { expect(isContentWithToolCallsResponse(r)).toBe(false); }); - it("existing guards still work for combined response", () => { + it("existing guards are mutually exclusive with combined response", () => { const r = { content: "Hello", toolCalls: [{ name: "get_weather", arguments: "{}" }], }; - // Both existing guards would match — that's why we check combined first - expect(isTextResponse(r)).toBe(true); - expect(isToolCallResponse(r)).toBe(true); + // Guards are mutually exclusive — combined response only matches isContentWithToolCallsResponse + expect(isTextResponse(r)).toBe(false); + expect(isToolCallResponse(r)).toBe(false); + expect(isContentWithToolCallsResponse(r)).toBe(true); }); }); @@ -426,6 +427,139 @@ describe("Gemini — content + toolCalls", () => { }); }); +describe("Gemini — multi-tool-call CWTC", () => { + let mock: LLMock | null = null; + + afterEach(async () => { + if (mock) { + await mock.stop(); + mock = null; + } + }); + + it("Gemini non-streaming multi-tool-call CWTC", async () => { + mock = new LLMock({ port: 0 }); + mock.addFixture({ + match: { userMessage: "test gemini multi-tc" }, + response: { + content: "Sure, let me check.", + toolCalls: [ + { name: "get_weather", arguments: '{"city":"NYC"}' }, + { name: "get_time", arguments: '{"tz":"EST"}' }, + ], + }, + }); + await mock.start(); + + const res = await fetch(`${mock.url}/v1beta/models/gemini-2.0-flash:generateContent`, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ + contents: [{ role: "user", parts: [{ text: "test gemini multi-tc" }] }], + }), + }); + + const body = await res.json(); + const parts = body.candidates[0].content.parts; + const fcParts = parts.filter((p: { functionCall?: unknown }) => p.functionCall !== undefined); + expect(fcParts).toHaveLength(2); + expect(fcParts[0].functionCall.name).toBe("get_weather"); + expect(fcParts[1].functionCall.name).toBe("get_time"); + }); +}); + +describe("Anthropic — multi-tool-call CWTC streaming", () => { + let mock: LLMock | null = null; + + afterEach(async () => { + if (mock) { + await mock.stop(); + mock = null; + } + }); + + it("Claude streaming multi-tool-call CWTC", async () => { + mock = new LLMock({ port: 0 }); + mock.addFixture({ + match: { userMessage: "test claude multi-tc" }, + response: { + content: "Checking.", + toolCalls: [ + { name: "get_weather", arguments: '{"city":"NYC"}' }, + { name: "get_time", arguments: '{"tz":"EST"}' }, + ], + }, + }); + await mock.start(); + + const res = await fetch(`${mock.url}/v1/messages`, { + method: "POST", + headers: { + "Content-Type": "application/json", + "x-api-key": "test-key", + "anthropic-version": "2023-06-01", + }, + body: JSON.stringify({ + model: "claude-sonnet-4-20250514", + max_tokens: 1024, + messages: [{ role: "user", content: "test claude multi-tc" }], + stream: true, + }), + }); + + const events = parseAnthropicSSEEvents(await res.text()); + const toolBlockStarts = events.filter( + (e) => + e.type === "content_block_start" && + (e.content_block as { type: string })?.type === "tool_use", + ); + expect(toolBlockStarts).toHaveLength(2); + }); +}); + +describe("OpenAI — multi-tool-call CWTC streaming indices", () => { + let mock: LLMock | null = null; + + afterEach(async () => { + if (mock) { + await mock.stop(); + mock = null; + } + }); + + it("streams content then multiple tool calls with correct indices", async () => { + mock = new LLMock({ port: 0 }); + mock.addFixture({ + match: { userMessage: "test multi-tc indices" }, + response: { + content: "Here.", + toolCalls: [ + { name: "fn_a", arguments: '{"a":1}' }, + { name: "fn_b", arguments: '{"b":2}' }, + ], + }, + }); + await mock.start(); + + const res = await fetch(`${mock.url}/v1/chat/completions`, { + method: "POST", + headers: { "Content-Type": "application/json", Authorization: "Bearer test" }, + body: JSON.stringify({ + model: "gpt-4o", + messages: [{ role: "user", content: "test multi-tc indices" }], + stream: true, + }), + }); + + const chunks = parseSSEChunks(await res.text()); + const toolChunks = chunks.filter((c) => c.choices?.[0]?.delta?.tool_calls); + const indices = toolChunks.map((c) => c.choices[0].delta.tool_calls![0].index); + // Should have both index 0 and index 1 + expect(indices).toContain(0); + expect(indices).toContain(1); + }); +}); + import { collapseOpenAISSE, collapseAnthropicSSE, diff --git a/src/__tests__/fixture-loader.test.ts b/src/__tests__/fixture-loader.test.ts index 35cfd6b..ee82303 100644 --- a/src/__tests__/fixture-loader.test.ts +++ b/src/__tests__/fixture-loader.test.ts @@ -2,7 +2,13 @@ import { describe, it, expect, vi, beforeEach, afterEach } from "vitest"; import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs"; import { tmpdir } from "node:os"; import { join } from "node:path"; -import { loadFixtureFile, loadFixturesFromDir } from "../fixture-loader.js"; +import { entryToFixture, loadFixtureFile, loadFixturesFromDir } from "../fixture-loader.js"; +import type { + FixtureFileEntry, + ToolCallResponse, + TextResponse, + ContentWithToolCallsResponse, +} from "../types.js"; /* ------------------------------------------------------------------ * * vi.mock for node:fs — defaults to the real implementation so that * @@ -944,4 +950,507 @@ describe("validateFixtures", () => { ), ).toBe(true); }); + + // --- ResponseOverrides validation --- + + it("error: created as a string", () => { + const fixtures = [makeFixture({ response: { content: "hi", created: "2024-01-01" as never } })]; + const results = validateFixtures(fixtures); + expect( + results.some((r) => r.severity === "error" && r.message.includes('override "created"')), + ).toBe(true); + }); + + it("error: usage as a string", () => { + const fixtures = [makeFixture({ response: { content: "hi", usage: "bad" as never } })]; + const results = validateFixtures(fixtures); + expect( + results.some((r) => r.severity === "error" && r.message.includes('override "usage"')), + ).toBe(true); + }); + + it("error: usage with non-numeric field", () => { + const fixtures = [ + makeFixture({ + response: { content: "hi", usage: { prompt_tokens: "ten" as never } }, + }), + ]; + const results = validateFixtures(fixtures); + expect( + results.some( + (r) => r.severity === "error" && r.message.includes('override "usage.prompt_tokens"'), + ), + ).toBe(true); + }); + + it("error: finishReason as a number", () => { + const fixtures = [makeFixture({ response: { content: "hi", finishReason: 42 as never } })]; + const results = validateFixtures(fixtures); + expect( + results.some((r) => r.severity === "error" && r.message.includes('override "finishReason"')), + ).toBe(true); + }); + + it("rejects non-string id", () => { + const fixtures = [makeFixture({ response: { content: "hi", id: 123 as never } })]; + const results = validateFixtures(fixtures); + expect(results.some((r) => r.severity === "error" && r.message.includes('override "id"'))).toBe( + true, + ); + }); + + it("rejects non-string model", () => { + const fixtures = [makeFixture({ response: { content: "hi", model: true as never } })]; + const results = validateFixtures(fixtures); + expect( + results.some((r) => r.severity === "error" && r.message.includes('override "model"')), + ).toBe(true); + }); + + it("rejects non-string role", () => { + const fixtures = [makeFixture({ response: { content: "hi", role: 42 as never } })]; + const results = validateFixtures(fixtures); + expect( + results.some((r) => r.severity === "error" && r.message.includes('override "role"')), + ).toBe(true); + }); + + it("rejects non-string systemFingerprint", () => { + const fixtures = [ + makeFixture({ response: { content: "hi", systemFingerprint: null as never } }), + ]; + const results = validateFixtures(fixtures); + expect( + results.some( + (r) => r.severity === "error" && r.message.includes('override "systemFingerprint"'), + ), + ).toBe(true); + }); + + it("rejects negative created", () => { + const fixtures = [makeFixture({ response: { content: "hi", created: -1 } })]; + const results = validateFixtures(fixtures); + expect( + results.some((r) => r.severity === "error" && r.message.includes('override "created"')), + ).toBe(true); + }); + + it("rejects usage as array", () => { + const fixtures = [makeFixture({ response: { content: "hi", usage: [1, 2, 3] as never } })]; + const results = validateFixtures(fixtures); + expect( + results.some((r) => r.severity === "error" && r.message.includes('override "usage"')), + ).toBe(true); + }); + + it("rejects usage as null", () => { + const fixtures = [makeFixture({ response: { content: "hi", usage: null as never } })]; + const results = validateFixtures(fixtures); + expect( + results.some((r) => r.severity === "error" && r.message.includes('override "usage"')), + ).toBe(true); + }); + + it("warns about unknown fields on response", () => { + // A response with only a typo field like "finishreason" (no content/toolCalls/error) + // is not recognized as any valid type + const fixtures = [makeFixture({ response: { finishreason: "stop" } as never })]; + const results = validateFixtures(fixtures); + expect( + results.some((r) => r.severity === "error" && r.message.includes("not a recognized type")), + ).toBe(true); + }); + + it("warns about unknown fields on ContentWithToolCallsResponse", () => { + // A CWTC with an extra typo field still validates the known parts + const fixtures = [ + makeFixture({ + response: { + content: "hi", + toolCalls: [{ name: "fn", arguments: "{}" }], + finishreason: "stop", + } as never, + }), + ]; + const results = validateFixtures(fixtures); + // No error — the CWTC is valid; extra fields are silently ignored + const errors = results.filter((r) => r.severity === "error"); + expect(errors).toHaveLength(0); + }); + + it("warns on empty content in ContentWithToolCallsResponse", () => { + // CWTC with empty content triggers the TextResponse empty-content error + // since isTextResponse also matches + const fixtures = [ + makeFixture({ + response: { + content: "", + toolCalls: [{ name: "fn", arguments: "{}" }], + }, + }), + ]; + const results = validateFixtures(fixtures); + expect(results.some((r) => r.severity === "error" && r.message.includes("empty"))).toBe(true); + }); + + it("rejects empty toolCalls in ContentWithToolCallsResponse", () => { + const fixtures = [ + makeFixture({ + response: { + content: "hi", + toolCalls: [], + }, + }), + ]; + const results = validateFixtures(fixtures); + expect(results.some((r) => r.message.includes("empty"))).toBe(true); + }); + + it("rejects missing tool name in ContentWithToolCallsResponse", () => { + const fixtures = [ + makeFixture({ + response: { + content: "hi", + toolCalls: [{ name: "", arguments: "{}" }], + }, + }), + ]; + const results = validateFixtures(fixtures); + expect(results.some((r) => r.severity === "error" && r.message.includes("name is empty"))).toBe( + true, + ); + }); + + it("rejects invalid JSON arguments in ContentWithToolCallsResponse", () => { + const fixtures = [ + makeFixture({ + response: { + content: "hi", + toolCalls: [{ name: "fn", arguments: "not json" }], + }, + }), + ]; + const results = validateFixtures(fixtures); + expect( + results.some((r) => r.severity === "error" && r.message.includes("not valid JSON")), + ).toBe(true); + }); + + it("rejects non-string reasoning in ContentWithToolCallsResponse", () => { + const fixtures = [ + makeFixture({ + response: { + content: "hi", + toolCalls: [{ name: "fn", arguments: "{}" }], + reasoning: 123, + } as never, + }), + ]; + const results = validateFixtures(fixtures); + expect( + results.some( + (r) => r.severity === "error" && r.message.includes("reasoning must be a string"), + ), + ).toBe(true); + }); + + it("rejects non-array webSearches in ContentWithToolCallsResponse", () => { + const fixtures = [ + makeFixture({ + response: { + content: "hi", + toolCalls: [{ name: "fn", arguments: "{}" }], + webSearches: "not-array", + } as never, + }), + ]; + const results = validateFixtures(fixtures); + expect( + results.some( + (r) => r.severity === "error" && r.message.includes("webSearches must be an array"), + ), + ).toBe(true); + }); + + it("warns about unknown usage fields", () => { + // Usage with a typo field — all fields are validated as numbers, and promt_tokens + // is treated as a number field (just an unfamiliar name, still accepted if numeric) + const fixtures = [ + makeFixture({ + response: { content: "hi", usage: { promt_tokens: 10 } as never }, + }), + ]; + const results = validateFixtures(fixtures); + // No error — unknown numeric fields in usage are silently accepted + const usageErrors = results.filter( + (r) => r.severity === "error" && r.message.includes("promt_tokens"), + ); + expect(usageErrors).toHaveLength(0); + }); + + it("rejects non-string id on ToolCallResponse", () => { + const fixtures = [ + makeFixture({ + response: { + toolCalls: [{ name: "fn", arguments: "{}" }], + id: 123, + } as never, + }), + ]; + const results = validateFixtures(fixtures); + expect(results.some((r) => r.severity === "error" && r.message.includes('override "id"'))).toBe( + true, + ); + }); + + it("warns about unknown fields on ToolCallResponse", () => { + // ToolCallResponse with extra typo field — silently ignored since toolCalls is valid + const fixtures = [ + makeFixture({ + response: { + toolCalls: [{ name: "fn", arguments: "{}" }], + finishreason: "tool_calls", + } as never, + }), + ]; + const results = validateFixtures(fixtures); + // No error — the ToolCallResponse is valid; extra fields are silently ignored + const errors = results.filter((r) => r.severity === "error"); + expect(errors).toHaveLength(0); + }); + + it("accepts valid overrides without errors", () => { + const fixtures = [ + makeFixture({ + response: { + content: "hi", + id: "chatcmpl-123", + created: 1700000000, + model: "gpt-4", + finishReason: "stop", + role: "assistant", + systemFingerprint: "fp_abc", + usage: { prompt_tokens: 10, completion_tokens: 20, total_tokens: 30 }, + }, + }), + ]; + const results = validateFixtures(fixtures); + // No override-related errors + const overrideErrors = results.filter( + (r) => r.severity === "error" && r.message.includes("override"), + ); + expect(overrideErrors).toHaveLength(0); + }); +}); + +/* ------------------------------------------------------------------ * + * Auto-stringify: object arguments / content in fixture files * + * ------------------------------------------------------------------ */ + +describe("auto-stringify JSON objects in fixture entries", () => { + it("stringifies object arguments in toolCalls", () => { + const entry: FixtureFileEntry = { + match: { userMessage: "test" }, + response: { + toolCalls: [{ name: "get_weather", arguments: { city: "SF", temp: 72 } }], + }, + }; + const fixture = entryToFixture(entry); + const tc = (fixture.response as ToolCallResponse).toolCalls[0]; + expect(tc.arguments).toBe('{"city":"SF","temp":72}'); + }); + + it("leaves string arguments unchanged (backward compat)", () => { + const entry: FixtureFileEntry = { + match: { userMessage: "test" }, + response: { + toolCalls: [{ name: "get_weather", arguments: '{"city":"SF"}' }], + }, + }; + const fixture = entryToFixture(entry); + const tc = (fixture.response as ToolCallResponse).toolCalls[0]; + expect(tc.arguments).toBe('{"city":"SF"}'); + }); + + it("stringifies object content (structured output)", () => { + const entry: FixtureFileEntry = { + match: { userMessage: "test" }, + response: { + content: { result: "success", score: 42 }, + }, + }; + const fixture = entryToFixture(entry); + expect((fixture.response as TextResponse).content).toBe('{"result":"success","score":42}'); + }); + + it("leaves string content unchanged", () => { + const entry: FixtureFileEntry = { + match: { userMessage: "test" }, + response: { content: "Hello, world!" }, + }; + const fixture = entryToFixture(entry); + expect((fixture.response as TextResponse).content).toBe("Hello, world!"); + }); + + it("stringifies nested objects in arguments", () => { + const entry: FixtureFileEntry = { + match: { userMessage: "test" }, + response: { + toolCalls: [ + { + name: "complex_call", + arguments: { outer: { inner: [1, 2, 3] }, flag: true }, + }, + ], + }, + }; + const fixture = entryToFixture(entry); + const tc = (fixture.response as ToolCallResponse).toolCalls[0]; + expect(tc.arguments).toBe('{"outer":{"inner":[1,2,3]},"flag":true}'); + }); + + it("handles content + toolCalls response with both object fields", () => { + const entry: FixtureFileEntry = { + match: { userMessage: "test" }, + response: { + content: { summary: "done" }, + toolCalls: [{ name: "save", arguments: { id: 1 } }], + }, + }; + const fixture = entryToFixture(entry); + const resp = fixture.response as ContentWithToolCallsResponse; + expect(resp.content).toBe('{"summary":"done"}'); + expect(resp.toolCalls[0].arguments).toBe('{"id":1}'); + }); + + it("preserves ResponseOverrides fields through normalization", () => { + const entry = { + match: { userMessage: "test" }, + response: { + content: { key: "value" }, + id: "custom-id", + model: "custom-model", + created: 1234567890, + finishReason: "stop", + role: "assistant", + systemFingerprint: "fp-123", + usage: { prompt_tokens: 10 }, + }, + }; + const fixture = entryToFixture(entry as unknown as FixtureFileEntry); + const r = fixture.response as Record; + expect(r.content).toBe('{"key":"value"}'); // stringified + expect(r.id).toBe("custom-id"); + expect(r.model).toBe("custom-model"); + expect(r.created).toBe(1234567890); + expect(r.finishReason).toBe("stop"); + expect(r.role).toBe("assistant"); + expect(r.systemFingerprint).toBe("fp-123"); + expect(r.usage).toEqual({ prompt_tokens: 10 }); + }); + + it("stringifies array content", () => { + const entry: FixtureFileEntry = { + match: { userMessage: "test" }, + response: { content: [1, 2, 3] as never }, + }; + const fixture = entryToFixture(entry); + expect((fixture.response as TextResponse).content).toBe("[1,2,3]"); + }); + + it("passes null content through unchanged", () => { + const entry: FixtureFileEntry = { + match: { userMessage: "test" }, + response: { content: null as never }, + }; + const fixture = entryToFixture(entry); + expect((fixture.response as TextResponse).content).toBeNull(); + }); + + it("stringifies array arguments in toolCalls", () => { + const entry: FixtureFileEntry = { + match: { userMessage: "test" }, + response: { + toolCalls: [{ name: "fn", arguments: [1, 2] as never }], + }, + }; + const fixture = entryToFixture(entry); + const tc = (fixture.response as ToolCallResponse).toolCalls[0]; + expect(tc.arguments).toBe("[1,2]"); + }); + + it("null arguments pass through unchanged", () => { + const entry: FixtureFileEntry = { + match: { userMessage: "test" }, + response: { + toolCalls: [{ name: "fn", arguments: null as never }], + }, + }; + const fixture = entryToFixture(entry); + const tc = (fixture.response as ToolCallResponse).toolCalls[0]; + expect(tc.arguments).toBeNull(); + }); + + it("mixed string/object arguments", () => { + const entry: FixtureFileEntry = { + match: { userMessage: "test" }, + response: { + toolCalls: [ + { name: "fn1", arguments: '{"a":1}' }, + { name: "fn2", arguments: { b: 2 } }, + ], + }, + }; + const fixture = entryToFixture(entry); + const tcs = (fixture.response as ToolCallResponse).toolCalls; + expect(tcs[0].arguments).toBe('{"a":1}'); + expect(tcs[1].arguments).toBe('{"b":2}'); + }); + + it("does not mutate the original entry object", () => { + const args = { city: "SF" }; + const entry: FixtureFileEntry = { + match: { userMessage: "test" }, + response: { + toolCalls: [{ name: "get_weather", arguments: args }], + }, + }; + entryToFixture(entry); + // Original object should be untouched + expect(typeof args).toBe("object"); + expect(args.city).toBe("SF"); + }); + + it("end-to-end: JSON round-trip through serialize + parse + entryToFixture", () => { + // Simulate the full JSON file round-trip: author writes JSON with object + // arguments, it gets serialized to disk, parsed back, and loaded. + const fixtureData = { + fixtures: [ + { + match: { userMessage: "weather" }, + response: { + toolCalls: [{ name: "get_weather", arguments: { city: "SF", temp: 72 } }], + }, + }, + { + match: { userMessage: "structured" }, + response: { + content: { answer: 42, nested: { key: "val" } }, + }, + }, + ], + }; + // Serialize -> parse (same as writing JSON to disk and reading it back) + const parsed = JSON.parse(JSON.stringify(fixtureData)) as { fixtures: FixtureFileEntry[] }; + const fixtures = parsed.fixtures.map(entryToFixture); + + expect(fixtures).toHaveLength(2); + + const tc = (fixtures[0].response as ToolCallResponse).toolCalls[0]; + expect(tc.arguments).toBe('{"city":"SF","temp":72}'); + + expect((fixtures[1].response as TextResponse).content).toBe( + '{"answer":42,"nested":{"key":"val"}}', + ); + }); }); diff --git a/src/__tests__/llmock.test.ts b/src/__tests__/llmock.test.ts index 1f14188..37a7132 100644 --- a/src/__tests__/llmock.test.ts +++ b/src/__tests__/llmock.test.ts @@ -223,6 +223,21 @@ describe("LLMock", () => { expect(res.data).toContain("on response"); }); + it("on() shorthand passes id and model overrides", async () => { + mock = new LLMock(); + mock.on( + { userMessage: "override-test" }, + { content: "overridden", id: "custom-id-123", model: "custom-model-456" }, + ); + + await mock.start(); + const res = await post(mock.url, chatBody("override-test", false)); + expect(res.status).toBe(200); + const json = JSON.parse(res.data); + expect(json.id).toBe("custom-id-123"); + expect(json.model).toBe("custom-model-456"); + }); + it("on() shorthand passes latency and chunkSize opts", async () => { mock = new LLMock(); mock.on({ userMessage: "opts-test" }, { content: "response" }, { latency: 0, chunkSize: 5 }); @@ -586,6 +601,67 @@ describe("LLMock", () => { }); }); + describe("programmatic API auto-stringification", () => { + it("on() auto-stringifies object arguments in toolCalls", async () => { + mock = new LLMock(); + mock.on( + { userMessage: "weather" }, + { + toolCalls: [{ name: "get_weather", arguments: { city: "SF" } }], + }, + ); + await mock.start(); + + const res = await post(mock.url, { + model: "gpt-4", + messages: [{ role: "user", content: "weather" }], + stream: false, + }); + + expect(res.status).toBe(200); + const json = JSON.parse(res.data); + const args = json.choices[0].message.tool_calls[0].function.arguments; + expect(typeof args).toBe("string"); + expect(JSON.parse(args)).toEqual({ city: "SF" }); + }); + + it("onMessage() auto-stringifies object content", async () => { + mock = new LLMock(); + mock.onMessage("structured", { content: { answer: 42, nested: { key: "val" } } }); + await mock.start(); + + const res = await post(mock.url, chatBody("structured", false)); + + expect(res.status).toBe(200); + const json = JSON.parse(res.data); + const content = json.choices[0].message.content; + expect(typeof content).toBe("string"); + expect(JSON.parse(content)).toEqual({ answer: 42, nested: { key: "val" } }); + }); + + it("on() preserves string arguments without double-stringifying", async () => { + mock = new LLMock(); + mock.on( + { userMessage: "already-string" }, + { + toolCalls: [{ name: "fn", arguments: JSON.stringify({ key: "val" }) }], + }, + ); + await mock.start(); + + const res = await post(mock.url, { + model: "gpt-4", + messages: [{ role: "user", content: "already-string" }], + stream: false, + }); + + expect(res.status).toBe(200); + const json = JSON.parse(res.data); + const args = json.choices[0].message.tool_calls[0].function.arguments; + expect(JSON.parse(args)).toEqual({ key: "val" }); + }); + }); + describe("onJsonOutput convenience", () => { it("registers a fixture with responseFormat json_object and stringified content", () => { mock = new LLMock(); diff --git a/src/__tests__/response-overrides.test.ts b/src/__tests__/response-overrides.test.ts new file mode 100644 index 0000000..8e59aee --- /dev/null +++ b/src/__tests__/response-overrides.test.ts @@ -0,0 +1,1377 @@ +import { describe, it, expect, afterEach } from "vitest"; +import http from "node:http"; +import { createServer, type ServerInstance } from "../server.js"; +import type { + Fixture, + SSEChunk, + TextResponse, + ToolCallResponse, + ContentWithToolCallsResponse, +} from "../types.js"; + +// --------------------------------------------------------------------------- +// Helpers +// --------------------------------------------------------------------------- + +function parseSSEResponse(body: string): SSEChunk[] { + return body + .split("\n\n") + .filter((line) => line.startsWith("data: ") && !line.includes("[DONE]")) + .map((line) => JSON.parse(line.slice(6))); +} + +function parseClaudeSSE(body: string): object[] { + return body + .split("\n\n") + .filter((line) => line.includes("data: ")) + .map((line) => { + const dataLine = line.split("\n").find((l) => l.startsWith("data: ")); + return JSON.parse(dataLine!.slice(6)); + }); +} + +function parseGeminiSSE(body: string): object[] { + return body + .split("\n\n") + .filter((line) => line.startsWith("data: ")) + .map((line) => JSON.parse(line.slice(6))); +} + +function parseResponsesSSE(body: string): object[] { + return body + .split("\n\n") + .filter((line) => line.includes("data: ")) + .map((line) => { + const dataLine = line.split("\n").find((l) => l.startsWith("data: ")); + return JSON.parse(dataLine!.slice(6)); + }); +} + +async function httpPost(url: string, body: object): Promise<{ status: number; body: string }> { + return new Promise((resolve, reject) => { + const req = http.request( + url, + { + method: "POST", + headers: { "Content-Type": "application/json" }, + }, + (res) => { + const chunks: Buffer[] = []; + res.on("data", (c) => chunks.push(c)); + res.on("end", () => + resolve({ status: res.statusCode!, body: Buffer.concat(chunks).toString() }), + ); + }, + ); + req.on("error", reject); + req.write(JSON.stringify(body)); + req.end(); + }); +} + +// --------------------------------------------------------------------------- +// Tests +// --------------------------------------------------------------------------- + +let instance: ServerInstance | null = null; + +afterEach(async () => { + if (instance) { + await new Promise((resolve) => instance!.server.close(() => resolve())); + instance = null; + } +}); + +describe("response overrides: OpenAI Chat Completions (non-streaming)", () => { + it("applies id override", async () => { + const fixtures: Fixture[] = [ + { + match: { userMessage: "hello" }, + response: { content: "Hi!", id: "chatcmpl-test123" }, + }, + ]; + instance = await createServer(fixtures); + const res = await httpPost(`${instance.url}/v1/chat/completions`, { + model: "gpt-4", + stream: false, + messages: [{ role: "user", content: "hello" }], + }); + const json = JSON.parse(res.body); + expect(json.id).toBe("chatcmpl-test123"); + }); + + it("applies created override", async () => { + const fixtures: Fixture[] = [ + { + match: { userMessage: "hello" }, + response: { content: "Hi!", created: 1700000000 }, + }, + ]; + instance = await createServer(fixtures); + const res = await httpPost(`${instance.url}/v1/chat/completions`, { + model: "gpt-4", + stream: false, + messages: [{ role: "user", content: "hello" }], + }); + const json = JSON.parse(res.body); + expect(json.created).toBe(1700000000); + }); + + it("applies model override", async () => { + const fixtures: Fixture[] = [ + { + match: { userMessage: "hello" }, + response: { content: "Hi!", model: "gpt-4o-2024-08-06" }, + }, + ]; + instance = await createServer(fixtures); + const res = await httpPost(`${instance.url}/v1/chat/completions`, { + model: "gpt-4", + stream: false, + messages: [{ role: "user", content: "hello" }], + }); + const json = JSON.parse(res.body); + expect(json.model).toBe("gpt-4o-2024-08-06"); + }); + + it("applies usage override", async () => { + const fixtures: Fixture[] = [ + { + match: { userMessage: "hello" }, + response: { + content: "Hi!", + usage: { prompt_tokens: 10, completion_tokens: 5, total_tokens: 15 }, + }, + }, + ]; + instance = await createServer(fixtures); + const res = await httpPost(`${instance.url}/v1/chat/completions`, { + model: "gpt-4", + stream: false, + messages: [{ role: "user", content: "hello" }], + }); + const json = JSON.parse(res.body); + expect(json.usage.prompt_tokens).toBe(10); + expect(json.usage.completion_tokens).toBe(5); + expect(json.usage.total_tokens).toBe(15); + }); + + it("applies finishReason override", async () => { + const fixtures: Fixture[] = [ + { + match: { userMessage: "hello" }, + response: { content: "Hi!", finishReason: "length" }, + }, + ]; + instance = await createServer(fixtures); + const res = await httpPost(`${instance.url}/v1/chat/completions`, { + model: "gpt-4", + stream: false, + messages: [{ role: "user", content: "hello" }], + }); + const json = JSON.parse(res.body); + expect(json.choices[0].finish_reason).toBe("length"); + }); + + it("applies role override", async () => { + const fixtures: Fixture[] = [ + { + match: { userMessage: "hello" }, + response: { content: "Hi!", role: "system" }, + }, + ]; + instance = await createServer(fixtures); + const res = await httpPost(`${instance.url}/v1/chat/completions`, { + model: "gpt-4", + stream: false, + messages: [{ role: "user", content: "hello" }], + }); + const json = JSON.parse(res.body); + expect(json.choices[0].message.role).toBe("system"); + }); + + it("applies systemFingerprint override", async () => { + const fixtures: Fixture[] = [ + { + match: { userMessage: "hello" }, + response: { content: "Hi!", systemFingerprint: "fp_abc123" }, + }, + ]; + instance = await createServer(fixtures); + const res = await httpPost(`${instance.url}/v1/chat/completions`, { + model: "gpt-4", + stream: false, + messages: [{ role: "user", content: "hello" }], + }); + const json = JSON.parse(res.body); + expect(json.system_fingerprint).toBe("fp_abc123"); + }); + + it("partial usage merge — only prompt_tokens set", async () => { + const fixtures: Fixture[] = [ + { + match: { userMessage: "hello" }, + response: { content: "Hi!", usage: { prompt_tokens: 42 } }, + }, + ]; + instance = await createServer(fixtures); + const res = await httpPost(`${instance.url}/v1/chat/completions`, { + model: "gpt-4", + stream: false, + messages: [{ role: "user", content: "hello" }], + }); + const json = JSON.parse(res.body); + expect(json.usage.prompt_tokens).toBe(42); + expect(json.usage.completion_tokens).toBe(0); + expect(json.usage.total_tokens).toBe(42); + }); + + it("default behavior unchanged when no overrides specified", async () => { + const fixtures: Fixture[] = [ + { + match: { userMessage: "hello" }, + response: { content: "Hi!" }, + }, + ]; + instance = await createServer(fixtures); + const res = await httpPost(`${instance.url}/v1/chat/completions`, { + model: "gpt-4", + stream: false, + messages: [{ role: "user", content: "hello" }], + }); + const json = JSON.parse(res.body); + expect(json.id).toMatch(/^chatcmpl-/); + expect(json.model).toBe("gpt-4"); + expect(json.choices[0].message.role).toBe("assistant"); + expect(json.choices[0].finish_reason).toBe("stop"); + expect(json.usage.prompt_tokens).toBe(0); + expect(json.system_fingerprint).toBeUndefined(); + }); +}); + +describe("response overrides: OpenAI Chat Completions (streaming)", () => { + it("overrides id/created/model on every chunk", async () => { + const fixtures: Fixture[] = [ + { + match: { userMessage: "hello" }, + response: { + content: "Hi!", + id: "chatcmpl-stream-test", + created: 1700000000, + model: "gpt-4o-override", + }, + }, + ]; + instance = await createServer(fixtures); + const res = await httpPost(`${instance.url}/v1/chat/completions`, { + model: "gpt-4", + stream: true, + messages: [{ role: "user", content: "hello" }], + }); + const chunks = parseSSEResponse(res.body); + expect(chunks.length).toBeGreaterThan(0); + for (const chunk of chunks) { + expect(chunk.id).toBe("chatcmpl-stream-test"); + expect(chunk.created).toBe(1700000000); + expect(chunk.model).toBe("gpt-4o-override"); + } + }); + + it("overrides finishReason on final chunk only", async () => { + const fixtures: Fixture[] = [ + { + match: { userMessage: "hello" }, + response: { content: "Hi!", finishReason: "length" }, + }, + ]; + instance = await createServer(fixtures); + const res = await httpPost(`${instance.url}/v1/chat/completions`, { + model: "gpt-4", + stream: true, + messages: [{ role: "user", content: "hello" }], + }); + const chunks = parseSSEResponse(res.body); + const lastChunk = chunks[chunks.length - 1]; + expect(lastChunk.choices[0].finish_reason).toBe("length"); + }); + + it("overrides role on role chunk", async () => { + const fixtures: Fixture[] = [ + { + match: { userMessage: "hello" }, + response: { content: "Hi!", role: "system" }, + }, + ]; + instance = await createServer(fixtures); + const res = await httpPost(`${instance.url}/v1/chat/completions`, { + model: "gpt-4", + stream: true, + messages: [{ role: "user", content: "hello" }], + }); + const chunks = parseSSEResponse(res.body); + const roleChunk = chunks.find((c) => c.choices[0]?.delta?.role !== undefined); + expect(roleChunk?.choices[0].delta.role).toBe("system"); + }); + + it("adds systemFingerprint to every chunk", async () => { + const fixtures: Fixture[] = [ + { + match: { userMessage: "hello" }, + response: { content: "Hi!", systemFingerprint: "fp_stream" }, + }, + ]; + instance = await createServer(fixtures); + const res = await httpPost(`${instance.url}/v1/chat/completions`, { + model: "gpt-4", + stream: true, + messages: [{ role: "user", content: "hello" }], + }); + const chunks = parseSSEResponse(res.body); + for (const chunk of chunks) { + expect((chunk as Record).system_fingerprint).toBe("fp_stream"); + } + }); +}); + +describe("response overrides: tool call", () => { + it("applies role override on tool-call-only response", async () => { + const fixtures: Fixture[] = [ + { + match: { userMessage: "weather" }, + response: { + toolCalls: [{ name: "get_weather", arguments: '{"city":"NYC"}' }], + role: "system", + }, + }, + ]; + instance = await createServer(fixtures); + const res = await httpPost(`${instance.url}/v1/chat/completions`, { + model: "gpt-4", + stream: false, + messages: [{ role: "user", content: "weather" }], + }); + const json = JSON.parse(res.body); + expect(json.choices[0].message.role).toBe("system"); + }); + + it("applies finishReason on tool call response", async () => { + const fixtures: Fixture[] = [ + { + match: { userMessage: "weather" }, + response: { + toolCalls: [{ name: "get_weather", arguments: '{"city":"NYC"}' }], + finishReason: "stop", + }, + }, + ]; + instance = await createServer(fixtures); + const res = await httpPost(`${instance.url}/v1/chat/completions`, { + model: "gpt-4", + stream: false, + messages: [{ role: "user", content: "weather" }], + }); + const json = JSON.parse(res.body); + expect(json.choices[0].finish_reason).toBe("stop"); + }); +}); + +describe("response overrides: content+toolCalls", () => { + it("applies all overrides on combined response", async () => { + const fixtures: Fixture[] = [ + { + match: { userMessage: "search" }, + response: { + content: "Let me search", + toolCalls: [{ name: "search", arguments: '{"q":"test"}' }], + id: "chatcmpl-combo", + model: "gpt-4o-combo", + usage: { prompt_tokens: 20, completion_tokens: 10, total_tokens: 30 }, + systemFingerprint: "fp_combo", + role: "system", + finishReason: "stop", + }, + }, + ]; + instance = await createServer(fixtures); + const res = await httpPost(`${instance.url}/v1/chat/completions`, { + model: "gpt-4", + stream: false, + messages: [{ role: "user", content: "search" }], + }); + const json = JSON.parse(res.body); + expect(json.id).toBe("chatcmpl-combo"); + expect(json.model).toBe("gpt-4o-combo"); + expect(json.usage.prompt_tokens).toBe(20); + expect(json.system_fingerprint).toBe("fp_combo"); + expect(json.choices[0].message.role).toBe("system"); + expect(json.choices[0].finish_reason).toBe("stop"); + }); +}); + +describe("response overrides: Claude format", () => { + it("maps id to message id", async () => { + const fixtures: Fixture[] = [ + { + match: { userMessage: "hello" }, + response: { content: "Hi!", id: "msg_test123" }, + }, + ]; + instance = await createServer(fixtures); + const res = await httpPost(`${instance.url}/v1/messages`, { + model: "claude-3-opus-20240229", + max_tokens: 100, + stream: false, + messages: [{ role: "user", content: "hello" }], + }); + const json = JSON.parse(res.body); + expect(json.id).toBe("msg_test123"); + }); + + it("maps finishReason 'stop' to stop_reason 'end_turn'", async () => { + const fixtures: Fixture[] = [ + { + match: { userMessage: "hello" }, + response: { content: "Hi!", finishReason: "stop" }, + }, + ]; + instance = await createServer(fixtures); + const res = await httpPost(`${instance.url}/v1/messages`, { + model: "claude-3-opus-20240229", + max_tokens: 100, + stream: false, + messages: [{ role: "user", content: "hello" }], + }); + const json = JSON.parse(res.body); + expect(json.stop_reason).toBe("end_turn"); + }); + + it("maps usage input_tokens/output_tokens", async () => { + const fixtures: Fixture[] = [ + { + match: { userMessage: "hello" }, + response: { + content: "Hi!", + usage: { input_tokens: 15, output_tokens: 8 }, + }, + }, + ]; + instance = await createServer(fixtures); + const res = await httpPost(`${instance.url}/v1/messages`, { + model: "claude-3-opus-20240229", + max_tokens: 100, + stream: false, + messages: [{ role: "user", content: "hello" }], + }); + const json = JSON.parse(res.body); + expect(json.usage.input_tokens).toBe(15); + expect(json.usage.output_tokens).toBe(8); + }); + + it("maps overrides in streaming mode", async () => { + const fixtures: Fixture[] = [ + { + match: { userMessage: "hello" }, + response: { + content: "Hi!", + id: "msg_stream_test", + model: "claude-override", + finishReason: "tool_calls", + }, + }, + ]; + instance = await createServer(fixtures); + const res = await httpPost(`${instance.url}/v1/messages`, { + model: "claude-3-opus-20240229", + max_tokens: 100, + stream: true, + messages: [{ role: "user", content: "hello" }], + }); + const events = parseClaudeSSE(res.body); + const msgStart = events.find((e: Record) => e.type === "message_start") as + | Record + | undefined; + const msg = msgStart?.message as Record; + expect(msg.id).toBe("msg_stream_test"); + expect(msg.model).toBe("claude-override"); + + const msgDelta = events.find((e: Record) => e.type === "message_delta") as + | Record + | undefined; + const delta = msgDelta?.delta as Record; + expect(delta.stop_reason).toBe("tool_use"); + }); +}); + +describe("response overrides: Gemini format", () => { + it("maps finishReason 'stop' to 'STOP'", async () => { + const fixtures: Fixture[] = [ + { + match: { userMessage: "hello" }, + response: { content: "Hi!", finishReason: "stop" }, + }, + ]; + instance = await createServer(fixtures); + const res = await httpPost(`${instance.url}/v1beta/models/gemini-pro:generateContent`, { + contents: [{ role: "user", parts: [{ text: "hello" }] }], + }); + const json = JSON.parse(res.body); + expect(json.candidates[0].finishReason).toBe("STOP"); + }); + + it("maps usage to usageMetadata", async () => { + const fixtures: Fixture[] = [ + { + match: { userMessage: "hello" }, + response: { + content: "Hi!", + usage: { promptTokenCount: 10, candidatesTokenCount: 5, totalTokenCount: 15 }, + }, + }, + ]; + instance = await createServer(fixtures); + const res = await httpPost(`${instance.url}/v1beta/models/gemini-pro:generateContent`, { + contents: [{ role: "user", parts: [{ text: "hello" }] }], + }); + const json = JSON.parse(res.body); + expect(json.usageMetadata.promptTokenCount).toBe(10); + expect(json.usageMetadata.candidatesTokenCount).toBe(5); + expect(json.usageMetadata.totalTokenCount).toBe(15); + }); + + it("id/model/created are ignored in Gemini format", async () => { + const fixtures: Fixture[] = [ + { + match: { userMessage: "hello" }, + response: { + content: "Hi!", + id: "should-be-ignored", + model: "should-be-ignored", + created: 1700000000, + }, + }, + ]; + instance = await createServer(fixtures); + const res = await httpPost(`${instance.url}/v1beta/models/gemini-pro:generateContent`, { + contents: [{ role: "user", parts: [{ text: "hello" }] }], + }); + const json = JSON.parse(res.body); + // Gemini format does not have id, model, or created at top level + expect(json.id).toBeUndefined(); + expect(json.model).toBeUndefined(); + expect(json.created).toBeUndefined(); + }); + + it("auto-computes totalTokenCount in streaming mode when omitted", async () => { + const fixtures: Fixture[] = [ + { + match: { userMessage: "hello" }, + response: { + content: "Hi!", + usage: { promptTokenCount: 10, candidatesTokenCount: 20 }, + }, + }, + ]; + instance = await createServer(fixtures); + const res = await httpPost( + `${instance.url}/v1beta/models/gemini-pro:streamGenerateContent?alt=sse`, + { + contents: [{ role: "user", parts: [{ text: "hello" }] }], + }, + ); + const chunks = parseGeminiSSE(res.body) as Array>; + // Find the last chunk that has usageMetadata + const chunksWithUsage = chunks.filter((c) => c.usageMetadata !== undefined); + expect(chunksWithUsage.length).toBeGreaterThan(0); + const lastWithUsage = chunksWithUsage[chunksWithUsage.length - 1]; + const usage = lastWithUsage.usageMetadata as Record; + expect(usage.totalTokenCount).toBe(30); + }); + + it("maps finishReason in streaming mode", async () => { + const fixtures: Fixture[] = [ + { + match: { userMessage: "hello" }, + response: { content: "Hi!", finishReason: "tool_calls" }, + }, + ]; + instance = await createServer(fixtures); + const res = await httpPost( + `${instance.url}/v1beta/models/gemini-pro:streamGenerateContent?alt=sse`, + { + contents: [{ role: "user", parts: [{ text: "hello" }] }], + }, + ); + const chunks = parseGeminiSSE(res.body) as Array>; + const lastChunk = chunks[chunks.length - 1]; + const candidates = lastChunk.candidates as Array>; + expect(candidates[0].finishReason).toBe("FUNCTION_CALL"); + }); +}); + +describe("response overrides: Responses API", () => { + it("applies id/created_at/model in envelope", async () => { + const fixtures: Fixture[] = [ + { + match: { userMessage: "hello" }, + response: { + content: "Hi!", + id: "resp_test123", + created: 1700000000, + model: "gpt-4o-responses", + }, + }, + ]; + instance = await createServer(fixtures); + const res = await httpPost(`${instance.url}/v1/responses`, { + model: "gpt-4", + stream: false, + input: [{ role: "user", content: "hello" }], + }); + const json = JSON.parse(res.body); + expect(json.id).toBe("resp_test123"); + expect(json.created_at).toBe(1700000000); + expect(json.model).toBe("gpt-4o-responses"); + }); + + it("maps finishReason 'stop' to status 'completed'", async () => { + const fixtures: Fixture[] = [ + { + match: { userMessage: "hello" }, + response: { content: "Hi!", finishReason: "stop" }, + }, + ]; + instance = await createServer(fixtures); + const res = await httpPost(`${instance.url}/v1/responses`, { + model: "gpt-4", + stream: false, + input: [{ role: "user", content: "hello" }], + }); + const json = JSON.parse(res.body); + expect(json.status).toBe("completed"); + }); + + it("maps finishReason 'length' to status 'incomplete'", async () => { + const fixtures: Fixture[] = [ + { + match: { userMessage: "hello" }, + response: { content: "Hi!", finishReason: "length" }, + }, + ]; + instance = await createServer(fixtures); + const res = await httpPost(`${instance.url}/v1/responses`, { + model: "gpt-4", + stream: false, + input: [{ role: "user", content: "hello" }], + }); + const json = JSON.parse(res.body); + expect(json.status).toBe("incomplete"); + }); + + it("maps usage in Responses API format", async () => { + const fixtures: Fixture[] = [ + { + match: { userMessage: "hello" }, + response: { + content: "Hi!", + usage: { input_tokens: 12, output_tokens: 6, total_tokens: 18 }, + }, + }, + ]; + instance = await createServer(fixtures); + const res = await httpPost(`${instance.url}/v1/responses`, { + model: "gpt-4", + stream: false, + input: [{ role: "user", content: "hello" }], + }); + const json = JSON.parse(res.body); + expect(json.usage.input_tokens).toBe(12); + expect(json.usage.output_tokens).toBe(6); + expect(json.usage.total_tokens).toBe(18); + }); + + it("applies overrides in streaming mode", async () => { + const fixtures: Fixture[] = [ + { + match: { userMessage: "hello" }, + response: { + content: "Hi!", + id: "resp_stream", + created: 1700000000, + model: "gpt-4o-stream-resp", + finishReason: "length", + usage: { input_tokens: 5, output_tokens: 3, total_tokens: 8 }, + }, + }, + ]; + instance = await createServer(fixtures); + const res = await httpPost(`${instance.url}/v1/responses`, { + model: "gpt-4", + stream: true, + input: [{ role: "user", content: "hello" }], + }); + const events = parseResponsesSSE(res.body) as Array>; + + const created = events.find((e) => e.type === "response.created") as Record; + const createdResp = created.response as Record; + expect(createdResp.id).toBe("resp_stream"); + expect(createdResp.created_at).toBe(1700000000); + expect(createdResp.model).toBe("gpt-4o-stream-resp"); + + const completed = events.find((e) => e.type === "response.completed") as Record< + string, + unknown + >; + const completedResp = completed.response as Record; + expect(completedResp.status).toBe("incomplete"); + const usage = completedResp.usage as Record; + expect(usage.input_tokens).toBe(5); + expect(usage.output_tokens).toBe(3); + expect(usage.total_tokens).toBe(8); + }); +}); + +describe("response overrides: cross-provider tool call coverage", () => { + it("Gemini tool call finishReason maps to FUNCTION_CALL", async () => { + const fixtures: Fixture[] = [ + { + match: { userMessage: "weather" }, + response: { + toolCalls: [{ name: "get_weather", arguments: '{"city":"NYC"}' }], + finishReason: "tool_calls", + }, + }, + ]; + instance = await createServer(fixtures); + const res = await httpPost(`${instance.url}/v1beta/models/gemini-2.0-flash:generateContent`, { + contents: [{ role: "user", parts: [{ text: "weather" }] }], + }); + const json = JSON.parse(res.body); + expect(json.candidates[0].finishReason).toBe("FUNCTION_CALL"); + }); + + it("Claude tool call finishReason maps to tool_use", async () => { + const fixtures: Fixture[] = [ + { + match: { userMessage: "weather" }, + response: { + toolCalls: [{ name: "get_weather", arguments: '{"city":"NYC"}' }], + finishReason: "tool_calls", + }, + }, + ]; + instance = await createServer(fixtures); + const res = await httpPost(`${instance.url}/v1/messages`, { + model: "claude-3-opus-20240229", + max_tokens: 100, + stream: false, + messages: [{ role: "user", content: "weather" }], + }); + const json = JSON.parse(res.body); + expect(json.stop_reason).toBe("tool_use"); + }); + + it("Responses API tool call with id and finishReason overrides", async () => { + const fixtures: Fixture[] = [ + { + match: { userMessage: "weather" }, + response: { + toolCalls: [{ name: "get_weather", arguments: '{"city":"NYC"}' }], + id: "resp_custom_tc", + finishReason: "stop", + }, + }, + ]; + instance = await createServer(fixtures); + const res = await httpPost(`${instance.url}/v1/responses`, { + model: "gpt-4o", + input: [{ role: "user", content: "weather" }], + }); + const json = JSON.parse(res.body); + expect(json.id).toBe("resp_custom_tc"); + expect(json.status).toBe("completed"); + }); +}); + +describe("response overrides: finishReason cross-provider mappings", () => { + it("finishReason length maps to max_tokens on Claude", async () => { + const fixtures: Fixture[] = [ + { + match: { userMessage: "hello" }, + response: { content: "Hi!", finishReason: "length" }, + }, + ]; + instance = await createServer(fixtures); + const res = await httpPost(`${instance.url}/v1/messages`, { + model: "claude-3-opus-20240229", + max_tokens: 100, + stream: false, + messages: [{ role: "user", content: "hello" }], + }); + const json = JSON.parse(res.body); + expect(json.stop_reason).toBe("max_tokens"); + }); + + it("finishReason length maps to MAX_TOKENS on Gemini", async () => { + const fixtures: Fixture[] = [ + { + match: { userMessage: "hello" }, + response: { content: "Hi!", finishReason: "length" }, + }, + ]; + instance = await createServer(fixtures); + const res = await httpPost(`${instance.url}/v1beta/models/gemini-pro:generateContent`, { + contents: [{ role: "user", parts: [{ text: "hello" }] }], + }); + const json = JSON.parse(res.body); + expect(json.candidates[0].finishReason).toBe("MAX_TOKENS"); + }); + + it("content_filter passthrough on OpenAI", async () => { + const fixtures: Fixture[] = [ + { + match: { userMessage: "hello" }, + response: { content: "Hi!", finishReason: "content_filter" }, + }, + ]; + instance = await createServer(fixtures); + const res = await httpPost(`${instance.url}/v1/chat/completions`, { + model: "gpt-4", + stream: false, + messages: [{ role: "user", content: "hello" }], + }); + const json = JSON.parse(res.body); + expect(json.choices[0].finish_reason).toBe("content_filter"); + }); + + it("unknown finishReason passthrough", async () => { + const fixtures: Fixture[] = [ + { + match: { userMessage: "hello" }, + response: { content: "Hi!", finishReason: "custom_reason" }, + }, + ]; + instance = await createServer(fixtures); + const res = await httpPost(`${instance.url}/v1/chat/completions`, { + model: "gpt-4", + stream: false, + messages: [{ role: "user", content: "hello" }], + }); + const json = JSON.parse(res.body); + expect(json.choices[0].finish_reason).toBe("custom_reason"); + }); + + it("content_filter maps to SAFETY on Gemini", async () => { + const fixtures: Fixture[] = [ + { + match: { userMessage: "hello" }, + response: { content: "Hi!", finishReason: "content_filter" }, + }, + ]; + instance = await createServer(fixtures); + const res = await httpPost(`${instance.url}/v1beta/models/gemini-pro:generateContent`, { + contents: [{ role: "user", parts: [{ text: "hello" }] }], + }); + const json = JSON.parse(res.body); + expect(json.candidates[0].finishReason).toBe("SAFETY"); + }); + + it("content_filter maps to failed on Responses API", async () => { + const fixtures: Fixture[] = [ + { + match: { userMessage: "hello" }, + response: { content: "Hi!", finishReason: "content_filter" }, + }, + ]; + instance = await createServer(fixtures); + const res = await httpPost(`${instance.url}/v1/responses`, { + model: "gpt-4", + stream: false, + input: [{ role: "user", content: "hello" }], + }); + const json = JSON.parse(res.body); + expect(json.status).toBe("failed"); + }); + + it("content_filter passthrough on Claude", async () => { + const fixtures: Fixture[] = [ + { + match: { userMessage: "hello" }, + response: { content: "Hi!", finishReason: "content_filter" }, + }, + ]; + instance = await createServer(fixtures); + const res = await httpPost(`${instance.url}/v1/messages`, { + model: "claude-3-opus-20240229", + max_tokens: 100, + stream: false, + messages: [{ role: "user", content: "hello" }], + }); + const json = JSON.parse(res.body); + expect(json.stop_reason).toBe("content_filter"); + }); +}); + +describe("response overrides: total_tokens auto-sum", () => { + it("total_tokens auto-sum with both prompt and completion tokens", async () => { + const fixtures: Fixture[] = [ + { + match: { userMessage: "hello" }, + response: { + content: "Hi!", + usage: { prompt_tokens: 10, completion_tokens: 20 }, + }, + }, + ]; + instance = await createServer(fixtures); + const res = await httpPost(`${instance.url}/v1/chat/completions`, { + model: "gpt-4", + stream: false, + messages: [{ role: "user", content: "hello" }], + }); + const json = JSON.parse(res.body); + expect(json.usage.prompt_tokens).toBe(10); + expect(json.usage.completion_tokens).toBe(20); + // total_tokens is auto-computed from prompt_tokens + completion_tokens when omitted + expect(json.usage.total_tokens).toBe(30); + }); + + it("Responses API total_tokens auto-sum", async () => { + const fixtures: Fixture[] = [ + { + match: { userMessage: "hello" }, + response: { + content: "Hi!", + usage: { input_tokens: 10, output_tokens: 20 }, + }, + }, + ]; + instance = await createServer(fixtures); + const res = await httpPost(`${instance.url}/v1/responses`, { + model: "gpt-4", + stream: false, + input: [{ role: "user", content: "hello" }], + }); + const json = JSON.parse(res.body); + expect(json.usage.input_tokens).toBe(10); + expect(json.usage.output_tokens).toBe(20); + expect(json.usage.total_tokens).toBe(30); + }); + + it("Gemini totalTokenCount auto-sum", async () => { + const fixtures: Fixture[] = [ + { + match: { userMessage: "hello" }, + response: { + content: "Hi!", + usage: { promptTokenCount: 10, candidatesTokenCount: 20 }, + }, + }, + ]; + instance = await createServer(fixtures); + const res = await httpPost(`${instance.url}/v1beta/models/gemini-pro:generateContent`, { + contents: [{ role: "user", parts: [{ text: "hello" }] }], + }); + const json = JSON.parse(res.body); + expect(json.usageMetadata.promptTokenCount).toBe(10); + expect(json.usageMetadata.candidatesTokenCount).toBe(20); + expect(json.usageMetadata.totalTokenCount).toBe(30); + }); +}); + +describe("response overrides: partial usage merge for non-OpenAI", () => { + it("partial usage merge for Claude", async () => { + const fixtures: Fixture[] = [ + { + match: { userMessage: "hello" }, + response: { + content: "Hi!", + usage: { input_tokens: 42 }, + }, + }, + ]; + instance = await createServer(fixtures); + const res = await httpPost(`${instance.url}/v1/messages`, { + model: "claude-3-opus-20240229", + max_tokens: 100, + stream: false, + messages: [{ role: "user", content: "hello" }], + }); + const json = JSON.parse(res.body); + expect(json.usage.input_tokens).toBe(42); + expect(json.usage.output_tokens).toBe(0); + }); + + it("partial usage merge for Gemini", async () => { + const fixtures: Fixture[] = [ + { + match: { userMessage: "hello" }, + response: { + content: "Hi!", + usage: { promptTokenCount: 42 }, + }, + }, + ]; + instance = await createServer(fixtures); + const res = await httpPost(`${instance.url}/v1beta/models/gemini-pro:generateContent`, { + contents: [{ role: "user", parts: [{ text: "hello" }] }], + }); + const json = JSON.parse(res.body); + expect(json.usageMetadata.promptTokenCount).toBe(42); + expect(json.usageMetadata.candidatesTokenCount).toBe(0); + expect(json.usageMetadata.totalTokenCount).toBe(42); + }); + + it("partial usage merge for Responses API", async () => { + const fixtures: Fixture[] = [ + { + match: { userMessage: "hello" }, + response: { + content: "Hi!", + usage: { input_tokens: 42 }, + }, + }, + ]; + instance = await createServer(fixtures); + const res = await httpPost(`${instance.url}/v1/responses`, { + model: "gpt-4", + stream: false, + input: [{ role: "user", content: "hello" }], + }); + const json = JSON.parse(res.body); + expect(json.usage.input_tokens).toBe(42); + expect(json.usage.output_tokens).toBe(0); + expect(json.usage.total_tokens).toBe(42); + }); +}); + +describe("response overrides: streaming CWTC overrides", () => { + it("streaming Claude CWTC overrides", async () => { + const fixtures: Fixture[] = [ + { + match: { userMessage: "search" }, + response: { + content: "Let me search", + toolCalls: [{ name: "search", arguments: '{"q":"test"}' }], + id: "msg_cwtc_test", + model: "claude-override", + }, + }, + ]; + instance = await createServer(fixtures); + const res = await httpPost(`${instance.url}/v1/messages`, { + model: "claude-3-opus-20240229", + max_tokens: 100, + stream: true, + messages: [{ role: "user", content: "search" }], + }); + const events = parseClaudeSSE(res.body); + const msgStart = events.find((e: Record) => e.type === "message_start") as + | Record + | undefined; + const msg = msgStart?.message as Record; + expect(msg.id).toBe("msg_cwtc_test"); + expect(msg.model).toBe("claude-override"); + }); + + it("streaming Gemini CWTC finishReason", async () => { + const fixtures: Fixture[] = [ + { + match: { userMessage: "search" }, + response: { + content: "Let me search", + toolCalls: [{ name: "search", arguments: '{"q":"test"}' }], + finishReason: "tool_calls", + }, + }, + ]; + instance = await createServer(fixtures); + const res = await httpPost( + `${instance.url}/v1beta/models/gemini-pro:streamGenerateContent?alt=sse`, + { + contents: [{ role: "user", parts: [{ text: "search" }] }], + }, + ); + const chunks = parseGeminiSSE(res.body) as Array>; + const lastChunk = chunks[chunks.length - 1]; + const candidates = lastChunk.candidates as Array>; + expect(candidates[0].finishReason).toBe("FUNCTION_CALL"); + }); + + it("streaming Responses API CWTC overrides", async () => { + const fixtures: Fixture[] = [ + { + match: { userMessage: "search" }, + response: { + content: "Let me search", + toolCalls: [{ name: "search", arguments: '{"q":"test"}' }], + id: "resp_cwtc_test", + model: "gpt-4o-cwtc", + }, + }, + ]; + instance = await createServer(fixtures); + const res = await httpPost(`${instance.url}/v1/responses`, { + model: "gpt-4", + stream: true, + input: [{ role: "user", content: "search" }], + }); + const events = parseResponsesSSE(res.body) as Array>; + const completed = events.find((e) => e.type === "response.completed") as Record< + string, + unknown + >; + const completedResp = completed.response as Record; + expect(completedResp.id).toBe("resp_cwtc_test"); + expect(completedResp.model).toBe("gpt-4o-cwtc"); + }); + + it("finishReason length in Claude streaming", async () => { + const fixtures: Fixture[] = [ + { + match: { userMessage: "hello" }, + response: { content: "Hi!", finishReason: "length" }, + }, + ]; + instance = await createServer(fixtures); + const res = await httpPost(`${instance.url}/v1/messages`, { + model: "claude-3-opus-20240229", + max_tokens: 100, + stream: true, + messages: [{ role: "user", content: "hello" }], + }); + const events = parseClaudeSSE(res.body); + const msgDelta = events.find((e: Record) => e.type === "message_delta") as + | Record + | undefined; + const delta = msgDelta?.delta as Record; + expect(delta.stop_reason).toBe("max_tokens"); + }); +}); + +describe("response overrides: reasoning in CWTC", () => { + it("reasoning in CWTC streaming OpenAI", async () => { + // OpenAI CWTC streaming does not currently include reasoning_content chunks; + // reasoning is only supported for text-only streaming in OpenAI format. + // Verify that the content and tool call chunks still appear correctly. + const fixtures: Fixture[] = [ + { + match: { userMessage: "think" }, + response: { + content: "The answer is 42", + toolCalls: [{ name: "calc", arguments: '{"x":42}' }], + reasoning: "Let me think about this...", + }, + }, + ]; + instance = await createServer(fixtures); + const res = await httpPost(`${instance.url}/v1/chat/completions`, { + model: "gpt-4", + stream: true, + messages: [{ role: "user", content: "think" }], + }); + const chunks = parseSSEResponse(res.body); + const contentChunks = chunks.filter((c) => c.choices?.[0]?.delta?.content); + const toolChunks = chunks.filter((c) => c.choices?.[0]?.delta?.tool_calls); + expect(contentChunks.length).toBeGreaterThan(0); + expect(toolChunks.length).toBeGreaterThan(0); + }); + + it("reasoning in CWTC for Claude non-streaming", async () => { + const fixtures: Fixture[] = [ + { + match: { userMessage: "think" }, + response: { + content: "The answer is 42", + toolCalls: [{ name: "calc", arguments: '{"x":42}' }], + reasoning: "Let me think about this...", + }, + }, + ]; + instance = await createServer(fixtures); + const res = await httpPost(`${instance.url}/v1/messages`, { + model: "claude-3-opus-20240229", + max_tokens: 100, + stream: false, + messages: [{ role: "user", content: "think" }], + }); + const json = JSON.parse(res.body); + const thinkingBlock = json.content.find((b: Record) => b.type === "thinking"); + expect(thinkingBlock).toBeDefined(); + expect(thinkingBlock.thinking).toBe("Let me think about this..."); + }); + + it("reasoning in CWTC for Gemini non-streaming", async () => { + // Gemini CWTC does not currently include thought parts for reasoning; + // reasoning is only supported for text-only responses in Gemini format. + // Verify that the text and functionCall parts still appear correctly. + const fixtures: Fixture[] = [ + { + match: { userMessage: "think" }, + response: { + content: "The answer is 42", + toolCalls: [{ name: "calc", arguments: '{"x":42}' }], + reasoning: "Let me think about this...", + }, + }, + ]; + instance = await createServer(fixtures); + const res = await httpPost(`${instance.url}/v1beta/models/gemini-pro:generateContent`, { + contents: [{ role: "user", parts: [{ text: "think" }] }], + }); + const json = JSON.parse(res.body); + const parts = json.candidates[0].content.parts; + const textPart = parts.find((p: Record) => p.text !== undefined && !p.thought); + const fcPart = parts.find((p: Record) => p.functionCall !== undefined); + expect(textPart).toBeDefined(); + expect(textPart.text).toBe("The answer is 42"); + expect(fcPart).toBeDefined(); + }); +}); + +describe("response overrides: webSearches in CWTC", () => { + it("webSearches in CWTC for Responses API", async () => { + const fixtures: Fixture[] = [ + { + match: { userMessage: "search" }, + response: { + content: "Here are results", + toolCalls: [{ name: "lookup", arguments: '{"q":"test"}' }], + webSearches: ["search query 1"], + }, + }, + ]; + instance = await createServer(fixtures); + const res = await httpPost(`${instance.url}/v1/responses`, { + model: "gpt-4", + stream: false, + input: [{ role: "user", content: "search" }], + }); + const json = JSON.parse(res.body); + const output = json.output as Array>; + const webSearchItems = output.filter((o) => o.type === "web_search_call"); + expect(webSearchItems.length).toBeGreaterThan(0); + }); +}); + +describe("response overrides: streaming tool calls with overrides", () => { + it("streaming tool call chunks with overrides per-chunk", async () => { + const fixtures: Fixture[] = [ + { + match: { userMessage: "weather" }, + response: { + toolCalls: [{ name: "get_weather", arguments: '{"city":"NYC"}' }], + id: "chatcmpl-tc-override", + model: "gpt-4o-tc-override", + }, + }, + ]; + instance = await createServer(fixtures); + const res = await httpPost(`${instance.url}/v1/chat/completions`, { + model: "gpt-4", + stream: true, + messages: [{ role: "user", content: "weather" }], + }); + const chunks = parseSSEResponse(res.body); + expect(chunks.length).toBeGreaterThan(0); + for (const chunk of chunks) { + expect(chunk.id).toBe("chatcmpl-tc-override"); + expect(chunk.model).toBe("gpt-4o-tc-override"); + } + }); + + it("streaming content+toolCalls with overrides", async () => { + const fixtures: Fixture[] = [ + { + match: { userMessage: "combo" }, + response: { + content: "Let me check", + toolCalls: [{ name: "search", arguments: '{"q":"test"}' }], + id: "chatcmpl-combo-stream", + model: "gpt-4o-combo-stream", + }, + }, + ]; + instance = await createServer(fixtures); + const res = await httpPost(`${instance.url}/v1/chat/completions`, { + model: "gpt-4", + stream: true, + messages: [{ role: "user", content: "combo" }], + }); + const chunks = parseSSEResponse(res.body); + expect(chunks.length).toBeGreaterThan(0); + for (const chunk of chunks) { + expect(chunk.id).toBe("chatcmpl-combo-stream"); + expect(chunk.model).toBe("gpt-4o-combo-stream"); + } + }); +}); + +describe("response overrides: extractOverrides unit tests", () => { + it("extractOverrides with empty usage", async () => { + const { extractOverrides } = await import("../helpers.js"); + const result = extractOverrides({ content: "hi", usage: {} } as TextResponse); + expect(result.usage).toEqual({}); + }); + + it("extractOverrides from ToolCallResponse", async () => { + const { extractOverrides } = await import("../helpers.js"); + const result = extractOverrides({ + toolCalls: [{ name: "fn", arguments: "{}" }], + id: "tc-1", + finishReason: "tool_calls", + } as ToolCallResponse); + expect(result.id).toBe("tc-1"); + expect(result.finishReason).toBe("tool_calls"); + }); + + it("extractOverrides from ContentWithToolCallsResponse", async () => { + const { extractOverrides } = await import("../helpers.js"); + const result = extractOverrides({ + content: "Hello", + toolCalls: [{ name: "fn", arguments: "{}" }], + id: "cwtc-1", + model: "gpt-4", + created: 1700000000, + finishReason: "tool_calls", + role: "assistant", + systemFingerprint: "fp_test", + usage: { prompt_tokens: 10 }, + } as ContentWithToolCallsResponse); + expect(result.id).toBe("cwtc-1"); + expect(result.model).toBe("gpt-4"); + expect(result.created).toBe(1700000000); + expect(result.finishReason).toBe("tool_calls"); + expect(result.role).toBe("assistant"); + expect(result.systemFingerprint).toBe("fp_test"); + expect(result.usage).toEqual({ prompt_tokens: 10 }); + }); +}); + +describe("response overrides: fixture file round-trip", () => { + it("preserves override fields from fixture file format", async () => { + // This tests that override fields on FixtureResponse are preserved through + // entryToFixture (fixture-loader) since it copies response as-is + const { entryToFixture } = await import("../fixture-loader.js"); + const fixture = entryToFixture({ + match: { userMessage: "hello" }, + response: { + content: "Hi!", + id: "chatcmpl-file", + created: 1700000000, + model: "gpt-4o-file", + usage: { prompt_tokens: 10, completion_tokens: 5, total_tokens: 15 }, + finishReason: "stop", + systemFingerprint: "fp_file", + }, + }); + + const response = fixture.response as Record; + expect(response.id).toBe("chatcmpl-file"); + expect(response.created).toBe(1700000000); + expect(response.model).toBe("gpt-4o-file"); + expect(response.finishReason).toBe("stop"); + expect(response.systemFingerprint).toBe("fp_file"); + const usage = response.usage as Record; + expect(usage.prompt_tokens).toBe(10); + }); +}); From 77c9f388f67af20e49c7694664d927d80f42f93e Mon Sep 17 00:00:00 2001 From: Jordan Ritter Date: Wed, 15 Apr 2026 16:38:44 -0700 Subject: [PATCH 3/4] docs: response overrides guide, migration docs, provider support matrix - Migration guide from openai-responses-python - Fixtures docs: Response Override Fields table, provider support matrix, ContentWithToolCallsResponse row, finishReason/usage mapping details - SKILL.md: complete override field docs with provider support matrix, finishReason translation table, usage auto-compute notes - Convert all fixture examples to object syntax (auto-stringify) - Fix provider count to 8, finishReason to camelCase in README - Remove stale TODO in stream-collapse.ts --- CHANGELOG.md | 15 + README.md | 3 +- docs/aws-bedrock/index.html | 2 +- docs/chat-completions/index.html | 7 +- docs/claude-messages/index.html | 2 +- docs/cohere/index.html | 2 +- docs/docs/index.html | 2 + docs/fixtures/index.html | 208 ++++++++- docs/gemini/index.html | 2 +- docs/integrate-adk/index.html | 2 +- docs/integrate-crewai/index.html | 2 +- docs/integrate-langchain/index.html | 4 +- docs/integrate-mastra/index.html | 4 +- docs/integrate-pydanticai/index.html | 6 +- docs/migrate-from-openai-responses/index.html | 437 ++++++++++++++++++ docs/ollama/index.html | 2 +- docs/responses-api/index.html | 2 +- docs/sidebar.js | 1 + docs/structured-output/index.html | 11 +- docs/transcription/index.html | 4 +- docs/vertex-ai/index.html | 2 +- fixtures/example-multi-turn.json | 2 +- fixtures/example-tool-call.json | 2 +- fixtures/examples/adk/gemini-agent.json | 8 +- fixtures/examples/langchain/agent-loop.json | 2 +- fixtures/examples/mastra/agent-workflow.json | 4 +- .../pydanticai/structured-output.json | 2 +- skills/write-fixtures/SKILL.md | 86 +++- src/stream-collapse.ts | 3 - 29 files changed, 780 insertions(+), 49 deletions(-) create mode 100644 docs/migrate-from-openai-responses/index.html diff --git a/CHANGELOG.md b/CHANGELOG.md index 94559d8..c743513 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,20 @@ # @copilotkit/aimock +## 1.14.0 + +### Minor Changes + +- Response template merging — override `id`, `created`, `model`, `usage`, `finishReason`, `role`, `systemFingerprint` on fixture responses across all 4 provider formats (OpenAI, Claude, Gemini, Responses API) (#111) +- JSON auto-stringify — fixture `arguments` and `content` fields accept objects that are auto-stringified by the loader, eliminating escaped JSON pain (#111) +- Migration guide from openai-responses-python (#111) +- All fixture examples and docs converted to object syntax (#111) + +### Patch Changes + +- Fix `onTranscription` docs to show correct 1-argument signature +- Fix `validateFixtures` to recognize ContentWithToolCalls and multimedia response types +- Add `ResponseOverrides` field validation in `validateFixtures` — catches invalid types for `id`, `created`, `model`, `usage`, `finishReason`, `role`, `systemFingerprint` + ## 1.13.0 ### Minor Changes diff --git a/README.md b/README.md index 982b679..2a6df7a 100644 --- a/README.md +++ b/README.md @@ -52,6 +52,7 @@ Run them all on one port with `npx aimock --config aimock.json`, or use the prog - **[Prometheus Metrics](https://aimock.copilotkit.dev/metrics)** — Request counts, latencies, fixture match rates - **[Docker + Helm](https://aimock.copilotkit.dev/docker)** — Container image and Helm chart for CI/CD - **[Vitest & Jest Plugins](https://aimock.copilotkit.dev/test-plugins)** — Zero-config `useAimock()` with auto lifecycle and env patching +- **[Response Overrides](https://aimock.copilotkit.dev/fixtures)** — Control `id`, `model`, `usage`, `finishReason` in fixture responses - **Zero dependencies** — Everything from Node.js builtins ## GitHub Action @@ -94,7 +95,7 @@ Test your AI agents with aimock — no API keys, no network calls: [LangChain](h ## Switching from other tools? -Step-by-step migration guides: [MSW](https://aimock.copilotkit.dev/migrate-from-msw) · [VidaiMock](https://aimock.copilotkit.dev/migrate-from-vidaimock) · [mock-llm](https://aimock.copilotkit.dev/migrate-from-mock-llm) · [piyook/llm-mock](https://aimock.copilotkit.dev/migrate-from-piyook) · [Python mocks](https://aimock.copilotkit.dev/migrate-from-python-mocks) · [Mokksy](https://aimock.copilotkit.dev/migrate-from-mokksy) +Step-by-step migration guides: [MSW](https://aimock.copilotkit.dev/migrate-from-msw) · [VidaiMock](https://aimock.copilotkit.dev/migrate-from-vidaimock) · [mock-llm](https://aimock.copilotkit.dev/migrate-from-mock-llm) · [piyook/llm-mock](https://aimock.copilotkit.dev/migrate-from-piyook) · [Python mocks](https://aimock.copilotkit.dev/migrate-from-python-mocks) · [openai-responses](https://aimock.copilotkit.dev/migrate-from-openai-responses) · [Mokksy](https://aimock.copilotkit.dev/migrate-from-mokksy) ## Documentation diff --git a/docs/aws-bedrock/index.html b/docs/aws-bedrock/index.html index 1d6c73e..b37c979 100644 --- a/docs/aws-bedrock/index.html +++ b/docs/aws-bedrock/index.html @@ -214,7 +214,7 @@

Fixture Examples

"response": { "toolCalls": [{ "name": "get_weather", - "arguments": "{\"city\":\"SF\"}" + "arguments": { "city": "SF" } }] } } diff --git a/docs/chat-completions/index.html b/docs/chat-completions/index.html index 1a689bb..3dbc84f 100644 --- a/docs/chat-completions/index.html +++ b/docs/chat-completions/index.html @@ -120,9 +120,10 @@

Unit Test: Tool Calls

tool-calls.test.ts ts
it("returns tool call in streaming mode", async () => {
+  // arguments accepts objects (auto-stringified) or JSON strings
   mock.on(
     { userMessage: "weather" },
-    { toolCalls: [{ name: "get_weather", arguments: '{"city":"SF"}' }] }
+    { toolCalls: [{ name: "get_weather", arguments: { city: "SF" } }] }
   );
 
   const res = await fetch(`${mock.url}/v1/chat/completions`, {
@@ -147,7 +148,7 @@ 

Integration Test: Streaming SSE

streaming-integration.test.ts ts
-
import { createServer, type ServerInstance } from "@copilotkit/aimock/server";
+          
import { createServer, type ServerInstance } from "@copilotkit/aimock";
 
 const instance = await createServer(
   [{ match: { userMessage: "hello" }, response: { content: "Hello! How can I help?" } }],
@@ -192,7 +193,7 @@ 

JSON Fixture

"response": { "toolCalls": [{ "name": "get_weather", - "arguments": "{\"city\":\"SF\"}" + "arguments": { "city": "SF" } }] } } diff --git a/docs/claude-messages/index.html b/docs/claude-messages/index.html index 5c97580..58c2841 100644 --- a/docs/claude-messages/index.html +++ b/docs/claude-messages/index.html @@ -106,7 +106,7 @@

Unit Test: Tool Use

const toolFixture = {
   match: { userMessage: "weather" },
   response: {
-    toolCalls: [{ name: "get_weather", arguments: '{"city":"NYC"}' }]
+    toolCalls: [{ name: "get_weather", arguments: { city: "NYC" } }]
   },
 };
 
diff --git a/docs/cohere/index.html b/docs/cohere/index.html
index 539791b..9491470 100644
--- a/docs/cohere/index.html
+++ b/docs/cohere/index.html
@@ -188,7 +188,7 @@ 

Fixture Examples

"toolCalls": [ { "name": "web_search", - "arguments": "{\"query\":\"latest news\"}" + "arguments": { "query": "latest news" } } ] } diff --git a/docs/docs/index.html b/docs/docs/index.html index 7863533..10a3488 100644 --- a/docs/docs/index.html +++ b/docs/docs/index.html @@ -362,6 +362,8 @@

Switching from other tools?

mock-llm · piyook/llm-mock · Python mocks · + openai-responses + · Mokksy
diff --git a/docs/fixtures/index.html b/docs/fixtures/index.html index b023802..c2d0e34 100644 --- a/docs/fixtures/index.html +++ b/docs/fixtures/index.html @@ -123,6 +123,13 @@

Match Fields

number Match on the Nth occurrence of this pattern + + endpoint + string + + Restrict to endpoint type: chat, image, speech, transcription, video, embedding + + predicate function @@ -152,6 +159,11 @@

Response Types

toolCalls[], finishReason? Function call(s) with name + arguments + + Content + Tool Calls + content, toolCalls[], reasoning?, finishReason? + Text and tool calls in a single response + Error error.message, error.type?, status? @@ -179,12 +191,99 @@

Response Types

Video - video.url, video.duration? + video.id, video.status, video.url? Generated video URL with async polling +
+

+ Override fields: Text, Tool Call, and Content + Tool Calls responses + also accept the override fields listed below (id, model, + usage, finishReason, role, + systemFingerprint, created). +

+
+ +
+

+ JSON auto-stringify: In fixture files and programmatic API, + arguments and content fields accept both objects and strings. + Objects are automatically stringified via JSON.stringify(). Use the object + form for readability — no more escaped JSON strings. +

+
+ +

Response Override Fields

+

+ Fixture responses can include optional fields to override auto-generated envelope values. + These map correctly across all provider formats (OpenAI, Claude, Gemini, Responses API). +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FieldTypeDescription
idstringOverride auto-generated response ID
creatednumberOverride Unix timestamp
modelstringOverride model name in response
usageobject + Override token counts: + { prompt_tokens, completion_tokens, total_tokens }. Also accepts + Anthropic field names (input_tokens, output_tokens) and + Gemini field names (promptTokenCount, + candidatesTokenCount, totalTokenCount). OpenAI Chat + Completions includes usage in the response body; the Responses API uses a separate + response.usage object. When omitted, token counts are auto-computed + from content length +
finishReasonstring + Override finish reason (default: "stop" or "tool_calls"). Provider mappings: + stopend_turn (Claude), STOP (Gemini); + tool_callstool_use (Claude), + FUNCTION_CALL (Gemini); length → + max_tokens (Claude), MAX_TOKENS (Gemini); + content_filterSAFETY (Gemini), + failed (Responses API) +
rolestringOverride message role (default: "assistant")
systemFingerprintstringAdd system_fingerprint to response
+

Fixture Options

@@ -199,7 +298,7 @@

Fixture Options

- + @@ -220,7 +319,7 @@

Fixture Options

@@ -228,7 +327,8 @@

Fixture Options

@@ -261,8 +361,8 @@

Programmatically

mock.onEmbedding("my text", { embedding: [0.1, 0.2] }); mock.onImage("sunset", { image: { url: "https://example.com/sunset.png" } }); mock.onSpeech("hello", { audio: "SGVsbG8=" }); -mock.onTranscription("audio.mp3", { transcription: { text: "Hello" } }); -mock.onVideo("cats", { video: { url: "https://example.com/cats.mp4" } }); +mock.onTranscription({ transcription: { text: "Hello" } }); +mock.onVideo("cats", { video: { id: "vid-1", status: "completed", url: "https://example.com/cats.mp4" } }); mock.onJsonOutput("data", { key: "value" }); mock.onToolResult("call_123", { content: "Done" }); @@ -305,6 +405,102 @@

Routing Rules

programmatic registration for predicate-based routing.

+ +

Provider Support Matrix

+
latency numberMilliseconds delay before first chunkMilliseconds delay between SSE chunks (streaming)
chunkSize streamingProfile object - Streaming physics profile: { ttftMs, tps, jitter }. See + Streaming physics profile: { ttft, tps, jitter }. See Streaming Physics
chaos object - Per-fixture chaos config: { errorRate, latencyMs, ... }. See + Per-fixture chaos config: { dropRate, malformedRate, disconnectRate }. + See Chaos Testing
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureOpenAI ChatOpenAI ResponsesClaudeGeminiBedrockAzureOllamaCohere
TextYesYesYesYesYesYesYesYes
Tool CallsYesYesYesYesYesYesYesYes
Content + Tool CallsYesYesYesYesYesYesYesYes
StreamingSSESSESSESSEBinary EventStreamSSENDJSONSSE
ReasoningYesYesYesYesYesYes
Web SearchesYes
Response OverridesYesYesYesYesYes
diff --git a/docs/gemini/index.html b/docs/gemini/index.html index 672e803..5fc6368 100644 --- a/docs/gemini/index.html +++ b/docs/gemini/index.html @@ -122,7 +122,7 @@

Unit Test: Tool Call

const toolFixture = {
   match: { userMessage: "weather" },
   response: {
-    toolCalls: [{ name: "get_weather", arguments: '{"city":"NYC"}' }]
+    toolCalls: [{ name: "get_weather", arguments: { city: "NYC" } }]
   },
 };
 
diff --git a/docs/integrate-adk/index.html b/docs/integrate-adk/index.html
index 17ace3b..a785a12 100644
--- a/docs/integrate-adk/index.html
+++ b/docs/integrate-adk/index.html
@@ -138,7 +138,7 @@ 

Function Calling

"toolCalls": [ { "name": "get_weather", - "arguments": "{\"city\":\"San Francisco\",\"unit\":\"fahrenheit\"}" + "arguments": { "city": "San Francisco", "unit": "fahrenheit" } } ] } diff --git a/docs/integrate-crewai/index.html b/docs/integrate-crewai/index.html index d6e3a13..5171b39 100644 --- a/docs/integrate-crewai/index.html +++ b/docs/integrate-crewai/index.html @@ -249,7 +249,7 @@

Tool Calls

"toolCalls": [ { "name": "web_search", - "arguments": "{\"query\": \"LLM testing frameworks 2025\"}" + "arguments": { "query": "LLM testing frameworks 2025" } } ] } diff --git a/docs/integrate-langchain/index.html b/docs/integrate-langchain/index.html index 35c96cc..bf5bdaf 100644 --- a/docs/integrate-langchain/index.html +++ b/docs/integrate-langchain/index.html @@ -121,7 +121,7 @@

Multi-Turn Agent Loops (LangGraph)

"match": { "userMessage": "plan a trip", "sequenceIndex": 1 }, "response": { "toolCalls": [ - { "name": "search_flights", "arguments": "{\"origin\":\"SFO\",\"dest\":\"NRT\"}" } + { "name": "search_flights", "arguments": { "origin": "SFO", "dest": "NRT" } } ] } }, @@ -159,7 +159,7 @@

Tool Call Fixtures

"toolCalls": [ { "name": "get_weather", - "arguments": "{\"location\":\"San Francisco\",\"unit\":\"fahrenheit\"}" + "arguments": { "location": "San Francisco", "unit": "fahrenheit" } } ] } diff --git a/docs/integrate-mastra/index.html b/docs/integrate-mastra/index.html index 936d8d6..3e42e43 100644 --- a/docs/integrate-mastra/index.html +++ b/docs/integrate-mastra/index.html @@ -126,7 +126,7 @@

Tool Call Workflows

"toolCalls": [ { "name": "search_flights", - "arguments": "{\"origin\":\"SFO\",\"destination\":\"NRT\",\"date\":\"2025-03-15\"}" + "arguments": { "origin": "SFO", "destination": "NRT", "date": "2025-03-15" } } ] } @@ -137,7 +137,7 @@

Tool Call Workflows

"toolCalls": [ { "name": "search_hotels", - "arguments": "{\"city\":\"Tokyo\",\"checkIn\":\"2025-03-15\",\"checkOut\":\"2025-03-22\"}" + "arguments": { "city": "Tokyo", "checkIn": "2025-03-15", "checkOut": "2025-03-22" } } ] } diff --git a/docs/integrate-pydanticai/index.html b/docs/integrate-pydanticai/index.html index 0dd22ce..0a8a7e4 100644 --- a/docs/integrate-pydanticai/index.html +++ b/docs/integrate-pydanticai/index.html @@ -136,7 +136,7 @@

Structured Output

"toolCalls": [ { "name": "final_result", - "arguments": "{\"city\": \"SF\", \"temp\": 72, \"unit\": \"fahrenheit\"}" + "arguments": { "city": "SF", "temp": 72, "unit": "fahrenheit" } } ] } @@ -163,7 +163,7 @@

Structured Output

{ "match": { "responseFormat": "json_object" }, "response": { - "content": "{\"city\": \"SF\", \"temp\": 72, \"unit\": \"fahrenheit\"}" + "content": { "city": "SF", "temp": 72, "unit": "fahrenheit" } } } ] @@ -218,7 +218,7 @@

Tool Calls

"toolCalls": [ { "name": "get_weather", - "arguments": "{\"city\": \"San Francisco\"}" + "arguments": { "city": "San Francisco" } } ] } diff --git a/docs/migrate-from-openai-responses/index.html b/docs/migrate-from-openai-responses/index.html new file mode 100644 index 0000000..3322aa7 --- /dev/null +++ b/docs/migrate-from-openai-responses/index.html @@ -0,0 +1,437 @@ + + + + + + From openai-responses — aimock + + + + + + + + + + + +
+ + +
+

Switching from openai-responses to aimock

+

+ openai-responses intercepts httpx calls to mock OpenAI responses inline. aimock runs a + real HTTP server with fixture files—no monkey-patching, works with any framework, + supports streaming. +

+ + +

Before / After

+

Side-by-side: mocking a chat completion with openai-responses vs. aimock.

+ +
+
+
+ openai-responses (~14 lines) py +
+
import openai_responses
+from openai import OpenAI
+
+@openai_responses.mock()
+def test_chat(openai_mock):
+    openai_mock.chat.completions.create.response = {
+        "choices": [{
+            "index": 0,
+            "message": {"role": "assistant", "content": "Hello!"},
+            "finish_reason": "stop"
+        }]
+    }
+    client = OpenAI()
+    result = client.chat.completions.create(
+        model="gpt-4o", messages=[{"role": "user", "content": "hi"}]
+    )
+    assert result.choices[0].message.content == "Hello!"
+
+ +
+
aimock (6 lines) py
+
from openai import OpenAI
+
+def test_chat(aimock):
+    aimock.on_message("hi", content="Hello!")
+    client = OpenAI(base_url=aimock.url + "/v1", api_key="test")
+    result = client.chat.completions.create(
+        model="gpt-4o", messages=[{"role": "user", "content": "hi"}]
+    )
+    assert result.choices[0].message.content == "Hello!"
+
+
+ +

Or with fixture files:

+ +
+
+
+ fixtures/chat.json json +
+
{
+  "fixtures": [
+    {
+      "match": { "userMessage": "hi" },
+      "response": { "content": "Hello!" }
+    }
+  ]
+}
+
+ +
+
test_chat.py py
+
def test_chat(aimock):
+    aimock.load_fixtures("./fixtures/chat.json")
+    client = OpenAI(base_url=aimock.url + "/v1", api_key="test")
+    result = client.chat.completions.create(
+        model="gpt-4o", messages=[{"role": "user", "content": "hi"}]
+    )
+    assert result.choices[0].message.content == "Hello!"
+
+
+ + +

Step-by-step migration

+ +
    +
  1. + Install aimock-pytest (replaces + pip install openai-responses) +
    +
    pip install aimock-pytest
    +
    +
  2. +
  3. + Convert inline mock definitions to fixture files or + on_message() calls. Instead of constructing the full response envelope + manually, just specify content or toolCalls—aimock + generates the envelope automatically. +
  4. +
  5. + Replace the decorator — + @openai_responses.mock() becomes the aimock pytest fixture + parameter (auto-provided by aimock-pytest). +
  6. +
  7. + Point the client at aimock — replace OpenAI() with + OpenAI(base_url=aimock.url + "/v1", api_key="test"). +
  8. +
+ + +

Feature mapping

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
openai-responsesaimock
@openai_responses.mock() decoratoraimock pytest fixture (auto-provided)
openai_mock.chat.completions.create.response = {...}aimock.on_message("pattern", content="...")
Partial envelope (choices required, other fields auto-filled) + Just specify content or toolCalls—envelope + auto-generated +
openai_mock.chat.completions.create.route.callsaimock.journal
Python + OpenAI onlyPython, TypeScript, any LLM provider
Manual SSE chunk construction (streaming.EventStream)Automatic SSE streaming from fixture content
No fixture filesJSON fixture files with match patterns
httpx monkey-patchingReal HTTP server—works with any HTTP client
✗ No record/replaynpx aimock --record captures real API calls
✗ No CI actionCopilotKit/aimock@v1 GitHub Action
✗ No chaos testingError injection, mid-stream disconnects
+ + +

What you gain

+ +
+
+
🌐
+

Cross-process, cross-language

+

+ Your Python tests, Node.js frontend, Go microservices, and Playwright E2E tests all + hit the same mock server. No per-language patching. +

+
+
+
+

Built-in SSE for 10+ providers

+

+ OpenAI, Claude, Gemini, Bedrock, Azure, Vertex AI, Ollama, Cohere. No manual chunk + construction. +

+
+
+
🔌
+

WebSocket APIs

+

+ OpenAI Realtime, Responses WS, Gemini Live. openai-responses cannot intercept + WebSocket. +

+
+
+
+

Record & Replay

+

+ Proxy real APIs, save as fixtures, replay forever. + npx aimock --record --provider-openai https://api.openai.com +

+
+
+
📁
+

Fixture files

+

+ JSON files on disk. Version-controlled. Shared across tests. No hand-crafted + envelopes. +

+
+
+
💥
+

Chaos testing

+

+ Inject latency, drop chunks, corrupt payloads mid-stream. Test your error handling + under realistic failure conditions. +

+
+
+ + +

CI with GitHub Action

+

One step replaces all the httpx monkey-patching infrastructure in CI.

+ +
+
+ .github/workflows/test.yml yaml +
+
name: Tests
+on: [push, pull_request]
+jobs:
+  test:
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v4
+
+      - uses: actions/setup-python@v5
+        with:
+          python-version: "3.12"
+
+      - name: Start aimock
+        uses: CopilotKit/aimock@v1
+        with:
+          fixtures: ./fixtures
+
+      - run: pip install -r requirements.txt
+      - run: pytest
+        env:
+          OPENAI_BASE_URL: http://127.0.0.1:4010/v1
+          OPENAI_API_KEY: mock-key
+
+ + +

CLI / Docker quick start

+ +
+
+
+
CLI sh
+
npx aimock -p 4010 -f ./fixtures
+
+
+
+
+
Docker sh
+
docker run -d -p 4010:4010 \
+  -v $(pwd)/fixtures:/fixtures \
+  ghcr.io/copilotkit/aimock:latest \
+  -p 4010 -f /fixtures
+
+
+
+
+ +
+ +
+ +
+ + + + diff --git a/docs/ollama/index.html b/docs/ollama/index.html index 83d954a..8776726 100644 --- a/docs/ollama/index.html +++ b/docs/ollama/index.html @@ -182,7 +182,7 @@

Tool Calls

"match": { "userMessage": "weather" }, "response": { "toolCalls": [ - { "name": "get_weather", "arguments": "{\"city\":\"NYC\"}" } + { "name": "get_weather", "arguments": { "city": "NYC" } } ] } } diff --git a/docs/responses-api/index.html b/docs/responses-api/index.html index 2dcd9d6..a396308 100644 --- a/docs/responses-api/index.html +++ b/docs/responses-api/index.html @@ -117,7 +117,7 @@

Unit Test: Tool Call Response

{ match: { userMessage: "weather" }, response: { - toolCalls: [{ name: "get_weather", arguments: '{"city":"NYC"}' }] + toolCalls: [{ name: "get_weather", arguments: { city: "NYC" } }] } } ]); diff --git a/docs/sidebar.js b/docs/sidebar.js index 8d092bd..c79ca3c 100644 --- a/docs/sidebar.js +++ b/docs/sidebar.js @@ -90,6 +90,7 @@ { label: "From mock-llm", href: "/migrate-from-mock-llm" }, { label: "From piyook/llm-mock", href: "/migrate-from-piyook" }, { label: "From Python Mocks", href: "/migrate-from-python-mocks" }, + { label: "From openai-responses", href: "/migrate-from-openai-responses" }, { label: "From Mokksy", href: "/migrate-from-mokksy" }, ], }, diff --git a/docs/structured-output/index.html b/docs/structured-output/index.html index ffdbe7d..a4d70a1 100644 --- a/docs/structured-output/index.html +++ b/docs/structured-output/index.html @@ -111,13 +111,22 @@

JSON Fixture

"responseFormat": "json_object" }, "response": { - "content": "{\"answer\":42,\"items\":[\"a\",\"b\"]}" + "content": { "answer": 42, "items": ["a", "b"] } } } ] }
+
+

+ Auto-stringify: The content field accepts objects in + fixture files. The loader detects typeof === "object" and calls + JSON.stringify() automatically. The escaped-string form + ("{\"answer\":42}") still works for backward compatibility. +

+
+

Match Behavior

diff --git a/docs/transcription/index.html b/docs/transcription/index.html index 0eb0653..cde8b37 100644 --- a/docs/transcription/index.html +++ b/docs/transcription/index.html @@ -96,7 +96,7 @@

Unit Test: Simple Transcription

}); it("returns simple transcription text", async () => { - mock.onTranscription("audio.mp3", { + mock.onTranscription({ transcription: { text: "Hello, how are you today?" }, }); @@ -121,7 +121,7 @@

Unit Test: Verbose Response with Segments

transcription-verbose.test.ts ts
it("returns verbose transcription with words and segments", async () => {
-  mock.onTranscription("meeting.wav", {
+  mock.onTranscription({
     transcription: {
       text: "Welcome to the meeting.",
       words: [
diff --git a/docs/vertex-ai/index.html b/docs/vertex-ai/index.html
index 078ee98..0d46602 100644
--- a/docs/vertex-ai/index.html
+++ b/docs/vertex-ai/index.html
@@ -185,7 +185,7 @@ 

Fixture Examples

"toolCalls": [ { "name": "analyze_data", - "arguments": "{\"dataset\":\"sales_q4\"}" + "arguments": { "dataset": "sales_q4" } } ] } diff --git a/fixtures/example-multi-turn.json b/fixtures/example-multi-turn.json index 7976f60..abeb3d4 100644 --- a/fixtures/example-multi-turn.json +++ b/fixtures/example-multi-turn.json @@ -3,7 +3,7 @@ { "match": { "userMessage": "change background to blue" }, "response": { - "toolCalls": [{ "name": "change_background", "arguments": "{\"background\":\"blue\"}" }] + "toolCalls": [{ "name": "change_background", "arguments": { "background": "blue" } }] } }, { diff --git a/fixtures/example-tool-call.json b/fixtures/example-tool-call.json index 9ad26ab..3c376d4 100644 --- a/fixtures/example-tool-call.json +++ b/fixtures/example-tool-call.json @@ -6,7 +6,7 @@ "toolCalls": [ { "name": "get_weather", - "arguments": "{\"location\":\"San Francisco\",\"unit\":\"fahrenheit\"}" + "arguments": { "location": "San Francisco", "unit": "fahrenheit" } } ] } diff --git a/fixtures/examples/adk/gemini-agent.json b/fixtures/examples/adk/gemini-agent.json index 929f125..5222d9f 100644 --- a/fixtures/examples/adk/gemini-agent.json +++ b/fixtures/examples/adk/gemini-agent.json @@ -6,7 +6,7 @@ "toolCalls": [ { "name": "get_weather", - "arguments": "{\"city\":\"San Francisco\",\"unit\":\"fahrenheit\"}" + "arguments": { "city": "San Francisco", "unit": "fahrenheit" } } ] } @@ -23,7 +23,7 @@ "toolCalls": [ { "name": "google_search", - "arguments": "{\"query\":\"latest AI news\"}" + "arguments": { "query": "latest AI news" } } ] } @@ -34,11 +34,11 @@ "toolCalls": [ { "name": "get_weather", - "arguments": "{\"city\":\"New York\",\"unit\":\"celsius\"}" + "arguments": { "city": "New York", "unit": "celsius" } }, { "name": "get_time", - "arguments": "{\"timezone\":\"America/New_York\"}" + "arguments": { "timezone": "America/New_York" } } ] } diff --git a/fixtures/examples/langchain/agent-loop.json b/fixtures/examples/langchain/agent-loop.json index 852e71f..8a4216d 100644 --- a/fixtures/examples/langchain/agent-loop.json +++ b/fixtures/examples/langchain/agent-loop.json @@ -12,7 +12,7 @@ "toolCalls": [ { "name": "search_flights", - "arguments": "{\"origin\":\"SFO\",\"dest\":\"NRT\"}" + "arguments": { "origin": "SFO", "dest": "NRT" } } ] } diff --git a/fixtures/examples/mastra/agent-workflow.json b/fixtures/examples/mastra/agent-workflow.json index 3ac6505..aa9a4d7 100644 --- a/fixtures/examples/mastra/agent-workflow.json +++ b/fixtures/examples/mastra/agent-workflow.json @@ -6,7 +6,7 @@ "toolCalls": [ { "name": "search_flights", - "arguments": "{\"origin\":\"SFO\",\"destination\":\"NRT\",\"date\":\"2025-03-15\"}" + "arguments": { "origin": "SFO", "destination": "NRT", "date": "2025-03-15" } } ] } @@ -17,7 +17,7 @@ "toolCalls": [ { "name": "search_hotels", - "arguments": "{\"city\":\"Tokyo\",\"checkIn\":\"2025-03-15\",\"checkOut\":\"2025-03-22\"}" + "arguments": { "city": "Tokyo", "checkIn": "2025-03-15", "checkOut": "2025-03-22" } } ] } diff --git a/fixtures/examples/pydanticai/structured-output.json b/fixtures/examples/pydanticai/structured-output.json index 3cca151..c5c47d3 100644 --- a/fixtures/examples/pydanticai/structured-output.json +++ b/fixtures/examples/pydanticai/structured-output.json @@ -6,7 +6,7 @@ "toolCalls": [ { "name": "final_result", - "arguments": "{\"city\": \"SF\", \"temp\": 72, \"unit\": \"fahrenheit\"}" + "arguments": { "city": "SF", "temp": 72, "unit": "fahrenheit" } } ] } diff --git a/skills/write-fixtures/SKILL.md b/skills/write-fixtures/SKILL.md index 066643c..c61f722 100644 --- a/skills/write-fixtures/SKILL.md +++ b/skills/write-fixtures/SKILL.md @@ -51,12 +51,18 @@ Multi-part content (e.g., `[{type: "text", text: "hello"}]`) is automatically ex ### Tool Calls ```typescript +// Preferred: object form (auto-stringified by the fixture loader) +{ + toolCalls: [{ name: "get_weather", arguments: { city: "SF" } }]; +} + +// Also accepted: JSON string form (backward compatible) { toolCalls: [{ name: "get_weather", arguments: '{"city":"SF"}' }]; } ``` -**`arguments` MUST be a JSON string**, not an object. This is the #1 mistake. +**Both object and string forms are accepted** for `arguments`. The fixture loader auto-stringifies objects via `JSON.stringify()`. Object form is preferred for readability. ### Embedding @@ -106,7 +112,7 @@ Use `match: { endpoint: "image" }` to prevent cross-matching with chat fixtures. ### Video ```typescript -{ video: { url: "https://example.com/video.mp4", duration: 10 } } +{ video: { id: "vid-1", status: "completed", url: "https://example.com/video.mp4" } } ``` Video uses async polling — `POST /v1/videos` creates, `GET /v1/videos/{id}` checks status. @@ -148,7 +154,7 @@ The most common pattern. Fixture 1 triggers the tool call, fixture 2 handles the ```typescript // Step 1: User asks about weather → LLM calls tool mock.onMessage("weather", { - toolCalls: [{ name: "get_weather", arguments: '{"city":"SF"}' }], + toolCalls: [{ name: "get_weather", arguments: { city: "SF" } }], }); // Step 2: Tool result comes back → LLM responds with text @@ -198,7 +204,7 @@ mock.addFixture({ // First call returns tool call, second returns text mock.on( { userMessage: "status", sequenceIndex: 0 }, - { toolCalls: [{ name: "check_status", arguments: "{}" }] }, + { toolCalls: [{ name: "check_status", arguments: {} }] }, ); mock.on({ userMessage: "status", sequenceIndex: 1 }, { content: "All systems operational." }); ``` @@ -233,7 +239,7 @@ mock.addFixture({ return typeof sys === "string" && sys.includes("Flights found: false"); }, }, - response: { toolCalls: [{ name: "search_flights", arguments: "{}" }] }, + response: { toolCalls: [{ name: "search_flights", arguments: {} }] }, }); ``` @@ -307,6 +313,17 @@ mock.nextRequestError(429, { message: "Rate limited", type: "rate_limit_error" } "match": { "userMessage": "hello" }, "response": { "content": "Hi!" } }, + { + "match": { "userMessage": "weather" }, + "response": { + "toolCalls": [ + { + "name": "get_weather", + "arguments": { "city": "SF", "units": "fahrenheit" } + } + ] + } + }, { "match": { "inputText": "search query" }, "response": { "embedding": [0.1, 0.2, 0.3] } @@ -319,6 +336,8 @@ mock.nextRequestError(429, { message: "Rate limited", type: "rate_limit_error" } } ``` +**JSON auto-stringify**: In JSON fixture files, `arguments` and `content` can be objects — the loader auto-stringifies them with `JSON.stringify()`. The escaped-string form (`"{\"city\":\"SF\"}"`) still works but objects are preferred for readability. + JSON files cannot use `RegExp` or `predicate` — those are code-only features. `streamingProfile` is supported in JSON fixture files. Load with `mock.loadFixtureFile("./fixtures/greetings.json")` or `mock.loadFixtureDir("./fixtures/")`. @@ -360,11 +379,64 @@ All providers share the same fixture pool — write fixtures once, they work for | `POST /v1/videos` | OpenAI | HTTP | | `GET /v1/videos/{id}` | OpenAI | HTTP | +## Response Template Overrides + +Fixture responses can include optional override fields to control auto-generated envelope values. These are merged into the provider-specific response format (OpenAI, Claude, Gemini, Responses API). + +| Field | Type | Default | Description | +| ------------------- | ------ | ------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `id` | string | auto-generated | Override response ID (e.g., `chatcmpl-custom`) | +| `created` | number | `Date.now()/1000` | Override Unix timestamp | +| `model` | string | echoes request | Override model name in response | +| `usage` | object | zeroed | Override token counts: `{ prompt_tokens, completion_tokens, total_tokens }`. OpenAI Chat includes usage in response body; Responses API uses `response.usage`. When omitted, auto-computed from content length | +| `finishReason` | string | `"stop"` / `"tool_calls"` | Override finish reason. Mappings: `stop` -> `end_turn` (Claude), `STOP` (Gemini); `tool_calls` -> `tool_use` (Claude), `FUNCTION_CALL` (Gemini); `length` -> `max_tokens` (Claude), `MAX_TOKENS` (Gemini); `content_filter` -> `SAFETY` (Gemini), `failed` (Responses API) | +| `role` | string | `"assistant"` | Override message role | +| `systemFingerprint` | string | (omitted) | Add `system_fingerprint` to response | + +### Example + +```typescript +mock.onMessage("hello", { + content: "Hi!", + model: "gpt-4-turbo-2024-04-09", + usage: { prompt_tokens: 10, completion_tokens: 5, total_tokens: 15 }, + systemFingerprint: "fp_abc123", +}); +``` + +### In JSON fixtures + +```json +{ + "match": { "userMessage": "hello" }, + "response": { + "content": "Hi!", + "model": "gpt-4-turbo-2024-04-09", + "usage": { "prompt_tokens": 10, "completion_tokens": 5, "total_tokens": 15 }, + "systemFingerprint": "fp_abc123" + } +} +``` + +These fields map correctly across all provider formats — for example, `finishReason: "stop"` becomes `finish_reason: "stop"` in OpenAI, `stop_reason: "end_turn"` in Claude, and `finishReason: "STOP"` in Gemini. + +## Provider Support Matrix + +| Feature | OpenAI Chat | OpenAI Responses | Claude | Gemini | Bedrock | Azure | Ollama | Cohere | +| -------------------- | ----------- | ---------------- | ------ | ------ | ------- | ----- | ------ | ------ | +| Text | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | +| Tool Calls | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | +| Content + Tool Calls | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | +| Streaming | SSE | SSE | SSE | SSE | Binary | SSE | NDJSON | SSE | +| Reasoning | Yes | Yes | Yes | Yes | Yes | Yes | -- | -- | +| Web Searches | -- | Yes | -- | -- | -- | -- | -- | -- | +| Response Overrides | Yes | Yes | Yes | Yes | -- | Yes | -- | -- | + ## Critical Gotchas 1. **Order matters** — first match wins. Specific fixtures before general ones. Use `prependFixture()` to force priority. -2. **`arguments` must be a JSON string** — `"arguments": "{\"key\":\"value\"}"` not `"arguments": {"key":"value"}`. The type system enforces this but JSON fixtures can get it wrong silently. +2. **`arguments` accepts both objects and strings** — `"arguments": {"key":"value"}` (preferred, auto-stringified) or `"arguments": "{\"key\":\"value\"}"` (legacy). The same applies to `content` fields that contain JSON. The fixture loader detects `typeof === "object"` and calls `JSON.stringify()` automatically. 3. **Latency is per-chunk, not total** — `latency: 100` means 100ms between each SSE chunk, not 100ms total response time. Similarly, `truncateAfterChunks` and `disconnectAfterMs` are for simulating stream interruptions (added in v1.3.0). @@ -611,7 +683,7 @@ const mock = await LLMock.create({ port: 0 }); // creates + starts in one call | `onModerate(pattern, result)` | Match moderation requests by input | | `onImage(pattern, response)` | Match image generation by prompt | | `onSpeech(pattern, response)` | Match TTS by input text | -| `onTranscription(match, response)` | Match audio transcription | +| `onTranscription(response)` | Match audio transcription | | `onVideo(pattern, response)` | Match video generation by prompt | | `mount(path, handler)` | Mount a Mountable (VectorMock, etc.) | | `url` / `baseUrl` | Server URL (throws if not started) | diff --git a/src/stream-collapse.ts b/src/stream-collapse.ts index c50e87c..31bad19 100644 --- a/src/stream-collapse.ts +++ b/src/stream-collapse.ts @@ -15,9 +15,6 @@ import type { Logger } from "./logger.js"; // Result type shared by all collapse functions // --------------------------------------------------------------------------- -// TODO: Consider making this a discriminated union ({ type: "text"; content: string } -// | { type: "toolCalls"; toolCalls: ToolCall[] } | { type: "empty" }) to prevent -// ambiguous results and simplify downstream consumers. export interface CollapseResult { content?: string; reasoning?: string; From 320d4669d43fd09208bdcd0292f7a2bc1b14b9f7 Mon Sep 17 00:00:00 2001 From: Jordan Ritter Date: Wed, 15 Apr 2026 16:38:51 -0700 Subject: [PATCH 4/4] chore: release v1.14.0 --- package-lock.json | 7134 +++++++++++++++++++++++++++++++++++++++++++++ package.json | 2 +- 2 files changed, 7135 insertions(+), 1 deletion(-) create mode 100644 package-lock.json diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..1782bab --- /dev/null +++ b/package-lock.json @@ -0,0 +1,7134 @@ +{ + "name": "@copilotkit/aimock", + "version": "1.14.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "@copilotkit/aimock", + "version": "1.14.0", + "license": "MIT", + "bin": { + "aimock": "dist/aimock-cli.js", + "llmock": "dist/cli.js" + }, + "devDependencies": { + "@anthropic-ai/sdk": "^0.78.0", + "@arethetypeswrong/cli": "^0.17.3", + "@commitlint/cli": "^19.8.1", + "@commitlint/config-conventional": "^19.8.0", + "@eslint/js": "^9.30.0", + "@google/generative-ai": "^0.24.0", + "@types/node": "^22.0.0", + "@vitest/coverage-v8": "^3.2.4", + "eslint": "^9.30.0", + "eslint-config-prettier": "^10.1.5", + "husky": "^9.1.7", + "lint-staged": "^16.3.2", + "openai": "^4.0.0", + "prettier": "^3.6.2", + "publint": "^0.3.12", + "tsdown": "^0.12.5", + "tsx": "^4.19.0", + "typescript": "^5.8.3", + "typescript-eslint": "^8.35.1", + "vitest": "^3.2.1" + }, + "engines": { + "node": ">=20.15.0" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@andrewbranch/untar.js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@andrewbranch/untar.js/-/untar.js-1.0.3.tgz", + "integrity": "sha512-Jh15/qVmrLGhkKJBdXlK1+9tY4lZruYjsgkDFj08ZmDiWVBLJcqkok7Z0/R0In+i1rScBpJlSvrTS2Lm41Pbnw==", + "dev": true + }, + "node_modules/@anthropic-ai/sdk": { + "version": "0.78.0", + "resolved": "https://registry.npmjs.org/@anthropic-ai/sdk/-/sdk-0.78.0.tgz", + "integrity": "sha512-PzQhR715td/m1UaaN5hHXjYB8Gl2lF9UVhrrGrZeysiF6Rb74Wc9GCB8hzLdzmQtBd1qe89F9OptgB9Za1Ib5w==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-schema-to-ts": "^3.1.1" + }, + "bin": { + "anthropic-ai-sdk": "bin/cli" + }, + "peerDependencies": { + "zod": "^3.25.0 || ^4.0.0" + }, + "peerDependenciesMeta": { + "zod": { + "optional": true + } + } + }, + "node_modules/@arethetypeswrong/cli": { + "version": "0.17.4", + "resolved": "https://registry.npmjs.org/@arethetypeswrong/cli/-/cli-0.17.4.tgz", + "integrity": "sha512-AeiKxtf67XD/NdOqXgBOE5TZWH3EOCt+0GkbUpekOzngc+Q/cRZ5azjWyMxISxxfp0EItgm5NoSld9p7BAA5xQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@arethetypeswrong/core": "0.17.4", + "chalk": "^4.1.2", + "cli-table3": "^0.6.3", + "commander": "^10.0.1", + "marked": "^9.1.2", + "marked-terminal": "^7.1.0", + "semver": "^7.5.4" + }, + "bin": { + "attw": "dist/index.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@arethetypeswrong/cli/node_modules/@arethetypeswrong/core": { + "version": "0.17.4", + "resolved": "https://registry.npmjs.org/@arethetypeswrong/core/-/core-0.17.4.tgz", + "integrity": "sha512-Izvir8iIoU+X4SKtDAa5kpb+9cpifclzsbA8x/AZY0k0gIfXYQ1fa1B6Epfe6vNA2YfDX8VtrZFgvnXB6aPEoQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@andrewbranch/untar.js": "^1.0.3", + "@loaderkit/resolve": "^1.0.2", + "cjs-module-lexer": "^1.2.3", + "fflate": "^0.8.2", + "lru-cache": "^10.4.3", + "semver": "^7.5.4", + "typescript": "5.6.1-rc", + "validate-npm-package-name": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@arethetypeswrong/cli/node_modules/typescript": { + "version": "5.6.1-rc", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.1-rc.tgz", + "integrity": "sha512-E3b2+1zEFu84jB0YQi9BORDjz9+jGbwwy1Zi3G0LUNw7a7cePUrHMRNy8aPh53nXpkFGVHSxIZo5vKTfYaFiBQ==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/@arethetypeswrong/core": { + "version": "0.18.2", + "resolved": "https://registry.npmjs.org/@arethetypeswrong/core/-/core-0.18.2.tgz", + "integrity": "sha512-GiwTmBFOU1/+UVNqqCGzFJYfBXEytUkiI+iRZ6Qx7KmUVtLm00sYySkfe203C9QtPG11yOz1ZaMek8dT/xnlgg==", + "extraneous": true, + "license": "MIT", + "dependencies": { + "@andrewbranch/untar.js": "^1.0.3", + "@loaderkit/resolve": "^1.0.2", + "cjs-module-lexer": "^1.2.3", + "fflate": "^0.8.2", + "lru-cache": "^11.0.1", + "semver": "^7.5.4", + "typescript": "5.6.1-rc", + "validate-npm-package-name": "^5.0.0" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@arethetypeswrong/core/node_modules/lru-cache": { + "version": "11.3.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.3.5.tgz", + "integrity": "sha512-NxVFwLAnrd9i7KUBxC4DrUhmgjzOs+1Qm50D3oF1/oL+r1NpZ4gA7xvG0/zJ8evR7zIKn4vLf7qTNduWFtCrRw==", + "extraneous": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/@arethetypeswrong/core/node_modules/typescript": { + "version": "5.6.1-rc", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.1-rc.tgz", + "integrity": "sha512-E3b2+1zEFu84jB0YQi9BORDjz9+jGbwwy1Zi3G0LUNw7a7cePUrHMRNy8aPh53nXpkFGVHSxIZo5vKTfYaFiBQ==", + "extraneous": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz", + "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.28.5", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/code-frame/node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@babel/generator": { + "version": "7.29.1", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz", + "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.0", + "@babel/types": "^7.29.0", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.2.tgz", + "integrity": "sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.0" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.2.tgz", + "integrity": "sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", + "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@bcoe/v8-coverage": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-1.0.2.tgz", + "integrity": "sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@braidai/lang": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@braidai/lang/-/lang-1.1.2.tgz", + "integrity": "sha512-qBcknbBufNHlui137Hft8xauQMTZDKdophmLFv05r2eNmdIv/MlPuP4TdUknHG68UdWLgVZwgxVe735HzJNIwA==", + "dev": true, + "license": "ISC" + }, + "node_modules/@colors/colors": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", + "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/@commitlint/cli": { + "version": "19.8.1", + "resolved": "https://registry.npmjs.org/@commitlint/cli/-/cli-19.8.1.tgz", + "integrity": "sha512-LXUdNIkspyxrlV6VDHWBmCZRtkEVRpBKxi2Gtw3J54cGWhLCTouVD/Q6ZSaSvd2YaDObWK8mDjrz3TIKtaQMAA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/format": "^19.8.1", + "@commitlint/lint": "^19.8.1", + "@commitlint/load": "^19.8.1", + "@commitlint/read": "^19.8.1", + "@commitlint/types": "^19.8.1", + "tinyexec": "^1.0.0", + "yargs": "^17.0.0" + }, + "bin": { + "commitlint": "cli.js" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/config-conventional": { + "version": "19.8.1", + "resolved": "https://registry.npmjs.org/@commitlint/config-conventional/-/config-conventional-19.8.1.tgz", + "integrity": "sha512-/AZHJL6F6B/G959CsMAzrPKKZjeEiAVifRyEwXxcT6qtqbPwGw+iQxmNS+Bu+i09OCtdNRW6pNpBvgPrtMr9EQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/types": "^19.8.1", + "conventional-changelog-conventionalcommits": "^7.0.2" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/config-validator": { + "version": "19.8.1", + "resolved": "https://registry.npmjs.org/@commitlint/config-validator/-/config-validator-19.8.1.tgz", + "integrity": "sha512-0jvJ4u+eqGPBIzzSdqKNX1rvdbSU1lPNYlfQQRIFnBgLy26BtC0cFnr7c/AyuzExMxWsMOte6MkTi9I3SQ3iGQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/types": "^19.8.1", + "ajv": "^8.11.0" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/ensure": { + "version": "19.8.1", + "resolved": "https://registry.npmjs.org/@commitlint/ensure/-/ensure-19.8.1.tgz", + "integrity": "sha512-mXDnlJdvDzSObafjYrOSvZBwkD01cqB4gbnnFuVyNpGUM5ijwU/r/6uqUmBXAAOKRfyEjpkGVZxaDsCVnHAgyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/types": "^19.8.1", + "lodash.camelcase": "^4.3.0", + "lodash.kebabcase": "^4.1.1", + "lodash.snakecase": "^4.1.1", + "lodash.startcase": "^4.4.0", + "lodash.upperfirst": "^4.3.1" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/execute-rule": { + "version": "19.8.1", + "resolved": "https://registry.npmjs.org/@commitlint/execute-rule/-/execute-rule-19.8.1.tgz", + "integrity": "sha512-YfJyIqIKWI64Mgvn/sE7FXvVMQER/Cd+s3hZke6cI1xgNT/f6ZAz5heND0QtffH+KbcqAwXDEE1/5niYayYaQA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/format": { + "version": "19.8.1", + "resolved": "https://registry.npmjs.org/@commitlint/format/-/format-19.8.1.tgz", + "integrity": "sha512-kSJj34Rp10ItP+Eh9oCItiuN/HwGQMXBnIRk69jdOwEW9llW9FlyqcWYbHPSGofmjsqeoxa38UaEA5tsbm2JWw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/types": "^19.8.1", + "chalk": "^5.3.0" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/format/node_modules/chalk": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", + "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@commitlint/is-ignored": { + "version": "19.8.1", + "resolved": "https://registry.npmjs.org/@commitlint/is-ignored/-/is-ignored-19.8.1.tgz", + "integrity": "sha512-AceOhEhekBUQ5dzrVhDDsbMaY5LqtN8s1mqSnT2Kz1ERvVZkNihrs3Sfk1Je/rxRNbXYFzKZSHaPsEJJDJV8dg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/types": "^19.8.1", + "semver": "^7.6.0" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/lint": { + "version": "19.8.1", + "resolved": "https://registry.npmjs.org/@commitlint/lint/-/lint-19.8.1.tgz", + "integrity": "sha512-52PFbsl+1EvMuokZXLRlOsdcLHf10isTPlWwoY1FQIidTsTvjKXVXYb7AvtpWkDzRO2ZsqIgPK7bI98x8LRUEw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/is-ignored": "^19.8.1", + "@commitlint/parse": "^19.8.1", + "@commitlint/rules": "^19.8.1", + "@commitlint/types": "^19.8.1" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/load": { + "version": "19.8.1", + "resolved": "https://registry.npmjs.org/@commitlint/load/-/load-19.8.1.tgz", + "integrity": "sha512-9V99EKG3u7z+FEoe4ikgq7YGRCSukAcvmKQuTtUyiYPnOd9a2/H9Ak1J9nJA1HChRQp9OA/sIKPugGS+FK/k1A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/config-validator": "^19.8.1", + "@commitlint/execute-rule": "^19.8.1", + "@commitlint/resolve-extends": "^19.8.1", + "@commitlint/types": "^19.8.1", + "chalk": "^5.3.0", + "cosmiconfig": "^9.0.0", + "cosmiconfig-typescript-loader": "^6.1.0", + "lodash.isplainobject": "^4.0.6", + "lodash.merge": "^4.6.2", + "lodash.uniq": "^4.5.0" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/load/node_modules/chalk": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", + "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@commitlint/message": { + "version": "19.8.1", + "resolved": "https://registry.npmjs.org/@commitlint/message/-/message-19.8.1.tgz", + "integrity": "sha512-+PMLQvjRXiU+Ae0Wc+p99EoGEutzSXFVwQfa3jRNUZLNW5odZAyseb92OSBTKCu+9gGZiJASt76Cj3dLTtcTdg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/parse": { + "version": "19.8.1", + "resolved": "https://registry.npmjs.org/@commitlint/parse/-/parse-19.8.1.tgz", + "integrity": "sha512-mmAHYcMBmAgJDKWdkjIGq50X4yB0pSGpxyOODwYmoexxxiUCy5JJT99t1+PEMK7KtsCtzuWYIAXYAiKR+k+/Jw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/types": "^19.8.1", + "conventional-changelog-angular": "^7.0.0", + "conventional-commits-parser": "^5.0.0" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/read": { + "version": "19.8.1", + "resolved": "https://registry.npmjs.org/@commitlint/read/-/read-19.8.1.tgz", + "integrity": "sha512-03Jbjb1MqluaVXKHKRuGhcKWtSgh3Jizqy2lJCRbRrnWpcM06MYm8th59Xcns8EqBYvo0Xqb+2DoZFlga97uXQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/top-level": "^19.8.1", + "@commitlint/types": "^19.8.1", + "git-raw-commits": "^4.0.0", + "minimist": "^1.2.8", + "tinyexec": "^1.0.0" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/resolve-extends": { + "version": "19.8.1", + "resolved": "https://registry.npmjs.org/@commitlint/resolve-extends/-/resolve-extends-19.8.1.tgz", + "integrity": "sha512-GM0mAhFk49I+T/5UCYns5ayGStkTt4XFFrjjf0L4S26xoMTSkdCf9ZRO8en1kuopC4isDFuEm7ZOm/WRVeElVg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/config-validator": "^19.8.1", + "@commitlint/types": "^19.8.1", + "global-directory": "^4.0.1", + "import-meta-resolve": "^4.0.0", + "lodash.mergewith": "^4.6.2", + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/rules": { + "version": "19.8.1", + "resolved": "https://registry.npmjs.org/@commitlint/rules/-/rules-19.8.1.tgz", + "integrity": "sha512-Hnlhd9DyvGiGwjfjfToMi1dsnw1EXKGJNLTcsuGORHz6SS9swRgkBsou33MQ2n51/boIDrbsg4tIBbRpEWK2kw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/ensure": "^19.8.1", + "@commitlint/message": "^19.8.1", + "@commitlint/to-lines": "^19.8.1", + "@commitlint/types": "^19.8.1" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/to-lines": { + "version": "19.8.1", + "resolved": "https://registry.npmjs.org/@commitlint/to-lines/-/to-lines-19.8.1.tgz", + "integrity": "sha512-98Mm5inzbWTKuZQr2aW4SReY6WUukdWXuZhrqf1QdKPZBCCsXuG87c+iP0bwtD6DBnmVVQjgp4whoHRVixyPBg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/top-level": { + "version": "19.8.1", + "resolved": "https://registry.npmjs.org/@commitlint/top-level/-/top-level-19.8.1.tgz", + "integrity": "sha512-Ph8IN1IOHPSDhURCSXBz44+CIu+60duFwRsg6HqaISFHQHbmBtxVw4ZrFNIYUzEP7WwrNPxa2/5qJ//NK1FGcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "find-up": "^7.0.0" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/types": { + "version": "19.8.1", + "resolved": "https://registry.npmjs.org/@commitlint/types/-/types-19.8.1.tgz", + "integrity": "sha512-/yCrWGCoA1SVKOks25EGadP9Pnj0oAIHGpl2wH2M2Y46dPM2ueb8wyCVOD7O3WCTkaJ0IkKvzhl1JY7+uCT2Dw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/conventional-commits-parser": "^5.0.0", + "chalk": "^5.3.0" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/types/node_modules/chalk": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", + "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@emnapi/core": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.9.2.tgz", + "integrity": "sha512-UC+ZhH3XtczQYfOlu3lNEkdW/p4dsJ1r/bP7H8+rhao3TTTMO1ATq/4DdIi23XuGoFY+Cz0JmCbdVl0hz9jZcA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.2.1", + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.9.2.tgz", + "integrity": "sha512-3U4+MIWHImeyu1wnmVygh5WlgfYDtyf0k8AbLhMFxOipihf6nrWC4syIm/SwEeec0mNSafiiNnMJwbza/Is6Lw==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/wasi-threads": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz", + "integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.7.tgz", + "integrity": "sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.7.tgz", + "integrity": "sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.7.tgz", + "integrity": "sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.7.tgz", + "integrity": "sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.7.tgz", + "integrity": "sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.7.tgz", + "integrity": "sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.7.tgz", + "integrity": "sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.7.tgz", + "integrity": "sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.7.tgz", + "integrity": "sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.7.tgz", + "integrity": "sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.7.tgz", + "integrity": "sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.7.tgz", + "integrity": "sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.7.tgz", + "integrity": "sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.7.tgz", + "integrity": "sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.7.tgz", + "integrity": "sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.7.tgz", + "integrity": "sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.7.tgz", + "integrity": "sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.7.tgz", + "integrity": "sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.7.tgz", + "integrity": "sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.7.tgz", + "integrity": "sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.7.tgz", + "integrity": "sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.7.tgz", + "integrity": "sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.7.tgz", + "integrity": "sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.7.tgz", + "integrity": "sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.7.tgz", + "integrity": "sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.7.tgz", + "integrity": "sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", + "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", + "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.21.2", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.2.tgz", + "integrity": "sha512-nJl2KGTlrf9GjLimgIru+V/mzgSK0ABCDQRvxw5BjURL7WfH5uoWmizbH7QB6MmnMBd8cIC9uceWnezL1VZWWw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^2.1.7", + "debug": "^4.3.1", + "minimatch": "^3.1.5" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/config-helpers": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz", + "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.17.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/core": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz", + "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.5.tgz", + "integrity": "sha512-4IlJx0X0qftVsN5E+/vGujTRIFtwuLbNsVUe7TO6zYPDR1O6nFwvwhIKEKSrl6dZchmYBITazxKoUYOjdtjlRg==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.14.0", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.1", + "minimatch": "^3.1.5", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/ajv": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", + "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/@eslint/eslintrc/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@eslint/js": { + "version": "9.39.4", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.4.tgz", + "integrity": "sha512-nE7DEIchvtiFTwBw4Lfbu59PG+kCofhjsKaCWzxTpt4lfRjRMqG6uMBzKXuEcyXhOHoUp9riAm7/aWYGhXZ9cw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.7.tgz", + "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz", + "integrity": "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.17.0", + "levn": "^0.4.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@google/generative-ai": { + "version": "0.24.1", + "resolved": "https://registry.npmjs.org/@google/generative-ai/-/generative-ai-0.24.1.tgz", + "integrity": "sha512-MqO+MLfM6kjxcKoy0p1wRzG3b4ZZXtPI+z2IE26UogS2Cm/XHO+7gGRBh6gcJsOiIVoH93UwKvW4HdgiOZCy9Q==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@humanfs/core": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.7", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.7.tgz", + "integrity": "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.4.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@isaacs/cliui/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.6.tgz", + "integrity": "sha512-+Sg6GCR/wy1oSmQDFq4LQDAhm3ETKnorxN+y5nbLULOR3P0c14f2Wurzj3/xqPXtasLFfHd5iRFQ7AJt4KH2cw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@loaderkit/resolve": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@loaderkit/resolve/-/resolve-1.0.4.tgz", + "integrity": "sha512-rJzYKVcV4dxJv+vW6jlvagF8zvGxHJ2+HTr1e2qOejfmGhAApgJHl8Aog4mMszxceTRiKTTbnpgmTO1bEZHV/A==", + "dev": true, + "license": "ISC", + "dependencies": { + "@braidai/lang": "^1.0.0" + } + }, + "node_modules/@napi-rs/wasm-runtime": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.3.tgz", + "integrity": "sha512-xK9sGVbJWYb08+mTJt3/YV24WxvxpXcXtP6B172paPZ+Ts69Re9dAr7lKwJoeIx8OoeuimEiRZ7umkiUVClmmQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@tybys/wasm-util": "^0.10.1" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + }, + "peerDependencies": { + "@emnapi/core": "^1.7.1", + "@emnapi/runtime": "^1.7.1" + } + }, + "node_modules/@oxc-project/types": { + "version": "0.124.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.124.0.tgz", + "integrity": "sha512-VBFWMTBvHxS11Z5Lvlr3IWgrwhMTXV+Md+EQF0Xf60+wAdsGFTBx7X7K/hP4pi8N7dcm1RvcHwDxZ16Qx8keUg==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/Boshen" + } + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@publint/pack": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/@publint/pack/-/pack-0.1.4.tgz", + "integrity": "sha512-HDVTWq3H0uTXiU0eeSQntcVUTPP3GamzeXI41+x7uU9J65JgWQh3qWZHblR1i0npXfFtF+mxBiU2nJH8znxWnQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://bjornlu.com/sponsor" + } + }, + "node_modules/@quansync/fs": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@quansync/fs/-/fs-1.0.0.tgz", + "integrity": "sha512-4TJ3DFtlf1L5LDMaM6CanJ/0lckGNtJcMjQ1NAV6zDmA0tEHKZtxNKin8EgPaVX1YzljbxckyT2tJrpQKAtngQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "quansync": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sxzz" + } + }, + "node_modules/@rolldown/binding-android-arm64": { + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-rc.15.tgz", + "integrity": "sha512-YYe6aWruPZDtHNpwu7+qAHEMbQ/yRl6atqb/AhznLTnD3UY99Q1jE7ihLSahNWkF4EqRPVC4SiR4O0UkLK02tA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-arm64": { + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0-rc.15.tgz", + "integrity": "sha512-oArR/ig8wNTPYsXL+Mzhs0oxhxfuHRfG7Ikw7jXsw8mYOtk71W0OkF2VEVh699pdmzjPQsTjlD1JIOoHkLP1Fg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-x64": { + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0-rc.15.tgz", + "integrity": "sha512-YzeVqOqjPYvUbJSWJ4EDL8ahbmsIXQpgL3JVipmN+MX0XnXMeWomLN3Fb+nwCmP/jfyqte5I3XRSm7OfQrbyxw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-freebsd-x64": { + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0-rc.15.tgz", + "integrity": "sha512-9Erhx956jeQ0nNTyif1+QWAXDRD38ZNjr//bSHrt6wDwB+QkAfl2q6Mn1k6OBPerznjRmbM10lgRb1Pli4xZPw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm-gnueabihf": { + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0-rc.15.tgz", + "integrity": "sha512-cVwk0w8QbZJGTnP/AHQBs5yNwmpgGYStL88t4UIaqcvYJWBfS0s3oqVLZPwsPU6M0zlW4GqjP0Zq5MnAGwFeGA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-gnu": { + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-rc.15.tgz", + "integrity": "sha512-eBZ/u8iAK9SoHGanqe/jrPnY0JvBN6iXbVOsbO38mbz+ZJsaobExAm1Iu+rxa4S1l2FjG0qEZn4Rc6X8n+9M+w==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-musl": { + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-rc.15.tgz", + "integrity": "sha512-ZvRYMGrAklV9PEkgt4LQM6MjQX2P58HPAuecwYObY2DhS2t35R0I810bKi0wmaYORt6m/2Sm+Z+nFgb0WhXNcQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-ppc64-gnu": { + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.0-rc.15.tgz", + "integrity": "sha512-VDpgGBzgfg5hLg+uBpCLoFG5kVvEyafmfxGUV0UHLcL5irxAK7PKNeC2MwClgk6ZAiNhmo9FLhRYgvMmedLtnQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-s390x-gnu": { + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.0-rc.15.tgz", + "integrity": "sha512-y1uXY3qQWCzcPgRJATPSOUP4tCemh4uBdY7e3EZbVwCJTY3gLJWnQABgeUetvED+bt1FQ01OeZwvhLS2bpNrAQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-gnu": { + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0-rc.15.tgz", + "integrity": "sha512-023bTPBod7J3Y/4fzAN6QtpkSABR0rigtrwaP+qSEabUh5zf6ELr9Nc7GujaROuPY3uwdSIXWrvhn1KxOvurWA==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-musl": { + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0-rc.15.tgz", + "integrity": "sha512-witB2O0/hU4CgfOOKUoeFgQ4GktPi1eEbAhaLAIpgD6+ZnhcPkUtPsoKKHRzmOoWPZue46IThdSgdo4XneOLYw==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-openharmony-arm64": { + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0-rc.15.tgz", + "integrity": "sha512-UCL68NJ0Ud5zRipXZE9dF5PmirzJE4E4BCIOOssEnM7wLDsxjc6Qb0sGDxTNRTP53I6MZpygyCpY8Aa8sPfKPg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-wasm32-wasi": { + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0-rc.15.tgz", + "integrity": "sha512-ApLruZq/ig+nhaE7OJm4lDjayUnOHVUa77zGeqnqZ9pn0ovdVbbNPerVibLXDmWeUZXjIYIT8V3xkT58Rm9u5Q==", + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "1.9.2", + "@emnapi/runtime": "1.9.2", + "@napi-rs/wasm-runtime": "^1.1.3" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@rolldown/binding-win32-arm64-msvc": { + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-rc.15.tgz", + "integrity": "sha512-KmoUoU7HnN+Si5YWJigfTws1jz1bKBYDQKdbLspz0UaqjjFkddHsqorgiW1mxcAj88lYUE6NC/zJNwT+SloqtA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-win32-x64-msvc": { + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0-rc.15.tgz", + "integrity": "sha512-3P2A8L+x75qavWLe/Dll3EYBJLQmtkJN8rfh+U/eR3MqMgL/h98PhYI+JFfXuDPgPeCB7iZAKiqii5vqOvnA0g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.15.tgz", + "integrity": "sha512-UromN0peaE53IaBRe9W7CjrZgXl90fqGpK+mIZbA3qSTeYqg3pqpROBdIPvOG3F5ereDHNwoHBI2e50n1BDr1g==", + "dev": true, + "license": "MIT" + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.60.1.tgz", + "integrity": "sha512-d6FinEBLdIiK+1uACUttJKfgZREXrF0Qc2SmLII7W2AD8FfiZ9Wjd+rD/iRuf5s5dWrr1GgwXCvPqOuDquOowA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.60.1.tgz", + "integrity": "sha512-YjG/EwIDvvYI1YvYbHvDz/BYHtkY4ygUIXHnTdLhG+hKIQFBiosfWiACWortsKPKU/+dUwQQCKQM3qrDe8c9BA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.60.1.tgz", + "integrity": "sha512-mjCpF7GmkRtSJwon+Rq1N8+pI+8l7w5g9Z3vWj4T7abguC4Czwi3Yu/pFaLvA3TTeMVjnu3ctigusqWUfjZzvw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.60.1.tgz", + "integrity": "sha512-haZ7hJ1JT4e9hqkoT9R/19XW2QKqjfJVv+i5AGg57S+nLk9lQnJ1F/eZloRO3o9Scy9CM3wQ9l+dkXtcBgN5Ew==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.60.1.tgz", + "integrity": "sha512-czw90wpQq3ZsAVBlinZjAYTKduOjTywlG7fEeWKUA7oCmpA8xdTkxZZlwNJKWqILlq0wehoZcJYfBvOyhPTQ6w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.60.1.tgz", + "integrity": "sha512-KVB2rqsxTHuBtfOeySEyzEOB7ltlB/ux38iu2rBQzkjbwRVlkhAGIEDiiYnO2kFOkJp+Z7pUXKyrRRFuFUKt+g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.60.1.tgz", + "integrity": "sha512-L+34Qqil+v5uC0zEubW7uByo78WOCIrBvci69E7sFASRl0X7b/MB6Cqd1lky/CtcSVTydWa2WZwFuWexjS5o6g==", + "cpu": [ + "arm" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.60.1.tgz", + "integrity": "sha512-n83O8rt4v34hgFzlkb1ycniJh7IR5RCIqt6mz1VRJD6pmhRi0CXdmfnLu9dIUS6buzh60IvACM842Ffb3xd6Gg==", + "cpu": [ + "arm" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.60.1.tgz", + "integrity": "sha512-Nql7sTeAzhTAja3QXeAI48+/+GjBJ+QmAH13snn0AJSNL50JsDqotyudHyMbO2RbJkskbMbFJfIJKWA6R1LCJQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.60.1.tgz", + "integrity": "sha512-+pUymDhd0ys9GcKZPPWlFiZ67sTWV5UU6zOJat02M1+PiuSGDziyRuI/pPue3hoUwm2uGfxdL+trT6Z9rxnlMA==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.60.1.tgz", + "integrity": "sha512-VSvgvQeIcsEvY4bKDHEDWcpW4Yw7BtlKG1GUT4FzBUlEKQK0rWHYBqQt6Fm2taXS+1bXvJT6kICu5ZwqKCnvlQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.60.1.tgz", + "integrity": "sha512-4LqhUomJqwe641gsPp6xLfhqWMbQV04KtPp7/dIp0nzPxAkNY1AbwL5W0MQpcalLYk07vaW9Kp1PBhdpZYYcEw==", + "cpu": [ + "loong64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.60.1.tgz", + "integrity": "sha512-tLQQ9aPvkBxOc/EUT6j3pyeMD6Hb8QF2BTBnCQWP/uu1lhc9AIrIjKnLYMEroIz/JvtGYgI9dF3AxHZNaEH0rw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.60.1.tgz", + "integrity": "sha512-RMxFhJwc9fSXP6PqmAz4cbv3kAyvD1etJFjTx4ONqFP9DkTkXsAMU4v3Vyc5BgzC+anz7nS/9tp4obsKfqkDHg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.60.1.tgz", + "integrity": "sha512-QKgFl+Yc1eEk6MmOBfRHYF6lTxiiiV3/z/BRrbSiW2I7AFTXoBFvdMEyglohPj//2mZS4hDOqeB0H1ACh3sBbg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.60.1.tgz", + "integrity": "sha512-RAjXjP/8c6ZtzatZcA1RaQr6O1TRhzC+adn8YZDnChliZHviqIjmvFwHcxi4JKPSDAt6Uhf/7vqcBzQJy0PDJg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.60.1.tgz", + "integrity": "sha512-wcuocpaOlaL1COBYiA89O6yfjlp3RwKDeTIA0hM7OpmhR1Bjo9j31G1uQVpDlTvwxGn2nQs65fBFL5UFd76FcQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.60.1.tgz", + "integrity": "sha512-77PpsFQUCOiZR9+LQEFg9GClyfkNXj1MP6wRnzYs0EeWbPcHs02AXu4xuUbM1zhwn3wqaizle3AEYg5aeoohhg==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.60.1.tgz", + "integrity": "sha512-5cIATbk5vynAjqqmyBjlciMJl1+R/CwX9oLk/EyiFXDWd95KpHdrOJT//rnUl4cUcskrd0jCCw3wpZnhIHdD9w==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.60.1.tgz", + "integrity": "sha512-cl0w09WsCi17mcmWqqglez9Gk8isgeWvoUZ3WiJFYSR3zjBQc2J5/ihSjpl+VLjPqjQ/1hJRcqBfLjssREQILw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.60.1.tgz", + "integrity": "sha512-4Cv23ZrONRbNtbZa37mLSueXUCtN7MXccChtKpUnQNgF010rjrjfHx3QxkS2PI7LqGT5xXyYs1a7LbzAwT0iCA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.60.1.tgz", + "integrity": "sha512-i1okWYkA4FJICtr7KpYzFpRTHgy5jdDbZiWfvny21iIKky5YExiDXP+zbXzm3dUcFpkEeYNHgQ5fuG236JPq0g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.60.1.tgz", + "integrity": "sha512-u09m3CuwLzShA0EYKMNiFgcjjzwqtUMLmuCJLeZWjjOYA3IT2Di09KaxGBTP9xVztWyIWjVdsB2E9goMjZvTQg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.60.1.tgz", + "integrity": "sha512-k+600V9Zl1CM7eZxJgMyTUzmrmhB/0XZnF4pRypKAlAgxmedUA+1v9R+XOFv56W4SlHEzfeMtzujLJD22Uz5zg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.60.1.tgz", + "integrity": "sha512-lWMnixq/QzxyhTV6NjQJ4SFo1J6PvOX8vUx5Wb4bBPsEb+8xZ89Bz6kOXpfXj9ak9AHTQVQzlgzBEc1SyM27xQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@sindresorhus/is": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz", + "integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/is?sponsor=1" + } + }, + "node_modules/@tybys/wasm-util": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz", + "integrity": "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@types/chai": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz", + "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/deep-eql": "*", + "assertion-error": "^2.0.1" + } + }, + "node_modules/@types/conventional-commits-parser": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@types/conventional-commits-parser/-/conventional-commits-parser-5.0.2.tgz", + "integrity": "sha512-BgT2szDXnVypgpNxOK8aL5SGjUdaQbC++WZNjF1Qge3Og2+zhHj+RWhmehLhYyvQwqAmvezruVfOf8+3m74W+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/deep-eql": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", + "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "22.19.17", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.17.tgz", + "integrity": "sha512-wGdMcf+vPYM6jikpS/qhg6WiqSV/OhG+jeeHT/KlVqxYfD40iYJf9/AE1uQxVWFvU7MipKRkRv8NSHiCGgPr8Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/@types/node-fetch": { + "version": "2.6.13", + "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.13.tgz", + "integrity": "sha512-QGpRVpzSaUs30JBSGPjOg4Uveu384erbHBoT1zeONvyCfwQxIkUshLAOqN/k9EjGviPRmWTTe6aH2qySWKTVSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "form-data": "^4.0.4" + } + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.58.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.58.2.tgz", + "integrity": "sha512-aC2qc5thQahutKjP+cl8cgN9DWe3ZUqVko30CMSZHnFEHyhOYoZSzkGtAI2mcwZ38xeImDucI4dnqsHiOYuuCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.12.2", + "@typescript-eslint/scope-manager": "8.58.2", + "@typescript-eslint/type-utils": "8.58.2", + "@typescript-eslint/utils": "8.58.2", + "@typescript-eslint/visitor-keys": "8.58.2", + "ignore": "^7.0.5", + "natural-compare": "^1.4.0", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.58.2", + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "8.58.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.58.2.tgz", + "integrity": "sha512-/Zb/xaIDfxeJnvishjGdcR4jmr7S+bda8PKNhRGdljDM+elXhlvN0FyPSsMnLmJUrVG9aPO6dof80wjMawsASg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/scope-manager": "8.58.2", + "@typescript-eslint/types": "8.58.2", + "@typescript-eslint/typescript-estree": "8.58.2", + "@typescript-eslint/visitor-keys": "8.58.2", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/project-service": { + "version": "8.58.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.58.2.tgz", + "integrity": "sha512-Cq6UfpZZk15+r87BkIh5rDpi38W4b+Sjnb8wQCPPDDweS/LRCFjCyViEbzHk5Ck3f2QDfgmlxqSa7S7clDtlfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/tsconfig-utils": "^8.58.2", + "@typescript-eslint/types": "^8.58.2", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.58.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.58.2.tgz", + "integrity": "sha512-SgmyvDPexWETQek+qzZnrG6844IaO02UVyOLhI4wpo82dpZJY9+6YZCKAMFzXb7qhx37mFK1QcPQ18tud+vo6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.58.2", + "@typescript-eslint/visitor-keys": "8.58.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.58.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.58.2.tgz", + "integrity": "sha512-3SR+RukipDvkkKp/d0jP0dyzuls3DbGmwDpVEc5wqk5f38KFThakqAAO0XMirWAE+kT00oTauTbzMFGPoAzB0A==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "8.58.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.58.2.tgz", + "integrity": "sha512-Z7EloNR/B389FvabdGeTo2XMs4W9TjtPiO9DAsmT0yom0bwlPyRjkJ1uCdW1DvrrrYP50AJZ9Xc3sByZA9+dcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.58.2", + "@typescript-eslint/typescript-estree": "8.58.2", + "@typescript-eslint/utils": "8.58.2", + "debug": "^4.4.3", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "8.58.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.58.2.tgz", + "integrity": "sha512-9TukXyATBQf/Jq9AMQXfvurk+G5R2MwfqQGDR2GzGz28HvY/lXNKGhkY+6IOubwcquikWk5cjlgPvD2uAA7htQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.58.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.58.2.tgz", + "integrity": "sha512-ELGuoofuhhoCvNbQjFFiobFcGgcDCEm0ThWdmO4Z0UzLqPXS3KFvnEZ+SHewwOYHjM09tkzOWXNTv9u6Gqtyuw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/project-service": "8.58.2", + "@typescript-eslint/tsconfig-utils": "8.58.2", + "@typescript-eslint/types": "8.58.2", + "@typescript-eslint/visitor-keys": "8.58.2", + "debug": "^4.4.3", + "minimatch": "^10.2.2", + "semver": "^7.7.3", + "tinyglobby": "^0.2.15", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz", + "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.5" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "8.58.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.58.2.tgz", + "integrity": "sha512-QZfjHNEzPY8+l0+fIXMvuQ2sJlplB4zgDZvA+NmvZsZv3EQwOcc1DuIU1VJUTWZ/RKouBMhDyNaBMx4sWvrzRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.9.1", + "@typescript-eslint/scope-manager": "8.58.2", + "@typescript-eslint/types": "8.58.2", + "@typescript-eslint/typescript-estree": "8.58.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.58.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.58.2.tgz", + "integrity": "sha512-f1WO2Lx8a9t8DARmcWAUPJbu0G20bJlj8L4z72K00TMeJAoyLr/tHhI/pzYBLrR4dXWkcxO1cWYZEOX8DKHTqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.58.2", + "eslint-visitor-keys": "^5.0.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", + "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@vitest/coverage-v8": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-3.2.4.tgz", + "integrity": "sha512-EyF9SXU6kS5Ku/U82E259WSnvg6c8KTjppUncuNdm5QHpe17mwREHnjDzozC8x9MZ0xfBUFSaLkRv4TMA75ALQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@ampproject/remapping": "^2.3.0", + "@bcoe/v8-coverage": "^1.0.2", + "ast-v8-to-istanbul": "^0.3.3", + "debug": "^4.4.1", + "istanbul-lib-coverage": "^3.2.2", + "istanbul-lib-report": "^3.0.1", + "istanbul-lib-source-maps": "^5.0.6", + "istanbul-reports": "^3.1.7", + "magic-string": "^0.30.17", + "magicast": "^0.3.5", + "std-env": "^3.9.0", + "test-exclude": "^7.0.1", + "tinyrainbow": "^2.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@vitest/browser": "3.2.4", + "vitest": "3.2.4" + }, + "peerDependenciesMeta": { + "@vitest/browser": { + "optional": true + } + } + }, + "node_modules/@vitest/expect": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-3.2.4.tgz", + "integrity": "sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/chai": "^5.2.2", + "@vitest/spy": "3.2.4", + "@vitest/utils": "3.2.4", + "chai": "^5.2.0", + "tinyrainbow": "^2.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/mocker": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-3.2.4.tgz", + "integrity": "sha512-46ryTE9RZO/rfDd7pEqFl7etuyzekzEhUbTW3BvmeO/BcCMEgq59BKhek3dXDWgAj4oMK6OZi+vRr1wPW6qjEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/spy": "3.2.4", + "estree-walker": "^3.0.3", + "magic-string": "^0.30.17" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "msw": "^2.4.9", + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0" + }, + "peerDependenciesMeta": { + "msw": { + "optional": true + }, + "vite": { + "optional": true + } + } + }, + "node_modules/@vitest/pretty-format": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-3.2.4.tgz", + "integrity": "sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyrainbow": "^2.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/runner": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-3.2.4.tgz", + "integrity": "sha512-oukfKT9Mk41LreEW09vt45f8wx7DordoWUZMYdY/cyAk7w5TWkTRCNZYF7sX7n2wB7jyGAl74OxgwhPgKaqDMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/utils": "3.2.4", + "pathe": "^2.0.3", + "strip-literal": "^3.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/snapshot": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-3.2.4.tgz", + "integrity": "sha512-dEYtS7qQP2CjU27QBC5oUOxLE/v5eLkGqPE0ZKEIDGMs4vKWe7IjgLOeauHsR0D5YuuycGRO5oSRXnwnmA78fQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "3.2.4", + "magic-string": "^0.30.17", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/spy": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-3.2.4.tgz", + "integrity": "sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyspy": "^4.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/utils": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-3.2.4.tgz", + "integrity": "sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "3.2.4", + "loupe": "^3.1.4", + "tinyrainbow": "^2.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "dev": true, + "license": "MIT", + "dependencies": { + "event-target-shim": "^5.0.0" + }, + "engines": { + "node": ">=6.5" + } + }, + "node_modules/acorn": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", + "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/agentkeepalive": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.6.0.tgz", + "integrity": "sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "humanize-ms": "^1.2.1" + }, + "engines": { + "node": ">= 8.0.0" + } + }, + "node_modules/ajv": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", + "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-escapes": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.3.0.tgz", + "integrity": "sha512-BvU8nYgGQBxcmMuEeUEmNTvrMVjJNSH7RgW24vXexN4Ven6qCvy4TntnvlnwnMLTVlcRQQdbRY8NKnaIoeWDNg==", + "dev": true, + "license": "MIT", + "dependencies": { + "environment": "^1.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/ansis": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/ansis/-/ansis-4.2.0.tgz", + "integrity": "sha512-HqZ5rWlFjGiV0tDm3UxxgNRqsOTniqoKZu0pIAfh7TZQMGuZK+hH0drySty0si0QXj1ieop4+SkSfPZBPPkHig==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + } + }, + "node_modules/any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", + "dev": true, + "license": "MIT" + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/array-ify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-ify/-/array-ify-1.0.0.tgz", + "integrity": "sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng==", + "dev": true, + "license": "MIT" + }, + "node_modules/assertion-error": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", + "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/ast-kit": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/ast-kit/-/ast-kit-2.2.0.tgz", + "integrity": "sha512-m1Q/RaVOnTp9JxPX+F+Zn7IcLYMzM8kZofDImfsKZd8MbR+ikdOzTeztStWqfrqIxZnYWryyI9ePm3NGjnZgGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.28.5", + "pathe": "^2.0.3" + }, + "engines": { + "node": ">=20.19.0" + }, + "funding": { + "url": "https://github.com/sponsors/sxzz" + } + }, + "node_modules/ast-v8-to-istanbul": { + "version": "0.3.12", + "resolved": "https://registry.npmjs.org/ast-v8-to-istanbul/-/ast-v8-to-istanbul-0.3.12.tgz", + "integrity": "sha512-BRRC8VRZY2R4Z4lFIL35MwNXmwVqBityvOIwETtsCSwvjl0IdgFsy9NhdaA6j74nUdtJJlIypeRhpDam19Wq3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.31", + "estree-walker": "^3.0.3", + "js-tokens": "^10.0.0" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/birpc": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/birpc/-/birpc-2.9.0.tgz", + "integrity": "sha512-KrayHS5pBi69Xi9JmvoqrIgYGDkD6mcSe/i6YKi3w5kekCLzrX4+nawcXqrj2tIp50Kw/mT/s3p+GVK0A0sKxw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.14.tgz", + "integrity": "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/cac": { + "version": "6.7.14", + "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", + "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/chai": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/chai/-/chai-5.3.3.tgz", + "integrity": "sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "assertion-error": "^2.0.1", + "check-error": "^2.1.1", + "deep-eql": "^5.0.1", + "loupe": "^3.1.0", + "pathval": "^2.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/check-error": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.3.tgz", + "integrity": "sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 16" + } + }, + "node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/cjs-module-lexer": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.4.3.tgz", + "integrity": "sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/cli-cursor": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz", + "integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==", + "dev": true, + "license": "MIT", + "dependencies": { + "restore-cursor": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-highlight": { + "version": "2.1.11", + "resolved": "https://registry.npmjs.org/cli-highlight/-/cli-highlight-2.1.11.tgz", + "integrity": "sha512-9KDcoEVwyUXrjcJNvHD0NFc/hiwe/WPVYIleQh2O1N2Zro5gWJZ/K+3DGn8w8P/F6FxOgzyC5bxDyHIgCSPhGg==", + "dev": true, + "license": "ISC", + "dependencies": { + "chalk": "^4.0.0", + "highlight.js": "^10.7.1", + "mz": "^2.4.0", + "parse5": "^5.1.1", + "parse5-htmlparser2-tree-adapter": "^6.0.0", + "yargs": "^16.0.0" + }, + "bin": { + "highlight": "bin/highlight" + }, + "engines": { + "node": ">=8.0.0", + "npm": ">=5.0.0" + } + }, + "node_modules/cli-highlight/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cli-highlight/node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/cli-highlight/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cli-highlight/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/cli-highlight/node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/cli-highlight/node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/cli-table3": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.5.tgz", + "integrity": "sha512-+W/5efTR7y5HRD7gACw9yQjqMVvEMLBHmboM/kPWam+H+Hmyrgjh6YncVKK122YZkXrLudzTuAukUw9FnMf7IQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "string-width": "^4.2.0" + }, + "engines": { + "node": "10.* || >= 12.*" + }, + "optionalDependencies": { + "@colors/colors": "1.5.0" + } + }, + "node_modules/cli-truncate": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-5.2.0.tgz", + "integrity": "sha512-xRwvIOMGrfOAnM1JYtqQImuaNtDEv9v6oIYAs4LIHwTiKee8uwvIi363igssOC0O5U04i4AlENs79LQLu9tEMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "slice-ansi": "^8.0.0", + "string-width": "^8.2.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-truncate/node_modules/string-width": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-8.2.0.tgz", + "integrity": "sha512-6hJPQ8N0V0P3SNmP6h2J99RLuzrWz2gvT7VnK5tKvrNqJoyS9W4/Fb8mo31UiPvy00z7DQXkP2hnKBVav76thw==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-east-asian-width": "^1.5.0", + "strip-ansi": "^7.1.2" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/cliui/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "dev": true, + "license": "MIT" + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/commander": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + } + }, + "node_modules/compare-func": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/compare-func/-/compare-func-2.0.0.tgz", + "integrity": "sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-ify": "^1.0.0", + "dot-prop": "^5.1.0" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/conventional-changelog-angular": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-7.0.0.tgz", + "integrity": "sha512-ROjNchA9LgfNMTTFSIWPzebCwOGFdgkEq45EnvvrmSLvCtAw0HSmrCs7/ty+wAeYUZyNay0YMUNYFTRL72PkBQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "compare-func": "^2.0.0" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/conventional-changelog-conventionalcommits": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-7.0.2.tgz", + "integrity": "sha512-NKXYmMR/Hr1DevQegFB4MwfM5Vv0m4UIxKZTTYuD98lpTknaZlSRrDOG4X7wIXpGkfsYxZTghUN+Qq+T0YQI7w==", + "dev": true, + "license": "ISC", + "dependencies": { + "compare-func": "^2.0.0" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/conventional-commits-parser": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-5.0.0.tgz", + "integrity": "sha512-ZPMl0ZJbw74iS9LuX9YIAiW8pfM5p3yh2o/NbXHbkFuZzY5jvdi5jFycEOkmBW5H5I7nA+D6f3UcsCLP2vvSEA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-text-path": "^2.0.0", + "JSONStream": "^1.3.5", + "meow": "^12.0.1", + "split2": "^4.0.0" + }, + "bin": { + "conventional-commits-parser": "cli.mjs" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/cosmiconfig": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.1.tgz", + "integrity": "sha512-hr4ihw+DBqcvrsEDioRO31Z17x71pUYoNe/4h6Z0wB72p7MU7/9gH8Q3s12NFhHPfYBBOV3qyfUxmr/Yn3shnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "env-paths": "^2.2.1", + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/cosmiconfig-typescript-loader": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/cosmiconfig-typescript-loader/-/cosmiconfig-typescript-loader-6.3.0.tgz", + "integrity": "sha512-Akr82WH1Wfqatyiqpj8HDkO2o2KmJRu1FhKfSNJP3K4IdXwHfEyL7MOb62i1AGQVLtIQM+iCE9CGOtrfhR+mmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "jiti": "2.6.1" + }, + "engines": { + "node": ">=v18" + }, + "peerDependencies": { + "@types/node": "*", + "cosmiconfig": ">=9", + "typescript": ">=5" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/dargs": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/dargs/-/dargs-8.1.0.tgz", + "integrity": "sha512-wAV9QHOsNbwnWdNW2FYvE1P56wtgSbM+3SZcdGiWQILwVjACCXDCI3Ai8QlCjMDB8YK5zySiXZYBiwGmNY3lnw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-eql": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.2.tgz", + "integrity": "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/defu": { + "version": "6.1.7", + "resolved": "https://registry.npmjs.org/defu/-/defu-6.1.7.tgz", + "integrity": "sha512-7z22QmUWiQ/2d0KkdYmANbRUVABpZ9SNYyH5vx6PZ+nE5bcC0l7uFvEfHlyld/HcGBFTL536ClDt3DEcSlEJAQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/diff": { + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/diff/-/diff-8.0.4.tgz", + "integrity": "sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/dot-prop": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", + "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-obj": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/dts-resolver": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/dts-resolver/-/dts-resolver-2.1.3.tgz", + "integrity": "sha512-bihc7jPC90VrosXNzK0LTE2cuLP6jr0Ro8jk+kMugHReJVLIpHz/xadeq3MhuwyO4TD4OA3L1Q8pBBFRc08Tsw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20.19.0" + }, + "funding": { + "url": "https://github.com/sponsors/sxzz" + }, + "peerDependencies": { + "oxc-resolver": ">=11.0.0" + }, + "peerDependenciesMeta": { + "oxc-resolver": { + "optional": true + } + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true, + "license": "MIT" + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/emojilib": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/emojilib/-/emojilib-2.4.0.tgz", + "integrity": "sha512-5U0rVMU5Y2n2+ykNLQqMoqklN9ICBT/KsvC1Gz6vqHbz2AXXGkG+Pm5rMWk/8Vjrr/mY9985Hi8DYzn1F09Nyw==", + "dev": true, + "license": "MIT" + }, + "node_modules/empathic": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/empathic/-/empathic-2.0.0.tgz", + "integrity": "sha512-i6UzDscO/XfAcNYD75CfICkmfLedpyPDdozrLMmQc5ORaQcdMoc21OnlEylMIqI7U8eniKrPMxxtj8k0vhmJhA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + } + }, + "node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/environment": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/environment/-/environment-1.1.0.tgz", + "integrity": "sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/error-ex": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", + "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-module-lexer": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", + "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==", + "dev": true, + "license": "MIT" + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/esbuild": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.7.tgz", + "integrity": "sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.27.7", + "@esbuild/android-arm": "0.27.7", + "@esbuild/android-arm64": "0.27.7", + "@esbuild/android-x64": "0.27.7", + "@esbuild/darwin-arm64": "0.27.7", + "@esbuild/darwin-x64": "0.27.7", + "@esbuild/freebsd-arm64": "0.27.7", + "@esbuild/freebsd-x64": "0.27.7", + "@esbuild/linux-arm": "0.27.7", + "@esbuild/linux-arm64": "0.27.7", + "@esbuild/linux-ia32": "0.27.7", + "@esbuild/linux-loong64": "0.27.7", + "@esbuild/linux-mips64el": "0.27.7", + "@esbuild/linux-ppc64": "0.27.7", + "@esbuild/linux-riscv64": "0.27.7", + "@esbuild/linux-s390x": "0.27.7", + "@esbuild/linux-x64": "0.27.7", + "@esbuild/netbsd-arm64": "0.27.7", + "@esbuild/netbsd-x64": "0.27.7", + "@esbuild/openbsd-arm64": "0.27.7", + "@esbuild/openbsd-x64": "0.27.7", + "@esbuild/openharmony-arm64": "0.27.7", + "@esbuild/sunos-x64": "0.27.7", + "@esbuild/win32-arm64": "0.27.7", + "@esbuild/win32-ia32": "0.27.7", + "@esbuild/win32-x64": "0.27.7" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "9.39.4", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.4.tgz", + "integrity": "sha512-XoMjdBOwe/esVgEvLmNsD3IRHkm7fbKIUGvrleloJXUZgDHig2IPWNniv+GwjyJXzuNqVjlr5+4yVUZjycJwfQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.8.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.21.2", + "@eslint/config-helpers": "^0.4.2", + "@eslint/core": "^0.17.0", + "@eslint/eslintrc": "^3.3.5", + "@eslint/js": "9.39.4", + "@eslint/plugin-kit": "^0.4.1", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "ajv": "^6.14.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.4.0", + "eslint-visitor-keys": "^4.2.1", + "espree": "^10.4.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.5", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-config-prettier": { + "version": "10.1.8", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-10.1.8.tgz", + "integrity": "sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==", + "dev": true, + "license": "MIT", + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "funding": { + "url": "https://opencollective.com/eslint-config-prettier" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, + "node_modules/eslint-scope": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", + "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/ajv": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", + "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/eslint/node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/eslint/node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint/node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/espree": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", + "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.15.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", + "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/eventemitter3": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.4.tgz", + "integrity": "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==", + "dev": true, + "license": "MIT" + }, + "node_modules/expect-type": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.3.0.tgz", + "integrity": "sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz", + "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/fflate": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.2.tgz", + "integrity": "sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==", + "dev": true, + "license": "MIT" + }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/find-up": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-7.0.0.tgz", + "integrity": "sha512-YyZM99iHrqLKjmt4LJDj58KI+fYyufRLBSYcqycxf//KpBk9FoewoGX0450m9nB44qrZnovzC2oeP5hUibxc/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^7.2.0", + "path-exists": "^5.0.0", + "unicorn-magic": "^0.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz", + "integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==", + "dev": true, + "license": "ISC" + }, + "node_modules/foreground-child": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", + "dev": true, + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.6", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/form-data": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz", + "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==", + "dev": true, + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/form-data-encoder": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-1.7.2.tgz", + "integrity": "sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A==", + "dev": true, + "license": "MIT" + }, + "node_modules/formdata-node": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/formdata-node/-/formdata-node-4.4.1.tgz", + "integrity": "sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "node-domexception": "1.0.0", + "web-streams-polyfill": "4.0.0-beta.3" + }, + "engines": { + "node": ">= 12.20" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-east-asian-width": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.5.0.tgz", + "integrity": "sha512-CQ+bEO+Tva/qlmw24dCejulK5pMzVnUOFOijVogd3KQs07HnRIgp8TGipvCCRT06xeYEbpbgwaCxglFyiuIcmA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/get-tsconfig": { + "version": "4.13.8", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.8.tgz", + "integrity": "sha512-J87BxkLXykmisLQ+KA4x2+O6rVf+PJrtFUO8lGyiRg4lyxJLJ8/v0sRAKdVZQOy6tR6lMRAF1NqzCf9BQijm0w==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, + "node_modules/git-raw-commits": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/git-raw-commits/-/git-raw-commits-4.0.0.tgz", + "integrity": "sha512-ICsMM1Wk8xSGMowkOmPrzo2Fgmfo4bMHLNX6ytHjajRJUqvHOw/TFapQ+QG75c3X/tTDDhOSRPGC52dDbNM8FQ==", + "deprecated": "This package is no longer maintained. For the JavaScript API, please use @conventional-changelog/git-client instead.", + "dev": true, + "license": "MIT", + "dependencies": { + "dargs": "^8.0.0", + "meow": "^12.0.1", + "split2": "^4.0.0" + }, + "bin": { + "git-raw-commits": "cli.mjs" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/glob": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", + "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "dev": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/glob/node_modules/brace-expansion": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.0.tgz", + "integrity": "sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.2" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/global-directory": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/global-directory/-/global-directory-4.0.1.tgz", + "integrity": "sha512-wHTUcDUoZ1H5/0iVqEudYW4/kAlN5cZ3j/bXn0Dpbizl9iaUVeWSHqiOjsgk6OW2bkLclbBjzewBz6weQ1zA2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ini": "4.1.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/highlight.js": { + "version": "10.7.3", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz", + "integrity": "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": "*" + } + }, + "node_modules/hookable": { + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/hookable/-/hookable-5.5.3.tgz", + "integrity": "sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true, + "license": "MIT" + }, + "node_modules/humanize-ms": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", + "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.0.0" + } + }, + "node_modules/husky": { + "version": "9.1.7", + "resolved": "https://registry.npmjs.org/husky/-/husky-9.1.7.tgz", + "integrity": "sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA==", + "dev": true, + "license": "MIT", + "bin": { + "husky": "bin.js" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/typicode" + } + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-fresh/node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/import-meta-resolve": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/import-meta-resolve/-/import-meta-resolve-4.2.0.tgz", + "integrity": "sha512-Iqv2fzaTQN28s/FwZAoFq0ZSs/7hMAHJVX+w8PZl3cY19Pxk6jFFalxQoIfW2826i/fDLXv8IiEZRIT0lDuWcg==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/ini": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.1.tgz", + "integrity": "sha512-QQnnxNyfvmHFIsj7gkPcYymR8Jdw/o7mp5ZFihxn6h8Ci6fh3Dx4E1gPjpQEpIuPo9XVNY/ZUwh4BPMjGyL01g==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-5.1.0.tgz", + "integrity": "sha512-5XHYaSyiqADb4RnZ1Bdad6cPp8Toise4TzEjcOYDHZkTCbKgiUl7WTUCpNWHuxmDt91wnsZBc9xinNzopv3JMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-east-asian-width": "^1.3.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-text-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-text-path/-/is-text-path-2.0.0.tgz", + "integrity": "sha512-+oDTluR6WEjdXEJMnC2z6A4FRwFoYuvShVVEGsS7ewc0UTi2QtAKMDJuL4BDEVt+5T7MjFo12RP8ghOM75oKJw==", + "dev": true, + "license": "MIT", + "dependencies": { + "text-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-source-maps": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-5.0.6.tgz", + "integrity": "sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.23", + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-reports": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz", + "integrity": "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/jiti": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz", + "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==", + "dev": true, + "license": "MIT", + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, + "node_modules/js-tokens": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-10.0.0.tgz", + "integrity": "sha512-lM/UBzQmfJRo9ABXbPWemivdCW8V2G8FHaHdypQaIy523snUjog0W71ayWXTjiR+ixeMyVHN2XcpnTd/liPg/Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-to-ts": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/json-schema-to-ts/-/json-schema-to-ts-3.1.1.tgz", + "integrity": "sha512-+DWg8jCJG2TEnpy7kOm/7/AxaYoaRbjVB4LFZLySZlWn8exGs3A4OLJR966cVvU26N7X9TWxl+Jsw7dzAqKT6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.18.3", + "ts-algebra": "^2.0.0" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/jsonparse": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", + "integrity": "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==", + "dev": true, + "engines": [ + "node >= 0.2.0" + ], + "license": "MIT" + }, + "node_modules/JSONStream": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz", + "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==", + "dev": true, + "license": "(MIT OR Apache-2.0)", + "dependencies": { + "jsonparse": "^1.2.0", + "through": ">=2.2.7 <3" + }, + "bin": { + "JSONStream": "bin.js" + }, + "engines": { + "node": "*" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true, + "license": "MIT" + }, + "node_modules/lint-staged": { + "version": "16.4.0", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-16.4.0.tgz", + "integrity": "sha512-lBWt8hujh/Cjysw5GYVmZpFHXDCgZzhrOm8vbcUdobADZNOK/bRshr2kM3DfgrrtR1DQhfupW9gnIXOfiFi+bw==", + "dev": true, + "license": "MIT", + "dependencies": { + "commander": "^14.0.3", + "listr2": "^9.0.5", + "picomatch": "^4.0.3", + "string-argv": "^0.3.2", + "tinyexec": "^1.0.4", + "yaml": "^2.8.2" + }, + "bin": { + "lint-staged": "bin/lint-staged.js" + }, + "engines": { + "node": ">=20.17" + }, + "funding": { + "url": "https://opencollective.com/lint-staged" + } + }, + "node_modules/lint-staged/node_modules/commander": { + "version": "14.0.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.3.tgz", + "integrity": "sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + } + }, + "node_modules/listr2": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-9.0.5.tgz", + "integrity": "sha512-ME4Fb83LgEgwNw96RKNvKV4VTLuXfoKudAmm2lP8Kk87KaMK0/Xrx/aAkMWmT8mDb+3MlFDspfbCs7adjRxA2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "cli-truncate": "^5.0.0", + "colorette": "^2.0.20", + "eventemitter3": "^5.0.1", + "log-update": "^6.1.0", + "rfdc": "^1.4.1", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/locate-path": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-7.2.0.tgz", + "integrity": "sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^6.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.kebabcase": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.kebabcase/-/lodash.kebabcase-4.1.1.tgz", + "integrity": "sha512-N8XRTIMMqqDgSy4VLKPnJ/+hpGZN+PHQiJnSenYqPaVV/NCqEogTnAdZLQiGKhxX+JCs8waWq2t1XHWKOmlY8g==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.mergewith": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz", + "integrity": "sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.snakecase": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.snakecase/-/lodash.snakecase-4.1.1.tgz", + "integrity": "sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.startcase": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.startcase/-/lodash.startcase-4.4.0.tgz", + "integrity": "sha512-+WKqsK294HMSc2jEbNgpHpd0JfIBhp7rEV4aqXWqFr6AlXov+SlcgB1Fv01y2kGe3Gc8nMW7VA0SrGuSkRfIEg==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.uniq": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", + "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.upperfirst": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/lodash.upperfirst/-/lodash.upperfirst-4.3.1.tgz", + "integrity": "sha512-sReKOYJIJf74dhJONhU4e0/shzi1trVbSWDOhKYE5XV2O+H7Sb2Dihwuc7xWxVl+DgFPyTqIN3zMfT9cq5iWDg==", + "dev": true, + "license": "MIT" + }, + "node_modules/log-update": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/log-update/-/log-update-6.1.0.tgz", + "integrity": "sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-escapes": "^7.0.0", + "cli-cursor": "^5.0.0", + "slice-ansi": "^7.1.0", + "strip-ansi": "^7.1.0", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/log-update/node_modules/slice-ansi": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-7.1.2.tgz", + "integrity": "sha512-iOBWFgUX7caIZiuutICxVgX1SdxwAVFFKwt1EvMYYec/NWO5meOJ6K5uQxhrYBdQJne4KxiqZc+KptFOWFSI9w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.1", + "is-fullwidth-code-point": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/loupe": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.2.1.tgz", + "integrity": "sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/magicast": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/magicast/-/magicast-0.3.5.tgz", + "integrity": "sha512-L0WhttDl+2BOsybvEOLK7fW3UA0OQ0IQ2d6Zl2x/a6vVRs3bAY0ECOSHHeL5jD+SbOpOCUEi0y1DgHEn9Qn1AQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.25.4", + "@babel/types": "^7.25.4", + "source-map-js": "^1.2.0" + } + }, + "node_modules/make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/marked": { + "version": "9.1.6", + "resolved": "https://registry.npmjs.org/marked/-/marked-9.1.6.tgz", + "integrity": "sha512-jcByLnIFkd5gSXZmjNvS1TlmRhCXZjIzHYlaGkPlLIekG55JDR2Z4va9tZwCiP+/RDERiNhMOFu01xd6O5ct1Q==", + "dev": true, + "license": "MIT", + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 16" + } + }, + "node_modules/marked-terminal": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/marked-terminal/-/marked-terminal-7.3.0.tgz", + "integrity": "sha512-t4rBvPsHc57uE/2nJOLmMbZCQ4tgAccAED3ngXQqW6g+TxA488JzJ+FK3lQkzBQOI1mRV/r/Kq+1ZlJ4D0owQw==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-escapes": "^7.0.0", + "ansi-regex": "^6.1.0", + "chalk": "^5.4.1", + "cli-highlight": "^2.1.11", + "cli-table3": "^0.6.5", + "node-emoji": "^2.2.0", + "supports-hyperlinks": "^3.1.0" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "marked": ">=1 <16" + } + }, + "node_modules/marked-terminal/node_modules/chalk": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", + "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/meow": { + "version": "12.1.1", + "resolved": "https://registry.npmjs.org/meow/-/meow-12.1.1.tgz", + "integrity": "sha512-BhXM0Au22RwUneMPwSCnyhTOizdWoIEPU9sp0Aqa1PnDMR5Wv2FGXYDjuzJEIX+Eo2Rb8xuYe5jrnm5QowQFkw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16.10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-function": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz", + "integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minipass": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", + "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/mri": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz", + "integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/mz": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" + } + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/node-domexception": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", + "deprecated": "Use your platform's native DOMException instead", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "github", + "url": "https://paypal.me/jimmywarting" + } + ], + "license": "MIT", + "engines": { + "node": ">=10.5.0" + } + }, + "node_modules/node-emoji": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-2.2.0.tgz", + "integrity": "sha512-Z3lTE9pLaJF47NyMhd4ww1yFTAP8YhYI8SleJiHzM46Fgpm5cnNzSl9XfzFNqbaz+VlJrIj3fXQ4DeN1Rjm6cw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sindresorhus/is": "^4.6.0", + "char-regex": "^1.0.2", + "emojilib": "^2.4.0", + "skin-tone": "^2.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/onetime": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz", + "integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-function": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/openai": { + "version": "4.104.0", + "resolved": "https://registry.npmjs.org/openai/-/openai-4.104.0.tgz", + "integrity": "sha512-p99EFNsA/yX6UhVO93f5kJsDRLAg+CTA2RBqdHK4RtK8u5IJw32Hyb2dTGKbnnFmnuoBv5r7Z2CURI9sGZpSuA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/node": "^18.11.18", + "@types/node-fetch": "^2.6.4", + "abort-controller": "^3.0.0", + "agentkeepalive": "^4.2.1", + "form-data-encoder": "1.7.2", + "formdata-node": "^4.3.2", + "node-fetch": "^2.6.7" + }, + "bin": { + "openai": "bin/cli" + }, + "peerDependencies": { + "ws": "^8.18.0", + "zod": "^3.23.8" + }, + "peerDependenciesMeta": { + "ws": { + "optional": true + }, + "zod": { + "optional": true + } + } + }, + "node_modules/openai/node_modules/@types/node": { + "version": "18.19.130", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.130.tgz", + "integrity": "sha512-GRaXQx6jGfL8sKfaIDD6OupbIHBr9jv7Jnaml9tB7l4v068PAOXqfcujMMo5PhbIs6ggR1XODELqahT2R8v0fg==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/openai/node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "dev": true, + "license": "MIT" + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz", + "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^1.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-6.0.0.tgz", + "integrity": "sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "dev": true, + "license": "BlueOak-1.0.0" + }, + "node_modules/package-manager-detector": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/package-manager-detector/-/package-manager-detector-1.6.0.tgz", + "integrity": "sha512-61A5ThoTiDG/C8s8UMZwSorAGwMJ0ERVGj2OjoW5pAalsNOg15+iQiPzrLJ4jhZ1HJzmC2PIHT2oEiH3R5fzNA==", + "dev": true, + "license": "MIT" + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parse5": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.1.tgz", + "integrity": "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==", + "dev": true, + "license": "MIT" + }, + "node_modules/parse5-htmlparser2-tree-adapter": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz", + "integrity": "sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==", + "dev": true, + "license": "MIT", + "dependencies": { + "parse5": "^6.0.1" + } + }, + "node_modules/parse5-htmlparser2-tree-adapter/node_modules/parse5": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", + "dev": true, + "license": "MIT" + }, + "node_modules/path-exists": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-5.0.0.tgz", + "integrity": "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "dev": true, + "license": "MIT" + }, + "node_modules/pathval": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.1.tgz", + "integrity": "sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14.16" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/postcss": { + "version": "8.5.9", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.9.tgz", + "integrity": "sha512-7a70Nsot+EMX9fFU3064K/kdHWZqGVY+BADLyXc8Dfv+mTLLVl6JzJpPaCZ2kQL9gIJvKXSLMHhqdRRjwQeFtw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "3.8.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.2.tgz", + "integrity": "sha512-8c3mgTe0ASwWAJK+78dpviD+A8EqhndQPUBpNUIPt6+xWlIigCwfN01lWr9MAede4uqXGTEKeQWTvzb3vjia0Q==", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/publint": { + "version": "0.3.18", + "resolved": "https://registry.npmjs.org/publint/-/publint-0.3.18.tgz", + "integrity": "sha512-JRJFeBTrfx4qLwEuGFPk+haJOJN97KnPuK01yj+4k/Wj5BgoOK5uNsivporiqBjk2JDaslg7qJOhGRnpltGeog==", + "dev": true, + "license": "MIT", + "dependencies": { + "@publint/pack": "^0.1.4", + "package-manager-detector": "^1.6.0", + "picocolors": "^1.1.1", + "sade": "^1.8.1" + }, + "bin": { + "publint": "src/cli.js" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://bjornlu.com/sponsor" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/quansync": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/quansync/-/quansync-1.0.0.tgz", + "integrity": "sha512-5xZacEEufv3HSTPQuchrvV6soaiACMFnq1H8wkVioctoH3TRha9Sz66lOxRwPK/qZj7HPiSveih9yAyh98gvqA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/antfu" + }, + { + "type": "individual", + "url": "https://github.com/sponsors/sxzz" + } + ], + "license": "MIT" + }, + "node_modules/readdirp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, + "node_modules/restore-cursor": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz", + "integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==", + "dev": true, + "license": "MIT", + "dependencies": { + "onetime": "^7.0.0", + "signal-exit": "^4.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/rfdc": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", + "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", + "dev": true, + "license": "MIT" + }, + "node_modules/rolldown": { + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-rc.15.tgz", + "integrity": "sha512-Ff31guA5zT6WjnGp0SXw76X6hzGRk/OQq2hE+1lcDe+lJdHSgnSX6nK3erbONHyCbpSj9a9E+uX/OvytZoWp2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@oxc-project/types": "=0.124.0", + "@rolldown/pluginutils": "1.0.0-rc.15" + }, + "bin": { + "rolldown": "bin/cli.mjs" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "optionalDependencies": { + "@rolldown/binding-android-arm64": "1.0.0-rc.15", + "@rolldown/binding-darwin-arm64": "1.0.0-rc.15", + "@rolldown/binding-darwin-x64": "1.0.0-rc.15", + "@rolldown/binding-freebsd-x64": "1.0.0-rc.15", + "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-rc.15", + "@rolldown/binding-linux-arm64-gnu": "1.0.0-rc.15", + "@rolldown/binding-linux-arm64-musl": "1.0.0-rc.15", + "@rolldown/binding-linux-ppc64-gnu": "1.0.0-rc.15", + "@rolldown/binding-linux-s390x-gnu": "1.0.0-rc.15", + "@rolldown/binding-linux-x64-gnu": "1.0.0-rc.15", + "@rolldown/binding-linux-x64-musl": "1.0.0-rc.15", + "@rolldown/binding-openharmony-arm64": "1.0.0-rc.15", + "@rolldown/binding-wasm32-wasi": "1.0.0-rc.15", + "@rolldown/binding-win32-arm64-msvc": "1.0.0-rc.15", + "@rolldown/binding-win32-x64-msvc": "1.0.0-rc.15" + } + }, + "node_modules/rolldown-plugin-dts": { + "version": "0.13.14", + "resolved": "https://registry.npmjs.org/rolldown-plugin-dts/-/rolldown-plugin-dts-0.13.14.tgz", + "integrity": "sha512-wjNhHZz9dlN6PTIXyizB6u/mAg1wEFMW9yw7imEVe3CxHSRnNHVyycIX0yDEOVJfDNISLPbkCIPEpFpizy5+PQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/generator": "^7.28.0", + "@babel/parser": "^7.28.0", + "@babel/types": "^7.28.1", + "ast-kit": "^2.1.1", + "birpc": "^2.5.0", + "debug": "^4.4.1", + "dts-resolver": "^2.1.1", + "get-tsconfig": "^4.10.1" + }, + "engines": { + "node": ">=20.18.0" + }, + "funding": { + "url": "https://github.com/sponsors/sxzz" + }, + "peerDependencies": { + "@typescript/native-preview": ">=7.0.0-dev.20250601.1", + "rolldown": "^1.0.0-beta.9", + "typescript": "^5.0.0", + "vue-tsc": "^2.2.0 || ^3.0.0" + }, + "peerDependenciesMeta": { + "@typescript/native-preview": { + "optional": true + }, + "typescript": { + "optional": true + }, + "vue-tsc": { + "optional": true + } + } + }, + "node_modules/rollup": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.60.1.tgz", + "integrity": "sha512-VmtB2rFU/GroZ4oL8+ZqXgSA38O6GR8KSIvWmEFv63pQ0G6KaBH9s07PO8XTXP4vI+3UJUEypOfjkGfmSBBR0w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.60.1", + "@rollup/rollup-android-arm64": "4.60.1", + "@rollup/rollup-darwin-arm64": "4.60.1", + "@rollup/rollup-darwin-x64": "4.60.1", + "@rollup/rollup-freebsd-arm64": "4.60.1", + "@rollup/rollup-freebsd-x64": "4.60.1", + "@rollup/rollup-linux-arm-gnueabihf": "4.60.1", + "@rollup/rollup-linux-arm-musleabihf": "4.60.1", + "@rollup/rollup-linux-arm64-gnu": "4.60.1", + "@rollup/rollup-linux-arm64-musl": "4.60.1", + "@rollup/rollup-linux-loong64-gnu": "4.60.1", + "@rollup/rollup-linux-loong64-musl": "4.60.1", + "@rollup/rollup-linux-ppc64-gnu": "4.60.1", + "@rollup/rollup-linux-ppc64-musl": "4.60.1", + "@rollup/rollup-linux-riscv64-gnu": "4.60.1", + "@rollup/rollup-linux-riscv64-musl": "4.60.1", + "@rollup/rollup-linux-s390x-gnu": "4.60.1", + "@rollup/rollup-linux-x64-gnu": "4.60.1", + "@rollup/rollup-linux-x64-musl": "4.60.1", + "@rollup/rollup-openbsd-x64": "4.60.1", + "@rollup/rollup-openharmony-arm64": "4.60.1", + "@rollup/rollup-win32-arm64-msvc": "4.60.1", + "@rollup/rollup-win32-ia32-msvc": "4.60.1", + "@rollup/rollup-win32-x64-gnu": "4.60.1", + "@rollup/rollup-win32-x64-msvc": "4.60.1", + "fsevents": "~2.3.2" + } + }, + "node_modules/sade": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/sade/-/sade-1.8.1.tgz", + "integrity": "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==", + "dev": true, + "license": "MIT", + "dependencies": { + "mri": "^1.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/siginfo": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", + "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", + "dev": true, + "license": "ISC" + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/skin-tone": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/skin-tone/-/skin-tone-2.0.0.tgz", + "integrity": "sha512-kUMbT1oBJCpgrnKoSr0o6wPtvRWT9W9UKvGLwfJYO2WuahZRHOpEyL1ckyMGgMWh0UdpmaoFqKKD29WTomNEGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "unicode-emoji-modifier-base": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/slice-ansi": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-8.0.0.tgz", + "integrity": "sha512-stxByr12oeeOyY2BlviTNQlYV5xOj47GirPr4yA1hE9JCtxfQN0+tVbkxwCtYDQWhEKWFHsEK48ORg5jrouCAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.3", + "is-fullwidth-code-point": "^5.1.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/slice-ansi/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/split2": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", + "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">= 10.x" + } + }, + "node_modules/stackback": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", + "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", + "dev": true, + "license": "MIT" + }, + "node_modules/std-env": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.10.0.tgz", + "integrity": "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==", + "dev": true, + "license": "MIT" + }, + "node_modules/string-argv": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.2.tgz", + "integrity": "sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.6.19" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.2.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strip-literal": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-3.1.0.tgz", + "integrity": "sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg==", + "dev": true, + "license": "MIT", + "dependencies": { + "js-tokens": "^9.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/strip-literal/node_modules/js-tokens": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-9.0.1.tgz", + "integrity": "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-hyperlinks": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-3.2.0.tgz", + "integrity": "sha512-zFObLMyZeEwzAoKCyu1B91U79K2t7ApXuQfo8OuxwXLDgcKxuwM+YvcbIhm6QWqz7mHUH1TVytR1PwVVjEuMig==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0", + "supports-color": "^7.0.0" + }, + "engines": { + "node": ">=14.18" + }, + "funding": { + "url": "https://github.com/chalk/supports-hyperlinks?sponsor=1" + } + }, + "node_modules/test-exclude": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-7.0.2.tgz", + "integrity": "sha512-u9E6A+ZDYdp7a4WnarkXPZOx8Ilz46+kby6p1yZ8zsGTz9gYa6FIS7lj2oezzNKmtdyyJNNmmXDppga5GB7kSw==", + "dev": true, + "license": "ISC", + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^10.4.1", + "minimatch": "^10.2.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/test-exclude/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/test-exclude/node_modules/brace-expansion": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz", + "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/test-exclude/node_modules/minimatch": { + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.5" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/text-extensions": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/text-extensions/-/text-extensions-2.4.0.tgz", + "integrity": "sha512-te/NtwBwfiNRLf9Ijqx3T0nlqZiQ2XrrtBvu+cLL8ZRrGkO0NHTug8MYFKyoSrv/sHTaSKfilUkizV6XhxMJ3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/thenify": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", + "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "any-promise": "^1.0.0" + } + }, + "node_modules/thenify-all": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "thenify": ">= 3.1.0 < 4" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinybench": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", + "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinyexec": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.1.1.tgz", + "integrity": "sha512-VKS/ZaQhhkKFMANmAOhhXVoIfBXblQxGX1myCQ2faQrfmobMftXeJPcZGp0gS07ocvGJWDLZGyOZDadDBqYIJg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.16", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.16.tgz", + "integrity": "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinypool": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-1.1.1.tgz", + "integrity": "sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.0.0 || >=20.0.0" + } + }, + "node_modules/tinyrainbow": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-2.0.0.tgz", + "integrity": "sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tinyspy": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-4.0.4.tgz", + "integrity": "sha512-azl+t0z7pw/z958Gy9svOTuzqIk6xq+NSheJzn5MMWtWTFywIacg2wUlzKFGtt3cthx0r2SxMK0yzJOR0IES7Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "dev": true, + "license": "MIT" + }, + "node_modules/ts-algebra": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ts-algebra/-/ts-algebra-2.0.0.tgz", + "integrity": "sha512-FPAhNPFMrkwz76P7cdjdmiShwMynZYN6SgOujD1urY4oNm80Ou9oMdmbR45LotcKOXoy7wSmHkRFE6Mxbrhefw==", + "dev": true, + "license": "MIT" + }, + "node_modules/ts-api-utils": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.5.0.tgz", + "integrity": "sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.12" + }, + "peerDependencies": { + "typescript": ">=4.8.4" + } + }, + "node_modules/tsdown": { + "version": "0.12.9", + "resolved": "https://registry.npmjs.org/tsdown/-/tsdown-0.12.9.tgz", + "integrity": "sha512-MfrXm9PIlT3saovtWKf/gCJJ/NQCdE0SiREkdNC+9Qy6UHhdeDPxnkFaBD7xttVUmgp0yUHtGirpoLB+OVLuLA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansis": "^4.1.0", + "cac": "^6.7.14", + "chokidar": "^4.0.3", + "debug": "^4.4.1", + "diff": "^8.0.2", + "empathic": "^2.0.0", + "hookable": "^5.5.3", + "rolldown": "^1.0.0-beta.19", + "rolldown-plugin-dts": "^0.13.12", + "semver": "^7.7.2", + "tinyexec": "^1.0.1", + "tinyglobby": "^0.2.14", + "unconfig": "^7.3.2" + }, + "bin": { + "tsdown": "dist/run.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sxzz" + }, + "peerDependencies": { + "@arethetypeswrong/core": "^0.18.1", + "publint": "^0.3.0", + "typescript": "^5.0.0", + "unplugin-lightningcss": "^0.4.0", + "unplugin-unused": "^0.5.0" + }, + "peerDependenciesMeta": { + "@arethetypeswrong/core": { + "optional": true + }, + "publint": { + "optional": true + }, + "typescript": { + "optional": true + }, + "unplugin-lightningcss": { + "optional": true + }, + "unplugin-unused": { + "optional": true + } + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true, + "license": "0BSD", + "optional": true + }, + "node_modules/tsx": { + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.21.0.tgz", + "integrity": "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "~0.27.0", + "get-tsconfig": "^4.7.5" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/typescript-eslint": { + "version": "8.58.2", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.58.2.tgz", + "integrity": "sha512-V8iSng9mRbdZjl54VJ9NKr6ZB+dW0J3TzRXRGcSbLIej9jV86ZRtlYeTKDR/QLxXykocJ5icNzbsl2+5TzIvcQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/eslint-plugin": "8.58.2", + "@typescript-eslint/parser": "8.58.2", + "@typescript-eslint/typescript-estree": "8.58.2", + "@typescript-eslint/utils": "8.58.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/unconfig": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/unconfig/-/unconfig-7.5.0.tgz", + "integrity": "sha512-oi8Qy2JV4D3UQ0PsopR28CzdQ3S/5A1zwsUwp/rosSbfhJ5z7b90bIyTwi/F7hCLD4SGcZVjDzd4XoUQcEanvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@quansync/fs": "^1.0.0", + "defu": "^6.1.4", + "jiti": "^2.6.1", + "quansync": "^1.0.0", + "unconfig-core": "7.5.0" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/unconfig-core": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/unconfig-core/-/unconfig-core-7.5.0.tgz", + "integrity": "sha512-Su3FauozOGP44ZmKdHy2oE6LPjk51M/TRRjHv2HNCWiDvfvCoxC2lno6jevMA91MYAdCdwP05QnWdWpSbncX/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@quansync/fs": "^1.0.0", + "quansync": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/unicode-emoji-modifier-base": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unicode-emoji-modifier-base/-/unicode-emoji-modifier-base-1.0.0.tgz", + "integrity": "sha512-yLSH4py7oFH3oG/9K+XWrz1pSi3dfUrWEnInbxMfArOfc1+33BlGPQtLsOYwvdMy11AwUBetYuaRxSPqgkq+8g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicorn-magic": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.1.0.tgz", + "integrity": "sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/validate-npm-package-name": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-5.0.1.tgz", + "integrity": "sha512-OljLrQ9SQdOUqTaQxqL5dEfZWrXExyyWsozYlAWFawPVNuD83igl7uJD2RTkNMbniIYgt8l81eCJGIdQF7avLQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/vite": { + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.2.tgz", + "integrity": "sha512-Bby3NOsna2jsjfLVOHKes8sGwgl4TT0E6vvpYgnAYDIF/tie7MRaFthmKuHx1NSXjiTueXH3do80FMQgvEktRg==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.27.0", + "fdir": "^6.5.0", + "picomatch": "^4.0.3", + "postcss": "^8.5.6", + "rollup": "^4.43.0", + "tinyglobby": "^0.2.15" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "lightningcss": "^1.21.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/vite-node": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-3.2.4.tgz", + "integrity": "sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cac": "^6.7.14", + "debug": "^4.4.1", + "es-module-lexer": "^1.7.0", + "pathe": "^2.0.3", + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0" + }, + "bin": { + "vite-node": "vite-node.mjs" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/vitest": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-3.2.4.tgz", + "integrity": "sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/chai": "^5.2.2", + "@vitest/expect": "3.2.4", + "@vitest/mocker": "3.2.4", + "@vitest/pretty-format": "^3.2.4", + "@vitest/runner": "3.2.4", + "@vitest/snapshot": "3.2.4", + "@vitest/spy": "3.2.4", + "@vitest/utils": "3.2.4", + "chai": "^5.2.0", + "debug": "^4.4.1", + "expect-type": "^1.2.1", + "magic-string": "^0.30.17", + "pathe": "^2.0.3", + "picomatch": "^4.0.2", + "std-env": "^3.9.0", + "tinybench": "^2.9.0", + "tinyexec": "^0.3.2", + "tinyglobby": "^0.2.14", + "tinypool": "^1.1.1", + "tinyrainbow": "^2.0.0", + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0", + "vite-node": "3.2.4", + "why-is-node-running": "^2.3.0" + }, + "bin": { + "vitest": "vitest.mjs" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@edge-runtime/vm": "*", + "@types/debug": "^4.1.12", + "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", + "@vitest/browser": "3.2.4", + "@vitest/ui": "3.2.4", + "happy-dom": "*", + "jsdom": "*" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true + }, + "@types/debug": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@vitest/browser": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + } + } + }, + "node_modules/vitest/node_modules/tinyexec": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz", + "integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/web-streams-polyfill": { + "version": "4.0.0-beta.3", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-4.0.0-beta.3.tgz", + "integrity": "sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dev": true, + "license": "MIT", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/why-is-node-running": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", + "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", + "dev": true, + "license": "MIT", + "dependencies": { + "siginfo": "^2.0.0", + "stackback": "0.0.2" + }, + "bin": { + "why-is-node-running": "cli.js" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wrap-ansi": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", + "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/emoji-regex": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", + "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", + "dev": true, + "license": "MIT" + }, + "node_modules/wrap-ansi/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yaml": { + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.3.tgz", + "integrity": "sha512-AvbaCLOO2Otw/lW5bmh9d/WEdcDFdQp2Z2ZUH3pX9U2ihyUY0nvLv7J6TrWowklRGPYbB/IuIMfYgxaCPg5Bpg==", + "dev": true, + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + }, + "funding": { + "url": "https://github.com/sponsors/eemeli" + } + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/yocto-queue": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.2.2.tgz", + "integrity": "sha512-4LCcse/U2MHZ63HAJVE+v71o7yOdIe4cZ70Wpf8D/IyjDKYQLV5GD46B+hSTjJsvV5PztjvHoU580EftxjDZFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/package.json b/package.json index 544bbfa..5ba4b46 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@copilotkit/aimock", - "version": "1.13.0", + "version": "1.14.0", "description": "Mock infrastructure for AI application testing — LLM APIs, image generation, text-to-speech, transcription, video generation, MCP tools, A2A agents, AG-UI event streams, vector databases, search, rerank, and moderation. One package, one port, zero dependencies.", "license": "MIT", "keywords": [