diff --git a/.github/workflows/js.yaml b/.github/workflows/js.yaml index dc055adc..4737ca53 100644 --- a/.github/workflows/js.yaml +++ b/.github/workflows/js.yaml @@ -25,3 +25,7 @@ jobs: pnpm install pnpm run test pnpm run build + env: + OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} + ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} + GEMINI_API_KEY: ${{ secrets.GEMINI_API_KEY }} diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 4547f1cc..639569c3 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -13,7 +13,7 @@ repos: .*\.(json|prisma|svg)| .*pnpm-lock.yaml )$ - args: ["-L rouge,coo,couldn,unsecure"] + args: ["-L rouge,coo,couldn,unsecure,afterall"] - repo: https://github.com/rbubley/mirrors-prettier rev: v3.3.2 hooks: diff --git a/packages/proxy/edge/deps.test.ts b/packages/proxy/edge/deps.test.ts new file mode 100644 index 00000000..be2aaecf --- /dev/null +++ b/packages/proxy/edge/deps.test.ts @@ -0,0 +1,20 @@ +import skott from "skott"; +import { describe, expect, it } from "vitest"; + +describe("proxy/edge", () => { + it("no circ dependencies", async () => { + const { useGraph } = await skott({ + entrypoint: `${__dirname}/index.ts`, + tsConfigPath: `${__dirname}/../tsconfig.json`, + dependencyTracking: { + builtin: false, + thirdParty: true, + typeOnly: true, + }, + }); + + const { findCircularDependencies } = useGraph(); + + expect(findCircularDependencies()).toEqual([]); + }); +}); diff --git a/packages/proxy/package.json b/packages/proxy/package.json index 38263764..0b2b7bf6 100644 --- a/packages/proxy/package.json +++ b/packages/proxy/package.json @@ -1,6 +1,6 @@ { "name": "@braintrust/proxy", - "version": "0.0.7", + "version": "0.0.8", "description": "A proxy server that load balances across AI providers.", "main": "./dist/index.js", "module": "./dist/index.mjs", @@ -36,12 +36,19 @@ "import": "./utils/dist/index.mjs", "module": "./utils/dist/index.mjs", "require": "./utils/dist/index.js" + }, + "./types": { + "types": "./types/dist/index.d.ts", + "import": "./types/dist/index.mjs", + "module": "./types/dist/index.mjs", + "require": "./types/dist/index.js" } }, "files": [ "dist/**/*", "edge/dist/**/*", - "schema/dist/**/*" + "schema/dist/**/*", + "types/dist/**/*" ], "license": "MIT", "publishConfig": { @@ -74,7 +81,9 @@ "@types/yargs": "^17.0.33", "@typescript-eslint/eslint-plugin": "^8.21.0", "esbuild": "^0.19.10", + "msw": "^2.8.2", "npm-run-all": "^4.1.5", + "skott": "^0.35.4", "tsup": "^8.4.0", "typescript": "5.5.4", "vite-tsconfig-paths": "^4.3.2", @@ -84,10 +93,10 @@ "dependencies": { "@anthropic-ai/sdk": "^0.39.0", "@apidevtools/json-schema-ref-parser": "^11.9.1", - "@aws-sdk/client-bedrock-runtime": "^3.738.0", - "@braintrust/core": "^0.0.85", + "@aws-sdk/client-bedrock-runtime": "^3.806.0", + "@braintrust/core": "^0.0.87", "@breezystack/lamejs": "^1.2.7", - "@google/generative-ai": "^0.24.0", + "@google/genai": "^0.13.0", "@opentelemetry/api": "^1.7.0", "@opentelemetry/core": "^1.19.0", "@opentelemetry/resources": "^1.19.0", diff --git a/packages/proxy/schema/deps.test.ts b/packages/proxy/schema/deps.test.ts new file mode 100644 index 00000000..7797c7f2 --- /dev/null +++ b/packages/proxy/schema/deps.test.ts @@ -0,0 +1,20 @@ +import skott from "skott"; +import { describe, expect, it } from "vitest"; + +describe("proxy/schema", () => { + it("no circ dependencies", async () => { + const { useGraph } = await skott({ + entrypoint: `${__dirname}/index.ts`, + tsConfigPath: `${__dirname}/../tsconfig.json`, + dependencyTracking: { + builtin: false, + thirdParty: true, + typeOnly: true, + }, + }); + + const { findCircularDependencies } = useGraph(); + + expect(findCircularDependencies()).toEqual([]); + }); +}); diff --git a/packages/proxy/schema/index.test.ts b/packages/proxy/schema/index.test.ts new file mode 100644 index 00000000..59928cb5 --- /dev/null +++ b/packages/proxy/schema/index.test.ts @@ -0,0 +1,270 @@ +import { MessageCreateParamsBase } from "@anthropic-ai/sdk/resources/messages"; +import { GenerateContentParameters } from "@google/genai"; +import { ChatCompletionCreateParams } from "openai/resources"; +import { expect, it } from "vitest"; +import { ModelFormat, translateParams } from "./index"; + +const examples: Record< + string, + { + openai: ChatCompletionCreateParams; + } & ( // NOTE: these are not strictly the API params. + | { google: GenerateContentParameters } + | { anthropic: MessageCreateParamsBase } + ) +> = { + simple: { + openai: { + model: "gpt-4o", + max_tokens: 1500, + temperature: 0.7, + top_p: 0.9, + frequency_penalty: 0.1, + presence_penalty: 0.2, + messages: [ + { role: "system", content: "You are a helpful assistant." }, + { role: "user", content: "Hello, how are you?" }, + ], + stream: true, + }, + google: { + maxOutputTokens: 1500, + max_tokens: 1500, + messages: [ + { + content: "You are a helpful assistant.", + role: "system", + }, + { + content: "Hello, how are you?", + role: "user", + }, + ], + model: "gpt-4o", + stream: true, + temperature: 0.7, + top_p: 0.9, + }, + anthropic: { + max_tokens: 1500, + messages: [ + { + content: "You are a helpful assistant.", + // @ts-expect-error -- TODO: shouldn't we have translated this to a non system role? + role: "system", + }, + { + content: "Hello, how are you?", + role: "user", + }, + ], + model: "gpt-4o", + stream: true, + temperature: 0.7, + top_p: 0.9, + }, + }, + reasoning_effort: { + openai: { + model: "gpt-4o", + messages: [ + { + role: "system", + content: "You are a detailed reasoning assistant.", + }, + { + role: "user", + content: "Explain how to solve 2x + 4 = 12 step by step.", + }, + ], + temperature: 0, + max_tokens: 1000, + reasoning_effort: "high", + stream: false, + }, + google: { + model: "gpt-4o", + // notice how this is still an intermediate param + // google's api expects a content instead of messages, for example + messages: [ + { + role: "system", + content: "You are a detailed reasoning assistant.", + }, + { + role: "user", + content: "Explain how to solve 2x + 4 = 12 step by step.", + }, + ], + temperature: 0, + thinkingConfig: { + thinkingBudget: 800, + includeThoughts: true, + }, + maxOutputTokens: 1000, + max_tokens: 1000, + stream: false, + }, + anthropic: { + model: "gpt-4o", + messages: [ + { + // @ts-expect-error -- we use the role to later manipulate the request + role: "system", + content: "You are a detailed reasoning assistant.", + }, + { + role: "user", + content: "Explain how to solve 2x + 4 = 12 step by step.", + }, + ], + temperature: 1, + stream: false, + max_tokens: 1536, + thinking: { + budget_tokens: 1024, + type: "enabled", + }, + }, + }, + "reasoning disable": { + openai: { + model: "gpt-4o", + messages: [ + { + role: "system", + content: "You are a detailed reasoning assistant.", + }, + { + role: "user", + content: "Explain how to solve 2x + 4 = 12 step by step.", + }, + ], + temperature: 0, + reasoning_enabled: false, + reasoning_budget: 1024, + stream: false, + }, + google: { + model: "gpt-4o", + // notice how this is still an intermediate param + // google's api expects a content instead of messages, for example + messages: [ + { + role: "system", + content: "You are a detailed reasoning assistant.", + }, + { + role: "user", + content: "Explain how to solve 2x + 4 = 12 step by step.", + }, + ], + temperature: 0, + thinkingConfig: { + thinkingBudget: 0, + }, + stream: false, + }, + anthropic: { + model: "gpt-4o", + messages: [ + { + // @ts-expect-error -- we use the role to later manipulate the request + role: "system", + content: "You are a detailed reasoning assistant.", + }, + { + role: "user", + content: "Explain how to solve 2x + 4 = 12 step by step.", + }, + ], + temperature: 0, + stream: false, + max_tokens: 1024, + thinking: { + type: "disabled", + }, + }, + }, + "reasoning budget": { + openai: { + model: "gpt-4o", + messages: [ + { + role: "system", + content: "You are a detailed reasoning assistant.", + }, + { + role: "user", + content: "Explain how to solve 2x + 4 = 12 step by step.", + }, + ], + temperature: 0, + reasoning_enabled: true, + reasoning_budget: 1024, + stream: false, + }, + google: { + model: "gpt-4o", + // notice how this is still an intermediate param + // google's api expects a content instead of messages, for example + messages: [ + { + role: "system", + content: "You are a detailed reasoning assistant.", + }, + { + role: "user", + content: "Explain how to solve 2x + 4 = 12 step by step.", + }, + ], + temperature: 0, + thinkingConfig: { + thinkingBudget: 1024, + includeThoughts: true, + }, + stream: false, + }, + anthropic: { + model: "gpt-4o", + messages: [ + { + // @ts-expect-error -- we use the role to later manipulate the request + role: "system", + content: "You are a detailed reasoning assistant.", + }, + { + role: "user", + content: "Explain how to solve 2x + 4 = 12 step by step.", + }, + ], + temperature: 1, + stream: false, + max_tokens: 1536, + thinking: { + budget_tokens: 1024, + type: "enabled", + }, + }, + }, +}; + +Object.entries(examples).forEach(([example, { openai, ...providers }]) => { + Object.entries(providers).forEach(([provider, expected]) => { + it(`[${example}] translate openai to ${provider} params`, () => { + const result = translateParams( + provider as ModelFormat, + openai as unknown as Record, + ); + try { + expect(result).toEqual(expected); + } catch (error) { + console.warn( + `Exact openai -> ${provider} translation failed. Found:`, + JSON.stringify(result, null, 2), + ); + expect.soft(result).toEqual(expected); + } + }); + }); +}); diff --git a/packages/proxy/schema/index.ts b/packages/proxy/schema/index.ts index 07eefac2..3fa77cda 100644 --- a/packages/proxy/schema/index.ts +++ b/packages/proxy/schema/index.ts @@ -6,6 +6,9 @@ import type { ModelParams, } from "@braintrust/core/typespecs"; import { AvailableModels, ModelFormat, ModelEndpointType } from "./models"; +import { openaiParamsToAnthropicMesssageParams } from "@lib/providers/anthropic"; +import { OpenAIChatCompletionCreateParams } from "@types"; +import { openaiParamsToGeminiMessageParams } from "@lib/providers/google"; export * from "./secrets"; export * from "./models"; @@ -49,10 +52,17 @@ export const modelParamToModelParam: { stream_options: null, parallel_tool_calls: null, response_format: null, - reasoning_effort: null, + reasoning_effort: "reasoning_effort", stop: null, }; +const paramMappers: Partial< + Record object> +> = { + anthropic: openaiParamsToAnthropicMesssageParams, + google: openaiParamsToGeminiMessageParams, +}; + export const sliderSpecs: { // min, max, step, required [name: string]: [number, number, number, boolean]; @@ -82,6 +92,7 @@ export const defaultModelParamSettings: { response_format: null, stop: undefined, use_cache: true, + reasoning_effort: "medium", }, anthropic: { temperature: undefined, @@ -89,6 +100,8 @@ export const defaultModelParamSettings: { top_p: 0.7, top_k: 5, use_cache: true, + reasoning_enabled: false, + reasoning_budget: undefined, }, google: { temperature: undefined, @@ -96,6 +109,8 @@ export const defaultModelParamSettings: { topP: 0.7, topK: 5, use_cache: true, + reasoning_enabled: false, + reasoning_budget: undefined, }, js: {}, window: { @@ -121,6 +136,17 @@ export const modelProviderHasTools: { converse: true, }; +export const modelProviderHasReasoning: { + [name in ModelFormat]?: RegExp; +} = { + openai: /^o[1-4]/i, + anthropic: /^claude-3\.7/i, + google: /gemini-2.0-flash$|gemini-2.5/i, + js: undefined, + window: undefined, + converse: undefined, +}; + export const DefaultEndpointTypes: { [name in ModelFormat]: ModelEndpointType[]; } = { @@ -441,23 +467,34 @@ export function translateParams( toProvider: ModelFormat, params: Record, ): Record { - const translatedParams: Record = {}; + let translatedParams: Record = {}; + for (const [k, v] of Object.entries(params || {})) { const safeValue = v ?? undefined; // Don't propagate "null" along const translatedKey = modelParamToModelParam[k as keyof ModelParams] as | keyof ModelParams | undefined | null; + if (translatedKey === null) { continue; - } else if ( - translatedKey !== undefined && - defaultModelParamSettings[toProvider][translatedKey] !== undefined - ) { - translatedParams[translatedKey] = safeValue; - } else { - translatedParams[k] = safeValue; } + + const hasDefaultParam = + translatedKey !== undefined && + defaultModelParamSettings[toProvider][translatedKey] !== undefined; + + translatedParams[hasDefaultParam ? translatedKey : k] = safeValue; + } + + // ideally we should short circuit and just have a master mapper but this avoids scope + // for now + const mapper = paramMappers[toProvider]; + if (mapper) { + translatedParams = mapper(translatedParams as any) as Record< + string, + unknown + >; } return translatedParams; diff --git a/packages/proxy/schema/model_list.json b/packages/proxy/schema/model_list.json index 255fd958..d6437b39 100644 --- a/packages/proxy/schema/model_list.json +++ b/packages/proxy/schema/model_list.json @@ -113,7 +113,7 @@ "input_cost_per_mil_tokens": 1.1, "output_cost_per_mil_tokens": 4.4, "input_cache_read_cost_per_mil_tokens": 0.275, - "o1_like": true + "reasoning": true }, "o4-mini-2025-04-16": { "format": "openai", @@ -122,7 +122,7 @@ "input_cost_per_mil_tokens": 1.1, "output_cost_per_mil_tokens": 4.4, "input_cache_read_cost_per_mil_tokens": 0.275, - "o1_like": true, + "reasoning": true, "parent": "o4-mini" }, "o3-mini": { @@ -132,7 +132,7 @@ "input_cost_per_mil_tokens": 1.1, "output_cost_per_mil_tokens": 4.4, "input_cache_read_cost_per_mil_tokens": 0.55, - "o1_like": true + "reasoning": true }, "o3-mini-2025-01-31": { "format": "openai", @@ -141,7 +141,7 @@ "input_cost_per_mil_tokens": 1.1, "output_cost_per_mil_tokens": 4.4, "input_cache_read_cost_per_mil_tokens": 0.55, - "o1_like": true, + "reasoning": true, "parent": "o3-mini" }, "o3": { @@ -151,7 +151,7 @@ "input_cost_per_mil_tokens": 10, "output_cost_per_mil_tokens": 40, "input_cache_read_cost_per_mil_tokens": 2.5, - "o1_like": true + "reasoning": true }, "o3-2025-04-16": { "format": "openai", @@ -160,7 +160,7 @@ "input_cost_per_mil_tokens": 10, "output_cost_per_mil_tokens": 40, "input_cache_read_cost_per_mil_tokens": 2.5, - "o1_like": true, + "reasoning": true, "parent": "o3" }, "o1": { @@ -170,7 +170,7 @@ "input_cost_per_mil_tokens": 15, "output_cost_per_mil_tokens": 60, "input_cache_read_cost_per_mil_tokens": 7.5, - "o1_like": true + "reasoning": true }, "o1-2024-12-17": { "format": "openai", @@ -179,7 +179,7 @@ "input_cost_per_mil_tokens": 15, "output_cost_per_mil_tokens": 60, "input_cache_read_cost_per_mil_tokens": 7.5, - "o1_like": true, + "reasoning": true, "parent": "o1" }, "o1-mini": { @@ -189,7 +189,7 @@ "input_cost_per_mil_tokens": 1.1, "output_cost_per_mil_tokens": 4.4, "input_cache_read_cost_per_mil_tokens": 0.55, - "o1_like": true + "reasoning": true }, "o1-mini-2024-09-12": { "format": "openai", @@ -198,7 +198,7 @@ "input_cost_per_mil_tokens": 3, "output_cost_per_mil_tokens": 12, "input_cache_read_cost_per_mil_tokens": 1.5, - "o1_like": true, + "reasoning": true, "parent": "o1-mini" }, "o1-pro": { @@ -207,7 +207,7 @@ "multimodal": true, "input_cost_per_mil_tokens": 150, "output_cost_per_mil_tokens": 600, - "o1_like": true + "reasoning": true }, "o1-pro-2025-03-19": { "format": "openai", @@ -215,7 +215,7 @@ "multimodal": true, "input_cost_per_mil_tokens": 150, "output_cost_per_mil_tokens": 600, - "o1_like": true, + "reasoning": true, "parent": "o1-pro" }, "chatgpt-4o-latest": { @@ -313,7 +313,7 @@ "input_cost_per_mil_tokens": 15, "output_cost_per_mil_tokens": 60, "input_cache_read_cost_per_mil_tokens": 7.5, - "o1_like": true, + "reasoning": true, "experimental": true, "parent": "o1" }, @@ -324,7 +324,7 @@ "input_cost_per_mil_tokens": 15, "output_cost_per_mil_tokens": 60, "input_cache_read_cost_per_mil_tokens": 7.5, - "o1_like": true, + "reasoning": true, "experimental": true, "parent": "o1" }, @@ -510,6 +510,8 @@ "format": "anthropic", "flavor": "chat", "multimodal": true, + "reasoning": true, + "reasoning_budget": true, "input_cost_per_mil_tokens": 3, "output_cost_per_mil_tokens": 15, "input_cache_read_cost_per_mil_tokens": 0.3, @@ -531,6 +533,8 @@ "format": "anthropic", "flavor": "chat", "multimodal": true, + "reasoning_budget": true, + "reasoning": true, "input_cost_per_mil_tokens": 3, "output_cost_per_mil_tokens": 15, "input_cache_read_cost_per_mil_tokens": 0.3, @@ -541,6 +545,8 @@ "format": "anthropic", "flavor": "chat", "multimodal": true, + "reasoning_budget": true, + "reasoning": true, "input_cost_per_mil_tokens": 3, "output_cost_per_mil_tokens": 15, "input_cache_read_cost_per_mil_tokens": 0.3, @@ -601,6 +607,8 @@ "format": "anthropic", "flavor": "chat", "multimodal": true, + "reasoning": true, + "reasoning_budget": true, "input_cost_per_mil_tokens": 15, "output_cost_per_mil_tokens": 75, "input_cache_read_cost_per_mil_tokens": 1.5, @@ -1784,7 +1792,7 @@ "multimodal": true, "input_cost_per_mil_tokens": 0.1, "output_cost_per_mil_tokens": 0.4, - "displayName": "Gemini 2.0 Flash" + "displayName": "Gemini 2.0 Flash Latest" }, "gemini-2.0-flash-001": { "format": "google", @@ -1902,6 +1910,8 @@ "format": "google", "flavor": "chat", "multimodal": true, + "reasoning": true, + "reasoning_budget": true, "input_cost_per_mil_tokens": 0.15, "output_cost_per_mil_tokens": 0.6, "displayName": "Gemini 2.5 Flash Preview", @@ -1911,6 +1921,8 @@ "format": "google", "flavor": "chat", "multimodal": true, + "reasoning": true, + "reasoning_budget": true, "input_cost_per_mil_tokens": 0.15, "output_cost_per_mil_tokens": 0.6, "experimental": false, @@ -1920,6 +1932,8 @@ "format": "google", "flavor": "chat", "multimodal": true, + "reasoning_budget": true, + "reasoning": true, "input_cost_per_mil_tokens": 1.25, "output_cost_per_mil_tokens": 10, "displayName": "Gemini 2.5 Pro Preview", @@ -1929,6 +1943,8 @@ "format": "google", "flavor": "chat", "multimodal": true, + "reasoning_budget": true, + "reasoning": true, "input_cost_per_mil_tokens": 1.25, "output_cost_per_mil_tokens": 10, "experimental": false, @@ -1938,12 +1954,22 @@ "format": "google", "flavor": "chat", "multimodal": true, + "reasoning": true, "input_cost_per_mil_tokens": 1.25, "output_cost_per_mil_tokens": 10, - "displayName": "Gemini 2.5 Pro Experimental", "experimental": true, "parent": "gemini-2.5-pro-preview-05-06" }, + "gemini-2.0-pro-exp-02-05": { + "format": "google", + "flavor": "chat", + "multimodal": true, + "input_cost_per_mil_tokens": 1.25, + "output_cost_per_mil_tokens": 10, + "experimental": true, + "deprecated": true, + "parent": "gemini-2.5-pro-preview-03-25" + }, "gemini-2.0-flash-exp": { "format": "google", "flavor": "chat", @@ -1957,6 +1983,9 @@ "format": "google", "flavor": "chat", "multimodal": true, + "reasoning_budget": true, + "reasoning": true, + "deprecated": true, "input_cost_per_mil_tokens": 0, "output_cost_per_mil_tokens": 0, "experimental": true, @@ -1970,16 +1999,6 @@ "output_cost_per_mil_tokens": 0, "experimental": true }, - "gemini-2.0-pro-exp-02-05": { - "format": "google", - "flavor": "chat", - "multimodal": true, - "input_cost_per_mil_tokens": 1.25, - "output_cost_per_mil_tokens": 10, - "experimental": true, - "deprecated": true, - "parent": "gemini-2.5-pro-preview-03-25" - }, "gemini-exp-1206": { "format": "google", "flavor": "chat", @@ -2137,6 +2156,8 @@ "format": "anthropic", "flavor": "chat", "multimodal": true, + "reasoning": true, + "reasoning_budget": true, "input_cost_per_mil_tokens": 3, "output_cost_per_mil_tokens": 15, "input_cache_read_cost_per_mil_tokens": 0.3, @@ -2147,6 +2168,8 @@ "format": "anthropic", "flavor": "chat", "multimodal": true, + "reasoning": true, + "reasoning_budget": true, "input_cost_per_mil_tokens": 3, "output_cost_per_mil_tokens": 15, "input_cache_read_cost_per_mil_tokens": 0.3, @@ -2158,6 +2181,8 @@ "format": "anthropic", "flavor": "chat", "multimodal": true, + "reasoning_budget": true, + "reasoning": true, "input_cost_per_mil_tokens": 3, "output_cost_per_mil_tokens": 15, "input_cache_read_cost_per_mil_tokens": 0.3, @@ -2168,6 +2193,8 @@ "format": "anthropic", "flavor": "chat", "multimodal": true, + "reasoning_budget": true, + "reasoning": true, "input_cost_per_mil_tokens": 3, "output_cost_per_mil_tokens": 15, "input_cache_read_cost_per_mil_tokens": 0.3, @@ -2265,6 +2292,8 @@ "format": "anthropic", "flavor": "chat", "multimodal": true, + "reasoning": true, + "reasoning_budget": true, "input_cost_per_mil_tokens": 15, "output_cost_per_mil_tokens": 75, "displayName": "Claude 4 Opus" @@ -2273,6 +2302,8 @@ "format": "anthropic", "flavor": "chat", "multimodal": true, + "reasoning": true, + "reasoning_budget": true, "input_cost_per_mil_tokens": 15, "output_cost_per_mil_tokens": 75, "displayName": "US Claude 4 Opus", @@ -2674,6 +2705,8 @@ "format": "anthropic", "flavor": "chat", "multimodal": true, + "reasoning": true, + "reasoning_budget": true, "input_cost_per_mil_tokens": 3, "output_cost_per_mil_tokens": 15, "displayName": "Claude 4 Sonnet" @@ -2682,6 +2715,8 @@ "format": "anthropic", "flavor": "chat", "multimodal": true, + "reasoning": true, + "reasoning_budget": true, "input_cost_per_mil_tokens": 3, "output_cost_per_mil_tokens": 15, "experimental": true, @@ -2693,6 +2728,8 @@ "multimodal": true, "input_cost_per_mil_tokens": 3, "output_cost_per_mil_tokens": 15, + "reasoning_budget": true, + "reasoning": true, "displayName": "Claude 3.7 Sonnet" }, "publishers/anthropic/models/claude-3-7-sonnet@20250219": { @@ -2701,6 +2738,8 @@ "multimodal": true, "input_cost_per_mil_tokens": 3, "output_cost_per_mil_tokens": 15, + "reasoning_budget": true, + "reasoning": true, "experimental": true, "parent": "publishers/anthropic/models/claude-3-7-sonnet" }, @@ -2756,6 +2795,8 @@ "format": "anthropic", "flavor": "chat", "multimodal": true, + "reasoning": true, + "reasoning_budget": true, "input_cost_per_mil_tokens": 15, "output_cost_per_mil_tokens": 75, "displayName": "Claude 4 Opus" @@ -2764,6 +2805,8 @@ "format": "anthropic", "flavor": "chat", "multimodal": true, + "reasoning": true, + "reasoning_budget": true, "input_cost_per_mil_tokens": 15, "output_cost_per_mil_tokens": 75, "parent": "publishers/anthropic/models/claude-opus-4" @@ -2854,6 +2897,8 @@ "flavor": "chat", "displayName": "Gemini 2.5 Flash Preview", "multimodal": true, + "reasoning": true, + "reasoning_budget": true, "input_cost_per_mil_tokens": 0.15, "output_cost_per_mil_tokens": 0.6 }, @@ -2862,6 +2907,8 @@ "flavor": "chat", "displayName": "Gemini 2.5 Flash Preview", "multimodal": true, + "reasoning": true, + "reasoning_budget": true, "input_cost_per_mil_tokens": 0.15, "output_cost_per_mil_tokens": 0.6, "parent": "publishers/google/models/gemini-2.5-flash-preview-05-20" @@ -2911,6 +2958,9 @@ "databricks-claude-3-7-sonnet": { "format": "openai", "flavor": "chat", + "multimodal": true, + "reasoning_budget": true, + "reasoning": true, "displayName": "Claude 3.7 Sonnet" }, "databricks-meta-llama-3-3-70b-instruct": { diff --git a/packages/proxy/schema/models.ts b/packages/proxy/schema/models.ts index 9b4cba0c..d15a925f 100644 --- a/packages/proxy/schema/models.ts +++ b/packages/proxy/schema/models.ts @@ -45,11 +45,30 @@ export const ModelSchema = z.object({ output_cost_per_mil_tokens: z.number().nullish(), input_cache_read_cost_per_mil_tokens: z.number().nullish(), input_cache_write_cost_per_mil_tokens: z.number().nullish(), - displayName: z.string().nullish(), - o1_like: z.boolean().nullish(), - experimental: z.boolean().nullish(), - deprecated: z.boolean().nullish(), - parent: z.string().nullish(), + displayName: z + .string() + .nullish() + .describe("The model is the latest production/stable"), + o1_like: z.boolean().nullish().describe('DEPRECATED use "reasoning" instead'), + reasoning: z + .boolean() + .nullish() + .describe("The model supports reasoning/thinking tokens"), + reasoning_budget: z + .boolean() + .nullish() + .describe("The model supports reasoning/thinking budgets"), + experimental: z + .boolean() + .nullish() + .describe("The model is not allowed production load or API is unstable."), + deprecated: z + .boolean() + .nullish() + .describe( + "Discourage the use of the model (we will hide the model in the UI).", + ), + parent: z.string().nullish().describe("The model was replaced this model."), endpoint_types: z.array(z.enum(ModelEndpointType)).nullish(), locations: z.array(z.string()).nullish(), description: z.string().nullish(), diff --git a/packages/proxy/src/deps.test.ts b/packages/proxy/src/deps.test.ts new file mode 100644 index 00000000..01d5049b --- /dev/null +++ b/packages/proxy/src/deps.test.ts @@ -0,0 +1,20 @@ +import skott from "skott"; +import { describe, expect, it } from "vitest"; + +describe("proxy/src", () => { + it("no circ dependencies", async () => { + const { useGraph } = await skott({ + entrypoint: `${__dirname}/index.ts`, + tsConfigPath: `${__dirname}/../tsconfig.json`, + dependencyTracking: { + builtin: false, + thirdParty: true, + typeOnly: true, + }, + }); + + const { findCircularDependencies } = useGraph(); + + expect(findCircularDependencies()).toEqual([]); + }); +}); diff --git a/packages/proxy/src/providers/anthropic.test.ts b/packages/proxy/src/providers/anthropic.test.ts new file mode 100644 index 00000000..63c2ab94 --- /dev/null +++ b/packages/proxy/src/providers/anthropic.test.ts @@ -0,0 +1,272 @@ +import { describe, it, expect } from "vitest"; +import { callProxyV1 } from "../../utils/tests"; +import { + OpenAIChatCompletion, + OpenAIChatCompletionChunk, + OpenAIChatCompletionCreateParams, +} from "@types"; + +it("should convert OpenAI streaming request to Anthropic and back", async () => { + const { events } = await callProxyV1< + OpenAIChatCompletionCreateParams, + OpenAIChatCompletionChunk + >({ + body: { + model: "claude-2", + messages: [ + { role: "system", content: "You are a helpful assistant." }, + { role: "user", content: "Tell me a short joke about programming." }, + ], + stream: true, + max_tokens: 150, + }, + }); + + const streamedEvents = events(); + + expect(streamedEvents.length).toBeGreaterThan(0); + + streamedEvents.forEach((event) => { + expect(event.type).toBe("event"); + + const data = event.data; + expect(data.id).toBeTruthy(); + expect(data.object).toBe("chat.completion.chunk"); + expect(data.created).toBeTruthy(); + expect(Array.isArray(data.choices)).toBe(true); + + if (data.choices[0]?.delta?.content) { + expect(data.choices[0].delta.content.trim()).not.toBe(""); + } + }); + + const hasContent = streamedEvents.some( + (event) => event.data.choices[0]?.delta?.content !== undefined, + ); + expect(hasContent).toBe(true); +}); + +it("should convert OpenAI non-streaming request to Anthropic and back", async () => { + const { json } = await callProxyV1< + OpenAIChatCompletionCreateParams, + OpenAIChatCompletion + >({ + body: { + model: "claude-2.1", + messages: [ + { role: "system", content: "You are a helpful assistant." }, + { role: "user", content: "Tell me a short joke about programming." }, + ], + stream: false, + max_tokens: 150, + }, + }); + + expect(json()).toEqual({ + choices: [ + { + finish_reason: "stop", + index: 0, + logprobs: null, + message: { + content: expect.any(String), + refusal: null, + role: "assistant", + }, + }, + ], + created: expect.any(Number), + id: expect.any(String), + model: "claude-2.1", + object: "chat.completion", + usage: { + completion_tokens: expect.any(Number), + prompt_tokens: expect.any(Number), + total_tokens: expect.any(Number), + prompt_tokens_details: { + cache_creation_tokens: expect.any(Number), + cached_tokens: expect.any(Number), + }, + }, + }); +}); + +it("should accept and return reasoning/thinking params and detail streaming", async () => { + const { events } = await callProxyV1< + OpenAIChatCompletionCreateParams, + OpenAIChatCompletionChunk + >({ + body: { + model: "claude-3-7-sonnet-latest", + reasoning_effort: "medium", + messages: [ + { + role: "user", + content: "How many rs in 'ferrocarril'", + }, + { + role: "assistant", + content: "There are 4 letter 'r's in the word \"ferrocarril\".", + refusal: null, + reasoning: [ + { + id: "ErUBCkYIAxgCIkDWT/7OwDfkVSgdtjIwGqUpzIHQXkiBQQpIqzh6WnHHoGxN1ilJxIlnJQNarUI4Jo/3WWrmRnnqOU3LtAakLr4REgwvY1G5jTSbLHWOo4caDKNco+CyDfNT56iXBCIwrNSFdvNJNsBaa0hpbTZ6N4Q4z4/6l+gu8hniKnftBhS+IuzcncsuJqKxWKs/EVyjKh3tvH/eDeYovKskosVSO5x64iebuze1S8JbavI3UBgC", + content: + "To count the number of 'r's in the word 'ferrocarril', I'll just go through the word letter by letter.\n\n'ferrocarril' has the following letters:\nf-e-r-r-o-c-a-r-r-i-l\n\nLooking at each letter:\n- 'f': not an 'r'\n- 'e': not an 'r'\n- 'r': This is an 'r', so that's 1.\n- 'r': This is an 'r', so that's 2.\n- 'o': not an 'r'\n- 'c': not an 'r'\n- 'a': not an 'r'\n- 'r': This is an 'r', so that's 3.\n- 'r': This is an 'r', so that's 4.\n- 'i': not an 'r'\n- 'l': not an 'r'\n\nSo there are 4 'r's in the word 'ferrocarril'.", + }, + ], + }, + { + role: "user", + content: "How many e in what you said?", + }, + ], + stream: true, + }, + }); + + const streamedEvents = events(); + expect(streamedEvents.length).toBeGreaterThan(0); + + const hasReasoning = streamedEvents.some( + (event) => event.data.choices[0]?.delta?.reasoning?.content !== undefined, + ); + expect(hasReasoning).toBe(true); + + const hasContent = streamedEvents.some( + (event) => event.data.choices[0]?.delta?.content !== undefined, + ); + expect(hasContent).toBe(true); +}); + +it("should accept and return reasoning/thinking params and detail non-streaming", async () => { + const { json } = await callProxyV1< + OpenAIChatCompletionCreateParams, + OpenAIChatCompletionChunk + >({ + body: { + model: "claude-3-7-sonnet-20250219", + reasoning_effort: "medium", + stream: false, + messages: [ + { + role: "user", + content: "How many rs in 'ferrocarril'", + }, + { + role: "assistant", + content: "There are 4 letter 'r's in the word \"ferrocarril\".", + refusal: null, + reasoning: [ + { + id: "ErUBCkYIAxgCIkDWT/7OwDfkVSgdtjIwGqUpzIHQXkiBQQpIqzh6WnHHoGxN1ilJxIlnJQNarUI4Jo/3WWrmRnnqOU3LtAakLr4REgwvY1G5jTSbLHWOo4caDKNco+CyDfNT56iXBCIwrNSFdvNJNsBaa0hpbTZ6N4Q4z4/6l+gu8hniKnftBhS+IuzcncsuJqKxWKs/EVyjKh3tvH/eDeYovKskosVSO5x64iebuze1S8JbavI3UBgC", + content: + "To count the number of 'r's in the word 'ferrocarril', I'll just go through the word letter by letter.\n\n'ferrocarril' has the following letters:\nf-e-r-r-o-c-a-r-r-i-l\n\nLooking at each letter:\n- 'f': not an 'r'\n- 'e': not an 'r'\n- 'r': This is an 'r', so that's 1.\n- 'r': This is an 'r', so that's 2.\n- 'o': not an 'r'\n- 'c': not an 'r'\n- 'a': not an 'r'\n- 'r': This is an 'r', so that's 3.\n- 'r': This is an 'r', so that's 4.\n- 'i': not an 'r'\n- 'l': not an 'r'\n\nSo there are 4 'r's in the word 'ferrocarril'.", + }, + ], + }, + { + role: "user", + content: "How many e in what you said?", + }, + ], + }, + }); + + expect(json()).toEqual({ + choices: [ + { + finish_reason: "stop", + index: 0, + logprobs: null, + message: { + content: expect.any(String), + reasoning: [ + { + content: expect.any(String), + id: expect.any(String), + }, + ], + refusal: null, + role: "assistant", + }, + }, + ], + created: expect.any(Number), + id: expect.any(String), + model: "claude-3-7-sonnet-20250219", + object: "chat.completion", + usage: { + completion_tokens: expect.any(Number), + prompt_tokens: expect.any(Number), + total_tokens: expect.any(Number), + prompt_tokens_details: { + cache_creation_tokens: expect.any(Number), + cached_tokens: expect.any(Number), + }, + }, + }); +}); + +it("should disable reasoning/thinking params non-streaming", async () => { + const { json } = await callProxyV1< + OpenAIChatCompletionCreateParams, + OpenAIChatCompletionChunk + >({ + body: { + model: "claude-3-7-sonnet-20250219", + reasoning_enabled: false, + stream: false, + messages: [ + { + role: "user", + content: "How many rs in 'ferrocarril'", + }, + { + role: "assistant", + content: "There are 4 letter 'r's in the word \"ferrocarril\".", + refusal: null, + reasoning: [ + { + id: "ErUBCkYIAxgCIkDWT/7OwDfkVSgdtjIwGqUpzIHQXkiBQQpIqzh6WnHHoGxN1ilJxIlnJQNarUI4Jo/3WWrmRnnqOU3LtAakLr4REgwvY1G5jTSbLHWOo4caDKNco+CyDfNT56iXBCIwrNSFdvNJNsBaa0hpbTZ6N4Q4z4/6l+gu8hniKnftBhS+IuzcncsuJqKxWKs/EVyjKh3tvH/eDeYovKskosVSO5x64iebuze1S8JbavI3UBgC", + content: + "To count the number of 'r's in the word 'ferrocarril', I'll just go through the word letter by letter.\n\n'ferrocarril' has the following letters:\nf-e-r-r-o-c-a-r-r-i-l\n\nLooking at each letter:\n- 'f': not an 'r'\n- 'e': not an 'r'\n- 'r': This is an 'r', so that's 1.\n- 'r': This is an 'r', so that's 2.\n- 'o': not an 'r'\n- 'c': not an 'r'\n- 'a': not an 'r'\n- 'r': This is an 'r', so that's 3.\n- 'r': This is an 'r', so that's 4.\n- 'i': not an 'r'\n- 'l': not an 'r'\n\nSo there are 4 'r's in the word 'ferrocarril'.", + }, + ], + }, + { + role: "user", + content: "How many e in what you said?", + }, + ], + }, + }); + + expect(json()).toEqual({ + choices: [ + { + finish_reason: "stop", + index: 0, + logprobs: null, + message: { + content: expect.any(String), + refusal: null, + role: "assistant", + }, + }, + ], + created: expect.any(Number), + id: expect.any(String), + model: "claude-3-7-sonnet-20250219", + object: "chat.completion", + usage: { + completion_tokens: expect.any(Number), + prompt_tokens: expect.any(Number), + total_tokens: expect.any(Number), + prompt_tokens_details: { + cache_creation_tokens: expect.any(Number), + cached_tokens: expect.any(Number), + }, + }, + }); +}); diff --git a/packages/proxy/src/providers/anthropic.ts b/packages/proxy/src/providers/anthropic.ts index 3c18053f..20bc337b 100644 --- a/packages/proxy/src/providers/anthropic.ts +++ b/packages/proxy/src/providers/anthropic.ts @@ -1,29 +1,37 @@ -import { v4 as uuidv4 } from "uuid"; -import { - ChatCompletion, - ChatCompletionChunk, - ChatCompletionMessageToolCall, - ChatCompletionTool, - ChatCompletionToolMessageParam, -} from "openai/resources"; -import { getTimestampInSeconds, isEmpty, isObject } from "../util"; -import { Message } from "@braintrust/core/typespecs"; -import { z } from "zod"; import { MessageParam, ToolResultBlockParam, ToolUseBlockParam, } from "@anthropic-ai/sdk/resources"; -import { convertMediaToBase64 } from "./util"; import { - ImageBlockParam, - DocumentBlockParam, - MessageCreateParamsBase, Base64ImageSource, CacheControlEphemeral, + DocumentBlockParam, + ImageBlockParam, + MessageCreateParams, + MessageCreateParamsBase, + ThinkingConfigParam, } from "@anthropic-ai/sdk/resources/messages"; -import { ChatCompletionCreateParamsBase } from "openai/resources/chat/completions"; -import { CompletionUsage } from "types/openai"; +import { Message } from "@braintrust/core/typespecs"; +import { + OpenAICompletionUsage, + OpenAIChatCompletion, + OpenAIChatCompletionChoice, + OpenAIChatCompletionChunk, + OpenAIChatCompletionChunkChoiceDelta, + OpenAIChatCompletionCreateParams, +} from "@types"; +import { + ChatCompletionMessageToolCall, + ChatCompletionTool, + ChatCompletionToolMessageParam, +} from "openai/resources"; +import { getBudgetMultiplier } from "utils"; +import { cleanOpenAIParams } from "utils/openai"; +import { v4 as uuidv4 } from "uuid"; +import { z } from "zod"; +import { getTimestampInSeconds, isEmpty, isObject } from "../util"; +import { convertMediaToBase64 } from "./util"; /* Example events: @@ -114,6 +122,11 @@ export const anthropicStreamEventSchema = z.discriminatedUnion("type", [ type: z.literal("text"), text: z.string(), }), + z.object({ + type: z.literal("thinking"), + thinking: z.string(), + signature: z.string(), + }), z.object({ type: z.literal("tool_use"), id: z.string(), @@ -169,6 +182,7 @@ export interface AnthropicCompletion { role: "assistant"; content: [ | { type: "text"; text: string } + | { type: "thinking"; thinking: string; signature: string } | { type: "tool_use"; id: string; @@ -189,7 +203,7 @@ export interface AnthropicCompletion { function updateUsage( anthropic: z.infer, - openai: Partial, + openai: Partial, ) { if (!isEmpty(anthropic.cache_read_input_tokens)) { openai.prompt_tokens_details = { @@ -221,10 +235,10 @@ function updateUsage( export function anthropicEventToOpenAIEvent( idx: number, - usage: Partial, + usage: Partial, eventU: unknown, isStructuredOutput: boolean, -): { event: ChatCompletionChunk | null; finished: boolean } { +): { event: OpenAIChatCompletionChunk | null; finished: boolean } { const parsedEvent = anthropicStreamEventSchema.safeParse(eventU); if (!parsedEvent.success) { throw new Error( @@ -242,7 +256,11 @@ export function anthropicEventToOpenAIEvent( } let content: string | undefined = undefined; - let tool_calls: ChatCompletionChunk.Choice.Delta.ToolCall[] | undefined = + let tool_calls: + | OpenAIChatCompletionChunkChoiceDelta["tool_calls"] + | undefined = undefined; + + let reasoning: OpenAIChatCompletionChunkChoiceDelta["reasoning"] | undefined = undefined; if (event.type === "message_start") { @@ -292,6 +310,28 @@ export function anthropicEventToOpenAIEvent( event.delta.type === "text_delta" ) { content = idx === 0 ? event.delta.text.trimStart() : event.delta.text; + } else if ( + event.type === "content_block_start" && + event.content_block.type === "thinking" + ) { + reasoning = { + id: event.content_block.signature, + content: event.content_block.thinking, + }; + } else if ( + event.type === "content_block_delta" && + event.delta.type === "thinking_delta" + ) { + reasoning = { + content: event.delta.thinking, + }; + } else if ( + event.type === "content_block_delta" && + event.delta.type === "signature_delta" + ) { + reasoning = { + id: event.delta.signature, + }; } else if ( event.type === "content_block_delta" && event.delta.type === "input_json_delta" @@ -333,7 +373,7 @@ export function anthropicEventToOpenAIEvent( created: getTimestampInSeconds(), usage: !isEmpty(usage.completion_tokens) && !isEmpty(usage.prompt_tokens) - ? (usage as CompletionUsage) + ? (usage as OpenAICompletionUsage) : undefined, }, finished: true, @@ -362,6 +402,7 @@ export function anthropicEventToOpenAIEvent( content, tool_calls: isStructuredOutput ? undefined : tool_calls, role: "assistant", + reasoning, }, finish_reason: null, // Anthropic places this in a separate stream event. index: 0, @@ -379,10 +420,12 @@ export function anthropicCompletionToOpenAICompletion( completion: AnthropicCompletion, isFunction: boolean, isStructuredOutput: boolean, -): ChatCompletion { +): OpenAIChatCompletion { + // TODO: will we ever have text -> thinking -> text -> tool_use, thus are we dropping tokens? const firstText = completion.content.find((c) => c.type === "text"); + const firstThinking = completion.content.find((c) => c.type === "thinking"); const firstTool = completion.content.find((c) => c.type === "tool_use"); - let usage: CompletionUsage | undefined = undefined; + let usage: OpenAICompletionUsage | undefined = undefined; if (completion.usage) { usage = { prompt_tokens: 0, @@ -428,6 +471,14 @@ export function anthropicCompletionToOpenAICompletion( } : undefined, refusal: null, + ...(firstThinking && { + reasoning: [ + { + id: firstThinking.signature, + content: firstThinking.thinking, + }, + ], + }), }, }, ], @@ -440,7 +491,7 @@ export function anthropicCompletionToOpenAICompletion( function anthropicFinishReason( stop_reason: string, -): ChatCompletion.Choice["finish_reason"] | null { +): OpenAIChatCompletionChoice["finish_reason"] | null { return stop_reason === "stop_reason" ? "stop" : stop_reason === "max_tokens" @@ -599,7 +650,7 @@ export function openAIToolsToAnthropicTools( } export function anthropicToolChoiceToOpenAIToolChoice( - toolChoice: ChatCompletionCreateParamsBase["tool_choice"], + toolChoice: OpenAIChatCompletionCreateParams["tool_choice"], ): MessageCreateParamsBase["tool_choice"] { if (!toolChoice) { return undefined; @@ -615,3 +666,85 @@ export function anthropicToolChoiceToOpenAIToolChoice( return { type: "tool", name: toolChoice.function.name }; } } + +export function openaiParamsToAnthropicMesssageParams( + openai: OpenAIChatCompletionCreateParams, +): MessageCreateParams { + const anthropic: MessageCreateParams = { + // TODO: we depend on translateParams to get us half way there + ...(cleanOpenAIParams(openai) as any), + }; + + const maxTokens = + Math.max(openai.max_completion_tokens || 0, openai.max_tokens || 0) || 1024; + + anthropic.max_tokens = maxTokens; + + if ( + openai.reasoning_effort !== undefined || + openai.reasoning_budget !== undefined || + openai.reasoning_enabled !== undefined + ) { + anthropic.thinking = getAnthropicThinkingParams({ + ...openai, + max_completion_tokens: maxTokens, + }); + + if (anthropic.thinking.type === "enabled") { + // must be 1 when thinking + anthropic.temperature = 1; + + // avoid anthropic APIs complaining about this + // need to make sure max_tokens are greater than budget_tokens + const effectiveMax = Math.max( + anthropic.max_tokens, + anthropic.thinking.budget_tokens, + ); + if (effectiveMax === anthropic.thinking.budget_tokens) { + anthropic.max_tokens = Math.floor(effectiveMax * 1.5); + } + } + } + + return anthropic; +} + +const getAnthropicThinkingParams = ( + openai: OpenAIChatCompletionCreateParams & { + max_completion_tokens: Required; + }, +): ThinkingConfigParam => { + if (openai.reasoning_enabled === false || openai.reasoning_budget === 0) { + return { type: "disabled" }; + } + + return { + type: "enabled", + budget_tokens: getThinkingBudget(openai), + }; +}; + +const getThinkingBudget = ( + openai: OpenAIChatCompletionCreateParams & { + max_completion_tokens: Required; + }, +): number => { + if (openai.reasoning_budget !== undefined) { + return openai.reasoning_budget; + } + + let budget = 1024; + + if (openai.reasoning_effort !== undefined) { + // budget must be at least 1024 + budget = Math.max( + Math.floor( + getBudgetMultiplier(openai.reasoning_effort || "low") * + openai.max_completion_tokens, + ), + 1024, + ); + } + + return budget; +}; diff --git a/packages/proxy/src/providers/bedrock.ts b/packages/proxy/src/providers/bedrock.ts index 36c576dc..2ebd345f 100644 --- a/packages/proxy/src/providers/bedrock.ts +++ b/packages/proxy/src/providers/bedrock.ts @@ -1,56 +1,54 @@ -import { v4 as uuidv4 } from "uuid"; -import { z } from "zod"; import { + Message as BedrockMessage, BedrockRuntimeClient, ContentBlock, ConverseCommand, ConverseCommandOutput, ConverseStreamCommand, ConverseStreamOutput, + ImageFormat, + InferenceConfiguration, InvokeModelCommand, InvokeModelWithResponseStreamCommand, + ResponseStream, StopReason, SystemContentBlock, - Message as BedrockMessage, - ImageBlock, - DocumentBlock, ToolConfiguration, - InferenceConfiguration, - ImageFormat, - ResponseStream, } from "@aws-sdk/client-bedrock-runtime"; +import { + MessageRole, + Message as OaiMessage, + responseFormatJsonSchemaSchema, + toolsSchema, +} from "@braintrust/core/typespecs"; import { APISecret, BedrockMetadata, BedrockMetadataSchema, MessageTypeToMessageType, } from "@schema"; +import { OpenAIChatCompletion, OpenAIChatCompletionChunk } from "@types"; +import { CompletionUsage } from "openai/resources"; import { - anthropicCompletionToOpenAICompletion, - anthropicEventToOpenAIEvent, -} from "./anthropic"; -import { ChatCompletionChunk, CompletionUsage } from "openai/resources"; + ChatCompletionMessageToolCall, + ChatCompletionTool, + ChatCompletionToolMessageParam, +} from "openai/resources/chat/completions"; +import { v4 as uuidv4 } from "uuid"; +import { z } from "zod"; import { getTimestampInSeconds, - writeToReadable, isEmpty, + ModelResponse, ProxyBadRequestError, -} from ".."; -import { - Message as OaiMessage, - MessageRole, - toolsSchema, - responseFormatJsonSchemaSchema, -} from "@braintrust/core/typespecs"; + writeToReadable, +} from "../util"; import { - ChatCompletion, - ChatCompletionMessageToolCall, - ChatCompletionTool, - ChatCompletionToolMessageParam, -} from "openai/resources/chat/completions"; -import { convertMediaToBase64 } from "./util"; + anthropicCompletionToOpenAICompletion, + anthropicEventToOpenAIEvent, +} from "./anthropic"; import { makeFakeOpenAIStreamTransformer } from "./openai"; -import { ModelResponse } from "../util"; +import { convertMediaToBase64 } from "./util"; function streamResponse( body: AsyncIterable, @@ -752,7 +750,7 @@ function openAIResponse( model: string, response: ConverseCommandOutput, isStructuredOutput: boolean, -): ChatCompletion { +): OpenAIChatCompletion { const firstText = response.output?.message?.content?.find( (c) => c.text !== undefined, ); @@ -833,7 +831,7 @@ function translateInferenceConfig( interface BedrockMessageState { completionId: string; - role: ChatCompletionChunk["choices"][0]["delta"]["role"]; + role: OpenAIChatCompletionChunk["choices"][0]["delta"]["role"]; } export function bedrockMessageToOpenAIMessage( @@ -841,11 +839,11 @@ export function bedrockMessageToOpenAIMessage( output: ConverseStreamOutput, isStructuredOutput: boolean, ): { - event: ChatCompletionChunk | null; + event: OpenAIChatCompletionChunk | null; finished: boolean; } { return ConverseStreamOutput.visit<{ - event: ChatCompletionChunk | null; + event: OpenAIChatCompletionChunk | null; finished: boolean; }>(output, { messageStart: (value) => { @@ -876,6 +874,12 @@ export function bedrockMessageToOpenAIMessage( }, ] : undefined, + ...(value.delta?.reasoningContent && { + reasoning: { + id: value.delta.reasoningContent.signature, + content: value.delta.reasoningContent.text, + }, + }), }, finish_reason: null, index: 0, diff --git a/packages/proxy/src/providers/google.test.ts b/packages/proxy/src/providers/google.test.ts new file mode 100644 index 00000000..f4d0bdd5 --- /dev/null +++ b/packages/proxy/src/providers/google.test.ts @@ -0,0 +1,191 @@ +import { describe, it, expect } from "vitest"; +import { callProxyV1 } from "../../utils/tests"; +import { + OpenAIChatCompletionChunk, + OpenAIChatCompletionCreateParams, +} from "@types"; + +for (const model of [ + "gemini-2.5-flash-preview-05-20", + // TODO: re-enable when we have a working CI/CD solution + // "publishers/google/models/gemini-2.5-flash-preview-05-20", +]) { + describe(model, () => { + it("should accept and should not return reasoning/thinking params and detail streaming", async () => { + const { events, json } = await callProxyV1< + OpenAIChatCompletionCreateParams, + OpenAIChatCompletionChunk + >({ + body: { + model, + reasoning_effort: "medium", + messages: [ + { + role: "user", + content: "How many rs in 'ferrocarril'", + }, + { + role: "assistant", + content: "There are 4 letter 'r's in the word \"ferrocarril\".", + refusal: null, + reasoning: [ + { + id: "", + content: + "To count the number of 'r's in the word 'ferrocarril', I'll just go through the word letter by letter.\n\n'ferrocarril' has the following letters:\nf-e-r-r-o-c-a-r-r-i-l\n\nLooking at each letter:\n- 'f': not an 'r'\n- 'e': not an 'r'\n- 'r': This is an 'r', so that's 1.\n- 'r': This is an 'r', so that's 2.\n- 'o': not an 'r'\n- 'c': not an 'r'\n- 'a': not an 'r'\n- 'r': This is an 'r', so that's 3.\n- 'r': This is an 'r', so that's 4.\n- 'i': not an 'r'\n- 'l': not an 'r'\n\nSo there are 4 'r's in the word 'ferrocarril'.", + }, + ], + }, + { + role: "user", + content: "How many e in what you said?", + }, + ], + stream: true, + }, + }); + + const streamedEvents = events(); + expect(streamedEvents.length).toBeGreaterThan(0); + + const hasContent = streamedEvents.some( + (event) => event.data.choices[0]?.delta?.content !== undefined, + ); + expect(hasContent).toBe(true); + + const hasReasoning = streamedEvents.some( + (event) => + event.data.choices[0]?.delta?.reasoning?.content !== undefined, + ); + expect(hasReasoning).toBe(true); + }); + + it("should accept and return reasoning/thinking params and detail non-streaming", async () => { + const { json } = await callProxyV1< + OpenAIChatCompletionCreateParams, + OpenAIChatCompletionChunk + >({ + body: { + model, + reasoning_effort: "medium", + stream: false, + messages: [ + { + role: "user", + content: "How many rs in 'ferrocarril'", + }, + { + role: "assistant", + content: "There are 4 letter 'r's in the word \"ferrocarril\".", + refusal: null, + reasoning: [ + { + id: "", + content: + "To count the number of 'r's in the word 'ferrocarril', I'll just go through the word letter by letter.\n\n'ferrocarril' has the following letters:\nf-e-r-r-o-c-a-r-r-i-l\n\nLooking at each letter:\n- 'f': not an 'r'\n- 'e': not an 'r'\n- 'r': This is an 'r', so that's 1.\n- 'r': This is an 'r', so that's 2.\n- 'o': not an 'r'\n- 'c': not an 'r'\n- 'a': not an 'r'\n- 'r': This is an 'r', so that's 3.\n- 'r': This is an 'r', so that's 4.\n- 'i': not an 'r'\n- 'l': not an 'r'\n\nSo there are 4 'r's in the word 'ferrocarril'.", + }, + ], + }, + { + role: "user", + content: "How many e in what you said?", + }, + ], + }, + }); + + expect(json()).toEqual({ + choices: [ + { + finish_reason: "stop", + index: 0, + logprobs: null, + message: { + content: expect.any(String), + reasoning: [ + { + id: expect.any(String), + content: expect.any(String), + }, + ], + refusal: null, + role: "assistant", + }, + }, + ], + created: expect.any(Number), + id: expect.any(String), + model, + object: "chat.completion", + usage: { + completion_tokens: expect.any(Number), + completion_tokens_details: { + reasoning_tokens: expect.any(Number), + }, + prompt_tokens: expect.any(Number), + total_tokens: expect.any(Number), + }, + }); + }); + + it("should disable reasoning/thinking non-streaming", async () => { + const { json } = await callProxyV1< + OpenAIChatCompletionCreateParams, + OpenAIChatCompletionChunk + >({ + body: { + model, + reasoning_enabled: true, + reasoning_budget: 0, + stream: false, + messages: [ + { + role: "user", + content: "How many rs in 'ferrocarril'", + }, + { + role: "assistant", + content: "There are 4 letter 'r's in the word \"ferrocarril\".", + refusal: null, + reasoning: [ + { + id: "", + content: + "To count the number of 'r's in the word 'ferrocarril', I'll just go through the word letter by letter.\n\n'ferrocarril' has the following letters:\nf-e-r-r-o-c-a-r-r-i-l\n\nLooking at each letter:\n- 'f': not an 'r'\n- 'e': not an 'r'\n- 'r': This is an 'r', so that's 1.\n- 'r': This is an 'r', so that's 2.\n- 'o': not an 'r'\n- 'c': not an 'r'\n- 'a': not an 'r'\n- 'r': This is an 'r', so that's 3.\n- 'r': This is an 'r', so that's 4.\n- 'i': not an 'r'\n- 'l': not an 'r'\n\nSo there are 4 'r's in the word 'ferrocarril'.", + }, + ], + }, + { + role: "user", + content: "How many e in what you said?", + }, + ], + }, + }); + + expect(json()).toEqual({ + choices: [ + { + finish_reason: "stop", + index: 0, + logprobs: null, + message: { + content: expect.any(String), + refusal: null, + role: "assistant", + }, + }, + ], + created: expect.any(Number), + id: expect.any(String), + model, + object: "chat.completion", + usage: { + completion_tokens: expect.any(Number), + prompt_tokens: expect.any(Number), + total_tokens: expect.any(Number), + }, + }); + }); + }); +} diff --git a/packages/proxy/src/providers/google.ts b/packages/proxy/src/providers/google.ts index a74b16c1..7446d06d 100644 --- a/packages/proxy/src/providers/google.ts +++ b/packages/proxy/src/providers/google.ts @@ -1,17 +1,28 @@ -import { v4 as uuidv4 } from "uuid"; import { Message } from "@braintrust/core/typespecs"; import { Content, FinishReason, + GenerateContentConfig, + GenerateContentParameters, GenerateContentResponse, - InlineDataPart, + GenerateContentResponseUsageMetadata, Part, -} from "@google/generative-ai"; -import { ChatCompletion, ChatCompletionChunk } from "openai/resources"; -import { getTimestampInSeconds } from ".."; + ThinkingConfig, +} from "@google/genai"; +import { + OpenAIChatCompletion, + OpenAIChatCompletionChoice, + OpenAIChatCompletionChunk, + OpenAIChatCompletionCreateParams, + OpenAICompletionUsage, +} from "@types"; +import { getBudgetMultiplier } from "utils"; +import { cleanOpenAIParams } from "utils/openai"; +import { v4 as uuidv4 } from "uuid"; +import { getTimestampInSeconds } from "../util"; import { convertMediaToBase64 } from "./util"; -async function makeGoogleMediaBlock(media: string): Promise { +async function makeGoogleMediaBlock(media: string): Promise { const { media_type: mimeType, data } = await convertMediaToBase64({ media, allowedMediaTypes: [ @@ -63,6 +74,11 @@ export async function openAIMessagesToGoogleMessages( // First, do a basic mapping const content: Content[] = await Promise.all( messages.map(async (m) => { + const reasoningParts = + "reasoning" in m && m.reasoning + ? m.reasoning.map((r) => ({ text: r.content, thought: true })) + : []; + const contentParts = m.role === "tool" ? [] : await openAIContentToGoogleContent(m.content); const toolCallParts: Part[] = @@ -89,7 +105,12 @@ export async function openAIMessagesToGoogleMessages( ] : []; return { - parts: [...contentParts, ...toolCallParts, ...toolResponseParts], + parts: [ + ...reasoningParts, + ...contentParts, + ...toolCallParts, + ...toolResponseParts, + ], role: m.role === "assistant" ? "model" @@ -102,13 +123,9 @@ export async function openAIMessagesToGoogleMessages( const flattenedContent: Content[] = []; for (let i = 0; i < content.length; i++) { - if ( - flattenedContent.length > 0 && - flattenedContent[flattenedContent.length - 1].role === content[i].role - ) { - flattenedContent[flattenedContent.length - 1].parts = flattenedContent[ - flattenedContent.length - 1 - ].parts.concat(content[i].parts); + const last = flattenedContent[flattenedContent.length - 1]; + if (last && last.role === content[i].role) { + last.parts = [...(last.parts || []), ...(content[i].parts || [])]; } else { flattenedContent.push(content[i]); } @@ -120,9 +137,12 @@ export async function openAIMessagesToGoogleMessages( // 3. Then all user messages' text parts // The EcmaScript spec requires the sort to be stable, so this is safe. const sortedContent: Content[] = flattenedContent.sort((a, b) => { - if (a.parts[0].inlineData && !b.parts[0].inlineData) { + const aFirst = a.parts?.[0]; + const bFirst = b.parts?.[0]; + + if (aFirst?.inlineData && !bFirst?.inlineData) { return -1; - } else if (b.parts[0].inlineData && !a.parts[0].inlineData) { + } else if (bFirst?.inlineData && !aFirst?.inlineData) { return 1; } @@ -140,7 +160,7 @@ export async function openAIMessagesToGoogleMessages( function translateFinishReason( reason?: FinishReason, -): ChatCompletion.Choice["finish_reason"] | null { +): OpenAIChatCompletionChoice["finish_reason"] | null { // "length" | "stop" | "tool_calls" | "content_filter" | "function_call" switch (reason) { case FinishReason.MAX_TOKENS: @@ -162,37 +182,48 @@ function translateFinishReason( default: return null; } + return null; } export function googleEventToOpenAIChatEvent( model: string, data: GenerateContentResponse, -): { event: ChatCompletionChunk | null; finished: boolean } { +): { event: OpenAIChatCompletionChunk | null; finished: boolean } { return { event: data.candidates ? { id: uuidv4(), choices: (data.candidates || []).map((candidate) => { - const firstText = candidate.content.parts.find( - (p) => p.text !== undefined, + const firstThought = candidate.content?.parts?.find( + (part) => part.text !== undefined && part.thought, ); - const toolCalls = candidate.content.parts - .filter((p) => p.functionCall !== undefined) - .map((p, i) => ({ - id: uuidv4(), - type: "function" as const, - function: { - name: p.functionCall.name, - arguments: JSON.stringify(p.functionCall.args), - }, - index: i, - })); + const firstText = candidate.content?.parts?.find( + (part) => part.text !== undefined && !part.thought, + ); + const toolCalls = + candidate.content?.parts + ?.filter((part) => part.functionCall !== undefined) + .map((part, i) => ({ + id: uuidv4(), + type: "function" as const, + function: { + name: part?.functionCall?.name, + arguments: JSON.stringify(part.functionCall?.args), + }, + index: i, + })) || []; return { index: 0, delta: { role: "assistant", content: firstText?.text ?? "", tool_calls: toolCalls.length > 0 ? toolCalls : undefined, + ...(firstThought && { + reasoning: { + id: uuidv4(), + content: firstThought.text, + }, + }), }, finish_reason: toolCalls.length > 0 @@ -203,13 +234,7 @@ export function googleEventToOpenAIChatEvent( created: getTimestampInSeconds(), model, object: "chat.completion.chunk", - usage: data.usageMetadata - ? { - prompt_tokens: data.usageMetadata.promptTokenCount, - completion_tokens: data.usageMetadata.candidatesTokenCount, - total_tokens: data.usageMetadata.totalTokenCount, - } - : undefined, + usage: geminiUsageToOpenAIUsage(data.usageMetadata), } : null, finished: @@ -219,34 +244,64 @@ export function googleEventToOpenAIChatEvent( }; } +const geminiUsageToOpenAIUsage = ( + usageMetadata?: GenerateContentResponseUsageMetadata, +): OpenAICompletionUsage | undefined => { + if (!usageMetadata) { + return undefined; + } + + const thoughtsTokenCount = usageMetadata.thoughtsTokenCount; + const cachedContentTokenCount = usageMetadata.cachedContentTokenCount; + + return { + prompt_tokens: usageMetadata.promptTokenCount || 0, + completion_tokens: usageMetadata.candidatesTokenCount || 0, + total_tokens: usageMetadata.totalTokenCount || 0, + ...(thoughtsTokenCount && { + completion_tokens_details: { reasoning_tokens: thoughtsTokenCount }, + }), + ...(cachedContentTokenCount && { + prompt_tokens_details: { cached_tokens: cachedContentTokenCount }, + }), + }; +}; + export function googleCompletionToOpenAICompletion( model: string, data: GenerateContentResponse, -): ChatCompletion { +): OpenAIChatCompletion { return { id: uuidv4(), choices: (data.candidates || []).map((candidate) => { - const firstText = candidate.content.parts.find( - (p) => p.text !== undefined, + const firstText = candidate.content?.parts?.find( + (part) => part.text !== undefined && !part.thought, ); - const toolCalls = candidate.content.parts - .filter((p) => p.functionCall !== undefined) - .map((p) => ({ - id: uuidv4(), - type: "function" as const, - function: { - name: p.functionCall.name, - arguments: JSON.stringify(p.functionCall.args), - }, - })); + const firstThought = candidate.content?.parts?.find( + (part) => part.text !== undefined && part.thought, + ); + const toolCalls = + candidate.content?.parts + ?.filter((part) => part.functionCall !== undefined) + .map((part) => ({ + id: uuidv4(), + type: "function" as const, + function: { + name: part?.functionCall?.name || "unknown", + arguments: JSON.stringify(part?.functionCall?.args), + }, + })) || []; return { logprobs: null, - index: candidate.index, + index: candidate.index || 0, message: { role: "assistant", content: firstText?.text ?? "", tool_calls: toolCalls.length > 0 ? toolCalls : undefined, refusal: null, + ...(firstThought && { + reasoning: [{ id: uuidv4(), content: firstThought.text }], + }), }, finish_reason: toolCalls.length > 0 @@ -257,13 +312,7 @@ export function googleCompletionToOpenAICompletion( created: getTimestampInSeconds(), model, object: "chat.completion", - usage: data.usageMetadata - ? { - prompt_tokens: data.usageMetadata.promptTokenCount, - completion_tokens: data.usageMetadata.candidatesTokenCount, - total_tokens: data.usageMetadata.totalTokenCount, - } - : undefined, + usage: geminiUsageToOpenAIUsage(data.usageMetadata), }; } @@ -278,3 +327,83 @@ export const OpenAIParamsToGoogleParams: { presence_penalty: null, tool_choice: null, }; + +// because GenAI sdk doesn't provide a convenient API equivalent type +type GeminiGenerateContentParams = Omit & + Omit< + GenerateContentConfig, + | "httpOptions" + | "abortSignal" + | "routingConfig" + | "modelSelectionConfig" + | "labels" + >; + +export const openaiParamsToGeminiMessageParams = ( + openai: OpenAIChatCompletionCreateParams, +): GeminiGenerateContentParams => { + const gemini: GeminiGenerateContentParams = { + // TODO: we depend on translateParams to get us half way there + ...(cleanOpenAIParams(openai) as any), + }; + + const maxTokens = + openai.max_completion_tokens !== undefined || + openai.max_tokens !== undefined + ? Math.max(openai.max_completion_tokens || 0, openai.max_tokens || 0) || + 1024 + : undefined; + + gemini.maxOutputTokens = maxTokens; + + if ( + openai.reasoning_effort !== undefined || + openai.reasoning_budget !== undefined || + openai.reasoning_enabled !== undefined + ) { + gemini.thinkingConfig = getGeminiThinkingParams({ + ...openai, + max_completion_tokens: maxTokens, + }); + } + + return gemini; +}; + +const getGeminiThinkingParams = ( + openai: OpenAIChatCompletionCreateParams & { + max_completion_tokens?: Required; + }, +): ThinkingConfig => { + if (openai.reasoning_enabled === false || openai.reasoning_budget === 0) { + return { + thinkingBudget: 0, + }; + } + + return { + includeThoughts: true, + thinkingBudget: getThinkingBudget(openai), + }; +}; + +const getThinkingBudget = ( + openai: OpenAIChatCompletionCreateParams & { + max_completion_tokens?: Required; + }, +): number => { + if (openai.reasoning_budget !== undefined) { + return openai.reasoning_budget; + } + + let budget = 1024; + + if (openai.reasoning_effort !== undefined) { + budget = Math.floor( + getBudgetMultiplier(openai.reasoning_effort || "low") * + (openai.max_completion_tokens ?? 1024), + ); + } + + return budget; +}; diff --git a/packages/proxy/src/providers/openai.test.ts b/packages/proxy/src/providers/openai.test.ts index 6c0d02d2..cf5a8bcb 100644 --- a/packages/proxy/src/providers/openai.test.ts +++ b/packages/proxy/src/providers/openai.test.ts @@ -1,8 +1,412 @@ -import { describe, test, expect, vi, afterEach } from "vitest"; -import { normalizeOpenAIContent } from "./openai"; +import { + OpenAIChatCompletion, + OpenAIChatCompletionChunk, + OpenAIChatCompletionCreateParams, +} from "@types"; +import { bypass, http, HttpResponse, JsonBodyType } from "msw"; +import { setupServer } from "msw/node"; import { ChatCompletionContentPart } from "openai/resources"; -import * as util from "./util"; +import { + afterAll, + afterEach, + beforeAll, + describe, + expect, + it, + test, + vi, +} from "vitest"; +import { callProxyV1 } from "../../utils/tests"; import * as proxyUtil from "../util"; +import { normalizeOpenAIContent } from "./openai"; +import * as util from "./util"; + +it("should deny reasoning_effort for unsupported models non-streaming", async () => { + const { json } = await callProxyV1< + OpenAIChatCompletionCreateParams, + OpenAIChatCompletionChunk + >({ + body: { + model: "gpt-4o-mini", + reasoning_effort: "high", + messages: [ + { role: "system", content: "You are a helpful assistant." }, + { role: "user", content: "Tell me a short joke about programming." }, + ], + stream: true, + max_tokens: 150, + }, + }); + + expect(json()).toEqual({ + error: { + message: "Unrecognized request argument supplied: reasoning_effort", + type: "invalid_request_error", + param: null, + code: null, + }, + }); +}); + +it("should deny reasoning_effort for unsupported models non-streaming", async () => { + const { json } = await callProxyV1< + OpenAIChatCompletionCreateParams, + OpenAIChatCompletion + >({ + body: { + model: "gpt-4o-mini", + reasoning_effort: "high", + messages: [ + { role: "system", content: "You are a helpful assistant." }, + { role: "user", content: "Tell me a short joke about programming." }, + ], + stream: false, + max_tokens: 150, + }, + }); + + expect(json()).toEqual({ + error: { + message: "Unrecognized request argument supplied: reasoning_effort", + type: "invalid_request_error", + param: null, + code: null, + }, + }); +}); + +it("should accept and return reasoning/thinking params and detail streaming", async () => { + const { events } = await callProxyV1< + OpenAIChatCompletionCreateParams, + OpenAIChatCompletionChunk + >({ + body: { + model: "o3-mini-2025-01-31", + reasoning_effort: "medium", + messages: [ + { + role: "user", + content: "How many rs in 'ferrocarril'", + }, + { + role: "assistant", + content: "There are 4 letter 'r's in the word \"ferrocarril\".", + refusal: null, + reasoning: [ + { + id: "", + content: + "To count the number of 'r's in the word 'ferrocarril', I'll just go through the word letter by letter.\n\n'ferrocarril' has the following letters:\nf-e-r-r-o-c-a-r-r-i-l\n\nLooking at each letter:\n- 'f': not an 'r'\n- 'e': not an 'r'\n- 'r': This is an 'r', so that's 1.\n- 'r': This is an 'r', so that's 2.\n- 'o': not an 'r'\n- 'c': not an 'r'\n- 'a': not an 'r'\n- 'r': This is an 'r', so that's 3.\n- 'r': This is an 'r', so that's 4.\n- 'i': not an 'r'\n- 'l': not an 'r'\n\nSo there are 4 'r's in the word 'ferrocarril'.", + }, + ], + }, + { + role: "user", + content: "How many e in what you said?", + }, + ], + stream: true, + }, + }); + + const streamedEvents = events(); + expect(streamedEvents.length).toBeGreaterThan(0); + + const hasContent = streamedEvents.some( + (event) => event.data.choices[0]?.delta?.content !== undefined, + ); + expect(hasContent).toBe(true); + + const hasReasoning = streamedEvents.some( + (event) => event.data.choices[0]?.delta?.reasoning?.content !== undefined, + ); + expect(hasReasoning).toBe(false); // as of writing, openai is not providing this detail! +}); + +it("should accept and return reasoning/thinking params and detail non-streaming", async () => { + const { json } = await callProxyV1< + OpenAIChatCompletionCreateParams, + OpenAIChatCompletionChunk + >({ + body: { + model: "o3-mini-2025-01-31", + reasoning_effort: "medium", + stream: false, + messages: [ + { + role: "user", + content: "How many rs in 'ferrocarril'", + }, + { + role: "assistant", + content: "There are 4 letter 'r's in the word \"ferrocarril\".", + refusal: null, + reasoning: [ + { + id: "", + content: + "To count the number of 'r's in the word 'ferrocarril', I'll just go through the word letter by letter.\n\n'ferrocarril' has the following letters:\nf-e-r-r-o-c-a-r-r-i-l\n\nLooking at each letter:\n- 'f': not an 'r'\n- 'e': not an 'r'\n- 'r': This is an 'r', so that's 1.\n- 'r': This is an 'r', so that's 2.\n- 'o': not an 'r'\n- 'c': not an 'r'\n- 'a': not an 'r'\n- 'r': This is an 'r', so that's 3.\n- 'r': This is an 'r', so that's 4.\n- 'i': not an 'r'\n- 'l': not an 'r'\n\nSo there are 4 'r's in the word 'ferrocarril'.", + }, + ], + }, + { + role: "user", + content: "How many e in what you said?", + }, + ], + }, + }); + + expect(json()).toEqual({ + choices: [ + { + finish_reason: "stop", + index: 0, + message: { + content: expect.any(String), + // as of writing, openai does not provide this detail + // reasoning: [], + annotations: [], + refusal: null, + role: "assistant", + }, + }, + ], + created: expect.any(Number), + id: expect.any(String), + model: "o3-mini-2025-01-31", + object: "chat.completion", + service_tier: expect.any(String), + system_fingerprint: expect.any(String), + usage: { + completion_tokens: expect.any(Number), + prompt_tokens: expect.any(Number), + total_tokens: expect.any(Number), + completion_tokens_details: { + accepted_prediction_tokens: expect.any(Number), + audio_tokens: expect.any(Number), + reasoning_tokens: expect.any(Number), + rejected_prediction_tokens: expect.any(Number), + }, + prompt_tokens_details: { + audio_tokens: expect.any(Number), + cached_tokens: expect.any(Number), + }, + }, + }); +}); + +type InterceptedRequest = { + method: string; + url: string; + body: JsonBodyType; +}; + +type InterceptedResponse = { + status: number; + body: JsonBodyType; +}; + +type InterceptedCall = { + request: InterceptedRequest; + response: InterceptedResponse; +}; + +describe("request/response checking", () => { + const server = setupServer(); + + beforeAll(() => { + server.listen({ + onUnhandledRequest: () => { + throw new Error("Unexpected request"); + }, + }); + }); + + afterEach(() => { + server.resetHandlers(); + }); + + afterAll(() => { + server.close(); + }); + + it("should fallback to medium if reasoning_effort is missing", async () => { + const calls: InterceptedCall[] = []; + server.use( + http.post( + "https://api.openai.com/v1/chat/completions", + async ({ request: req }) => { + const request: InterceptedRequest = { + method: req.method, + url: req.url, + body: await req.json(), + }; + + const res = await fetch( + bypass( + new Request(req.url, { + method: req.method, + body: JSON.stringify(request.body), + headers: req.headers, + }), + ), + ); + + const response: InterceptedResponse = { + status: res.status, + body: await res.json(), + }; + + calls.push({ request, response }); + + return HttpResponse.json(response.body, { + status: res.status, + headers: res.headers, + }); + }, + ), + ); + + const { json } = await callProxyV1< + OpenAIChatCompletionCreateParams, + OpenAIChatCompletionChunk + >({ + body: { + model: "o3-mini-2025-01-31", + reasoning_effort: null, + stream: false, + messages: [ + { + role: "user", + content: "How many rs in 'ferrocarril'", + }, + { + role: "assistant", + content: "There are 4 letter 'r's in the word \"ferrocarril\".", + refusal: null, + reasoning: [ + { + id: "", + content: + "To count the number of 'r's in the word 'ferrocarril', I'll just go through the word letter by letter.\n\n'ferrocarril' has the following letters:\nf-e-r-r-o-c-a-r-r-i-l\n\nLooking at each letter:\n- 'f': not an 'r'\n- 'e': not an 'r'\n- 'r': This is an 'r', so that's 1.\n- 'r': This is an 'r', so that's 2.\n- 'o': not an 'r'\n- 'c': not an 'r'\n- 'a': not an 'r'\n- 'r': This is an 'r', so that's 3.\n- 'r': This is an 'r', so that's 4.\n- 'i': not an 'r'\n- 'l': not an 'r'\n\nSo there are 4 'r's in the word 'ferrocarril'.", + }, + ], + }, + { + role: "user", + content: "How many e in what you said?", + }, + ], + }, + }); + + expect(json()).toEqual({ + choices: [ + { + finish_reason: "stop", + index: 0, + message: { + content: expect.any(String), + // as of writing, openai does not provide this detail + // reasoning: [], + annotations: [], + refusal: null, + role: "assistant", + }, + }, + ], + created: expect.any(Number), + id: expect.any(String), + model: "o3-mini-2025-01-31", + object: "chat.completion", + service_tier: expect.any(String), + system_fingerprint: expect.any(String), + usage: { + completion_tokens: expect.any(Number), + prompt_tokens: expect.any(Number), + total_tokens: expect.any(Number), + completion_tokens_details: { + accepted_prediction_tokens: expect.any(Number), + audio_tokens: expect.any(Number), + reasoning_tokens: expect.any(Number), + rejected_prediction_tokens: expect.any(Number), + }, + prompt_tokens_details: { + audio_tokens: expect.any(Number), + cached_tokens: expect.any(Number), + }, + }, + }); + + expect(calls).toEqual([ + { + request: { + body: { + reasoning_effort: null, // let openai decide what is the default + messages: [ + { + content: "How many rs in 'ferrocarril'", + role: "user", + }, + { + content: "There are 4 letter 'r's in the word \"ferrocarril\".", + refusal: null, + role: "assistant", + }, + { + content: "How many e in what you said?", + role: "user", + }, + ], + model: "o3-mini-2025-01-31", + stream: false, + }, + method: "POST", + url: "https://api.openai.com/v1/chat/completions", + }, + response: { + body: { + choices: [ + { + finish_reason: "stop", + index: 0, + message: { + annotations: [], + content: expect.any(String), + refusal: null, + role: "assistant", + }, + }, + ], + created: expect.any(Number), + id: expect.any(String), + model: "o3-mini-2025-01-31", + object: "chat.completion", + service_tier: "default", + system_fingerprint: expect.any(String), + usage: { + completion_tokens: expect.any(Number), + completion_tokens_details: { + accepted_prediction_tokens: expect.any(Number), + audio_tokens: expect.any(Number), + reasoning_tokens: expect.any(Number), + rejected_prediction_tokens: expect.any(Number), + }, + prompt_tokens: expect.any(Number), + prompt_tokens_details: { + audio_tokens: expect.any(Number), + cached_tokens: expect.any(Number), + }, + total_tokens: expect.any(Number), + }, + }, + status: 200, + }, + }, + ]); + }); +}); const mockBase64Data = "AF1231KF=="; diff --git a/packages/proxy/src/providers/openai.ts b/packages/proxy/src/providers/openai.ts index 9e41970b..c6edcc63 100644 --- a/packages/proxy/src/providers/openai.ts +++ b/packages/proxy/src/providers/openai.ts @@ -91,6 +91,10 @@ export async function normalizeOpenAIMessages( ), ); } + // not part of the openai spec + if ("reasoning" in message) { + delete message.reasoning; + } return message; }), ); diff --git a/packages/proxy/src/proxy.ts b/packages/proxy/src/proxy.ts index 83ecbdc1..bc0aba3d 100644 --- a/packages/proxy/src/proxy.ts +++ b/packages/proxy/src/proxy.ts @@ -1,58 +1,39 @@ +import { MessageParam } from "@anthropic-ai/sdk/resources"; +import $RefParser from "@apidevtools/json-schema-ref-parser"; +import { _urljoin, ExperimentLogPartialArgs, isArray } from "@braintrust/core"; import { - createParser, - type EventSourceParser, - type ParsedEvent, - type ReconnectInterval, -} from "eventsource-parser"; -import { parse as cacheControlParse } from "cache-control-parser"; + Message, + MessageRole, + responseFormatSchema, +} from "@braintrust/core/typespecs"; +import { Meter, MeterProvider } from "@opentelemetry/api"; import { + APISecret, AvailableModels, - MessageTypeToMessageType, + AzureEntraSecretSchema, + DatabricksOAuthSecretSchema, EndpointProviderToBaseURL, + MessageTypeToMessageType, + modelProviderHasReasoning, + ModelSpec, translateParams, - APISecret, VertexMetadataSchema, - ModelSpec, - AzureEntraSecretSchema, - DatabricksOAuthSecretSchema, } from "@schema"; import { - ModelResponse, - ProxyBadRequestError, - flattenChunks, - flattenChunksArray, - getRandomInt, - isEmpty, - isObject, - parseAuthHeader, - parseNumericHeader, -} from "./util"; -import { - anthropicCompletionToOpenAICompletion, - anthropicEventToOpenAIEvent, - anthropicToolChoiceToOpenAIToolChoice, - flattenAnthropicMessages, - openAIContentToAnthropicContent, - openAIToolCallsToAnthropicToolUse, - openAIToolMessageToAnthropicToolCall, - openAIToolsToAnthropicTools, - upgradeAnthropicContentMessage, -} from "./providers/anthropic"; -import { Meter, MeterProvider } from "@opentelemetry/api"; -import { NOOP_METER_PROVIDER, nowMs } from "./metrics"; -import { - googleCompletionToOpenAICompletion, - googleEventToOpenAIChatEvent, - openAIContentToGoogleContent, - openAIMessagesToGoogleMessages, - OpenAIParamsToGoogleParams, -} from "./providers/google"; + completionUsageSchema, + OpenAIChatCompletionChunk, + OpenAIReasoning, +} from "@types"; +import cacheControlParse from "cache-control-parser"; +import { differenceInSeconds } from "date-fns"; import { - Message, - MessageRole, - responseFormatSchema, -} from "@braintrust/core/typespecs"; -import { _urljoin, isArray } from "@braintrust/core"; + createParser, + type EventSourceParser, + type ParsedEvent, + type ReconnectInterval, +} from "eventsource-parser"; +import { importPKCS8, SignJWT } from "jose"; +import { Buffer } from "node:buffer"; import { ChatCompletion, ChatCompletionChunk, @@ -62,44 +43,68 @@ import { ModerationCreateResponse, } from "openai/resources"; import { + ChatCompletionContentPart, + ChatCompletionCreateParamsBase, + ChatCompletionMessage, + ChatCompletionMessageParam, +} from "openai/resources/chat/completions"; +import { + Response as OpenAIResponse, ResponseCreateParams, ResponseInputContent, ResponseInputItem, - Response as OpenAIResponse, ResponseOutputItem, } from "openai/resources/responses/responses"; -import { - fetchBedrockAnthropic, - fetchBedrockAnthropicMessages, - fetchConverse, -} from "./providers/bedrock"; -import { Buffer } from "node:buffer"; -import { ExperimentLogPartialArgs } from "@braintrust/core"; -import { MessageParam } from "@anthropic-ai/sdk/resources"; import { getCurrentUnixTimestamp, - parseOpenAIStream, isTempCredential, makeTempCredentials, + parseOpenAIStream, verifyTempCredentials, } from "utils"; -import { differenceInSeconds } from "date-fns"; +import { z } from "zod"; +import { NOOP_METER_PROVIDER, nowMs } from "./metrics"; +import { + anthropicCompletionToOpenAICompletion, + anthropicEventToOpenAIEvent, + anthropicToolChoiceToOpenAIToolChoice, + flattenAnthropicMessages, + openAIContentToAnthropicContent, + openAIToolCallsToAnthropicToolUse, + openAIToolMessageToAnthropicToolCall, + openAIToolsToAnthropicTools, + upgradeAnthropicContentMessage, +} from "./providers/anthropic"; +import { getAzureEntraAccessToken } from "./providers/azure"; +import { + fetchBedrockAnthropic, + fetchBedrockAnthropicMessages, + fetchConverse, +} from "./providers/bedrock"; +import { getDatabricksOAuthAccessToken } from "./providers/databricks"; +import { + googleCompletionToOpenAICompletion, + googleEventToOpenAIChatEvent, + openAIContentToGoogleContent, + openAIMessagesToGoogleMessages, + OpenAIParamsToGoogleParams, +} from "./providers/google"; import { makeFakeOpenAIStreamTransformer, normalizeOpenAIMessages, } from "./providers/openai"; import { - ChatCompletionContentPart, - ChatCompletionCreateParamsBase, - ChatCompletionMessage, - ChatCompletionMessageParam, -} from "openai/resources/chat/completions"; -import { importPKCS8, SignJWT } from "jose"; -import { z } from "zod"; -import $RefParser from "@apidevtools/json-schema-ref-parser"; -import { getAzureEntraAccessToken } from "./providers/azure"; -import { getDatabricksOAuthAccessToken } from "./providers/databricks"; -import { completionUsageSchema } from "types"; + flattenChunks, + flattenChunksArray, + getRandomInt, + isEmpty, + isObject, + ModelResponse, + parseAuthHeader, + parseNumericHeader, + ProxyBadRequestError, + writeToReadable, +} from "./util"; type CachedMetadata = { cached_at: Date; @@ -243,7 +248,9 @@ export async function proxyV1({ ), MAX_CACHE_TTL, ); - const cacheControl = cacheControlParse(proxyHeaders["cache-control"] || ""); + const cacheControl = cacheControlParse.parse( + proxyHeaders["cache-control"] || "", + ); const cacheMaxAge = cacheControl?.["max-age"]; const noCache = !!cacheControl?.["no-cache"] || cacheMaxAge === 0; const noStore = !!cacheControl?.["no-store"]; @@ -623,6 +630,7 @@ export async function proxyV1({ const allChunks: Uint8Array[] = []; // These parameters are for the streaming case + let reasoning: OpenAIReasoning[] | undefined = undefined; let role: string | undefined = undefined; let content: string | undefined = undefined; let tool_calls: ChatCompletionChunk.Choice.Delta.ToolCall[] | undefined = @@ -645,7 +653,7 @@ export async function proxyV1({ try { if ("data" in event) { const result = JSON.parse(event.data) as - | ChatCompletionChunk + | OpenAIChatCompletionChunk | undefined; if (result) { const extendedUsage = completionUsageSchema.safeParse( @@ -653,6 +661,7 @@ export async function proxyV1({ ); if (extendedUsage.success) { spanLogger.log({ + // TODO: we should include the proxy meters metrics here metrics: { tokens: extendedUsage.data.total_tokens, prompt_tokens: extendedUsage.data.prompt_tokens, @@ -688,6 +697,22 @@ export async function proxyV1({ content = (content || "") + delta.content; } + if (delta.reasoning) { + if (!reasoning) { + reasoning = [ + { + id: delta.reasoning.id || "", + content: delta.reasoning.content || "", + }, + ]; + } else { + // TODO: could be multiple + reasoning[0].id = reasoning[0].id || delta.reasoning.id; + reasoning[0].content = + reasoning[0].content + (delta.reasoning.content || ""); + } + } + if (delta.tool_calls) { if (!tool_calls) { tool_calls = [ @@ -699,6 +724,7 @@ export async function proxyV1({ }, ]; } else if (tool_calls[0].function) { + // TODO: what about parallel calls? tool_calls[0].function.arguments = (tool_calls[0].function.arguments ?? "") + (delta.tool_calls[0].function?.arguments ?? ""); @@ -744,6 +770,7 @@ export async function proxyV1({ role, content, tool_calls, + reasoning, }, logprobs: null, finish_reason, @@ -910,8 +937,6 @@ async function fetchModelLoop( ttl_seconds?: number, ) => Promise, ): Promise<{ modelResponse: ModelResponse; secretName?: string | null }> { - const requestId = ++loopIndex; - const endpointCalls = meter.createCounter("endpoint_calls"); const endpointFailures = meter.createCounter("endpoint_failures"); const endpointRetryableErrors = meter.createCounter( @@ -936,9 +961,9 @@ async function fetchModelLoop( url === ANTHROPIC_MESSAGES || url === ANTHROPIC_V1_MESSAGES) && isObject(bodyData) && - bodyData.model + bodyData?.model ) { - model = bodyData.model; + model = bodyData?.model; } else if (method === "POST") { const m = url.match(GOOGLE_URL_REGEX); if (m) { @@ -1690,15 +1715,12 @@ async function fetchOpenAI( }); } - // TODO: Ideally this is encapsulated as some advanced per-model config - // or mapping, but for now, let's just map it manually. - const isO1Like = - bodyData.o1_like || - (typeof bodyData.model === "string" && - (bodyData.model.startsWith("o1") || - bodyData.model.startsWith("o3") || - bodyData.model.startsWith("o4"))); - if (isO1Like) { + const hasReasoning = + bodyData?.reasoning || + (typeof bodyData?.model === "string" && + modelProviderHasReasoning.openai?.test(bodyData.model)); + + if (hasReasoning) { if (!isEmpty(bodyData.max_tokens)) { bodyData.max_completion_tokens = bodyData.max_tokens; delete bodyData.max_tokens; @@ -1709,9 +1731,9 @@ async function fetchOpenAI( // Only remove system messages for old O1 models. if ( - bodyData.messages && + bodyData?.messages && ["o1-preview", "o1-mini", "o1-preview-2024-09-12"].includes( - bodyData.model, + bodyData?.model, ) ) { bodyData.messages = bodyData.messages.map((m: any) => ({ @@ -1721,7 +1743,7 @@ async function fetchOpenAI( } } - if (bodyData.messages) { + if (bodyData?.messages) { bodyData.messages = await normalizeOpenAIMessages(bodyData.messages); } @@ -1744,7 +1766,7 @@ async function fetchOpenAI( let isManagedStructuredOutput = false; const responseFormatParsed = responseFormatSchema.safeParse( - bodyData.response_format, + bodyData?.response_format, ); if (responseFormatParsed.success) { switch (responseFormatParsed.data.type) { @@ -1804,7 +1826,7 @@ async function fetchOpenAI( let stream = proxyResponse.body; if (isManagedStructuredOutput && stream) { - if (bodyData.stream) { + if (bodyData?.stream) { stream = stream.pipeThrough( createEventStreamTransformer((data) => { const chunk: ChatCompletionChunk = JSON.parse(data); @@ -2096,9 +2118,20 @@ async function fetchAnthropicChatCompletions({ } else if (m.role === "tool") { role = "user"; content = openAIToolMessageToAnthropicToolCall(m); - } else if (m.role === "assistant" && m.tool_calls) { + } else if (m.role === "assistant") { content = upgradeAnthropicContentMessage(content); - content.push(...openAIToolCallsToAnthropicToolUse(m.tool_calls)); + if (m.tool_calls) { + content.push(...openAIToolCallsToAnthropicToolUse(m.tool_calls)); + } + if (m?.reasoning) { + content.unshift( + ...m?.reasoning.map((r) => ({ + type: "thinking", + thinking: r.content, + signature: r.id, + })), + ); + } } const translatedRole = MessageTypeToMessageType[role]; @@ -2116,10 +2149,14 @@ async function fetchAnthropicChatCompletions({ } messages = flattenAnthropicMessages(messages); - const params: Record = { - max_tokens: 4096, // Required param - ...translateParams("anthropic", oaiParams), - }; + const params: Record = translateParams( + "anthropic", + oaiParams, + ); + + if (!params.max_tokens) { + params.max_tokens = 4096; // Required param + } const stop = z .union([z.string(), z.array(z.string())]) @@ -2893,12 +2930,3 @@ function logSpanInputs( } } } - -export const writeToReadable = (response: string) => { - return new ReadableStream({ - start(controller) { - controller.enqueue(new TextEncoder().encode(response)); - controller.close(); - }, - }); -}; diff --git a/packages/proxy/src/util.ts b/packages/proxy/src/util.ts index 3a2dd5bd..2ee5b460 100644 --- a/packages/proxy/src/util.ts +++ b/packages/proxy/src/util.ts @@ -149,3 +149,12 @@ export function parseFileMetadataFromUrl( return undefined; } } + +export const writeToReadable = (response: string) => { + return new ReadableStream({ + start(controller) { + controller.enqueue(new TextEncoder().encode(response)); + controller.close(); + }, + }); +}; diff --git a/packages/proxy/tsconfig.json b/packages/proxy/tsconfig.json index 68a163da..b739d1e7 100644 --- a/packages/proxy/tsconfig.json +++ b/packages/proxy/tsconfig.json @@ -8,7 +8,9 @@ "baseUrl": ".", "paths": { "@lib/*": ["src/*"], - "@schema": ["schema/index"] + "@schema": ["schema/index"], + "@schema/*": ["schema/*"], + "@types": ["types/index"] }, "resolveJsonModule": true, "esModuleInterop": true diff --git a/packages/proxy/tsup.config.ts b/packages/proxy/tsup.config.ts index 79d8338b..9a2e208e 100644 --- a/packages/proxy/tsup.config.ts +++ b/packages/proxy/tsup.config.ts @@ -25,4 +25,10 @@ export default defineConfig([ outDir: "utils/dist", dts: true, }, + { + entry: ["types/index.ts"], + format: ["cjs", "esm"], + outDir: "types/dist", + dts: true, + }, ]); diff --git a/packages/proxy/types/openai.ts b/packages/proxy/types/openai.ts index 90948536..1dccbcf6 100644 --- a/packages/proxy/types/openai.ts +++ b/packages/proxy/types/openai.ts @@ -1,5 +1,87 @@ +// TODO: move from core +import { chatCompletionMessageParamSchema } from "@braintrust/core/typespecs"; + import { z } from "zod"; +import { + ChatCompletion, + ChatCompletionChunk, + ChatCompletionCreateParams, +} from "openai/resources"; + +export type OpenAIChatCompletionMessage = z.infer< + typeof chatCompletionMessageParamSchema +>; + +export type OpenAIChatCompletionChoice = ChatCompletion.Choice & { + message: OpenAIChatCompletionMessage; +}; + +export type OpenAIChatCompletion = ChatCompletion & { + choices: Array; +}; + +export const chatCompletionMessageReasoningSchema = z + .object({ + id: z + .string() + .nullish() + .transform((x) => x ?? undefined), + content: z + .string() + .nullish() + .transform((x) => x ?? undefined), + }) + .describe( + "Note: This is not part of the OpenAI API spec, but we added it for interoperability with multiple reasoning models.", + ); + +export type OpenAIReasoning = z.infer< + typeof chatCompletionMessageReasoningSchema +>; + +export type OpenAIChatCompletionChunkChoiceDelta = + ChatCompletionChunk.Choice.Delta & { + reasoning?: OpenAIReasoning; + }; + +export type OpenAIChatCompletionChunkChoice = ChatCompletionChunk.Choice & { + delta: OpenAIChatCompletionChunkChoiceDelta; +}; + +export type OpenAIChatCompletionChunk = ChatCompletionChunk & { + choices: Array; +}; + +export type OpenAIChatCompletionCreateParams = ChatCompletionCreateParams & { + messages: Array; + reasoning_enabled?: boolean; + reasoning_budget?: number; +}; + +// overrides +declare module "openai/resources/chat/completions" { + interface ChatCompletionCreateParamsBase { + reasoning_enabled?: boolean; + reasoning_budget?: number; + } + interface ChatCompletionAssistantMessageParam { + reasoning?: OpenAIReasoning[]; + } + namespace ChatCompletion { + interface Choice { + reasoning?: OpenAIReasoning[]; + } + } + namespace ChatCompletionChunk { + namespace Choice { + interface Delta { + reasoning?: OpenAIReasoning; + } + } + } +} + export const completionUsageSchema = z.object({ completion_tokens: z.number(), prompt_tokens: z.number(), @@ -26,4 +108,4 @@ export const completionUsageSchema = z.object({ .optional(), }); -export type CompletionUsage = z.infer; +export type OpenAICompletionUsage = z.infer; diff --git a/packages/proxy/utils/audioEncoder.ts b/packages/proxy/utils/audioEncoder.ts index 87b758a4..9a3663ce 100644 --- a/packages/proxy/utils/audioEncoder.ts +++ b/packages/proxy/utils/audioEncoder.ts @@ -1,4 +1,4 @@ -import { Mp3Bitrate, PcmAudioFormat } from "@schema"; +import { Mp3Bitrate, PcmAudioFormat } from "@schema/audio"; import { Mp3Encoder } from "@breezystack/lamejs"; export function makeWavFile( diff --git a/packages/proxy/utils/deps.test.ts b/packages/proxy/utils/deps.test.ts new file mode 100644 index 00000000..cde1be7b --- /dev/null +++ b/packages/proxy/utils/deps.test.ts @@ -0,0 +1,18 @@ +import skott from "skott"; +import { expect, it } from "vitest"; + +it("no circ dependencies", async () => { + const { useGraph } = await skott({ + entrypoint: `${__dirname}/index.ts`, + tsConfigPath: `${__dirname}/../tsconfig.json`, + dependencyTracking: { + builtin: false, + thirdParty: true, + typeOnly: true, + }, + }); + + const { findCircularDependencies } = useGraph(); + + expect(findCircularDependencies()).toEqual([]); +}); diff --git a/packages/proxy/utils/index.ts b/packages/proxy/utils/index.ts index 7652eee5..587fcfc1 100644 --- a/packages/proxy/utils/index.ts +++ b/packages/proxy/utils/index.ts @@ -16,3 +16,15 @@ export { makeWavFile, makeMp3File } from "./audioEncoder"; export function getCurrentUnixTimestamp(): number { return Date.now() / 1000; } + +export const effortToBudgetMultiplier = { + low: 0.2, + medium: 0.5, + high: 0.8, +} as const; + +export const getBudgetMultiplier = ( + effort: keyof typeof effortToBudgetMultiplier, +) => { + return effortToBudgetMultiplier[effort] || effortToBudgetMultiplier.low; +}; diff --git a/packages/proxy/utils/openai.ts b/packages/proxy/utils/openai.ts index 667b9289..bfc53489 100644 --- a/packages/proxy/utils/openai.ts +++ b/packages/proxy/utils/openai.ts @@ -1,143 +1,9 @@ -// This is copied from the Vercel AI SDK commit bfa1182c7f5379d7a3d81878ea00ec84682cb046 -// We just need the OpenAI parser, but not the streaming code. - -import { CompletionUsage, FunctionCall, trimStartOfStreamHelper } from "ai"; - -// https://github.com/openai/openai-node/blob/07b3504e1c40fd929f4aae1651b83afc19e3baf8/src/resources/chat/completions.ts#L28-L40 -interface ChatCompletionChunk { - id: string; - choices: Array; - created: number; - model: string; - object: string; -} - -// https://github.com/openai/openai-node/blob/07b3504e1c40fd929f4aae1651b83afc19e3baf8/src/resources/chat/completions.ts#L43-L49 -// Updated for https://github.com/openai/openai-node/commit/f10c757d831d90407ba47b4659d9cd34b1a35b1d -// Updated to https://github.com/openai/openai-node/commit/84b43280089eacdf18f171723591856811beddce -interface ChatCompletionChunkChoice { - delta: ChoiceDelta; - finish_reason: - | "stop" - | "length" - | "tool_calls" - | "content_filter" - | "function_call" - | null; - index: number; -} - -// https://github.com/openai/openai-node/blob/07b3504e1c40fd929f4aae1651b83afc19e3baf8/src/resources/chat/completions.ts#L123-L139 -// Updated to https://github.com/openai/openai-node/commit/84b43280089eacdf18f171723591856811beddce -interface ChoiceDelta { - /** - * The contents of the chunk message. - */ - content?: string | null; - - /** - * The name and arguments of a function that should be called, as generated by the - * model. - */ - function_call?: FunctionCall; - - /** - * The role of the author of this message. - */ - role?: "system" | "user" | "assistant" | "tool"; - - tool_calls?: Array; -} - -// From https://github.com/openai/openai-node/blob/master/src/resources/chat/completions.ts -// Updated to https://github.com/openai/openai-node/commit/84b43280089eacdf18f171723591856811beddce -interface DeltaToolCall { - index: number; - - /** - * The ID of the tool call. - */ - id?: string; - - /** - * The function that the model called. - */ - function?: ToolCallFunction; - - /** - * The type of the tool. Currently, only `function` is supported. - */ - type?: "function"; -} - -// From https://github.com/openai/openai-node/blob/master/src/resources/chat/completions.ts -// Updated to https://github.com/openai/openai-node/commit/84b43280089eacdf18f171723591856811beddce -interface ToolCallFunction { - /** - * The arguments to call the function with, as generated by the model in JSON - * format. Note that the model does not always generate valid JSON, and may - * hallucinate parameters not defined by your function schema. Validate the - * arguments in your code before calling your function. - */ - arguments?: string; - - /** - * The name of the function to call. - */ - name?: string; -} - -/** - * https://github.com/openai/openai-node/blob/3ec43ee790a2eb6a0ccdd5f25faa23251b0f9b8e/src/resources/completions.ts#L28C1-L64C1 - * Completions API. Streamed and non-streamed responses are the same. - */ -interface Completion { - /** - * A unique identifier for the completion. - */ - id: string; - - /** - * The list of completion choices the model generated for the input prompt. - */ - choices: Array; - - /** - * The Unix timestamp of when the completion was created. - */ - created: number; - - /** - * The model used for completion. - */ - model: string; - - /** - * The object type, which is always "text_completion" - */ - object: string; - - /** - * Usage statistics for the completion request. - */ - usage?: CompletionUsage; -} - -interface CompletionChoice { - /** - * The reason the model stopped generating tokens. This will be `stop` if the model - * hit a natural stop point or a provided stop sequence, or `length` if the maximum - * number of tokens specified in the request was reached. - */ - finish_reason: "stop" | "length" | "content_filter"; - - index: number; - - // edited: Removed CompletionChoice.logProbs and replaced with any - logprobs: any | null; - - text: string; -} +import { + OpenAIChatCompletionChunk, + OpenAIChatCompletionCreateParams, +} from "@types"; +import { trimStartOfStreamHelper } from "ai"; +import { ChatCompletionCreateParams, Completion } from "openai/resources"; /** * Creates a parser function for processing the OpenAI stream data. @@ -219,7 +85,7 @@ const __internal__OpenAIFnMessagesSymbol = Symbol( type AzureChatCompletions = any; type AsyncIterableOpenAIStreamReturnTypes = - | AsyncIterable + | AsyncIterable | AsyncIterable | AsyncIterable; @@ -230,7 +96,7 @@ type OpenAIStreamReturnTypes = export function isChatCompletionChunk( data: unknown, -): data is ChatCompletionChunk { +): data is OpenAIChatCompletionChunk { if (!data || typeof data !== "object") { return false; } @@ -255,3 +121,18 @@ export function isCompletion(data: unknown): data is Completion { "text" in data.choices[0] ); } + +/** + * Cleans the OpenAI parameters by removing extra braintrust fields. + * + * @param {OpenAIChatCompletionCreateParams} params - The OpenAI parameters to clean. + * @returns {ChatCompletionCreateParams} - The cleaned OpenAI parameters. + */ +export function cleanOpenAIParams({ + reasoning_effort, + reasoning_budget, + reasoning_enabled, + ...openai +}: OpenAIChatCompletionCreateParams): ChatCompletionCreateParams { + return openai; +} diff --git a/packages/proxy/utils/tempCredentials.ts b/packages/proxy/utils/tempCredentials.ts index b597079e..5f854ac1 100644 --- a/packages/proxy/utils/tempCredentials.ts +++ b/packages/proxy/utils/tempCredentials.ts @@ -5,14 +5,10 @@ import { tempCredentialJwtPayloadSchema, TempCredentialsCacheValue, tempCredentialsCacheValueSchema, -} from "../schema"; +} from "@schema/secrets"; import { v4 as uuidv4 } from "uuid"; import { arrayBufferToBase64 } from "./encrypt"; -import { - sign as jwtSign, - verify as jwtVerify, - decode as jwtDecode, -} from "jsonwebtoken"; +import jsonwebtoken from "jsonwebtoken"; import { isEmpty } from "@lib/util"; const JWT_ALGORITHM = "HS256"; @@ -81,7 +77,7 @@ export function makeTempCredentialsJwt({ logging: request.logging ?? undefined, }, }; - const jwt = jwtSign(jwtPayload, authToken, { + const jwt = jsonwebtoken.sign(jwtPayload, authToken, { expiresIn: request.ttl_seconds, mutatePayload: true, algorithm: JWT_ALGORITHM, @@ -177,7 +173,7 @@ export function isTempCredential(jwt: string): boolean { .pick({ iss: true }) .or(tempCredentialJwtPayloadSchema.pick({ aud: true })); return looseJwtPayloadSchema.safeParse( - jwtDecode(jwt, { complete: false, json: true }), + jsonwebtoken.decode(jwt, { complete: false, json: true }), ).success; } @@ -195,7 +191,7 @@ export function verifyJwtOnly({ jwt: string; credentialCacheValue: TempCredentialsCacheValue; }): void { - jwtVerify(jwt, credentialCacheValue.authToken, { + jsonwebtoken.verify(jwt, credentialCacheValue.authToken, { algorithms: [JWT_ALGORITHM], }); } @@ -225,7 +221,10 @@ export async function verifyTempCredentials({ cacheGet: (encryptionKey: string, key: string) => Promise; }): Promise { // Decode, but do not verify, just to get the ID and encryption key. - const jwtPayloadRaw = jwtDecode(jwt, { complete: false, json: true }); + const jwtPayloadRaw = jsonwebtoken.decode(jwt, { + complete: false, + json: true, + }); if (isEmpty(jwtPayloadRaw)) { throw new Error("Could not parse JWT format"); } diff --git a/packages/proxy/utils/tests.ts b/packages/proxy/utils/tests.ts new file mode 100644 index 00000000..2006af9f --- /dev/null +++ b/packages/proxy/utils/tests.ts @@ -0,0 +1,192 @@ +/* eslint-disable turbo/no-undeclared-env-vars */ + +import { TextDecoder } from "util"; +import { Buffer } from "node:buffer"; +import { proxyV1 } from "../src/proxy"; +import { getModelEndpointTypes } from "@schema"; +import { createParser, ParsedEvent, ParseEvent } from "eventsource-parser"; + +export function createResponseStream(): [ + WritableStream, + Promise, +] { + const chunks: Uint8Array[] = []; + let resolveChunks: (chunks: Uint8Array[]) => void; + let rejectChunks: (error: Error) => void; + + const chunksPromise = new Promise((resolve, reject) => { + resolveChunks = resolve; + rejectChunks = reject; + }); + + const writableStream = new WritableStream({ + write(chunk) { + chunks.push(chunk); + }, + close() { + resolveChunks(chunks); + }, + abort(reason) { + rejectChunks(new Error(`Stream aborted: ${reason}`)); + }, + }); + + return [writableStream, chunksPromise]; +} + +export function createHeaderHandlers() { + const headers: Record = {}; + let statusCode = 200; + + const setHeader = (name: string, value: string) => { + headers[name] = value; + }; + + const setStatusCode = (code: number) => { + statusCode = code; + }; + + return { headers, statusCode, setHeader, setStatusCode }; +} + +export const getKnownApiSecrets: Parameters< + typeof proxyV1 +>[0]["getApiSecrets"] = async ( + useCache: boolean, + authToken: string, + model: string | null, +) => { + const endpointTypes = model && getModelEndpointTypes(model); + if (!endpointTypes?.length) throw new Error(`Unknown model: ${model}`); + + return [ + { + type: "anthropic" as const, + secret: process.env.ANTHROPIC_API_KEY || "", + name: "anthropic", + }, + { + type: "google" as const, + secret: process.env.GEMINI_API_KEY || "", + name: "google", + }, + { + type: "openai" as const, + secret: process.env.OPENAI_API_KEY || "", + name: "openai", + }, + { + type: "vertex" as const, + secret: process.env.VERTEX_AI_API_KEY || "", + name: "vertex", + metadata: { + project: process.env.GCP_PROJECT_ID || "", + authType: "access_token" as const, + api_base: "", + supportsStreaming: true, + excludeDefaultModels: false, + }, + }, + { + type: "bedrock" as const, + secret: process.env.AWS_SECRET_ACCESS_KEY || "", + name: "bedrock" as const, + metadata: { + region: process.env.AWS_REGION || "", + access_key: process.env.AWS_ACCESS_KEY_ID || "", + session_token: process.env.AWS_SESSION_TOKEN || "", + supportsStreaming: true, + excludeDefaultModels: false, + }, + }, + ].filter((secret) => !!secret.secret && endpointTypes.includes(secret.type)); +}; + +export async function callProxyV1({ + body, + ...request +}: Partial, "body">> & { + body: Input; +}) { + const [writableStream, chunksPromise] = createResponseStream(); + const { headers, statusCode, setHeader, setStatusCode } = + createHeaderHandlers(); + + let timeoutId: NodeJS.Timeout | null = null; + const timeoutPromise = new Promise((_, reject) => { + timeoutId = setTimeout(() => { + reject(new Error(`Request timed out after 30s`)); + }, 30000); + }); + + try { + const requestBody = typeof body === "string" ? body : JSON.stringify(body); + + const proxyPromise = proxyV1({ + method: "POST", + url: "/chat/completions", + proxyHeaders: { + "content-type": "application/json", + authorization: `Bearer dummy-token`, + }, + setHeader, + setStatusCode, + res: writableStream, + getApiSecrets: getKnownApiSecrets, + cacheGet: async () => null, + cachePut: async () => {}, + digest: async (message: string) => + Buffer.from(message).toString("base64"), + ...request, + body: requestBody, + }); + + await proxyPromise; + + const chunks = await Promise.race([chunksPromise, timeoutPromise]); + const responseText = new TextDecoder().decode(Buffer.concat(chunks)); + + return { + chunks, + headers, + statusCode, + responseText, + events() { + return chucksToEvents(chunks); + }, + json() { + try { + return JSON.parse(responseText) as Output; + } catch (e) { + return null; + } + }, + }; + } catch (error) { + throw error; + } finally { + if (timeoutId) { + clearTimeout(timeoutId); + } + } +} + +const chucksToEvents = (chunks: Uint8Array[]) => { + const textDecoder = new TextDecoder(); + const results: (Omit & { data: ChunkData })[] = []; + + const parser = createParser((event) => { + if (event.type === "event" && event.data !== "[DONE]") { + results.push({ + ...event, + data: JSON.parse(event.data) as ChunkData, + }); + } + }); + + for (const chunk of chunks) { + parser.feed(textDecoder.decode(chunk)); + } + + return results; +}; diff --git a/packages/proxy/vitest.config.js b/packages/proxy/vitest.config.js index fed4d6c0..d38e8f1c 100644 --- a/packages/proxy/vitest.config.js +++ b/packages/proxy/vitest.config.js @@ -4,6 +4,7 @@ const config = { plugins: [tsconfigPaths()], test: { exclude: ["**/node_modules/**"], + testTimeout: 30_000, }, }; export default config; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f050a8a4..ee0513a2 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -22,10 +22,10 @@ importers: version: 2.3.3 vite-tsconfig-paths: specifier: ^4.3.2 - version: 4.3.2 + version: 4.3.2(typescript@5.5.4) vitest: specifier: ^2.1.9 - version: 2.1.9 + version: 2.1.9(@types/node@20.10.5)(msw@2.8.4) apis/cloudflare: dependencies: @@ -204,17 +204,17 @@ importers: specifier: ^11.9.1 version: 11.9.1 '@aws-sdk/client-bedrock-runtime': - specifier: ^3.738.0 - version: 3.738.0 + specifier: ^3.806.0 + version: 3.817.0 '@braintrust/core': - specifier: ^0.0.85 - version: 0.0.85 + specifier: ^0.0.87 + version: 0.0.87 '@breezystack/lamejs': specifier: ^1.2.7 version: 1.2.7 - '@google/generative-ai': - specifier: ^0.24.0 - version: 0.24.0 + '@google/genai': + specifier: ^0.13.0 + version: 0.13.0 '@opentelemetry/api': specifier: ^1.7.0 version: 1.7.0 @@ -279,9 +279,15 @@ importers: esbuild: specifier: ^0.19.10 version: 0.19.10 + msw: + specifier: ^2.8.2 + version: 2.8.4(@types/node@20.10.5)(typescript@5.5.4) npm-run-all: specifier: ^4.1.5 version: 4.1.5 + skott: + specifier: ^0.35.4 + version: 0.35.4 tsup: specifier: ^8.4.0 version: 8.4.0(typescript@5.5.4) @@ -293,7 +299,7 @@ importers: version: 4.3.2(typescript@5.5.4) vitest: specifier: ^2.1.9 - version: 2.1.9(@types/node@20.10.5) + version: 2.1.9(@types/node@20.10.5)(msw@2.8.4) yargs: specifier: ^17.7.2 version: 17.7.2 @@ -451,6 +457,11 @@ packages: js-yaml: 4.1.0 dev: false + /@arr/every@1.0.1: + resolution: {integrity: sha512-UQFQ6SgyJ6LX42W8rHCs8KVc0JS0tzVL9ct4XYedJukskYVWTo49tNiMEK9C2HTyarbNiT/RVIRSY82vH+6sTg==} + engines: {node: '>=4'} + dev: true + /@asteasolutions/zod-to-openapi@6.4.0(zod@3.22.4): resolution: {integrity: sha512-8cxfF7AHHx2PqnN4Cd8/O8CBu/nVYJP9DpnfVLW3BFb66VJDnqI/CczZnkqMc3SNh6J9GiX7JbJ5T4BSP4HZ2Q==} peerDependencies: @@ -465,7 +476,7 @@ packages: engines: {node: '>=16.0.0'} dependencies: '@aws-crypto/util': 5.2.0 - '@aws-sdk/types': 3.734.0 + '@aws-sdk/types': 3.804.0 tslib: 2.6.2 dev: false @@ -475,7 +486,7 @@ packages: '@aws-crypto/sha256-js': 5.2.0 '@aws-crypto/supports-web-crypto': 5.2.0 '@aws-crypto/util': 5.2.0 - '@aws-sdk/types': 3.734.0 + '@aws-sdk/types': 3.804.0 '@aws-sdk/util-locate-window': 3.535.0 '@smithy/util-utf8': 2.3.0 tslib: 2.6.2 @@ -486,7 +497,7 @@ packages: engines: {node: '>=16.0.0'} dependencies: '@aws-crypto/util': 5.2.0 - '@aws-sdk/types': 3.734.0 + '@aws-sdk/types': 3.804.0 tslib: 2.6.2 dev: false @@ -499,56 +510,58 @@ packages: /@aws-crypto/util@5.2.0: resolution: {integrity: sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==} dependencies: - '@aws-sdk/types': 3.734.0 + '@aws-sdk/types': 3.804.0 '@smithy/util-utf8': 2.3.0 tslib: 2.6.2 dev: false - /@aws-sdk/client-bedrock-runtime@3.738.0: - resolution: {integrity: sha512-RBFk+THc/qY8ZgKem6OsqnwnOoQcpms8JC8euKfJjWO8UB5nQvUDZCH4GxjnXKOtpNWnZ6eg2fCaKpKflYyfgQ==} + /@aws-sdk/client-bedrock-runtime@3.817.0: + resolution: {integrity: sha512-fG3QAjIEq7P0a134E2P8r4qw/V6rL0X5voUPIcXte1oNKUXUjNXJb21N/NGmcDLCUVWvYXb24dD0YXyQ2kwZdA==} engines: {node: '>=18.0.0'} dependencies: '@aws-crypto/sha256-browser': 5.2.0 '@aws-crypto/sha256-js': 5.2.0 - '@aws-sdk/core': 3.734.0 - '@aws-sdk/credential-provider-node': 3.738.0 - '@aws-sdk/middleware-host-header': 3.734.0 - '@aws-sdk/middleware-logger': 3.734.0 - '@aws-sdk/middleware-recursion-detection': 3.734.0 - '@aws-sdk/middleware-user-agent': 3.734.0 - '@aws-sdk/region-config-resolver': 3.734.0 - '@aws-sdk/types': 3.734.0 - '@aws-sdk/util-endpoints': 3.734.0 - '@aws-sdk/util-user-agent-browser': 3.734.0 - '@aws-sdk/util-user-agent-node': 3.734.0 - '@smithy/config-resolver': 4.0.1 - '@smithy/core': 3.1.2 - '@smithy/eventstream-serde-browser': 4.0.1 - '@smithy/eventstream-serde-config-resolver': 4.0.1 - '@smithy/eventstream-serde-node': 4.0.1 - '@smithy/fetch-http-handler': 5.0.1 - '@smithy/hash-node': 4.0.1 - '@smithy/invalid-dependency': 4.0.1 - '@smithy/middleware-content-length': 4.0.1 - '@smithy/middleware-endpoint': 4.0.3 - '@smithy/middleware-retry': 4.0.4 - '@smithy/middleware-serde': 4.0.2 - '@smithy/middleware-stack': 4.0.1 - '@smithy/node-config-provider': 4.0.1 - '@smithy/node-http-handler': 4.0.2 - '@smithy/protocol-http': 5.0.1 - '@smithy/smithy-client': 4.1.3 - '@smithy/types': 4.1.0 - '@smithy/url-parser': 4.0.1 + '@aws-sdk/core': 3.816.0 + '@aws-sdk/credential-provider-node': 3.817.0 + '@aws-sdk/eventstream-handler-node': 3.804.0 + '@aws-sdk/middleware-eventstream': 3.804.0 + '@aws-sdk/middleware-host-header': 3.804.0 + '@aws-sdk/middleware-logger': 3.804.0 + '@aws-sdk/middleware-recursion-detection': 3.804.0 + '@aws-sdk/middleware-user-agent': 3.816.0 + '@aws-sdk/region-config-resolver': 3.808.0 + '@aws-sdk/types': 3.804.0 + '@aws-sdk/util-endpoints': 3.808.0 + '@aws-sdk/util-user-agent-browser': 3.804.0 + '@aws-sdk/util-user-agent-node': 3.816.0 + '@smithy/config-resolver': 4.1.3 + '@smithy/core': 3.4.0 + '@smithy/eventstream-serde-browser': 4.0.3 + '@smithy/eventstream-serde-config-resolver': 4.1.1 + '@smithy/eventstream-serde-node': 4.0.3 + '@smithy/fetch-http-handler': 5.0.3 + '@smithy/hash-node': 4.0.3 + '@smithy/invalid-dependency': 4.0.3 + '@smithy/middleware-content-length': 4.0.3 + '@smithy/middleware-endpoint': 4.1.7 + '@smithy/middleware-retry': 4.1.8 + '@smithy/middleware-serde': 4.0.6 + '@smithy/middleware-stack': 4.0.3 + '@smithy/node-config-provider': 4.1.2 + '@smithy/node-http-handler': 4.0.5 + '@smithy/protocol-http': 5.1.1 + '@smithy/smithy-client': 4.3.0 + '@smithy/types': 4.3.0 + '@smithy/url-parser': 4.0.3 '@smithy/util-base64': 4.0.0 '@smithy/util-body-length-browser': 4.0.0 '@smithy/util-body-length-node': 4.0.0 - '@smithy/util-defaults-mode-browser': 4.0.4 - '@smithy/util-defaults-mode-node': 4.0.4 - '@smithy/util-endpoints': 3.0.1 - '@smithy/util-middleware': 4.0.1 - '@smithy/util-retry': 4.0.1 - '@smithy/util-stream': 4.0.2 + '@smithy/util-defaults-mode-browser': 4.0.15 + '@smithy/util-defaults-mode-node': 4.0.15 + '@smithy/util-endpoints': 3.0.5 + '@smithy/util-middleware': 4.0.3 + '@smithy/util-retry': 4.0.4 + '@smithy/util-stream': 4.2.1 '@smithy/util-utf8': 4.0.0 '@types/uuid': 9.0.7 tslib: 2.6.2 @@ -557,308 +570,329 @@ packages: - aws-crt dev: false - /@aws-sdk/client-sso@3.734.0: - resolution: {integrity: sha512-oerepp0mut9VlgTwnG5Ds/lb0C0b2/rQ+hL/rF6q+HGKPfGsCuPvFx1GtwGKCXd49ase88/jVgrhcA9OQbz3kg==} + /@aws-sdk/client-sso@3.817.0: + resolution: {integrity: sha512-fCh5rUHmWmWDvw70NNoWpE5+BRdtNi45kDnIoeoszqVg7UKF79SlG+qYooUT52HKCgDNHqgbWaXxMOSqd2I/OQ==} engines: {node: '>=18.0.0'} dependencies: '@aws-crypto/sha256-browser': 5.2.0 '@aws-crypto/sha256-js': 5.2.0 - '@aws-sdk/core': 3.734.0 - '@aws-sdk/middleware-host-header': 3.734.0 - '@aws-sdk/middleware-logger': 3.734.0 - '@aws-sdk/middleware-recursion-detection': 3.734.0 - '@aws-sdk/middleware-user-agent': 3.734.0 - '@aws-sdk/region-config-resolver': 3.734.0 - '@aws-sdk/types': 3.734.0 - '@aws-sdk/util-endpoints': 3.734.0 - '@aws-sdk/util-user-agent-browser': 3.734.0 - '@aws-sdk/util-user-agent-node': 3.734.0 - '@smithy/config-resolver': 4.0.1 - '@smithy/core': 3.1.2 - '@smithy/fetch-http-handler': 5.0.1 - '@smithy/hash-node': 4.0.1 - '@smithy/invalid-dependency': 4.0.1 - '@smithy/middleware-content-length': 4.0.1 - '@smithy/middleware-endpoint': 4.0.3 - '@smithy/middleware-retry': 4.0.4 - '@smithy/middleware-serde': 4.0.2 - '@smithy/middleware-stack': 4.0.1 - '@smithy/node-config-provider': 4.0.1 - '@smithy/node-http-handler': 4.0.2 - '@smithy/protocol-http': 5.0.1 - '@smithy/smithy-client': 4.1.3 - '@smithy/types': 4.1.0 - '@smithy/url-parser': 4.0.1 + '@aws-sdk/core': 3.816.0 + '@aws-sdk/middleware-host-header': 3.804.0 + '@aws-sdk/middleware-logger': 3.804.0 + '@aws-sdk/middleware-recursion-detection': 3.804.0 + '@aws-sdk/middleware-user-agent': 3.816.0 + '@aws-sdk/region-config-resolver': 3.808.0 + '@aws-sdk/types': 3.804.0 + '@aws-sdk/util-endpoints': 3.808.0 + '@aws-sdk/util-user-agent-browser': 3.804.0 + '@aws-sdk/util-user-agent-node': 3.816.0 + '@smithy/config-resolver': 4.1.3 + '@smithy/core': 3.4.0 + '@smithy/fetch-http-handler': 5.0.3 + '@smithy/hash-node': 4.0.3 + '@smithy/invalid-dependency': 4.0.3 + '@smithy/middleware-content-length': 4.0.3 + '@smithy/middleware-endpoint': 4.1.7 + '@smithy/middleware-retry': 4.1.8 + '@smithy/middleware-serde': 4.0.6 + '@smithy/middleware-stack': 4.0.3 + '@smithy/node-config-provider': 4.1.2 + '@smithy/node-http-handler': 4.0.5 + '@smithy/protocol-http': 5.1.1 + '@smithy/smithy-client': 4.3.0 + '@smithy/types': 4.3.0 + '@smithy/url-parser': 4.0.3 '@smithy/util-base64': 4.0.0 '@smithy/util-body-length-browser': 4.0.0 '@smithy/util-body-length-node': 4.0.0 - '@smithy/util-defaults-mode-browser': 4.0.4 - '@smithy/util-defaults-mode-node': 4.0.4 - '@smithy/util-endpoints': 3.0.1 - '@smithy/util-middleware': 4.0.1 - '@smithy/util-retry': 4.0.1 + '@smithy/util-defaults-mode-browser': 4.0.15 + '@smithy/util-defaults-mode-node': 4.0.15 + '@smithy/util-endpoints': 3.0.5 + '@smithy/util-middleware': 4.0.3 + '@smithy/util-retry': 4.0.4 '@smithy/util-utf8': 4.0.0 tslib: 2.6.2 transitivePeerDependencies: - aws-crt dev: false - /@aws-sdk/core@3.734.0: - resolution: {integrity: sha512-SxnDqf3vobdm50OLyAKfqZetv6zzwnSqwIwd3jrbopxxHKqNIM/I0xcYjD6Tn+mPig+u7iRKb9q3QnEooFTlmg==} + /@aws-sdk/core@3.816.0: + resolution: {integrity: sha512-Lx50wjtyarzKpMFV6V+gjbSZDgsA/71iyifbClGUSiNPoIQ4OCV0KVOmAAj7mQRVvGJqUMWKVM+WzK79CjbjWA==} engines: {node: '>=18.0.0'} dependencies: - '@aws-sdk/types': 3.734.0 - '@smithy/core': 3.1.2 - '@smithy/node-config-provider': 4.0.1 - '@smithy/property-provider': 4.0.1 - '@smithy/protocol-http': 5.0.1 - '@smithy/signature-v4': 5.0.1 - '@smithy/smithy-client': 4.1.3 - '@smithy/types': 4.1.0 - '@smithy/util-middleware': 4.0.1 + '@aws-sdk/types': 3.804.0 + '@smithy/core': 3.4.0 + '@smithy/node-config-provider': 4.1.2 + '@smithy/property-provider': 4.0.3 + '@smithy/protocol-http': 5.1.1 + '@smithy/signature-v4': 5.1.1 + '@smithy/smithy-client': 4.3.0 + '@smithy/types': 4.3.0 + '@smithy/util-middleware': 4.0.3 fast-xml-parser: 4.4.1 tslib: 2.6.2 dev: false - /@aws-sdk/credential-provider-env@3.734.0: - resolution: {integrity: sha512-gtRkzYTGafnm1FPpiNO8VBmJrYMoxhDlGPYDVcijzx3DlF8dhWnowuSBCxLSi+MJMx5hvwrX2A+e/q0QAeHqmw==} + /@aws-sdk/credential-provider-env@3.816.0: + resolution: {integrity: sha512-wUJZwRLe+SxPxRV9AENYBLrJZRrNIo+fva7ZzejsC83iz7hdfq6Rv6B/aHEdPwG/nQC4+q7UUvcRPlomyrpsBA==} engines: {node: '>=18.0.0'} dependencies: - '@aws-sdk/core': 3.734.0 - '@aws-sdk/types': 3.734.0 - '@smithy/property-provider': 4.0.1 - '@smithy/types': 4.1.0 + '@aws-sdk/core': 3.816.0 + '@aws-sdk/types': 3.804.0 + '@smithy/property-provider': 4.0.3 + '@smithy/types': 4.3.0 tslib: 2.6.2 dev: false - /@aws-sdk/credential-provider-http@3.734.0: - resolution: {integrity: sha512-JFSL6xhONsq+hKM8xroIPhM5/FOhiQ1cov0lZxhzZWj6Ai3UAjucy3zyIFDr9MgP1KfCYNdvyaUq9/o+HWvEDg==} + /@aws-sdk/credential-provider-http@3.816.0: + resolution: {integrity: sha512-gcWGzMQ7yRIF+ljTkR8Vzp7727UY6cmeaPrFQrvcFB8PhOqWpf7g0JsgOf5BSaP8CkkSQcTQHc0C5ZYAzUFwPg==} engines: {node: '>=18.0.0'} dependencies: - '@aws-sdk/core': 3.734.0 - '@aws-sdk/types': 3.734.0 - '@smithy/fetch-http-handler': 5.0.1 - '@smithy/node-http-handler': 4.0.2 - '@smithy/property-provider': 4.0.1 - '@smithy/protocol-http': 5.0.1 - '@smithy/smithy-client': 4.1.3 - '@smithy/types': 4.1.0 - '@smithy/util-stream': 4.0.2 + '@aws-sdk/core': 3.816.0 + '@aws-sdk/types': 3.804.0 + '@smithy/fetch-http-handler': 5.0.3 + '@smithy/node-http-handler': 4.0.5 + '@smithy/property-provider': 4.0.3 + '@smithy/protocol-http': 5.1.1 + '@smithy/smithy-client': 4.3.0 + '@smithy/types': 4.3.0 + '@smithy/util-stream': 4.2.1 tslib: 2.6.2 dev: false - /@aws-sdk/credential-provider-ini@3.734.0: - resolution: {integrity: sha512-HEyaM/hWI7dNmb4NhdlcDLcgJvrilk8G4DQX6qz0i4pBZGC2l4iffuqP8K6ZQjUfz5/6894PzeFuhTORAMd+cg==} + /@aws-sdk/credential-provider-ini@3.817.0: + resolution: {integrity: sha512-kyEwbQyuXE+phWVzloMdkFv6qM6NOon+asMXY5W0fhDKwBz9zQLObDRWBrvQX9lmqq8BbDL1sCfZjOh82Y+RFw==} engines: {node: '>=18.0.0'} dependencies: - '@aws-sdk/core': 3.734.0 - '@aws-sdk/credential-provider-env': 3.734.0 - '@aws-sdk/credential-provider-http': 3.734.0 - '@aws-sdk/credential-provider-process': 3.734.0 - '@aws-sdk/credential-provider-sso': 3.734.0 - '@aws-sdk/credential-provider-web-identity': 3.734.0 - '@aws-sdk/nested-clients': 3.734.0 - '@aws-sdk/types': 3.734.0 - '@smithy/credential-provider-imds': 4.0.1 - '@smithy/property-provider': 4.0.1 - '@smithy/shared-ini-file-loader': 4.0.1 - '@smithy/types': 4.1.0 + '@aws-sdk/core': 3.816.0 + '@aws-sdk/credential-provider-env': 3.816.0 + '@aws-sdk/credential-provider-http': 3.816.0 + '@aws-sdk/credential-provider-process': 3.816.0 + '@aws-sdk/credential-provider-sso': 3.817.0 + '@aws-sdk/credential-provider-web-identity': 3.817.0 + '@aws-sdk/nested-clients': 3.817.0 + '@aws-sdk/types': 3.804.0 + '@smithy/credential-provider-imds': 4.0.5 + '@smithy/property-provider': 4.0.3 + '@smithy/shared-ini-file-loader': 4.0.3 + '@smithy/types': 4.3.0 tslib: 2.6.2 transitivePeerDependencies: - aws-crt dev: false - /@aws-sdk/credential-provider-node@3.738.0: - resolution: {integrity: sha512-3MuREsazwBxghKb2sQQHvie+uuK4dX4/ckFYiSoffzJQd0YHxaGxf8cr4NOSCQCUesWu8D3Y0SzlnHGboVSkpA==} + /@aws-sdk/credential-provider-node@3.817.0: + resolution: {integrity: sha512-b5mz7av0Lhavs1Bz3Zb+jrs0Pki93+8XNctnVO0drBW98x1fM4AR38cWvGbM/w9F9Q0/WEH3TinkmrMPrP4T/w==} engines: {node: '>=18.0.0'} dependencies: - '@aws-sdk/credential-provider-env': 3.734.0 - '@aws-sdk/credential-provider-http': 3.734.0 - '@aws-sdk/credential-provider-ini': 3.734.0 - '@aws-sdk/credential-provider-process': 3.734.0 - '@aws-sdk/credential-provider-sso': 3.734.0 - '@aws-sdk/credential-provider-web-identity': 3.734.0 - '@aws-sdk/types': 3.734.0 - '@smithy/credential-provider-imds': 4.0.1 - '@smithy/property-provider': 4.0.1 - '@smithy/shared-ini-file-loader': 4.0.1 - '@smithy/types': 4.1.0 + '@aws-sdk/credential-provider-env': 3.816.0 + '@aws-sdk/credential-provider-http': 3.816.0 + '@aws-sdk/credential-provider-ini': 3.817.0 + '@aws-sdk/credential-provider-process': 3.816.0 + '@aws-sdk/credential-provider-sso': 3.817.0 + '@aws-sdk/credential-provider-web-identity': 3.817.0 + '@aws-sdk/types': 3.804.0 + '@smithy/credential-provider-imds': 4.0.5 + '@smithy/property-provider': 4.0.3 + '@smithy/shared-ini-file-loader': 4.0.3 + '@smithy/types': 4.3.0 tslib: 2.6.2 transitivePeerDependencies: - aws-crt dev: false - /@aws-sdk/credential-provider-process@3.734.0: - resolution: {integrity: sha512-zvjsUo+bkYn2vjT+EtLWu3eD6me+uun+Hws1IyWej/fKFAqiBPwyeyCgU7qjkiPQSXqk1U9+/HG9IQ6Iiz+eBw==} + /@aws-sdk/credential-provider-process@3.816.0: + resolution: {integrity: sha512-9Tm+AxMoV2Izvl5b9tyMQRbBwaex8JP06HN7ZeCXgC5sAsSN+o8dsThnEhf8jKN+uBpT6CLWKN1TXuUMrAmW1A==} engines: {node: '>=18.0.0'} dependencies: - '@aws-sdk/core': 3.734.0 - '@aws-sdk/types': 3.734.0 - '@smithy/property-provider': 4.0.1 - '@smithy/shared-ini-file-loader': 4.0.1 - '@smithy/types': 4.1.0 + '@aws-sdk/core': 3.816.0 + '@aws-sdk/types': 3.804.0 + '@smithy/property-provider': 4.0.3 + '@smithy/shared-ini-file-loader': 4.0.3 + '@smithy/types': 4.3.0 tslib: 2.6.2 dev: false - /@aws-sdk/credential-provider-sso@3.734.0: - resolution: {integrity: sha512-cCwwcgUBJOsV/ddyh1OGb4gKYWEaTeTsqaAK19hiNINfYV/DO9r4RMlnWAo84sSBfJuj9shUNsxzyoe6K7R92Q==} + /@aws-sdk/credential-provider-sso@3.817.0: + resolution: {integrity: sha512-gFUAW3VmGvdnueK1bh6TOcRX+j99Xm0men1+gz3cA4RE+rZGNy1Qjj8YHlv0hPwI9OnTPZquvPzA5fkviGREWg==} engines: {node: '>=18.0.0'} dependencies: - '@aws-sdk/client-sso': 3.734.0 - '@aws-sdk/core': 3.734.0 - '@aws-sdk/token-providers': 3.734.0 - '@aws-sdk/types': 3.734.0 - '@smithy/property-provider': 4.0.1 - '@smithy/shared-ini-file-loader': 4.0.1 - '@smithy/types': 4.1.0 + '@aws-sdk/client-sso': 3.817.0 + '@aws-sdk/core': 3.816.0 + '@aws-sdk/token-providers': 3.817.0 + '@aws-sdk/types': 3.804.0 + '@smithy/property-provider': 4.0.3 + '@smithy/shared-ini-file-loader': 4.0.3 + '@smithy/types': 4.3.0 tslib: 2.6.2 transitivePeerDependencies: - aws-crt dev: false - /@aws-sdk/credential-provider-web-identity@3.734.0: - resolution: {integrity: sha512-t4OSOerc+ppK541/Iyn1AS40+2vT/qE+MFMotFkhCgCJbApeRF2ozEdnDN6tGmnl4ybcUuxnp9JWLjwDVlR/4g==} + /@aws-sdk/credential-provider-web-identity@3.817.0: + resolution: {integrity: sha512-A2kgkS9g6NY0OMT2f2EdXHpL17Ym81NhbGnQ8bRXPqESIi7TFypFD2U6osB2VnsFv+MhwM+Ke4PKXSmLun22/A==} engines: {node: '>=18.0.0'} dependencies: - '@aws-sdk/core': 3.734.0 - '@aws-sdk/nested-clients': 3.734.0 - '@aws-sdk/types': 3.734.0 - '@smithy/property-provider': 4.0.1 - '@smithy/types': 4.1.0 + '@aws-sdk/core': 3.816.0 + '@aws-sdk/nested-clients': 3.817.0 + '@aws-sdk/types': 3.804.0 + '@smithy/property-provider': 4.0.3 + '@smithy/types': 4.3.0 tslib: 2.6.2 transitivePeerDependencies: - aws-crt dev: false - /@aws-sdk/middleware-host-header@3.734.0: - resolution: {integrity: sha512-LW7RRgSOHHBzWZnigNsDIzu3AiwtjeI2X66v+Wn1P1u+eXssy1+up4ZY/h+t2sU4LU36UvEf+jrZti9c6vRnFw==} + /@aws-sdk/eventstream-handler-node@3.804.0: + resolution: {integrity: sha512-LZddQVBUCB86tZtLJRhqiDyIqr4hfRxZCcUp1fZSfpBMcf419lgcFRGWMR3J/kCWHQ0G05aor7fSeoeaxskuNQ==} + engines: {node: '>=18.0.0'} + dependencies: + '@aws-sdk/types': 3.804.0 + '@smithy/eventstream-codec': 4.0.3 + '@smithy/types': 4.3.0 + tslib: 2.6.2 + dev: false + + /@aws-sdk/middleware-eventstream@3.804.0: + resolution: {integrity: sha512-3lPxZshOJoKSxIMUq8FCiIre+FZ1g/t+O7DHwOMB6EuzJ8lp5QyUeh1wE5iD/gB8VhWZoj90rGIaWCmT8ccEuA==} + engines: {node: '>=18.0.0'} + dependencies: + '@aws-sdk/types': 3.804.0 + '@smithy/protocol-http': 5.1.1 + '@smithy/types': 4.3.0 + tslib: 2.6.2 + dev: false + + /@aws-sdk/middleware-host-header@3.804.0: + resolution: {integrity: sha512-bum1hLVBrn2lJCi423Z2fMUYtsbkGI2s4N+2RI2WSjvbaVyMSv/WcejIrjkqiiMR+2Y7m5exgoKeg4/TODLDPQ==} engines: {node: '>=18.0.0'} dependencies: - '@aws-sdk/types': 3.734.0 - '@smithy/protocol-http': 5.0.1 - '@smithy/types': 4.1.0 + '@aws-sdk/types': 3.804.0 + '@smithy/protocol-http': 5.1.1 + '@smithy/types': 4.3.0 tslib: 2.6.2 dev: false - /@aws-sdk/middleware-logger@3.734.0: - resolution: {integrity: sha512-mUMFITpJUW3LcKvFok176eI5zXAUomVtahb9IQBwLzkqFYOrMJvWAvoV4yuxrJ8TlQBG8gyEnkb9SnhZvjg67w==} + /@aws-sdk/middleware-logger@3.804.0: + resolution: {integrity: sha512-w/qLwL3iq0KOPQNat0Kb7sKndl9BtceigINwBU7SpkYWX9L/Lem6f8NPEKrC9Tl4wDBht3Yztub4oRTy/horJA==} engines: {node: '>=18.0.0'} dependencies: - '@aws-sdk/types': 3.734.0 - '@smithy/types': 4.1.0 + '@aws-sdk/types': 3.804.0 + '@smithy/types': 4.3.0 tslib: 2.6.2 dev: false - /@aws-sdk/middleware-recursion-detection@3.734.0: - resolution: {integrity: sha512-CUat2d9ITsFc2XsmeiRQO96iWpxSKYFjxvj27Hc7vo87YUHRnfMfnc8jw1EpxEwMcvBD7LsRa6vDNky6AjcrFA==} + /@aws-sdk/middleware-recursion-detection@3.804.0: + resolution: {integrity: sha512-zqHOrvLRdsUdN/ehYfZ9Tf8svhbiLLz5VaWUz22YndFv6m9qaAcijkpAOlKexsv3nLBMJdSdJ6GUTAeIy3BZzw==} engines: {node: '>=18.0.0'} dependencies: - '@aws-sdk/types': 3.734.0 - '@smithy/protocol-http': 5.0.1 - '@smithy/types': 4.1.0 + '@aws-sdk/types': 3.804.0 + '@smithy/protocol-http': 5.1.1 + '@smithy/types': 4.3.0 tslib: 2.6.2 dev: false - /@aws-sdk/middleware-user-agent@3.734.0: - resolution: {integrity: sha512-MFVzLWRkfFz02GqGPjqSOteLe5kPfElUrXZft1eElnqulqs6RJfVSpOV7mO90gu293tNAeggMWAVSGRPKIYVMg==} + /@aws-sdk/middleware-user-agent@3.816.0: + resolution: {integrity: sha512-bHRSlWZ0xDsFR8E2FwDb//0Ff6wMkVx4O+UKsfyNlAbtqCiiHRt5ANNfKPafr95cN2CCxLxiPvFTFVblQM5TsQ==} engines: {node: '>=18.0.0'} dependencies: - '@aws-sdk/core': 3.734.0 - '@aws-sdk/types': 3.734.0 - '@aws-sdk/util-endpoints': 3.734.0 - '@smithy/core': 3.1.2 - '@smithy/protocol-http': 5.0.1 - '@smithy/types': 4.1.0 + '@aws-sdk/core': 3.816.0 + '@aws-sdk/types': 3.804.0 + '@aws-sdk/util-endpoints': 3.808.0 + '@smithy/core': 3.4.0 + '@smithy/protocol-http': 5.1.1 + '@smithy/types': 4.3.0 tslib: 2.6.2 dev: false - /@aws-sdk/nested-clients@3.734.0: - resolution: {integrity: sha512-iph2XUy8UzIfdJFWo1r0Zng9uWj3253yvW9gljhtu+y/LNmNvSnJxQk1f3D2BC5WmcoPZqTS3UsycT3mLPSzWA==} + /@aws-sdk/nested-clients@3.817.0: + resolution: {integrity: sha512-vQ2E06A48STJFssueJQgxYD8lh1iGJoLJnHdshRDWOQb8gy1wVQR+a7MkPGhGR6lGoS0SCnF/Qp6CZhnwLsqsQ==} engines: {node: '>=18.0.0'} dependencies: '@aws-crypto/sha256-browser': 5.2.0 '@aws-crypto/sha256-js': 5.2.0 - '@aws-sdk/core': 3.734.0 - '@aws-sdk/middleware-host-header': 3.734.0 - '@aws-sdk/middleware-logger': 3.734.0 - '@aws-sdk/middleware-recursion-detection': 3.734.0 - '@aws-sdk/middleware-user-agent': 3.734.0 - '@aws-sdk/region-config-resolver': 3.734.0 - '@aws-sdk/types': 3.734.0 - '@aws-sdk/util-endpoints': 3.734.0 - '@aws-sdk/util-user-agent-browser': 3.734.0 - '@aws-sdk/util-user-agent-node': 3.734.0 - '@smithy/config-resolver': 4.0.1 - '@smithy/core': 3.1.2 - '@smithy/fetch-http-handler': 5.0.1 - '@smithy/hash-node': 4.0.1 - '@smithy/invalid-dependency': 4.0.1 - '@smithy/middleware-content-length': 4.0.1 - '@smithy/middleware-endpoint': 4.0.3 - '@smithy/middleware-retry': 4.0.4 - '@smithy/middleware-serde': 4.0.2 - '@smithy/middleware-stack': 4.0.1 - '@smithy/node-config-provider': 4.0.1 - '@smithy/node-http-handler': 4.0.2 - '@smithy/protocol-http': 5.0.1 - '@smithy/smithy-client': 4.1.3 - '@smithy/types': 4.1.0 - '@smithy/url-parser': 4.0.1 + '@aws-sdk/core': 3.816.0 + '@aws-sdk/middleware-host-header': 3.804.0 + '@aws-sdk/middleware-logger': 3.804.0 + '@aws-sdk/middleware-recursion-detection': 3.804.0 + '@aws-sdk/middleware-user-agent': 3.816.0 + '@aws-sdk/region-config-resolver': 3.808.0 + '@aws-sdk/types': 3.804.0 + '@aws-sdk/util-endpoints': 3.808.0 + '@aws-sdk/util-user-agent-browser': 3.804.0 + '@aws-sdk/util-user-agent-node': 3.816.0 + '@smithy/config-resolver': 4.1.3 + '@smithy/core': 3.4.0 + '@smithy/fetch-http-handler': 5.0.3 + '@smithy/hash-node': 4.0.3 + '@smithy/invalid-dependency': 4.0.3 + '@smithy/middleware-content-length': 4.0.3 + '@smithy/middleware-endpoint': 4.1.7 + '@smithy/middleware-retry': 4.1.8 + '@smithy/middleware-serde': 4.0.6 + '@smithy/middleware-stack': 4.0.3 + '@smithy/node-config-provider': 4.1.2 + '@smithy/node-http-handler': 4.0.5 + '@smithy/protocol-http': 5.1.1 + '@smithy/smithy-client': 4.3.0 + '@smithy/types': 4.3.0 + '@smithy/url-parser': 4.0.3 '@smithy/util-base64': 4.0.0 '@smithy/util-body-length-browser': 4.0.0 '@smithy/util-body-length-node': 4.0.0 - '@smithy/util-defaults-mode-browser': 4.0.4 - '@smithy/util-defaults-mode-node': 4.0.4 - '@smithy/util-endpoints': 3.0.1 - '@smithy/util-middleware': 4.0.1 - '@smithy/util-retry': 4.0.1 + '@smithy/util-defaults-mode-browser': 4.0.15 + '@smithy/util-defaults-mode-node': 4.0.15 + '@smithy/util-endpoints': 3.0.5 + '@smithy/util-middleware': 4.0.3 + '@smithy/util-retry': 4.0.4 '@smithy/util-utf8': 4.0.0 tslib: 2.6.2 transitivePeerDependencies: - aws-crt dev: false - /@aws-sdk/region-config-resolver@3.734.0: - resolution: {integrity: sha512-Lvj1kPRC5IuJBr9DyJ9T9/plkh+EfKLy+12s/mykOy1JaKHDpvj+XGy2YO6YgYVOb8JFtaqloid+5COtje4JTQ==} + /@aws-sdk/region-config-resolver@3.808.0: + resolution: {integrity: sha512-9x2QWfphkARZY5OGkl9dJxZlSlYM2l5inFeo2bKntGuwg4A4YUe5h7d5yJ6sZbam9h43eBrkOdumx03DAkQF9A==} engines: {node: '>=18.0.0'} dependencies: - '@aws-sdk/types': 3.734.0 - '@smithy/node-config-provider': 4.0.1 - '@smithy/types': 4.1.0 + '@aws-sdk/types': 3.804.0 + '@smithy/node-config-provider': 4.1.2 + '@smithy/types': 4.3.0 '@smithy/util-config-provider': 4.0.0 - '@smithy/util-middleware': 4.0.1 + '@smithy/util-middleware': 4.0.3 tslib: 2.6.2 dev: false - /@aws-sdk/token-providers@3.734.0: - resolution: {integrity: sha512-2U6yWKrjWjZO8Y5SHQxkFvMVWHQWbS0ufqfAIBROqmIZNubOL7jXCiVdEFekz6MZ9LF2tvYGnOW4jX8OKDGfIw==} + /@aws-sdk/token-providers@3.817.0: + resolution: {integrity: sha512-CYN4/UO0VaqyHf46ogZzNrVX7jI3/CfiuktwKlwtpKA6hjf2+ivfgHSKzPpgPBcSEfiibA/26EeLuMnB6cpSrQ==} engines: {node: '>=18.0.0'} dependencies: - '@aws-sdk/nested-clients': 3.734.0 - '@aws-sdk/types': 3.734.0 - '@smithy/property-provider': 4.0.1 - '@smithy/shared-ini-file-loader': 4.0.1 - '@smithy/types': 4.1.0 + '@aws-sdk/core': 3.816.0 + '@aws-sdk/nested-clients': 3.817.0 + '@aws-sdk/types': 3.804.0 + '@smithy/property-provider': 4.0.3 + '@smithy/shared-ini-file-loader': 4.0.3 + '@smithy/types': 4.3.0 tslib: 2.6.2 transitivePeerDependencies: - aws-crt dev: false - /@aws-sdk/types@3.734.0: - resolution: {integrity: sha512-o11tSPTT70nAkGV1fN9wm/hAIiLPyWX6SuGf+9JyTp7S/rC2cFWhR26MvA69nplcjNaXVzB0f+QFrLXXjOqCrg==} + /@aws-sdk/types@3.804.0: + resolution: {integrity: sha512-A9qnsy9zQ8G89vrPPlNG9d1d8QcKRGqJKqwyGgS0dclJpwy6d1EWgQLIolKPl6vcFpLoe6avLOLxr+h8ur5wpg==} engines: {node: '>=18.0.0'} dependencies: - '@smithy/types': 4.1.0 + '@smithy/types': 4.3.0 tslib: 2.6.2 dev: false - /@aws-sdk/util-endpoints@3.734.0: - resolution: {integrity: sha512-w2+/E88NUbqql6uCVAsmMxDQKu7vsKV0KqhlQb0lL+RCq4zy07yXYptVNs13qrnuTfyX7uPXkXrlugvK9R1Ucg==} + /@aws-sdk/util-endpoints@3.808.0: + resolution: {integrity: sha512-N6Lic98uc4ADB7fLWlzx+1uVnq04VgVjngZvwHoujcRg9YDhIg9dUDiTzD5VZv13g1BrPYmvYP1HhsildpGV6w==} engines: {node: '>=18.0.0'} dependencies: - '@aws-sdk/types': 3.734.0 - '@smithy/types': 4.1.0 - '@smithy/util-endpoints': 3.0.1 + '@aws-sdk/types': 3.804.0 + '@smithy/types': 4.3.0 + '@smithy/util-endpoints': 3.0.5 tslib: 2.6.2 dev: false @@ -869,17 +903,17 @@ packages: tslib: 2.6.2 dev: false - /@aws-sdk/util-user-agent-browser@3.734.0: - resolution: {integrity: sha512-xQTCus6Q9LwUuALW+S76OL0jcWtMOVu14q+GoLnWPUM7QeUw963oQcLhF7oq0CtaLLKyl4GOUfcwc773Zmwwng==} + /@aws-sdk/util-user-agent-browser@3.804.0: + resolution: {integrity: sha512-KfW6T6nQHHM/vZBBdGn6fMyG/MgX5lq82TDdX4HRQRRuHKLgBWGpKXqqvBwqIaCdXwWHgDrg2VQups6GqOWW2A==} dependencies: - '@aws-sdk/types': 3.734.0 - '@smithy/types': 4.1.0 + '@aws-sdk/types': 3.804.0 + '@smithy/types': 4.3.0 bowser: 2.11.0 tslib: 2.6.2 dev: false - /@aws-sdk/util-user-agent-node@3.734.0: - resolution: {integrity: sha512-c6Iinh+RVQKs6jYUFQ64htOU2HUXFQ3TVx+8Tu3EDF19+9vzWi9UukhIMH9rqyyEXIAkk9XL7avt8y2Uyw2dGA==} + /@aws-sdk/util-user-agent-node@3.816.0: + resolution: {integrity: sha512-Q6dxmuj4hL7pudhrneWEQ7yVHIQRBFr0wqKLF1opwOi1cIePuoEbPyJ2jkel6PDEv1YMfvsAKaRshp6eNA8VHg==} engines: {node: '>=18.0.0'} peerDependencies: aws-crt: '>=1.0.0' @@ -887,22 +921,40 @@ packages: aws-crt: optional: true dependencies: - '@aws-sdk/middleware-user-agent': 3.734.0 - '@aws-sdk/types': 3.734.0 - '@smithy/node-config-provider': 4.0.1 - '@smithy/types': 4.1.0 + '@aws-sdk/middleware-user-agent': 3.816.0 + '@aws-sdk/types': 3.804.0 + '@smithy/node-config-provider': 4.1.2 + '@smithy/types': 4.3.0 tslib: 2.6.2 dev: false + /@babel/code-frame@7.27.1: + resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-validator-identifier': 7.27.1 + js-tokens: 4.0.0 + picocolors: 1.1.1 + dev: true + + /@babel/generator@7.27.1: + resolution: {integrity: sha512-UnJfnIpc/+JO0/+KRVQNGU+y5taA5vCbwN8+azkX6beii/ZF+enZJSOKo11ZSzGJjlNfJHfQtmQT8H+9TXPG2w==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/parser': 7.27.1 + '@babel/types': 7.27.1 + '@jridgewell/gen-mapping': 0.3.8 + '@jridgewell/trace-mapping': 0.3.25 + jsesc: 3.1.0 + dev: true + /@babel/helper-string-parser@7.27.1: resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} engines: {node: '>=6.9.0'} - dev: false /@babel/helper-validator-identifier@7.27.1: resolution: {integrity: sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==} engines: {node: '>=6.9.0'} - dev: false /@babel/parser@7.27.1: resolution: {integrity: sha512-I0dZ3ZpCrJ1c04OqlNsQcKiZlsrXf/kkE4FXzID9rIOYICsAbA8mMDzhW/luRNAHdCNt7os/u8wenklZDlUVUQ==} @@ -910,7 +962,14 @@ packages: hasBin: true dependencies: '@babel/types': 7.27.1 - dev: false + + /@babel/parser@7.27.2: + resolution: {integrity: sha512-QYLs8299NA7WM/bZAdp+CviYYkVoYXlDW2rzliy3chxd1PQjej7JORuMJDJXJUb9g0TT+B99EwaVLKmX+sPXWw==} + engines: {node: '>=6.0.0'} + hasBin: true + dependencies: + '@babel/types': 7.27.1 + dev: true /@babel/runtime@7.23.6: resolution: {integrity: sha512-zHd0eUrf5GZoOWVCXp6koAKQTfZV07eit6bGPmJgnZdnSAvvZee6zniW2XMF7Cmc4ISOOnPy3QaSiIJGJkVEDQ==} @@ -919,13 +978,36 @@ packages: regenerator-runtime: 0.14.1 dev: true + /@babel/template@7.27.2: + resolution: {integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/code-frame': 7.27.1 + '@babel/parser': 7.27.2 + '@babel/types': 7.27.1 + dev: true + + /@babel/traverse@7.27.1: + resolution: {integrity: sha512-ZCYtZciz1IWJB4U61UPu4KEaqyfj+r5T1Q5mqPo+IBpcG9kHv30Z0aD8LXPgC1trYa6rK0orRyAhqUgk4MjmEg==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/code-frame': 7.27.1 + '@babel/generator': 7.27.1 + '@babel/parser': 7.27.1 + '@babel/template': 7.27.2 + '@babel/types': 7.27.1 + debug: 4.4.0 + globals: 11.12.0 + transitivePeerDependencies: + - supports-color + dev: true + /@babel/types@7.27.1: resolution: {integrity: sha512-+EzkxvLNfiUeKMgy/3luqfsCWFRXLb7U6wNQTk60tovuckwB15B191tJWvpp4HjiQWdJkCxO3Wbvc6jlk3Xb2Q==} engines: {node: '>=6.9.0'} dependencies: '@babel/helper-string-parser': 7.27.1 '@babel/helper-validator-identifier': 7.27.1 - dev: false /@braintrust/core@0.0.84: resolution: {integrity: sha512-LByhkZ6ueKk5wFo1kuWwOjIw21mmkHNzOX8NRbPMISbRId26H8mWbShGa6UtM7+mS0KrIgQhy13vpa0tt69Gvg==} @@ -943,10 +1025,37 @@ packages: zod: 3.22.4 dev: false + /@braintrust/core@0.0.87: + resolution: {integrity: sha512-yKo+2McKBcluVUq+5qoYI7QfGvqZ7c0ftTOmnRSToBR2RqGyHkClnnQZ3+M8Guuk9NEKJu92UMTTaR9AonIvvA==} + dependencies: + '@asteasolutions/zod-to-openapi': 6.4.0(zod@3.22.4) + uuid: 9.0.1 + zod: 3.22.4 + dev: false + /@breezystack/lamejs@1.2.7: resolution: {integrity: sha512-6wc7ck65ctA75Hq7FYHTtTvGnYs6msgdxiSUICQ+A01nVOWg6rqouZB8IdyteRlfpYYiFovkf67dIeOgWIUzTA==} dev: false + /@bundled-es-modules/cookie@2.0.1: + resolution: {integrity: sha512-8o+5fRPLNbjbdGRRmJj3h6Hh1AQJf2dk3qQ/5ZFb+PXkRNiSoMGGUKlsgLfrxneb72axVJyIYji64E2+nNfYyw==} + dependencies: + cookie: 0.7.2 + dev: true + + /@bundled-es-modules/statuses@1.0.1: + resolution: {integrity: sha512-yn7BklA5acgcBr+7w064fGV+SGIFySjCKpqjcWgBAIfrAkY+4GQTJJHQMeT3V/sgz23VTEVV8TtOmkvJAhFVfg==} + dependencies: + statuses: 2.0.1 + dev: true + + /@bundled-es-modules/tough-cookie@0.1.6: + resolution: {integrity: sha512-dvMHbL464C0zI+Yqxbz6kZ5TOEp7GLW+pry/RWndAR8MJQAXZ2rPmIs8tziTZjeIyhSNZgZbCePtfSbdWqStJw==} + dependencies: + '@types/tough-cookie': 4.0.5 + tough-cookie: 4.1.4 + dev: true + /@cloudflare/kv-asset-handler@0.3.4: resolution: {integrity: sha512-YLPHc8yASwjNkmcDMQMY35yiWjoKAKnhUbPRszBRS0YgH+IXtsMp61j+yTcnCE3oO2DgP0U3iejLC8FTtKDC8Q==} engines: {node: '>=16.13'} @@ -2139,9 +2248,19 @@ packages: engines: {node: '>=14'} dev: true - /@google/generative-ai@0.24.0: - resolution: {integrity: sha512-fnEITCGEB7NdX0BhoYZ/cq/7WPZ1QS5IzJJfC3Tg/OwkvBetMiVJciyaan297OvE4B9Jg1xvo0zIazX/9sGu1Q==} + /@google/genai@0.13.0: + resolution: {integrity: sha512-eaEncWt875H7046T04mOpxpHJUM+jLIljEf+5QctRyOeChylE/nhpwm1bZWTRWoOu/t46R9r+PmgsJFhTpE7tQ==} engines: {node: '>=18.0.0'} + dependencies: + google-auth-library: 9.15.1 + ws: 8.18.0 + zod: 3.22.4 + zod-to-json-schema: 3.23.5(zod@3.22.4) + transitivePeerDependencies: + - bufferutil + - encoding + - supports-color + - utf-8-validate dev: false /@humanwhocodes/config-array@0.11.13: @@ -2183,6 +2302,57 @@ packages: deprecated: Use @eslint/object-schema instead dev: true + /@inquirer/confirm@5.1.12(@types/node@20.10.5): + resolution: {integrity: sha512-dpq+ielV9/bqgXRUbNH//KsY6WEw9DrGPmipkpmgC1Y46cwuBTNx7PXFWTjc3MQ+urcc0QxoVHcMI0FW4Ok0hg==} + engines: {node: '>=18'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + dependencies: + '@inquirer/core': 10.1.13(@types/node@20.10.5) + '@inquirer/type': 3.0.7(@types/node@20.10.5) + '@types/node': 20.10.5 + dev: true + + /@inquirer/core@10.1.13(@types/node@20.10.5): + resolution: {integrity: sha512-1viSxebkYN2nJULlzCxES6G9/stgHSepZ9LqqfdIGPHj5OHhiBUXVS0a6R0bEC2A+VL4D9w6QB66ebCr6HGllA==} + engines: {node: '>=18'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + dependencies: + '@inquirer/figures': 1.0.12 + '@inquirer/type': 3.0.7(@types/node@20.10.5) + '@types/node': 20.10.5 + ansi-escapes: 4.3.2 + cli-width: 4.1.0 + mute-stream: 2.0.0 + signal-exit: 4.1.0 + wrap-ansi: 6.2.0 + yoctocolors-cjs: 2.1.2 + dev: true + + /@inquirer/figures@1.0.12: + resolution: {integrity: sha512-MJttijd8rMFcKJC8NYmprWr6hD3r9Gd9qUC0XwPNwoEPWSMVJwA2MlXxF+nhZZNMY+HXsWa+o7KY2emWYIn0jQ==} + engines: {node: '>=18'} + dev: true + + /@inquirer/type@3.0.7(@types/node@20.10.5): + resolution: {integrity: sha512-PfunHQcjwnju84L+ycmcMKB/pTPIngjUJvfnRhKY6FKPuYXlM4aQCb/nIdTFR6BEhMjFvngzvng/vBAJMZpLSA==} + engines: {node: '>=18'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + dependencies: + '@types/node': 20.10.5 + dev: true + /@isaacs/cliui@8.0.2: resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} engines: {node: '>=12'} @@ -2243,6 +2413,18 @@ packages: resolution: {integrity: sha512-GaHYm+c0O9MjZRu0ongGBRbinu8gVAMd2UZjji6jVmqKtZluZnptXGWhz1E8j8D2HJ3f/yMxKAUC0b+57wncIw==} dev: false + /@mswjs/interceptors@0.37.6: + resolution: {integrity: sha512-wK+5pLK5XFmgtH3aQ2YVvA3HohS3xqV/OxuVOdNx9Wpnz7VE/fnC+e1A7ln6LFYeck7gOJ/dsZV6OLplOtAJ2w==} + engines: {node: '>=18'} + dependencies: + '@open-draft/deferred-promise': 2.2.0 + '@open-draft/logger': 0.3.0 + '@open-draft/until': 2.1.0 + is-node-process: 1.2.0 + outvariant: 1.4.3 + strict-event-emitter: 0.5.1 + dev: true + /@next/env@14.2.3: resolution: {integrity: sha512-W7fd7IbkfmeeY2gXrzJYDx8D2lWKbVoTIj1o1ScPHNzvp30s1AuoEFSdr39bC5sjxJaxTtq3OTCZboNp0lNWHA==} dev: false @@ -2355,6 +2537,21 @@ packages: fastq: 1.15.0 dev: true + /@open-draft/deferred-promise@2.2.0: + resolution: {integrity: sha512-CecwLWx3rhxVQF6V4bAgPS5t+So2sTbPgAzafKkVizyi7tlwpcFpdFqq+wqF2OwNBmqFuu6tOyouTuxgpMfzmA==} + dev: true + + /@open-draft/logger@0.3.0: + resolution: {integrity: sha512-X2g45fzhxH238HKO4xbSr7+wBS8Fvw6ixhTDuvLd5mqh6bJJCFAPwU9mPDxbcrRtfxv4u5IHCEH77BmxvXmmxQ==} + dependencies: + is-node-process: 1.2.0 + outvariant: 1.4.3 + dev: true + + /@open-draft/until@2.1.0: + resolution: {integrity: sha512-U69T3ItWHvLwGg5eJ0n3I62nWuE6ilHlmz7zM0npLBRvPRd7e6NYmg54vvRtP5mZG7kZqZCFVdsTWo7BPtBujg==} + dev: true + /@opentelemetry/api@1.7.0: resolution: {integrity: sha512-AdY5wvN0P2vXBi3b29hxZgSFvdhdxPB9+f0B6s//P9Q8nibRWeA3cHm8UmLpio9ABigkVHJ5NMPk+Mz8VCCyrw==} engines: {node: '>=8.0.0'} @@ -2403,6 +2600,148 @@ packages: engines: {node: '>=14'} dev: false + /@parcel/watcher-android-arm64@2.5.1: + resolution: {integrity: sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@parcel/watcher-darwin-arm64@2.5.1: + resolution: {integrity: sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /@parcel/watcher-darwin-x64@2.5.1: + resolution: {integrity: sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /@parcel/watcher-freebsd-x64@2.5.1: + resolution: {integrity: sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + + /@parcel/watcher-linux-arm-glibc@2.5.1: + resolution: {integrity: sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA==} + engines: {node: '>= 10.0.0'} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@parcel/watcher-linux-arm-musl@2.5.1: + resolution: {integrity: sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==} + engines: {node: '>= 10.0.0'} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@parcel/watcher-linux-arm64-glibc@2.5.1: + resolution: {integrity: sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@parcel/watcher-linux-arm64-musl@2.5.1: + resolution: {integrity: sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@parcel/watcher-linux-x64-glibc@2.5.1: + resolution: {integrity: sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@parcel/watcher-linux-x64-musl@2.5.1: + resolution: {integrity: sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@parcel/watcher-win32-arm64@2.5.1: + resolution: {integrity: sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@parcel/watcher-win32-ia32@2.5.1: + resolution: {integrity: sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ==} + engines: {node: '>= 10.0.0'} + cpu: [ia32] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@parcel/watcher-win32-x64@2.5.1: + resolution: {integrity: sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@parcel/watcher@2.5.1: + resolution: {integrity: sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==} + engines: {node: '>= 10.0.0'} + requiresBuild: true + dependencies: + detect-libc: 1.0.3 + is-glob: 4.0.3 + micromatch: 4.0.8 + node-addon-api: 7.1.1 + optionalDependencies: + '@parcel/watcher-android-arm64': 2.5.1 + '@parcel/watcher-darwin-arm64': 2.5.1 + '@parcel/watcher-darwin-x64': 2.5.1 + '@parcel/watcher-freebsd-x64': 2.5.1 + '@parcel/watcher-linux-arm-glibc': 2.5.1 + '@parcel/watcher-linux-arm-musl': 2.5.1 + '@parcel/watcher-linux-arm64-glibc': 2.5.1 + '@parcel/watcher-linux-arm64-musl': 2.5.1 + '@parcel/watcher-linux-x64-glibc': 2.5.1 + '@parcel/watcher-linux-x64-musl': 2.5.1 + '@parcel/watcher-win32-arm64': 2.5.1 + '@parcel/watcher-win32-ia32': 2.5.1 + '@parcel/watcher-win32-x64': 2.5.1 + dev: true + /@pkgjs/parseargs@0.11.0: resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} @@ -2410,6 +2749,14 @@ packages: dev: true optional: true + /@polka/url@0.5.0: + resolution: {integrity: sha512-oZLYFEAzUKyi3SKnXvj32ZCEGH6RDnao7COuCVhDydMS9NrCSVXhM79VaKyP5+Zc33m0QXEd2DN3UkU7OsHcfw==} + dev: true + + /@polka/url@1.0.0-next.29: + resolution: {integrity: sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==} + dev: true + /@redis/bloom@1.2.0(@redis/client@1.5.9): resolution: {integrity: sha512-HG2DFjYKbpNmVXsa0keLHp/3leGJz1mjh09f2RLGGLQZzSHpkmZWuwJbAvo3QcRY8p80m5+ZdXZdYOSBLlp7Cg==} peerDependencies: @@ -2743,121 +3090,121 @@ packages: resolution: {integrity: sha512-UY+FGM/2jjMkzQLn8pxcHGMaVLh9aEitG3zY2CiY7XHdLiz3bZOwa6oDxNqEMv7zZkV+cj5DOdz0cQ1BP5Hjgw==} dev: true - /@smithy/abort-controller@4.0.1: - resolution: {integrity: sha512-fiUIYgIgRjMWznk6iLJz35K2YxSLHzLBA/RC6lBrKfQ8fHbPfvk7Pk9UvpKoHgJjI18MnbPuEju53zcVy6KF1g==} + /@smithy/abort-controller@4.0.3: + resolution: {integrity: sha512-AqXFf6DXnuRBXy4SoK/n1mfgHaKaq36bmkphmD1KO0nHq6xK/g9KHSW4HEsPQUBCGdIEfuJifGHwxFXPIFay9Q==} engines: {node: '>=18.0.0'} dependencies: - '@smithy/types': 4.1.0 + '@smithy/types': 4.3.0 tslib: 2.6.2 dev: false - /@smithy/config-resolver@4.0.1: - resolution: {integrity: sha512-Igfg8lKu3dRVkTSEm98QpZUvKEOa71jDX4vKRcvJVyRc3UgN3j7vFMf0s7xLQhYmKa8kyJGQgUJDOV5V3neVlQ==} + /@smithy/config-resolver@4.1.3: + resolution: {integrity: sha512-N5e7ofiyYDmHxnPnqF8L4KtsbSDwyxFRfDK9bp1d9OyPO4ytRLd0/XxCqi5xVaaqB65v4woW8uey6jND6zxzxQ==} engines: {node: '>=18.0.0'} dependencies: - '@smithy/node-config-provider': 4.0.1 - '@smithy/types': 4.1.0 + '@smithy/node-config-provider': 4.1.2 + '@smithy/types': 4.3.0 '@smithy/util-config-provider': 4.0.0 - '@smithy/util-middleware': 4.0.1 + '@smithy/util-middleware': 4.0.3 tslib: 2.6.2 dev: false - /@smithy/core@3.1.2: - resolution: {integrity: sha512-htwQXkbdF13uwwDevz9BEzL5ABK+1sJpVQXywwGSH973AVOvisHNfpcB8A8761G6XgHoS2kHPqc9DqHJ2gp+/Q==} + /@smithy/core@3.4.0: + resolution: {integrity: sha512-dDYISQo7k0Ml/rXlFIjkTmTcQze/LxhtIRAEmZ6HJ/EI0inVxVEVnrUXJ7jPx6ZP0GHUhFm40iQcCgS5apXIXA==} engines: {node: '>=18.0.0'} dependencies: - '@smithy/middleware-serde': 4.0.2 - '@smithy/protocol-http': 5.0.1 - '@smithy/types': 4.1.0 + '@smithy/middleware-serde': 4.0.6 + '@smithy/protocol-http': 5.1.1 + '@smithy/types': 4.3.0 '@smithy/util-body-length-browser': 4.0.0 - '@smithy/util-middleware': 4.0.1 - '@smithy/util-stream': 4.0.2 + '@smithy/util-middleware': 4.0.3 + '@smithy/util-stream': 4.2.1 '@smithy/util-utf8': 4.0.0 tslib: 2.6.2 dev: false - /@smithy/credential-provider-imds@4.0.1: - resolution: {integrity: sha512-l/qdInaDq1Zpznpmev/+52QomsJNZ3JkTl5yrTl02V6NBgJOQ4LY0SFw/8zsMwj3tLe8vqiIuwF6nxaEwgf6mg==} + /@smithy/credential-provider-imds@4.0.5: + resolution: {integrity: sha512-saEAGwrIlkb9XxX/m5S5hOtzjoJPEK6Qw2f9pYTbIsMPOFyGSXBBTw95WbOyru8A1vIS2jVCCU1Qhz50QWG3IA==} engines: {node: '>=18.0.0'} dependencies: - '@smithy/node-config-provider': 4.0.1 - '@smithy/property-provider': 4.0.1 - '@smithy/types': 4.1.0 - '@smithy/url-parser': 4.0.1 + '@smithy/node-config-provider': 4.1.2 + '@smithy/property-provider': 4.0.3 + '@smithy/types': 4.3.0 + '@smithy/url-parser': 4.0.3 tslib: 2.6.2 dev: false - /@smithy/eventstream-codec@4.0.1: - resolution: {integrity: sha512-Q2bCAAR6zXNVtJgifsU16ZjKGqdw/DyecKNgIgi7dlqw04fqDu0mnq+JmGphqheypVc64CYq3azSuCpAdFk2+A==} + /@smithy/eventstream-codec@4.0.3: + resolution: {integrity: sha512-V22KIPXZsE2mc4zEgYGANM/7UbL9jWlOACEolyGyMuTY+jjHJ2PQ0FdopOTS1CS7u6PlAkALmypkv2oQ4aftcg==} engines: {node: '>=18.0.0'} dependencies: '@aws-crypto/crc32': 5.2.0 - '@smithy/types': 4.1.0 + '@smithy/types': 4.3.0 '@smithy/util-hex-encoding': 4.0.0 tslib: 2.6.2 dev: false - /@smithy/eventstream-serde-browser@4.0.1: - resolution: {integrity: sha512-HbIybmz5rhNg+zxKiyVAnvdM3vkzjE6ccrJ620iPL8IXcJEntd3hnBl+ktMwIy12Te/kyrSbUb8UCdnUT4QEdA==} + /@smithy/eventstream-serde-browser@4.0.3: + resolution: {integrity: sha512-oe1d/tfCGVZBMX8O6HApaM4G+fF9JNdyLP7tWXt00epuL/kLOdp/4o9VqheLFeJaXgao+9IaBgs/q/oM48hxzg==} engines: {node: '>=18.0.0'} dependencies: - '@smithy/eventstream-serde-universal': 4.0.1 - '@smithy/types': 4.1.0 + '@smithy/eventstream-serde-universal': 4.0.3 + '@smithy/types': 4.3.0 tslib: 2.6.2 dev: false - /@smithy/eventstream-serde-config-resolver@4.0.1: - resolution: {integrity: sha512-lSipaiq3rmHguHa3QFF4YcCM3VJOrY9oq2sow3qlhFY+nBSTF/nrO82MUQRPrxHQXA58J5G1UnU2WuJfi465BA==} + /@smithy/eventstream-serde-config-resolver@4.1.1: + resolution: {integrity: sha512-XXCPGjRNwpFWHKQJMKIjGLfFKYULYckFnxGcWmBC2mBf3NsrvUKgqHax4NCqc0TfbDAimPDHOc6HOKtzsXK9Gw==} engines: {node: '>=18.0.0'} dependencies: - '@smithy/types': 4.1.0 + '@smithy/types': 4.3.0 tslib: 2.6.2 dev: false - /@smithy/eventstream-serde-node@4.0.1: - resolution: {integrity: sha512-o4CoOI6oYGYJ4zXo34U8X9szDe3oGjmHgsMGiZM0j4vtNoT+h80TLnkUcrLZR3+E6HIxqW+G+9WHAVfl0GXK0Q==} + /@smithy/eventstream-serde-node@4.0.3: + resolution: {integrity: sha512-HOEbRmm9TrikCoFrypYu0J/gC4Lsk8gl5LtOz1G3laD2Jy44+ht2Pd2E9qjNQfhMJIzKDZ/gbuUH0s0v4kWQ0A==} engines: {node: '>=18.0.0'} dependencies: - '@smithy/eventstream-serde-universal': 4.0.1 - '@smithy/types': 4.1.0 + '@smithy/eventstream-serde-universal': 4.0.3 + '@smithy/types': 4.3.0 tslib: 2.6.2 dev: false - /@smithy/eventstream-serde-universal@4.0.1: - resolution: {integrity: sha512-Z94uZp0tGJuxds3iEAZBqGU2QiaBHP4YytLUjwZWx+oUeohCsLyUm33yp4MMBmhkuPqSbQCXq5hDet6JGUgHWA==} + /@smithy/eventstream-serde-universal@4.0.3: + resolution: {integrity: sha512-ShOP512CZrYI9n+h64PJ84udzoNHUQtPddyh1j175KNTKsSnMEDNscOWJWyEoLQiuhWWw51lSa+k6ea9ZGXcRg==} engines: {node: '>=18.0.0'} dependencies: - '@smithy/eventstream-codec': 4.0.1 - '@smithy/types': 4.1.0 + '@smithy/eventstream-codec': 4.0.3 + '@smithy/types': 4.3.0 tslib: 2.6.2 dev: false - /@smithy/fetch-http-handler@5.0.1: - resolution: {integrity: sha512-3aS+fP28urrMW2KTjb6z9iFow6jO8n3MFfineGbndvzGZit3taZhKWtTorf+Gp5RpFDDafeHlhfsGlDCXvUnJA==} + /@smithy/fetch-http-handler@5.0.3: + resolution: {integrity: sha512-yBZwavI31roqTndNI7ONHqesfH01JmjJK6L3uUpZAhyAmr86LN5QiPzfyZGIxQmed8VEK2NRSQT3/JX5V1njfQ==} engines: {node: '>=18.0.0'} dependencies: - '@smithy/protocol-http': 5.0.1 - '@smithy/querystring-builder': 4.0.1 - '@smithy/types': 4.1.0 + '@smithy/protocol-http': 5.1.1 + '@smithy/querystring-builder': 4.0.3 + '@smithy/types': 4.3.0 '@smithy/util-base64': 4.0.0 tslib: 2.6.2 dev: false - /@smithy/hash-node@4.0.1: - resolution: {integrity: sha512-TJ6oZS+3r2Xu4emVse1YPB3Dq3d8RkZDKcPr71Nj/lJsdAP1c7oFzYqEn1IBc915TsgLl2xIJNuxCz+gLbLE0w==} + /@smithy/hash-node@4.0.3: + resolution: {integrity: sha512-W5Uhy6v/aYrgtjh9y0YP332gIQcwccQ+EcfWhllL0B9rPae42JngTTUpb8W6wuxaNFzqps4xq5klHckSSOy5fw==} engines: {node: '>=18.0.0'} dependencies: - '@smithy/types': 4.1.0 + '@smithy/types': 4.3.0 '@smithy/util-buffer-from': 4.0.0 '@smithy/util-utf8': 4.0.0 tslib: 2.6.2 dev: false - /@smithy/invalid-dependency@4.0.1: - resolution: {integrity: sha512-gdudFPf4QRQ5pzj7HEnu6FhKRi61BfH/Gk5Yf6O0KiSbr1LlVhgjThcvjdu658VE6Nve8vaIWB8/fodmS1rBPQ==} + /@smithy/invalid-dependency@4.0.3: + resolution: {integrity: sha512-1Bo8Ur1ZGqxvwTqBmv6DZEn0rXtwJGeqiiO2/JFcCtz3nBakOqeXbJBElXJMMzd0ghe8+eB6Dkw98nMYctgizg==} engines: {node: '>=18.0.0'} dependencies: - '@smithy/types': 4.1.0 + '@smithy/types': 4.3.0 tslib: 2.6.2 dev: false @@ -2875,169 +3222,170 @@ packages: tslib: 2.6.2 dev: false - /@smithy/middleware-content-length@4.0.1: - resolution: {integrity: sha512-OGXo7w5EkB5pPiac7KNzVtfCW2vKBTZNuCctn++TTSOMpe6RZO/n6WEC1AxJINn3+vWLKW49uad3lo/u0WJ9oQ==} + /@smithy/middleware-content-length@4.0.3: + resolution: {integrity: sha512-NE/Zph4BP5u16bzYq2csq9qD0T6UBLeg4AuNrwNJ7Gv9uLYaGEgelZUOdRndGdMGcUfSGvNlXGb2aA2hPCwJ6g==} engines: {node: '>=18.0.0'} dependencies: - '@smithy/protocol-http': 5.0.1 - '@smithy/types': 4.1.0 + '@smithy/protocol-http': 5.1.1 + '@smithy/types': 4.3.0 tslib: 2.6.2 dev: false - /@smithy/middleware-endpoint@4.0.3: - resolution: {integrity: sha512-YdbmWhQF5kIxZjWqPIgboVfi8i5XgiYMM7GGKFMTvBei4XjNQfNv8sukT50ITvgnWKKKpOtp0C0h7qixLgb77Q==} + /@smithy/middleware-endpoint@4.1.7: + resolution: {integrity: sha512-KDzM7Iajo6K7eIWNNtukykRT4eWwlHjCEsULZUaSfi/SRSBK8BPRqG5FsVfp58lUxcvre8GT8AIPIqndA0ERKw==} engines: {node: '>=18.0.0'} dependencies: - '@smithy/core': 3.1.2 - '@smithy/middleware-serde': 4.0.2 - '@smithy/node-config-provider': 4.0.1 - '@smithy/shared-ini-file-loader': 4.0.1 - '@smithy/types': 4.1.0 - '@smithy/url-parser': 4.0.1 - '@smithy/util-middleware': 4.0.1 + '@smithy/core': 3.4.0 + '@smithy/middleware-serde': 4.0.6 + '@smithy/node-config-provider': 4.1.2 + '@smithy/shared-ini-file-loader': 4.0.3 + '@smithy/types': 4.3.0 + '@smithy/url-parser': 4.0.3 + '@smithy/util-middleware': 4.0.3 tslib: 2.6.2 dev: false - /@smithy/middleware-retry@4.0.4: - resolution: {integrity: sha512-wmxyUBGHaYUqul0wZiset4M39SMtDBOtUr2KpDuftKNN74Do9Y36Go6Eqzj9tL0mIPpr31ulB5UUtxcsCeGXsQ==} + /@smithy/middleware-retry@4.1.8: + resolution: {integrity: sha512-e2OtQgFzzlSG0uCjcJmi02QuFSRTrpT11Eh2EcqqDFy7DYriteHZJkkf+4AsxsrGDugAtPFcWBz1aq06sSX5fQ==} engines: {node: '>=18.0.0'} dependencies: - '@smithy/node-config-provider': 4.0.1 - '@smithy/protocol-http': 5.0.1 - '@smithy/service-error-classification': 4.0.1 - '@smithy/smithy-client': 4.1.3 - '@smithy/types': 4.1.0 - '@smithy/util-middleware': 4.0.1 - '@smithy/util-retry': 4.0.1 + '@smithy/node-config-provider': 4.1.2 + '@smithy/protocol-http': 5.1.1 + '@smithy/service-error-classification': 4.0.4 + '@smithy/smithy-client': 4.3.0 + '@smithy/types': 4.3.0 + '@smithy/util-middleware': 4.0.3 + '@smithy/util-retry': 4.0.4 tslib: 2.6.2 uuid: 9.0.1 dev: false - /@smithy/middleware-serde@4.0.2: - resolution: {integrity: sha512-Sdr5lOagCn5tt+zKsaW+U2/iwr6bI9p08wOkCp6/eL6iMbgdtc2R5Ety66rf87PeohR0ExI84Txz9GYv5ou3iQ==} + /@smithy/middleware-serde@4.0.6: + resolution: {integrity: sha512-YECyl7uNII+jCr/9qEmCu8xYL79cU0fqjo0qxpcVIU18dAPHam/iYwcknAu4Jiyw1uN+sAx7/SMf/Kmef/Jjsg==} engines: {node: '>=18.0.0'} dependencies: - '@smithy/types': 4.1.0 + '@smithy/protocol-http': 5.1.1 + '@smithy/types': 4.3.0 tslib: 2.6.2 dev: false - /@smithy/middleware-stack@4.0.1: - resolution: {integrity: sha512-dHwDmrtR/ln8UTHpaIavRSzeIk5+YZTBtLnKwDW3G2t6nAupCiQUvNzNoHBpik63fwUaJPtlnMzXbQrNFWssIA==} + /@smithy/middleware-stack@4.0.3: + resolution: {integrity: sha512-baeV7t4jQfQtFxBADFmnhmqBmqR38dNU5cvEgHcMK/Kp3D3bEI0CouoX2Sr/rGuntR+Eg0IjXdxnGGTc6SbIkw==} engines: {node: '>=18.0.0'} dependencies: - '@smithy/types': 4.1.0 + '@smithy/types': 4.3.0 tslib: 2.6.2 dev: false - /@smithy/node-config-provider@4.0.1: - resolution: {integrity: sha512-8mRTjvCtVET8+rxvmzRNRR0hH2JjV0DFOmwXPrISmTIJEfnCBugpYYGAsCj8t41qd+RB5gbheSQ/6aKZCQvFLQ==} + /@smithy/node-config-provider@4.1.2: + resolution: {integrity: sha512-SUvNup8iU1v7fmM8XPk+27m36udmGCfSz+VZP5Gb0aJ3Ne0X28K/25gnsrg3X1rWlhcnhzNUUysKW/Ied46ivQ==} engines: {node: '>=18.0.0'} dependencies: - '@smithy/property-provider': 4.0.1 - '@smithy/shared-ini-file-loader': 4.0.1 - '@smithy/types': 4.1.0 + '@smithy/property-provider': 4.0.3 + '@smithy/shared-ini-file-loader': 4.0.3 + '@smithy/types': 4.3.0 tslib: 2.6.2 dev: false - /@smithy/node-http-handler@4.0.2: - resolution: {integrity: sha512-X66H9aah9hisLLSnGuzRYba6vckuFtGE+a5DcHLliI/YlqKrGoxhisD5XbX44KyoeRzoNlGr94eTsMVHFAzPOw==} + /@smithy/node-http-handler@4.0.5: + resolution: {integrity: sha512-T7QglZC1vS7SPT44/1qSIAQEx5bFKb3LfO6zw/o4Xzt1eC5HNoH1TkS4lMYA9cWFbacUhx4hRl/blLun4EOCkg==} engines: {node: '>=18.0.0'} dependencies: - '@smithy/abort-controller': 4.0.1 - '@smithy/protocol-http': 5.0.1 - '@smithy/querystring-builder': 4.0.1 - '@smithy/types': 4.1.0 + '@smithy/abort-controller': 4.0.3 + '@smithy/protocol-http': 5.1.1 + '@smithy/querystring-builder': 4.0.3 + '@smithy/types': 4.3.0 tslib: 2.6.2 dev: false - /@smithy/property-provider@4.0.1: - resolution: {integrity: sha512-o+VRiwC2cgmk/WFV0jaETGOtX16VNPp2bSQEzu0whbReqE1BMqsP2ami2Vi3cbGVdKu1kq9gQkDAGKbt0WOHAQ==} + /@smithy/property-provider@4.0.3: + resolution: {integrity: sha512-Wcn17QNdawJZcZZPBuMuzyBENVi1AXl4TdE0jvzo4vWX2x5df/oMlmr/9M5XAAC6+yae4kWZlOYIsNsgDrMU9A==} engines: {node: '>=18.0.0'} dependencies: - '@smithy/types': 4.1.0 + '@smithy/types': 4.3.0 tslib: 2.6.2 dev: false - /@smithy/protocol-http@5.0.1: - resolution: {integrity: sha512-TE4cpj49jJNB/oHyh/cRVEgNZaoPaxd4vteJNB0yGidOCVR0jCw/hjPVsT8Q8FRmj8Bd3bFZt8Dh7xGCT+xMBQ==} + /@smithy/protocol-http@5.1.1: + resolution: {integrity: sha512-Vsay2mzq05DwNi9jK01yCFtfvu9HimmgC7a4HTs7lhX12Sx8aWsH0mfz6q/02yspSp+lOB+Q2HJwi4IV2GKz7A==} engines: {node: '>=18.0.0'} dependencies: - '@smithy/types': 4.1.0 + '@smithy/types': 4.3.0 tslib: 2.6.2 dev: false - /@smithy/querystring-builder@4.0.1: - resolution: {integrity: sha512-wU87iWZoCbcqrwszsOewEIuq+SU2mSoBE2CcsLwE0I19m0B2gOJr1MVjxWcDQYOzHbR1xCk7AcOBbGFUYOKvdg==} + /@smithy/querystring-builder@4.0.3: + resolution: {integrity: sha512-UUzIWMVfPmDZcOutk2/r1vURZqavvQW0OHvgsyNV0cKupChvqg+/NKPRMaMEe+i8tP96IthMFeZOZWpV+E4RAw==} engines: {node: '>=18.0.0'} dependencies: - '@smithy/types': 4.1.0 + '@smithy/types': 4.3.0 '@smithy/util-uri-escape': 4.0.0 tslib: 2.6.2 dev: false - /@smithy/querystring-parser@4.0.1: - resolution: {integrity: sha512-Ma2XC7VS9aV77+clSFylVUnPZRindhB7BbmYiNOdr+CHt/kZNJoPP0cd3QxCnCFyPXC4eybmyE98phEHkqZ5Jw==} + /@smithy/querystring-parser@4.0.3: + resolution: {integrity: sha512-K5M4ZJQpFCblOJ5Oyw7diICpFg1qhhR47m2/5Ef1PhGE19RaIZf50tjYFrxa6usqcuXyTiFPGo4d1geZdH4YcQ==} engines: {node: '>=18.0.0'} dependencies: - '@smithy/types': 4.1.0 + '@smithy/types': 4.3.0 tslib: 2.6.2 dev: false - /@smithy/service-error-classification@4.0.1: - resolution: {integrity: sha512-3JNjBfOWpj/mYfjXJHB4Txc/7E4LVq32bwzE7m28GN79+M1f76XHflUaSUkhOriprPDzev9cX/M+dEB80DNDKA==} + /@smithy/service-error-classification@4.0.4: + resolution: {integrity: sha512-W5ScbQ1bTzgH91kNEE2CvOzM4gXlDOqdow4m8vMFSIXCel2scbHwjflpVNnC60Y3F1m5i7w2gQg9lSnR+JsJAA==} engines: {node: '>=18.0.0'} dependencies: - '@smithy/types': 4.1.0 + '@smithy/types': 4.3.0 dev: false - /@smithy/shared-ini-file-loader@4.0.1: - resolution: {integrity: sha512-hC8F6qTBbuHRI/uqDgqqi6J0R4GtEZcgrZPhFQnMhfJs3MnUTGSnR1NSJCJs5VWlMydu0kJz15M640fJlRsIOw==} + /@smithy/shared-ini-file-loader@4.0.3: + resolution: {integrity: sha512-vHwlrqhZGIoLwaH8vvIjpHnloShqdJ7SUPNM2EQtEox+yEDFTVQ7E+DLZ+6OhnYEgFUwPByJyz6UZaOu2tny6A==} engines: {node: '>=18.0.0'} dependencies: - '@smithy/types': 4.1.0 + '@smithy/types': 4.3.0 tslib: 2.6.2 dev: false - /@smithy/signature-v4@5.0.1: - resolution: {integrity: sha512-nCe6fQ+ppm1bQuw5iKoeJ0MJfz2os7Ic3GBjOkLOPtavbD1ONoyE3ygjBfz2ythFWm4YnRm6OxW+8p/m9uCoIA==} + /@smithy/signature-v4@5.1.1: + resolution: {integrity: sha512-zy8Repr5zvT0ja+Tf5wjV/Ba6vRrhdiDcp/ww6cvqYbSEudIkziDe3uppNRlFoCViyJXdPnLcwyZdDLA4CHzSg==} engines: {node: '>=18.0.0'} dependencies: '@smithy/is-array-buffer': 4.0.0 - '@smithy/protocol-http': 5.0.1 - '@smithy/types': 4.1.0 + '@smithy/protocol-http': 5.1.1 + '@smithy/types': 4.3.0 '@smithy/util-hex-encoding': 4.0.0 - '@smithy/util-middleware': 4.0.1 + '@smithy/util-middleware': 4.0.3 '@smithy/util-uri-escape': 4.0.0 '@smithy/util-utf8': 4.0.0 tslib: 2.6.2 dev: false - /@smithy/smithy-client@4.1.3: - resolution: {integrity: sha512-A2Hz85pu8BJJaYFdX8yb1yocqigyqBzn+OVaVgm+Kwi/DkN8vhN2kbDVEfADo6jXf5hPKquMLGA3UINA64UZ7A==} + /@smithy/smithy-client@4.3.0: + resolution: {integrity: sha512-DNsRA38pN6tYHUjebmwD9e4KcgqTLldYQb2gC6K+oxXYdCTxPn6wV9+FvOa6wrU2FQEnGJoi+3GULzOTKck/tg==} engines: {node: '>=18.0.0'} dependencies: - '@smithy/core': 3.1.2 - '@smithy/middleware-endpoint': 4.0.3 - '@smithy/middleware-stack': 4.0.1 - '@smithy/protocol-http': 5.0.1 - '@smithy/types': 4.1.0 - '@smithy/util-stream': 4.0.2 + '@smithy/core': 3.4.0 + '@smithy/middleware-endpoint': 4.1.7 + '@smithy/middleware-stack': 4.0.3 + '@smithy/protocol-http': 5.1.1 + '@smithy/types': 4.3.0 + '@smithy/util-stream': 4.2.1 tslib: 2.6.2 dev: false - /@smithy/types@4.1.0: - resolution: {integrity: sha512-enhjdwp4D7CXmwLtD6zbcDMbo6/T6WtuuKCY49Xxc6OMOmUWlBEBDREsxxgV2LIdeQPW756+f97GzcgAwp3iLw==} + /@smithy/types@4.3.0: + resolution: {integrity: sha512-+1iaIQHthDh9yaLhRzaoQxRk+l9xlk+JjMFxGRhNLz+m9vKOkjNeU8QuB4w3xvzHyVR/BVlp/4AXDHjoRIkfgQ==} engines: {node: '>=18.0.0'} dependencies: tslib: 2.6.2 dev: false - /@smithy/url-parser@4.0.1: - resolution: {integrity: sha512-gPXcIEUtw7VlK8f/QcruNXm7q+T5hhvGu9tl63LsJPZ27exB6dtNwvh2HIi0v7JcXJ5emBxB+CJxwaLEdJfA+g==} + /@smithy/url-parser@4.0.3: + resolution: {integrity: sha512-n5/DnosDu/tweOqUUNtUbu7eRIR4J/Wz9nL7V5kFYQQVb8VYdj7a4G5NJHCw6o21ul7CvZoJkOpdTnsQDLT0tQ==} engines: {node: '>=18.0.0'} dependencies: - '@smithy/querystring-parser': 4.0.1 - '@smithy/types': 4.1.0 + '@smithy/querystring-parser': 4.0.3 + '@smithy/types': 4.3.0 tslib: 2.6.2 dev: false @@ -3087,36 +3435,36 @@ packages: tslib: 2.6.2 dev: false - /@smithy/util-defaults-mode-browser@4.0.4: - resolution: {integrity: sha512-Ej1bV5sbrIfH++KnWxjjzFNq9nyP3RIUq2c9Iqq7SmMO/idUR24sqvKH2LUQFTSPy/K7G4sB2m8n7YYlEAfZaw==} + /@smithy/util-defaults-mode-browser@4.0.15: + resolution: {integrity: sha512-bJJ/B8owQbHAflatSq92f9OcV8858DJBQF1Y3GRjB8psLyUjbISywszYPFw16beREHO/C3I3taW4VGH+tOuwrQ==} engines: {node: '>=18.0.0'} dependencies: - '@smithy/property-provider': 4.0.1 - '@smithy/smithy-client': 4.1.3 - '@smithy/types': 4.1.0 + '@smithy/property-provider': 4.0.3 + '@smithy/smithy-client': 4.3.0 + '@smithy/types': 4.3.0 bowser: 2.11.0 tslib: 2.6.2 dev: false - /@smithy/util-defaults-mode-node@4.0.4: - resolution: {integrity: sha512-HE1I7gxa6yP7ZgXPCFfZSDmVmMtY7SHqzFF55gM/GPegzZKaQWZZ+nYn9C2Cc3JltCMyWe63VPR3tSFDEvuGjw==} + /@smithy/util-defaults-mode-node@4.0.15: + resolution: {integrity: sha512-8CUrEW2Ni5q+NmYkj8wsgkfqoP7l4ZquptFbq92yQE66xevc4SxqP2zH6tMtN158kgBqBDsZ+qlrRwXWOjCR8A==} engines: {node: '>=18.0.0'} dependencies: - '@smithy/config-resolver': 4.0.1 - '@smithy/credential-provider-imds': 4.0.1 - '@smithy/node-config-provider': 4.0.1 - '@smithy/property-provider': 4.0.1 - '@smithy/smithy-client': 4.1.3 - '@smithy/types': 4.1.0 + '@smithy/config-resolver': 4.1.3 + '@smithy/credential-provider-imds': 4.0.5 + '@smithy/node-config-provider': 4.1.2 + '@smithy/property-provider': 4.0.3 + '@smithy/smithy-client': 4.3.0 + '@smithy/types': 4.3.0 tslib: 2.6.2 dev: false - /@smithy/util-endpoints@3.0.1: - resolution: {integrity: sha512-zVdUENQpdtn9jbpD9SCFK4+aSiavRb9BxEtw9ZGUR1TYo6bBHbIoi7VkrFQ0/RwZlzx0wRBaRmPclj8iAoJCLA==} + /@smithy/util-endpoints@3.0.5: + resolution: {integrity: sha512-PjDpqLk24/vAl340tmtCA++Q01GRRNH9cwL9qh46NspAX9S+IQVcK+GOzPt0GLJ6KYGyn8uOgo2kvJhiThclJw==} engines: {node: '>=18.0.0'} dependencies: - '@smithy/node-config-provider': 4.0.1 - '@smithy/types': 4.1.0 + '@smithy/node-config-provider': 4.1.2 + '@smithy/types': 4.3.0 tslib: 2.6.2 dev: false @@ -3127,30 +3475,30 @@ packages: tslib: 2.6.2 dev: false - /@smithy/util-middleware@4.0.1: - resolution: {integrity: sha512-HiLAvlcqhbzhuiOa0Lyct5IIlyIz0PQO5dnMlmQ/ubYM46dPInB+3yQGkfxsk6Q24Y0n3/JmcA1v5iEhmOF5mA==} + /@smithy/util-middleware@4.0.3: + resolution: {integrity: sha512-iIsC6qZXxkD7V3BzTw3b1uK8RVC1M8WvwNxK1PKrH9FnxntCd30CSunXjL/8iJBE8Z0J14r2P69njwIpRG4FBQ==} engines: {node: '>=18.0.0'} dependencies: - '@smithy/types': 4.1.0 + '@smithy/types': 4.3.0 tslib: 2.6.2 dev: false - /@smithy/util-retry@4.0.1: - resolution: {integrity: sha512-WmRHqNVwn3kI3rKk1LsKcVgPBG6iLTBGC1iYOV3GQegwJ3E8yjzHytPt26VNzOWr1qu0xE03nK0Ug8S7T7oufw==} + /@smithy/util-retry@4.0.4: + resolution: {integrity: sha512-Aoqr9W2jDYGrI6OxljN8VmLDQIGO4VdMAUKMf9RGqLG8hn6or+K41NEy1Y5dtum9q8F7e0obYAuKl2mt/GnpZg==} engines: {node: '>=18.0.0'} dependencies: - '@smithy/service-error-classification': 4.0.1 - '@smithy/types': 4.1.0 + '@smithy/service-error-classification': 4.0.4 + '@smithy/types': 4.3.0 tslib: 2.6.2 dev: false - /@smithy/util-stream@4.0.2: - resolution: {integrity: sha512-0eZ4G5fRzIoewtHtwaYyl8g2C+osYOT4KClXgfdNEDAgkbe2TYPqcnw4GAWabqkZCax2ihRGPe9LZnsPdIUIHA==} + /@smithy/util-stream@4.2.1: + resolution: {integrity: sha512-W3IR0x5DY6iVtjj5p902oNhD+Bz7vs5S+p6tppbPa509rV9BdeXZjGuRSCtVEad9FA0Mba+tNUtUmtnSI1nwUw==} engines: {node: '>=18.0.0'} dependencies: - '@smithy/fetch-http-handler': 5.0.1 - '@smithy/node-http-handler': 4.0.2 - '@smithy/types': 4.1.0 + '@smithy/fetch-http-handler': 5.0.3 + '@smithy/node-http-handler': 4.0.5 + '@smithy/types': 4.3.0 '@smithy/util-base64': 4.0.0 '@smithy/util-buffer-from': 4.0.0 '@smithy/util-hex-encoding': 4.0.0 @@ -3289,6 +3637,10 @@ packages: resolution: {integrity: sha512-QVSSvno3dE0MgO76pJhmv4Qyi/j0Yk9pBp0Y7TJ2Tlj+KCgJWY6qX7nnxCOLkZ3VYRSIk1WTxCvwUSdx6CCLdg==} dev: true + /@types/cookie@0.6.0: + resolution: {integrity: sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==} + dev: true + /@types/cors@2.8.13: resolution: {integrity: sha512-RG8AStHlUiV5ysZQKq97copd2UmVYw3/pRMLefISZ3S1hK104Cwm7iLQ3fTKx+lsUH2CE8FlLaYeEA2LSeqYUA==} dependencies: @@ -3357,6 +3709,10 @@ packages: resolution: {integrity: sha512-iJt33IQnVRkqeqC7PzBHPTC6fDlRNRW8vjrgqtScAhrmMwe8c4Eo7+fUGTa+XdWrpEgpyKWMYmi2dIwMAYRzPw==} dev: true + /@types/minimatch@3.0.5: + resolution: {integrity: sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==} + dev: true + /@types/node-fetch@2.6.9: resolution: {integrity: sha512-bQVlnMLFJ2d35DkPNjEPmd9ueO/rh5EiaZt2bhqiSarPjZIuIV6bPQVqcrEyvNo+AfTrRGVazle1tl597w3gfA==} dependencies: @@ -3379,6 +3735,10 @@ packages: dependencies: undici-types: 5.26.5 + /@types/parse-json@4.0.2: + resolution: {integrity: sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==} + dev: true + /@types/phoenix@1.6.4: resolution: {integrity: sha512-B34A7uot1Cv0XtaHRYDATltAdKx0BvVKNgYNqE4WjtPUa4VQJM7kxeXcVKaH+KS+kCmZ+6w+QaUdcljiheiBJA==} dev: false @@ -3417,6 +3777,14 @@ packages: '@types/node': 20.10.5 dev: true + /@types/statuses@2.0.5: + resolution: {integrity: sha512-jmIUGWrAiwu3dZpxntxieC+1n/5c3mjrImkmOSQ2NC5uP6cYO4aAZDdSmRcI5C1oiTmqlZGHC+/NmJrKogbP5A==} + dev: true + + /@types/tough-cookie@4.0.5: + resolution: {integrity: sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==} + dev: true + /@types/uuid@9.0.7: resolution: {integrity: sha512-WUtIVRUZ9i5dYXefDEAI7sh9/O7jGvHg7Df/5O/gtH3Yabe5odI3UWopVR1qbPXQtvOxWu3mM4XxlYeZtMWF4g==} @@ -3545,6 +3913,11 @@ packages: engines: {node: ^16.0.0 || >=18.0.0} dev: true + /@typescript-eslint/types@7.13.1: + resolution: {integrity: sha512-7K7HMcSQIAND6RBL4kDl24sG/xKM13cA85dc7JnmQXw2cBDngg7c19B++JzvJHRG3zG36n9j1i451GBzRuHchw==} + engines: {node: ^18.18.0 || >=20.0.0} + dev: true + /@typescript-eslint/types@8.21.0: resolution: {integrity: sha512-PAL6LUuQwotLW2a8VsySDBwYMm129vFm4tMVlylzdoTybTHaAi0oBp7Ac6LhSrHHOdLM3efH+nAR6hAWoMF89A==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -3576,6 +3949,28 @@ packages: - supports-color dev: true + /@typescript-eslint/typescript-estree@7.13.1(typescript@5.4.5): + resolution: {integrity: sha512-uxNr51CMV7npU1BxZzYjoVz9iyjckBduFBP0S5sLlh1tXYzHzgZ3BR9SVsNed+LmwKrmnqN3Kdl5t7eZ5TS1Yw==} + engines: {node: ^18.18.0 || >=20.0.0} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/types': 7.13.1 + '@typescript-eslint/visitor-keys': 7.13.1 + debug: 4.4.0 + globby: 11.1.0 + is-glob: 4.0.3 + minimatch: 9.0.5 + semver: 7.7.1 + ts-api-utils: 1.4.3(typescript@5.4.5) + typescript: 5.4.5 + transitivePeerDependencies: + - supports-color + dev: true + /@typescript-eslint/typescript-estree@8.21.0(typescript@5.5.4): resolution: {integrity: sha512-x+aeKh/AjAArSauz0GiQZsjT8ciadNMHdkUSwBB9Z6PrKc/4knM4g3UfHml6oDJmKC88a6//cdxnO/+P2LkMcg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -3639,8 +4034,16 @@ packages: eslint-visitor-keys: 3.4.3 dev: true - /@typescript-eslint/visitor-keys@8.21.0: - resolution: {integrity: sha512-BkLMNpdV6prozk8LlyK/SOoWLmUFi+ZD+pcqti9ILCbVvHGk1ui1g4jJOc2WDLaeExz2qWwojxlPce5PljcT3w==} + /@typescript-eslint/visitor-keys@7.13.1: + resolution: {integrity: sha512-k/Bfne7lrP7hcb7m9zSsgcBmo+8eicqqfNAJ7uUY+jkTFpKeH2FSkWpFRtimBxgkyvqfu9jTPRbYOvud6isdXA==} + engines: {node: ^18.18.0 || >=20.0.0} + dependencies: + '@typescript-eslint/types': 7.13.1 + eslint-visitor-keys: 3.4.3 + dev: true + + /@typescript-eslint/visitor-keys@8.21.0: + resolution: {integrity: sha512-BkLMNpdV6prozk8LlyK/SOoWLmUFi+ZD+pcqti9ILCbVvHGk1ui1g4jJOc2WDLaeExz2qWwojxlPce5PljcT3w==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} dependencies: '@typescript-eslint/types': 8.21.0 @@ -3729,7 +4132,7 @@ packages: tinyrainbow: 1.2.0 dev: true - /@vitest/mocker@2.1.9(vite@5.4.10): + /@vitest/mocker@2.1.9(msw@2.8.4)(vite@5.4.10): resolution: {integrity: sha512-tVL6uJgoUdi6icpxmdrn5YNo3g3Dxv+IHJBr0GXHaEdTcw3F+cPKnsXFhli6nO+f/6SDKPHEK1UN+k+TQv0Ehg==} peerDependencies: msw: ^2.4.9 @@ -3743,7 +4146,8 @@ packages: '@vitest/spy': 2.1.9 estree-walker: 3.0.3 magic-string: 0.30.17 - vite: 5.4.10 + msw: 2.8.4(@types/node@20.10.5)(typescript@5.5.4) + vite: 5.4.10(@types/node@20.10.5) dev: true /@vitest/pretty-format@2.1.9: @@ -3789,14 +4193,12 @@ packages: entities: 4.5.0 estree-walker: 2.0.2 source-map-js: 1.2.1 - dev: false /@vue/compiler-dom@3.5.13: resolution: {integrity: sha512-ZOJ46sMOKUjO3e94wPdCzQ6P1Lx/vhp2RSvfaab88Ajexs0AHeV0uasYhi99WPaogmBlRHNRuly8xV75cNTMDA==} dependencies: '@vue/compiler-core': 3.5.13 '@vue/shared': 3.5.13 - dev: false /@vue/compiler-sfc@3.5.13: resolution: {integrity: sha512-6VdaljMpD82w6c2749Zhf5T9u5uLBWKnVue6XWxprDobftnletJ8+oel7sexFfM3qIxNmVE7LSFGTpv6obNyaQ==} @@ -3810,14 +4212,12 @@ packages: magic-string: 0.30.17 postcss: 8.5.3 source-map-js: 1.2.1 - dev: false /@vue/compiler-ssr@3.5.13: resolution: {integrity: sha512-wMH6vrYHxQl/IybKJagqbquvxpWCuVYpoUJfCqFZwa/JY1GdATAQ+TgVtgrwwMZ0D07QhA99rs/EAAWfvG6KpA==} dependencies: '@vue/compiler-dom': 3.5.13 '@vue/shared': 3.5.13 - dev: false /@vue/reactivity@3.5.13: resolution: {integrity: sha512-NaCwtw8o48B9I6L1zl2p41OHo/2Z4wqYGGIK1Khu5T7yxrn+ATOixn/Udn2m+6kZKB/J7cuT9DbWWhRxqixACg==} @@ -3848,12 +4248,11 @@ packages: dependencies: '@vue/compiler-ssr': 3.5.13 '@vue/shared': 3.5.13 - vue: 3.5.13(typescript@5.5.4) + vue: 3.5.13(typescript@5.3.3) dev: false /@vue/shared@3.5.13: resolution: {integrity: sha512-/hnE/qP5ZoGpol0a5mDi45bOd7t3tjYJBjsgCsivow7D48cJeV5l05RD82lPqi7gRiphZM37rnhW1l6ZoCNNnQ==} - dev: false /abbrev@1.1.1: resolution: {integrity: sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==} @@ -3926,6 +4325,11 @@ packages: hasBin: true dev: false + /agent-base@7.1.3: + resolution: {integrity: sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==} + engines: {node: '>= 14'} + dev: false + /agentkeepalive@4.5.0: resolution: {integrity: sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew==} engines: {node: '>= 8.0.0'} @@ -4046,6 +4450,13 @@ packages: uri-js: 4.4.1 dev: true + /ansi-escapes@4.3.2: + resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==} + engines: {node: '>=8'} + dependencies: + type-fest: 0.21.3 + dev: true + /ansi-regex@5.0.1: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} @@ -4093,7 +4504,6 @@ packages: resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} dependencies: sprintf-js: 1.0.3 - dev: false /argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} @@ -4116,6 +4526,11 @@ packages: is-array-buffer: 3.0.2 dev: true + /array-differ@3.0.0: + resolution: {integrity: sha512-THtfYS6KtME/yIAhKjZ2ul7XI96lQGHRputJQHO80LAWQnuGP4iCIN8vdMRboGbIEYBwU33q8Tch1os2+X0kMg==} + engines: {node: '>=8'} + dev: true + /array-flatten@1.1.1: resolution: {integrity: sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==} dev: false @@ -4190,6 +4605,11 @@ packages: is-shared-array-buffer: 1.0.2 dev: true + /arrify@2.0.1: + resolution: {integrity: sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==} + engines: {node: '>=8'} + dev: true + /as-table@1.0.55: resolution: {integrity: sha512-xvsWESUJn0JN421Xb9MQw6AsMHRCUknCe0Wjlxvjud80mU4E6hQf1A6NzQKcYNmYw62MfzEtXc+badstZP3JpQ==} dependencies: @@ -4292,6 +4712,9 @@ packages: /base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + + /bignumber.js@9.3.0: + resolution: {integrity: sha512-EM7aMFTXbptt/wZdMlBv2t8IViwQL+h6SLHosp8Yf0dqJMTnY6iL32opnAB6kAdL0SZPuvcAzFr31o0c/R3/RA==} dev: false /binary-extensions@2.2.0: @@ -4303,6 +4726,14 @@ packages: resolution: {integrity: sha512-nbE1WxOTTrUWIfsfZ4aHGYu5DOuNkbxGokjV6Z2kxfJK3uaAb8zNK1muzOeipoLHZjInT4Br88BHpzevc681xA==} dev: false + /bl@5.1.0: + resolution: {integrity: sha512-tv1ZJHLfTDnXE6tMHv73YgSJaWR2AFuPwMntBe7XL/GBFHnT0CLnsHMogfk5+GzCDC5ZWarSCYaIGATZt9dNsQ==} + dependencies: + buffer: 6.0.3 + inherits: 2.0.4 + readable-stream: 3.6.2 + dev: true + /blake3-wasm@2.1.5: resolution: {integrity: sha512-F1+K8EbfOZE49dtoPtmxUQrpXaBIl3ICvasLh+nJta0xkz+9kF/7uet9fLnwKqhDrmj6g+6K3Tw9yQPUg2ka5g==} dev: true @@ -4418,6 +4849,13 @@ packages: isarray: 1.0.0 dev: false + /buffer@6.0.3: + resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} + dependencies: + base64-js: 1.5.1 + ieee754: 1.2.1 + dev: true + /bufferutil@4.0.8: resolution: {integrity: sha512-4T53u4PdgsXqKaIctwF8ifXlRTTmEPJ8iEPWFdGZvcf7sbwYo6FKFEX9eNNAnzFZ7EzJAQ3CJeOtCRA4rDp7Pw==} engines: {node: '>=6.14.2'} @@ -4446,7 +4884,6 @@ packages: /bytes@3.1.2: resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} engines: {node: '>= 0.8'} - dev: false /cac@6.7.14: resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} @@ -4464,6 +4901,10 @@ packages: get-intrinsic: 1.2.2 set-function-length: 1.1.1 + /callsite@1.0.0: + resolution: {integrity: sha512-0vdNRFXn5q+dtOqjfFtmtlI9N2eVZ7LMyEV2iKC5mEEFvSg/69Ml6b/WU2qF8W1nLRa0wiSrDT3Y5jOHZCwKPQ==} + dev: true + /callsites@3.1.0: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} @@ -4474,6 +4915,11 @@ packages: engines: {node: '>= 6'} dev: true + /camelcase@6.3.0: + resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} + engines: {node: '>=10'} + dev: true + /caniuse-lite@1.0.30001632: resolution: {integrity: sha512-udx3o7yHJfUxMLkGohMlVHCvFvWmirKh9JAH/d7WOLPetlH+LTL5cocMZ0t7oZx/mdlOWXti97xLZWc8uURRHg==} @@ -4507,7 +4953,6 @@ packages: /chalk@5.3.0: resolution: {integrity: sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==} engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} - dev: false /check-error@2.1.1: resolution: {integrity: sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==} @@ -4536,6 +4981,13 @@ packages: readdirp: 4.1.2 dev: true + /cli-cursor@4.0.0: + resolution: {integrity: sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + restore-cursor: 4.0.0 + dev: true + /cli-progress@3.12.0: resolution: {integrity: sha512-tRkV3HJ1ASwm19THiiLIXLO7Im7wlTuKnvkYaTkyoAPefqjNg7W7DHKUlGRxy9vxDvbyCYQkQozvptuMkGCg8A==} engines: {node: '>=4'} @@ -4543,10 +4995,28 @@ packages: string-width: 4.2.3 dev: false + /cli-spinners@2.9.2: + resolution: {integrity: sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==} + engines: {node: '>=6'} + dev: true + + /cli-width@4.1.0: + resolution: {integrity: sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==} + engines: {node: '>= 12'} + dev: true + /client-only@0.0.1: resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==} dev: false + /cliui@7.0.4: + resolution: {integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==} + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 + dev: true + /cliui@8.0.1: resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} engines: {node: '>=12'} @@ -4556,6 +5026,11 @@ packages: wrap-ansi: 7.0.0 dev: true + /clone@1.0.4: + resolution: {integrity: sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==} + engines: {node: '>=0.8'} + dev: true + /clsx@1.2.1: resolution: {integrity: sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==} engines: {node: '>=6'} @@ -4607,6 +5082,11 @@ packages: delayed-stream: 1.0.0 dev: false + /commander@11.1.0: + resolution: {integrity: sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==} + engines: {node: '>=16'} + dev: true + /commander@3.0.2: resolution: {integrity: sha512-Gar0ASD4BDyKC4hl4DwHqDrmvjoxWKZigVnAbn5H1owvm4CxCPdb0HQDehwNYMJpla5+M2tPmPARzhtYuwpHow==} dev: false @@ -4616,6 +5096,28 @@ packages: engines: {node: '>= 6'} dev: true + /compressible@2.0.18: + resolution: {integrity: sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==} + engines: {node: '>= 0.6'} + dependencies: + mime-db: 1.52.0 + dev: true + + /compression@1.8.0: + resolution: {integrity: sha512-k6WLKfunuqCYD3t6AsuPGvQWaKwuLLh2/xHNcX4qE+vIfDNXpSqnrhwA7O53R7WVQUnt8dVAIW+YHr7xTgOgGA==} + engines: {node: '>= 0.8.0'} + dependencies: + bytes: 3.1.2 + compressible: 2.0.18 + debug: 2.6.9 + negotiator: 0.6.4 + on-headers: 1.0.2 + safe-buffer: 5.2.1 + vary: 1.1.2 + transitivePeerDependencies: + - supports-color + dev: true + /concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} dev: true @@ -4663,6 +5165,17 @@ packages: vary: 1.1.2 dev: false + /cosmiconfig@7.1.0: + resolution: {integrity: sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==} + engines: {node: '>=10'} + dependencies: + '@types/parse-json': 4.0.2 + import-fresh: 3.3.0 + parse-json: 5.2.0 + path-type: 4.0.0 + yaml: 1.10.2 + dev: true + /cross-fetch@3.1.8: resolution: {integrity: sha512-cvA+JwZoU0Xq+h6WkMvAUqPEYy92Obet6UdKLfW60qn99ftItKjB5T+BkyWOFWe2pUyfQ+IJHmpOTznqk1M6Kg==} dependencies: @@ -4749,7 +5262,6 @@ packages: optional: true dependencies: ms: 2.0.0 - dev: false /debug@3.2.7(supports-color@5.5.0): resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} @@ -4807,6 +5319,12 @@ packages: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} dev: true + /defaults@1.0.4: + resolution: {integrity: sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==} + dependencies: + clone: 1.0.4 + dev: true + /define-data-property@1.1.1: resolution: {integrity: sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==} engines: {node: '>= 0.4'} @@ -4837,11 +5355,47 @@ packages: engines: {node: '>=0.4.0'} dev: false + /depcheck@1.4.7: + resolution: {integrity: sha512-1lklS/bV5chOxwNKA/2XUUk/hPORp8zihZsXflr8x0kLwmcZ9Y9BsS6Hs3ssvA+2wUVbG0U2Ciqvm1SokNjPkA==} + engines: {node: '>=10'} + hasBin: true + dependencies: + '@babel/parser': 7.27.1 + '@babel/traverse': 7.27.1 + '@vue/compiler-sfc': 3.5.13 + callsite: 1.0.0 + camelcase: 6.3.0 + cosmiconfig: 7.1.0 + debug: 4.4.0 + deps-regex: 0.2.0 + findup-sync: 5.0.0 + ignore: 5.3.2 + is-core-module: 2.13.1 + js-yaml: 3.14.1 + json5: 2.2.3 + lodash: 4.17.21 + minimatch: 7.4.6 + multimatch: 5.0.0 + please-upgrade-node: 3.2.0 + readdirp: 3.6.0 + require-package-name: 2.0.1 + resolve: 1.22.8 + resolve-from: 5.0.0 + semver: 7.7.1 + yargs: 16.2.0 + transitivePeerDependencies: + - supports-color + dev: true + /depd@2.0.0: resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} engines: {node: '>= 0.8'} dev: false + /deps-regex@0.2.0: + resolution: {integrity: sha512-PwuBojGMQAYbWkMXOY9Pd/NWCDNHVH12pnS7WHqZkTSeMESe4hwnKKRp0yR87g37113x4JPbo/oIvXY+s/f56Q==} + dev: true + /dequal@2.0.3: resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} engines: {node: '>=6'} @@ -4851,6 +5405,17 @@ packages: engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} dev: false + /detect-file@1.0.0: + resolution: {integrity: sha512-DtCOLG98P007x7wiiOmfI0fi3eIKyWiLTGJ2MDnVi/E04lWGbf+JzrRHMm0rgIIZJGtHpKpbVgLWHrv8xXpc3Q==} + engines: {node: '>=0.10.0'} + dev: true + + /detect-libc@1.0.3: + resolution: {integrity: sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==} + engines: {node: '>=0.10'} + hasBin: true + dev: true + /detective@5.2.1: resolution: {integrity: sha512-v9XE1zRnz1wRtgurGu0Bs8uHKFSTdteYZNbIPFVhUZ39L/S79ppMpdmVOZAnoz1jfEFodc48n6MX483Xo3t1yw==} engines: {node: '>=0.8.0'} @@ -4869,6 +5434,14 @@ packages: resolution: {integrity: sha512-IayShXAgj/QMXgB0IWmKx+rOPuGMhqm5w6jvFxmVenXKIzRqTAAsbBPT3kWQeGANj3jGgvcvv4yK6SxqYmikgw==} dev: false + /digraph-js@2.2.3: + resolution: {integrity: sha512-btynrARSW6pBmDz9+cwCxkBJ91CGBxIaNQo7V+ul9/rCRr3HddwehpEMnL6Ru2OeC2pKdRteB1v5TgZRrAAYKQ==} + engines: {node: '>=16.0.0'} + dependencies: + lodash.isequal: 4.5.0 + lodash.uniqwith: 4.5.0 + dev: true + /dir-glob@3.0.1: resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} engines: {node: '>=8'} @@ -4922,6 +5495,10 @@ packages: resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} dev: false + /effect@3.3.2: + resolution: {integrity: sha512-695XQBtp+UUYG50oREG9ujnRoeQU7xhwHDhT6ZAexm3Q+umdml1kjxcPoYRrS65crmaLlhVpjZHePJNzWOODnA==} + dev: true + /electron-to-chromium@1.4.591: resolution: {integrity: sha512-vLv/P7wwAPKQoY+CVMyyI6rsTp+A14KGtPXx92oz1FY41AAqa9l6Wkizcixg0LDuJgyeo8xgNN9+9hsnGp66UA==} dev: true @@ -4949,7 +5526,6 @@ packages: /entities@4.5.0: resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} engines: {node: '>=0.12'} - dev: false /error-ex@1.3.2: resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} @@ -5580,7 +6156,6 @@ packages: resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} engines: {node: '>=4'} hasBin: true - dev: false /esquery@1.5.0: resolution: {integrity: sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==} @@ -5620,7 +6195,6 @@ packages: /estree-walker@2.0.2: resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} - dev: false /estree-walker@3.0.3: resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} @@ -5662,6 +6236,13 @@ packages: engines: {node: '>=6'} dev: true + /expand-tilde@2.0.2: + resolution: {integrity: sha512-A5EmesHW6rfnZ9ysHQjPdJRni0SRar0tjtG5MNtm9n5TUvsYU8oozprtRD4AqHxcZWWlVuAmQo2nWKfN9oyjTw==} + engines: {node: '>=0.10.0'} + dependencies: + homedir-polyfill: 1.0.3 + dev: true + /expect-type@1.2.0: resolution: {integrity: sha512-80F22aiJ3GLyVnS/B3HzgR6RelZVumzj9jkL0Rhz4h0xYbNW9PjlQz5h3J/SShErbXBc295vseR4/MIbVmUbeA==} engines: {node: '>=12.0.0'} @@ -5712,6 +6293,10 @@ packages: type: 2.7.2 dev: false + /extend@3.0.2: + resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} + dev: false + /fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} dev: true @@ -5814,6 +6399,16 @@ packages: path-exists: 4.0.0 dev: true + /findup-sync@5.0.0: + resolution: {integrity: sha512-MzwXju70AuyflbgeOhzvQWAvvQdo1XL0A9bVvlXsYcFEBM87WR4OakL4OfZq+QRmr+duJubio+UtNQCPsVESzQ==} + engines: {node: '>= 10.13.0'} + dependencies: + detect-file: 1.0.0 + is-glob: 4.0.3 + micromatch: 4.0.8 + resolve-dir: 1.0.1 + dev: true + /flat-cache@3.2.0: resolution: {integrity: sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==} engines: {node: ^10.12.0 || >=12.0.0} @@ -5876,6 +6471,10 @@ packages: engines: {node: '>= 0.6'} dev: false + /fp-ts@2.5.0: + resolution: {integrity: sha512-xkC9ZKl/i2cU+8FAsdyLcTvPRXphp42FcK5WmZpB47VXb4gggC3DHlVDKNLdbC+U8zz6yp1b0bj0mZg0axmZYQ==} + dev: true + /fraction.js@4.3.7: resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==} dev: true @@ -5885,6 +6484,12 @@ packages: engines: {node: '>= 0.6'} dev: false + /fs-tree-structure@0.0.5: + resolution: {integrity: sha512-827ACYnAMC1DQRvhLUzZH0fCPhBJLo9P7WfxxwP4cibIzlrSzbD+Fh9W4FxFtSU+p9GlX0BoQUWLJ2LFJuoKuQ==} + dependencies: + lodash-es: 4.17.21 + dev: true + /fs.realpath@1.0.0: resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} dev: true @@ -5914,6 +6519,32 @@ packages: resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} dev: true + /gaxios@6.7.1: + resolution: {integrity: sha512-LDODD4TMYx7XXdpwxAVRAIAuB0bzv0s+ywFonY46k126qzQHT9ygyoa9tncmOiQmmDrik65UYsEkv3lbfqQ3yQ==} + engines: {node: '>=14'} + dependencies: + extend: 3.0.2 + https-proxy-agent: 7.0.6 + is-stream: 2.0.1 + node-fetch: 2.7.0 + uuid: 9.0.1 + transitivePeerDependencies: + - encoding + - supports-color + dev: false + + /gcp-metadata@6.1.1: + resolution: {integrity: sha512-a4tiq7E0/5fTjxPAaH4jpjkSv/uCaU2p5KC6HVGrvl0cDjA8iBZv4vv1gyzlmK0ZUKqwpOyQMKzZQe3lTit77A==} + engines: {node: '>=14'} + dependencies: + gaxios: 6.7.1 + google-logging-utils: 0.0.2 + json-bigint: 1.0.0 + transitivePeerDependencies: + - encoding + - supports-color + dev: false + /generic-pool@3.9.0: resolution: {integrity: sha512-hymDOu5B53XvN4QT9dBmZxPX4CWhBPPLguTZ9MMFeFa/Kg0xWVfylOVNlJji/E7yTZWFd/q9GO5TxDLq156D7g==} engines: {node: '>= 4'} @@ -5994,6 +6625,31 @@ packages: path-is-absolute: 1.0.1 dev: true + /global-modules@1.0.0: + resolution: {integrity: sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==} + engines: {node: '>=0.10.0'} + dependencies: + global-prefix: 1.0.2 + is-windows: 1.0.2 + resolve-dir: 1.0.1 + dev: true + + /global-prefix@1.0.2: + resolution: {integrity: sha512-5lsx1NUDHtSjfg0eHlmYvZKv8/nVqX4ckFbM+FrGcQ+04KWcWFo9P5MxPZYSzUvyzmdTbI7Eix8Q4IbELDqzKg==} + engines: {node: '>=0.10.0'} + dependencies: + expand-tilde: 2.0.2 + homedir-polyfill: 1.0.3 + ini: 1.3.8 + is-windows: 1.0.2 + which: 1.3.1 + dev: true + + /globals@11.12.0: + resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} + engines: {node: '>=4'} + dev: true + /globals@13.24.0: resolution: {integrity: sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==} engines: {node: '>=8'} @@ -6024,6 +6680,26 @@ packages: resolution: {integrity: sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==} dev: true + /google-auth-library@9.15.1: + resolution: {integrity: sha512-Jb6Z0+nvECVz+2lzSMt9u98UsoakXxA2HGHMCxh+so3n90XgYWkq5dur19JAJV7ONiJY22yBTyJB1TSkvPq9Ng==} + engines: {node: '>=14'} + dependencies: + base64-js: 1.5.1 + ecdsa-sig-formatter: 1.0.11 + gaxios: 6.7.1 + gcp-metadata: 6.1.1 + gtoken: 7.1.0 + jws: 4.0.0 + transitivePeerDependencies: + - encoding + - supports-color + dev: false + + /google-logging-utils@0.0.2: + resolution: {integrity: sha512-NEgUnEcBiP5HrPzufUkBzJOD/Sxsco3rLNo1F1TNf7ieU8ryUzBhqba8r756CjLX7rn3fHl6iLEwPYuqpoKgQQ==} + engines: {node: '>=14'} + dev: false + /gopd@1.0.1: resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==} dependencies: @@ -6036,6 +6712,22 @@ packages: resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} dev: true + /graphql@16.11.0: + resolution: {integrity: sha512-mS1lbMsxgQj6hge1XZ6p7GPhbrtFwUFYi3wRzXAC/FmYnyXMTvvI3td3rjmQ2u8ewXueaSvRPWaEcgVVOT9Jnw==} + engines: {node: ^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0} + dev: true + + /gtoken@7.1.0: + resolution: {integrity: sha512-pCcEwRi+TKpMlxAQObHDQ56KawURgyAf6jtIY046fJ5tIv3zDe/LEIubckAO8fj6JnAxLdmWkUfNyulQ2iKdEw==} + engines: {node: '>=14.0.0'} + dependencies: + gaxios: 6.7.1 + jws: 4.0.0 + transitivePeerDependencies: + - encoding + - supports-color + dev: false + /has-bigints@1.0.2: resolution: {integrity: sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==} dev: true @@ -6074,6 +6766,17 @@ packages: dependencies: function-bind: 1.1.2 + /headers-polyfill@4.0.3: + resolution: {integrity: sha512-IScLbePpkvO846sIwOtOTDjutRMWdXdJmXdMvk6gCBHxFO8d+QKOQedyZSxFTTFYRSmlgSTDtXqqq4pcenBXLQ==} + dev: true + + /homedir-polyfill@1.0.3: + resolution: {integrity: sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==} + engines: {node: '>=0.10.0'} + dependencies: + parse-passwd: 1.0.0 + dev: true + /hosted-git-info@2.8.9: resolution: {integrity: sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==} dev: true @@ -6089,6 +6792,16 @@ packages: toidentifier: 1.0.1 dev: false + /https-proxy-agent@7.0.6: + resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} + engines: {node: '>= 14'} + dependencies: + agent-base: 7.1.3 + debug: 4.4.0 + transitivePeerDependencies: + - supports-color + dev: false + /humanize-ms@1.2.1: resolution: {integrity: sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==} dependencies: @@ -6106,10 +6819,21 @@ packages: resolution: {integrity: sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==} dev: false + /ieee754@1.2.1: + resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} + dev: true + /ignore-by-default@1.0.1: resolution: {integrity: sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==} dev: true + /ignore-walk@6.0.5: + resolution: {integrity: sha512-VuuG0wCnjhnylG1ABXT3dAuIpTNDs/G8jlpmwXY03fXoXy/8ZK8/T+hMzt8L4WnrLCJgdybqgPagnF/f97cg3A==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + dependencies: + minimatch: 9.0.5 + dev: true + /ignore@5.3.0: resolution: {integrity: sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==} engines: {node: '>= 4'} @@ -6144,6 +6868,10 @@ packages: /inherits@2.0.4: resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + /ini@1.3.8: + resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} + dev: true + /internal-slot@1.0.6: resolution: {integrity: sha512-Xj6dv+PsbtwyPpEflsejS+oIZxmMlV44zAhG479uYu89MsjcYOhCFnNyKrkJrihbsiasQyY0afoCl/9BLR65bg==} engines: {node: '>= 0.4'} @@ -6153,6 +6881,14 @@ packages: side-channel: 1.0.4 dev: true + /io-ts@2.2.22(fp-ts@2.5.0): + resolution: {integrity: sha512-FHCCztTkHoV9mdBsHpocLpdTAfh956ZQcIkWQxxS0U5HT53vtrcuYdQneEJKH6xILaLNzXVl2Cvwtoy8XNN0AA==} + peerDependencies: + fp-ts: ^2.5.0 + dependencies: + fp-ts: 2.5.0 + dev: true + /ipaddr.js@1.9.1: resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} engines: {node: '>= 0.10'} @@ -6223,6 +6959,12 @@ packages: has-tostringtag: 1.0.0 dev: true + /is-docker@3.0.0: + resolution: {integrity: sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + hasBin: true + dev: true + /is-extglob@2.1.1: resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} engines: {node: '>=0.10.0'} @@ -6251,6 +6993,19 @@ packages: is-extglob: 2.1.1 dev: true + /is-inside-container@1.0.0: + resolution: {integrity: sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==} + engines: {node: '>=14.16'} + hasBin: true + dependencies: + is-docker: 3.0.0 + dev: true + + /is-interactive@2.0.0: + resolution: {integrity: sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ==} + engines: {node: '>=12'} + dev: true + /is-map@2.0.2: resolution: {integrity: sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==} dev: true @@ -6260,6 +7015,10 @@ packages: engines: {node: '>= 0.4'} dev: true + /is-node-process@1.2.0: + resolution: {integrity: sha512-Vg4o6/fqPxIjtxgUH5QLJhwZ7gW5diGCVlXpuUfELC62CuxM1iHcRe51f2W1FDy04Ai4KJkagKjx3XaqyfRKXw==} + dev: true + /is-number-object@1.0.7: resolution: {integrity: sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==} engines: {node: '>= 0.4'} @@ -6301,6 +7060,11 @@ packages: call-bind: 1.0.5 dev: true + /is-stream@2.0.1: + resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} + engines: {node: '>=8'} + dev: false + /is-string@1.0.7: resolution: {integrity: sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==} engines: {node: '>= 0.4'} @@ -6325,6 +7089,11 @@ packages: resolution: {integrity: sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==} dev: false + /is-unicode-supported@1.3.0: + resolution: {integrity: sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==} + engines: {node: '>=12'} + dev: true + /is-weakmap@2.0.1: resolution: {integrity: sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==} dev: true @@ -6342,6 +7111,18 @@ packages: get-intrinsic: 1.2.2 dev: true + /is-windows@1.0.2: + resolution: {integrity: sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==} + engines: {node: '>=0.10.0'} + dev: true + + /is-wsl@3.1.0: + resolution: {integrity: sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==} + engines: {node: '>=16'} + dependencies: + is-inside-container: 1.0.0 + dev: true + /isarray@1.0.0: resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} dev: false @@ -6409,7 +7190,6 @@ packages: dependencies: argparse: 1.0.10 esprima: 4.0.1 - dev: false /js-yaml@4.1.0: resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} @@ -6417,6 +7197,18 @@ packages: dependencies: argparse: 2.0.1 + /jsesc@3.1.0: + resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} + engines: {node: '>=6'} + hasBin: true + dev: true + + /json-bigint@1.0.0: + resolution: {integrity: sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==} + dependencies: + bignumber.js: 9.3.0 + dev: false + /json-buffer@3.0.1: resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} dev: true @@ -6425,6 +7217,10 @@ packages: resolution: {integrity: sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==} dev: true + /json-parse-even-better-errors@2.3.1: + resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} + dev: true + /json-schema-traverse@0.4.1: resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} dev: true @@ -6444,6 +7240,12 @@ packages: minimist: 1.2.8 dev: true + /json5@2.2.3: + resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} + engines: {node: '>=6'} + hasBin: true + dev: true + /jsondiffpatch@0.6.0: resolution: {integrity: sha512-3QItJOXp2AP1uv7waBkao5nCvhEv+QmJAd38Ybq7wNI74Q+BBmnLn4EDKz6yI9xGAIQoUF87qHt+kc1IVxB4zQ==} engines: {node: ^18.0.0 || >=20.0.0} @@ -6488,6 +7290,14 @@ packages: safe-buffer: 5.2.1 dev: false + /jwa@2.0.1: + resolution: {integrity: sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==} + dependencies: + buffer-equal-constant-time: 1.0.1 + ecdsa-sig-formatter: 1.0.11 + safe-buffer: 5.2.1 + dev: false + /jws@3.2.2: resolution: {integrity: sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==} dependencies: @@ -6495,12 +7305,24 @@ packages: safe-buffer: 5.2.1 dev: false + /jws@4.0.0: + resolution: {integrity: sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==} + dependencies: + jwa: 2.0.1 + safe-buffer: 5.2.1 + dev: false + /keyv@4.5.4: resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} dependencies: json-buffer: 3.0.1 dev: true + /kleur@4.1.5: + resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==} + engines: {node: '>=6'} + dev: true + /language-subtag-registry@0.3.22: resolution: {integrity: sha512-tN0MCzyWnoz/4nHS6uxdlFWoUZT7ABptwKPQ52Ea7URk6vll88bWBVhodtnlfEuCcKWNGoc+uGbw1cwa9IKh/w==} dev: true @@ -6560,6 +7382,10 @@ packages: p-locate: 5.0.0 dev: true + /lodash-es@4.17.21: + resolution: {integrity: sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==} + dev: true + /lodash.includes@4.3.0: resolution: {integrity: sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==} dev: false @@ -6568,6 +7394,11 @@ packages: resolution: {integrity: sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==} dev: false + /lodash.isequal@4.5.0: + resolution: {integrity: sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==} + deprecated: This package is deprecated. Use require('node:util').isDeepStrictEqual instead. + dev: true + /lodash.isinteger@4.0.4: resolution: {integrity: sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==} dev: false @@ -6595,6 +7426,22 @@ packages: resolution: {integrity: sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==} dev: true + /lodash.uniqwith@4.5.0: + resolution: {integrity: sha512-7lYL8bLopMoy4CTICbxygAUq6CdRJ36vFc80DucPueUee+d5NBRxz3FdT9Pes/HEx5mPoT9jwnsEJWz1N7uq7Q==} + dev: true + + /lodash@4.17.21: + resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + dev: true + + /log-symbols@5.1.0: + resolution: {integrity: sha512-l0x2DvrW294C9uDCoQe1VSU4gf529FkSZ6leBl4TiqZH/e+0R7hSfHQBNut2mNygDgHwvYHfFLn6Oxb3VWj2rA==} + engines: {node: '>=12'} + dependencies: + chalk: 5.3.0 + is-unicode-supported: 1.3.0 + dev: true + /loose-envify@1.4.0: resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} hasBin: true @@ -6627,6 +7474,13 @@ packages: dependencies: '@jridgewell/sourcemap-codec': 1.5.0 + /matchit@1.1.0: + resolution: {integrity: sha512-+nGYoOlfHmxe5BW5tE0EMJppXEwdSf8uBA1GTZC7Q77kbT35+VKLYJMzVNWCHSsga1ps1tPYFtFyvxvKzWVmMA==} + engines: {node: '>=6'} + dependencies: + '@arr/every': 1.0.1 + dev: true + /mdn-data@2.0.30: resolution: {integrity: sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==} dev: false @@ -6650,6 +7504,11 @@ packages: engines: {node: '>= 8'} dev: true + /meriyah@4.5.0: + resolution: {integrity: sha512-Rbiu0QPIxTXgOXwiIpRVJfZRQ2FWyfzYrOGBs9SN5RbaXg1CN5ELn/plodwWwluX93yzc4qO/bNIen1ThGFCxw==} + engines: {node: '>=10.4.0'} + dev: true + /methods@1.1.2: resolution: {integrity: sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==} engines: {node: '>= 0.6'} @@ -6674,7 +7533,6 @@ packages: /mime-db@1.52.0: resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} engines: {node: '>= 0.6'} - dev: false /mime-types@2.1.35: resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} @@ -6695,6 +7553,11 @@ packages: hasBin: true dev: true + /mimic-fn@2.1.0: + resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} + engines: {node: '>=6'} + dev: true + /miniflare@3.20250129.0: resolution: {integrity: sha512-qYlGEjMl/2kJdgNaztj4hpA64d6Dl79Lx/NL61p/v5XZRiWanBOTgkQqdPxCKZOj6KQnioqhC7lfd6jDXKSs2A==} engines: {node: '>=16.13'} @@ -6722,6 +7585,13 @@ packages: brace-expansion: 1.1.11 dev: true + /minimatch@7.4.6: + resolution: {integrity: sha512-sBz8G/YjVniEz6lKPNpKxXwazJe4c19fEfV2GDMX6AjFz+MX9uDWIZW8XreVhkFW3fkIdTv/gxWr/Kks5FFAVw==} + engines: {node: '>=10'} + dependencies: + brace-expansion: 2.0.1 + dev: true + /minimatch@9.0.4: resolution: {integrity: sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==} engines: {node: '>=16 || 14 >=14.17'} @@ -6753,9 +7623,13 @@ packages: ufo: 1.5.4 dev: true + /mrmime@2.0.1: + resolution: {integrity: sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==} + engines: {node: '>=10'} + dev: true + /ms@2.0.0: resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} - dev: false /ms@2.1.2: resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} @@ -6764,10 +7638,60 @@ packages: /ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + /msw@2.8.4(@types/node@20.10.5)(typescript@5.5.4): + resolution: {integrity: sha512-GLU8gx0o7RBG/3x/eTnnLd5S5ZInxXRRRMN8GJwaPZ4jpJTxzQfWGvwr90e8L5dkKJnz+gT4gQYCprLy/c4kVw==} + engines: {node: '>=18'} + hasBin: true + requiresBuild: true + peerDependencies: + typescript: '>= 4.8.x' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@bundled-es-modules/cookie': 2.0.1 + '@bundled-es-modules/statuses': 1.0.1 + '@bundled-es-modules/tough-cookie': 0.1.6 + '@inquirer/confirm': 5.1.12(@types/node@20.10.5) + '@mswjs/interceptors': 0.37.6 + '@open-draft/deferred-promise': 2.2.0 + '@open-draft/until': 2.1.0 + '@types/cookie': 0.6.0 + '@types/statuses': 2.0.5 + graphql: 16.11.0 + headers-polyfill: 4.0.3 + is-node-process: 1.2.0 + outvariant: 1.4.3 + path-to-regexp: 6.3.0 + picocolors: 1.1.1 + strict-event-emitter: 0.5.1 + type-fest: 4.41.0 + typescript: 5.5.4 + yargs: 17.7.2 + transitivePeerDependencies: + - '@types/node' + dev: true + + /multimatch@5.0.0: + resolution: {integrity: sha512-ypMKuglUrZUD99Tk2bUQ+xNQj43lPEfAeX2o9cTteAmShXy2VHDJpuwu1o0xqoKCt9jLVAvwyFKdLTPXKAfJyA==} + engines: {node: '>=10'} + dependencies: + '@types/minimatch': 3.0.5 + array-differ: 3.0.0 + array-union: 2.1.0 + arrify: 2.0.1 + minimatch: 3.1.2 + dev: true + /mustache@4.2.0: resolution: {integrity: sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==} hasBin: true + /mute-stream@2.0.0: + resolution: {integrity: sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA==} + engines: {node: ^18.17.0 || >=20.5.0} + dev: true + /mz@2.7.0: resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} dependencies: @@ -6780,7 +7704,6 @@ packages: resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true - dev: false /nanoid@3.3.6: resolution: {integrity: sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==} @@ -6807,6 +7730,11 @@ packages: engines: {node: '>= 0.6'} dev: false + /negotiator@0.6.4: + resolution: {integrity: sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==} + engines: {node: '>= 0.6'} + dev: true + /next-tick@1.1.0: resolution: {integrity: sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==} dev: false @@ -6857,6 +7785,10 @@ packages: resolution: {integrity: sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==} dev: true + /node-addon-api@7.1.1: + resolution: {integrity: sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==} + dev: true + /node-domexception@1.0.0: resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==} engines: {node: '>=10.5.0'} @@ -7023,12 +7955,24 @@ packages: ee-first: 1.1.1 dev: false + /on-headers@1.0.2: + resolution: {integrity: sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==} + engines: {node: '>= 0.8'} + dev: true + /once@1.4.0: resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} dependencies: wrappy: 1.0.2 dev: true + /onetime@5.1.2: + resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} + engines: {node: '>=6'} + dependencies: + mimic-fn: 2.1.0 + dev: true + /openai@4.51.0: resolution: {integrity: sha512-UKuWc3/qQyklqhHM8CbdXCv0Z0obap6T0ECdcO5oATQxAbKE5Ky3YCXFQY207z+eGG6ez4U9wvAcuMygxhmStg==} hasBin: true @@ -7099,6 +8043,25 @@ packages: word-wrap: 1.2.5 dev: true + /ora@6.3.1: + resolution: {integrity: sha512-ERAyNnZOfqM+Ao3RAvIXkYh5joP220yf59gVe2X/cI6SiCxIdi4c9HZKZD8R6q/RDXEje1THBju6iExiSsgJaQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + chalk: 5.3.0 + cli-cursor: 4.0.0 + cli-spinners: 2.9.2 + is-interactive: 2.0.0 + is-unicode-supported: 1.3.0 + log-symbols: 5.1.0 + stdin-discarder: 0.1.0 + strip-ansi: 7.1.0 + wcwidth: 1.0.1 + dev: true + + /outvariant@1.4.3: + resolution: {integrity: sha512-+Sl2UErvtsoajRDKCE5/dBz4DIvHXQQnAxtQTF04OJxY0+DyZXSo5P5Bb7XYWOh81syohlYL24hbDwxedPUJCA==} + dev: true + /p-limit@3.1.0: resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} engines: {node: '>=10'} @@ -7120,6 +8083,11 @@ packages: callsites: 3.1.0 dev: true + /parse-gitignore@2.0.0: + resolution: {integrity: sha512-RmVuCHWsfu0QPNW+mraxh/xjQVw/lhUCUru8Zni3Ctq3AoMhpDTq0OVdKS6iesd6Kqb7viCV3isAL43dciOSog==} + engines: {node: '>=14'} + dev: true + /parse-json@4.0.0: resolution: {integrity: sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==} engines: {node: '>=4'} @@ -7128,6 +8096,21 @@ packages: json-parse-better-errors: 1.0.2 dev: true + /parse-json@5.2.0: + resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} + engines: {node: '>=8'} + dependencies: + '@babel/code-frame': 7.27.1 + error-ex: 1.3.2 + json-parse-even-better-errors: 2.3.1 + lines-and-columns: 1.2.4 + dev: true + + /parse-passwd@1.0.0: + resolution: {integrity: sha512-1Y1A//QUXEZK7YKz+rD9WydcE1+EuPr6ZBgKecAB8tmoW6UFv0NREVJe1p+jRxtThkcbbKkfwIbWJe/IeE6m2Q==} + engines: {node: '>=0.10.0'} + dev: true + /parseurl@1.3.3: resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} engines: {node: '>= 0.8'} @@ -7208,6 +8191,7 @@ packages: /picocolors@1.0.1: resolution: {integrity: sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==} + dev: true /picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} @@ -7251,11 +8235,24 @@ packages: pathe: 2.0.2 dev: true + /please-upgrade-node@3.2.0: + resolution: {integrity: sha512-gQR3WpIgNIKwBMVLkpMUeR3e1/E1y42bqDQZfql+kDeXd8COYfM8PQA4X6y7a8u9Ua9FHmsrrmirW2vHs45hWg==} + dependencies: + semver-compare: 1.0.0 + dev: true + /pluralize@8.0.0: resolution: {integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==} engines: {node: '>=4'} dev: false + /polka@0.5.2: + resolution: {integrity: sha512-FVg3vDmCqP80tOrs+OeNlgXYmFppTXdjD5E7I4ET1NjvtNmQrb1/mJibybKkb/d4NA7YWAr1ojxuhpL3FHqdlw==} + dependencies: + '@polka/url': 0.5.0 + trouter: 2.0.1 + dev: true + /postcss-import@14.1.0(postcss@8.4.38): resolution: {integrity: sha512-flwI+Vgm4SElObFVPpTIT7SU7R3qk2L7PyduMcokiaVKuWv9d/U+Gm/QAd8NDLuykTWTkcrjOeD2Pp1rMeBTGw==} engines: {node: '>=10.0.0'} @@ -7343,7 +8340,7 @@ packages: engines: {node: ^10 || ^12 || >=14} dependencies: nanoid: 3.3.7 - picocolors: 1.0.1 + picocolors: 1.1.1 source-map-js: 1.2.0 dev: false @@ -7372,7 +8369,6 @@ packages: nanoid: 3.3.11 picocolors: 1.1.1 source-map-js: 1.2.1 - dev: false /prelude-ls@1.2.1: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} @@ -7403,6 +8399,12 @@ packages: resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} dev: false + /psl@1.15.0: + resolution: {integrity: sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w==} + dependencies: + punycode: 2.3.1 + dev: true + /pstree.remy@1.1.8: resolution: {integrity: sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==} dev: true @@ -7416,6 +8418,11 @@ packages: engines: {node: '>=6'} dev: true + /punycode@2.3.1: + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} + engines: {node: '>=6'} + dev: true + /qs@6.11.0: resolution: {integrity: sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==} engines: {node: '>=0.6'} @@ -7429,6 +8436,10 @@ packages: deprecated: The querystring API is considered Legacy. new code should use the URLSearchParams API instead. dev: false + /querystringify@2.2.0: + resolution: {integrity: sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==} + dev: true + /queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} dev: true @@ -7489,6 +8500,15 @@ packages: path-type: 3.0.0 dev: true + /readable-stream@3.6.2: + resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} + engines: {node: '>= 6'} + dependencies: + inherits: 2.0.4 + string_decoder: 1.3.0 + util-deprecate: 1.0.2 + dev: true + /readdirp@3.6.0: resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} engines: {node: '>=8.10.0'} @@ -7542,6 +8562,22 @@ packages: engines: {node: '>=0.10.0'} dev: true + /require-package-name@2.0.1: + resolution: {integrity: sha512-uuoJ1hU/k6M0779t3VMVIYpb2VMJk05cehCaABFhXaibcbvfgR8wKiozLjVFSzJPmQMRqIcO0HMyTFqfV09V6Q==} + dev: true + + /requires-port@1.0.0: + resolution: {integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==} + dev: true + + /resolve-dir@1.0.1: + resolution: {integrity: sha512-R7uiTjECzvOsWSfdM0QKFNBVFcK27aHOUwdvK53BcW8zqnGdYp0Fbj82cy54+2A4P2tFM22J5kRfe1R+lM/1yg==} + engines: {node: '>=0.10.0'} + dependencies: + expand-tilde: 2.0.2 + global-modules: 1.0.0 + dev: true + /resolve-from@4.0.0: resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} engines: {node: '>=4'} @@ -7574,6 +8610,14 @@ packages: supports-preserve-symlinks-flag: 1.0.0 dev: true + /restore-cursor@4.0.0: + resolution: {integrity: sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + onetime: 5.1.2 + signal-exit: 3.0.7 + dev: true + /reusify@1.0.4: resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} engines: {iojs: '>=1.0.0', node: '>=0.10.0'} @@ -7681,7 +8725,6 @@ packages: /safe-buffer@5.2.1: resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} - dev: false /safe-regex-test@1.0.0: resolution: {integrity: sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==} @@ -7709,6 +8752,10 @@ packages: resolution: {integrity: sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw==} dev: false + /semver-compare@1.0.0: + resolution: {integrity: sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==} + dev: true + /semver@5.7.2: resolution: {integrity: sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==} hasBin: true @@ -7846,6 +8893,10 @@ packages: resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} dev: true + /signal-exit@3.0.7: + resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} + dev: true + /signal-exit@4.1.0: resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} engines: {node: '>=14'} @@ -7868,6 +8919,53 @@ packages: semver: 7.5.4 dev: true + /sirv@2.0.4: + resolution: {integrity: sha512-94Bdh3cC2PKrbgSOUqTiGPWVZeSiXfKOVZNJniWoqrWrRkB1CJzBU3NEbiTsPcYy1lDsANA/THzS+9WBiy5nfQ==} + engines: {node: '>= 10'} + dependencies: + '@polka/url': 1.0.0-next.29 + mrmime: 2.0.1 + totalist: 3.0.1 + dev: true + + /skott-webapp@2.3.0: + resolution: {integrity: sha512-nmt+ilxGOqX5zN2WDKv1Y5gLfxy/lceHgbB8HM/ym/Cm8572ypD1s2S+pcN+jOw13xqoavHJPonX1WT2QvkpDg==} + dependencies: + digraph-js: 2.2.3 + dev: true + + /skott@0.35.4: + resolution: {integrity: sha512-z6Ww+Z+TdLO1Z1HXiW9iltburLEWkapxk2MkI+8UQGsJ7d1HiO0dj7ZI0Q/kV/nwbOaOZyRUgMO7hj1/d8h8hw==} + hasBin: true + dependencies: + '@parcel/watcher': 2.5.1 + '@typescript-eslint/typescript-estree': 7.13.1(typescript@5.4.5) + commander: 11.1.0 + compression: 1.8.0 + depcheck: 1.4.7 + digraph-js: 2.2.3 + effect: 3.3.2 + estree-walker: 3.0.3 + fp-ts: 2.5.0 + fs-tree-structure: 0.0.5 + ignore-walk: 6.0.5 + io-ts: 2.2.22(fp-ts@2.5.0) + is-wsl: 3.1.0 + json5: 2.2.3 + kleur: 4.1.5 + lodash-es: 4.17.21 + meriyah: 4.5.0 + minimatch: 9.0.5 + ora: 6.3.1 + parse-gitignore: 2.0.0 + polka: 0.5.2 + sirv: 2.0.4 + skott-webapp: 2.3.0 + typescript: 5.4.5 + transitivePeerDependencies: + - supports-color + dev: true + /slash@3.0.0: resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} engines: {node: '>=8'} @@ -7952,7 +9050,6 @@ packages: /sprintf-js@1.0.3: resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} - dev: false /sswr@2.0.0(svelte@4.2.19): resolution: {integrity: sha512-mV0kkeBHcjcb0M5NqKtKVg/uTIYNlIIniyDfSGrSfxpEdM9C365jK0z55pl9K0xAkNTJi2OAOVFQpgMPUk+V0w==} @@ -7986,12 +9083,18 @@ packages: /statuses@2.0.1: resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==} engines: {node: '>= 0.8'} - dev: false /std-env@3.8.1: resolution: {integrity: sha512-vj5lIj3Mwf9D79hBkltk5qmkFI+biIKWS2IBxEyEU3AX1tUf7AoL8nSazCOiiqQsGKIq01SClsKEzweu34uwvA==} dev: true + /stdin-discarder@0.1.0: + resolution: {integrity: sha512-xhV7w8S+bUwlPTb4bAOUQhv8/cSS5offJuX8GQGq32ONF0ZtDWKfkdomM3HMRA+LhX6um/FZ0COqlwsjD53LeQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + bl: 5.1.0 + dev: true + /stoppable@1.1.0: resolution: {integrity: sha512-KXDYZ9dszj6bzvnEMRYvxgeTHU74QBFL54XKtP3nyMuJ81CFYtABZ3bAzL2EdFUaEwJOBOgENyFj3R7oTzDyyw==} engines: {node: '>=4', npm: '>=6'} @@ -8002,6 +9105,10 @@ packages: engines: {node: '>=10.0.0'} dev: false + /strict-event-emitter@0.5.1: + resolution: {integrity: sha512-vMgjE/GGEPEFnhFub6pa4FmJBRBVOLpIII2hvCZ8Kzb7K0hlHo7mQv6xYrBvCL2LtAIBwFUK8wvuJgTVSQ5MFQ==} + dev: true + /string-width@4.2.3: resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} engines: {node: '>=8'} @@ -8067,6 +9174,12 @@ packages: es-abstract: 1.22.3 dev: true + /string_decoder@1.3.0: + resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} + dependencies: + safe-buffer: 5.2.1 + dev: true + /strip-ansi@6.0.1: resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} engines: {node: '>=8'} @@ -8222,7 +9335,7 @@ packages: peerDependencies: vue: '>=3.2.26 < 4' dependencies: - vue: 3.5.13(typescript@5.5.4) + vue: 3.5.13(typescript@5.3.3) dev: false /tailwindcss@3.2.7(postcss@8.4.38): @@ -8328,6 +9441,11 @@ packages: engines: {node: '>=0.6'} dev: false + /totalist@3.0.1: + resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==} + engines: {node: '>=6'} + dev: true + /touch@3.1.0: resolution: {integrity: sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==} hasBin: true @@ -8335,6 +9453,16 @@ packages: nopt: 1.0.10 dev: true + /tough-cookie@4.1.4: + resolution: {integrity: sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==} + engines: {node: '>=6'} + dependencies: + psl: 1.15.0 + punycode: 2.1.1 + universalify: 0.2.0 + url-parse: 1.5.10 + dev: true + /tr46@0.0.3: resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} dev: false @@ -8350,6 +9478,13 @@ packages: hasBin: true dev: true + /trouter@2.0.1: + resolution: {integrity: sha512-kr8SKKw94OI+xTGOkfsvwZQ8mWoikZDd2n8XZHjJVZUARZT+4/VV6cacRS6CLsH9bNm+HFIPU1Zx4CnNnb4qlQ==} + engines: {node: '>=6'} + dependencies: + matchit: 1.1.0 + dev: true + /ts-api-utils@1.0.3(typescript@4.7.4): resolution: {integrity: sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg==} engines: {node: '>=16.13.0'} @@ -8359,6 +9494,15 @@ packages: typescript: 4.7.4 dev: true + /ts-api-utils@1.4.3(typescript@5.4.5): + resolution: {integrity: sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw==} + engines: {node: '>=16'} + peerDependencies: + typescript: '>=4.2.0' + dependencies: + typescript: 5.4.5 + dev: true + /ts-api-utils@2.0.0(typescript@5.5.4): resolution: {integrity: sha512-xCt/TOAc+EOHS1XPnijD3/yzpH6qg2xppZO1YDqGoVsNXfQfzHpOdNuXwrwOU8u4ITXJyDCTyt8w5g1sZv9ynQ==} engines: {node: '>=18.12'} @@ -8381,17 +9525,6 @@ packages: resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} dev: true - /tsconfck@3.1.4: - resolution: {integrity: sha512-kdqWFGVJqe+KGYvlSO9NIaWn9jT1Ny4oKVzAJsKii5eoE9snzTJzL4+MMVOMn+fikWGFmKEylcXL710V/kIPJQ==} - engines: {node: ^18 || >=20} - hasBin: true - peerDependencies: - typescript: ^5.0.0 - peerDependenciesMeta: - typescript: - optional: true - dev: true - /tsconfck@3.1.4(typescript@5.5.4): resolution: {integrity: sha512-kdqWFGVJqe+KGYvlSO9NIaWn9jT1Ny4oKVzAJsKii5eoE9snzTJzL4+MMVOMn+fikWGFmKEylcXL710V/kIPJQ==} engines: {node: ^18 || >=20} @@ -8636,6 +9769,16 @@ packages: engines: {node: '>=10'} dev: true + /type-fest@0.21.3: + resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==} + engines: {node: '>=10'} + dev: true + + /type-fest@4.41.0: + resolution: {integrity: sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==} + engines: {node: '>=16'} + dev: true + /type-is@1.6.18: resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==} engines: {node: '>= 0.6'} @@ -8707,6 +9850,12 @@ packages: engines: {node: '>=14.17'} hasBin: true + /typescript@5.4.5: + resolution: {integrity: sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==} + engines: {node: '>=14.17'} + hasBin: true + dev: true + /typescript@5.5.4: resolution: {integrity: sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==} engines: {node: '>=14.17'} @@ -8749,6 +9898,11 @@ packages: ufo: 1.5.4 dev: true + /universalify@0.2.0: + resolution: {integrity: sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==} + engines: {node: '>= 4.0.0'} + dev: true + /unpipe@1.0.0: resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} engines: {node: '>= 0.8'} @@ -8771,6 +9925,13 @@ packages: punycode: 2.1.1 dev: true + /url-parse@1.5.10: + resolution: {integrity: sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==} + dependencies: + querystringify: 2.2.0 + requires-port: 1.0.0 + dev: true + /url@0.10.3: resolution: {integrity: sha512-hzSUW2q06EqL1gKM/a+obYHLIO6ct2hwPuviqTTOcfFVc61UbfJ2Q32+uGL/HCPxKqrdGB5QUwIe7UqlDgwsOQ==} dependencies: @@ -8833,29 +9994,6 @@ packages: /vary@1.1.2: resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} engines: {node: '>= 0.8'} - dev: false - - /vite-node@2.1.9: - resolution: {integrity: sha512-AM9aQ/IPrW/6ENLQg3AGY4K1N2TGZdR5e4gu/MmmR2xR3Ll1+dib+nook92g4TV3PXVyeyxdWwtaCAiUL0hMxA==} - engines: {node: ^18.0.0 || >=20.0.0} - hasBin: true - dependencies: - cac: 6.7.14 - debug: 4.4.0 - es-module-lexer: 1.6.0 - pathe: 1.1.2 - vite: 5.4.10 - transitivePeerDependencies: - - '@types/node' - - less - - lightningcss - - sass - - sass-embedded - - stylus - - sugarss - - supports-color - - terser - dev: true /vite-node@2.1.9(@types/node@20.10.5): resolution: {integrity: sha512-AM9aQ/IPrW/6ENLQg3AGY4K1N2TGZdR5e4gu/MmmR2xR3Ll1+dib+nook92g4TV3PXVyeyxdWwtaCAiUL0hMxA==} @@ -8879,22 +10017,6 @@ packages: - terser dev: true - /vite-tsconfig-paths@4.3.2: - resolution: {integrity: sha512-0Vd/a6po6Q+86rPlntHye7F31zA2URZMbH8M3saAZ/xR9QoGN/L21bxEGfXdWmFdNkqPpRdxFT7nmNe12e9/uA==} - peerDependencies: - vite: '*' - peerDependenciesMeta: - vite: - optional: true - dependencies: - debug: 4.3.7 - globrex: 0.1.2 - tsconfck: 3.1.4 - transitivePeerDependencies: - - supports-color - - typescript - dev: true - /vite-tsconfig-paths@4.3.2(typescript@5.5.4): resolution: {integrity: sha512-0Vd/a6po6Q+86rPlntHye7F31zA2URZMbH8M3saAZ/xR9QoGN/L21bxEGfXdWmFdNkqPpRdxFT7nmNe12e9/uA==} peerDependencies: @@ -8911,44 +10033,6 @@ packages: - typescript dev: true - /vite@5.4.10: - resolution: {integrity: sha512-1hvaPshuPUtxeQ0hsVH3Mud0ZanOLwVTneA1EgbAM5LhaZEqyPWGRQ7BtaMvUrTDeEaC8pxtj6a6jku3x4z6SQ==} - engines: {node: ^18.0.0 || >=20.0.0} - hasBin: true - peerDependencies: - '@types/node': ^18.0.0 || >=20.0.0 - less: '*' - lightningcss: ^1.21.0 - sass: '*' - sass-embedded: '*' - stylus: '*' - sugarss: '*' - terser: ^5.4.0 - peerDependenciesMeta: - '@types/node': - optional: true - less: - optional: true - lightningcss: - optional: true - sass: - optional: true - sass-embedded: - optional: true - stylus: - optional: true - sugarss: - optional: true - terser: - optional: true - dependencies: - esbuild: 0.21.5 - postcss: 8.5.1 - rollup: 4.24.0 - optionalDependencies: - fsevents: 2.3.3 - dev: true - /vite@5.4.10(@types/node@20.10.5): resolution: {integrity: sha512-1hvaPshuPUtxeQ0hsVH3Mud0ZanOLwVTneA1EgbAM5LhaZEqyPWGRQ7BtaMvUrTDeEaC8pxtj6a6jku3x4z6SQ==} engines: {node: ^18.0.0 || >=20.0.0} @@ -8988,64 +10072,7 @@ packages: fsevents: 2.3.3 dev: true - /vitest@2.1.9: - resolution: {integrity: sha512-MSmPM9REYqDGBI8439mA4mWhV5sKmDlBKWIYbA3lRb2PTHACE0mgKwA8yQ2xq9vxDTuk4iPrECBAEW2aoFXY0Q==} - engines: {node: ^18.0.0 || >=20.0.0} - hasBin: true - peerDependencies: - '@edge-runtime/vm': '*' - '@types/node': ^18.0.0 || >=20.0.0 - '@vitest/browser': 2.1.9 - '@vitest/ui': 2.1.9 - happy-dom: '*' - jsdom: '*' - peerDependenciesMeta: - '@edge-runtime/vm': - optional: true - '@types/node': - optional: true - '@vitest/browser': - optional: true - '@vitest/ui': - optional: true - happy-dom: - optional: true - jsdom: - optional: true - dependencies: - '@vitest/expect': 2.1.9 - '@vitest/mocker': 2.1.9(vite@5.4.10) - '@vitest/pretty-format': 2.1.9 - '@vitest/runner': 2.1.9 - '@vitest/snapshot': 2.1.9 - '@vitest/spy': 2.1.9 - '@vitest/utils': 2.1.9 - chai: 5.1.2 - debug: 4.4.0 - expect-type: 1.2.0 - magic-string: 0.30.17 - pathe: 1.1.2 - std-env: 3.8.1 - tinybench: 2.9.0 - tinyexec: 0.3.1 - tinypool: 1.0.1 - tinyrainbow: 1.2.0 - vite: 5.4.10 - vite-node: 2.1.9 - why-is-node-running: 2.3.0 - transitivePeerDependencies: - - less - - lightningcss - - msw - - sass - - sass-embedded - - stylus - - sugarss - - supports-color - - terser - dev: true - - /vitest@2.1.9(@types/node@20.10.5): + /vitest@2.1.9(@types/node@20.10.5)(msw@2.8.4): resolution: {integrity: sha512-MSmPM9REYqDGBI8439mA4mWhV5sKmDlBKWIYbA3lRb2PTHACE0mgKwA8yQ2xq9vxDTuk4iPrECBAEW2aoFXY0Q==} engines: {node: ^18.0.0 || >=20.0.0} hasBin: true @@ -9072,7 +10099,7 @@ packages: dependencies: '@types/node': 20.10.5 '@vitest/expect': 2.1.9 - '@vitest/mocker': 2.1.9(vite@5.4.10) + '@vitest/mocker': 2.1.9(msw@2.8.4)(vite@5.4.10) '@vitest/pretty-format': 2.1.9 '@vitest/runner': 2.1.9 '@vitest/snapshot': 2.1.9 @@ -9143,6 +10170,12 @@ packages: graceful-fs: 4.2.11 dev: false + /wcwidth@1.0.1: + resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==} + dependencies: + defaults: 1.0.4 + dev: true + /web-streams-polyfill@3.2.1: resolution: {integrity: sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==} engines: {node: '>= 8'} @@ -9310,6 +10343,15 @@ packages: - utf-8-validate dev: true + /wrap-ansi@6.2.0: + resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==} + engines: {node: '>=8'} + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + dev: true + /wrap-ansi@7.0.0: resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} engines: {node: '>=10'} @@ -9386,11 +10428,29 @@ packages: hasBin: true dev: false + /yargs-parser@20.2.9: + resolution: {integrity: sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==} + engines: {node: '>=10'} + dev: true + /yargs-parser@21.1.1: resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} engines: {node: '>=12'} dev: true + /yargs@16.2.0: + resolution: {integrity: sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==} + engines: {node: '>=10'} + dependencies: + cliui: 7.0.4 + escalade: 3.1.1 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + string-width: 4.2.3 + y18n: 5.0.8 + yargs-parser: 20.2.9 + dev: true + /yargs@17.7.2: resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} engines: {node: '>=12'} @@ -9409,6 +10469,11 @@ packages: engines: {node: '>=10'} dev: true + /yoctocolors-cjs@2.1.2: + resolution: {integrity: sha512-cYVsTjKl8b+FrnidjibDWskAv7UKOfcwaVZdp/it9n1s9fU3IkgDbhdIRKCW4JDsAlECJY0ytoVPT3sK6kideA==} + engines: {node: '>=18'} + dev: true + /youch@3.3.4: resolution: {integrity: sha512-UeVBXie8cA35DS6+nBkls68xaBBXCye0CNznrhszZjTbRVnJKQuNsyLKBTTL4ln1o1rh2PKtv35twV7irj5SEg==} dependencies: diff --git a/vitest.config.js b/vitest.config.js index fed4d6c0..d38e8f1c 100644 --- a/vitest.config.js +++ b/vitest.config.js @@ -4,6 +4,7 @@ const config = { plugins: [tsconfigPaths()], test: { exclude: ["**/node_modules/**"], + testTimeout: 30_000, }, }; export default config;