├── CHANGELOG.md ├── .gitignore ├── turbo.json ├── tsconfig ├── package.json ├── react-library.json ├── ts-library.json └── base.json ├── tsup.config.ts ├── tsconfig.json ├── vitest.node.config.mjs ├── vitest.edge.config.mjs ├── src ├── common │ ├── ollama-config.ts │ └── get-response-metadata.ts ├── index.ts ├── adaptors │ ├── map-ollama-finish-reason.ts │ ├── ollama-chat-prompt.ts │ ├── convert-to-ollama-completion-prompt.ts │ └── convert-to-ollama-chat-messages.ts ├── responses │ ├── map-ollama-responses-finish-reason.ts │ ├── ollama-responses-api-types.ts │ ├── ollama-responses-prepare-tools.ts │ ├── test-helpers │ │ └── ollama-test-helpers.ts │ ├── ollama-responses-language-model.ts │ ├── ollama-responses-processor.ts │ ├── ollama-responses-request-builder.ts │ ├── convert-to-ollama-responses-messages.ts │ ├── ollama-responses-language-model.test.ts │ └── ollama-responses-stream-processor.ts ├── embedding │ ├── __snapshots__ │ │ └── ollama-embedding-model.test.ts.snap │ ├── ollama-embedding-settings.ts │ ├── ollama-embedding-model.ts │ └── ollama-embedding-model.test.ts ├── completion │ ├── ollama-error.ts │ ├── ollama-completion-settings.ts │ ├── ollama-error.test.ts │ └── ollama-completion-language-model.ts ├── ollama-chat-settings.ts └── ollama-provider.ts ├── .github ├── dependabot.yml └── workflows │ ├── release.yml │ └── test.yml ├── package.json ├── README.md ├── LICENSE.md └── pnpm-lock.yaml /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | ollama-api.md -------------------------------------------------------------------------------- /turbo.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "//" 4 | ], 5 | "tasks": { 6 | "build": { 7 | "outputs": [ 8 | "**/dist/**" 9 | ] 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /tsconfig/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@vercel/ai-tsconfig", 3 | "version": "0.0.0", 4 | "private": true, 5 | "license": "MIT", 6 | "publishConfig": { 7 | "access": "public" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /tsup.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'tsup'; 2 | 3 | export default defineConfig([ 4 | { 5 | entry: ['src/index.ts'], 6 | format: ['cjs', 'esm'], 7 | dts: true, 8 | sourcemap: true, 9 | }, 10 | ]); 11 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./node_modules/@vercel/ai-tsconfig/ts-library.json", 3 | "include": ["."], 4 | "exclude": ["*/dist", "dist", "build", "node_modules"], 5 | "compilerOptions": { 6 | "types": ["vitest/globals"] 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /vitest.node.config.mjs: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite'; 2 | 3 | // https://vitejs.dev/config/ 4 | export default defineConfig({ 5 | test: { 6 | environment: 'node', 7 | globals: true, 8 | include: ['**/*.test.ts', '**/*.test.tsx'], 9 | }, 10 | }); 11 | -------------------------------------------------------------------------------- /vitest.edge.config.mjs: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite'; 2 | 3 | // https://vitejs.dev/config/ 4 | export default defineConfig({ 5 | test: { 6 | environment: 'edge-runtime', 7 | globals: true, 8 | include: ['**/*.test.ts', '**/*.test.tsx'], 9 | }, 10 | }); 11 | -------------------------------------------------------------------------------- /tsconfig/react-library.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "display": "React Library", 4 | "extends": "./base.json", 5 | "compilerOptions": { 6 | "jsx": "react-jsx", 7 | "lib": ["dom", "ES2015"], 8 | "module": "ESNext", 9 | "target": "es6" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/common/ollama-config.ts: -------------------------------------------------------------------------------- 1 | import { FetchFunction } from '@ai-sdk/provider-utils'; 2 | 3 | export type OllamaConfig = { 4 | provider: string; 5 | url: (options: { modelId: string; path: string }) => string; 6 | headers: () => Record; 7 | fetch?: FetchFunction; 8 | generateId?: () => string; 9 | }; 10 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | export { createOllama, ollama } from './ollama-provider'; 2 | export type { OllamaProvider, OllamaProviderSettings } from './ollama-provider'; 3 | export type { OllamaEmbeddingProviderOptions } from './embedding/ollama-embedding-model'; 4 | export type { OllamaCompletionProviderOptions } from './completion/ollama-completion-language-model'; -------------------------------------------------------------------------------- /src/common/get-response-metadata.ts: -------------------------------------------------------------------------------- 1 | export function getResponseMetadata({ 2 | model, 3 | created_at, 4 | }: { 5 | created_at?: string | undefined | null; 6 | model?: string | undefined | null; 7 | }) { 8 | return { 9 | id: undefined, 10 | modelId: model ?? undefined, 11 | timestamp: created_at != null ? new Date(created_at) : undefined, 12 | }; 13 | } 14 | -------------------------------------------------------------------------------- /tsconfig/ts-library.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "display": "TypeScript Library", 4 | "extends": "./base.json", 5 | "compilerOptions": { 6 | "lib": [ 7 | "dom", 8 | "ES2018" 9 | ], 10 | "module": "ESNext", 11 | "target": "ES2018", 12 | "stripInternal": true 13 | }, 14 | } 15 | -------------------------------------------------------------------------------- /src/adaptors/map-ollama-finish-reason.ts: -------------------------------------------------------------------------------- 1 | import { LanguageModelV2FinishReason } from '@ai-sdk/provider'; 2 | 3 | export function mapOllamaFinishReason( 4 | finishReason: string | null | undefined, 5 | ): LanguageModelV2FinishReason { 6 | switch (finishReason) { 7 | case 'stop': 8 | return 'stop'; 9 | case 'length': 10 | return 'length'; 11 | case 'content_filter': 12 | return 'content-filter'; 13 | case 'function_call': 14 | case 'tool_calls': 15 | return 'tool-calls'; 16 | default: 17 | return 'unknown'; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /tsconfig/base.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "display": "Default", 4 | "compilerOptions": { 5 | "composite": false, 6 | "declaration": true, 7 | "declarationMap": true, 8 | "esModuleInterop": true, 9 | "forceConsistentCasingInFileNames": true, 10 | "inlineSources": false, 11 | "isolatedModules": true, 12 | "moduleResolution": "node", 13 | "noUnusedLocals": false, 14 | "noUnusedParameters": false, 15 | "preserveWatchOutput": true, 16 | "skipLibCheck": true, 17 | "strict": true, 18 | "types": ["@types/node"] 19 | }, 20 | "exclude": ["node_modules"] 21 | } 22 | -------------------------------------------------------------------------------- /src/responses/map-ollama-responses-finish-reason.ts: -------------------------------------------------------------------------------- 1 | import { LanguageModelV2FinishReason } from '@ai-sdk/provider'; 2 | 3 | export function mapOllamaResponseFinishReason({ 4 | finishReason, 5 | hasToolCalls, 6 | }: { 7 | finishReason: string | null | undefined; 8 | hasToolCalls: boolean; 9 | }): LanguageModelV2FinishReason { 10 | switch (finishReason) { 11 | case undefined: 12 | case null: 13 | return hasToolCalls ? 'tool-calls' : 'stop'; 14 | case 'max_output_tokens': 15 | return 'length'; 16 | case 'content_filter': 17 | return 'content-filter'; 18 | default: 19 | return hasToolCalls ? 'tool-calls' : 'unknown'; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/embedding/__snapshots__/ollama-embedding-model.test.ts.snap: -------------------------------------------------------------------------------- 1 | // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html 2 | 3 | exports[`doEmbed > should expose the raw response 1`] = ` 4 | { 5 | "body": { 6 | "embeddings": [ 7 | [ 8 | 0.1, 9 | 0.2, 10 | 0.3, 11 | 0.4, 12 | 0.5, 13 | ], 14 | [ 15 | 0.6, 16 | 0.7, 17 | 0.8, 18 | 0.9, 19 | 1, 20 | ], 21 | ], 22 | "load_duration": 1019500, 23 | "model": "dummy-embedding-model", 24 | "prompt_eval_count": 8, 25 | "total_duration": 14143917, 26 | }, 27 | "headers": { 28 | "content-length": "162", 29 | "content-type": "application/json", 30 | "test-header": "test-value", 31 | }, 32 | } 33 | `; 34 | -------------------------------------------------------------------------------- /src/completion/ollama-error.ts: -------------------------------------------------------------------------------- 1 | import { z } from 'zod/v4'; 2 | import { createJsonErrorResponseHandler } from '@ai-sdk/provider-utils'; 3 | 4 | export const ollamaErrorDataSchema = z.object({ 5 | error: z.object({ 6 | message: z.string(), 7 | 8 | // The additional information below is handled loosely to support 9 | // Ollama-compatible providers that have slightly different error 10 | // responses: 11 | type: z.string().nullish(), 12 | param: z.any().nullish(), 13 | code: z.union([z.string(), z.number()]).nullish(), 14 | }), 15 | }); 16 | 17 | export type OllamaErrorData = z.infer; 18 | 19 | export const ollamaFailedResponseHandler = createJsonErrorResponseHandler({ 20 | errorSchema: ollamaErrorDataSchema, 21 | errorToMessage: data => data.error.message, 22 | }); 23 | -------------------------------------------------------------------------------- /src/embedding/ollama-embedding-settings.ts: -------------------------------------------------------------------------------- 1 | export type OllamaEmbeddingModelId = 2 | | 'text-embedding-3-small' 3 | | 'text-embedding-3-large' 4 | | 'text-embedding-ada-002' 5 | | (string & {}); 6 | 7 | export interface OllamaEmbeddingSettings { 8 | /** 9 | Override the maximum number of embeddings per call. 10 | */ 11 | maxEmbeddingsPerCall?: number; 12 | 13 | /** 14 | Override the parallelism of embedding calls. 15 | */ 16 | supportsParallelCalls?: boolean; 17 | 18 | /** 19 | The number of dimensions the resulting output embeddings should have. 20 | Only supported in text-embedding-3 and later models. 21 | */ 22 | dimensions?: number; 23 | 24 | /** 25 | A unique identifier representing your end-user, which can help Ollama to 26 | monitor and detect abuse. Learn more. 27 | */ 28 | user?: string; 29 | } 30 | -------------------------------------------------------------------------------- /src/completion/ollama-completion-settings.ts: -------------------------------------------------------------------------------- 1 | // https://ollama.com/library 2 | export type OllamaCompletionModelId = (string & {}); 3 | 4 | export interface OllamaCompletionSettings { 5 | /** 6 | * Enable or disable the model's thinking process. When enabled, the output will separate 7 | * the model's thinking from the model's output. When disabled, the model will not think 8 | * and directly output the content. 9 | * 10 | * Only supported by certain models like DeepSeek R1 and Qwen 3. 11 | */ 12 | think?: boolean; 13 | 14 | /** 15 | * Echo back the prompt in addition to the completion. 16 | */ 17 | echo?: boolean; 18 | 19 | /** 20 | * The suffix that comes after a completion of inserted text. 21 | */ 22 | suffix?: string; 23 | 24 | /** 25 | * A unique identifier representing your end-user, which can help Ollama to 26 | * monitor and detect abuse. 27 | */ 28 | user?: string; 29 | } 30 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "npm" 4 | directory: "/" 5 | schedule: 6 | interval: "weekly" 7 | day: "monday" 8 | time: "09:00" 9 | timezone: "UTC" 10 | open-pull-requests-limit: 10 11 | reviewers: 12 | - "nordwestt" 13 | assignees: 14 | - "nordwestt" 15 | commit-message: 16 | prefix: "chore" 17 | include: "scope" 18 | labels: 19 | - "dependencies" 20 | - "automated" 21 | 22 | groups: 23 | dev-dependencies: 24 | patterns: 25 | - "@types/*" 26 | - "@edge-runtime/*" 27 | - "typescript" 28 | - "tsup" 29 | - "vitest" 30 | update-types: 31 | - "minor" 32 | - "patch" 33 | ai-sdk-dependencies: 34 | patterns: 35 | - "@ai-sdk/*" 36 | update-types: 37 | - "minor" 38 | - "patch" 39 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | 3 | on: 4 | push: 5 | branches: 6 | - 'release/**' 7 | 8 | jobs: 9 | build-and-publish: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: Checkout code 13 | uses: actions/checkout@v4 14 | 15 | - name: Set up Node.js 16 | uses: actions/setup-node@v4 17 | with: 18 | node-version: '18.x' 19 | registry-url: 'https://registry.npmjs.org/' 20 | 21 | - name: Install dependencies 22 | run: pnpm install 23 | 24 | - name: Build 25 | run: pnpm build 26 | 27 | # - name: Publish to npm 28 | # env: 29 | # NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} 30 | # run: pnpm publish --access public --no-git-checks 31 | # # Remove --no-git-checks if you want git checks 32 | 33 | - name: Create GitHub Release 34 | uses: softprops/action-gh-release@v2 35 | with: 36 | tag_name: ${{ github.ref_name }} 37 | env: 38 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 39 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Test 2 | 3 | on: 4 | pull_request: 5 | branches: 6 | - master 7 | push: 8 | branches: 9 | - master 10 | 11 | permissions: 12 | contents: read 13 | 14 | jobs: 15 | test: 16 | name: Test Node.js ${{ matrix.node-version }} 17 | runs-on: ubuntu-latest 18 | 19 | strategy: 20 | matrix: 21 | node-version: [18, 20, 22, 24] 22 | 23 | steps: 24 | - name: Checkout code 25 | uses: actions/checkout@v4 26 | 27 | - name: Install pnpm 28 | uses: pnpm/action-setup@v4 29 | with: 30 | version: latest 31 | 32 | - name: Set up Node.js 33 | uses: actions/setup-node@v4 34 | with: 35 | node-version: ${{ matrix.node-version }} 36 | cache: 'pnpm' 37 | 38 | - name: Install dependencies 39 | run: pnpm install 40 | 41 | - name: Run tests 42 | run: pnpm run test 43 | 44 | - name: Run type check 45 | run: pnpm run type-check 46 | 47 | # - name: Run linting 48 | # run: pnpm run lint 49 | 50 | # - name: Check code formatting 51 | # run: pnpm run prettier-check 52 | -------------------------------------------------------------------------------- /src/completion/ollama-error.test.ts: -------------------------------------------------------------------------------- 1 | import { safeParseJSON } from '@ai-sdk/provider-utils'; 2 | import { ollamaErrorDataSchema } from './ollama-error'; 3 | 4 | describe('ollamaErrorDataSchema', () => { 5 | it('should parse OpenRouter resource exhausted error', async () => { 6 | const error = ` 7 | {"error":{"message":"{\\n \\"error\\": {\\n \\"code\\": 429,\\n \\"message\\": \\"Resource has been exhausted (e.g. check quota).\\",\\n \\"status\\": \\"RESOURCE_EXHAUSTED\\"\\n }\\n}\\n","code":429}} 8 | `; 9 | 10 | const result = await safeParseJSON({ 11 | text: error, 12 | schema: ollamaErrorDataSchema, 13 | }); 14 | 15 | expect(result).toStrictEqual({ 16 | success: true, 17 | value: { 18 | error: { 19 | message: 20 | '{\n "error": {\n "code": 429,\n "message": "Resource has been exhausted (e.g. check quota).",\n "status": "RESOURCE_EXHAUSTED"\n }\n}\n', 21 | code: 429, 22 | }, 23 | }, 24 | rawValue: { 25 | error: { 26 | message: 27 | '{\n "error": {\n "code": 429,\n "message": "Resource has been exhausted (e.g. check quota).",\n "status": "RESOURCE_EXHAUSTED"\n }\n}\n', 28 | code: 429, 29 | }, 30 | }, 31 | }); 32 | }); 33 | }); 34 | -------------------------------------------------------------------------------- /src/responses/ollama-responses-api-types.ts: -------------------------------------------------------------------------------- 1 | import { JSONSchema7 } from "@ai-sdk/provider"; 2 | 3 | export type OllamaResponsesPrompt = Array; 4 | 5 | export type OllamaResponsesMessage = 6 | | OllamaResponsesSystemMessage 7 | | OllamaResponsesUserMessage 8 | | OllamaResponsesAssistantMessage 9 | | OllamaResponsesFunctionCall 10 | | OllamaResponsesFunctionCallOutput 11 | | OllamaWebSearchCall 12 | | OllamaComputerCall; 13 | 14 | export type OllamaResponsesSystemMessage = { 15 | role: "system" | "developer"; 16 | content: string; 17 | }; 18 | 19 | export type OllamaResponsesUserMessage = { 20 | role: "user"; 21 | content: Array< 22 | | { type: "input_text"; text: string } 23 | | { type: "input_image"; image_url: string } 24 | | { type: "input_file"; filename: string; file_data: string } 25 | >; 26 | }; 27 | 28 | export type OllamaResponsesAssistantMessage = { 29 | role: "assistant"; 30 | content: Array< 31 | | { type: "output_text"; text: string } 32 | | OllamaWebSearchCall 33 | | OllamaComputerCall 34 | >; 35 | }; 36 | 37 | export type OllamaResponsesFunctionCall = { 38 | type: "function_call"; 39 | call_id: string; 40 | name: string; 41 | arguments: string; 42 | }; 43 | 44 | export type OllamaResponsesFunctionCallOutput = { 45 | type: "function_call_output"; 46 | call_id: string; 47 | output: string; 48 | }; 49 | 50 | export type OllamaWebSearchCall = { 51 | type: "web_search_call"; 52 | id: string; 53 | status?: string; 54 | }; 55 | 56 | export type OllamaComputerCall = { 57 | type: "computer_call"; 58 | id: string; 59 | status?: string; 60 | }; 61 | 62 | export type OllamaResponsesTool = 63 | | { 64 | type: "function"; 65 | function: { 66 | name: string; 67 | description: string | undefined; 68 | parameters: JSONSchema7; 69 | }; 70 | } 71 | | { 72 | type: "web_search_preview"; 73 | search_context_size: "low" | "medium" | "high"; 74 | user_location: { 75 | type: "approximate"; 76 | city: string; 77 | region: string; 78 | }; 79 | }; 80 | -------------------------------------------------------------------------------- /src/adaptors/ollama-chat-prompt.ts: -------------------------------------------------------------------------------- 1 | export type OllamaChatPrompt = Array; 2 | 3 | export type ChatCompletionMessage = 4 | | ChatCompletionSystemMessage 5 | | ChatCompletionDeveloperMessage 6 | | ChatCompletionUserMessage 7 | | ChatCompletionAssistantMessage 8 | | ChatCompletionToolMessage 9 | | ChatCompletionFunctionMessage; 10 | 11 | export interface ChatCompletionSystemMessage { 12 | role: 'system'; 13 | content: string; 14 | } 15 | 16 | export interface ChatCompletionDeveloperMessage { 17 | role: 'developer'; 18 | content: string; 19 | } 20 | 21 | export interface ChatCompletionUserMessage { 22 | role: 'user'; 23 | content: string | Array; 24 | images?: Array; 25 | } 26 | 27 | export type ChatCompletionContentPart = 28 | | ChatCompletionContentPartText 29 | | ChatCompletionContentPartImage 30 | | ChatCompletionContentPartInputAudio; 31 | 32 | export interface ChatCompletionContentPartText { 33 | type: 'text'; 34 | text: string; 35 | } 36 | 37 | export interface ChatCompletionContentPartImage { 38 | type: 'image_url'; 39 | image_url: { url: string }; 40 | } 41 | 42 | export interface ChatCompletionContentPartInputAudio { 43 | type: 'input_audio'; 44 | input_audio: { data: string; format: 'wav' | 'mp3' }; 45 | } 46 | 47 | export interface ChatCompletionAssistantMessage { 48 | role: 'assistant'; 49 | content?: string | null; 50 | tool_calls?: Array; 51 | thinking?: string; 52 | images?: Array; 53 | } 54 | 55 | export interface ChatCompletionMessageToolCall { 56 | type: 'function'; 57 | id: string; 58 | function: { 59 | arguments: object; 60 | name: string; 61 | }; 62 | } 63 | 64 | export interface ChatCompletionToolMessage { 65 | role: 'tool'; 66 | content: string; 67 | tool_call_id: string; 68 | } 69 | 70 | /** 71 | * Legacy function calling interface. 72 | * @deprecated this API is supported but deprecated by Ollama. 73 | */ 74 | export interface ChatCompletionFunctionMessage { 75 | role: 'function'; 76 | content: string; 77 | name: string; 78 | } 79 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ollama-ai-provider-v2", 3 | "version": "1.5.5", 4 | "license": "Apache-2.0", 5 | "sideEffects": false, 6 | "main": "./dist/index.js", 7 | "module": "./dist/index.mjs", 8 | "types": "./dist/index.d.ts", 9 | "files": [ 10 | "dist/**/*", 11 | "internal/dist/**/*", 12 | "CHANGELOG.md" 13 | ], 14 | "scripts": { 15 | "build": "tsup", 16 | "build:watch": "tsup --watch", 17 | "clean": "rm -rf dist && rm -rf internal/dist", 18 | "lint": "eslint \"./**/*.ts*\"", 19 | "type-check": "tsc --noEmit", 20 | "prettier-check": "prettier --check \"./**/*.ts*\"", 21 | "test": "pnpm test:node && pnpm test:edge", 22 | "test:edge": "vitest --config vitest.edge.config.mjs --run", 23 | "test:node": "vitest --config vitest.node.config.mjs --run" 24 | }, 25 | "exports": { 26 | "./package.json": "./package.json", 27 | ".": { 28 | "types": "./dist/index.d.ts", 29 | "import": "./dist/index.mjs", 30 | "require": "./dist/index.js" 31 | }, 32 | "./internal": { 33 | "types": "./internal/dist/index.d.ts", 34 | "import": "./internal/dist/index.mjs", 35 | "module": "./internal/dist/index.mjs", 36 | "require": "./internal/dist/index.js" 37 | } 38 | }, 39 | "dependencies": { 40 | "@ai-sdk/provider": "^2.0.0", 41 | "@ai-sdk/provider-utils": "^3.0.17" 42 | }, 43 | "devDependencies": { 44 | "@edge-runtime/vm": "^5.0.0", 45 | "@types/node": "24.10.1", 46 | "@vercel/ai-tsconfig": "./tsconfig", 47 | "eslint": "^9.39.1", 48 | "msw": "^2.12.4", 49 | "tsup": "^8", 50 | "typescript": "5.9.3", 51 | "vite": "^7.2.4", 52 | "vitest": "^4.0.15", 53 | "zod": "4.1.13" 54 | }, 55 | "peerDependencies": { 56 | "zod": "^4.0.16" 57 | }, 58 | "engines": { 59 | "node": ">=18" 60 | }, 61 | "publishConfig": { 62 | "access": "public" 63 | }, 64 | "homepage": "https://github.com/nordwestt/ollama-ai-provider-v2", 65 | "repository": { 66 | "type": "git", 67 | "url": "git+https://github.com/nordwestt/ollama-ai-provider-v2.git" 68 | }, 69 | "bugs": { 70 | "url": "https://github.com/nordwestt/ollama-ai-provider-v2/issues" 71 | }, 72 | "keywords": [ 73 | "ai", 74 | "vercel", 75 | "ai-sdk", 76 | "ollama", 77 | "llm", 78 | "provider", 79 | "chat", 80 | "streaming", 81 | "tool-calling", 82 | "thinking-mode", 83 | "completion-models", 84 | "local-ai", 85 | "embeddings" 86 | ] 87 | } 88 | -------------------------------------------------------------------------------- /src/adaptors/convert-to-ollama-completion-prompt.ts: -------------------------------------------------------------------------------- 1 | import { 2 | InvalidPromptError, 3 | LanguageModelV2Prompt, 4 | UnsupportedFunctionalityError, 5 | } from '@ai-sdk/provider'; 6 | 7 | export function convertToOllamaCompletionPrompt({ 8 | prompt, 9 | user = 'user', 10 | assistant = 'assistant', 11 | }: { 12 | prompt: LanguageModelV2Prompt; 13 | user?: string; 14 | assistant?: string; 15 | }): { 16 | prompt: string; 17 | stopSequences?: string[]; 18 | } { 19 | // transform to a chat message format: 20 | let text = ''; 21 | 22 | // if first message is a system message, add it to the text: 23 | if (prompt[0].role === 'system') { 24 | text += `${prompt[0].content}\n\n`; 25 | prompt = prompt.slice(1); 26 | } 27 | 28 | for (const { role, content } of prompt) { 29 | switch (role) { 30 | case 'system': { 31 | throw new InvalidPromptError({ 32 | message: 'Unexpected system message in prompt: ${content}', 33 | prompt, 34 | }); 35 | } 36 | 37 | case 'user': { 38 | const userMessage = content 39 | .map(part => { 40 | switch (part.type) { 41 | case 'text': { 42 | return part.text; 43 | } 44 | } 45 | }) 46 | .filter(Boolean) 47 | .join(''); 48 | 49 | text += `${user}:\n${userMessage}\n\n`; 50 | break; 51 | } 52 | 53 | case 'assistant': { 54 | const assistantMessage = content 55 | .map(part => { 56 | switch (part.type) { 57 | case 'text': { 58 | return part.text; 59 | } 60 | case 'tool-call': { 61 | throw new UnsupportedFunctionalityError({ 62 | functionality: 'tool-call messages', 63 | }); 64 | } 65 | } 66 | }) 67 | .join(''); 68 | 69 | text += `${assistant}:\n${assistantMessage}\n\n`; 70 | break; 71 | } 72 | 73 | case 'tool': { 74 | throw new UnsupportedFunctionalityError({ 75 | functionality: 'tool messages', 76 | }); 77 | } 78 | 79 | default: { 80 | const _exhaustiveCheck: never = role; 81 | throw new Error(`Unsupported role: ${_exhaustiveCheck}`); 82 | } 83 | } 84 | } 85 | 86 | // Assistant message prefix: 87 | text += `${assistant}:\n`; 88 | 89 | return { 90 | prompt: text, 91 | stopSequences: [`\n${user}:`], 92 | }; 93 | } 94 | -------------------------------------------------------------------------------- /src/responses/ollama-responses-prepare-tools.ts: -------------------------------------------------------------------------------- 1 | import { 2 | LanguageModelV2CallOptions, 3 | LanguageModelV2CallWarning, 4 | UnsupportedFunctionalityError, 5 | } from "@ai-sdk/provider"; 6 | import { OllamaResponsesTool } from "./ollama-responses-api-types"; 7 | 8 | export function prepareResponsesTools({ 9 | tools, 10 | toolChoice, 11 | }: { 12 | tools: LanguageModelV2CallOptions["tools"]; 13 | toolChoice?: LanguageModelV2CallOptions["toolChoice"]; 14 | }): { 15 | tools?: Array; 16 | toolChoice?: 17 | | "auto" 18 | | "none" 19 | | "required" 20 | | { type: "web_search_preview" } 21 | | { type: "function"; name: string }; 22 | toolWarnings: LanguageModelV2CallWarning[]; 23 | } { 24 | // when the tools array is empty, change it to undefined to prevent errors: 25 | tools = tools?.length ? tools : undefined; 26 | 27 | const toolWarnings: LanguageModelV2CallWarning[] = []; 28 | 29 | if (tools == null) { 30 | return { tools: undefined, toolChoice: undefined, toolWarnings }; 31 | } 32 | 33 | const ollamaTools: Array = []; 34 | 35 | for (const tool of tools) { 36 | switch (tool.type) { 37 | case "function": { 38 | // Ensure parameters is always a non-null object (even if empty) 39 | let parameters = tool.inputSchema; 40 | if(!parameters){ 41 | parameters = { 42 | type: "object", 43 | properties: {}, 44 | required: [], 45 | }; 46 | } 47 | else if ( 48 | parameters && 49 | typeof parameters === "object" && 50 | parameters.type === "object" && 51 | parameters.properties && 52 | Object.keys(parameters.properties).length === 0 53 | ) { 54 | // Defensive: ensure required/optional fields are handled for empty schemas 55 | parameters = { 56 | ...parameters, 57 | properties: {}, 58 | required: [], 59 | }; 60 | } 61 | 62 | ollamaTools.push({ 63 | type: "function", 64 | function: { 65 | name: tool.name, 66 | description: tool.description, 67 | parameters, 68 | }, 69 | }); 70 | break; 71 | } 72 | default: 73 | toolWarnings.push({ type: "unsupported-tool", tool }); 74 | break; 75 | } 76 | } 77 | 78 | if (toolChoice == null) { 79 | return { tools: ollamaTools, toolChoice: undefined, toolWarnings }; 80 | } 81 | 82 | const type = toolChoice.type; 83 | 84 | switch (type) { 85 | case "auto": 86 | case "none": 87 | case "required": 88 | return { tools: ollamaTools, toolChoice: type, toolWarnings }; 89 | case "tool": 90 | return { 91 | tools: ollamaTools, 92 | toolChoice: 93 | toolChoice.toolName == "web_search_preview" 94 | ? { type: "web_search_preview" } 95 | : { type: "function", name: toolChoice.toolName }, 96 | toolWarnings, 97 | }; 98 | default: { 99 | const _exhaustiveCheck: never = type; 100 | throw new UnsupportedFunctionalityError({ 101 | functionality: `tool choice type: ${_exhaustiveCheck}`, 102 | }); 103 | } 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /src/responses/test-helpers/ollama-test-helpers.ts: -------------------------------------------------------------------------------- 1 | import { 2 | LanguageModelV2FunctionTool, 3 | LanguageModelV2Prompt, 4 | } from '@ai-sdk/provider'; 5 | import { createTestServer } from '@ai-sdk/provider-utils/test'; 6 | import { OllamaChatModelId } from '../../ollama-chat-settings'; 7 | import { OllamaConfig } from '../../common/ollama-config'; 8 | 9 | export const TEST_PROMPT: LanguageModelV2Prompt = [ 10 | { role: 'user', content: [{ type: 'text', text: 'Hello' }] }, 11 | ]; 12 | 13 | export const TEST_TOOLS: Array = [ 14 | { 15 | type: 'function', 16 | name: 'weather', 17 | inputSchema: { 18 | type: 'object', 19 | properties: { location: { type: 'string' } }, 20 | required: ['location'], 21 | additionalProperties: false, 22 | }, 23 | }, 24 | { 25 | type: 'function', 26 | name: 'cityAttractions', 27 | inputSchema: { 28 | type: 'object', 29 | properties: { city: { type: 'string' } }, 30 | required: ['city'], 31 | additionalProperties: false, 32 | }, 33 | }, 34 | ]; 35 | 36 | export const TEST_MODEL_ID: OllamaChatModelId = 'llama2'; 37 | 38 | export const createTestConfig = (): OllamaConfig => ({ 39 | provider: 'ollama.responses', 40 | url: ({ path }) => `http://127.0.0.1:11434/api${path}`, 41 | headers: () => ({ 'Content-Type': 'application/json' }), 42 | generateId: () => 'mock-id-1', 43 | }); 44 | 45 | export const createMockServer : any = () => 46 | createTestServer({ 47 | 'http://127.0.0.1:11434/api/chat': {}, 48 | }); 49 | 50 | export interface MockResponseOptions { 51 | content?: string; 52 | toolCalls?: Array<{ 53 | id?: string; 54 | function: { name: string; arguments: Record }; 55 | }>; 56 | usage?: { prompt_eval_count?: number; eval_count?: number }; 57 | headers?: Record; 58 | doneReason?: string; 59 | } 60 | 61 | export const prepareJsonResponse = ( 62 | server: ReturnType, 63 | { 64 | content = 'Hello, how can I help you?', 65 | toolCalls, 66 | usage = { prompt_eval_count: 10, eval_count: 20 }, 67 | headers, 68 | doneReason = 'stop', 69 | }: MockResponseOptions = {} 70 | ) => { 71 | server.urls['http://127.0.0.1:11434/api/chat'].response = { 72 | type: 'json-value', 73 | headers, 74 | body: { 75 | model: TEST_MODEL_ID, 76 | created_at: '2024-01-01T00:00:00.000Z', 77 | done: true, 78 | done_reason: doneReason, 79 | message: { 80 | role: 'assistant', 81 | content, 82 | tool_calls: toolCalls, 83 | }, 84 | prompt_eval_count: usage.prompt_eval_count, 85 | eval_count: usage.eval_count, 86 | }, 87 | }; 88 | }; 89 | 90 | export const prepareErrorResponse = ( 91 | server: ReturnType, 92 | status: number = 500, 93 | body: string = 'Internal server error' 94 | ) => { 95 | server.urls['http://127.0.0.1:11434/api/chat'].response = { 96 | type: 'error', 97 | status, 98 | body, 99 | }; 100 | }; 101 | 102 | export const prepareStreamResponse = ( 103 | server: ReturnType, 104 | content: string = 'Hello' 105 | ) => { 106 | server.urls['http://127.0.0.1:11434/api/chat'].response = { 107 | type: 'json-value', 108 | body: { 109 | model: TEST_MODEL_ID, 110 | created_at: '2024-01-01T00:00:00.000Z', 111 | done: true, 112 | done_reason: 'stop', 113 | message: { 114 | role: 'assistant', 115 | content, 116 | }, 117 | eval_count: 5, 118 | }, 119 | }; 120 | }; -------------------------------------------------------------------------------- /src/embedding/ollama-embedding-model.ts: -------------------------------------------------------------------------------- 1 | import { 2 | EmbeddingModelV2, 3 | TooManyEmbeddingValuesForCallError, 4 | } from "@ai-sdk/provider"; 5 | import { 6 | combineHeaders, 7 | createJsonResponseHandler, 8 | parseProviderOptions, 9 | postJsonToApi, 10 | } from "@ai-sdk/provider-utils"; 11 | import { z } from "zod/v4"; 12 | import { OllamaConfig } from "../common/ollama-config"; 13 | import { 14 | OllamaEmbeddingModelId, 15 | OllamaEmbeddingSettings, 16 | } from "./ollama-embedding-settings"; 17 | import { ollamaFailedResponseHandler } from "../completion/ollama-error"; 18 | 19 | const ollamaEmbeddingProviderOptions = z.object({ 20 | dimensions: z.number().optional(), 21 | truncate: z.boolean().optional(), 22 | keepAlive: z.string().optional(), 23 | }); 24 | 25 | export type OllamaEmbeddingProviderOptions = z.infer; 26 | 27 | export class OllamaEmbeddingModel implements EmbeddingModelV2 { 28 | readonly specificationVersion = "v2"; 29 | readonly modelId: OllamaEmbeddingModelId; 30 | 31 | private readonly config: OllamaConfig; 32 | private readonly settings: OllamaEmbeddingSettings; 33 | 34 | get provider(): string { 35 | return this.config.provider; 36 | } 37 | 38 | get maxEmbeddingsPerCall(): number { 39 | return this.settings.maxEmbeddingsPerCall ?? 2048; 40 | } 41 | 42 | get supportsParallelCalls(): boolean { 43 | return this.settings.supportsParallelCalls ?? true; 44 | } 45 | 46 | constructor( 47 | modelId: OllamaEmbeddingModelId, 48 | settings: OllamaEmbeddingSettings, 49 | config: OllamaConfig 50 | ) { 51 | this.modelId = modelId; 52 | this.settings = settings; 53 | this.config = config; 54 | } 55 | 56 | private async getArgs({ 57 | values, 58 | providerOptions, 59 | }: Parameters["doEmbed"]>[0]) { 60 | // Parse provider options 61 | const ollamaOptions = 62 | (await parseProviderOptions({ 63 | provider: "ollama", 64 | providerOptions, 65 | schema: ollamaEmbeddingProviderOptions, 66 | })) ?? {}; 67 | 68 | return { 69 | args: { 70 | // model id: 71 | model: this.modelId, 72 | input: values, 73 | 74 | // advanced parameters: 75 | dimensions: ollamaOptions.dimensions ?? this.settings.dimensions, 76 | truncate: ollamaOptions.truncate, 77 | keep_alive: ollamaOptions.keepAlive, 78 | } 79 | }; 80 | } 81 | 82 | async doEmbed({ 83 | values, 84 | headers, 85 | abortSignal, 86 | providerOptions, 87 | }: Parameters["doEmbed"]>[0]): Promise< 88 | Awaited["doEmbed"]>> 89 | > { 90 | if (values.length > this.maxEmbeddingsPerCall) { 91 | throw new TooManyEmbeddingValuesForCallError({ 92 | provider: this.provider, 93 | modelId: this.modelId, 94 | maxEmbeddingsPerCall: this.maxEmbeddingsPerCall, 95 | values, 96 | }); 97 | } 98 | 99 | const { args: body } = await this.getArgs({values, providerOptions}) 100 | 101 | const { 102 | responseHeaders, 103 | value: response, 104 | rawValue, 105 | } = await postJsonToApi({ 106 | url: this.config.url({ 107 | path: "/embed", 108 | modelId: this.modelId, 109 | }), 110 | headers: combineHeaders(this.config.headers(), headers), 111 | body: { ...body }, 112 | failedResponseHandler: ollamaFailedResponseHandler, 113 | successfulResponseHandler: createJsonResponseHandler( 114 | ollamaTextEmbeddingResponseSchema, 115 | ), 116 | abortSignal, 117 | fetch: this.config.fetch, 118 | }); 119 | 120 | return { 121 | embeddings: response.embeddings.map((item) => item), 122 | usage: { tokens: response.prompt_eval_count }, 123 | response: { headers: responseHeaders, body: rawValue }, 124 | }; 125 | } 126 | } 127 | 128 | // minimal version of the schema, focussed on what is needed for the implementation 129 | // this approach limits breakages when the API changes and increases efficiency 130 | const ollamaTextEmbeddingResponseSchema = z.object({ 131 | model: z.string(), 132 | embeddings: z.array(z.array(z.number())), 133 | total_duration: z.number(), 134 | load_duration: z.number(), 135 | prompt_eval_count: z.number(), 136 | }); 137 | -------------------------------------------------------------------------------- /src/adaptors/convert-to-ollama-chat-messages.ts: -------------------------------------------------------------------------------- 1 | import { 2 | LanguageModelV2FilePart, 3 | LanguageModelV2Prompt, 4 | } from '@ai-sdk/provider'; 5 | import { OllamaChatPrompt } from './ollama-chat-prompt'; 6 | 7 | export function convertToOllamaChatMessages({ 8 | prompt, 9 | systemMessageMode = 'system', 10 | }: { 11 | prompt: LanguageModelV2Prompt; 12 | systemMessageMode?: 'system' | 'developer' | 'remove'; 13 | }): OllamaChatPrompt { 14 | const messages: OllamaChatPrompt = []; 15 | 16 | for (const { role, content } of prompt) { 17 | switch (role) { 18 | case 'system': { 19 | switch (systemMessageMode) { 20 | case 'system': { 21 | messages.push({ role: 'system', content }); 22 | break; 23 | } 24 | case 'developer': { 25 | messages.push({ role: 'developer', content }); 26 | break; 27 | } 28 | case 'remove': { 29 | break; 30 | } 31 | default: { 32 | const _exhaustiveCheck: never = systemMessageMode; 33 | throw new Error( 34 | `Unsupported system message mode: ${_exhaustiveCheck}`, 35 | ); 36 | } 37 | } 38 | break; 39 | } 40 | 41 | case 'user': { 42 | if (content.length === 1 && content[0].type === 'text') { 43 | messages.push({ role: 'user', content: content[0].text }); 44 | break; 45 | } 46 | 47 | const userText = content.filter((part) => part.type === 'text').map((part) => part.text).join(''); 48 | const images = content 49 | .filter((part) => part.type === 'file' && part.mediaType.startsWith('image/')) 50 | .map((part) => (part as LanguageModelV2FilePart).data); 51 | 52 | messages.push({ 53 | role: 'user', 54 | content: userText.length > 0 ? userText : [], 55 | images: images.length > 0 ? images : undefined 56 | }); 57 | 58 | break; 59 | } 60 | 61 | case 'assistant': { 62 | let text = ''; 63 | let thinking = ''; 64 | const toolCalls: Array<{ 65 | id: string; 66 | type: 'function'; 67 | function: { name: string; arguments: object }; 68 | }> = []; 69 | 70 | for (const part of content) { 71 | switch (part.type) { 72 | case 'text': { 73 | text += part.text; 74 | break; 75 | } 76 | case 'tool-call': { 77 | toolCalls.push({ 78 | id: part.toolCallId, 79 | type: 'function', 80 | function: { 81 | name: part.toolName, 82 | arguments: part.input as object, 83 | }, 84 | }); 85 | break; 86 | } 87 | case 'reasoning': { 88 | thinking += part.text; 89 | break; 90 | } 91 | default: { 92 | throw new Error(`Unsupported part: ${part}`); 93 | } 94 | } 95 | } 96 | 97 | messages.push({ 98 | role: 'assistant', 99 | content: text, 100 | ...(thinking && { thinking }), 101 | tool_calls: toolCalls.length > 0 ? toolCalls : undefined, 102 | }); 103 | 104 | break; 105 | } 106 | 107 | case 'tool': { 108 | for (const toolResponse of content) { 109 | const output = toolResponse.output; 110 | 111 | let contentValue: string; 112 | switch (output.type) { 113 | case 'text': 114 | case 'error-text': 115 | contentValue = output.value; 116 | break; 117 | case 'content': 118 | case 'json': 119 | case 'error-json': 120 | contentValue = JSON.stringify(output.value); 121 | break; 122 | } 123 | 124 | messages.push({ 125 | role: 'tool', 126 | tool_call_id: toolResponse.toolCallId, 127 | content: contentValue, 128 | }); 129 | } 130 | break; 131 | } 132 | 133 | default: { 134 | const _exhaustiveCheck: never = role; 135 | throw new Error(`Unsupported role: ${_exhaustiveCheck}`); 136 | } 137 | } 138 | } 139 | 140 | return messages; 141 | } 142 | -------------------------------------------------------------------------------- /src/responses/ollama-responses-language-model.ts: -------------------------------------------------------------------------------- 1 | import { 2 | LanguageModelV2, 3 | LanguageModelV2CallWarning, 4 | } from "@ai-sdk/provider"; 5 | import { 6 | combineHeaders, 7 | createJsonResponseHandler, 8 | createJsonStreamResponseHandler, 9 | postJsonToApi, 10 | } from "@ai-sdk/provider-utils"; 11 | import { OllamaConfig } from "../common/ollama-config"; 12 | import { ollamaFailedResponseHandler } from "../completion/ollama-error"; 13 | import { OllamaChatModelId } from "../ollama-chat-settings"; 14 | import { 15 | OllamaRequestBuilder, 16 | OllamaResponsesProviderOptions 17 | } from "./ollama-responses-request-builder"; 18 | import { 19 | OllamaResponseProcessor, 20 | baseOllamaResponseSchema 21 | } from "./ollama-responses-processor"; 22 | import { OllamaStreamProcessor } from "./ollama-responses-stream-processor"; 23 | 24 | export class OllamaResponsesLanguageModel implements LanguageModelV2 { 25 | readonly specificationVersion = "v2"; 26 | readonly modelId: OllamaChatModelId; 27 | 28 | private readonly config: OllamaConfig; 29 | private readonly requestBuilder: OllamaRequestBuilder; 30 | private readonly responseProcessor: OllamaResponseProcessor; 31 | 32 | constructor(modelId: OllamaChatModelId, config: OllamaConfig) { 33 | this.modelId = modelId; 34 | this.config = config; 35 | this.requestBuilder = new OllamaRequestBuilder(); 36 | this.responseProcessor = new OllamaResponseProcessor(config); 37 | } 38 | 39 | readonly supportedUrls: Record = { 40 | 'image/*': [ 41 | /^https?:\/\/.*$/ 42 | ] 43 | }; 44 | 45 | get provider(): string { 46 | return this.config.provider; 47 | } 48 | 49 | async doGenerate( 50 | options: Parameters[0], 51 | ): Promise>> { 52 | const { args: body, warnings } = await this.prepareRequest(options); 53 | 54 | const { 55 | responseHeaders, 56 | value: response, 57 | rawValue: rawResponse, 58 | } = await postJsonToApi({ 59 | url: this.config.url({ 60 | path: "/chat", 61 | modelId: this.modelId, 62 | }), 63 | headers: combineHeaders(this.config.headers(), options.headers), 64 | body: { ...body, stream: false }, 65 | failedResponseHandler: ollamaFailedResponseHandler, 66 | successfulResponseHandler: createJsonResponseHandler(baseOllamaResponseSchema), 67 | abortSignal: options.abortSignal, 68 | fetch: this.config.fetch, 69 | }); 70 | 71 | const processedResponse = this.responseProcessor.processGenerateResponse(response); 72 | 73 | return { 74 | ...processedResponse, 75 | request: { body: JSON.stringify(body) }, 76 | response: { 77 | modelId: this.modelId, 78 | timestamp: new Date(), 79 | headers: responseHeaders, 80 | body: rawResponse, 81 | }, 82 | warnings, 83 | }; 84 | } 85 | 86 | async doStream( 87 | options: Parameters[0], 88 | ): Promise>> { 89 | const { args: body, warnings } = await this.prepareRequest(options); 90 | 91 | const { responseHeaders, value: response } = await postJsonToApi({ 92 | url: this.config.url({ 93 | path: "/chat", 94 | modelId: this.modelId, 95 | }), 96 | headers: combineHeaders(this.config.headers(), options.headers), 97 | body: { ...body, stream: true }, 98 | failedResponseHandler: ollamaFailedResponseHandler, 99 | successfulResponseHandler: createJsonStreamResponseHandler(baseOllamaResponseSchema), 100 | abortSignal: options.abortSignal, 101 | fetch: this.config.fetch, 102 | }); 103 | 104 | const streamProcessor = new OllamaStreamProcessor(this.config); 105 | 106 | return { 107 | stream: response.pipeThrough( 108 | streamProcessor.createTransformStream(warnings, options) 109 | ), 110 | request: { body }, 111 | response: { headers: responseHeaders }, 112 | }; 113 | } 114 | 115 | private async prepareRequest(options: Parameters[0]) { 116 | return await this.requestBuilder.buildRequest({ 117 | modelId: this.modelId, 118 | ...options, 119 | }); 120 | } 121 | } 122 | 123 | // Re-export types for convenience 124 | export type { OllamaResponsesProviderOptions }; 125 | -------------------------------------------------------------------------------- /src/embedding/ollama-embedding-model.test.ts: -------------------------------------------------------------------------------- 1 | import { EmbeddingModelV2Embedding } from '@ai-sdk/provider'; 2 | import { createTestServer } from '@ai-sdk/provider-utils/test'; 3 | import { createOllama } from '../ollama-provider'; 4 | 5 | const dummyEmbeddings = [ 6 | [0.1, 0.2, 0.3, 0.4, 0.5], 7 | [0.6, 0.7, 0.8, 0.9, 1.0], 8 | ]; 9 | const testValues = ['sunny day at the beach', 'rainy day in the city']; 10 | 11 | const provider = createOllama(); 12 | const model = provider.embedding('dummy-embedding-model'); 13 | 14 | const server = createTestServer({ 15 | 'http://127.0.0.1:11434/api/embed': {}, 16 | }); 17 | 18 | describe('doEmbed', () => { 19 | function prepareJsonResponse({ 20 | embeddings = dummyEmbeddings, 21 | usage = { prompt_eval_count: 8 }, 22 | headers, 23 | }: { 24 | embeddings?: EmbeddingModelV2Embedding[]; 25 | usage?: { prompt_eval_count: number }; 26 | headers?: Record; 27 | } = {}) { 28 | server.urls['http://127.0.0.1:11434/api/embed'].response = { 29 | type: 'json-value', 30 | headers, 31 | body: { 32 | model: 'dummy-embedding-model', 33 | embeddings, 34 | total_duration: 14143917, 35 | load_duration: 1019500, 36 | prompt_eval_count: usage.prompt_eval_count, 37 | }, 38 | }; 39 | } 40 | 41 | it('should extract embedding', async () => { 42 | prepareJsonResponse(); 43 | 44 | const { embeddings } = await model.doEmbed({ values: testValues }); 45 | 46 | expect(embeddings).toStrictEqual(dummyEmbeddings); 47 | }); 48 | 49 | it('should expose the raw response', async () => { 50 | prepareJsonResponse({ 51 | headers: { 52 | 'test-header': 'test-value', 53 | }, 54 | }); 55 | 56 | const { response } = await model.doEmbed({ values: testValues }); 57 | 58 | expect(response?.headers).toStrictEqual({ 59 | // default headers: 60 | 'content-length': '162', 61 | 'content-type': 'application/json', 62 | 63 | // custom header 64 | 'test-header': 'test-value', 65 | }); 66 | expect(response).toMatchSnapshot(); 67 | }); 68 | 69 | it('should extract usage', async () => { 70 | prepareJsonResponse({ 71 | usage: { prompt_eval_count: 20 }, 72 | }); 73 | 74 | const { usage } = await model.doEmbed({ values: testValues }); 75 | 76 | expect(usage).toStrictEqual({ tokens: 20 }); 77 | }); 78 | 79 | it('should pass the model and the values', async () => { 80 | prepareJsonResponse(); 81 | 82 | await model.doEmbed({ values: testValues }); 83 | 84 | expect(await server.calls[0].requestBodyJson).toStrictEqual({ 85 | model: 'dummy-embedding-model', 86 | input: testValues, 87 | }); 88 | }); 89 | 90 | it('should pass the dimensions setting', async () => { 91 | prepareJsonResponse(); 92 | 93 | await provider.embedding('text-embedding-3-large', { dimensions: 64 }).doEmbed({ 94 | values: testValues, 95 | }); 96 | 97 | expect(await server.calls[0].requestBodyJson).toStrictEqual({ 98 | model: 'text-embedding-3-large', 99 | input: testValues, 100 | dimensions: 64, 101 | }); 102 | }); 103 | 104 | it('should pass the provider options', async () => { 105 | prepareJsonResponse(); 106 | 107 | await provider.embedding('text-embedding-3-large').doEmbed({ 108 | values: testValues, 109 | providerOptions: { 110 | ollama: { 111 | dimensions: 64, 112 | truncate: true, 113 | keepAlive: '10s', 114 | }, 115 | } 116 | }); 117 | 118 | expect(await server.calls[0].requestBodyJson).toStrictEqual({ 119 | model: 'text-embedding-3-large', 120 | input: testValues, 121 | dimensions: 64, 122 | truncate: true, 123 | keep_alive: '10s', 124 | }); 125 | }); 126 | 127 | it('should pass headers', async () => { 128 | prepareJsonResponse(); 129 | 130 | const provider = createOllama({ 131 | headers: { 132 | 'Custom-Provider-Header': 'provider-header-value', 133 | }, 134 | }); 135 | 136 | await provider.embedding('text-embedding-3-large').doEmbed({ 137 | values: testValues, 138 | headers: { 139 | 'Custom-Request-Header': 'request-header-value', 140 | }, 141 | }); 142 | 143 | expect(server.calls[0].requestHeaders).toStrictEqual({ 144 | 'content-type': 'application/json', 145 | 'custom-provider-header': 'provider-header-value', 146 | 'custom-request-header': 'request-header-value', 147 | }); 148 | }); 149 | }); -------------------------------------------------------------------------------- /src/responses/ollama-responses-processor.ts: -------------------------------------------------------------------------------- 1 | import { 2 | LanguageModelV2Content, 3 | LanguageModelV2FinishReason, 4 | LanguageModelV2Usage, 5 | SharedV2ProviderMetadata, 6 | } from "@ai-sdk/provider"; 7 | import { generateId } from "@ai-sdk/provider-utils"; 8 | import { z } from "zod/v4"; 9 | import { mapOllamaFinishReason } from "../adaptors/map-ollama-finish-reason"; 10 | import { OllamaConfig } from "../common/ollama-config"; 11 | 12 | export const baseOllamaResponseSchema = z.object({ 13 | model: z.string(), 14 | created_at: z.string(), 15 | done: z.boolean(), 16 | message: z.object({ 17 | content: z.string(), 18 | role: z.string(), 19 | thinking: z.string().optional(), 20 | tool_calls: z 21 | .array( 22 | z.object({ 23 | function: z.object({ 24 | name: z.string(), 25 | arguments: z.record(z.string(), z.any()), 26 | }), 27 | id: z.string().optional(), 28 | }), 29 | ) 30 | .optional() 31 | .nullable(), 32 | }), 33 | 34 | done_reason: z.string().optional(), 35 | eval_count: z.number().optional(), 36 | eval_duration: z.number().optional(), 37 | load_duration: z.number().optional(), 38 | prompt_eval_count: z.number().optional(), 39 | prompt_eval_duration: z.number().optional(), 40 | total_duration: z.number().optional(), 41 | }); 42 | 43 | export type OllamaResponse = z.infer; 44 | 45 | export class OllamaResponseProcessor { 46 | constructor(private config: OllamaConfig) {} 47 | 48 | processGenerateResponse(response: OllamaResponse): { 49 | content: LanguageModelV2Content[]; 50 | finishReason: LanguageModelV2FinishReason; 51 | usage: LanguageModelV2Usage; 52 | providerMetadata: SharedV2ProviderMetadata; 53 | } { 54 | const content = this.extractContent(response); 55 | const finishReason = mapOllamaFinishReason(response.done_reason); 56 | const usage = this.extractUsage(response); 57 | const providerMetadata: SharedV2ProviderMetadata = { ollama: {} }; 58 | 59 | return { 60 | content, 61 | finishReason, 62 | usage, 63 | providerMetadata, 64 | }; 65 | } 66 | 67 | private extractContent(response: OllamaResponse): LanguageModelV2Content[] { 68 | const content: LanguageModelV2Content[] = []; 69 | 70 | // Add text content 71 | const text = response.message.content; 72 | if (text != null && text.length > 0) { 73 | content.push({ 74 | type: "text", 75 | text, 76 | }); 77 | } 78 | 79 | // Add thinking content 80 | const thinking = response.message.thinking; 81 | if (thinking != null && thinking.length > 0) { 82 | content.push({ 83 | type: "reasoning", 84 | text: thinking, 85 | }); 86 | } 87 | 88 | // Add tool calls 89 | for (const toolCall of response.message.tool_calls ?? []) { 90 | content.push({ 91 | type: "tool-call" as const, 92 | toolCallId: toolCall.id ?? (this.config.generateId?.() ?? generateId()), 93 | toolName: toolCall.function.name, 94 | input: JSON.stringify(toolCall.function.arguments), 95 | }); 96 | } 97 | 98 | return content; 99 | } 100 | 101 | private extractUsage(response: OllamaResponse): LanguageModelV2Usage { 102 | return { 103 | inputTokens: response.prompt_eval_count ?? undefined, 104 | outputTokens: response.eval_count ?? undefined, 105 | totalTokens: (response.prompt_eval_count ?? 0) + (response.eval_count ?? 0), 106 | reasoningTokens: undefined, // Ollama doesn't provide separate reasoning tokens 107 | cachedInputTokens: undefined, 108 | }; 109 | } 110 | } 111 | 112 | /** 113 | * Extracts one or more valid Ollama response objects from a stream chunk. 114 | * Handles both successful parsed chunks and error chunks that may contain 115 | * multiple JSON objects separated by newlines (NDJSON-like behavior). 116 | */ 117 | export function extractOllamaResponseObjectsFromChunk( 118 | chunk: any, 119 | ): OllamaResponse[] { 120 | if (chunk.success) { 121 | return [chunk.value]; 122 | } 123 | 124 | const results: OllamaResponse[] = []; 125 | const raw = (chunk.error as any)?.text; 126 | if (typeof raw !== "string" || raw.length === 0) { 127 | return results; 128 | } 129 | 130 | const lines = raw.split(/\r?\n/); 131 | for (const line of lines) { 132 | const trimmed = line.trim(); 133 | if (trimmed === "") continue; 134 | try { 135 | const parsed = JSON.parse(trimmed); 136 | const validated = baseOllamaResponseSchema.safeParse(parsed); 137 | if (validated.success) { 138 | results.push(validated.data); 139 | } 140 | } catch { 141 | // Ignore malformed line; continue with remaining lines 142 | } 143 | } 144 | 145 | return results; 146 | } -------------------------------------------------------------------------------- /src/responses/ollama-responses-request-builder.ts: -------------------------------------------------------------------------------- 1 | import { 2 | LanguageModelV2CallWarning, 3 | LanguageModelV2, 4 | } from "@ai-sdk/provider"; 5 | import { parseProviderOptions } from "@ai-sdk/provider-utils"; 6 | import { z } from "zod/v4"; 7 | import { convertToOllamaResponsesMessages } from "./convert-to-ollama-responses-messages"; 8 | import { convertToOllamaChatMessages } from "../adaptors/convert-to-ollama-chat-messages"; 9 | import { prepareResponsesTools } from "./ollama-responses-prepare-tools"; 10 | import { OllamaChatModelId, ollamaProviderOptions } from "../ollama-chat-settings"; 11 | 12 | 13 | export type OllamaResponsesProviderOptions = z.infer< 14 | typeof ollamaProviderOptions 15 | >; 16 | 17 | interface RequestBuilderOptions { 18 | modelId: OllamaChatModelId; 19 | maxOutputTokens?: number; 20 | temperature?: number; 21 | stopSequences?: string[]; 22 | topP?: number; 23 | topK?: number; 24 | presencePenalty?: number; 25 | frequencyPenalty?: number; 26 | seed?: number; 27 | prompt: any; 28 | providerOptions?: any; 29 | tools?: any; 30 | toolChoice?: any; 31 | responseFormat?: any; 32 | } 33 | 34 | interface RequestBuilderResult { 35 | args: { 36 | model: OllamaChatModelId; 37 | messages: any; 38 | temperature?: number; 39 | top_p?: number; 40 | max_output_tokens?: number; 41 | format?: any; 42 | user?: string; 43 | think?: boolean; 44 | tools?: any; 45 | tool_choice?: any; 46 | }; 47 | warnings: LanguageModelV2CallWarning[]; 48 | } 49 | 50 | export class OllamaRequestBuilder { 51 | async buildRequest({ 52 | modelId, 53 | maxOutputTokens, 54 | temperature, 55 | stopSequences, 56 | topP, 57 | topK, 58 | presencePenalty, 59 | frequencyPenalty, 60 | seed, 61 | prompt, 62 | providerOptions, 63 | tools, 64 | toolChoice, 65 | responseFormat, 66 | }: RequestBuilderOptions): Promise { 67 | const warnings = this.collectUnsupportedSettingsWarnings({ 68 | topK, 69 | seed, 70 | presencePenalty, 71 | frequencyPenalty, 72 | stopSequences, 73 | }); 74 | 75 | const { messages, warnings: messageWarnings } = 76 | convertToOllamaResponsesMessages({ 77 | prompt, 78 | systemMessageMode: "system", 79 | }); 80 | 81 | warnings.push(...messageWarnings); 82 | 83 | const ollamaOptions = await this.parseProviderOptions(providerOptions); 84 | 85 | const baseArgs = this.buildBaseArgs({ 86 | modelId, 87 | prompt, 88 | temperature, 89 | topP, 90 | maxOutputTokens, 91 | responseFormat, 92 | ollamaOptions, 93 | }); 94 | 95 | const { tools: ollamaTools, toolChoice: ollamaToolChoice, toolWarnings } = 96 | prepareResponsesTools({ 97 | tools, 98 | toolChoice, 99 | }); 100 | 101 | return { 102 | args: { 103 | ...baseArgs, 104 | tools: ollamaTools, 105 | tool_choice: ollamaToolChoice, 106 | }, 107 | warnings: [...warnings, ...toolWarnings], 108 | }; 109 | } 110 | 111 | private collectUnsupportedSettingsWarnings({ 112 | topK, 113 | seed, 114 | presencePenalty, 115 | frequencyPenalty, 116 | stopSequences, 117 | }: { 118 | topK?: number; 119 | seed?: number; 120 | presencePenalty?: number; 121 | frequencyPenalty?: number; 122 | stopSequences?: string[]; 123 | }): LanguageModelV2CallWarning[] { 124 | const warnings: LanguageModelV2CallWarning[] = []; 125 | 126 | const unsupportedSettings = [ 127 | { value: topK, name: "topK" }, 128 | { value: seed, name: "seed" }, 129 | { value: presencePenalty, name: "presencePenalty" }, 130 | { value: frequencyPenalty, name: "frequencyPenalty" }, 131 | { value: stopSequences, name: "stopSequences" }, 132 | ] as const; 133 | 134 | for (const { value, name } of unsupportedSettings) { 135 | if (value != null) { 136 | warnings.push({ type: "unsupported-setting", setting: name }); 137 | } 138 | } 139 | 140 | return warnings; 141 | } 142 | 143 | private async parseProviderOptions(providerOptions: any): Promise { 144 | const result = await parseProviderOptions({ 145 | provider: "ollama", 146 | providerOptions, 147 | schema: ollamaProviderOptions, 148 | }); 149 | return result ?? null; 150 | } 151 | 152 | private buildBaseArgs({ 153 | modelId, 154 | prompt, 155 | temperature, 156 | topP, 157 | maxOutputTokens, 158 | responseFormat, 159 | ollamaOptions, 160 | }: { 161 | modelId: OllamaChatModelId; 162 | prompt: any; 163 | temperature?: number; 164 | topP?: number; 165 | maxOutputTokens?: number; 166 | responseFormat?: any; 167 | ollamaOptions: OllamaResponsesProviderOptions | null; 168 | }) { 169 | return { 170 | model: modelId, 171 | messages: convertToOllamaChatMessages({ 172 | prompt, 173 | systemMessageMode: "system", 174 | }), 175 | temperature, 176 | top_p: topP, 177 | max_output_tokens: maxOutputTokens, 178 | 179 | ...(responseFormat?.type === "json" && { 180 | format: responseFormat.schema != null ? responseFormat.schema : "json", 181 | }), 182 | 183 | think: ollamaOptions?.think ?? false, 184 | options: ollamaOptions?.options?? undefined 185 | }; 186 | } 187 | } -------------------------------------------------------------------------------- /src/ollama-chat-settings.ts: -------------------------------------------------------------------------------- 1 | import { z } from "zod/v4"; 2 | 3 | // https://platform.ollama.com/docs/models 4 | export type OllamaChatModelId = 5 | | "athene-v2" 6 | | "athene-v2:72b" 7 | | "aya-expanse" 8 | | "aya-expanse:8b" 9 | | "aya-expanse:32b" 10 | | "codegemma" 11 | | "codegemma:2b" 12 | | "codegemma:7b" 13 | | "codellama" 14 | | "codellama:7b" 15 | | "codellama:13b" 16 | | "codellama:34b" 17 | | "codellama:70b" 18 | | "codellama:code" 19 | | "codellama:python" 20 | | "command-r" 21 | | "command-r:35b" 22 | | "command-r-plus" 23 | | "command-r-plus:104b" 24 | | "command-r7b" 25 | | "command-r7b:7b" 26 | | "deepseek-r1" 27 | | "deepseek-r1:1.5b" 28 | | "deepseek-r1:7b" 29 | | "deepseek-r1:8b" 30 | | "deepseek-r1:14b" 31 | | "deepseek-r1:32b" 32 | | "deepseek-r1:70b" 33 | | "deepseek-r1:671b" 34 | | "deepseek-coder-v2" 35 | | "deepseek-coder-v2:16b" 36 | | "deepseek-coder-v2:236b" 37 | | "deepseek-v3" 38 | | "deepseek-v3:671b" 39 | | "devstral" 40 | | "devstral:24b" 41 | | "dolphin3" 42 | | "dolphin3:8b" 43 | | "exaone3.5" 44 | | "exaone3.5:2.4b" 45 | | "exaone3.5:7.8b" 46 | | "exaone3.5:32b" 47 | | "falcon2" 48 | | "falcon2:11b" 49 | | "falcon3" 50 | | "falcon3:1b" 51 | | "falcon3:3b" 52 | | "falcon3:7b" 53 | | "falcon3:10b" 54 | | "firefunction-v2" 55 | | "firefunction-v2:70b" 56 | | "gemma" 57 | | "gemma:2b" 58 | | "gemma:7b" 59 | | "gemma2" 60 | | "gemma2:2b" 61 | | "gemma2:9b" 62 | | "gemma2:27b" 63 | | "gemma3" 64 | | "gemma3:1b" 65 | | "gemma3:4b" 66 | | "gemma3:12b" 67 | | "gemma3:27b" 68 | | "granite3-dense" 69 | | "granite3-dense:2b" 70 | | "granite3-dense:8b" 71 | | "granite3-guardian" 72 | | "granite3-guardian:2b" 73 | | "granite3-guardian:8b" 74 | | "granite3-moe" 75 | | "granite3-moe:1b" 76 | | "granite3-moe:3b" 77 | | "granite3.1-dense" 78 | | "granite3.1-dense:2b" 79 | | "granite3.1-dense:8b" 80 | | "granite3.1-moe" 81 | | "granite3.1-moe:1b" 82 | | "granite3.1-moe:3b" 83 | | "llama2" 84 | | "llama2:7b" 85 | | "llama2:13b" 86 | | "llama2:70b" 87 | | "llama3" 88 | | "llama3:8b" 89 | | "llama3:70b" 90 | | "llama3-chatqa" 91 | | "llama3-chatqa:8b" 92 | | "llama3-chatqa:70b" 93 | | "llama3-gradient" 94 | | "llama3-gradient:8b" 95 | | "llama3-gradient:70b" 96 | | "llama3.1" 97 | | "llama3.1:8b" 98 | | "llama3.1:70b" 99 | | "llama3.1:405b" 100 | | "llama3.2" 101 | | "llama3.2:1b" 102 | | "llama3.2:3b" 103 | | "llama3.2-vision" 104 | | "llama3.2-vision:11b" 105 | | "llama3.2-vision:90b" 106 | | "llama3.3" 107 | | "llama3.3:70b" 108 | | "llama4" 109 | | "llama4:16x17b" 110 | | "llama4:128x17b" 111 | | "llama-guard3" 112 | | "llama-guard3:1b" 113 | | "llama-guard3:8b" 114 | | "llava" 115 | | "llava:7b" 116 | | "llava:13b" 117 | | "llava:34b" 118 | | "llava-llama3" 119 | | "llava-llama3:8b" 120 | | "llava-phi3" 121 | | "llava-phi3:3.8b" 122 | | "marco-o1" 123 | | "marco-o1:7b" 124 | | "mistral" 125 | | "mistral:7b" 126 | | "mistral-large" 127 | | "mistral-large:123b" 128 | | "mistral-nemo" 129 | | "mistral-nemo:12b" 130 | | "mistral-small" 131 | | "mistral-small:22b" 132 | | "mixtral" 133 | | "mixtral:8x7b" 134 | | "mixtral:8x22b" 135 | | "moondream" 136 | | "moondream:1.8b" 137 | | "openhermes" 138 | | "openhermes:v2.5" 139 | | "nemotron" 140 | | "nemotron:70b" 141 | | "nemotron-mini" 142 | | "nemotron-mini:4b" 143 | | "olmo" 144 | | "olmo:7b" 145 | | "olmo:13b" 146 | | "opencoder" 147 | | "opencoder:1.5b" 148 | | "opencoder:8b" 149 | | "phi3" 150 | | "phi3:3.8b" 151 | | "phi3:14b" 152 | | "phi3.5" 153 | | "phi3.5:3.8b" 154 | | "phi4" 155 | | "phi4:14b" 156 | | "qwen" 157 | | "qwen:7b" 158 | | "qwen:14b" 159 | | "qwen:32b" 160 | | "qwen:72b" 161 | | "qwen:110b" 162 | | "qwen2" 163 | | "qwen2:0.5b" 164 | | "qwen2:1.5b" 165 | | "qwen2:7b" 166 | | "qwen2:72b" 167 | | "qwen2.5" 168 | | "qwen2.5:0.5b" 169 | | "qwen2.5:1.5b" 170 | | "qwen2.5:3b" 171 | | "qwen2.5:7b" 172 | | "qwen2.5:14b" 173 | | "qwen2.5:32b" 174 | | "qwen2.5:72b" 175 | | "qwen2.5-coder" 176 | | "qwen2.5-coder:0.5b" 177 | | "qwen2.5-coder:1.5b" 178 | | "qwen2.5-coder:3b" 179 | | "qwen2.5-coder:7b" 180 | | "qwen2.5-coder:14b" 181 | | "qwen2.5-coder:32b" 182 | | "qwen3" 183 | | "qwen3:0.6b" 184 | | "qwen3:1.7b" 185 | | "qwen3:4b" 186 | | "qwen3:8b" 187 | | "qwen3:14b" 188 | | "qwen3:30b" 189 | | "qwen3:32b" 190 | | "qwen3:235b" 191 | | "qwq" 192 | | "qwq:32b" 193 | | "sailor2" 194 | | "sailor2:1b" 195 | | "sailor2:8b" 196 | | "sailor2:20b" 197 | | "shieldgemma" 198 | | "shieldgemma:2b" 199 | | "shieldgemma:9b" 200 | | "shieldgemma:27b" 201 | | "smallthinker" 202 | | "smallthinker:3b" 203 | | "smollm" 204 | | "smollm:135m" 205 | | "smollm:360m" 206 | | "smollm:1.7b" 207 | | "tinyllama" 208 | | "tinyllama:1.1b" 209 | | "tulu3" 210 | | "tulu3:8b" 211 | | "tulu3:70b" 212 | | (string & {}); 213 | 214 | export const ollamaProviderOptions = z.object({ 215 | /** 216 | * Enable or disable the model's thinking process. When enabled, the output will separate 217 | * the model's thinking from the model's output. When disabled, the model will not think 218 | * and directly output the content. 219 | * 220 | * Only supported by certain models like DeepSeek R1 and Qwen 3. 221 | */ 222 | think: z.boolean().optional(), 223 | options: z.object({ 224 | num_ctx: z.number().optional(), 225 | repeat_last_n: z.number().optional(), 226 | repeat_penalty: z.number().optional(), 227 | temperature: z.number().optional(), 228 | seed: z.number().optional(), 229 | stop: z.array(z.string()).optional(), 230 | num_predict: z.number().optional(), 231 | top_k: z.number().optional(), 232 | top_p: z.number().optional(), 233 | min_p: z.number().optional(), 234 | }).optional() 235 | 236 | 237 | }); 238 | 239 | export type OllamaProviderOptions = z.infer; 240 | -------------------------------------------------------------------------------- /src/ollama-provider.ts: -------------------------------------------------------------------------------- 1 | import { 2 | EmbeddingModelV2, 3 | LanguageModelV2, 4 | ProviderV2, 5 | NoSuchModelError, 6 | } from '@ai-sdk/provider'; 7 | import { 8 | FetchFunction, 9 | withoutTrailingSlash, 10 | } from '@ai-sdk/provider-utils'; 11 | import { OllamaChatModelId, OllamaProviderOptions, ollamaProviderOptions } from './ollama-chat-settings'; 12 | import { OllamaCompletionLanguageModel } from './completion/ollama-completion-language-model'; 13 | import { 14 | OllamaCompletionModelId, 15 | OllamaCompletionSettings, 16 | } from './completion/ollama-completion-settings'; 17 | import { OllamaEmbeddingModel } from './embedding/ollama-embedding-model'; 18 | import { 19 | OllamaEmbeddingModelId, 20 | OllamaEmbeddingSettings, 21 | } from './embedding/ollama-embedding-settings'; 22 | import { OllamaResponsesLanguageModel } from './responses/ollama-responses-language-model'; 23 | 24 | export interface OllamaProvider extends ProviderV2 { 25 | (modelId: OllamaChatModelId): LanguageModelV2; 26 | 27 | /** 28 | Creates an Ollama model for text generation. 29 | */ 30 | languageModel(modelId: OllamaChatModelId): LanguageModelV2; 31 | 32 | /** 33 | Creates an Ollama chat model for text generation. 34 | */ 35 | chat( 36 | modelId: OllamaChatModelId, 37 | settings?: OllamaProviderOptions, 38 | ): LanguageModelV2; 39 | 40 | /** 41 | Creates an Ollama completion model for text generation. 42 | */ 43 | completion( 44 | modelId: OllamaCompletionModelId, 45 | settings?: OllamaCompletionSettings, 46 | ): LanguageModelV2; 47 | 48 | /** 49 | Creates a model for text embeddings. 50 | */ 51 | embedding( 52 | modelId: OllamaEmbeddingModelId, 53 | settings?: OllamaEmbeddingSettings, 54 | ): EmbeddingModelV2; 55 | 56 | /** 57 | Creates a model for text embeddings. 58 | 59 | @deprecated Use `textEmbeddingModel` instead. 60 | */ 61 | textEmbedding( 62 | modelId: OllamaEmbeddingModelId, 63 | settings?: OllamaEmbeddingSettings, 64 | ): EmbeddingModelV2; 65 | 66 | /** 67 | Creates a model for text embeddings. 68 | */ 69 | textEmbeddingModel( 70 | modelId: OllamaEmbeddingModelId, 71 | settings?: OllamaEmbeddingSettings, 72 | ): EmbeddingModelV2; 73 | 74 | } 75 | 76 | export interface OllamaProviderSettings { 77 | /** 78 | Base URL for the Ollama API calls. 79 | */ 80 | baseURL?: string; 81 | 82 | /** 83 | Ollama Organization. 84 | */ 85 | organization?: string; 86 | 87 | /** 88 | Ollama project. 89 | */ 90 | project?: string; 91 | 92 | /** 93 | Custom headers to include in the requests. 94 | */ 95 | headers?: Record; 96 | 97 | /** 98 | Ollama compatibility mode. Should be set to `strict` when using the Ollama API, 99 | and `compatible` when using 3rd party providers. In `compatible` mode, newer 100 | information such as streamOptions are not being sent. Defaults to 'compatible'. 101 | */ 102 | compatibility?: 'strict' | 'compatible'; 103 | 104 | /** 105 | Provider name. Overrides the `ollama` default name for 3rd party providers. 106 | */ 107 | name?: string; 108 | 109 | /** 110 | Custom fetch implementation. You can use it as a middleware to intercept requests, 111 | or to provide a custom fetch implementation for e.g. testing. 112 | */ 113 | fetch?: FetchFunction; 114 | } 115 | 116 | /** 117 | Create an Ollama provider instance. 118 | */ 119 | export function createOllama( 120 | options: OllamaProviderSettings = {}, 121 | ): OllamaProvider { 122 | const baseURL = 123 | withoutTrailingSlash(options.baseURL) ?? 'http://127.0.0.1:11434/api'; 124 | 125 | const providerName = options.name ?? 'ollama'; 126 | 127 | const getHeaders = () => ({ 128 | 'Ollama-Organization': options.organization, 129 | 'Ollama-Project': options.project, 130 | ...options.headers, 131 | }); 132 | 133 | const createCompletionModel = ( 134 | modelId: OllamaCompletionModelId, 135 | settings: OllamaCompletionSettings = {}, 136 | ) => 137 | new OllamaCompletionLanguageModel(modelId, settings, { 138 | provider: `${providerName}.completion`, 139 | url: ({ path }) => `${baseURL}${path}`, 140 | headers: getHeaders, 141 | fetch: options.fetch, 142 | }); 143 | 144 | const createEmbeddingModel = ( 145 | modelId: OllamaEmbeddingModelId, 146 | settings: OllamaEmbeddingSettings = {}, 147 | ) => 148 | new OllamaEmbeddingModel(modelId, settings, { 149 | provider: `${providerName}.embedding`, 150 | url: ({ path }) => `${baseURL}${path}`, 151 | headers: getHeaders, 152 | fetch: options.fetch, 153 | }); 154 | 155 | const createLanguageModel = ( 156 | modelId: OllamaChatModelId) => { 157 | if (new.target) { 158 | throw new Error( 159 | 'The Ollama model function cannot be called with the new keyword.', 160 | ); 161 | } 162 | 163 | return createResponsesModel(modelId); 164 | }; 165 | 166 | const createResponsesModel = (modelId: OllamaChatModelId) => { 167 | return new OllamaResponsesLanguageModel(modelId, { 168 | provider: `${providerName}.responses`, 169 | url: ({ path }) => `${baseURL}${path}`, 170 | headers: getHeaders, 171 | fetch: options.fetch, 172 | }); 173 | }; 174 | 175 | const provider = function (modelId: OllamaChatModelId) { 176 | return createLanguageModel(modelId); 177 | }; 178 | 179 | provider.languageModel = createLanguageModel; 180 | provider.chat = createLanguageModel; 181 | provider.completion = createCompletionModel; 182 | provider.embedding = createEmbeddingModel; 183 | provider.textEmbedding = createEmbeddingModel; 184 | provider.textEmbeddingModel = createEmbeddingModel; 185 | provider.imageModel = (modelId: string) => { 186 | throw new NoSuchModelError({ 187 | modelId, 188 | modelType: 'imageModel', 189 | message: 'Image generation is unsupported with Ollama', 190 | }); 191 | }; 192 | 193 | return provider as OllamaProvider; 194 | } 195 | 196 | /** 197 | Default Ollama provider instance. 198 | */ 199 | export const ollama = createOllama(); 200 | 201 | -------------------------------------------------------------------------------- /src/responses/convert-to-ollama-responses-messages.ts: -------------------------------------------------------------------------------- 1 | import { 2 | LanguageModelV2CallWarning, 3 | LanguageModelV2Prompt, 4 | UnsupportedFunctionalityError, 5 | } from '@ai-sdk/provider'; 6 | import { OllamaResponsesPrompt } from './ollama-responses-api-types'; 7 | 8 | export function convertToOllamaResponsesMessages({ 9 | prompt, 10 | systemMessageMode, 11 | }: { 12 | prompt: LanguageModelV2Prompt; 13 | systemMessageMode: 'system' | 'developer' | 'remove'; 14 | }): { 15 | messages: OllamaResponsesPrompt; 16 | warnings: Array; 17 | } { 18 | const messages: OllamaResponsesPrompt = []; 19 | const warnings: Array = []; 20 | 21 | for (const { role, content } of prompt) { 22 | switch (role) { 23 | case 'system': { 24 | switch (systemMessageMode) { 25 | case 'system': { 26 | messages.push({ role: 'system', content }); 27 | break; 28 | } 29 | case 'developer': { 30 | messages.push({ role: 'developer', content }); 31 | break; 32 | } 33 | case 'remove': { 34 | warnings.push({ 35 | type: 'other', 36 | message: 'system messages are removed for this model', 37 | }); 38 | break; 39 | } 40 | default: { 41 | const _exhaustiveCheck: never = systemMessageMode; 42 | throw new Error( 43 | `Unsupported system message mode: ${_exhaustiveCheck}`, 44 | ); 45 | } 46 | } 47 | break; 48 | } 49 | 50 | case 'user': { 51 | messages.push({ 52 | role: 'user', 53 | content: content.map((part, index) => { 54 | switch (part.type) { 55 | case 'text': { 56 | return { type: 'input_text', text: part.text }; 57 | } 58 | case 'file': { 59 | if (part.mediaType.startsWith('image/')) { 60 | const mediaType = 61 | part.mediaType === 'image/*' 62 | ? 'image/jpeg' 63 | : part.mediaType; 64 | 65 | return { 66 | type: 'input_image', 67 | image_url: 68 | part.data instanceof URL 69 | ? part.data.toString() 70 | : `data:${mediaType};base64,${part.data}`, 71 | 72 | // Ollama specific extension: image detail 73 | detail: part.providerOptions?.ollama?.imageDetail, 74 | }; 75 | } else if (part.mediaType === 'application/pdf') { 76 | if (part.data instanceof URL) { 77 | // The AI SDK automatically downloads files for user file parts with URLs 78 | throw new UnsupportedFunctionalityError({ 79 | functionality: 'PDF file parts with URLs', 80 | }); 81 | } 82 | 83 | return { 84 | type: 'input_file', 85 | filename: part.filename ?? `part-${index}.pdf`, 86 | file_data: `data:application/pdf;base64,${part.data}`, 87 | }; 88 | } else { 89 | throw new UnsupportedFunctionalityError({ 90 | functionality: `file part media type ${part.mediaType}`, 91 | }); 92 | } 93 | } 94 | } 95 | }), 96 | }); 97 | 98 | break; 99 | } 100 | 101 | case 'assistant': { 102 | for (const part of content) { 103 | switch (part.type) { 104 | case 'text': { 105 | messages.push({ 106 | role: 'assistant', 107 | content: [{ type: 'output_text', text: part.text }], 108 | }); 109 | break; 110 | } 111 | case 'tool-call': { 112 | if (part.providerExecuted) { 113 | break; 114 | } 115 | 116 | messages.push({ 117 | type: 'function_call', 118 | call_id: part.toolCallId, 119 | name: part.toolName, 120 | arguments: JSON.stringify(part.input), 121 | }); 122 | break; 123 | } 124 | 125 | case 'tool-result': { 126 | warnings.push({ 127 | type: 'other', 128 | message: `tool result parts in assistant messages are not supported for Ollama responses`, 129 | }); 130 | break; 131 | } 132 | } 133 | } 134 | 135 | break; 136 | } 137 | 138 | case 'tool': { 139 | for (const part of content) { 140 | const output = part.output; 141 | 142 | let contentValue: string; 143 | switch (output.type) { 144 | case 'text': 145 | case 'error-text': 146 | contentValue = output.value; 147 | break; 148 | case 'content': 149 | case 'json': 150 | case 'error-json': 151 | contentValue = JSON.stringify(output.value); 152 | break; 153 | } 154 | 155 | messages.push({ 156 | type: 'function_call_output', 157 | call_id: part.toolCallId, 158 | output: contentValue, 159 | }); 160 | } 161 | 162 | break; 163 | } 164 | 165 | default: { 166 | const _exhaustiveCheck: never = role; 167 | throw new Error(`Unsupported role: ${_exhaustiveCheck}`); 168 | } 169 | } 170 | } 171 | 172 | return { messages, warnings }; 173 | } 174 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Ollama Provider V2 for Vercel AI SDK 2 | 3 | Use Ollama with the Vercel AI SDK, implementing the official Ollama API. This provider has minimal dependencies and is web-compatible out of the box. 4 | 5 | [![npm version](https://badge.fury.io/js/ollama-ai-provider-v2.svg)](https://badge.fury.io/js/ollama-ai-provider-v2) 6 | [![TypeScript](https://img.shields.io/badge/TypeScript-5.8+-blue.svg)](https://www.typescriptlang.org/) 7 | [![Node.js](https://img.shields.io/badge/Node.js-18+-green.svg)](https://nodejs.org/) 8 | [![License: Apache-2.0](https://img.shields.io/badge/License-Apache--2.0-yellow.svg)](https://opensource.org/licenses/Apache-2.0) 9 | 10 | ## Why Choose Ollama Provider V2? 11 | 12 | - ✅ **Minimal Dependencies** - Lean codebase with just 2 core dependencies 13 | - ✅ **Universal Compatibility** - Works seamlessly in Node.js, browsers, and edge environments 14 | - ✅ **Direct Ollama Integration** - Uses official Ollama API endpoints for maximum compatibility 15 | - ✅ **Advanced Features** - Tool calling, streaming, thinking mode, embeddings, and completion models 16 | - ✅ **Type Safety** - Full TypeScript support with comprehensive type definitions 17 | - ✅ **Zero Configuration** - Works out-of-the-box with sensible defaults 18 | - ✅ **Actively Maintained** - Regular updates and AI SDK v5+ compatibility 19 | 20 | ## Quick Start 21 | 22 | ```bash 23 | npm install ollama-ai-provider-v2 ai 24 | ``` 25 | 26 | ```typescript 27 | import { ollama } from 'ollama-ai-provider-v2'; 28 | import { generateText } from 'ai'; 29 | 30 | // Works everywhere - Node.js, browsers, edge environments 31 | const { text } = await generateText({ 32 | model: ollama('llama3.2'), 33 | prompt: 'Write a haiku about coding', 34 | }); 35 | 36 | console.log(text); 37 | ``` 38 | 39 | ## Core Features 40 | 41 | ### Streaming Text Generation 42 | 43 | ```typescript 44 | import { streamText } from 'ai'; 45 | 46 | const { textStream } = await streamText({ 47 | model: ollama('llama3.2'), 48 | prompt: 'Tell me a story about artificial intelligence', 49 | }); 50 | 51 | for await (const chunk of textStream) { 52 | process.stdout.write(chunk); 53 | } 54 | ``` 55 | 56 | ### Tool Calling Support 57 | 58 | ```typescript 59 | import { generateText, tool } from 'ai'; 60 | import { z } from 'zod'; 61 | 62 | const { text, toolCalls } = await generateText({ 63 | model: ollama('llama3.2'), 64 | prompt: 'What is the weather like in San Francisco?', 65 | tools: { 66 | getWeather: tool({ 67 | description: 'Get current weather for a location', 68 | inputSchema: z.object({ 69 | location: z.string().describe('City name'), 70 | unit: z.enum(['celsius', 'fahrenheit']).optional(), 71 | }), 72 | execute: async ({ location, unit = 'celsius' }) => { 73 | return { temp: 18, unit, condition: 'sunny' }; 74 | }, 75 | }), 76 | }, 77 | }); 78 | ``` 79 | 80 | ### Reasoning Mode (Thinking) 81 | 82 | Unique feature for models that support chain-of-thought reasoning: 83 | 84 | ```typescript 85 | const { text } = await generateText({ 86 | model: ollama('deepseek-r1:7b'), 87 | providerOptions: { ollama: { think: true } }, 88 | prompt: 'Solve this complex math problem step by step: 2x + 5 = 17', 89 | }); 90 | ``` 91 | 92 | ### Advanced Ollama Options 93 | 94 | Access Ollama's native parameters while maintaining AI SDK compatibility: 95 | 96 | ```typescript 97 | const { text } = await generateText({ 98 | model: ollama('llama3.2'), 99 | providerOptions: { 100 | ollama: { 101 | options: { 102 | seed: 123, // Deterministic outputs 103 | num_ctx: 8192, // Context window size 104 | repeat_penalty: 1.1, // Control repetition 105 | top_k: 40, // Advanced sampling 106 | min_p: 0.1, // Minimum probability 107 | }, 108 | }, 109 | }, 110 | prompt: 'Write a detailed analysis of Alice in Wonderland', 111 | temperature: 0.8, // Standard AI SDK parameters work too 112 | }); 113 | ``` 114 | 115 | ### Embeddings 116 | 117 | ```typescript 118 | import { embed } from 'ai'; 119 | 120 | // Single embedding 121 | const { embedding } = await embed({ 122 | model: ollama.embedding('nomic-embed-text'), 123 | value: 'Hello world', 124 | }); 125 | 126 | console.log('Embedding dimensions:', embedding.length); 127 | 128 | // Batch embeddings 129 | const texts = ['Hello world', 'How are you?', 'AI is amazing']; 130 | const results = await Promise.all( 131 | texts.map((text) => 132 | embed({ 133 | model: ollama.embedding('all-minilm'), 134 | value: text, 135 | }) 136 | ) 137 | ); 138 | ``` 139 | 140 | ### Completion Models 141 | 142 | For use cases requiring completion-style generation: 143 | 144 | ```typescript 145 | const { text } = await generateText({ 146 | model: ollama.completion('codellama:code'), 147 | prompt: 'def fibonacci(n):\n if n <= 1:\n return n\n else:\n return fibonacci(n-1) + fibonacci(n-2)\n\n# Optimize this function:\n', 148 | }); 149 | ``` 150 | 151 | ## Custom Ollama Instance 152 | 153 | Connect to remote Ollama servers or custom configurations: 154 | 155 | ```typescript 156 | import { createOllama } from 'ollama-ai-provider-v2'; 157 | 158 | const customOllama = createOllama({ 159 | baseURL: 'https://my-ollama-server.com/api', 160 | headers: { 161 | 'Authorization': 'Bearer your-token', 162 | }, 163 | }); 164 | 165 | const { text } = await generateText({ 166 | model: customOllama('llama3.2'), 167 | prompt: 'Hello from remote server!', 168 | }); 169 | ``` 170 | 171 | ## Supported Models 172 | 173 | Works with any model in your Ollama installation, including: 174 | 175 | - **Chat Models**: `llama3.2`, `mistral`, `phi4-mini`, `qwen2.5`, `codellama`, `gemma3` 176 | - **Vision Models**: `llava`, `llama3.2-vision`, `minicpm-v` 177 | - **Reasoning Models**: `deepseek-r1:7b`, `deepseek-r1:1.5b`, `deepseek-r1:8b` 178 | - **Code Models**: `codellama:code`, `codellama:python`, `deepseek-coder-v2` 179 | - **Embedding Models**: `nomic-embed-text`, `all-minilm`, `mxbai-embed-large` 180 | 181 | ## Prerequisites 182 | 183 | 1. [Ollama](https://ollama.com) installed and running 184 | 2. AI SDK v5+ (`ai` package) 185 | 3. Node.js 18+ for development 186 | 187 | ```bash 188 | # Start Ollama 189 | ollama serve 190 | 191 | # Pull a model 192 | ollama pull llama3.2 193 | ``` 194 | 195 | ## Contributing 196 | 197 | Contributions are welcome! Here's how to get started: 198 | 199 | 1. **Fork the repository** 200 | 2. **Install dependencies**: `pnpm install` 201 | 3. **Build the project**: `pnpm build` 202 | 4. **Run tests**: `pnpm test` 203 | 5. **Make your changes** 204 | 6. **Test locally**: Copy `dist/*` to your project's `node_modules/ollama-ai-provider-v2/dist` 205 | 7. **Submit a pull request** 206 | 207 | ## License 208 | 209 | Apache-2.0 © [nordwestt](https://github.com/nordwestt/ollama-ai-provider-v2) 210 | 211 | See [LICENSE.md](./LICENSE.md) for details. -------------------------------------------------------------------------------- /src/responses/ollama-responses-language-model.test.ts: -------------------------------------------------------------------------------- 1 | import { OllamaResponsesLanguageModel } from './ollama-responses-language-model'; 2 | import { 3 | TEST_PROMPT, 4 | TEST_TOOLS, 5 | TEST_MODEL_ID, 6 | createTestConfig, 7 | createMockServer, 8 | prepareJsonResponse, 9 | prepareErrorResponse, 10 | prepareStreamResponse, 11 | } from './test-helpers/ollama-test-helpers'; 12 | 13 | describe('OllamaResponsesLanguageModel', () => { 14 | const testConfig = createTestConfig(); 15 | const model = new OllamaResponsesLanguageModel(TEST_MODEL_ID, testConfig); 16 | const server = createMockServer(); 17 | 18 | describe('Model Properties', () => { 19 | it('should have correct specification version', () => { 20 | expect(model.specificationVersion).toBe('v2'); 21 | }); 22 | 23 | it('should have correct model ID', () => { 24 | expect(model.modelId).toBe(TEST_MODEL_ID); 25 | }); 26 | 27 | it('should have correct provider', () => { 28 | expect(model.provider).toBe('ollama.responses'); 29 | }); 30 | 31 | it('should support image URLs', () => { 32 | expect(model.supportedUrls['image/*']).toEqual([/^https?:\/\/.*$/]); 33 | }); 34 | }); 35 | 36 | describe('doGenerate', () => { 37 | describe('Basic Generation', () => { 38 | it('should generate text response', async () => { 39 | prepareJsonResponse(server); 40 | 41 | const result = await model.doGenerate({ 42 | prompt: TEST_PROMPT, 43 | maxOutputTokens: 100, 44 | temperature: 0.7, 45 | }); 46 | 47 | expect(result.content).toEqual([ 48 | { type: 'text', text: 'Hello, how can I help you?' }, 49 | ]); 50 | expect(result.finishReason).toBe('stop'); 51 | expect(result.usage).toEqual({ 52 | inputTokens: 10, 53 | outputTokens: 20, 54 | totalTokens: 30, 55 | reasoningTokens: undefined, 56 | cachedInputTokens: undefined, 57 | }); 58 | }); 59 | 60 | it('should expose raw response data', async () => { 61 | prepareJsonResponse(server, { 62 | headers: { 'x-custom-header': 'test-value' }, 63 | }); 64 | 65 | const result = await model.doGenerate({ 66 | prompt: TEST_PROMPT, 67 | }); 68 | 69 | expect(result.response?.headers).toMatchObject({ 70 | 'x-custom-header': 'test-value', 71 | }); 72 | expect(result.request?.body).toBeDefined(); 73 | }); 74 | }); 75 | 76 | describe('Tool Calls', () => { 77 | it('should handle tool calls', async () => { 78 | prepareJsonResponse(server, { 79 | content: 'I need to check the weather for you.', 80 | toolCalls: [ 81 | { 82 | id: 'call_1', 83 | function: { 84 | name: 'weather', 85 | arguments: { location: 'San Francisco' }, 86 | }, 87 | }, 88 | ], 89 | }); 90 | 91 | const result = await model.doGenerate({ 92 | prompt: TEST_PROMPT, 93 | tools: TEST_TOOLS, 94 | }); 95 | 96 | expect(result.content).toEqual([ 97 | { type: 'text', text: 'I need to check the weather for you.' }, 98 | { 99 | type: 'tool-call', 100 | toolCallId: 'call_1', 101 | toolName: 'weather', 102 | input: '{"location":"San Francisco"}', 103 | }, 104 | ]); 105 | }); 106 | 107 | it('should generate tool call ID when missing', async () => { 108 | prepareJsonResponse(server, { 109 | content: '', 110 | toolCalls: [ 111 | { 112 | function: { 113 | name: 'weather', 114 | arguments: { location: 'New York' }, 115 | }, 116 | }, 117 | ], 118 | }); 119 | 120 | const result = await model.doGenerate({ 121 | prompt: TEST_PROMPT, 122 | tools: TEST_TOOLS, 123 | }); 124 | 125 | expect(result.content[0]).toEqual({ 126 | type: 'tool-call', 127 | toolCallId: 'mock-id-1', 128 | toolName: 'weather', 129 | input: '{"location":"New York"}', 130 | }); 131 | }); 132 | }); 133 | 134 | describe('Settings and Options', () => { 135 | it('should return warnings for unsupported settings', async () => { 136 | prepareJsonResponse(server); 137 | 138 | const result = await model.doGenerate({ 139 | prompt: TEST_PROMPT, 140 | topK: 50, 141 | seed: 123, 142 | presencePenalty: 0.5, 143 | frequencyPenalty: 0.3, 144 | stopSequences: ['stop'], 145 | }); 146 | 147 | expect(result.warnings).toEqual([ 148 | { type: 'unsupported-setting', setting: 'topK' }, 149 | { type: 'unsupported-setting', setting: 'seed' }, 150 | { type: 'unsupported-setting', setting: 'presencePenalty' }, 151 | { type: 'unsupported-setting', setting: 'frequencyPenalty' }, 152 | { type: 'unsupported-setting', setting: 'stopSequences' }, 153 | ]); 154 | }); 155 | 156 | it('should handle JSON response format', async () => { 157 | prepareJsonResponse(server, { 158 | content: '{"result": "success"}', 159 | }); 160 | 161 | const result = await model.doGenerate({ 162 | prompt: TEST_PROMPT, 163 | responseFormat: { 164 | type: 'json', 165 | schema: { 166 | type: 'object', 167 | properties: { result: { type: 'string' } }, 168 | }, 169 | }, 170 | }); 171 | 172 | expect(result.content[0]).toEqual({ 173 | type: 'text', 174 | text: '{"result": "success"}', 175 | }); 176 | }); 177 | 178 | it('should handle provider options', async () => { 179 | prepareJsonResponse(server); 180 | 181 | const result = await model.doGenerate({ 182 | prompt: TEST_PROMPT, 183 | providerOptions: { 184 | ollama: { 185 | user: 'test-user', 186 | metadata: { session: 'test' }, 187 | think: true, 188 | }, 189 | }, 190 | }); 191 | 192 | expect(result.warnings).toEqual([]); 193 | }); 194 | }); 195 | 196 | describe('Error Handling', () => { 197 | it('should handle API errors', async () => { 198 | prepareErrorResponse(server); 199 | 200 | await expect( 201 | model.doGenerate({ 202 | prompt: TEST_PROMPT, 203 | }) 204 | ).rejects.toThrow(); 205 | }); 206 | }); 207 | }); 208 | 209 | describe('doStream', () => { 210 | describe('Basic Streaming', () => { 211 | it('should handle basic streaming', async () => { 212 | prepareStreamResponse(server); 213 | 214 | const result = await model.doStream({ 215 | prompt: TEST_PROMPT, 216 | }); 217 | 218 | expect(result.response?.headers).toBeDefined(); 219 | expect(result.request?.body).toBeDefined(); 220 | expect(result.stream).toBeDefined(); 221 | }); 222 | 223 | it('should handle stream with warnings', async () => { 224 | prepareStreamResponse(server); 225 | 226 | const result = await model.doStream({ 227 | prompt: TEST_PROMPT, 228 | topK: 50, // unsupported setting 229 | }); 230 | 231 | expect(result.stream).toBeDefined(); 232 | }); 233 | }); 234 | }); 235 | }); -------------------------------------------------------------------------------- /src/responses/ollama-responses-stream-processor.ts: -------------------------------------------------------------------------------- 1 | import { 2 | InvalidResponseDataError, 3 | LanguageModelV2FinishReason, 4 | LanguageModelV2StreamPart, 5 | LanguageModelV2Usage, 6 | } from "@ai-sdk/provider"; 7 | import { generateId, ParseResult } from "@ai-sdk/provider-utils"; 8 | import { z } from "zod/v4"; 9 | import { OllamaConfig } from "../common/ollama-config"; 10 | import { getResponseMetadata } from "../common/get-response-metadata"; 11 | import { mapOllamaFinishReason } from "../adaptors/map-ollama-finish-reason"; 12 | import { 13 | baseOllamaResponseSchema, 14 | OllamaResponse, 15 | extractOllamaResponseObjectsFromChunk, 16 | } from "./ollama-responses-processor"; 17 | 18 | interface StreamState { 19 | finishReason: LanguageModelV2FinishReason; 20 | usage: LanguageModelV2Usage; 21 | responseId: string | null; 22 | ongoingToolCalls: Record; 23 | hasToolCalls: boolean; 24 | isFirstChunk: boolean; 25 | hasTextStarted: boolean; 26 | hasReasoningStarted: boolean; 27 | textEnded: boolean; 28 | reasoningEnded: boolean; 29 | textId: string; 30 | } 31 | 32 | export class OllamaStreamProcessor { 33 | private state: StreamState; 34 | 35 | constructor(private config: OllamaConfig) { 36 | this.state = this.initializeState(); 37 | } 38 | 39 | createTransformStream(warnings: any[], options: any): TransformStream< 40 | ParseResult>, 41 | LanguageModelV2StreamPart 42 | > { 43 | return new TransformStream({ 44 | start: (controller) => { 45 | controller.enqueue({ type: "stream-start", warnings }); 46 | }, 47 | 48 | transform: (chunk, controller) => { 49 | this.processChunk(chunk, controller, options); 50 | }, 51 | 52 | flush: (controller) => { 53 | this.finalizeStream(controller); 54 | }, 55 | }); 56 | } 57 | 58 | private initializeState(): StreamState { 59 | return { 60 | finishReason: "unknown", 61 | usage: { 62 | inputTokens: undefined, 63 | outputTokens: undefined, 64 | totalTokens: undefined, 65 | }, 66 | responseId: null, 67 | ongoingToolCalls: {}, 68 | hasToolCalls: false, 69 | isFirstChunk: true, 70 | hasTextStarted: false, 71 | hasReasoningStarted: false, 72 | textEnded: false, 73 | reasoningEnded: false, 74 | textId: generateId(), 75 | }; 76 | } 77 | 78 | private processChunk( 79 | chunk: ParseResult>, 80 | controller: TransformStreamDefaultController, 81 | options: any, 82 | ) { 83 | if ((options as any)?.includeRawChunks) { 84 | controller.enqueue({ type: "raw", rawValue: (chunk as any).rawValue }); 85 | } 86 | 87 | const values = extractOllamaResponseObjectsFromChunk(chunk); 88 | 89 | if (values.length === 0) { 90 | if (!chunk.success) { 91 | this.state.finishReason = "error"; 92 | controller.enqueue({ type: "error", error: chunk.error }); 93 | } 94 | return; 95 | } 96 | 97 | for (const value of values) { 98 | this.processResponseValue(value, controller); 99 | } 100 | } 101 | 102 | private processResponseValue( 103 | value: OllamaResponse, 104 | controller: TransformStreamDefaultController, 105 | ) { 106 | // Handle error-like chunks 107 | if ((value as any) && typeof (value as any) === "object" && "error" in (value as any)) { 108 | this.state.finishReason = "error"; 109 | controller.enqueue({ type: "error", error: (value as any).error }); 110 | return; 111 | } 112 | 113 | if (this.state.isFirstChunk) { 114 | this.state.isFirstChunk = false; 115 | controller.enqueue({ 116 | type: "response-metadata", 117 | ...getResponseMetadata(value as any), 118 | }); 119 | } 120 | 121 | if (value.done) { 122 | this.handleDoneChunk(value, controller); 123 | } 124 | 125 | const delta = value?.message; 126 | if (delta) { 127 | this.processDelta(delta, controller); 128 | } 129 | } 130 | 131 | private handleDoneChunk( 132 | value: OllamaResponse, 133 | controller: TransformStreamDefaultController, 134 | ) { 135 | this.state.finishReason = mapOllamaFinishReason(value.done_reason); 136 | this.state.usage = { 137 | inputTokens: value.prompt_eval_count || 0, 138 | outputTokens: value.eval_count ?? undefined, 139 | totalTokens: (value.prompt_eval_count ?? 0) + (value.eval_count ?? 0), 140 | }; 141 | 142 | // Close any started streams 143 | if (this.state.hasTextStarted && !this.state.textEnded) { 144 | controller.enqueue({ type: "text-end", id: this.state.textId }); 145 | this.state.textEnded = true; 146 | } 147 | if (this.state.hasReasoningStarted && !this.state.reasoningEnded) { 148 | controller.enqueue({ type: "reasoning-end", id: "0" }); 149 | this.state.reasoningEnded = true; 150 | } 151 | } 152 | 153 | private processDelta( 154 | delta: OllamaResponse["message"], 155 | controller: TransformStreamDefaultController, 156 | ) { 157 | this.processTextContent(delta, controller); 158 | this.processThinking(delta, controller); 159 | this.processToolCalls(delta, controller); 160 | } 161 | 162 | private processTextContent( 163 | delta: OllamaResponse["message"], 164 | controller: TransformStreamDefaultController, 165 | ) { 166 | if (delta?.content != null) { 167 | if (!this.state.hasTextStarted) { 168 | controller.enqueue({ type: "text-start", id: this.state.textId }); 169 | this.state.hasTextStarted = true; 170 | } 171 | controller.enqueue({ 172 | type: "text-delta", 173 | id: this.state.textId, 174 | delta: delta.content, 175 | }); 176 | } 177 | } 178 | 179 | private processThinking( 180 | delta: OllamaResponse["message"], 181 | controller: TransformStreamDefaultController, 182 | ) { 183 | if (delta?.thinking) { 184 | if (!this.state.hasReasoningStarted) { 185 | controller.enqueue({ type: "reasoning-start", id: "0" }); 186 | this.state.hasReasoningStarted = true; 187 | } 188 | controller.enqueue({ 189 | type: "reasoning-delta", 190 | id: "0", 191 | delta: delta.thinking, 192 | }); 193 | } 194 | } 195 | 196 | private processToolCalls( 197 | delta: OllamaResponse["message"], 198 | controller: TransformStreamDefaultController, 199 | ) { 200 | for (const toolCall of delta.tool_calls ?? []) { 201 | if (toolCall.function?.name == null) { 202 | throw new InvalidResponseDataError({ 203 | data: toolCall, 204 | message: `Expected 'function.name' to be a string.`, 205 | }); 206 | } 207 | 208 | if ( 209 | toolCall.function?.name != null && 210 | toolCall.function?.arguments != null 211 | ) { 212 | this.emitToolCall(toolCall, controller); 213 | } 214 | } 215 | } 216 | 217 | private emitToolCall( 218 | toolCall: NonNullable[0], 219 | controller: TransformStreamDefaultController, 220 | ) { 221 | const id = toolCall.id ?? (this.config.generateId?.() ?? generateId()); 222 | 223 | controller.enqueue({ 224 | type: "tool-input-start", 225 | id: id, 226 | toolName: toolCall.function.name, 227 | }); 228 | 229 | controller.enqueue({ 230 | type: "tool-input-delta", 231 | id: id, 232 | delta: JSON.stringify(toolCall.function.arguments), 233 | }); 234 | 235 | controller.enqueue({ 236 | type: "tool-input-end", 237 | id: id, 238 | }); 239 | 240 | controller.enqueue({ 241 | type: "tool-call", 242 | toolCallId: id, 243 | toolName: toolCall.function.name, 244 | input: JSON.stringify(toolCall.function.arguments), 245 | }); 246 | 247 | this.state.hasToolCalls = true; 248 | } 249 | 250 | private finalizeStream( 251 | controller: TransformStreamDefaultController, 252 | ) { 253 | // Ensure any started segments are properly closed 254 | if (this.state.hasTextStarted && !this.state.textEnded) { 255 | controller.enqueue({ type: "text-end", id: "0" }); 256 | } 257 | if (this.state.hasReasoningStarted && !this.state.reasoningEnded) { 258 | controller.enqueue({ type: "reasoning-end", id: "0" }); 259 | } 260 | 261 | controller.enqueue({ 262 | type: "finish", 263 | finishReason: this.state.finishReason, 264 | usage: this.state.usage, 265 | providerMetadata: { 266 | ollama: { 267 | responseId: this.state.responseId, 268 | }, 269 | }, 270 | }); 271 | } 272 | } -------------------------------------------------------------------------------- /src/completion/ollama-completion-language-model.ts: -------------------------------------------------------------------------------- 1 | import { 2 | combineHeaders, 3 | createJsonResponseHandler, 4 | createJsonStreamResponseHandler, 5 | generateId, 6 | parseProviderOptions, 7 | ParseResult, 8 | postJsonToApi, 9 | } from "@ai-sdk/provider-utils"; 10 | import { z } from "zod/v4"; 11 | import { 12 | InvalidPromptError, 13 | LanguageModelV2, 14 | LanguageModelV2CallWarning, 15 | LanguageModelV2Content, 16 | LanguageModelV2FinishReason, 17 | LanguageModelV2StreamPart, 18 | LanguageModelV2Usage, 19 | SharedV2ProviderMetadata, 20 | } from "@ai-sdk/provider"; 21 | import { OllamaConfig } from "../common/ollama-config"; 22 | import { ollamaFailedResponseHandler } from "./ollama-error"; 23 | import { convertToOllamaCompletionPrompt } from "../adaptors/convert-to-ollama-completion-prompt"; 24 | import { OllamaCompletionModelId, OllamaCompletionSettings } from "./ollama-completion-settings"; 25 | import { mapOllamaFinishReason } from "../adaptors/map-ollama-finish-reason"; 26 | import { getResponseMetadata } from "../common/get-response-metadata"; 27 | 28 | // Completion-specific provider options schema 29 | const ollamaCompletionProviderOptions = z.object({ 30 | think: z.boolean().optional(), 31 | user: z.string().optional(), 32 | suffix: z.string().optional(), 33 | echo: z.boolean().optional(), 34 | }); 35 | 36 | type OllamaCompletionConfig = { 37 | provider: string; 38 | url: (options: { path: string; modelId: string }) => string; 39 | headers: () => Record; 40 | fetch?: typeof fetch; 41 | }; 42 | 43 | export type OllamaCompletionProviderOptions = z.infer; 44 | 45 | export class OllamaCompletionLanguageModel implements LanguageModelV2 { 46 | readonly specificationVersion = "v2"; 47 | 48 | readonly modelId: OllamaCompletionModelId; 49 | readonly settings: OllamaCompletionSettings; 50 | 51 | private readonly config: OllamaCompletionConfig; 52 | 53 | constructor( 54 | modelId: OllamaCompletionModelId, 55 | settings: OllamaCompletionSettings, 56 | config: OllamaCompletionConfig, 57 | ) { 58 | this.modelId = modelId; 59 | this.settings = settings; 60 | this.config = config; 61 | } 62 | 63 | get provider(): string { 64 | return this.config.provider; 65 | } 66 | 67 | readonly supportedUrls: Record = { 68 | // No URLs are supported for completion models. 69 | }; 70 | 71 | private async getArgs({ 72 | prompt, 73 | maxOutputTokens, 74 | temperature, 75 | topP, 76 | topK, 77 | frequencyPenalty, 78 | presencePenalty, 79 | stopSequences: userStopSequences, 80 | responseFormat, 81 | tools, 82 | toolChoice, 83 | seed, 84 | providerOptions, 85 | }: Parameters[0]) { 86 | const warnings: LanguageModelV2CallWarning[] = []; 87 | 88 | // Parse provider options 89 | const ollamaOptions = 90 | (await parseProviderOptions({ 91 | provider: "ollama", 92 | providerOptions, 93 | schema: ollamaCompletionProviderOptions, 94 | })) ?? {}; 95 | 96 | if (topK != null) { 97 | warnings.push({ 98 | type: "unsupported-setting", 99 | setting: "topK", 100 | }); 101 | } 102 | 103 | if (tools?.length) { 104 | warnings.push({ type: "unsupported-setting", setting: "tools" }); 105 | } 106 | 107 | if (toolChoice != null) { 108 | warnings.push({ type: "unsupported-setting", setting: "toolChoice" }); 109 | } 110 | 111 | if (responseFormat != null && responseFormat.type !== "text") { 112 | warnings.push({ 113 | type: "unsupported-setting", 114 | setting: "responseFormat", 115 | details: "JSON response format is not supported.", 116 | }); 117 | } 118 | 119 | const { prompt: completionPrompt, stopSequences } = 120 | convertToOllamaCompletionPrompt({ prompt }); 121 | 122 | const stop = [...(stopSequences ?? []), ...(userStopSequences ?? [])]; 123 | 124 | return { 125 | args: { 126 | // model id: 127 | model: this.modelId, 128 | 129 | // Ollama-supported settings: 130 | user: ollamaOptions.user, 131 | think: ollamaOptions.think, 132 | 133 | // standardized settings: 134 | max_tokens: maxOutputTokens, 135 | temperature, 136 | top_p: topP, 137 | frequency_penalty: frequencyPenalty, 138 | presence_penalty: presencePenalty, 139 | stop, 140 | 141 | // prompt: 142 | prompt: completionPrompt, 143 | 144 | // other settings: 145 | suffix: ollamaOptions.suffix, 146 | echo: ollamaOptions.echo, 147 | stream: false, // always disabled for doGenerate 148 | }, 149 | warnings, 150 | }; 151 | } 152 | 153 | async doGenerate( 154 | options: Parameters[0], 155 | ): Promise>> { 156 | const { args: body, warnings } = await this.getArgs(options); 157 | 158 | const { 159 | responseHeaders, 160 | value: response, 161 | rawValue: rawResponse, 162 | } = await postJsonToApi({ 163 | url: this.config.url({ 164 | path: "/generate", 165 | modelId: this.modelId, 166 | }), 167 | headers: combineHeaders(this.config.headers(), options.headers), 168 | body: { ...body, stream: false }, 169 | failedResponseHandler: ollamaFailedResponseHandler, 170 | successfulResponseHandler: createJsonResponseHandler( 171 | baseOllamaResponseSchema, 172 | ), 173 | abortSignal: options.abortSignal, 174 | fetch: this.config.fetch, 175 | }); 176 | 177 | const { prompt: rawPrompt, ...rawSettings } = body; 178 | 179 | const providerMetadata: SharedV2ProviderMetadata = { ollama: {} }; 180 | 181 | return { 182 | content: [ 183 | { 184 | type: "text", 185 | text: response.response, 186 | }, 187 | ], 188 | usage: { 189 | inputTokens: response.prompt_eval_count ?? undefined, 190 | outputTokens: response.eval_count ?? undefined, 191 | totalTokens: (response.prompt_eval_count ?? 0) + (response.eval_count ?? 0), 192 | }, 193 | finishReason: mapOllamaFinishReason("stop"), 194 | request: { body: JSON.stringify(body) }, 195 | response: { 196 | ...getResponseMetadata(response), 197 | headers: responseHeaders, 198 | body: rawResponse, 199 | }, 200 | warnings, 201 | providerMetadata, 202 | }; 203 | } 204 | 205 | async doStream( 206 | options: Parameters[0], 207 | ): Promise>> { 208 | const { args, warnings } = await this.getArgs(options); 209 | 210 | const body = { 211 | ...args, 212 | stream: true, 213 | }; 214 | 215 | const { responseHeaders, value: response } = await postJsonToApi({ 216 | url: this.config.url({ 217 | path: "/generate", 218 | modelId: this.modelId, 219 | }), 220 | headers: combineHeaders(this.config.headers(), options.headers), 221 | body, 222 | failedResponseHandler: ollamaFailedResponseHandler, 223 | successfulResponseHandler: createJsonStreamResponseHandler( 224 | baseOllamaResponseSchema, 225 | ), 226 | abortSignal: options.abortSignal, 227 | fetch: this.config.fetch, 228 | }); 229 | 230 | const { prompt: rawPrompt, ...rawSettings } = args; 231 | 232 | let finishReason: LanguageModelV2FinishReason = "unknown"; 233 | let usage: LanguageModelV2Usage = { 234 | inputTokens: undefined, 235 | outputTokens: undefined, 236 | totalTokens: undefined, 237 | }; 238 | let isFirstChunk = true; 239 | 240 | return { 241 | stream: response.pipeThrough( 242 | new TransformStream< 243 | ParseResult>, 244 | LanguageModelV2StreamPart 245 | >({ 246 | transform(chunk, controller) { 247 | // handle failed chunk parsing / validation: 248 | if (!chunk.success) { 249 | finishReason = "error"; 250 | controller.enqueue({ type: "error", error: (chunk as any).error }); 251 | return; 252 | } 253 | 254 | const value = chunk.value; 255 | 256 | // handle error chunks: 257 | if ("error" in value) { 258 | finishReason = "error"; 259 | controller.enqueue({ type: "error", error: value.error }); 260 | return; 261 | } 262 | 263 | if (isFirstChunk) { 264 | isFirstChunk = false; 265 | 266 | controller.enqueue({ 267 | type: "response-metadata", 268 | ...getResponseMetadata(value), 269 | }); 270 | } 271 | 272 | if (value.done) { 273 | finishReason = mapOllamaFinishReason("stop"); 274 | } 275 | 276 | if (value.response != null) { 277 | controller.enqueue({ 278 | type: "text-delta", 279 | id: "0", 280 | delta: value.response, 281 | }); 282 | } 283 | }, 284 | 285 | flush(controller) { 286 | controller.enqueue({ 287 | type: "finish", 288 | finishReason, 289 | usage, 290 | }); 291 | }, 292 | }), 293 | ), 294 | request: { body: JSON.stringify(body) }, 295 | response: { headers: responseHeaders }, 296 | }; 297 | } 298 | } 299 | 300 | const baseOllamaResponseSchema = z.object({ 301 | model: z.string(), 302 | created_at: z.string(), 303 | response: z.string(), 304 | done: z.boolean(), 305 | context: z.array(z.number()), 306 | 307 | eval_count: z.number().optional(), 308 | eval_duration: z.number().optional(), 309 | 310 | load_duration: z.number().optional(), 311 | total_duration: z.number().optional(), 312 | 313 | prompt_eval_count: z.number().optional(), 314 | prompt_eval_duration: z.number().optional(), 315 | }); 316 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /pnpm-lock.yaml: -------------------------------------------------------------------------------- 1 | lockfileVersion: '9.0' 2 | 3 | settings: 4 | autoInstallPeers: true 5 | excludeLinksFromLockfile: false 6 | 7 | importers: 8 | 9 | .: 10 | dependencies: 11 | '@ai-sdk/provider': 12 | specifier: ^2.0.0 13 | version: 2.0.0 14 | '@ai-sdk/provider-utils': 15 | specifier: ^3.0.17 16 | version: 3.0.17(zod@4.1.13) 17 | devDependencies: 18 | '@edge-runtime/vm': 19 | specifier: ^5.0.0 20 | version: 5.0.0 21 | '@types/node': 22 | specifier: 24.10.1 23 | version: 24.10.1 24 | '@vercel/ai-tsconfig': 25 | specifier: ./tsconfig 26 | version: link:tsconfig 27 | eslint: 28 | specifier: ^9.39.1 29 | version: 9.39.1 30 | msw: 31 | specifier: ^2.12.4 32 | version: 2.12.4(@types/node@24.10.1)(typescript@5.9.3) 33 | tsup: 34 | specifier: ^8 35 | version: 8.5.1(postcss@8.5.6)(typescript@5.9.3) 36 | typescript: 37 | specifier: 5.9.3 38 | version: 5.9.3 39 | vite: 40 | specifier: ^7.2.4 41 | version: 7.2.4(@types/node@24.10.1) 42 | vitest: 43 | specifier: ^4.0.15 44 | version: 4.0.15(@edge-runtime/vm@5.0.0)(@types/node@24.10.1)(msw@2.12.4(@types/node@24.10.1)(typescript@5.9.3)) 45 | zod: 46 | specifier: 4.1.13 47 | version: 4.1.13 48 | 49 | packages: 50 | 51 | '@ai-sdk/provider-utils@3.0.17': 52 | resolution: {integrity: sha512-TR3Gs4I3Tym4Ll+EPdzRdvo/rc8Js6c4nVhFLuvGLX/Y4V9ZcQMa/HTiYsHEgmYrf1zVi6Q145UEZUfleOwOjw==} 53 | engines: {node: '>=18'} 54 | peerDependencies: 55 | zod: ^3.25.76 || ^4.1.8 56 | 57 | '@ai-sdk/provider@2.0.0': 58 | resolution: {integrity: sha512-6o7Y2SeO9vFKB8lArHXehNuusnpddKPk7xqL7T2/b+OvXMRIXUO1rR4wcv1hAFUAT9avGZshty3Wlua/XA7TvA==} 59 | engines: {node: '>=18'} 60 | 61 | '@edge-runtime/primitives@6.0.0': 62 | resolution: {integrity: sha512-FqoxaBT+prPBHBwE1WXS1ocnu/VLTQyZ6NMUBAdbP7N2hsFTTxMC/jMu2D/8GAlMQfxeuppcPuCUk/HO3fpIvA==} 63 | engines: {node: '>=18'} 64 | 65 | '@edge-runtime/vm@5.0.0': 66 | resolution: {integrity: sha512-NKBGBSIKUG584qrS1tyxVpX/AKJKQw5HgjYEnPLC0QsTw79JrGn+qUr8CXFb955Iy7GUdiiUv1rJ6JBGvaKb6w==} 67 | engines: {node: '>=18'} 68 | 69 | '@esbuild/aix-ppc64@0.25.12': 70 | resolution: {integrity: sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==} 71 | engines: {node: '>=18'} 72 | cpu: [ppc64] 73 | os: [aix] 74 | 75 | '@esbuild/aix-ppc64@0.27.0': 76 | resolution: {integrity: sha512-KuZrd2hRjz01y5JK9mEBSD3Vj3mbCvemhT466rSuJYeE/hjuBrHfjjcjMdTm/sz7au+++sdbJZJmuBwQLuw68A==} 77 | engines: {node: '>=18'} 78 | cpu: [ppc64] 79 | os: [aix] 80 | 81 | '@esbuild/android-arm64@0.25.12': 82 | resolution: {integrity: sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==} 83 | engines: {node: '>=18'} 84 | cpu: [arm64] 85 | os: [android] 86 | 87 | '@esbuild/android-arm64@0.27.0': 88 | resolution: {integrity: sha512-CC3vt4+1xZrs97/PKDkl0yN7w8edvU2vZvAFGD16n9F0Cvniy5qvzRXjfO1l94efczkkQE6g1x0i73Qf5uthOQ==} 89 | engines: {node: '>=18'} 90 | cpu: [arm64] 91 | os: [android] 92 | 93 | '@esbuild/android-arm@0.25.12': 94 | resolution: {integrity: sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==} 95 | engines: {node: '>=18'} 96 | cpu: [arm] 97 | os: [android] 98 | 99 | '@esbuild/android-arm@0.27.0': 100 | resolution: {integrity: sha512-j67aezrPNYWJEOHUNLPj9maeJte7uSMM6gMoxfPC9hOg8N02JuQi/T7ewumf4tNvJadFkvLZMlAq73b9uwdMyQ==} 101 | engines: {node: '>=18'} 102 | cpu: [arm] 103 | os: [android] 104 | 105 | '@esbuild/android-x64@0.25.12': 106 | resolution: {integrity: sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==} 107 | engines: {node: '>=18'} 108 | cpu: [x64] 109 | os: [android] 110 | 111 | '@esbuild/android-x64@0.27.0': 112 | resolution: {integrity: sha512-wurMkF1nmQajBO1+0CJmcN17U4BP6GqNSROP8t0X/Jiw2ltYGLHpEksp9MpoBqkrFR3kv2/te6Sha26k3+yZ9Q==} 113 | engines: {node: '>=18'} 114 | cpu: [x64] 115 | os: [android] 116 | 117 | '@esbuild/darwin-arm64@0.25.12': 118 | resolution: {integrity: sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==} 119 | engines: {node: '>=18'} 120 | cpu: [arm64] 121 | os: [darwin] 122 | 123 | '@esbuild/darwin-arm64@0.27.0': 124 | resolution: {integrity: sha512-uJOQKYCcHhg07DL7i8MzjvS2LaP7W7Pn/7uA0B5S1EnqAirJtbyw4yC5jQ5qcFjHK9l6o/MX9QisBg12kNkdHg==} 125 | engines: {node: '>=18'} 126 | cpu: [arm64] 127 | os: [darwin] 128 | 129 | '@esbuild/darwin-x64@0.25.12': 130 | resolution: {integrity: sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==} 131 | engines: {node: '>=18'} 132 | cpu: [x64] 133 | os: [darwin] 134 | 135 | '@esbuild/darwin-x64@0.27.0': 136 | resolution: {integrity: sha512-8mG6arH3yB/4ZXiEnXof5MK72dE6zM9cDvUcPtxhUZsDjESl9JipZYW60C3JGreKCEP+p8P/72r69m4AZGJd5g==} 137 | engines: {node: '>=18'} 138 | cpu: [x64] 139 | os: [darwin] 140 | 141 | '@esbuild/freebsd-arm64@0.25.12': 142 | resolution: {integrity: sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==} 143 | engines: {node: '>=18'} 144 | cpu: [arm64] 145 | os: [freebsd] 146 | 147 | '@esbuild/freebsd-arm64@0.27.0': 148 | resolution: {integrity: sha512-9FHtyO988CwNMMOE3YIeci+UV+x5Zy8fI2qHNpsEtSF83YPBmE8UWmfYAQg6Ux7Gsmd4FejZqnEUZCMGaNQHQw==} 149 | engines: {node: '>=18'} 150 | cpu: [arm64] 151 | os: [freebsd] 152 | 153 | '@esbuild/freebsd-x64@0.25.12': 154 | resolution: {integrity: sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==} 155 | engines: {node: '>=18'} 156 | cpu: [x64] 157 | os: [freebsd] 158 | 159 | '@esbuild/freebsd-x64@0.27.0': 160 | resolution: {integrity: sha512-zCMeMXI4HS/tXvJz8vWGexpZj2YVtRAihHLk1imZj4efx1BQzN76YFeKqlDr3bUWI26wHwLWPd3rwh6pe4EV7g==} 161 | engines: {node: '>=18'} 162 | cpu: [x64] 163 | os: [freebsd] 164 | 165 | '@esbuild/linux-arm64@0.25.12': 166 | resolution: {integrity: sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==} 167 | engines: {node: '>=18'} 168 | cpu: [arm64] 169 | os: [linux] 170 | 171 | '@esbuild/linux-arm64@0.27.0': 172 | resolution: {integrity: sha512-AS18v0V+vZiLJyi/4LphvBE+OIX682Pu7ZYNsdUHyUKSoRwdnOsMf6FDekwoAFKej14WAkOef3zAORJgAtXnlQ==} 173 | engines: {node: '>=18'} 174 | cpu: [arm64] 175 | os: [linux] 176 | 177 | '@esbuild/linux-arm@0.25.12': 178 | resolution: {integrity: sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==} 179 | engines: {node: '>=18'} 180 | cpu: [arm] 181 | os: [linux] 182 | 183 | '@esbuild/linux-arm@0.27.0': 184 | resolution: {integrity: sha512-t76XLQDpxgmq2cNXKTVEB7O7YMb42atj2Re2Haf45HkaUpjM2J0UuJZDuaGbPbamzZ7bawyGFUkodL+zcE+jvQ==} 185 | engines: {node: '>=18'} 186 | cpu: [arm] 187 | os: [linux] 188 | 189 | '@esbuild/linux-ia32@0.25.12': 190 | resolution: {integrity: sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==} 191 | engines: {node: '>=18'} 192 | cpu: [ia32] 193 | os: [linux] 194 | 195 | '@esbuild/linux-ia32@0.27.0': 196 | resolution: {integrity: sha512-Mz1jxqm/kfgKkc/KLHC5qIujMvnnarD9ra1cEcrs7qshTUSksPihGrWHVG5+osAIQ68577Zpww7SGapmzSt4Nw==} 197 | engines: {node: '>=18'} 198 | cpu: [ia32] 199 | os: [linux] 200 | 201 | '@esbuild/linux-loong64@0.25.12': 202 | resolution: {integrity: sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==} 203 | engines: {node: '>=18'} 204 | cpu: [loong64] 205 | os: [linux] 206 | 207 | '@esbuild/linux-loong64@0.27.0': 208 | resolution: {integrity: sha512-QbEREjdJeIreIAbdG2hLU1yXm1uu+LTdzoq1KCo4G4pFOLlvIspBm36QrQOar9LFduavoWX2msNFAAAY9j4BDg==} 209 | engines: {node: '>=18'} 210 | cpu: [loong64] 211 | os: [linux] 212 | 213 | '@esbuild/linux-mips64el@0.25.12': 214 | resolution: {integrity: sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==} 215 | engines: {node: '>=18'} 216 | cpu: [mips64el] 217 | os: [linux] 218 | 219 | '@esbuild/linux-mips64el@0.27.0': 220 | resolution: {integrity: sha512-sJz3zRNe4tO2wxvDpH/HYJilb6+2YJxo/ZNbVdtFiKDufzWq4JmKAiHy9iGoLjAV7r/W32VgaHGkk35cUXlNOg==} 221 | engines: {node: '>=18'} 222 | cpu: [mips64el] 223 | os: [linux] 224 | 225 | '@esbuild/linux-ppc64@0.25.12': 226 | resolution: {integrity: sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==} 227 | engines: {node: '>=18'} 228 | cpu: [ppc64] 229 | os: [linux] 230 | 231 | '@esbuild/linux-ppc64@0.27.0': 232 | resolution: {integrity: sha512-z9N10FBD0DCS2dmSABDBb5TLAyF1/ydVb+N4pi88T45efQ/w4ohr/F/QYCkxDPnkhkp6AIpIcQKQ8F0ANoA2JA==} 233 | engines: {node: '>=18'} 234 | cpu: [ppc64] 235 | os: [linux] 236 | 237 | '@esbuild/linux-riscv64@0.25.12': 238 | resolution: {integrity: sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==} 239 | engines: {node: '>=18'} 240 | cpu: [riscv64] 241 | os: [linux] 242 | 243 | '@esbuild/linux-riscv64@0.27.0': 244 | resolution: {integrity: sha512-pQdyAIZ0BWIC5GyvVFn5awDiO14TkT/19FTmFcPdDec94KJ1uZcmFs21Fo8auMXzD4Tt+diXu1LW1gHus9fhFQ==} 245 | engines: {node: '>=18'} 246 | cpu: [riscv64] 247 | os: [linux] 248 | 249 | '@esbuild/linux-s390x@0.25.12': 250 | resolution: {integrity: sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==} 251 | engines: {node: '>=18'} 252 | cpu: [s390x] 253 | os: [linux] 254 | 255 | '@esbuild/linux-s390x@0.27.0': 256 | resolution: {integrity: sha512-hPlRWR4eIDDEci953RI1BLZitgi5uqcsjKMxwYfmi4LcwyWo2IcRP+lThVnKjNtk90pLS8nKdroXYOqW+QQH+w==} 257 | engines: {node: '>=18'} 258 | cpu: [s390x] 259 | os: [linux] 260 | 261 | '@esbuild/linux-x64@0.25.12': 262 | resolution: {integrity: sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==} 263 | engines: {node: '>=18'} 264 | cpu: [x64] 265 | os: [linux] 266 | 267 | '@esbuild/linux-x64@0.27.0': 268 | resolution: {integrity: sha512-1hBWx4OUJE2cab++aVZ7pObD6s+DK4mPGpemtnAORBvb5l/g5xFGk0vc0PjSkrDs0XaXj9yyob3d14XqvnQ4gw==} 269 | engines: {node: '>=18'} 270 | cpu: [x64] 271 | os: [linux] 272 | 273 | '@esbuild/netbsd-arm64@0.25.12': 274 | resolution: {integrity: sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==} 275 | engines: {node: '>=18'} 276 | cpu: [arm64] 277 | os: [netbsd] 278 | 279 | '@esbuild/netbsd-arm64@0.27.0': 280 | resolution: {integrity: sha512-6m0sfQfxfQfy1qRuecMkJlf1cIzTOgyaeXaiVaaki8/v+WB+U4hc6ik15ZW6TAllRlg/WuQXxWj1jx6C+dfy3w==} 281 | engines: {node: '>=18'} 282 | cpu: [arm64] 283 | os: [netbsd] 284 | 285 | '@esbuild/netbsd-x64@0.25.12': 286 | resolution: {integrity: sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==} 287 | engines: {node: '>=18'} 288 | cpu: [x64] 289 | os: [netbsd] 290 | 291 | '@esbuild/netbsd-x64@0.27.0': 292 | resolution: {integrity: sha512-xbbOdfn06FtcJ9d0ShxxvSn2iUsGd/lgPIO2V3VZIPDbEaIj1/3nBBe1AwuEZKXVXkMmpr6LUAgMkLD/4D2PPA==} 293 | engines: {node: '>=18'} 294 | cpu: [x64] 295 | os: [netbsd] 296 | 297 | '@esbuild/openbsd-arm64@0.25.12': 298 | resolution: {integrity: sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==} 299 | engines: {node: '>=18'} 300 | cpu: [arm64] 301 | os: [openbsd] 302 | 303 | '@esbuild/openbsd-arm64@0.27.0': 304 | resolution: {integrity: sha512-fWgqR8uNbCQ/GGv0yhzttj6sU/9Z5/Sv/VGU3F5OuXK6J6SlriONKrQ7tNlwBrJZXRYk5jUhuWvF7GYzGguBZQ==} 305 | engines: {node: '>=18'} 306 | cpu: [arm64] 307 | os: [openbsd] 308 | 309 | '@esbuild/openbsd-x64@0.25.12': 310 | resolution: {integrity: sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==} 311 | engines: {node: '>=18'} 312 | cpu: [x64] 313 | os: [openbsd] 314 | 315 | '@esbuild/openbsd-x64@0.27.0': 316 | resolution: {integrity: sha512-aCwlRdSNMNxkGGqQajMUza6uXzR/U0dIl1QmLjPtRbLOx3Gy3otfFu/VjATy4yQzo9yFDGTxYDo1FfAD9oRD2A==} 317 | engines: {node: '>=18'} 318 | cpu: [x64] 319 | os: [openbsd] 320 | 321 | '@esbuild/openharmony-arm64@0.25.12': 322 | resolution: {integrity: sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==} 323 | engines: {node: '>=18'} 324 | cpu: [arm64] 325 | os: [openharmony] 326 | 327 | '@esbuild/openharmony-arm64@0.27.0': 328 | resolution: {integrity: sha512-nyvsBccxNAsNYz2jVFYwEGuRRomqZ149A39SHWk4hV0jWxKM0hjBPm3AmdxcbHiFLbBSwG6SbpIcUbXjgyECfA==} 329 | engines: {node: '>=18'} 330 | cpu: [arm64] 331 | os: [openharmony] 332 | 333 | '@esbuild/sunos-x64@0.25.12': 334 | resolution: {integrity: sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==} 335 | engines: {node: '>=18'} 336 | cpu: [x64] 337 | os: [sunos] 338 | 339 | '@esbuild/sunos-x64@0.27.0': 340 | resolution: {integrity: sha512-Q1KY1iJafM+UX6CFEL+F4HRTgygmEW568YMqDA5UV97AuZSm21b7SXIrRJDwXWPzr8MGr75fUZPV67FdtMHlHA==} 341 | engines: {node: '>=18'} 342 | cpu: [x64] 343 | os: [sunos] 344 | 345 | '@esbuild/win32-arm64@0.25.12': 346 | resolution: {integrity: sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==} 347 | engines: {node: '>=18'} 348 | cpu: [arm64] 349 | os: [win32] 350 | 351 | '@esbuild/win32-arm64@0.27.0': 352 | resolution: {integrity: sha512-W1eyGNi6d+8kOmZIwi/EDjrL9nxQIQ0MiGqe/AWc6+IaHloxHSGoeRgDRKHFISThLmsewZ5nHFvGFWdBYlgKPg==} 353 | engines: {node: '>=18'} 354 | cpu: [arm64] 355 | os: [win32] 356 | 357 | '@esbuild/win32-ia32@0.25.12': 358 | resolution: {integrity: sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==} 359 | engines: {node: '>=18'} 360 | cpu: [ia32] 361 | os: [win32] 362 | 363 | '@esbuild/win32-ia32@0.27.0': 364 | resolution: {integrity: sha512-30z1aKL9h22kQhilnYkORFYt+3wp7yZsHWus+wSKAJR8JtdfI76LJ4SBdMsCopTR3z/ORqVu5L1vtnHZWVj4cQ==} 365 | engines: {node: '>=18'} 366 | cpu: [ia32] 367 | os: [win32] 368 | 369 | '@esbuild/win32-x64@0.25.12': 370 | resolution: {integrity: sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==} 371 | engines: {node: '>=18'} 372 | cpu: [x64] 373 | os: [win32] 374 | 375 | '@esbuild/win32-x64@0.27.0': 376 | resolution: {integrity: sha512-aIitBcjQeyOhMTImhLZmtxfdOcuNRpwlPNmlFKPcHQYPhEssw75Cl1TSXJXpMkzaua9FUetx/4OQKq7eJul5Cg==} 377 | engines: {node: '>=18'} 378 | cpu: [x64] 379 | os: [win32] 380 | 381 | '@eslint-community/eslint-utils@4.9.0': 382 | resolution: {integrity: sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==} 383 | engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} 384 | peerDependencies: 385 | eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 386 | 387 | '@eslint-community/regexpp@4.12.2': 388 | resolution: {integrity: sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==} 389 | engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} 390 | 391 | '@eslint/config-array@0.21.1': 392 | resolution: {integrity: sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==} 393 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 394 | 395 | '@eslint/config-helpers@0.4.2': 396 | resolution: {integrity: sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==} 397 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 398 | 399 | '@eslint/core@0.17.0': 400 | resolution: {integrity: sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==} 401 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 402 | 403 | '@eslint/eslintrc@3.3.1': 404 | resolution: {integrity: sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==} 405 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 406 | 407 | '@eslint/js@9.39.1': 408 | resolution: {integrity: sha512-S26Stp4zCy88tH94QbBv3XCuzRQiZ9yXofEILmglYTh/Ug/a9/umqvgFtYBAo3Lp0nsI/5/qH1CCrbdK3AP1Tw==} 409 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 410 | 411 | '@eslint/object-schema@2.1.7': 412 | resolution: {integrity: sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==} 413 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 414 | 415 | '@eslint/plugin-kit@0.4.1': 416 | resolution: {integrity: sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==} 417 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 418 | 419 | '@humanfs/core@0.19.1': 420 | resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} 421 | engines: {node: '>=18.18.0'} 422 | 423 | '@humanfs/node@0.16.7': 424 | resolution: {integrity: sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==} 425 | engines: {node: '>=18.18.0'} 426 | 427 | '@humanwhocodes/module-importer@1.0.1': 428 | resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} 429 | engines: {node: '>=12.22'} 430 | 431 | '@humanwhocodes/retry@0.4.3': 432 | resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==} 433 | engines: {node: '>=18.18'} 434 | 435 | '@inquirer/ansi@1.0.2': 436 | resolution: {integrity: sha512-S8qNSZiYzFd0wAcyG5AXCvUHC5Sr7xpZ9wZ2py9XR88jUz8wooStVx5M6dRzczbBWjic9NP7+rY0Xi7qqK/aMQ==} 437 | engines: {node: '>=18'} 438 | 439 | '@inquirer/confirm@5.1.21': 440 | resolution: {integrity: sha512-KR8edRkIsUayMXV+o3Gv+q4jlhENF9nMYUZs9PA2HzrXeHI8M5uDag70U7RJn9yyiMZSbtF5/UexBtAVtZGSbQ==} 441 | engines: {node: '>=18'} 442 | peerDependencies: 443 | '@types/node': '>=18' 444 | peerDependenciesMeta: 445 | '@types/node': 446 | optional: true 447 | 448 | '@inquirer/core@10.3.2': 449 | resolution: {integrity: sha512-43RTuEbfP8MbKzedNqBrlhhNKVwoK//vUFNW3Q3vZ88BLcrs4kYpGg+B2mm5p2K/HfygoCxuKwJJiv8PbGmE0A==} 450 | engines: {node: '>=18'} 451 | peerDependencies: 452 | '@types/node': '>=18' 453 | peerDependenciesMeta: 454 | '@types/node': 455 | optional: true 456 | 457 | '@inquirer/figures@1.0.15': 458 | resolution: {integrity: sha512-t2IEY+unGHOzAaVM5Xx6DEWKeXlDDcNPeDyUpsRc6CUhBfU3VQOEl+Vssh7VNp1dR8MdUJBWhuObjXCsVpjN5g==} 459 | engines: {node: '>=18'} 460 | 461 | '@inquirer/type@3.0.10': 462 | resolution: {integrity: sha512-BvziSRxfz5Ov8ch0z/n3oijRSEcEsHnhggm4xFZe93DHcUCTlutlq9Ox4SVENAfcRD22UQq7T/atg9Wr3k09eA==} 463 | engines: {node: '>=18'} 464 | peerDependencies: 465 | '@types/node': '>=18' 466 | peerDependenciesMeta: 467 | '@types/node': 468 | optional: true 469 | 470 | '@isaacs/cliui@8.0.2': 471 | resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} 472 | engines: {node: '>=12'} 473 | 474 | '@jridgewell/gen-mapping@0.3.13': 475 | resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} 476 | 477 | '@jridgewell/resolve-uri@3.1.2': 478 | resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} 479 | engines: {node: '>=6.0.0'} 480 | 481 | '@jridgewell/sourcemap-codec@1.5.5': 482 | resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} 483 | 484 | '@jridgewell/trace-mapping@0.3.31': 485 | resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} 486 | 487 | '@mswjs/interceptors@0.40.0': 488 | resolution: {integrity: sha512-EFd6cVbHsgLa6wa4RljGj6Wk75qoHxUSyc5asLyyPSyuhIcdS2Q3Phw6ImS1q+CkALthJRShiYfKANcQMuMqsQ==} 489 | engines: {node: '>=18'} 490 | 491 | '@open-draft/deferred-promise@2.2.0': 492 | resolution: {integrity: sha512-CecwLWx3rhxVQF6V4bAgPS5t+So2sTbPgAzafKkVizyi7tlwpcFpdFqq+wqF2OwNBmqFuu6tOyouTuxgpMfzmA==} 493 | 494 | '@open-draft/logger@0.3.0': 495 | resolution: {integrity: sha512-X2g45fzhxH238HKO4xbSr7+wBS8Fvw6ixhTDuvLd5mqh6bJJCFAPwU9mPDxbcrRtfxv4u5IHCEH77BmxvXmmxQ==} 496 | 497 | '@open-draft/until@2.1.0': 498 | resolution: {integrity: sha512-U69T3ItWHvLwGg5eJ0n3I62nWuE6ilHlmz7zM0npLBRvPRd7e6NYmg54vvRtP5mZG7kZqZCFVdsTWo7BPtBujg==} 499 | 500 | '@pkgjs/parseargs@0.11.0': 501 | resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} 502 | engines: {node: '>=14'} 503 | 504 | '@rollup/rollup-android-arm-eabi@4.53.2': 505 | resolution: {integrity: sha512-yDPzwsgiFO26RJA4nZo8I+xqzh7sJTZIWQOxn+/XOdPE31lAvLIYCKqjV+lNH/vxE2L2iH3plKxDCRK6i+CwhA==} 506 | cpu: [arm] 507 | os: [android] 508 | 509 | '@rollup/rollup-android-arm-eabi@4.53.3': 510 | resolution: {integrity: sha512-mRSi+4cBjrRLoaal2PnqH82Wqyb+d3HsPUN/W+WslCXsZsyHa9ZeQQX/pQsZaVIWDkPcpV6jJ+3KLbTbgnwv8w==} 511 | cpu: [arm] 512 | os: [android] 513 | 514 | '@rollup/rollup-android-arm64@4.53.2': 515 | resolution: {integrity: sha512-k8FontTxIE7b0/OGKeSN5B6j25EuppBcWM33Z19JoVT7UTXFSo3D9CdU39wGTeb29NO3XxpMNauh09B+Ibw+9g==} 516 | cpu: [arm64] 517 | os: [android] 518 | 519 | '@rollup/rollup-android-arm64@4.53.3': 520 | resolution: {integrity: sha512-CbDGaMpdE9sh7sCmTrTUyllhrg65t6SwhjlMJsLr+J8YjFuPmCEjbBSx4Z/e4SmDyH3aB5hGaJUP2ltV/vcs4w==} 521 | cpu: [arm64] 522 | os: [android] 523 | 524 | '@rollup/rollup-darwin-arm64@4.53.2': 525 | resolution: {integrity: sha512-A6s4gJpomNBtJ2yioj8bflM2oogDwzUiMl2yNJ2v9E7++sHrSrsQ29fOfn5DM/iCzpWcebNYEdXpaK4tr2RhfQ==} 526 | cpu: [arm64] 527 | os: [darwin] 528 | 529 | '@rollup/rollup-darwin-arm64@4.53.3': 530 | resolution: {integrity: sha512-Nr7SlQeqIBpOV6BHHGZgYBuSdanCXuw09hon14MGOLGmXAFYjx1wNvquVPmpZnl0tLjg25dEdr4IQ6GgyToCUA==} 531 | cpu: [arm64] 532 | os: [darwin] 533 | 534 | '@rollup/rollup-darwin-x64@4.53.2': 535 | resolution: {integrity: sha512-e6XqVmXlHrBlG56obu9gDRPW3O3hLxpwHpLsBJvuI8qqnsrtSZ9ERoWUXtPOkY8c78WghyPHZdmPhHLWNdAGEw==} 536 | cpu: [x64] 537 | os: [darwin] 538 | 539 | '@rollup/rollup-darwin-x64@4.53.3': 540 | resolution: {integrity: sha512-DZ8N4CSNfl965CmPktJ8oBnfYr3F8dTTNBQkRlffnUarJ2ohudQD17sZBa097J8xhQ26AwhHJ5mvUyQW8ddTsQ==} 541 | cpu: [x64] 542 | os: [darwin] 543 | 544 | '@rollup/rollup-freebsd-arm64@4.53.2': 545 | resolution: {integrity: sha512-v0E9lJW8VsrwPux5Qe5CwmH/CF/2mQs6xU1MF3nmUxmZUCHazCjLgYvToOk+YuuUqLQBio1qkkREhxhc656ViA==} 546 | cpu: [arm64] 547 | os: [freebsd] 548 | 549 | '@rollup/rollup-freebsd-arm64@4.53.3': 550 | resolution: {integrity: sha512-yMTrCrK92aGyi7GuDNtGn2sNW+Gdb4vErx4t3Gv/Tr+1zRb8ax4z8GWVRfr3Jw8zJWvpGHNpss3vVlbF58DZ4w==} 551 | cpu: [arm64] 552 | os: [freebsd] 553 | 554 | '@rollup/rollup-freebsd-x64@4.53.2': 555 | resolution: {integrity: sha512-ClAmAPx3ZCHtp6ysl4XEhWU69GUB1D+s7G9YjHGhIGCSrsg00nEGRRZHmINYxkdoJehde8VIsDC5t9C0gb6yqA==} 556 | cpu: [x64] 557 | os: [freebsd] 558 | 559 | '@rollup/rollup-freebsd-x64@4.53.3': 560 | resolution: {integrity: sha512-lMfF8X7QhdQzseM6XaX0vbno2m3hlyZFhwcndRMw8fbAGUGL3WFMBdK0hbUBIUYcEcMhVLr1SIamDeuLBnXS+Q==} 561 | cpu: [x64] 562 | os: [freebsd] 563 | 564 | '@rollup/rollup-linux-arm-gnueabihf@4.53.2': 565 | resolution: {integrity: sha512-EPlb95nUsz6Dd9Qy13fI5kUPXNSljaG9FiJ4YUGU1O/Q77i5DYFW5KR8g1OzTcdZUqQQ1KdDqsTohdFVwCwjqg==} 566 | cpu: [arm] 567 | os: [linux] 568 | 569 | '@rollup/rollup-linux-arm-gnueabihf@4.53.3': 570 | resolution: {integrity: sha512-k9oD15soC/Ln6d2Wv/JOFPzZXIAIFLp6B+i14KhxAfnq76ajt0EhYc5YPeX6W1xJkAdItcVT+JhKl1QZh44/qw==} 571 | cpu: [arm] 572 | os: [linux] 573 | 574 | '@rollup/rollup-linux-arm-musleabihf@4.53.2': 575 | resolution: {integrity: sha512-BOmnVW+khAUX+YZvNfa0tGTEMVVEerOxN0pDk2E6N6DsEIa2Ctj48FOMfNDdrwinocKaC7YXUZ1pHlKpnkja/Q==} 576 | cpu: [arm] 577 | os: [linux] 578 | 579 | '@rollup/rollup-linux-arm-musleabihf@4.53.3': 580 | resolution: {integrity: sha512-vTNlKq+N6CK/8UktsrFuc+/7NlEYVxgaEgRXVUVK258Z5ymho29skzW1sutgYjqNnquGwVUObAaxae8rZ6YMhg==} 581 | cpu: [arm] 582 | os: [linux] 583 | 584 | '@rollup/rollup-linux-arm64-gnu@4.53.2': 585 | resolution: {integrity: sha512-Xt2byDZ+6OVNuREgBXr4+CZDJtrVso5woFtpKdGPhpTPHcNG7D8YXeQzpNbFRxzTVqJf7kvPMCub/pcGUWgBjA==} 586 | cpu: [arm64] 587 | os: [linux] 588 | 589 | '@rollup/rollup-linux-arm64-gnu@4.53.3': 590 | resolution: {integrity: sha512-RGrFLWgMhSxRs/EWJMIFM1O5Mzuz3Xy3/mnxJp/5cVhZ2XoCAxJnmNsEyeMJtpK+wu0FJFWz+QF4mjCA7AUQ3w==} 591 | cpu: [arm64] 592 | os: [linux] 593 | 594 | '@rollup/rollup-linux-arm64-musl@4.53.2': 595 | resolution: {integrity: sha512-+LdZSldy/I9N8+klim/Y1HsKbJ3BbInHav5qE9Iy77dtHC/pibw1SR/fXlWyAk0ThnpRKoODwnAuSjqxFRDHUQ==} 596 | cpu: [arm64] 597 | os: [linux] 598 | 599 | '@rollup/rollup-linux-arm64-musl@4.53.3': 600 | resolution: {integrity: sha512-kASyvfBEWYPEwe0Qv4nfu6pNkITLTb32p4yTgzFCocHnJLAHs+9LjUu9ONIhvfT/5lv4YS5muBHyuV84epBo/A==} 601 | cpu: [arm64] 602 | os: [linux] 603 | 604 | '@rollup/rollup-linux-loong64-gnu@4.53.2': 605 | resolution: {integrity: sha512-8ms8sjmyc1jWJS6WdNSA23rEfdjWB30LH8Wqj0Cqvv7qSHnvw6kgMMXRdop6hkmGPlyYBdRPkjJnj3KCUHV/uQ==} 606 | cpu: [loong64] 607 | os: [linux] 608 | 609 | '@rollup/rollup-linux-loong64-gnu@4.53.3': 610 | resolution: {integrity: sha512-JiuKcp2teLJwQ7vkJ95EwESWkNRFJD7TQgYmCnrPtlu50b4XvT5MOmurWNrCj3IFdyjBQ5p9vnrX4JM6I8OE7g==} 611 | cpu: [loong64] 612 | os: [linux] 613 | 614 | '@rollup/rollup-linux-ppc64-gnu@4.53.2': 615 | resolution: {integrity: sha512-3HRQLUQbpBDMmzoxPJYd3W6vrVHOo2cVW8RUo87Xz0JPJcBLBr5kZ1pGcQAhdZgX9VV7NbGNipah1omKKe23/g==} 616 | cpu: [ppc64] 617 | os: [linux] 618 | 619 | '@rollup/rollup-linux-ppc64-gnu@4.53.3': 620 | resolution: {integrity: sha512-EoGSa8nd6d3T7zLuqdojxC20oBfNT8nexBbB/rkxgKj5T5vhpAQKKnD+h3UkoMuTyXkP5jTjK/ccNRmQrPNDuw==} 621 | cpu: [ppc64] 622 | os: [linux] 623 | 624 | '@rollup/rollup-linux-riscv64-gnu@4.53.2': 625 | resolution: {integrity: sha512-fMjKi+ojnmIvhk34gZP94vjogXNNUKMEYs+EDaB/5TG/wUkoeua7p7VCHnE6T2Tx+iaghAqQX8teQzcvrYpaQA==} 626 | cpu: [riscv64] 627 | os: [linux] 628 | 629 | '@rollup/rollup-linux-riscv64-gnu@4.53.3': 630 | resolution: {integrity: sha512-4s+Wped2IHXHPnAEbIB0YWBv7SDohqxobiiPA1FIWZpX+w9o2i4LezzH/NkFUl8LRci/8udci6cLq+jJQlh+0g==} 631 | cpu: [riscv64] 632 | os: [linux] 633 | 634 | '@rollup/rollup-linux-riscv64-musl@4.53.2': 635 | resolution: {integrity: sha512-XuGFGU+VwUUV5kLvoAdi0Wz5Xbh2SrjIxCtZj6Wq8MDp4bflb/+ThZsVxokM7n0pcbkEr2h5/pzqzDYI7cCgLQ==} 636 | cpu: [riscv64] 637 | os: [linux] 638 | 639 | '@rollup/rollup-linux-riscv64-musl@4.53.3': 640 | resolution: {integrity: sha512-68k2g7+0vs2u9CxDt5ktXTngsxOQkSEV/xBbwlqYcUrAVh6P9EgMZvFsnHy4SEiUl46Xf0IObWVbMvPrr2gw8A==} 641 | cpu: [riscv64] 642 | os: [linux] 643 | 644 | '@rollup/rollup-linux-s390x-gnu@4.53.2': 645 | resolution: {integrity: sha512-w6yjZF0P+NGzWR3AXWX9zc0DNEGdtvykB03uhonSHMRa+oWA6novflo2WaJr6JZakG2ucsyb+rvhrKac6NIy+w==} 646 | cpu: [s390x] 647 | os: [linux] 648 | 649 | '@rollup/rollup-linux-s390x-gnu@4.53.3': 650 | resolution: {integrity: sha512-VYsFMpULAz87ZW6BVYw3I6sWesGpsP9OPcyKe8ofdg9LHxSbRMd7zrVrr5xi/3kMZtpWL/wC+UIJWJYVX5uTKg==} 651 | cpu: [s390x] 652 | os: [linux] 653 | 654 | '@rollup/rollup-linux-x64-gnu@4.53.2': 655 | resolution: {integrity: sha512-yo8d6tdfdeBArzC7T/PnHd7OypfI9cbuZzPnzLJIyKYFhAQ8SvlkKtKBMbXDxe1h03Rcr7u++nFS7tqXz87Gtw==} 656 | cpu: [x64] 657 | os: [linux] 658 | 659 | '@rollup/rollup-linux-x64-gnu@4.53.3': 660 | resolution: {integrity: sha512-3EhFi1FU6YL8HTUJZ51imGJWEX//ajQPfqWLI3BQq4TlvHy4X0MOr5q3D2Zof/ka0d5FNdPwZXm3Yyib/UEd+w==} 661 | cpu: [x64] 662 | os: [linux] 663 | 664 | '@rollup/rollup-linux-x64-musl@4.53.2': 665 | resolution: {integrity: sha512-ah59c1YkCxKExPP8O9PwOvs+XRLKwh/mV+3YdKqQ5AMQ0r4M4ZDuOrpWkUaqO7fzAHdINzV9tEVu8vNw48z0lA==} 666 | cpu: [x64] 667 | os: [linux] 668 | 669 | '@rollup/rollup-linux-x64-musl@4.53.3': 670 | resolution: {integrity: sha512-eoROhjcc6HbZCJr+tvVT8X4fW3/5g/WkGvvmwz/88sDtSJzO7r/blvoBDgISDiCjDRZmHpwud7h+6Q9JxFwq1Q==} 671 | cpu: [x64] 672 | os: [linux] 673 | 674 | '@rollup/rollup-openharmony-arm64@4.53.2': 675 | resolution: {integrity: sha512-4VEd19Wmhr+Zy7hbUsFZ6YXEiP48hE//KPLCSVNY5RMGX2/7HZ+QkN55a3atM1C/BZCGIgqN+xrVgtdak2S9+A==} 676 | cpu: [arm64] 677 | os: [openharmony] 678 | 679 | '@rollup/rollup-openharmony-arm64@4.53.3': 680 | resolution: {integrity: sha512-OueLAWgrNSPGAdUdIjSWXw+u/02BRTcnfw9PN41D2vq/JSEPnJnVuBgw18VkN8wcd4fjUs+jFHVM4t9+kBSNLw==} 681 | cpu: [arm64] 682 | os: [openharmony] 683 | 684 | '@rollup/rollup-win32-arm64-msvc@4.53.2': 685 | resolution: {integrity: sha512-IlbHFYc/pQCgew/d5fslcy1KEaYVCJ44G8pajugd8VoOEI8ODhtb/j8XMhLpwHCMB3yk2J07ctup10gpw2nyMA==} 686 | cpu: [arm64] 687 | os: [win32] 688 | 689 | '@rollup/rollup-win32-arm64-msvc@4.53.3': 690 | resolution: {integrity: sha512-GOFuKpsxR/whszbF/bzydebLiXIHSgsEUp6M0JI8dWvi+fFa1TD6YQa4aSZHtpmh2/uAlj/Dy+nmby3TJ3pkTw==} 691 | cpu: [arm64] 692 | os: [win32] 693 | 694 | '@rollup/rollup-win32-ia32-msvc@4.53.2': 695 | resolution: {integrity: sha512-lNlPEGgdUfSzdCWU176ku/dQRnA7W+Gp8d+cWv73jYrb8uT7HTVVxq62DUYxjbaByuf1Yk0RIIAbDzp+CnOTFg==} 696 | cpu: [ia32] 697 | os: [win32] 698 | 699 | '@rollup/rollup-win32-ia32-msvc@4.53.3': 700 | resolution: {integrity: sha512-iah+THLcBJdpfZ1TstDFbKNznlzoxa8fmnFYK4V67HvmuNYkVdAywJSoteUszvBQ9/HqN2+9AZghbajMsFT+oA==} 701 | cpu: [ia32] 702 | os: [win32] 703 | 704 | '@rollup/rollup-win32-x64-gnu@4.53.2': 705 | resolution: {integrity: sha512-S6YojNVrHybQis2lYov1sd+uj7K0Q05NxHcGktuMMdIQ2VixGwAfbJ23NnlvvVV1bdpR2m5MsNBViHJKcA4ADw==} 706 | cpu: [x64] 707 | os: [win32] 708 | 709 | '@rollup/rollup-win32-x64-gnu@4.53.3': 710 | resolution: {integrity: sha512-J9QDiOIZlZLdcot5NXEepDkstocktoVjkaKUtqzgzpt2yWjGlbYiKyp05rWwk4nypbYUNoFAztEgixoLaSETkg==} 711 | cpu: [x64] 712 | os: [win32] 713 | 714 | '@rollup/rollup-win32-x64-msvc@4.53.2': 715 | resolution: {integrity: sha512-k+/Rkcyx//P6fetPoLMb8pBeqJBNGx81uuf7iljX9++yNBVRDQgD04L+SVXmXmh5ZP4/WOp4mWF0kmi06PW2tA==} 716 | cpu: [x64] 717 | os: [win32] 718 | 719 | '@rollup/rollup-win32-x64-msvc@4.53.3': 720 | resolution: {integrity: sha512-UhTd8u31dXadv0MopwGgNOBpUVROFKWVQgAg5N1ESyCz8AuBcMqm4AuTjrwgQKGDfoFuz02EuMRHQIw/frmYKQ==} 721 | cpu: [x64] 722 | os: [win32] 723 | 724 | '@standard-schema/spec@1.0.0': 725 | resolution: {integrity: sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==} 726 | 727 | '@types/chai@5.2.3': 728 | resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==} 729 | 730 | '@types/deep-eql@4.0.2': 731 | resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==} 732 | 733 | '@types/estree@1.0.8': 734 | resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} 735 | 736 | '@types/json-schema@7.0.15': 737 | resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} 738 | 739 | '@types/node@24.10.1': 740 | resolution: {integrity: sha512-GNWcUTRBgIRJD5zj+Tq0fKOJ5XZajIiBroOF0yvj2bSU1WvNdYS/dn9UxwsujGW4JX06dnHyjV2y9rRaybH0iQ==} 741 | 742 | '@types/statuses@2.0.6': 743 | resolution: {integrity: sha512-xMAgYwceFhRA2zY+XbEA7mxYbA093wdiW8Vu6gZPGWy9cmOyU9XesH1tNcEWsKFd5Vzrqx5T3D38PWx1FIIXkA==} 744 | 745 | '@vitest/expect@4.0.15': 746 | resolution: {integrity: sha512-Gfyva9/GxPAWXIWjyGDli9O+waHDC0Q0jaLdFP1qPAUUfo1FEXPXUfUkp3eZA0sSq340vPycSyOlYUeM15Ft1w==} 747 | 748 | '@vitest/mocker@4.0.15': 749 | resolution: {integrity: sha512-CZ28GLfOEIFkvCFngN8Sfx5h+Se0zN+h4B7yOsPVCcgtiO7t5jt9xQh2E1UkFep+eb9fjyMfuC5gBypwb07fvQ==} 750 | peerDependencies: 751 | msw: ^2.4.9 752 | vite: ^6.0.0 || ^7.0.0-0 753 | peerDependenciesMeta: 754 | msw: 755 | optional: true 756 | vite: 757 | optional: true 758 | 759 | '@vitest/pretty-format@4.0.15': 760 | resolution: {integrity: sha512-SWdqR8vEv83WtZcrfLNqlqeQXlQLh2iilO1Wk1gv4eiHKjEzvgHb2OVc3mIPyhZE6F+CtfYjNlDJwP5MN6Km7A==} 761 | 762 | '@vitest/runner@4.0.15': 763 | resolution: {integrity: sha512-+A+yMY8dGixUhHmNdPUxOh0la6uVzun86vAbuMT3hIDxMrAOmn5ILBHm8ajrqHE0t8R9T1dGnde1A5DTnmi3qw==} 764 | 765 | '@vitest/snapshot@4.0.15': 766 | resolution: {integrity: sha512-A7Ob8EdFZJIBjLjeO0DZF4lqR6U7Ydi5/5LIZ0xcI+23lYlsYJAfGn8PrIWTYdZQRNnSRlzhg0zyGu37mVdy5g==} 767 | 768 | '@vitest/spy@4.0.15': 769 | resolution: {integrity: sha512-+EIjOJmnY6mIfdXtE/bnozKEvTC4Uczg19yeZ2vtCz5Yyb0QQ31QWVQ8hswJ3Ysx/K2EqaNsVanjr//2+P3FHw==} 770 | 771 | '@vitest/utils@4.0.15': 772 | resolution: {integrity: sha512-HXjPW2w5dxhTD0dLwtYHDnelK3j8sR8cWIaLxr22evTyY6q8pRCjZSmhRWVjBaOVXChQd6AwMzi9pucorXCPZA==} 773 | 774 | acorn-jsx@5.3.2: 775 | resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} 776 | peerDependencies: 777 | acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 778 | 779 | acorn@8.15.0: 780 | resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==} 781 | engines: {node: '>=0.4.0'} 782 | hasBin: true 783 | 784 | ajv@6.12.6: 785 | resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} 786 | 787 | ansi-regex@5.0.1: 788 | resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} 789 | engines: {node: '>=8'} 790 | 791 | ansi-regex@6.2.2: 792 | resolution: {integrity: sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==} 793 | engines: {node: '>=12'} 794 | 795 | ansi-styles@4.3.0: 796 | resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} 797 | engines: {node: '>=8'} 798 | 799 | ansi-styles@6.2.3: 800 | resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==} 801 | engines: {node: '>=12'} 802 | 803 | any-promise@1.3.0: 804 | resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} 805 | 806 | argparse@2.0.1: 807 | resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} 808 | 809 | assertion-error@2.0.1: 810 | resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} 811 | engines: {node: '>=12'} 812 | 813 | balanced-match@1.0.2: 814 | resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} 815 | 816 | brace-expansion@1.1.12: 817 | resolution: {integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==} 818 | 819 | brace-expansion@2.0.2: 820 | resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==} 821 | 822 | bundle-require@5.1.0: 823 | resolution: {integrity: sha512-3WrrOuZiyaaZPWiEt4G3+IffISVC9HYlWueJEBWED4ZH4aIAC2PnkdnuRrR94M+w6yGWn4AglWtJtBI8YqvgoA==} 824 | engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} 825 | peerDependencies: 826 | esbuild: '>=0.18' 827 | 828 | cac@6.7.14: 829 | resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} 830 | engines: {node: '>=8'} 831 | 832 | callsites@3.1.0: 833 | resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} 834 | engines: {node: '>=6'} 835 | 836 | chai@6.2.1: 837 | resolution: {integrity: sha512-p4Z49OGG5W/WBCPSS/dH3jQ73kD6tiMmUM+bckNK6Jr5JHMG3k9bg/BvKR8lKmtVBKmOiuVaV2ws8s9oSbwysg==} 838 | engines: {node: '>=18'} 839 | 840 | chalk@4.1.2: 841 | resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} 842 | engines: {node: '>=10'} 843 | 844 | chokidar@4.0.3: 845 | resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} 846 | engines: {node: '>= 14.16.0'} 847 | 848 | cli-width@4.1.0: 849 | resolution: {integrity: sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==} 850 | engines: {node: '>= 12'} 851 | 852 | cliui@8.0.1: 853 | resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} 854 | engines: {node: '>=12'} 855 | 856 | color-convert@2.0.1: 857 | resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} 858 | engines: {node: '>=7.0.0'} 859 | 860 | color-name@1.1.4: 861 | resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} 862 | 863 | commander@4.1.1: 864 | resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} 865 | engines: {node: '>= 6'} 866 | 867 | concat-map@0.0.1: 868 | resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} 869 | 870 | confbox@0.1.8: 871 | resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==} 872 | 873 | consola@3.4.2: 874 | resolution: {integrity: sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==} 875 | engines: {node: ^14.18.0 || >=16.10.0} 876 | 877 | cookie@1.1.1: 878 | resolution: {integrity: sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==} 879 | engines: {node: '>=18'} 880 | 881 | cross-spawn@7.0.6: 882 | resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} 883 | engines: {node: '>= 8'} 884 | 885 | debug@4.4.3: 886 | resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} 887 | engines: {node: '>=6.0'} 888 | peerDependencies: 889 | supports-color: '*' 890 | peerDependenciesMeta: 891 | supports-color: 892 | optional: true 893 | 894 | deep-is@0.1.4: 895 | resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} 896 | 897 | eastasianwidth@0.2.0: 898 | resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} 899 | 900 | emoji-regex@8.0.0: 901 | resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} 902 | 903 | emoji-regex@9.2.2: 904 | resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} 905 | 906 | es-module-lexer@1.7.0: 907 | resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==} 908 | 909 | esbuild@0.25.12: 910 | resolution: {integrity: sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==} 911 | engines: {node: '>=18'} 912 | hasBin: true 913 | 914 | esbuild@0.27.0: 915 | resolution: {integrity: sha512-jd0f4NHbD6cALCyGElNpGAOtWxSq46l9X/sWB0Nzd5er4Kz2YTm+Vl0qKFT9KUJvD8+fiO8AvoHhFvEatfVixA==} 916 | engines: {node: '>=18'} 917 | hasBin: true 918 | 919 | escalade@3.2.0: 920 | resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} 921 | engines: {node: '>=6'} 922 | 923 | escape-string-regexp@4.0.0: 924 | resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} 925 | engines: {node: '>=10'} 926 | 927 | eslint-scope@8.4.0: 928 | resolution: {integrity: sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==} 929 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 930 | 931 | eslint-visitor-keys@3.4.3: 932 | resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} 933 | engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} 934 | 935 | eslint-visitor-keys@4.2.1: 936 | resolution: {integrity: sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==} 937 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 938 | 939 | eslint@9.39.1: 940 | resolution: {integrity: sha512-BhHmn2yNOFA9H9JmmIVKJmd288g9hrVRDkdoIgRCRuSySRUHH7r/DI6aAXW9T1WwUuY3DFgrcaqB+deURBLR5g==} 941 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 942 | hasBin: true 943 | peerDependencies: 944 | jiti: '*' 945 | peerDependenciesMeta: 946 | jiti: 947 | optional: true 948 | 949 | espree@10.4.0: 950 | resolution: {integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==} 951 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 952 | 953 | esquery@1.6.0: 954 | resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==} 955 | engines: {node: '>=0.10'} 956 | 957 | esrecurse@4.3.0: 958 | resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} 959 | engines: {node: '>=4.0'} 960 | 961 | estraverse@5.3.0: 962 | resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} 963 | engines: {node: '>=4.0'} 964 | 965 | estree-walker@3.0.3: 966 | resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} 967 | 968 | esutils@2.0.3: 969 | resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} 970 | engines: {node: '>=0.10.0'} 971 | 972 | eventsource-parser@3.0.6: 973 | resolution: {integrity: sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg==} 974 | engines: {node: '>=18.0.0'} 975 | 976 | expect-type@1.2.2: 977 | resolution: {integrity: sha512-JhFGDVJ7tmDJItKhYgJCGLOWjuK9vPxiXoUFLwLDc99NlmklilbiQJwoctZtt13+xMw91MCk/REan6MWHqDjyA==} 978 | engines: {node: '>=12.0.0'} 979 | 980 | fast-deep-equal@3.1.3: 981 | resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} 982 | 983 | fast-json-stable-stringify@2.1.0: 984 | resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} 985 | 986 | fast-levenshtein@2.0.6: 987 | resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} 988 | 989 | fdir@6.5.0: 990 | resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} 991 | engines: {node: '>=12.0.0'} 992 | peerDependencies: 993 | picomatch: ^3 || ^4 994 | peerDependenciesMeta: 995 | picomatch: 996 | optional: true 997 | 998 | file-entry-cache@8.0.0: 999 | resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} 1000 | engines: {node: '>=16.0.0'} 1001 | 1002 | find-up@5.0.0: 1003 | resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} 1004 | engines: {node: '>=10'} 1005 | 1006 | fix-dts-default-cjs-exports@1.0.1: 1007 | resolution: {integrity: sha512-pVIECanWFC61Hzl2+oOCtoJ3F17kglZC/6N94eRWycFgBH35hHx0Li604ZIzhseh97mf2p0cv7vVrOZGoqhlEg==} 1008 | 1009 | flat-cache@4.0.1: 1010 | resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} 1011 | engines: {node: '>=16'} 1012 | 1013 | flatted@3.3.3: 1014 | resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==} 1015 | 1016 | foreground-child@3.3.1: 1017 | resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} 1018 | engines: {node: '>=14'} 1019 | 1020 | fsevents@2.3.3: 1021 | resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} 1022 | engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} 1023 | os: [darwin] 1024 | 1025 | get-caller-file@2.0.5: 1026 | resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} 1027 | engines: {node: 6.* || 8.* || >= 10.*} 1028 | 1029 | glob-parent@6.0.2: 1030 | resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} 1031 | engines: {node: '>=10.13.0'} 1032 | 1033 | glob@10.4.5: 1034 | resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==} 1035 | hasBin: true 1036 | 1037 | globals@14.0.0: 1038 | resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} 1039 | engines: {node: '>=18'} 1040 | 1041 | graphql@16.12.0: 1042 | resolution: {integrity: sha512-DKKrynuQRne0PNpEbzuEdHlYOMksHSUI8Zc9Unei5gTsMNA2/vMpoMz/yKba50pejK56qj98qM0SjYxAKi13gQ==} 1043 | engines: {node: ^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0} 1044 | 1045 | has-flag@4.0.0: 1046 | resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} 1047 | engines: {node: '>=8'} 1048 | 1049 | headers-polyfill@4.0.3: 1050 | resolution: {integrity: sha512-IScLbePpkvO846sIwOtOTDjutRMWdXdJmXdMvk6gCBHxFO8d+QKOQedyZSxFTTFYRSmlgSTDtXqqq4pcenBXLQ==} 1051 | 1052 | ignore@5.3.2: 1053 | resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} 1054 | engines: {node: '>= 4'} 1055 | 1056 | import-fresh@3.3.1: 1057 | resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} 1058 | engines: {node: '>=6'} 1059 | 1060 | imurmurhash@0.1.4: 1061 | resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} 1062 | engines: {node: '>=0.8.19'} 1063 | 1064 | is-extglob@2.1.1: 1065 | resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} 1066 | engines: {node: '>=0.10.0'} 1067 | 1068 | is-fullwidth-code-point@3.0.0: 1069 | resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} 1070 | engines: {node: '>=8'} 1071 | 1072 | is-glob@4.0.3: 1073 | resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} 1074 | engines: {node: '>=0.10.0'} 1075 | 1076 | is-node-process@1.2.0: 1077 | resolution: {integrity: sha512-Vg4o6/fqPxIjtxgUH5QLJhwZ7gW5diGCVlXpuUfELC62CuxM1iHcRe51f2W1FDy04Ai4KJkagKjx3XaqyfRKXw==} 1078 | 1079 | isexe@2.0.0: 1080 | resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} 1081 | 1082 | jackspeak@3.4.3: 1083 | resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} 1084 | 1085 | joycon@3.1.1: 1086 | resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==} 1087 | engines: {node: '>=10'} 1088 | 1089 | js-yaml@4.1.1: 1090 | resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==} 1091 | hasBin: true 1092 | 1093 | json-buffer@3.0.1: 1094 | resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} 1095 | 1096 | json-schema-traverse@0.4.1: 1097 | resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} 1098 | 1099 | json-schema@0.4.0: 1100 | resolution: {integrity: sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==} 1101 | 1102 | json-stable-stringify-without-jsonify@1.0.1: 1103 | resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} 1104 | 1105 | keyv@4.5.4: 1106 | resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} 1107 | 1108 | levn@0.4.1: 1109 | resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} 1110 | engines: {node: '>= 0.8.0'} 1111 | 1112 | lilconfig@3.1.3: 1113 | resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==} 1114 | engines: {node: '>=14'} 1115 | 1116 | lines-and-columns@1.2.4: 1117 | resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} 1118 | 1119 | load-tsconfig@0.2.5: 1120 | resolution: {integrity: sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg==} 1121 | engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} 1122 | 1123 | locate-path@6.0.0: 1124 | resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} 1125 | engines: {node: '>=10'} 1126 | 1127 | lodash.merge@4.6.2: 1128 | resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} 1129 | 1130 | lru-cache@10.4.3: 1131 | resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} 1132 | 1133 | magic-string@0.30.21: 1134 | resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} 1135 | 1136 | minimatch@3.1.2: 1137 | resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} 1138 | 1139 | minimatch@9.0.5: 1140 | resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} 1141 | engines: {node: '>=16 || 14 >=14.17'} 1142 | 1143 | minipass@7.1.2: 1144 | resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} 1145 | engines: {node: '>=16 || 14 >=14.17'} 1146 | 1147 | mlly@1.8.0: 1148 | resolution: {integrity: sha512-l8D9ODSRWLe2KHJSifWGwBqpTZXIXTeo8mlKjY+E2HAakaTeNpqAyBZ8GSqLzHgw4XmHmC8whvpjJNMbFZN7/g==} 1149 | 1150 | ms@2.1.3: 1151 | resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} 1152 | 1153 | msw@2.12.4: 1154 | resolution: {integrity: sha512-rHNiVfTyKhzc0EjoXUBVGteNKBevdjOlVC6GlIRXpy+/3LHEIGRovnB5WPjcvmNODVQ1TNFnoa7wsGbd0V3epg==} 1155 | engines: {node: '>=18'} 1156 | hasBin: true 1157 | peerDependencies: 1158 | typescript: '>= 4.8.x' 1159 | peerDependenciesMeta: 1160 | typescript: 1161 | optional: true 1162 | 1163 | mute-stream@2.0.0: 1164 | resolution: {integrity: sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA==} 1165 | engines: {node: ^18.17.0 || >=20.5.0} 1166 | 1167 | mz@2.7.0: 1168 | resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} 1169 | 1170 | nanoid@3.3.11: 1171 | resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} 1172 | engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} 1173 | hasBin: true 1174 | 1175 | natural-compare@1.4.0: 1176 | resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} 1177 | 1178 | object-assign@4.1.1: 1179 | resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} 1180 | engines: {node: '>=0.10.0'} 1181 | 1182 | obug@2.1.1: 1183 | resolution: {integrity: sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==} 1184 | 1185 | optionator@0.9.4: 1186 | resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} 1187 | engines: {node: '>= 0.8.0'} 1188 | 1189 | outvariant@1.4.3: 1190 | resolution: {integrity: sha512-+Sl2UErvtsoajRDKCE5/dBz4DIvHXQQnAxtQTF04OJxY0+DyZXSo5P5Bb7XYWOh81syohlYL24hbDwxedPUJCA==} 1191 | 1192 | p-limit@3.1.0: 1193 | resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} 1194 | engines: {node: '>=10'} 1195 | 1196 | p-locate@5.0.0: 1197 | resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} 1198 | engines: {node: '>=10'} 1199 | 1200 | package-json-from-dist@1.0.1: 1201 | resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} 1202 | 1203 | parent-module@1.0.1: 1204 | resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} 1205 | engines: {node: '>=6'} 1206 | 1207 | path-exists@4.0.0: 1208 | resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} 1209 | engines: {node: '>=8'} 1210 | 1211 | path-key@3.1.1: 1212 | resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} 1213 | engines: {node: '>=8'} 1214 | 1215 | path-scurry@1.11.1: 1216 | resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} 1217 | engines: {node: '>=16 || 14 >=14.18'} 1218 | 1219 | path-to-regexp@6.3.0: 1220 | resolution: {integrity: sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==} 1221 | 1222 | pathe@2.0.3: 1223 | resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} 1224 | 1225 | picocolors@1.1.1: 1226 | resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} 1227 | 1228 | picomatch@4.0.3: 1229 | resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} 1230 | engines: {node: '>=12'} 1231 | 1232 | pirates@4.0.7: 1233 | resolution: {integrity: sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==} 1234 | engines: {node: '>= 6'} 1235 | 1236 | pkg-types@1.3.1: 1237 | resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==} 1238 | 1239 | postcss-load-config@6.0.1: 1240 | resolution: {integrity: sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==} 1241 | engines: {node: '>= 18'} 1242 | peerDependencies: 1243 | jiti: '>=1.21.0' 1244 | postcss: '>=8.0.9' 1245 | tsx: ^4.8.1 1246 | yaml: ^2.4.2 1247 | peerDependenciesMeta: 1248 | jiti: 1249 | optional: true 1250 | postcss: 1251 | optional: true 1252 | tsx: 1253 | optional: true 1254 | yaml: 1255 | optional: true 1256 | 1257 | postcss@8.5.6: 1258 | resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} 1259 | engines: {node: ^10 || ^12 || >=14} 1260 | 1261 | prelude-ls@1.2.1: 1262 | resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} 1263 | engines: {node: '>= 0.8.0'} 1264 | 1265 | punycode@2.3.1: 1266 | resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} 1267 | engines: {node: '>=6'} 1268 | 1269 | readdirp@4.1.2: 1270 | resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} 1271 | engines: {node: '>= 14.18.0'} 1272 | 1273 | require-directory@2.1.1: 1274 | resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} 1275 | engines: {node: '>=0.10.0'} 1276 | 1277 | resolve-from@4.0.0: 1278 | resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} 1279 | engines: {node: '>=4'} 1280 | 1281 | resolve-from@5.0.0: 1282 | resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} 1283 | engines: {node: '>=8'} 1284 | 1285 | rettime@0.7.0: 1286 | resolution: {integrity: sha512-LPRKoHnLKd/r3dVxcwO7vhCW+orkOGj9ViueosEBK6ie89CijnfRlhaDhHq/3Hxu4CkWQtxwlBG0mzTQY6uQjw==} 1287 | 1288 | rollup@4.53.2: 1289 | resolution: {integrity: sha512-MHngMYwGJVi6Fmnk6ISmnk7JAHRNF0UkuucA0CUW3N3a4KnONPEZz+vUanQP/ZC/iY1Qkf3bwPWzyY84wEks1g==} 1290 | engines: {node: '>=18.0.0', npm: '>=8.0.0'} 1291 | hasBin: true 1292 | 1293 | rollup@4.53.3: 1294 | resolution: {integrity: sha512-w8GmOxZfBmKknvdXU1sdM9NHcoQejwF/4mNgj2JuEEdRaHwwF12K7e9eXn1nLZ07ad+du76mkVsyeb2rKGllsA==} 1295 | engines: {node: '>=18.0.0', npm: '>=8.0.0'} 1296 | hasBin: true 1297 | 1298 | shebang-command@2.0.0: 1299 | resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} 1300 | engines: {node: '>=8'} 1301 | 1302 | shebang-regex@3.0.0: 1303 | resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} 1304 | engines: {node: '>=8'} 1305 | 1306 | siginfo@2.0.0: 1307 | resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} 1308 | 1309 | signal-exit@4.1.0: 1310 | resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} 1311 | engines: {node: '>=14'} 1312 | 1313 | source-map-js@1.2.1: 1314 | resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} 1315 | engines: {node: '>=0.10.0'} 1316 | 1317 | source-map@0.7.6: 1318 | resolution: {integrity: sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==} 1319 | engines: {node: '>= 12'} 1320 | 1321 | stackback@0.0.2: 1322 | resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} 1323 | 1324 | statuses@2.0.2: 1325 | resolution: {integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==} 1326 | engines: {node: '>= 0.8'} 1327 | 1328 | std-env@3.10.0: 1329 | resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==} 1330 | 1331 | strict-event-emitter@0.5.1: 1332 | resolution: {integrity: sha512-vMgjE/GGEPEFnhFub6pa4FmJBRBVOLpIII2hvCZ8Kzb7K0hlHo7mQv6xYrBvCL2LtAIBwFUK8wvuJgTVSQ5MFQ==} 1333 | 1334 | string-width@4.2.3: 1335 | resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} 1336 | engines: {node: '>=8'} 1337 | 1338 | string-width@5.1.2: 1339 | resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} 1340 | engines: {node: '>=12'} 1341 | 1342 | strip-ansi@6.0.1: 1343 | resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} 1344 | engines: {node: '>=8'} 1345 | 1346 | strip-ansi@7.1.2: 1347 | resolution: {integrity: sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==} 1348 | engines: {node: '>=12'} 1349 | 1350 | strip-json-comments@3.1.1: 1351 | resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} 1352 | engines: {node: '>=8'} 1353 | 1354 | sucrase@3.35.0: 1355 | resolution: {integrity: sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==} 1356 | engines: {node: '>=16 || 14 >=14.17'} 1357 | hasBin: true 1358 | 1359 | supports-color@7.2.0: 1360 | resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} 1361 | engines: {node: '>=8'} 1362 | 1363 | tagged-tag@1.0.0: 1364 | resolution: {integrity: sha512-yEFYrVhod+hdNyx7g5Bnkkb0G6si8HJurOoOEgC8B/O0uXLHlaey/65KRv6cuWBNhBgHKAROVpc7QyYqE5gFng==} 1365 | engines: {node: '>=20'} 1366 | 1367 | thenify-all@1.6.0: 1368 | resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} 1369 | engines: {node: '>=0.8'} 1370 | 1371 | thenify@3.3.1: 1372 | resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} 1373 | 1374 | tinybench@2.9.0: 1375 | resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} 1376 | 1377 | tinyexec@0.3.2: 1378 | resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} 1379 | 1380 | tinyexec@1.0.2: 1381 | resolution: {integrity: sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==} 1382 | engines: {node: '>=18'} 1383 | 1384 | tinyglobby@0.2.15: 1385 | resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} 1386 | engines: {node: '>=12.0.0'} 1387 | 1388 | tinyrainbow@3.0.3: 1389 | resolution: {integrity: sha512-PSkbLUoxOFRzJYjjxHJt9xro7D+iilgMX/C9lawzVuYiIdcihh9DXmVibBe8lmcFrRi/VzlPjBxbN7rH24q8/Q==} 1390 | engines: {node: '>=14.0.0'} 1391 | 1392 | tldts-core@7.0.19: 1393 | resolution: {integrity: sha512-lJX2dEWx0SGH4O6p+7FPwYmJ/bu1JbcGJ8RLaG9b7liIgZ85itUVEPbMtWRVrde/0fnDPEPHW10ZsKW3kVsE9A==} 1394 | 1395 | tldts@7.0.19: 1396 | resolution: {integrity: sha512-8PWx8tvC4jDB39BQw1m4x8y5MH1BcQ5xHeL2n7UVFulMPH/3Q0uiamahFJ3lXA0zO2SUyRXuVVbWSDmstlt9YA==} 1397 | hasBin: true 1398 | 1399 | tough-cookie@6.0.0: 1400 | resolution: {integrity: sha512-kXuRi1mtaKMrsLUxz3sQYvVl37B0Ns6MzfrtV5DvJceE9bPyspOqk9xxv7XbZWcfLWbFmm997vl83qUWVJA64w==} 1401 | engines: {node: '>=16'} 1402 | 1403 | tree-kill@1.2.2: 1404 | resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} 1405 | hasBin: true 1406 | 1407 | ts-interface-checker@0.1.13: 1408 | resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} 1409 | 1410 | tsup@8.5.1: 1411 | resolution: {integrity: sha512-xtgkqwdhpKWr3tKPmCkvYmS9xnQK3m3XgxZHwSUjvfTjp7YfXe5tT3GgWi0F2N+ZSMsOeWeZFh7ZZFg5iPhing==} 1412 | engines: {node: '>=18'} 1413 | hasBin: true 1414 | peerDependencies: 1415 | '@microsoft/api-extractor': ^7.36.0 1416 | '@swc/core': ^1 1417 | postcss: ^8.4.12 1418 | typescript: '>=4.5.0' 1419 | peerDependenciesMeta: 1420 | '@microsoft/api-extractor': 1421 | optional: true 1422 | '@swc/core': 1423 | optional: true 1424 | postcss: 1425 | optional: true 1426 | typescript: 1427 | optional: true 1428 | 1429 | type-check@0.4.0: 1430 | resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} 1431 | engines: {node: '>= 0.8.0'} 1432 | 1433 | type-fest@5.3.0: 1434 | resolution: {integrity: sha512-d9CwU93nN0IA1QL+GSNDdwLAu1Ew5ZjTwupvedwg3WdfoH6pIDvYQ2hV0Uc2nKBLPq7NB5apCx57MLS5qlmO5g==} 1435 | engines: {node: '>=20'} 1436 | 1437 | typescript@5.9.3: 1438 | resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} 1439 | engines: {node: '>=14.17'} 1440 | hasBin: true 1441 | 1442 | ufo@1.6.1: 1443 | resolution: {integrity: sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA==} 1444 | 1445 | undici-types@7.16.0: 1446 | resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==} 1447 | 1448 | until-async@3.0.2: 1449 | resolution: {integrity: sha512-IiSk4HlzAMqTUseHHe3VhIGyuFmN90zMTpD3Z3y8jeQbzLIq500MVM7Jq2vUAnTKAFPJrqwkzr6PoTcPhGcOiw==} 1450 | 1451 | uri-js@4.4.1: 1452 | resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} 1453 | 1454 | vite@7.2.4: 1455 | resolution: {integrity: sha512-NL8jTlbo0Tn4dUEXEsUg8KeyG/Lkmc4Fnzb8JXN/Ykm9G4HNImjtABMJgkQoVjOBN/j2WAwDTRytdqJbZsah7w==} 1456 | engines: {node: ^20.19.0 || >=22.12.0} 1457 | hasBin: true 1458 | peerDependencies: 1459 | '@types/node': ^20.19.0 || >=22.12.0 1460 | jiti: '>=1.21.0' 1461 | less: ^4.0.0 1462 | lightningcss: ^1.21.0 1463 | sass: ^1.70.0 1464 | sass-embedded: ^1.70.0 1465 | stylus: '>=0.54.8' 1466 | sugarss: ^5.0.0 1467 | terser: ^5.16.0 1468 | tsx: ^4.8.1 1469 | yaml: ^2.4.2 1470 | peerDependenciesMeta: 1471 | '@types/node': 1472 | optional: true 1473 | jiti: 1474 | optional: true 1475 | less: 1476 | optional: true 1477 | lightningcss: 1478 | optional: true 1479 | sass: 1480 | optional: true 1481 | sass-embedded: 1482 | optional: true 1483 | stylus: 1484 | optional: true 1485 | sugarss: 1486 | optional: true 1487 | terser: 1488 | optional: true 1489 | tsx: 1490 | optional: true 1491 | yaml: 1492 | optional: true 1493 | 1494 | vitest@4.0.15: 1495 | resolution: {integrity: sha512-n1RxDp8UJm6N0IbJLQo+yzLZ2sQCDyl1o0LeugbPWf8+8Fttp29GghsQBjYJVmWq3gBFfe9Hs1spR44vovn2wA==} 1496 | engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0} 1497 | hasBin: true 1498 | peerDependencies: 1499 | '@edge-runtime/vm': '*' 1500 | '@opentelemetry/api': ^1.9.0 1501 | '@types/node': ^20.0.0 || ^22.0.0 || >=24.0.0 1502 | '@vitest/browser-playwright': 4.0.15 1503 | '@vitest/browser-preview': 4.0.15 1504 | '@vitest/browser-webdriverio': 4.0.15 1505 | '@vitest/ui': 4.0.15 1506 | happy-dom: '*' 1507 | jsdom: '*' 1508 | peerDependenciesMeta: 1509 | '@edge-runtime/vm': 1510 | optional: true 1511 | '@opentelemetry/api': 1512 | optional: true 1513 | '@types/node': 1514 | optional: true 1515 | '@vitest/browser-playwright': 1516 | optional: true 1517 | '@vitest/browser-preview': 1518 | optional: true 1519 | '@vitest/browser-webdriverio': 1520 | optional: true 1521 | '@vitest/ui': 1522 | optional: true 1523 | happy-dom: 1524 | optional: true 1525 | jsdom: 1526 | optional: true 1527 | 1528 | which@2.0.2: 1529 | resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} 1530 | engines: {node: '>= 8'} 1531 | hasBin: true 1532 | 1533 | why-is-node-running@2.3.0: 1534 | resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} 1535 | engines: {node: '>=8'} 1536 | hasBin: true 1537 | 1538 | word-wrap@1.2.5: 1539 | resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} 1540 | engines: {node: '>=0.10.0'} 1541 | 1542 | wrap-ansi@6.2.0: 1543 | resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==} 1544 | engines: {node: '>=8'} 1545 | 1546 | wrap-ansi@7.0.0: 1547 | resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} 1548 | engines: {node: '>=10'} 1549 | 1550 | wrap-ansi@8.1.0: 1551 | resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} 1552 | engines: {node: '>=12'} 1553 | 1554 | y18n@5.0.8: 1555 | resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} 1556 | engines: {node: '>=10'} 1557 | 1558 | yargs-parser@21.1.1: 1559 | resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} 1560 | engines: {node: '>=12'} 1561 | 1562 | yargs@17.7.2: 1563 | resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} 1564 | engines: {node: '>=12'} 1565 | 1566 | yocto-queue@0.1.0: 1567 | resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} 1568 | engines: {node: '>=10'} 1569 | 1570 | yoctocolors-cjs@2.1.3: 1571 | resolution: {integrity: sha512-U/PBtDf35ff0D8X8D0jfdzHYEPFxAI7jJlxZXwCSez5M3190m+QobIfh+sWDWSHMCWWJN2AWamkegn6vr6YBTw==} 1572 | engines: {node: '>=18'} 1573 | 1574 | zod@4.1.13: 1575 | resolution: {integrity: sha512-AvvthqfqrAhNH9dnfmrfKzX5upOdjUVJYFqNSlkmGf64gRaTzlPwz99IHYnVs28qYAybvAlBV+H7pn0saFY4Ig==} 1576 | 1577 | snapshots: 1578 | 1579 | '@ai-sdk/provider-utils@3.0.17(zod@4.1.13)': 1580 | dependencies: 1581 | '@ai-sdk/provider': 2.0.0 1582 | '@standard-schema/spec': 1.0.0 1583 | eventsource-parser: 3.0.6 1584 | zod: 4.1.13 1585 | 1586 | '@ai-sdk/provider@2.0.0': 1587 | dependencies: 1588 | json-schema: 0.4.0 1589 | 1590 | '@edge-runtime/primitives@6.0.0': {} 1591 | 1592 | '@edge-runtime/vm@5.0.0': 1593 | dependencies: 1594 | '@edge-runtime/primitives': 6.0.0 1595 | 1596 | '@esbuild/aix-ppc64@0.25.12': 1597 | optional: true 1598 | 1599 | '@esbuild/aix-ppc64@0.27.0': 1600 | optional: true 1601 | 1602 | '@esbuild/android-arm64@0.25.12': 1603 | optional: true 1604 | 1605 | '@esbuild/android-arm64@0.27.0': 1606 | optional: true 1607 | 1608 | '@esbuild/android-arm@0.25.12': 1609 | optional: true 1610 | 1611 | '@esbuild/android-arm@0.27.0': 1612 | optional: true 1613 | 1614 | '@esbuild/android-x64@0.25.12': 1615 | optional: true 1616 | 1617 | '@esbuild/android-x64@0.27.0': 1618 | optional: true 1619 | 1620 | '@esbuild/darwin-arm64@0.25.12': 1621 | optional: true 1622 | 1623 | '@esbuild/darwin-arm64@0.27.0': 1624 | optional: true 1625 | 1626 | '@esbuild/darwin-x64@0.25.12': 1627 | optional: true 1628 | 1629 | '@esbuild/darwin-x64@0.27.0': 1630 | optional: true 1631 | 1632 | '@esbuild/freebsd-arm64@0.25.12': 1633 | optional: true 1634 | 1635 | '@esbuild/freebsd-arm64@0.27.0': 1636 | optional: true 1637 | 1638 | '@esbuild/freebsd-x64@0.25.12': 1639 | optional: true 1640 | 1641 | '@esbuild/freebsd-x64@0.27.0': 1642 | optional: true 1643 | 1644 | '@esbuild/linux-arm64@0.25.12': 1645 | optional: true 1646 | 1647 | '@esbuild/linux-arm64@0.27.0': 1648 | optional: true 1649 | 1650 | '@esbuild/linux-arm@0.25.12': 1651 | optional: true 1652 | 1653 | '@esbuild/linux-arm@0.27.0': 1654 | optional: true 1655 | 1656 | '@esbuild/linux-ia32@0.25.12': 1657 | optional: true 1658 | 1659 | '@esbuild/linux-ia32@0.27.0': 1660 | optional: true 1661 | 1662 | '@esbuild/linux-loong64@0.25.12': 1663 | optional: true 1664 | 1665 | '@esbuild/linux-loong64@0.27.0': 1666 | optional: true 1667 | 1668 | '@esbuild/linux-mips64el@0.25.12': 1669 | optional: true 1670 | 1671 | '@esbuild/linux-mips64el@0.27.0': 1672 | optional: true 1673 | 1674 | '@esbuild/linux-ppc64@0.25.12': 1675 | optional: true 1676 | 1677 | '@esbuild/linux-ppc64@0.27.0': 1678 | optional: true 1679 | 1680 | '@esbuild/linux-riscv64@0.25.12': 1681 | optional: true 1682 | 1683 | '@esbuild/linux-riscv64@0.27.0': 1684 | optional: true 1685 | 1686 | '@esbuild/linux-s390x@0.25.12': 1687 | optional: true 1688 | 1689 | '@esbuild/linux-s390x@0.27.0': 1690 | optional: true 1691 | 1692 | '@esbuild/linux-x64@0.25.12': 1693 | optional: true 1694 | 1695 | '@esbuild/linux-x64@0.27.0': 1696 | optional: true 1697 | 1698 | '@esbuild/netbsd-arm64@0.25.12': 1699 | optional: true 1700 | 1701 | '@esbuild/netbsd-arm64@0.27.0': 1702 | optional: true 1703 | 1704 | '@esbuild/netbsd-x64@0.25.12': 1705 | optional: true 1706 | 1707 | '@esbuild/netbsd-x64@0.27.0': 1708 | optional: true 1709 | 1710 | '@esbuild/openbsd-arm64@0.25.12': 1711 | optional: true 1712 | 1713 | '@esbuild/openbsd-arm64@0.27.0': 1714 | optional: true 1715 | 1716 | '@esbuild/openbsd-x64@0.25.12': 1717 | optional: true 1718 | 1719 | '@esbuild/openbsd-x64@0.27.0': 1720 | optional: true 1721 | 1722 | '@esbuild/openharmony-arm64@0.25.12': 1723 | optional: true 1724 | 1725 | '@esbuild/openharmony-arm64@0.27.0': 1726 | optional: true 1727 | 1728 | '@esbuild/sunos-x64@0.25.12': 1729 | optional: true 1730 | 1731 | '@esbuild/sunos-x64@0.27.0': 1732 | optional: true 1733 | 1734 | '@esbuild/win32-arm64@0.25.12': 1735 | optional: true 1736 | 1737 | '@esbuild/win32-arm64@0.27.0': 1738 | optional: true 1739 | 1740 | '@esbuild/win32-ia32@0.25.12': 1741 | optional: true 1742 | 1743 | '@esbuild/win32-ia32@0.27.0': 1744 | optional: true 1745 | 1746 | '@esbuild/win32-x64@0.25.12': 1747 | optional: true 1748 | 1749 | '@esbuild/win32-x64@0.27.0': 1750 | optional: true 1751 | 1752 | '@eslint-community/eslint-utils@4.9.0(eslint@9.39.1)': 1753 | dependencies: 1754 | eslint: 9.39.1 1755 | eslint-visitor-keys: 3.4.3 1756 | 1757 | '@eslint-community/regexpp@4.12.2': {} 1758 | 1759 | '@eslint/config-array@0.21.1': 1760 | dependencies: 1761 | '@eslint/object-schema': 2.1.7 1762 | debug: 4.4.3 1763 | minimatch: 3.1.2 1764 | transitivePeerDependencies: 1765 | - supports-color 1766 | 1767 | '@eslint/config-helpers@0.4.2': 1768 | dependencies: 1769 | '@eslint/core': 0.17.0 1770 | 1771 | '@eslint/core@0.17.0': 1772 | dependencies: 1773 | '@types/json-schema': 7.0.15 1774 | 1775 | '@eslint/eslintrc@3.3.1': 1776 | dependencies: 1777 | ajv: 6.12.6 1778 | debug: 4.4.3 1779 | espree: 10.4.0 1780 | globals: 14.0.0 1781 | ignore: 5.3.2 1782 | import-fresh: 3.3.1 1783 | js-yaml: 4.1.1 1784 | minimatch: 3.1.2 1785 | strip-json-comments: 3.1.1 1786 | transitivePeerDependencies: 1787 | - supports-color 1788 | 1789 | '@eslint/js@9.39.1': {} 1790 | 1791 | '@eslint/object-schema@2.1.7': {} 1792 | 1793 | '@eslint/plugin-kit@0.4.1': 1794 | dependencies: 1795 | '@eslint/core': 0.17.0 1796 | levn: 0.4.1 1797 | 1798 | '@humanfs/core@0.19.1': {} 1799 | 1800 | '@humanfs/node@0.16.7': 1801 | dependencies: 1802 | '@humanfs/core': 0.19.1 1803 | '@humanwhocodes/retry': 0.4.3 1804 | 1805 | '@humanwhocodes/module-importer@1.0.1': {} 1806 | 1807 | '@humanwhocodes/retry@0.4.3': {} 1808 | 1809 | '@inquirer/ansi@1.0.2': {} 1810 | 1811 | '@inquirer/confirm@5.1.21(@types/node@24.10.1)': 1812 | dependencies: 1813 | '@inquirer/core': 10.3.2(@types/node@24.10.1) 1814 | '@inquirer/type': 3.0.10(@types/node@24.10.1) 1815 | optionalDependencies: 1816 | '@types/node': 24.10.1 1817 | 1818 | '@inquirer/core@10.3.2(@types/node@24.10.1)': 1819 | dependencies: 1820 | '@inquirer/ansi': 1.0.2 1821 | '@inquirer/figures': 1.0.15 1822 | '@inquirer/type': 3.0.10(@types/node@24.10.1) 1823 | cli-width: 4.1.0 1824 | mute-stream: 2.0.0 1825 | signal-exit: 4.1.0 1826 | wrap-ansi: 6.2.0 1827 | yoctocolors-cjs: 2.1.3 1828 | optionalDependencies: 1829 | '@types/node': 24.10.1 1830 | 1831 | '@inquirer/figures@1.0.15': {} 1832 | 1833 | '@inquirer/type@3.0.10(@types/node@24.10.1)': 1834 | optionalDependencies: 1835 | '@types/node': 24.10.1 1836 | 1837 | '@isaacs/cliui@8.0.2': 1838 | dependencies: 1839 | string-width: 5.1.2 1840 | string-width-cjs: string-width@4.2.3 1841 | strip-ansi: 7.1.2 1842 | strip-ansi-cjs: strip-ansi@6.0.1 1843 | wrap-ansi: 8.1.0 1844 | wrap-ansi-cjs: wrap-ansi@7.0.0 1845 | 1846 | '@jridgewell/gen-mapping@0.3.13': 1847 | dependencies: 1848 | '@jridgewell/sourcemap-codec': 1.5.5 1849 | '@jridgewell/trace-mapping': 0.3.31 1850 | 1851 | '@jridgewell/resolve-uri@3.1.2': {} 1852 | 1853 | '@jridgewell/sourcemap-codec@1.5.5': {} 1854 | 1855 | '@jridgewell/trace-mapping@0.3.31': 1856 | dependencies: 1857 | '@jridgewell/resolve-uri': 3.1.2 1858 | '@jridgewell/sourcemap-codec': 1.5.5 1859 | 1860 | '@mswjs/interceptors@0.40.0': 1861 | dependencies: 1862 | '@open-draft/deferred-promise': 2.2.0 1863 | '@open-draft/logger': 0.3.0 1864 | '@open-draft/until': 2.1.0 1865 | is-node-process: 1.2.0 1866 | outvariant: 1.4.3 1867 | strict-event-emitter: 0.5.1 1868 | 1869 | '@open-draft/deferred-promise@2.2.0': {} 1870 | 1871 | '@open-draft/logger@0.3.0': 1872 | dependencies: 1873 | is-node-process: 1.2.0 1874 | outvariant: 1.4.3 1875 | 1876 | '@open-draft/until@2.1.0': {} 1877 | 1878 | '@pkgjs/parseargs@0.11.0': 1879 | optional: true 1880 | 1881 | '@rollup/rollup-android-arm-eabi@4.53.2': 1882 | optional: true 1883 | 1884 | '@rollup/rollup-android-arm-eabi@4.53.3': 1885 | optional: true 1886 | 1887 | '@rollup/rollup-android-arm64@4.53.2': 1888 | optional: true 1889 | 1890 | '@rollup/rollup-android-arm64@4.53.3': 1891 | optional: true 1892 | 1893 | '@rollup/rollup-darwin-arm64@4.53.2': 1894 | optional: true 1895 | 1896 | '@rollup/rollup-darwin-arm64@4.53.3': 1897 | optional: true 1898 | 1899 | '@rollup/rollup-darwin-x64@4.53.2': 1900 | optional: true 1901 | 1902 | '@rollup/rollup-darwin-x64@4.53.3': 1903 | optional: true 1904 | 1905 | '@rollup/rollup-freebsd-arm64@4.53.2': 1906 | optional: true 1907 | 1908 | '@rollup/rollup-freebsd-arm64@4.53.3': 1909 | optional: true 1910 | 1911 | '@rollup/rollup-freebsd-x64@4.53.2': 1912 | optional: true 1913 | 1914 | '@rollup/rollup-freebsd-x64@4.53.3': 1915 | optional: true 1916 | 1917 | '@rollup/rollup-linux-arm-gnueabihf@4.53.2': 1918 | optional: true 1919 | 1920 | '@rollup/rollup-linux-arm-gnueabihf@4.53.3': 1921 | optional: true 1922 | 1923 | '@rollup/rollup-linux-arm-musleabihf@4.53.2': 1924 | optional: true 1925 | 1926 | '@rollup/rollup-linux-arm-musleabihf@4.53.3': 1927 | optional: true 1928 | 1929 | '@rollup/rollup-linux-arm64-gnu@4.53.2': 1930 | optional: true 1931 | 1932 | '@rollup/rollup-linux-arm64-gnu@4.53.3': 1933 | optional: true 1934 | 1935 | '@rollup/rollup-linux-arm64-musl@4.53.2': 1936 | optional: true 1937 | 1938 | '@rollup/rollup-linux-arm64-musl@4.53.3': 1939 | optional: true 1940 | 1941 | '@rollup/rollup-linux-loong64-gnu@4.53.2': 1942 | optional: true 1943 | 1944 | '@rollup/rollup-linux-loong64-gnu@4.53.3': 1945 | optional: true 1946 | 1947 | '@rollup/rollup-linux-ppc64-gnu@4.53.2': 1948 | optional: true 1949 | 1950 | '@rollup/rollup-linux-ppc64-gnu@4.53.3': 1951 | optional: true 1952 | 1953 | '@rollup/rollup-linux-riscv64-gnu@4.53.2': 1954 | optional: true 1955 | 1956 | '@rollup/rollup-linux-riscv64-gnu@4.53.3': 1957 | optional: true 1958 | 1959 | '@rollup/rollup-linux-riscv64-musl@4.53.2': 1960 | optional: true 1961 | 1962 | '@rollup/rollup-linux-riscv64-musl@4.53.3': 1963 | optional: true 1964 | 1965 | '@rollup/rollup-linux-s390x-gnu@4.53.2': 1966 | optional: true 1967 | 1968 | '@rollup/rollup-linux-s390x-gnu@4.53.3': 1969 | optional: true 1970 | 1971 | '@rollup/rollup-linux-x64-gnu@4.53.2': 1972 | optional: true 1973 | 1974 | '@rollup/rollup-linux-x64-gnu@4.53.3': 1975 | optional: true 1976 | 1977 | '@rollup/rollup-linux-x64-musl@4.53.2': 1978 | optional: true 1979 | 1980 | '@rollup/rollup-linux-x64-musl@4.53.3': 1981 | optional: true 1982 | 1983 | '@rollup/rollup-openharmony-arm64@4.53.2': 1984 | optional: true 1985 | 1986 | '@rollup/rollup-openharmony-arm64@4.53.3': 1987 | optional: true 1988 | 1989 | '@rollup/rollup-win32-arm64-msvc@4.53.2': 1990 | optional: true 1991 | 1992 | '@rollup/rollup-win32-arm64-msvc@4.53.3': 1993 | optional: true 1994 | 1995 | '@rollup/rollup-win32-ia32-msvc@4.53.2': 1996 | optional: true 1997 | 1998 | '@rollup/rollup-win32-ia32-msvc@4.53.3': 1999 | optional: true 2000 | 2001 | '@rollup/rollup-win32-x64-gnu@4.53.2': 2002 | optional: true 2003 | 2004 | '@rollup/rollup-win32-x64-gnu@4.53.3': 2005 | optional: true 2006 | 2007 | '@rollup/rollup-win32-x64-msvc@4.53.2': 2008 | optional: true 2009 | 2010 | '@rollup/rollup-win32-x64-msvc@4.53.3': 2011 | optional: true 2012 | 2013 | '@standard-schema/spec@1.0.0': {} 2014 | 2015 | '@types/chai@5.2.3': 2016 | dependencies: 2017 | '@types/deep-eql': 4.0.2 2018 | assertion-error: 2.0.1 2019 | 2020 | '@types/deep-eql@4.0.2': {} 2021 | 2022 | '@types/estree@1.0.8': {} 2023 | 2024 | '@types/json-schema@7.0.15': {} 2025 | 2026 | '@types/node@24.10.1': 2027 | dependencies: 2028 | undici-types: 7.16.0 2029 | 2030 | '@types/statuses@2.0.6': {} 2031 | 2032 | '@vitest/expect@4.0.15': 2033 | dependencies: 2034 | '@standard-schema/spec': 1.0.0 2035 | '@types/chai': 5.2.3 2036 | '@vitest/spy': 4.0.15 2037 | '@vitest/utils': 4.0.15 2038 | chai: 6.2.1 2039 | tinyrainbow: 3.0.3 2040 | 2041 | '@vitest/mocker@4.0.15(msw@2.12.4(@types/node@24.10.1)(typescript@5.9.3))(vite@7.2.4(@types/node@24.10.1))': 2042 | dependencies: 2043 | '@vitest/spy': 4.0.15 2044 | estree-walker: 3.0.3 2045 | magic-string: 0.30.21 2046 | optionalDependencies: 2047 | msw: 2.12.4(@types/node@24.10.1)(typescript@5.9.3) 2048 | vite: 7.2.4(@types/node@24.10.1) 2049 | 2050 | '@vitest/pretty-format@4.0.15': 2051 | dependencies: 2052 | tinyrainbow: 3.0.3 2053 | 2054 | '@vitest/runner@4.0.15': 2055 | dependencies: 2056 | '@vitest/utils': 4.0.15 2057 | pathe: 2.0.3 2058 | 2059 | '@vitest/snapshot@4.0.15': 2060 | dependencies: 2061 | '@vitest/pretty-format': 4.0.15 2062 | magic-string: 0.30.21 2063 | pathe: 2.0.3 2064 | 2065 | '@vitest/spy@4.0.15': {} 2066 | 2067 | '@vitest/utils@4.0.15': 2068 | dependencies: 2069 | '@vitest/pretty-format': 4.0.15 2070 | tinyrainbow: 3.0.3 2071 | 2072 | acorn-jsx@5.3.2(acorn@8.15.0): 2073 | dependencies: 2074 | acorn: 8.15.0 2075 | 2076 | acorn@8.15.0: {} 2077 | 2078 | ajv@6.12.6: 2079 | dependencies: 2080 | fast-deep-equal: 3.1.3 2081 | fast-json-stable-stringify: 2.1.0 2082 | json-schema-traverse: 0.4.1 2083 | uri-js: 4.4.1 2084 | 2085 | ansi-regex@5.0.1: {} 2086 | 2087 | ansi-regex@6.2.2: {} 2088 | 2089 | ansi-styles@4.3.0: 2090 | dependencies: 2091 | color-convert: 2.0.1 2092 | 2093 | ansi-styles@6.2.3: {} 2094 | 2095 | any-promise@1.3.0: {} 2096 | 2097 | argparse@2.0.1: {} 2098 | 2099 | assertion-error@2.0.1: {} 2100 | 2101 | balanced-match@1.0.2: {} 2102 | 2103 | brace-expansion@1.1.12: 2104 | dependencies: 2105 | balanced-match: 1.0.2 2106 | concat-map: 0.0.1 2107 | 2108 | brace-expansion@2.0.2: 2109 | dependencies: 2110 | balanced-match: 1.0.2 2111 | 2112 | bundle-require@5.1.0(esbuild@0.27.0): 2113 | dependencies: 2114 | esbuild: 0.27.0 2115 | load-tsconfig: 0.2.5 2116 | 2117 | cac@6.7.14: {} 2118 | 2119 | callsites@3.1.0: {} 2120 | 2121 | chai@6.2.1: {} 2122 | 2123 | chalk@4.1.2: 2124 | dependencies: 2125 | ansi-styles: 4.3.0 2126 | supports-color: 7.2.0 2127 | 2128 | chokidar@4.0.3: 2129 | dependencies: 2130 | readdirp: 4.1.2 2131 | 2132 | cli-width@4.1.0: {} 2133 | 2134 | cliui@8.0.1: 2135 | dependencies: 2136 | string-width: 4.2.3 2137 | strip-ansi: 6.0.1 2138 | wrap-ansi: 7.0.0 2139 | 2140 | color-convert@2.0.1: 2141 | dependencies: 2142 | color-name: 1.1.4 2143 | 2144 | color-name@1.1.4: {} 2145 | 2146 | commander@4.1.1: {} 2147 | 2148 | concat-map@0.0.1: {} 2149 | 2150 | confbox@0.1.8: {} 2151 | 2152 | consola@3.4.2: {} 2153 | 2154 | cookie@1.1.1: {} 2155 | 2156 | cross-spawn@7.0.6: 2157 | dependencies: 2158 | path-key: 3.1.1 2159 | shebang-command: 2.0.0 2160 | which: 2.0.2 2161 | 2162 | debug@4.4.3: 2163 | dependencies: 2164 | ms: 2.1.3 2165 | 2166 | deep-is@0.1.4: {} 2167 | 2168 | eastasianwidth@0.2.0: {} 2169 | 2170 | emoji-regex@8.0.0: {} 2171 | 2172 | emoji-regex@9.2.2: {} 2173 | 2174 | es-module-lexer@1.7.0: {} 2175 | 2176 | esbuild@0.25.12: 2177 | optionalDependencies: 2178 | '@esbuild/aix-ppc64': 0.25.12 2179 | '@esbuild/android-arm': 0.25.12 2180 | '@esbuild/android-arm64': 0.25.12 2181 | '@esbuild/android-x64': 0.25.12 2182 | '@esbuild/darwin-arm64': 0.25.12 2183 | '@esbuild/darwin-x64': 0.25.12 2184 | '@esbuild/freebsd-arm64': 0.25.12 2185 | '@esbuild/freebsd-x64': 0.25.12 2186 | '@esbuild/linux-arm': 0.25.12 2187 | '@esbuild/linux-arm64': 0.25.12 2188 | '@esbuild/linux-ia32': 0.25.12 2189 | '@esbuild/linux-loong64': 0.25.12 2190 | '@esbuild/linux-mips64el': 0.25.12 2191 | '@esbuild/linux-ppc64': 0.25.12 2192 | '@esbuild/linux-riscv64': 0.25.12 2193 | '@esbuild/linux-s390x': 0.25.12 2194 | '@esbuild/linux-x64': 0.25.12 2195 | '@esbuild/netbsd-arm64': 0.25.12 2196 | '@esbuild/netbsd-x64': 0.25.12 2197 | '@esbuild/openbsd-arm64': 0.25.12 2198 | '@esbuild/openbsd-x64': 0.25.12 2199 | '@esbuild/openharmony-arm64': 0.25.12 2200 | '@esbuild/sunos-x64': 0.25.12 2201 | '@esbuild/win32-arm64': 0.25.12 2202 | '@esbuild/win32-ia32': 0.25.12 2203 | '@esbuild/win32-x64': 0.25.12 2204 | 2205 | esbuild@0.27.0: 2206 | optionalDependencies: 2207 | '@esbuild/aix-ppc64': 0.27.0 2208 | '@esbuild/android-arm': 0.27.0 2209 | '@esbuild/android-arm64': 0.27.0 2210 | '@esbuild/android-x64': 0.27.0 2211 | '@esbuild/darwin-arm64': 0.27.0 2212 | '@esbuild/darwin-x64': 0.27.0 2213 | '@esbuild/freebsd-arm64': 0.27.0 2214 | '@esbuild/freebsd-x64': 0.27.0 2215 | '@esbuild/linux-arm': 0.27.0 2216 | '@esbuild/linux-arm64': 0.27.0 2217 | '@esbuild/linux-ia32': 0.27.0 2218 | '@esbuild/linux-loong64': 0.27.0 2219 | '@esbuild/linux-mips64el': 0.27.0 2220 | '@esbuild/linux-ppc64': 0.27.0 2221 | '@esbuild/linux-riscv64': 0.27.0 2222 | '@esbuild/linux-s390x': 0.27.0 2223 | '@esbuild/linux-x64': 0.27.0 2224 | '@esbuild/netbsd-arm64': 0.27.0 2225 | '@esbuild/netbsd-x64': 0.27.0 2226 | '@esbuild/openbsd-arm64': 0.27.0 2227 | '@esbuild/openbsd-x64': 0.27.0 2228 | '@esbuild/openharmony-arm64': 0.27.0 2229 | '@esbuild/sunos-x64': 0.27.0 2230 | '@esbuild/win32-arm64': 0.27.0 2231 | '@esbuild/win32-ia32': 0.27.0 2232 | '@esbuild/win32-x64': 0.27.0 2233 | 2234 | escalade@3.2.0: {} 2235 | 2236 | escape-string-regexp@4.0.0: {} 2237 | 2238 | eslint-scope@8.4.0: 2239 | dependencies: 2240 | esrecurse: 4.3.0 2241 | estraverse: 5.3.0 2242 | 2243 | eslint-visitor-keys@3.4.3: {} 2244 | 2245 | eslint-visitor-keys@4.2.1: {} 2246 | 2247 | eslint@9.39.1: 2248 | dependencies: 2249 | '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.1) 2250 | '@eslint-community/regexpp': 4.12.2 2251 | '@eslint/config-array': 0.21.1 2252 | '@eslint/config-helpers': 0.4.2 2253 | '@eslint/core': 0.17.0 2254 | '@eslint/eslintrc': 3.3.1 2255 | '@eslint/js': 9.39.1 2256 | '@eslint/plugin-kit': 0.4.1 2257 | '@humanfs/node': 0.16.7 2258 | '@humanwhocodes/module-importer': 1.0.1 2259 | '@humanwhocodes/retry': 0.4.3 2260 | '@types/estree': 1.0.8 2261 | ajv: 6.12.6 2262 | chalk: 4.1.2 2263 | cross-spawn: 7.0.6 2264 | debug: 4.4.3 2265 | escape-string-regexp: 4.0.0 2266 | eslint-scope: 8.4.0 2267 | eslint-visitor-keys: 4.2.1 2268 | espree: 10.4.0 2269 | esquery: 1.6.0 2270 | esutils: 2.0.3 2271 | fast-deep-equal: 3.1.3 2272 | file-entry-cache: 8.0.0 2273 | find-up: 5.0.0 2274 | glob-parent: 6.0.2 2275 | ignore: 5.3.2 2276 | imurmurhash: 0.1.4 2277 | is-glob: 4.0.3 2278 | json-stable-stringify-without-jsonify: 1.0.1 2279 | lodash.merge: 4.6.2 2280 | minimatch: 3.1.2 2281 | natural-compare: 1.4.0 2282 | optionator: 0.9.4 2283 | transitivePeerDependencies: 2284 | - supports-color 2285 | 2286 | espree@10.4.0: 2287 | dependencies: 2288 | acorn: 8.15.0 2289 | acorn-jsx: 5.3.2(acorn@8.15.0) 2290 | eslint-visitor-keys: 4.2.1 2291 | 2292 | esquery@1.6.0: 2293 | dependencies: 2294 | estraverse: 5.3.0 2295 | 2296 | esrecurse@4.3.0: 2297 | dependencies: 2298 | estraverse: 5.3.0 2299 | 2300 | estraverse@5.3.0: {} 2301 | 2302 | estree-walker@3.0.3: 2303 | dependencies: 2304 | '@types/estree': 1.0.8 2305 | 2306 | esutils@2.0.3: {} 2307 | 2308 | eventsource-parser@3.0.6: {} 2309 | 2310 | expect-type@1.2.2: {} 2311 | 2312 | fast-deep-equal@3.1.3: {} 2313 | 2314 | fast-json-stable-stringify@2.1.0: {} 2315 | 2316 | fast-levenshtein@2.0.6: {} 2317 | 2318 | fdir@6.5.0(picomatch@4.0.3): 2319 | optionalDependencies: 2320 | picomatch: 4.0.3 2321 | 2322 | file-entry-cache@8.0.0: 2323 | dependencies: 2324 | flat-cache: 4.0.1 2325 | 2326 | find-up@5.0.0: 2327 | dependencies: 2328 | locate-path: 6.0.0 2329 | path-exists: 4.0.0 2330 | 2331 | fix-dts-default-cjs-exports@1.0.1: 2332 | dependencies: 2333 | magic-string: 0.30.21 2334 | mlly: 1.8.0 2335 | rollup: 4.53.2 2336 | 2337 | flat-cache@4.0.1: 2338 | dependencies: 2339 | flatted: 3.3.3 2340 | keyv: 4.5.4 2341 | 2342 | flatted@3.3.3: {} 2343 | 2344 | foreground-child@3.3.1: 2345 | dependencies: 2346 | cross-spawn: 7.0.6 2347 | signal-exit: 4.1.0 2348 | 2349 | fsevents@2.3.3: 2350 | optional: true 2351 | 2352 | get-caller-file@2.0.5: {} 2353 | 2354 | glob-parent@6.0.2: 2355 | dependencies: 2356 | is-glob: 4.0.3 2357 | 2358 | glob@10.4.5: 2359 | dependencies: 2360 | foreground-child: 3.3.1 2361 | jackspeak: 3.4.3 2362 | minimatch: 9.0.5 2363 | minipass: 7.1.2 2364 | package-json-from-dist: 1.0.1 2365 | path-scurry: 1.11.1 2366 | 2367 | globals@14.0.0: {} 2368 | 2369 | graphql@16.12.0: {} 2370 | 2371 | has-flag@4.0.0: {} 2372 | 2373 | headers-polyfill@4.0.3: {} 2374 | 2375 | ignore@5.3.2: {} 2376 | 2377 | import-fresh@3.3.1: 2378 | dependencies: 2379 | parent-module: 1.0.1 2380 | resolve-from: 4.0.0 2381 | 2382 | imurmurhash@0.1.4: {} 2383 | 2384 | is-extglob@2.1.1: {} 2385 | 2386 | is-fullwidth-code-point@3.0.0: {} 2387 | 2388 | is-glob@4.0.3: 2389 | dependencies: 2390 | is-extglob: 2.1.1 2391 | 2392 | is-node-process@1.2.0: {} 2393 | 2394 | isexe@2.0.0: {} 2395 | 2396 | jackspeak@3.4.3: 2397 | dependencies: 2398 | '@isaacs/cliui': 8.0.2 2399 | optionalDependencies: 2400 | '@pkgjs/parseargs': 0.11.0 2401 | 2402 | joycon@3.1.1: {} 2403 | 2404 | js-yaml@4.1.1: 2405 | dependencies: 2406 | argparse: 2.0.1 2407 | 2408 | json-buffer@3.0.1: {} 2409 | 2410 | json-schema-traverse@0.4.1: {} 2411 | 2412 | json-schema@0.4.0: {} 2413 | 2414 | json-stable-stringify-without-jsonify@1.0.1: {} 2415 | 2416 | keyv@4.5.4: 2417 | dependencies: 2418 | json-buffer: 3.0.1 2419 | 2420 | levn@0.4.1: 2421 | dependencies: 2422 | prelude-ls: 1.2.1 2423 | type-check: 0.4.0 2424 | 2425 | lilconfig@3.1.3: {} 2426 | 2427 | lines-and-columns@1.2.4: {} 2428 | 2429 | load-tsconfig@0.2.5: {} 2430 | 2431 | locate-path@6.0.0: 2432 | dependencies: 2433 | p-locate: 5.0.0 2434 | 2435 | lodash.merge@4.6.2: {} 2436 | 2437 | lru-cache@10.4.3: {} 2438 | 2439 | magic-string@0.30.21: 2440 | dependencies: 2441 | '@jridgewell/sourcemap-codec': 1.5.5 2442 | 2443 | minimatch@3.1.2: 2444 | dependencies: 2445 | brace-expansion: 1.1.12 2446 | 2447 | minimatch@9.0.5: 2448 | dependencies: 2449 | brace-expansion: 2.0.2 2450 | 2451 | minipass@7.1.2: {} 2452 | 2453 | mlly@1.8.0: 2454 | dependencies: 2455 | acorn: 8.15.0 2456 | pathe: 2.0.3 2457 | pkg-types: 1.3.1 2458 | ufo: 1.6.1 2459 | 2460 | ms@2.1.3: {} 2461 | 2462 | msw@2.12.4(@types/node@24.10.1)(typescript@5.9.3): 2463 | dependencies: 2464 | '@inquirer/confirm': 5.1.21(@types/node@24.10.1) 2465 | '@mswjs/interceptors': 0.40.0 2466 | '@open-draft/deferred-promise': 2.2.0 2467 | '@types/statuses': 2.0.6 2468 | cookie: 1.1.1 2469 | graphql: 16.12.0 2470 | headers-polyfill: 4.0.3 2471 | is-node-process: 1.2.0 2472 | outvariant: 1.4.3 2473 | path-to-regexp: 6.3.0 2474 | picocolors: 1.1.1 2475 | rettime: 0.7.0 2476 | statuses: 2.0.2 2477 | strict-event-emitter: 0.5.1 2478 | tough-cookie: 6.0.0 2479 | type-fest: 5.3.0 2480 | until-async: 3.0.2 2481 | yargs: 17.7.2 2482 | optionalDependencies: 2483 | typescript: 5.9.3 2484 | transitivePeerDependencies: 2485 | - '@types/node' 2486 | 2487 | mute-stream@2.0.0: {} 2488 | 2489 | mz@2.7.0: 2490 | dependencies: 2491 | any-promise: 1.3.0 2492 | object-assign: 4.1.1 2493 | thenify-all: 1.6.0 2494 | 2495 | nanoid@3.3.11: {} 2496 | 2497 | natural-compare@1.4.0: {} 2498 | 2499 | object-assign@4.1.1: {} 2500 | 2501 | obug@2.1.1: {} 2502 | 2503 | optionator@0.9.4: 2504 | dependencies: 2505 | deep-is: 0.1.4 2506 | fast-levenshtein: 2.0.6 2507 | levn: 0.4.1 2508 | prelude-ls: 1.2.1 2509 | type-check: 0.4.0 2510 | word-wrap: 1.2.5 2511 | 2512 | outvariant@1.4.3: {} 2513 | 2514 | p-limit@3.1.0: 2515 | dependencies: 2516 | yocto-queue: 0.1.0 2517 | 2518 | p-locate@5.0.0: 2519 | dependencies: 2520 | p-limit: 3.1.0 2521 | 2522 | package-json-from-dist@1.0.1: {} 2523 | 2524 | parent-module@1.0.1: 2525 | dependencies: 2526 | callsites: 3.1.0 2527 | 2528 | path-exists@4.0.0: {} 2529 | 2530 | path-key@3.1.1: {} 2531 | 2532 | path-scurry@1.11.1: 2533 | dependencies: 2534 | lru-cache: 10.4.3 2535 | minipass: 7.1.2 2536 | 2537 | path-to-regexp@6.3.0: {} 2538 | 2539 | pathe@2.0.3: {} 2540 | 2541 | picocolors@1.1.1: {} 2542 | 2543 | picomatch@4.0.3: {} 2544 | 2545 | pirates@4.0.7: {} 2546 | 2547 | pkg-types@1.3.1: 2548 | dependencies: 2549 | confbox: 0.1.8 2550 | mlly: 1.8.0 2551 | pathe: 2.0.3 2552 | 2553 | postcss-load-config@6.0.1(postcss@8.5.6): 2554 | dependencies: 2555 | lilconfig: 3.1.3 2556 | optionalDependencies: 2557 | postcss: 8.5.6 2558 | 2559 | postcss@8.5.6: 2560 | dependencies: 2561 | nanoid: 3.3.11 2562 | picocolors: 1.1.1 2563 | source-map-js: 1.2.1 2564 | 2565 | prelude-ls@1.2.1: {} 2566 | 2567 | punycode@2.3.1: {} 2568 | 2569 | readdirp@4.1.2: {} 2570 | 2571 | require-directory@2.1.1: {} 2572 | 2573 | resolve-from@4.0.0: {} 2574 | 2575 | resolve-from@5.0.0: {} 2576 | 2577 | rettime@0.7.0: {} 2578 | 2579 | rollup@4.53.2: 2580 | dependencies: 2581 | '@types/estree': 1.0.8 2582 | optionalDependencies: 2583 | '@rollup/rollup-android-arm-eabi': 4.53.2 2584 | '@rollup/rollup-android-arm64': 4.53.2 2585 | '@rollup/rollup-darwin-arm64': 4.53.2 2586 | '@rollup/rollup-darwin-x64': 4.53.2 2587 | '@rollup/rollup-freebsd-arm64': 4.53.2 2588 | '@rollup/rollup-freebsd-x64': 4.53.2 2589 | '@rollup/rollup-linux-arm-gnueabihf': 4.53.2 2590 | '@rollup/rollup-linux-arm-musleabihf': 4.53.2 2591 | '@rollup/rollup-linux-arm64-gnu': 4.53.2 2592 | '@rollup/rollup-linux-arm64-musl': 4.53.2 2593 | '@rollup/rollup-linux-loong64-gnu': 4.53.2 2594 | '@rollup/rollup-linux-ppc64-gnu': 4.53.2 2595 | '@rollup/rollup-linux-riscv64-gnu': 4.53.2 2596 | '@rollup/rollup-linux-riscv64-musl': 4.53.2 2597 | '@rollup/rollup-linux-s390x-gnu': 4.53.2 2598 | '@rollup/rollup-linux-x64-gnu': 4.53.2 2599 | '@rollup/rollup-linux-x64-musl': 4.53.2 2600 | '@rollup/rollup-openharmony-arm64': 4.53.2 2601 | '@rollup/rollup-win32-arm64-msvc': 4.53.2 2602 | '@rollup/rollup-win32-ia32-msvc': 4.53.2 2603 | '@rollup/rollup-win32-x64-gnu': 4.53.2 2604 | '@rollup/rollup-win32-x64-msvc': 4.53.2 2605 | fsevents: 2.3.3 2606 | 2607 | rollup@4.53.3: 2608 | dependencies: 2609 | '@types/estree': 1.0.8 2610 | optionalDependencies: 2611 | '@rollup/rollup-android-arm-eabi': 4.53.3 2612 | '@rollup/rollup-android-arm64': 4.53.3 2613 | '@rollup/rollup-darwin-arm64': 4.53.3 2614 | '@rollup/rollup-darwin-x64': 4.53.3 2615 | '@rollup/rollup-freebsd-arm64': 4.53.3 2616 | '@rollup/rollup-freebsd-x64': 4.53.3 2617 | '@rollup/rollup-linux-arm-gnueabihf': 4.53.3 2618 | '@rollup/rollup-linux-arm-musleabihf': 4.53.3 2619 | '@rollup/rollup-linux-arm64-gnu': 4.53.3 2620 | '@rollup/rollup-linux-arm64-musl': 4.53.3 2621 | '@rollup/rollup-linux-loong64-gnu': 4.53.3 2622 | '@rollup/rollup-linux-ppc64-gnu': 4.53.3 2623 | '@rollup/rollup-linux-riscv64-gnu': 4.53.3 2624 | '@rollup/rollup-linux-riscv64-musl': 4.53.3 2625 | '@rollup/rollup-linux-s390x-gnu': 4.53.3 2626 | '@rollup/rollup-linux-x64-gnu': 4.53.3 2627 | '@rollup/rollup-linux-x64-musl': 4.53.3 2628 | '@rollup/rollup-openharmony-arm64': 4.53.3 2629 | '@rollup/rollup-win32-arm64-msvc': 4.53.3 2630 | '@rollup/rollup-win32-ia32-msvc': 4.53.3 2631 | '@rollup/rollup-win32-x64-gnu': 4.53.3 2632 | '@rollup/rollup-win32-x64-msvc': 4.53.3 2633 | fsevents: 2.3.3 2634 | 2635 | shebang-command@2.0.0: 2636 | dependencies: 2637 | shebang-regex: 3.0.0 2638 | 2639 | shebang-regex@3.0.0: {} 2640 | 2641 | siginfo@2.0.0: {} 2642 | 2643 | signal-exit@4.1.0: {} 2644 | 2645 | source-map-js@1.2.1: {} 2646 | 2647 | source-map@0.7.6: {} 2648 | 2649 | stackback@0.0.2: {} 2650 | 2651 | statuses@2.0.2: {} 2652 | 2653 | std-env@3.10.0: {} 2654 | 2655 | strict-event-emitter@0.5.1: {} 2656 | 2657 | string-width@4.2.3: 2658 | dependencies: 2659 | emoji-regex: 8.0.0 2660 | is-fullwidth-code-point: 3.0.0 2661 | strip-ansi: 6.0.1 2662 | 2663 | string-width@5.1.2: 2664 | dependencies: 2665 | eastasianwidth: 0.2.0 2666 | emoji-regex: 9.2.2 2667 | strip-ansi: 7.1.2 2668 | 2669 | strip-ansi@6.0.1: 2670 | dependencies: 2671 | ansi-regex: 5.0.1 2672 | 2673 | strip-ansi@7.1.2: 2674 | dependencies: 2675 | ansi-regex: 6.2.2 2676 | 2677 | strip-json-comments@3.1.1: {} 2678 | 2679 | sucrase@3.35.0: 2680 | dependencies: 2681 | '@jridgewell/gen-mapping': 0.3.13 2682 | commander: 4.1.1 2683 | glob: 10.4.5 2684 | lines-and-columns: 1.2.4 2685 | mz: 2.7.0 2686 | pirates: 4.0.7 2687 | ts-interface-checker: 0.1.13 2688 | 2689 | supports-color@7.2.0: 2690 | dependencies: 2691 | has-flag: 4.0.0 2692 | 2693 | tagged-tag@1.0.0: {} 2694 | 2695 | thenify-all@1.6.0: 2696 | dependencies: 2697 | thenify: 3.3.1 2698 | 2699 | thenify@3.3.1: 2700 | dependencies: 2701 | any-promise: 1.3.0 2702 | 2703 | tinybench@2.9.0: {} 2704 | 2705 | tinyexec@0.3.2: {} 2706 | 2707 | tinyexec@1.0.2: {} 2708 | 2709 | tinyglobby@0.2.15: 2710 | dependencies: 2711 | fdir: 6.5.0(picomatch@4.0.3) 2712 | picomatch: 4.0.3 2713 | 2714 | tinyrainbow@3.0.3: {} 2715 | 2716 | tldts-core@7.0.19: {} 2717 | 2718 | tldts@7.0.19: 2719 | dependencies: 2720 | tldts-core: 7.0.19 2721 | 2722 | tough-cookie@6.0.0: 2723 | dependencies: 2724 | tldts: 7.0.19 2725 | 2726 | tree-kill@1.2.2: {} 2727 | 2728 | ts-interface-checker@0.1.13: {} 2729 | 2730 | tsup@8.5.1(postcss@8.5.6)(typescript@5.9.3): 2731 | dependencies: 2732 | bundle-require: 5.1.0(esbuild@0.27.0) 2733 | cac: 6.7.14 2734 | chokidar: 4.0.3 2735 | consola: 3.4.2 2736 | debug: 4.4.3 2737 | esbuild: 0.27.0 2738 | fix-dts-default-cjs-exports: 1.0.1 2739 | joycon: 3.1.1 2740 | picocolors: 1.1.1 2741 | postcss-load-config: 6.0.1(postcss@8.5.6) 2742 | resolve-from: 5.0.0 2743 | rollup: 4.53.2 2744 | source-map: 0.7.6 2745 | sucrase: 3.35.0 2746 | tinyexec: 0.3.2 2747 | tinyglobby: 0.2.15 2748 | tree-kill: 1.2.2 2749 | optionalDependencies: 2750 | postcss: 8.5.6 2751 | typescript: 5.9.3 2752 | transitivePeerDependencies: 2753 | - jiti 2754 | - supports-color 2755 | - tsx 2756 | - yaml 2757 | 2758 | type-check@0.4.0: 2759 | dependencies: 2760 | prelude-ls: 1.2.1 2761 | 2762 | type-fest@5.3.0: 2763 | dependencies: 2764 | tagged-tag: 1.0.0 2765 | 2766 | typescript@5.9.3: {} 2767 | 2768 | ufo@1.6.1: {} 2769 | 2770 | undici-types@7.16.0: {} 2771 | 2772 | until-async@3.0.2: {} 2773 | 2774 | uri-js@4.4.1: 2775 | dependencies: 2776 | punycode: 2.3.1 2777 | 2778 | vite@7.2.4(@types/node@24.10.1): 2779 | dependencies: 2780 | esbuild: 0.25.12 2781 | fdir: 6.5.0(picomatch@4.0.3) 2782 | picomatch: 4.0.3 2783 | postcss: 8.5.6 2784 | rollup: 4.53.3 2785 | tinyglobby: 0.2.15 2786 | optionalDependencies: 2787 | '@types/node': 24.10.1 2788 | fsevents: 2.3.3 2789 | 2790 | vitest@4.0.15(@edge-runtime/vm@5.0.0)(@types/node@24.10.1)(msw@2.12.4(@types/node@24.10.1)(typescript@5.9.3)): 2791 | dependencies: 2792 | '@vitest/expect': 4.0.15 2793 | '@vitest/mocker': 4.0.15(msw@2.12.4(@types/node@24.10.1)(typescript@5.9.3))(vite@7.2.4(@types/node@24.10.1)) 2794 | '@vitest/pretty-format': 4.0.15 2795 | '@vitest/runner': 4.0.15 2796 | '@vitest/snapshot': 4.0.15 2797 | '@vitest/spy': 4.0.15 2798 | '@vitest/utils': 4.0.15 2799 | es-module-lexer: 1.7.0 2800 | expect-type: 1.2.2 2801 | magic-string: 0.30.21 2802 | obug: 2.1.1 2803 | pathe: 2.0.3 2804 | picomatch: 4.0.3 2805 | std-env: 3.10.0 2806 | tinybench: 2.9.0 2807 | tinyexec: 1.0.2 2808 | tinyglobby: 0.2.15 2809 | tinyrainbow: 3.0.3 2810 | vite: 7.2.4(@types/node@24.10.1) 2811 | why-is-node-running: 2.3.0 2812 | optionalDependencies: 2813 | '@edge-runtime/vm': 5.0.0 2814 | '@types/node': 24.10.1 2815 | transitivePeerDependencies: 2816 | - jiti 2817 | - less 2818 | - lightningcss 2819 | - msw 2820 | - sass 2821 | - sass-embedded 2822 | - stylus 2823 | - sugarss 2824 | - terser 2825 | - tsx 2826 | - yaml 2827 | 2828 | which@2.0.2: 2829 | dependencies: 2830 | isexe: 2.0.0 2831 | 2832 | why-is-node-running@2.3.0: 2833 | dependencies: 2834 | siginfo: 2.0.0 2835 | stackback: 0.0.2 2836 | 2837 | word-wrap@1.2.5: {} 2838 | 2839 | wrap-ansi@6.2.0: 2840 | dependencies: 2841 | ansi-styles: 4.3.0 2842 | string-width: 4.2.3 2843 | strip-ansi: 6.0.1 2844 | 2845 | wrap-ansi@7.0.0: 2846 | dependencies: 2847 | ansi-styles: 4.3.0 2848 | string-width: 4.2.3 2849 | strip-ansi: 6.0.1 2850 | 2851 | wrap-ansi@8.1.0: 2852 | dependencies: 2853 | ansi-styles: 6.2.3 2854 | string-width: 5.1.2 2855 | strip-ansi: 7.1.2 2856 | 2857 | y18n@5.0.8: {} 2858 | 2859 | yargs-parser@21.1.1: {} 2860 | 2861 | yargs@17.7.2: 2862 | dependencies: 2863 | cliui: 8.0.1 2864 | escalade: 3.2.0 2865 | get-caller-file: 2.0.5 2866 | require-directory: 2.1.1 2867 | string-width: 4.2.3 2868 | y18n: 5.0.8 2869 | yargs-parser: 21.1.1 2870 | 2871 | yocto-queue@0.1.0: {} 2872 | 2873 | yoctocolors-cjs@2.1.3: {} 2874 | 2875 | zod@4.1.13: {} 2876 | --------------------------------------------------------------------------------