diff --git a/.env.example b/.env.example index 9bec51ec64..b724838845 100644 --- a/.env.example +++ b/.env.example @@ -12,6 +12,14 @@ # Get your API key from: https://console.anthropic.com/ ANTHROPIC_API_KEY=your_anthropic_api_key_here +# Cerebras (High-performance inference) +# Get your API key from: https://cloud.cerebras.ai/settings +CEREBRAS_API_KEY=your_cerebras_api_key_here + +# Fireworks AI (Fast inference with FireAttention engine) +# Get your API key from: https://fireworks.ai/api-keys +FIREWORKS_API_KEY=your_fireworks_api_key_here + # OpenAI GPT models # Get your API key from: https://platform.openai.com/api-keys OPENAI_API_KEY=your_openai_api_key_here @@ -59,6 +67,10 @@ XAI_API_KEY=your_xai_api_key_here # Get your API key from: https://platform.moonshot.ai/console/api-keys MOONSHOT_API_KEY=your_moonshot_api_key_here +# Z.AI (GLM models with JWT authentication) +# Get your API key from: https://open.bigmodel.cn/usercenter/apikeys +ZAI_API_KEY=your_zai_api_key_here + # Hugging Face # Get your API key from: https://huggingface.co/settings/tokens HuggingFace_API_KEY=your_huggingface_api_key_here diff --git a/app/components/chat/ModelSelector.tsx b/app/components/chat/ModelSelector.tsx index 2ccb9a5277..c69331fcf4 100644 --- a/app/components/chat/ModelSelector.tsx +++ b/app/components/chat/ModelSelector.tsx @@ -3,6 +3,7 @@ import { useEffect, useState, useRef, useMemo, useCallback } from 'react'; import type { KeyboardEvent } from 'react'; import type { ModelInfo } from '~/lib/modules/llm/types'; import { classNames } from '~/utils/classNames'; +import { LOCAL_PROVIDERS } from '~/lib/stores/settings'; // Fuzzy search utilities const levenshteinDistance = (str1: string, str2: string): number => { @@ -130,6 +131,32 @@ export const ModelSelector = ({ const providerDropdownRef = useRef(null); const [showFreeModelsOnly, setShowFreeModelsOnly] = useState(false); + type ConnectionStatus = 'unknown' | 'connected' | 'disconnected'; + + const [localProviderStatus, setLocalProviderStatus] = useState>({}); + + // Check connectivity of local providers when provider list changes + useEffect(() => { + const checkLocalProviders = async () => { + const statuses: Record = {}; + + for (const p of providerList) { + if (!LOCAL_PROVIDERS.includes(p.name)) { + continue; + } + + // If the provider has models loaded, it's connected + const hasModels = modelList.some((m) => m.provider === p.name); + + statuses[p.name] = hasModels ? 'connected' : 'disconnected'; + } + + setLocalProviderStatus(statuses); + }; + + checkLocalProviders(); + }, [providerList, modelList]); + // Debounce search queries useEffect(() => { const timer = setTimeout(() => { @@ -440,7 +467,28 @@ export const ModelSelector = ({ tabIndex={0} >
-
{provider?.name || 'Select provider'}
+
+ {provider?.name && LOCAL_PROVIDERS.includes(provider.name) && ( + + )} + {provider?.name || 'Select provider'} +
-
+
+ {LOCAL_PROVIDERS.includes(providerOption.name) && ( + + )} + +
)) )} @@ -717,8 +779,17 @@ export const ModelSelector = ({ ? `No models match "${debouncedModelSearchQuery}"${showFreeModelsOnly ? ' (free only)' : ''}` : showFreeModelsOnly ? 'No free models available' - : 'No models available'} + : provider?.name && LOCAL_PROVIDERS.includes(provider.name) + ? `No models found — is ${provider.name} running?` + : 'No models available'}
+ {!debouncedModelSearchQuery && provider?.name && LOCAL_PROVIDERS.includes(provider.name) && ( +
+ Make sure {provider.name} is running and has at least one model loaded. + {provider.name === 'Ollama' && ' Try: ollama pull llama3.2'} + {provider.name === 'LMStudio' && ' Load a model in LM Studio first.'} +
+ )} {debouncedModelSearchQuery && (
Try searching for model names, context sizes (e.g., "128k", "1M"), or capabilities diff --git a/app/lib/modules/llm/base-provider.ts b/app/lib/modules/llm/base-provider.ts index 9cb23403d7..ada2f3a4d2 100644 --- a/app/lib/modules/llm/base-provider.ts +++ b/app/lib/modules/llm/base-provider.ts @@ -4,6 +4,9 @@ import type { IProviderSetting } from '~/types/model'; import { createOpenAI } from '@ai-sdk/openai'; import { LLMManager } from './manager'; +/** Default timeout for model listing API calls (5 seconds) */ +const MODEL_FETCH_TIMEOUT = 5_000; + export abstract class BaseProvider implements ProviderInfo { abstract name: string; abstract staticModels: ModelInfo[]; @@ -17,6 +20,48 @@ export abstract class BaseProvider implements ProviderInfo { labelForGetApiKey?: string; icon?: string; + /** + * Convert Cloudflare Env bindings to a plain Record. + * Useful because provider methods expect Record but + * Cloudflare Workers pass an Env interface. + */ + protected convertEnvToRecord(env?: Env): Record { + if (!env) { + return {}; + } + + return Object.entries(env).reduce( + (acc, [key, value]) => { + acc[key] = String(value); + + return acc; + }, + {} as Record, + ); + } + + /** + * Rewrite localhost / 127.0.0.1 URLs to host.docker.internal when + * running inside Docker. Only applies on the server side. + */ + protected resolveDockerUrl(baseUrl: string, serverEnv?: Record): string { + const isDocker = process?.env?.RUNNING_IN_DOCKER === 'true' || serverEnv?.RUNNING_IN_DOCKER === 'true'; + + if (!isDocker) { + return baseUrl; + } + + return baseUrl.replace('localhost', 'host.docker.internal').replace('127.0.0.1', 'host.docker.internal'); + } + + /** + * Create an AbortSignal that times out after the given milliseconds. + * Used to prevent model-listing fetches from hanging indefinitely. + */ + protected createTimeoutSignal(ms: number = MODEL_FETCH_TIMEOUT): AbortSignal { + return AbortSignal.timeout(ms); + } + getProviderBaseUrlAndKey(options: { apiKeys?: Record; providerSettings?: IProviderSetting; @@ -59,7 +104,6 @@ export abstract class BaseProvider implements ProviderInfo { serverEnv?: Record; }): ModelInfo[] | null { if (!this.cachedDynamicModels) { - // console.log('no dynamic models',this.name); return null; } @@ -67,8 +111,8 @@ export abstract class BaseProvider implements ProviderInfo { const generatedCacheKey = this.getDynamicModelsCacheKey(options); if (cacheKey !== generatedCacheKey) { - // console.log('cache key mismatch',this.name,cacheKey,generatedCacheKey); this.cachedDynamicModels = undefined; + return null; } @@ -79,10 +123,20 @@ export abstract class BaseProvider implements ProviderInfo { providerSettings?: Record; serverEnv?: Record; }) { + // Only include provider-relevant env keys, not the entire server environment + const relevantEnvKeys = [this.config.baseUrlKey, this.config.apiTokenKey].filter(Boolean) as string[]; + const relevantEnv: Record = {}; + + for (const key of relevantEnvKeys) { + if (options.serverEnv?.[key]) { + relevantEnv[key] = options.serverEnv[key]; + } + } + return JSON.stringify({ apiKeys: options.apiKeys?.[this.name], providerSettings: options.providerSettings?.[this.name], - serverEnv: options.serverEnv, + serverEnv: relevantEnv, }); } storeDynamicModels( @@ -95,7 +149,6 @@ export abstract class BaseProvider implements ProviderInfo { ) { const cacheId = this.getDynamicModelsCacheKey(options); - // console.log('caching dynamic models',this.name,cacheId); this.cachedDynamicModels = { cacheId, models, diff --git a/app/lib/modules/llm/manager.ts b/app/lib/modules/llm/manager.ts index aec9190593..687c399ccf 100644 --- a/app/lib/modules/llm/manager.ts +++ b/app/lib/modules/llm/manager.ts @@ -9,7 +9,7 @@ export class LLMManager { private static _instance: LLMManager; private _providers: Map = new Map(); private _modelList: ModelInfo[] = []; - private readonly _env: any = {}; + private _env: Record = {}; private constructor(_env: Record) { this._registerProvidersFromDirectory(); @@ -19,6 +19,9 @@ export class LLMManager { static getInstance(env: Record = {}): LLMManager { if (!LLMManager._instance) { LLMManager._instance = new LLMManager(env); + } else if (Object.keys(env).length > 0) { + // Update env on subsequent calls so Cloudflare Workers get fresh bindings + LLMManager._instance._env = env; } return LLMManager._instance; @@ -121,10 +124,10 @@ export class LLMManager { const staticModels = Array.from(this._providers.values()).flatMap((p) => p.staticModels || []); const dynamicModelsFlat = dynamicModels.flat(); const dynamicModelKeys = dynamicModelsFlat.map((d) => `${d.name}-${d.provider}`); - const filteredStaticModesl = staticModels.filter((m) => !dynamicModelKeys.includes(`${m.name}-${m.provider}`)); + const filteredStaticModels = staticModels.filter((m) => !dynamicModelKeys.includes(`${m.name}-${m.provider}`)); // Combine static and dynamic models - const modelList = [...dynamicModelsFlat, ...filteredStaticModesl]; + const modelList = [...dynamicModelsFlat, ...filteredStaticModels]; modelList.sort((a, b) => a.name.localeCompare(b.name)); this._modelList = modelList; diff --git a/app/lib/modules/llm/providers/cerebras.ts b/app/lib/modules/llm/providers/cerebras.ts new file mode 100644 index 0000000000..3ac15d0eab --- /dev/null +++ b/app/lib/modules/llm/providers/cerebras.ts @@ -0,0 +1,137 @@ +import { BaseProvider } from '~/lib/modules/llm/base-provider'; +import type { ModelInfo } from '~/lib/modules/llm/types'; +import type { IProviderSetting } from '~/types/model'; +import type { LanguageModelV1 } from 'ai'; +import { createCerebras } from '@ai-sdk/cerebras'; + +export default class CerebrasProvider extends BaseProvider { + name = 'Cerebras'; + getApiKeyLink = 'https://cloud.cerebras.ai/settings'; + + config = { + apiTokenKey: 'CEREBRAS_API_KEY', + }; + + staticModels: ModelInfo[] = [ + { + name: 'qwen3-coder-480b', + label: 'Qwen3-Coder 480B (2000 tok/s, Best for Coding)', + provider: 'Cerebras', + maxTokenAllowed: 262000, + }, + { + name: 'llama3.1-8b', + label: 'Llama 3.1 8B', + provider: 'Cerebras', + maxTokenAllowed: 8000, + }, + { + name: 'gpt-oss-120b', + label: 'GPT OSS 120B (Reasoning)', + provider: 'Cerebras', + maxTokenAllowed: 8000, + }, + { + name: 'qwen-3-235b-a22b-instruct-2507', + label: 'Qwen 3 235B A22B Instruct', + provider: 'Cerebras', + maxTokenAllowed: 8000, + }, + { + name: 'qwen-3-235b-a22b-thinking-2507', + label: 'Qwen 3 235B A22B Thinking', + provider: 'Cerebras', + maxTokenAllowed: 8000, + }, + { + name: 'zai-glm-4.6', + label: 'ZAI GLM 4.6 (Coding: 73.8% SWE-bench)', + provider: 'Cerebras', + maxTokenAllowed: 8000, + }, + { + name: 'zai-glm-4.7', + label: 'ZAI GLM 4.7 (Reasoning)', + provider: 'Cerebras', + maxTokenAllowed: 8000, + }, + ]; + + async getDynamicModels( + apiKeys?: Record, + settings?: IProviderSetting, + serverEnv?: Record, + ): Promise { + const { apiKey } = this.getProviderBaseUrlAndKey({ + apiKeys, + providerSettings: settings, + serverEnv: serverEnv as any, + defaultBaseUrlKey: '', + defaultApiTokenKey: 'CEREBRAS_API_KEY', + }); + + if (!apiKey) { + return []; + } + + try { + const response = await fetch('https://api.cerebras.ai/v1/models', { + headers: { + Authorization: `Bearer ${apiKey}`, + }, + signal: this.createTimeoutSignal(5000), + }); + + if (!response.ok) { + console.error(`Cerebras API error: ${response.statusText}`); + return []; + } + + const data = (await response.json()) as any; + const staticModelIds = this.staticModels.map((m) => m.name); + + // Filter out models we already have in staticModels + const dynamicModels = + data.data + ?.filter((model: any) => !staticModelIds.includes(model.id)) + .map((m: any) => ({ + name: m.id, + label: `${m.id} (Dynamic)`, + provider: this.name, + maxTokenAllowed: 32000, // Default, Cerebras typically has good context + })) || []; + + return dynamicModels; + } catch (error) { + console.error(`Failed to fetch Cerebras models:`, error); + return []; + } + } + + getModelInstance(options: { + model: string; + serverEnv: Env; + apiKeys?: Record; + providerSettings?: Record; + }): LanguageModelV1 { + const { model, serverEnv, apiKeys, providerSettings } = options; + + const { apiKey } = this.getProviderBaseUrlAndKey({ + apiKeys, + providerSettings: providerSettings?.[this.name], + serverEnv: serverEnv as any, + defaultBaseUrlKey: '', + defaultApiTokenKey: 'CEREBRAS_API_KEY', + }); + + if (!apiKey) { + throw new Error(`Missing API key for ${this.name} provider`); + } + + const cerebras = createCerebras({ + apiKey, + }); + + return cerebras(model); + } +} diff --git a/app/lib/modules/llm/providers/deepseek.ts b/app/lib/modules/llm/providers/deepseek.ts index 7c9042d7cd..2acc4fda44 100644 --- a/app/lib/modules/llm/providers/deepseek.ts +++ b/app/lib/modules/llm/providers/deepseek.ts @@ -34,8 +34,74 @@ export default class DeepseekProvider extends BaseProvider { maxTokenAllowed: 8000, maxCompletionTokens: 8192, }, + { + name: 'deepseek-v3.2', + label: 'DeepSeek V3.2 (Coding + Tool Use)', + provider: 'Deepseek', + maxTokenAllowed: 64000, + maxCompletionTokens: 8192, + }, + { + name: 'deepseek-v3.2-speciale', + label: 'DeepSeek V3.2 Speciale (High-Compute)', + provider: 'Deepseek', + maxTokenAllowed: 64000, + maxCompletionTokens: 8192, + }, ]; + async getDynamicModels( + apiKeys?: Record, + settings?: IProviderSetting, + serverEnv?: Record, + ): Promise { + const { apiKey } = this.getProviderBaseUrlAndKey({ + apiKeys, + providerSettings: settings, + serverEnv: serverEnv as any, + defaultBaseUrlKey: '', + defaultApiTokenKey: 'DEEPSEEK_API_KEY', + }); + + if (!apiKey) { + return []; + } + + try { + const response = await fetch('https://api.deepseek.com/models', { + headers: { + Authorization: `Bearer ${apiKey}`, + }, + signal: this.createTimeoutSignal(5000), + }); + + if (!response.ok) { + console.error(`DeepSeek API error: ${response.statusText}`); + return []; + } + + const data = (await response.json()) as any; + const staticModelIds = this.staticModels.map((m) => m.name); + + // Filter out models we already have in staticModels + const dynamicModels = + data.data + ?.filter((model: any) => !staticModelIds.includes(model.id)) + .map((m: any) => ({ + name: m.id, + label: `${m.id} (Dynamic)`, + provider: this.name, + maxTokenAllowed: 64000, // Default, adjust per model if available + maxCompletionTokens: 8192, + })) || []; + + return dynamicModels; + } catch (error) { + console.error(`Failed to fetch DeepSeek models:`, error); + return []; + } + } + getModelInstance(options: { model: string; serverEnv: Env; diff --git a/app/lib/modules/llm/providers/fireworks.ts b/app/lib/modules/llm/providers/fireworks.ts new file mode 100644 index 0000000000..7dfa8bdf80 --- /dev/null +++ b/app/lib/modules/llm/providers/fireworks.ts @@ -0,0 +1,147 @@ +import { BaseProvider } from '~/lib/modules/llm/base-provider'; +import type { ModelInfo } from '~/lib/modules/llm/types'; +import type { IProviderSetting } from '~/types/model'; +import type { LanguageModelV1 } from 'ai'; +import { createFireworks } from '@ai-sdk/fireworks'; + +export default class FireworksProvider extends BaseProvider { + name = 'Fireworks'; + getApiKeyLink = 'https://fireworks.ai/api-keys'; + + config = { + apiTokenKey: 'FIREWORKS_API_KEY', + }; + + staticModels: ModelInfo[] = [ + { + name: 'accounts/fireworks/models/qwen3-coder-480b-a35b-instruct', + label: 'Qwen3-Coder 480B (Best for Coding)', + provider: 'Fireworks', + maxTokenAllowed: 262000, + }, + { + name: 'accounts/fireworks/models/qwen3-coder-30b-a3b-instruct', + label: 'Qwen3-Coder 30B (Fast Coding)', + provider: 'Fireworks', + maxTokenAllowed: 262000, + }, + { + name: 'accounts/fireworks/models/llama-v3p1-405b-instruct', + label: 'Llama 3.1 405B Instruct', + provider: 'Fireworks', + maxTokenAllowed: 128000, + }, + { + name: 'accounts/fireworks/models/llama-v3p1-70b-instruct', + label: 'Llama 3.1 70B Instruct', + provider: 'Fireworks', + maxTokenAllowed: 128000, + }, + { + name: 'accounts/fireworks/models/llama-v3p1-8b-instruct', + label: 'Llama 3.1 8B Instruct', + provider: 'Fireworks', + maxTokenAllowed: 128000, + }, + { + name: 'accounts/fireworks/models/deepseek-r1', + label: 'DeepSeek R1 (Reasoning)', + provider: 'Fireworks', + maxTokenAllowed: 64000, + }, + { + name: 'accounts/fireworks/models/qwen2p5-72b-instruct', + label: 'Qwen 2.5 72B Instruct', + provider: 'Fireworks', + maxTokenAllowed: 128000, + }, + { + name: 'accounts/fireworks/models/firefunction-v2', + label: 'FireFunction V2', + provider: 'Fireworks', + maxTokenAllowed: 8000, + }, + ]; + + async getDynamicModels( + apiKeys?: Record, + settings?: IProviderSetting, + serverEnv?: Record, + ): Promise { + const { apiKey } = this.getProviderBaseUrlAndKey({ + apiKeys, + providerSettings: settings, + serverEnv: serverEnv as any, + defaultBaseUrlKey: '', + defaultApiTokenKey: 'FIREWORKS_API_KEY', + }); + + if (!apiKey) { + return []; + } + + try { + // Try the accounts/fireworks/models endpoint which lists public models + const response = await fetch('https://api.fireworks.ai/v1/accounts/fireworks/models?page_size=100', { + headers: { + Authorization: `Bearer ${apiKey}`, + }, + signal: this.createTimeoutSignal(5000), + }); + + if (!response.ok) { + console.error(`Fireworks API error: ${response.statusText}`); + return []; + } + + const data = (await response.json()) as any; + const staticModelIds = this.staticModels.map((m) => m.name); + + // Filter out models we already have in staticModels + const dynamicModels = + data.data + ?.filter((model: any) => { + const modelPath = `accounts/fireworks/models/${model.id}`; + return !staticModelIds.includes(modelPath) && !staticModelIds.includes(model.id); + }) + .map((m: any) => ({ + name: `accounts/fireworks/models/${m.id}`, + label: `${m.id} (Dynamic)`, + provider: this.name, + maxTokenAllowed: m.context_length || 128000, + })) || []; + + return dynamicModels; + } catch (error) { + console.error(`Failed to fetch Fireworks models:`, error); + return []; + } + } + + getModelInstance(options: { + model: string; + serverEnv: Env; + apiKeys?: Record; + providerSettings?: Record; + }): LanguageModelV1 { + const { model, serverEnv, apiKeys, providerSettings } = options; + + const { apiKey } = this.getProviderBaseUrlAndKey({ + apiKeys, + providerSettings: providerSettings?.[this.name], + serverEnv: serverEnv as any, + defaultBaseUrlKey: '', + defaultApiTokenKey: 'FIREWORKS_API_KEY', + }); + + if (!apiKey) { + throw new Error(`Missing API key for ${this.name} provider`); + } + + const fireworks = createFireworks({ + apiKey, + }); + + return fireworks(model); + } +} diff --git a/app/lib/modules/llm/providers/lmstudio.ts b/app/lib/modules/llm/providers/lmstudio.ts index fe5b27cd4a..e7f6793eb9 100644 --- a/app/lib/modules/llm/providers/lmstudio.ts +++ b/app/lib/modules/llm/providers/lmstudio.ts @@ -18,11 +18,11 @@ export default class LMStudioProvider extends BaseProvider { staticModels: ModelInfo[] = []; - async getDynamicModels( + private _resolveBaseUrl( apiKeys?: Record, settings?: IProviderSetting, - serverEnv: Record = {}, - ): Promise { + serverEnv?: Record, + ): string { let { baseUrl } = this.getProviderBaseUrlAndKey({ apiKeys, providerSettings: settings, @@ -35,27 +35,54 @@ export default class LMStudioProvider extends BaseProvider { throw new Error('No baseUrl found for LMStudio provider'); } - if (typeof window === 'undefined') { - /* - * Running in Server - * Backend: Check if we're running in Docker - */ - const isDocker = process?.env?.RUNNING_IN_DOCKER === 'true' || serverEnv?.RUNNING_IN_DOCKER === 'true'; + baseUrl = this.resolveDockerUrl(baseUrl, serverEnv); - baseUrl = isDocker ? baseUrl.replace('localhost', 'host.docker.internal') : baseUrl; - baseUrl = isDocker ? baseUrl.replace('127.0.0.1', 'host.docker.internal') : baseUrl; - } + return baseUrl; + } + + async getDynamicModels( + apiKeys?: Record, + settings?: IProviderSetting, + serverEnv: Record = {}, + ): Promise { + const baseUrl = this._resolveBaseUrl(apiKeys, settings, serverEnv); + + try { + const response = await fetch(`${baseUrl}/v1/models`, { + signal: this.createTimeoutSignal(), + }); + + if (!response.ok) { + throw new Error(`HTTP ${response.status}: ${response.statusText}`); + } + + const data = (await response.json()) as { data: Array<{ id: string }> }; + + return data.data.map((model) => ({ + name: model.id, + label: model.id, + provider: this.name, + maxTokenAllowed: 8000, + })); + } catch (error) { + if (error instanceof DOMException && error.name === 'TimeoutError') { + logger.warn('LMStudio model fetch timed out — is LM Studio running?'); + + return []; + } - const response = await fetch(`${baseUrl}/v1/models`); - const data = (await response.json()) as { data: Array<{ id: string }> }; + if (error instanceof TypeError && error.message.includes('fetch')) { + logger.warn(`LMStudio not reachable at ${baseUrl} — is LM Studio running?`); - return data.data.map((model) => ({ - name: model.id, - label: model.id, - provider: this.name, - maxTokenAllowed: 8000, - })); + return []; + } + + logger.error('Error fetching LMStudio models:', error); + + return []; + } } + getModelInstance: (options: { model: string; serverEnv?: Env; @@ -63,24 +90,9 @@ export default class LMStudioProvider extends BaseProvider { providerSettings?: Record; }) => LanguageModelV1 = (options) => { const { apiKeys, providerSettings, serverEnv, model } = options; - let { baseUrl } = this.getProviderBaseUrlAndKey({ - apiKeys, - providerSettings: providerSettings?.[this.name], - serverEnv: serverEnv as any, - defaultBaseUrlKey: 'LMSTUDIO_API_BASE_URL', - defaultApiTokenKey: '', - }); + const envRecord = this.convertEnvToRecord(serverEnv); - if (!baseUrl) { - throw new Error('No baseUrl found for LMStudio provider'); - } - - const isDocker = process?.env?.RUNNING_IN_DOCKER === 'true' || serverEnv?.RUNNING_IN_DOCKER === 'true'; - - if (typeof window === 'undefined') { - baseUrl = isDocker ? baseUrl.replace('localhost', 'host.docker.internal') : baseUrl; - baseUrl = isDocker ? baseUrl.replace('127.0.0.1', 'host.docker.internal') : baseUrl; - } + const baseUrl = this._resolveBaseUrl(apiKeys, providerSettings?.[this.name], envRecord); logger.debug('LMStudio Base Url used: ', baseUrl); diff --git a/app/lib/modules/llm/providers/moonshot.ts b/app/lib/modules/llm/providers/moonshot.ts index a59f80e225..2417d43e0b 100644 --- a/app/lib/modules/llm/providers/moonshot.ts +++ b/app/lib/modules/llm/providers/moonshot.ts @@ -41,6 +41,57 @@ export default class MoonshotProvider extends BaseProvider { { name: 'kimi-thinking-preview', label: 'Kimi Thinking', provider: 'Moonshot', maxTokenAllowed: 128000 }, ]; + async getDynamicModels( + apiKeys?: Record, + settings?: IProviderSetting, + serverEnv?: Record, + ): Promise { + const { apiKey } = this.getProviderBaseUrlAndKey({ + apiKeys, + providerSettings: settings, + serverEnv: serverEnv as any, + defaultBaseUrlKey: '', + defaultApiTokenKey: 'MOONSHOT_API_KEY', + }); + + if (!apiKey) { + return []; + } + + try { + const response = await fetch('https://api.moonshot.ai/v1/models', { + headers: { + Authorization: `Bearer ${apiKey}`, + }, + signal: this.createTimeoutSignal(5000), + }); + + if (!response.ok) { + console.error(`Moonshot API error: ${response.statusText}`); + return []; + } + + const data = (await response.json()) as any; + const staticModelIds = this.staticModels.map((m) => m.name); + + // Filter out models we already have in staticModels + const dynamicModels = + data.data + ?.filter((model: any) => !staticModelIds.includes(model.id)) + .map((m: any) => ({ + name: m.id, + label: `${m.id} (Dynamic)`, + provider: this.name, + maxTokenAllowed: 128000, // Kimi models typically have large context + })) || []; + + return dynamicModels; + } catch (error) { + console.error(`Failed to fetch Moonshot models:`, error); + return []; + } + } + getModelInstance(options: { model: string; serverEnv: Env; diff --git a/app/lib/modules/llm/providers/ollama.ts b/app/lib/modules/llm/providers/ollama.ts index e50ecae561..3d7f53b8ee 100644 --- a/app/lib/modules/llm/providers/ollama.ts +++ b/app/lib/modules/llm/providers/ollama.ts @@ -2,7 +2,7 @@ import { BaseProvider } from '~/lib/modules/llm/base-provider'; import type { ModelInfo } from '~/lib/modules/llm/types'; import type { IProviderSetting } from '~/types/model'; import type { LanguageModelV1 } from 'ai'; -import { ollama } from 'ollama-ai-provider'; +import { createOllama } from 'ollama-ai-provider'; import { logger } from '~/utils/logger'; interface OllamaModelDetails { @@ -39,31 +39,17 @@ export default class OllamaProvider extends BaseProvider { staticModels: ModelInfo[] = []; - private _convertEnvToRecord(env?: Env): Record { - if (!env) { - return {}; - } - - // Convert Env to a plain object with string values - return Object.entries(env).reduce( - (acc, [key, value]) => { - acc[key] = String(value); - return acc; - }, - {} as Record, - ); - } - getDefaultNumCtx(serverEnv?: Env): number { - const envRecord = this._convertEnvToRecord(serverEnv); + const envRecord = this.convertEnvToRecord(serverEnv); + return envRecord.DEFAULT_NUM_CTX ? parseInt(envRecord.DEFAULT_NUM_CTX, 10) : 32768; } - async getDynamicModels( + private _resolveBaseUrl( apiKeys?: Record, settings?: IProviderSetting, - serverEnv: Record = {}, - ): Promise { + serverEnv?: Record, + ): string { let { baseUrl } = this.getProviderBaseUrlAndKey({ apiKeys, providerSettings: settings, @@ -73,31 +59,55 @@ export default class OllamaProvider extends BaseProvider { }); if (!baseUrl) { - throw new Error('No baseUrl found for OLLAMA provider'); + throw new Error('No baseUrl found for Ollama provider'); } - if (typeof window === 'undefined') { - /* - * Running in Server - * Backend: Check if we're running in Docker - */ - const isDocker = process?.env?.RUNNING_IN_DOCKER === 'true' || serverEnv?.RUNNING_IN_DOCKER === 'true'; + baseUrl = this.resolveDockerUrl(baseUrl, serverEnv); - baseUrl = isDocker ? baseUrl.replace('localhost', 'host.docker.internal') : baseUrl; - baseUrl = isDocker ? baseUrl.replace('127.0.0.1', 'host.docker.internal') : baseUrl; - } + return baseUrl; + } + + async getDynamicModels( + apiKeys?: Record, + settings?: IProviderSetting, + serverEnv: Record = {}, + ): Promise { + const baseUrl = this._resolveBaseUrl(apiKeys, settings, serverEnv); + + try { + const response = await fetch(`${baseUrl}/api/tags`, { + signal: this.createTimeoutSignal(), + }); + + if (!response.ok) { + throw new Error(`HTTP ${response.status}: ${response.statusText}`); + } + + const data = (await response.json()) as OllamaApiResponse; - const response = await fetch(`${baseUrl}/api/tags`); - const data = (await response.json()) as OllamaApiResponse; + return data.models.map((model: OllamaModel) => ({ + name: model.name, + label: `${model.name} (${model.details.parameter_size})`, + provider: this.name, + maxTokenAllowed: 8000, + })); + } catch (error) { + if (error instanceof DOMException && error.name === 'TimeoutError') { + logger.warn('Ollama model fetch timed out — is Ollama running?'); - // console.log({ ollamamodels: data.models }); + return []; + } - return data.models.map((model: OllamaModel) => ({ - name: model.name, - label: `${model.name} (${model.details.parameter_size})`, - provider: this.name, - maxTokenAllowed: 8000, - })); + if (error instanceof TypeError && error.message.includes('fetch')) { + logger.warn(`Ollama not reachable at ${baseUrl} — is Ollama running?`); + + return []; + } + + logger.error('Error fetching Ollama models:', error); + + return []; + } } getModelInstance: (options: { @@ -107,33 +117,18 @@ export default class OllamaProvider extends BaseProvider { providerSettings?: Record; }) => LanguageModelV1 = (options) => { const { apiKeys, providerSettings, serverEnv, model } = options; - const envRecord = this._convertEnvToRecord(serverEnv); - - let { baseUrl } = this.getProviderBaseUrlAndKey({ - apiKeys, - providerSettings: providerSettings?.[this.name], - serverEnv: envRecord, - defaultBaseUrlKey: 'OLLAMA_API_BASE_URL', - defaultApiTokenKey: '', - }); + const envRecord = this.convertEnvToRecord(serverEnv); - // Backend: Check if we're running in Docker - if (!baseUrl) { - throw new Error('No baseUrl found for OLLAMA provider'); - } - - const isDocker = process?.env?.RUNNING_IN_DOCKER === 'true' || envRecord.RUNNING_IN_DOCKER === 'true'; - baseUrl = isDocker ? baseUrl.replace('localhost', 'host.docker.internal') : baseUrl; - baseUrl = isDocker ? baseUrl.replace('127.0.0.1', 'host.docker.internal') : baseUrl; + const baseUrl = this._resolveBaseUrl(apiKeys, providerSettings?.[this.name], envRecord); logger.debug('Ollama Base Url used: ', baseUrl); - const ollamaInstance = ollama(model, { - numCtx: this.getDefaultNumCtx(serverEnv), - }) as LanguageModelV1 & { config: any }; - - ollamaInstance.config.baseURL = `${baseUrl}/api`; + const ollamaProvider = createOllama({ + baseURL: `${baseUrl}/api`, + }); - return ollamaInstance; + return ollamaProvider(model, { + numCtx: this.getDefaultNumCtx(serverEnv), + }); }; } diff --git a/app/lib/modules/llm/providers/openai-like.ts b/app/lib/modules/llm/providers/openai-like.ts index 713da07bc0..85dc42d68b 100644 --- a/app/lib/modules/llm/providers/openai-like.ts +++ b/app/lib/modules/llm/providers/openai-like.ts @@ -2,6 +2,11 @@ import { BaseProvider, getOpenAILikeModel } from '~/lib/modules/llm/base-provide import type { ModelInfo } from '~/lib/modules/llm/types'; import type { IProviderSetting } from '~/types/model'; import type { LanguageModelV1 } from 'ai'; +import { logger } from '~/utils/logger'; + +interface OpenAIModelsResponse { + data: Array<{ id: string }>; +} export default class OpenAILikeProvider extends BaseProvider { name = 'OpenAILike'; @@ -37,29 +42,31 @@ export default class OpenAILikeProvider extends BaseProvider { headers: { Authorization: `Bearer ${apiKey}`, }, + signal: this.createTimeoutSignal(), }); if (!response.ok) { throw new Error(`HTTP ${response.status}: ${response.statusText}`); } - const res = (await response.json()) as any; + const res = (await response.json()) as OpenAIModelsResponse; - return res.data.map((model: any) => ({ + return res.data.map((model) => ({ name: model.id, label: model.id, provider: this.name, maxTokenAllowed: 8000, })); } catch (error) { - console.log(`${this.name}: Not allowed to GET /models endpoint for provider`, error); + logger.info(`${this.name}: Could not fetch /models endpoint, checking fallback env`, error); // Fallback to OPENAI_LIKE_API_MODELS if available // eslint-disable-next-line dot-notation const modelsEnv = serverEnv['OPENAI_LIKE_API_MODELS'] || settings?.OPENAI_LIKE_API_MODELS; if (modelsEnv) { - console.log(`${this.name}: OPENAI_LIKE_API_MODELS=${modelsEnv}`); + logger.info(`${this.name}: Using OPENAI_LIKE_API_MODELS fallback`); + return this._parseModelsFromEnv(modelsEnv); } @@ -107,11 +114,11 @@ export default class OpenAILikeProvider extends BaseProvider { }); } - console.log(`${this.name}: Parsed Models:`, models); + logger.info(`${this.name}: Parsed ${models.length} models from env`); return models; } catch (error) { - console.error(`${this.name}: Error parsing OPENAI_LIKE_API_MODELS:`, error); + logger.error(`${this.name}: Error parsing OPENAI_LIKE_API_MODELS:`, error); return []; } } @@ -149,11 +156,12 @@ export default class OpenAILikeProvider extends BaseProvider { providerSettings?: Record; }): LanguageModelV1 { const { model, serverEnv, apiKeys, providerSettings } = options; + const envRecord = this.convertEnvToRecord(serverEnv); const { baseUrl, apiKey } = this.getProviderBaseUrlAndKey({ apiKeys, providerSettings: providerSettings?.[this.name], - serverEnv: serverEnv as any, + serverEnv: envRecord, defaultBaseUrlKey: 'OPENAI_LIKE_API_BASE_URL', defaultApiTokenKey: 'OPENAI_LIKE_API_KEY', }); diff --git a/app/lib/modules/llm/providers/z-ai.ts b/app/lib/modules/llm/providers/z-ai.ts new file mode 100644 index 0000000000..d400082015 --- /dev/null +++ b/app/lib/modules/llm/providers/z-ai.ts @@ -0,0 +1,193 @@ +import { BaseProvider } from '~/lib/modules/llm/base-provider'; +import type { IProviderSetting } from '~/types/model'; +import type { LanguageModelV1 } from 'ai'; +import type { ModelInfo } from '~/lib/modules/llm/types'; +import { createOpenAI } from '@ai-sdk/openai'; +import crypto from 'node:crypto'; + +export default class ZaiProvider extends BaseProvider { + name = 'Z.ai'; + getApiKeyLink = 'https://open.bigmodel.cn/usercenter/apikeys'; + + config = { + baseUrlKey: 'ZAI_BASE_URL', + apiTokenKey: 'ZAI_API_KEY', + baseUrl: 'https://api.z.ai/api/coding/paas/v4', //Dedicated endpoint for Coding Plan + }; + + staticModels: ModelInfo[] = [ + { + name: 'glm-4.6', + label: 'GLM-4.6 (200K)', + provider: 'Z.ai', + maxTokenAllowed: 200000, + maxCompletionTokens: 65536, + }, + { + name: 'glm-4.5', + label: 'GLM-4.5 (128K)', + provider: 'Z.ai', + maxTokenAllowed: 128000, + maxCompletionTokens: 65536, + }, + { + name: 'glm-4.5-flash', + label: 'GLM-4.5 Flash (128K)', + provider: 'Z.ai', + maxTokenAllowed: 128000, + maxCompletionTokens: 65536, + }, + ]; + + async getDynamicModels( + apiKeys?: Record, + settings?: IProviderSetting, + serverEnv?: Record, + ): Promise { + const { baseUrl, apiKey } = this.getProviderBaseUrlAndKey({ + apiKeys, + providerSettings: settings, + serverEnv: serverEnv as any, + defaultBaseUrlKey: 'ZAI_BASE_URL', + defaultApiTokenKey: 'ZAI_API_KEY', + }); + + if (!apiKey) { + throw new Error(`Missing Api Key configuration for ${this.name} provider`); + } + + const token = this._generateToken(apiKey); + + if (!this._isValidToken(token)) { + throw new Error(`Invalid API key format for ${this.name} provider`); + } + + try { + const response = await fetch(`${baseUrl}/models`, { + headers: { + Authorization: `Bearer ${token}`, + 'Content-Type': 'application/json', + }, + }); + + if (!response.ok) { + throw new Error(`Failed to fetch models: ${response.status} ${response.statusText}`); + } + + const res = (await response.json()) as any; + const staticModelIds = this.staticModels.map((m) => m.name); + + // Filter out static models and only include GLM models + const data = + res.data?.filter( + (model: any) => + model.object === 'model' && model.id?.startsWith('glm-') && !staticModelIds.includes(model.id), + ) || []; + + return data.map((m: any) => { + let contextWindow = 128000; + let maxCompletionTokens = 65536; + + if (m.id?.includes('glm-4.6')) { + contextWindow = 200000; + maxCompletionTokens = 65536; + } else if (m.id?.includes('glm-4.5')) { + contextWindow = 128000; + maxCompletionTokens = 65536; + } else if (m.id?.includes('glm-4')) { + contextWindow = 128000; + maxCompletionTokens = 8192; + } else if (m.id?.includes('glm-3')) { + contextWindow = 32000; + maxCompletionTokens = 4096; + } + + return { + name: m.id, + label: `${m.id} (${Math.floor(contextWindow / 1000)}k context)`, + provider: this.name, + maxTokenAllowed: contextWindow, + maxCompletionTokens, + }; + }); + } catch (error) { + console.error(`Failed to fetch dynamic models for ${this.name}:`, error); + return []; + } + } + + private _generateToken(apiKey: string): string { + try { + const [id, secret] = apiKey.split('.'); + + if (!id || !secret) { + throw new Error(`Invalid API key format for ${this.name}. Expected: id.secret`); + } + + const now = Date.now(); + const payload = { + apiKey: id, + exp: now + 3600 * 1000, + timestamp: now, + }; + + const header = { alg: 'HS256', sign_type: 'SIGN' }; + + const base64Url = (obj: any) => + Buffer.from(JSON.stringify(obj)).toString('base64').replace(/=/g, '').replace(/\+/g, '-').replace(/\//g, '_'); + const signature = crypto + .createHmac('sha256', secret) + .update(base64Url(header) + '.' + base64Url(payload)) + .digest('base64') + .replace(/=/g, '') + .replace(/\+/g, '-') + .replace(/\//g, '_'); + + return `${base64Url(header)}.${base64Url(payload)}.${signature}`; + } catch (error) { + console.error(`Failed to generate JWT token for ${this.name}:`, error); + throw new Error(`Failed to generate JWT token: ${error instanceof Error ? error.message : 'Unknown error'}`); + } + } + + /** + * Validates JWT token format + */ + private _isValidToken(token: string): boolean { + try { + const parts = token.split('.'); + return parts.length === 3 && parts.every((part) => part.length > 0); + } catch { + return false; + } + } + + getModelInstance(options: { + model: string; + serverEnv: Env; + apiKeys?: Record; + providerSettings?: Record; + }): LanguageModelV1 { + const { model, serverEnv, apiKeys, providerSettings } = options; + + const { baseUrl, apiKey } = this.getProviderBaseUrlAndKey({ + apiKeys, + providerSettings: providerSettings?.[this.name], + serverEnv: serverEnv as any, + defaultBaseUrlKey: 'ZAI_BASE_URL', + defaultApiTokenKey: 'ZAI_API_KEY', + }); + + if (!apiKey) { + throw new Error(`Missing API key for ${this.name} provider`); + } + + const token = this._generateToken(apiKey); + const zaiClient = createOpenAI({ + baseURL: baseUrl, + apiKey: token, + }); + + return zaiClient(model); + } +} diff --git a/app/lib/modules/llm/registry.ts b/app/lib/modules/llm/registry.ts index a28e4f9f3a..01bbe81140 100644 --- a/app/lib/modules/llm/registry.ts +++ b/app/lib/modules/llm/registry.ts @@ -1,6 +1,8 @@ import AnthropicProvider from './providers/anthropic'; +import CerebrasProvider from './providers/cerebras'; import CohereProvider from './providers/cohere'; import DeepseekProvider from './providers/deepseek'; +import FireworksProvider from './providers/fireworks'; import GoogleProvider from './providers/google'; import GroqProvider from './providers/groq'; import HuggingFaceProvider from './providers/huggingface'; @@ -17,11 +19,14 @@ import HyperbolicProvider from './providers/hyperbolic'; import AmazonBedrockProvider from './providers/amazon-bedrock'; import GithubProvider from './providers/github'; import MoonshotProvider from './providers/moonshot'; +import ZaiProvider from './providers/z-ai'; export { AnthropicProvider, + CerebrasProvider, CohereProvider, DeepseekProvider, + FireworksProvider, GoogleProvider, GroqProvider, HuggingFaceProvider, @@ -38,4 +43,5 @@ export { LMStudioProvider, AmazonBedrockProvider, GithubProvider, + ZaiProvider, }; diff --git a/package.json b/package.json index b02ba021ec..5c8c2a977f 100644 --- a/package.json +++ b/package.json @@ -48,8 +48,10 @@ "dependencies": { "@ai-sdk/amazon-bedrock": "1.0.6", "@ai-sdk/anthropic": "0.0.39", + "@ai-sdk/cerebras": "^0.2.16", "@ai-sdk/cohere": "1.0.3", "@ai-sdk/deepseek": "0.1.3", + "@ai-sdk/fireworks": "^0.2.16", "@ai-sdk/google": "0.0.52", "@ai-sdk/mistral": "0.0.43", "@ai-sdk/openai": "1.1.2", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e4061c9079..b397e9814a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -17,12 +17,18 @@ importers: '@ai-sdk/anthropic': specifier: 0.0.39 version: 0.0.39(zod@3.25.76) + '@ai-sdk/cerebras': + specifier: ^0.2.16 + version: 0.2.16(zod@3.25.76) '@ai-sdk/cohere': specifier: 1.0.3 version: 1.0.3(zod@3.25.76) '@ai-sdk/deepseek': specifier: 0.1.3 version: 0.1.3(zod@3.25.76) + '@ai-sdk/fireworks': + specifier: ^0.2.16 + version: 0.2.16(zod@3.25.76) '@ai-sdk/google': specifier: 0.0.52 version: 0.0.52(zod@3.25.76) @@ -504,6 +510,12 @@ packages: peerDependencies: zod: ^3.0.0 + '@ai-sdk/cerebras@0.2.16': + resolution: {integrity: sha512-FbT3gFYADXwyjQlpluWxl5fRnkJvGMHX5ahLZZ7qqpDQHH86ZO6X9j9Gk6vcMCwNPpI7+miiK79q1e5wzVHBSQ==} + engines: {node: '>=18'} + peerDependencies: + zod: ^3.0.0 + '@ai-sdk/cohere@1.0.3': resolution: {integrity: sha512-SDjPinUcGzTNiSMN+9zs1fuAcP8rU1/+CmDWAGu7eMhwVGDurgiOqscC0Oqs/aLsodLt/sFeOvyqj86DAknpbg==} engines: {node: '>=18'} @@ -516,6 +528,12 @@ packages: peerDependencies: zod: ^3.0.0 + '@ai-sdk/fireworks@0.2.16': + resolution: {integrity: sha512-YHUqW9QHMNjEg5vF0cmhnlAQJCMljWVWNAAFmKCPX31Dj4JaoCjOrIInrNEFerFRaO64hEffhlhuC1EmuO2Lyg==} + engines: {node: '>=18'} + peerDependencies: + zod: ^3.0.0 + '@ai-sdk/google@0.0.52': resolution: {integrity: sha512-bfsA/1Ae0SQ6NfLwWKs5SU4MBwlzJjVhK6bTVBicYFjUxg9liK/W76P1Tq/qK9OlrODACz3i1STOIWsFPpIOuQ==} engines: {node: '>=18'} @@ -534,6 +552,12 @@ packages: peerDependencies: zod: ^3.0.0 + '@ai-sdk/openai-compatible@0.2.16': + resolution: {integrity: sha512-LkvfcM8slJedRyJa/MiMiaOzcMjV1zNDwzTHEGz7aAsgsQV0maLfmJRi/nuSwf5jmp0EouC+JXXDUj2l94HgQw==} + engines: {node: '>=18'} + peerDependencies: + zod: ^3.0.0 + '@ai-sdk/openai@1.1.2': resolution: {integrity: sha512-9rfcwjl4g1/Bdr2SmgFQr+aw81r62MvIKE7QDHMC4ulFd/Hej2oClROSMpDFZHXzs7RGeb32VkRyCHUWWgN3RQ==} engines: {node: '>=18'} @@ -793,6 +817,10 @@ packages: resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==} engines: {node: '>=6.9.0'} + '@babel/code-frame@7.29.0': + resolution: {integrity: sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==} + engines: {node: '>=6.9.0'} + '@babel/compat-data@7.28.0': resolution: {integrity: sha512-60X7qkglvrap8mn1lh2ebxXdZYtUcpd7gsmy9kLaBJ4i/WdY8PqTSdxyA8qraikqKQK5C1KRBKXqznrVapyNaw==} engines: {node: '>=6.9.0'} @@ -863,6 +891,10 @@ packages: resolution: {integrity: sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==} engines: {node: '>=6.9.0'} + '@babel/helper-validator-identifier@7.28.5': + resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} + engines: {node: '>=6.9.0'} + '@babel/helper-validator-option@7.27.1': resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==} engines: {node: '>=6.9.0'} @@ -928,6 +960,10 @@ packages: resolution: {integrity: sha512-vbavdySgbTTrmFE+EsiqUTzlOr5bzlnJtUv9PynGCAKvfQqjIXbvFdumPM/GxMDfyuGMJaJAU6TO4zc1Jf1i8Q==} engines: {node: '>=6.9.0'} + '@babel/runtime@7.28.6': + resolution: {integrity: sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==} + engines: {node: '>=6.9.0'} + '@babel/template@7.27.2': resolution: {integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==} engines: {node: '>=6.9.0'} @@ -1148,14 +1184,14 @@ packages: cpu: [ppc64] os: [aix] - '@esbuild/aix-ppc64@0.25.4': - resolution: {integrity: sha512-1VCICWypeQKhVbE9oW/sJaAmjLxhVqacdkvPLEjwlttjfwENRSClS8EjBz0KzRyFSCPDIkuXW34Je/vk7zdB7Q==} + '@esbuild/aix-ppc64@0.25.12': + resolution: {integrity: sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==} engines: {node: '>=18'} cpu: [ppc64] os: [aix] - '@esbuild/aix-ppc64@0.25.8': - resolution: {integrity: sha512-urAvrUedIqEiFR3FYSLTWQgLu5tb+m0qZw0NBEasUeo6wuqatkMDaRT+1uABiGXEu5vqgPd7FGE1BhsAIy9QVA==} + '@esbuild/aix-ppc64@0.25.4': + resolution: {integrity: sha512-1VCICWypeQKhVbE9oW/sJaAmjLxhVqacdkvPLEjwlttjfwENRSClS8EjBz0KzRyFSCPDIkuXW34Je/vk7zdB7Q==} engines: {node: '>=18'} cpu: [ppc64] os: [aix] @@ -1178,14 +1214,14 @@ packages: cpu: [arm64] os: [android] - '@esbuild/android-arm64@0.25.4': - resolution: {integrity: sha512-bBy69pgfhMGtCnwpC/x5QhfxAz/cBgQ9enbtwjf6V9lnPI/hMyT9iWpR1arm0l3kttTr4L0KSLpKmLp/ilKS9A==} + '@esbuild/android-arm64@0.25.12': + resolution: {integrity: sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==} engines: {node: '>=18'} cpu: [arm64] os: [android] - '@esbuild/android-arm64@0.25.8': - resolution: {integrity: sha512-OD3p7LYzWpLhZEyATcTSJ67qB5D+20vbtr6vHlHWSQYhKtzUYrETuWThmzFpZtFsBIxRvhO07+UgVA9m0i/O1w==} + '@esbuild/android-arm64@0.25.4': + resolution: {integrity: sha512-bBy69pgfhMGtCnwpC/x5QhfxAz/cBgQ9enbtwjf6V9lnPI/hMyT9iWpR1arm0l3kttTr4L0KSLpKmLp/ilKS9A==} engines: {node: '>=18'} cpu: [arm64] os: [android] @@ -1208,14 +1244,14 @@ packages: cpu: [arm] os: [android] - '@esbuild/android-arm@0.25.4': - resolution: {integrity: sha512-QNdQEps7DfFwE3hXiU4BZeOV68HHzYwGd0Nthhd3uCkkEKK7/R6MTgM0P7H7FAs5pU/DIWsviMmEGxEoxIZ+ZQ==} + '@esbuild/android-arm@0.25.12': + resolution: {integrity: sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==} engines: {node: '>=18'} cpu: [arm] os: [android] - '@esbuild/android-arm@0.25.8': - resolution: {integrity: sha512-RONsAvGCz5oWyePVnLdZY/HHwA++nxYWIX1atInlaW6SEkwq6XkP3+cb825EUcRs5Vss/lGh/2YxAb5xqc07Uw==} + '@esbuild/android-arm@0.25.4': + resolution: {integrity: sha512-QNdQEps7DfFwE3hXiU4BZeOV68HHzYwGd0Nthhd3uCkkEKK7/R6MTgM0P7H7FAs5pU/DIWsviMmEGxEoxIZ+ZQ==} engines: {node: '>=18'} cpu: [arm] os: [android] @@ -1238,14 +1274,14 @@ packages: cpu: [x64] os: [android] - '@esbuild/android-x64@0.25.4': - resolution: {integrity: sha512-TVhdVtQIFuVpIIR282btcGC2oGQoSfZfmBdTip2anCaVYcqWlZXGcdcKIUklfX2wj0JklNYgz39OBqh2cqXvcQ==} + '@esbuild/android-x64@0.25.12': + resolution: {integrity: sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==} engines: {node: '>=18'} cpu: [x64] os: [android] - '@esbuild/android-x64@0.25.8': - resolution: {integrity: sha512-yJAVPklM5+4+9dTeKwHOaA+LQkmrKFX96BM0A/2zQrbS6ENCmxc4OVoBs5dPkCCak2roAD+jKCdnmOqKszPkjA==} + '@esbuild/android-x64@0.25.4': + resolution: {integrity: sha512-TVhdVtQIFuVpIIR282btcGC2oGQoSfZfmBdTip2anCaVYcqWlZXGcdcKIUklfX2wj0JklNYgz39OBqh2cqXvcQ==} engines: {node: '>=18'} cpu: [x64] os: [android] @@ -1268,14 +1304,14 @@ packages: cpu: [arm64] os: [darwin] - '@esbuild/darwin-arm64@0.25.4': - resolution: {integrity: sha512-Y1giCfM4nlHDWEfSckMzeWNdQS31BQGs9/rouw6Ub91tkK79aIMTH3q9xHvzH8d0wDru5Ci0kWB8b3up/nl16g==} + '@esbuild/darwin-arm64@0.25.12': + resolution: {integrity: sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==} engines: {node: '>=18'} cpu: [arm64] os: [darwin] - '@esbuild/darwin-arm64@0.25.8': - resolution: {integrity: sha512-Jw0mxgIaYX6R8ODrdkLLPwBqHTtYHJSmzzd+QeytSugzQ0Vg4c5rDky5VgkoowbZQahCbsv1rT1KW72MPIkevw==} + '@esbuild/darwin-arm64@0.25.4': + resolution: {integrity: sha512-Y1giCfM4nlHDWEfSckMzeWNdQS31BQGs9/rouw6Ub91tkK79aIMTH3q9xHvzH8d0wDru5Ci0kWB8b3up/nl16g==} engines: {node: '>=18'} cpu: [arm64] os: [darwin] @@ -1298,14 +1334,14 @@ packages: cpu: [x64] os: [darwin] - '@esbuild/darwin-x64@0.25.4': - resolution: {integrity: sha512-CJsry8ZGM5VFVeyUYB3cdKpd/H69PYez4eJh1W/t38vzutdjEjtP7hB6eLKBoOdxcAlCtEYHzQ/PJ/oU9I4u0A==} + '@esbuild/darwin-x64@0.25.12': + resolution: {integrity: sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==} engines: {node: '>=18'} cpu: [x64] os: [darwin] - '@esbuild/darwin-x64@0.25.8': - resolution: {integrity: sha512-Vh2gLxxHnuoQ+GjPNvDSDRpoBCUzY4Pu0kBqMBDlK4fuWbKgGtmDIeEC081xi26PPjn+1tct+Bh8FjyLlw1Zlg==} + '@esbuild/darwin-x64@0.25.4': + resolution: {integrity: sha512-CJsry8ZGM5VFVeyUYB3cdKpd/H69PYez4eJh1W/t38vzutdjEjtP7hB6eLKBoOdxcAlCtEYHzQ/PJ/oU9I4u0A==} engines: {node: '>=18'} cpu: [x64] os: [darwin] @@ -1328,14 +1364,14 @@ packages: cpu: [arm64] os: [freebsd] - '@esbuild/freebsd-arm64@0.25.4': - resolution: {integrity: sha512-yYq+39NlTRzU2XmoPW4l5Ifpl9fqSk0nAJYM/V/WUGPEFfek1epLHJIkTQM6bBs1swApjO5nWgvr843g6TjxuQ==} + '@esbuild/freebsd-arm64@0.25.12': + resolution: {integrity: sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==} engines: {node: '>=18'} cpu: [arm64] os: [freebsd] - '@esbuild/freebsd-arm64@0.25.8': - resolution: {integrity: sha512-YPJ7hDQ9DnNe5vxOm6jaie9QsTwcKedPvizTVlqWG9GBSq+BuyWEDazlGaDTC5NGU4QJd666V0yqCBL2oWKPfA==} + '@esbuild/freebsd-arm64@0.25.4': + resolution: {integrity: sha512-yYq+39NlTRzU2XmoPW4l5Ifpl9fqSk0nAJYM/V/WUGPEFfek1epLHJIkTQM6bBs1swApjO5nWgvr843g6TjxuQ==} engines: {node: '>=18'} cpu: [arm64] os: [freebsd] @@ -1358,14 +1394,14 @@ packages: cpu: [x64] os: [freebsd] - '@esbuild/freebsd-x64@0.25.4': - resolution: {integrity: sha512-0FgvOJ6UUMflsHSPLzdfDnnBBVoCDtBTVyn/MrWloUNvq/5SFmh13l3dvgRPkDihRxb77Y17MbqbCAa2strMQQ==} + '@esbuild/freebsd-x64@0.25.12': + resolution: {integrity: sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==} engines: {node: '>=18'} cpu: [x64] os: [freebsd] - '@esbuild/freebsd-x64@0.25.8': - resolution: {integrity: sha512-MmaEXxQRdXNFsRN/KcIimLnSJrk2r5H8v+WVafRWz5xdSVmWLoITZQXcgehI2ZE6gioE6HirAEToM/RvFBeuhw==} + '@esbuild/freebsd-x64@0.25.4': + resolution: {integrity: sha512-0FgvOJ6UUMflsHSPLzdfDnnBBVoCDtBTVyn/MrWloUNvq/5SFmh13l3dvgRPkDihRxb77Y17MbqbCAa2strMQQ==} engines: {node: '>=18'} cpu: [x64] os: [freebsd] @@ -1388,14 +1424,14 @@ packages: cpu: [arm64] os: [linux] - '@esbuild/linux-arm64@0.25.4': - resolution: {integrity: sha512-+89UsQTfXdmjIvZS6nUnOOLoXnkUTB9hR5QAeLrQdzOSWZvNSAXAtcRDHWtqAUtAmv7ZM1WPOOeSxDzzzMogiQ==} + '@esbuild/linux-arm64@0.25.12': + resolution: {integrity: sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==} engines: {node: '>=18'} cpu: [arm64] os: [linux] - '@esbuild/linux-arm64@0.25.8': - resolution: {integrity: sha512-WIgg00ARWv/uYLU7lsuDK00d/hHSfES5BzdWAdAig1ioV5kaFNrtK8EqGcUBJhYqotlUByUKz5Qo6u8tt7iD/w==} + '@esbuild/linux-arm64@0.25.4': + resolution: {integrity: sha512-+89UsQTfXdmjIvZS6nUnOOLoXnkUTB9hR5QAeLrQdzOSWZvNSAXAtcRDHWtqAUtAmv7ZM1WPOOeSxDzzzMogiQ==} engines: {node: '>=18'} cpu: [arm64] os: [linux] @@ -1418,14 +1454,14 @@ packages: cpu: [arm] os: [linux] - '@esbuild/linux-arm@0.25.4': - resolution: {integrity: sha512-kro4c0P85GMfFYqW4TWOpvmF8rFShbWGnrLqlzp4X1TNWjRY3JMYUfDCtOxPKOIY8B0WC8HN51hGP4I4hz4AaQ==} + '@esbuild/linux-arm@0.25.12': + resolution: {integrity: sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==} engines: {node: '>=18'} cpu: [arm] os: [linux] - '@esbuild/linux-arm@0.25.8': - resolution: {integrity: sha512-FuzEP9BixzZohl1kLf76KEVOsxtIBFwCaLupVuk4eFVnOZfU+Wsn+x5Ryam7nILV2pkq2TqQM9EZPsOBuMC+kg==} + '@esbuild/linux-arm@0.25.4': + resolution: {integrity: sha512-kro4c0P85GMfFYqW4TWOpvmF8rFShbWGnrLqlzp4X1TNWjRY3JMYUfDCtOxPKOIY8B0WC8HN51hGP4I4hz4AaQ==} engines: {node: '>=18'} cpu: [arm] os: [linux] @@ -1448,14 +1484,14 @@ packages: cpu: [ia32] os: [linux] - '@esbuild/linux-ia32@0.25.4': - resolution: {integrity: sha512-yTEjoapy8UP3rv8dB0ip3AfMpRbyhSN3+hY8mo/i4QXFeDxmiYbEKp3ZRjBKcOP862Ua4b1PDfwlvbuwY7hIGQ==} + '@esbuild/linux-ia32@0.25.12': + resolution: {integrity: sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==} engines: {node: '>=18'} cpu: [ia32] os: [linux] - '@esbuild/linux-ia32@0.25.8': - resolution: {integrity: sha512-A1D9YzRX1i+1AJZuFFUMP1E9fMaYY+GnSQil9Tlw05utlE86EKTUA7RjwHDkEitmLYiFsRd9HwKBPEftNdBfjg==} + '@esbuild/linux-ia32@0.25.4': + resolution: {integrity: sha512-yTEjoapy8UP3rv8dB0ip3AfMpRbyhSN3+hY8mo/i4QXFeDxmiYbEKp3ZRjBKcOP862Ua4b1PDfwlvbuwY7hIGQ==} engines: {node: '>=18'} cpu: [ia32] os: [linux] @@ -1478,14 +1514,14 @@ packages: cpu: [loong64] os: [linux] - '@esbuild/linux-loong64@0.25.4': - resolution: {integrity: sha512-NeqqYkrcGzFwi6CGRGNMOjWGGSYOpqwCjS9fvaUlX5s3zwOtn1qwg1s2iE2svBe4Q/YOG1q6875lcAoQK/F4VA==} + '@esbuild/linux-loong64@0.25.12': + resolution: {integrity: sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==} engines: {node: '>=18'} cpu: [loong64] os: [linux] - '@esbuild/linux-loong64@0.25.8': - resolution: {integrity: sha512-O7k1J/dwHkY1RMVvglFHl1HzutGEFFZ3kNiDMSOyUrB7WcoHGf96Sh+64nTRT26l3GMbCW01Ekh/ThKM5iI7hQ==} + '@esbuild/linux-loong64@0.25.4': + resolution: {integrity: sha512-NeqqYkrcGzFwi6CGRGNMOjWGGSYOpqwCjS9fvaUlX5s3zwOtn1qwg1s2iE2svBe4Q/YOG1q6875lcAoQK/F4VA==} engines: {node: '>=18'} cpu: [loong64] os: [linux] @@ -1508,14 +1544,14 @@ packages: cpu: [mips64el] os: [linux] - '@esbuild/linux-mips64el@0.25.4': - resolution: {integrity: sha512-IcvTlF9dtLrfL/M8WgNI/qJYBENP3ekgsHbYUIzEzq5XJzzVEV/fXY9WFPfEEXmu3ck2qJP8LG/p3Q8f7Zc2Xg==} + '@esbuild/linux-mips64el@0.25.12': + resolution: {integrity: sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==} engines: {node: '>=18'} cpu: [mips64el] os: [linux] - '@esbuild/linux-mips64el@0.25.8': - resolution: {integrity: sha512-uv+dqfRazte3BzfMp8PAQXmdGHQt2oC/y2ovwpTteqrMx2lwaksiFZ/bdkXJC19ttTvNXBuWH53zy/aTj1FgGw==} + '@esbuild/linux-mips64el@0.25.4': + resolution: {integrity: sha512-IcvTlF9dtLrfL/M8WgNI/qJYBENP3ekgsHbYUIzEzq5XJzzVEV/fXY9WFPfEEXmu3ck2qJP8LG/p3Q8f7Zc2Xg==} engines: {node: '>=18'} cpu: [mips64el] os: [linux] @@ -1538,14 +1574,14 @@ packages: cpu: [ppc64] os: [linux] - '@esbuild/linux-ppc64@0.25.4': - resolution: {integrity: sha512-HOy0aLTJTVtoTeGZh4HSXaO6M95qu4k5lJcH4gxv56iaycfz1S8GO/5Jh6X4Y1YiI0h7cRyLi+HixMR+88swag==} + '@esbuild/linux-ppc64@0.25.12': + resolution: {integrity: sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==} engines: {node: '>=18'} cpu: [ppc64] os: [linux] - '@esbuild/linux-ppc64@0.25.8': - resolution: {integrity: sha512-GyG0KcMi1GBavP5JgAkkstMGyMholMDybAf8wF5A70CALlDM2p/f7YFE7H92eDeH/VBtFJA5MT4nRPDGg4JuzQ==} + '@esbuild/linux-ppc64@0.25.4': + resolution: {integrity: sha512-HOy0aLTJTVtoTeGZh4HSXaO6M95qu4k5lJcH4gxv56iaycfz1S8GO/5Jh6X4Y1YiI0h7cRyLi+HixMR+88swag==} engines: {node: '>=18'} cpu: [ppc64] os: [linux] @@ -1568,14 +1604,14 @@ packages: cpu: [riscv64] os: [linux] - '@esbuild/linux-riscv64@0.25.4': - resolution: {integrity: sha512-i8JUDAufpz9jOzo4yIShCTcXzS07vEgWzyX3NH2G7LEFVgrLEhjwL3ajFE4fZI3I4ZgiM7JH3GQ7ReObROvSUA==} + '@esbuild/linux-riscv64@0.25.12': + resolution: {integrity: sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==} engines: {node: '>=18'} cpu: [riscv64] os: [linux] - '@esbuild/linux-riscv64@0.25.8': - resolution: {integrity: sha512-rAqDYFv3yzMrq7GIcen3XP7TUEG/4LK86LUPMIz6RT8A6pRIDn0sDcvjudVZBiiTcZCY9y2SgYX2lgK3AF+1eg==} + '@esbuild/linux-riscv64@0.25.4': + resolution: {integrity: sha512-i8JUDAufpz9jOzo4yIShCTcXzS07vEgWzyX3NH2G7LEFVgrLEhjwL3ajFE4fZI3I4ZgiM7JH3GQ7ReObROvSUA==} engines: {node: '>=18'} cpu: [riscv64] os: [linux] @@ -1598,14 +1634,14 @@ packages: cpu: [s390x] os: [linux] - '@esbuild/linux-s390x@0.25.4': - resolution: {integrity: sha512-jFnu+6UbLlzIjPQpWCNh5QtrcNfMLjgIavnwPQAfoGx4q17ocOU9MsQ2QVvFxwQoWpZT8DvTLooTvmOQXkO51g==} + '@esbuild/linux-s390x@0.25.12': + resolution: {integrity: sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==} engines: {node: '>=18'} cpu: [s390x] os: [linux] - '@esbuild/linux-s390x@0.25.8': - resolution: {integrity: sha512-Xutvh6VjlbcHpsIIbwY8GVRbwoviWT19tFhgdA7DlenLGC/mbc3lBoVb7jxj9Z+eyGqvcnSyIltYUrkKzWqSvg==} + '@esbuild/linux-s390x@0.25.4': + resolution: {integrity: sha512-jFnu+6UbLlzIjPQpWCNh5QtrcNfMLjgIavnwPQAfoGx4q17ocOU9MsQ2QVvFxwQoWpZT8DvTLooTvmOQXkO51g==} engines: {node: '>=18'} cpu: [s390x] os: [linux] @@ -1628,26 +1664,26 @@ packages: cpu: [x64] os: [linux] - '@esbuild/linux-x64@0.25.4': - resolution: {integrity: sha512-6e0cvXwzOnVWJHq+mskP8DNSrKBr1bULBvnFLpc1KY+d+irZSgZ02TGse5FsafKS5jg2e4pbvK6TPXaF/A6+CA==} + '@esbuild/linux-x64@0.25.12': + resolution: {integrity: sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==} engines: {node: '>=18'} cpu: [x64] os: [linux] - '@esbuild/linux-x64@0.25.8': - resolution: {integrity: sha512-ASFQhgY4ElXh3nDcOMTkQero4b1lgubskNlhIfJrsH5OKZXDpUAKBlNS0Kx81jwOBp+HCeZqmoJuihTv57/jvQ==} + '@esbuild/linux-x64@0.25.4': + resolution: {integrity: sha512-6e0cvXwzOnVWJHq+mskP8DNSrKBr1bULBvnFLpc1KY+d+irZSgZ02TGse5FsafKS5jg2e4pbvK6TPXaF/A6+CA==} engines: {node: '>=18'} cpu: [x64] os: [linux] - '@esbuild/netbsd-arm64@0.25.4': - resolution: {integrity: sha512-vUnkBYxZW4hL/ie91hSqaSNjulOnYXE1VSLusnvHg2u3jewJBz3YzB9+oCw8DABeVqZGg94t9tyZFoHma8gWZQ==} + '@esbuild/netbsd-arm64@0.25.12': + resolution: {integrity: sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==} engines: {node: '>=18'} cpu: [arm64] os: [netbsd] - '@esbuild/netbsd-arm64@0.25.8': - resolution: {integrity: sha512-d1KfruIeohqAi6SA+gENMuObDbEjn22olAR7egqnkCD9DGBG0wsEARotkLgXDu6c4ncgWTZJtN5vcgxzWRMzcw==} + '@esbuild/netbsd-arm64@0.25.4': + resolution: {integrity: sha512-vUnkBYxZW4hL/ie91hSqaSNjulOnYXE1VSLusnvHg2u3jewJBz3YzB9+oCw8DABeVqZGg94t9tyZFoHma8gWZQ==} engines: {node: '>=18'} cpu: [arm64] os: [netbsd] @@ -1670,14 +1706,14 @@ packages: cpu: [x64] os: [netbsd] - '@esbuild/netbsd-x64@0.25.4': - resolution: {integrity: sha512-XAg8pIQn5CzhOB8odIcAm42QsOfa98SBeKUdo4xa8OvX8LbMZqEtgeWE9P/Wxt7MlG2QqvjGths+nq48TrUiKw==} + '@esbuild/netbsd-x64@0.25.12': + resolution: {integrity: sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==} engines: {node: '>=18'} cpu: [x64] os: [netbsd] - '@esbuild/netbsd-x64@0.25.8': - resolution: {integrity: sha512-nVDCkrvx2ua+XQNyfrujIG38+YGyuy2Ru9kKVNyh5jAys6n+l44tTtToqHjino2My8VAY6Lw9H7RI73XFi66Cg==} + '@esbuild/netbsd-x64@0.25.4': + resolution: {integrity: sha512-XAg8pIQn5CzhOB8odIcAm42QsOfa98SBeKUdo4xa8OvX8LbMZqEtgeWE9P/Wxt7MlG2QqvjGths+nq48TrUiKw==} engines: {node: '>=18'} cpu: [x64] os: [netbsd] @@ -1688,14 +1724,14 @@ packages: cpu: [arm64] os: [openbsd] - '@esbuild/openbsd-arm64@0.25.4': - resolution: {integrity: sha512-Ct2WcFEANlFDtp1nVAXSNBPDxyU+j7+tId//iHXU2f/lN5AmO4zLyhDcpR5Cz1r08mVxzt3Jpyt4PmXQ1O6+7A==} + '@esbuild/openbsd-arm64@0.25.12': + resolution: {integrity: sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==} engines: {node: '>=18'} cpu: [arm64] os: [openbsd] - '@esbuild/openbsd-arm64@0.25.8': - resolution: {integrity: sha512-j8HgrDuSJFAujkivSMSfPQSAa5Fxbvk4rgNAS5i3K+r8s1X0p1uOO2Hl2xNsGFppOeHOLAVgYwDVlmxhq5h+SQ==} + '@esbuild/openbsd-arm64@0.25.4': + resolution: {integrity: sha512-Ct2WcFEANlFDtp1nVAXSNBPDxyU+j7+tId//iHXU2f/lN5AmO4zLyhDcpR5Cz1r08mVxzt3Jpyt4PmXQ1O6+7A==} engines: {node: '>=18'} cpu: [arm64] os: [openbsd] @@ -1718,20 +1754,20 @@ packages: cpu: [x64] os: [openbsd] - '@esbuild/openbsd-x64@0.25.4': - resolution: {integrity: sha512-xAGGhyOQ9Otm1Xu8NT1ifGLnA6M3sJxZ6ixylb+vIUVzvvd6GOALpwQrYrtlPouMqd/vSbgehz6HaVk4+7Afhw==} + '@esbuild/openbsd-x64@0.25.12': + resolution: {integrity: sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==} engines: {node: '>=18'} cpu: [x64] os: [openbsd] - '@esbuild/openbsd-x64@0.25.8': - resolution: {integrity: sha512-1h8MUAwa0VhNCDp6Af0HToI2TJFAn1uqT9Al6DJVzdIBAd21m/G0Yfc77KDM3uF3T/YaOgQq3qTJHPbTOInaIQ==} + '@esbuild/openbsd-x64@0.25.4': + resolution: {integrity: sha512-xAGGhyOQ9Otm1Xu8NT1ifGLnA6M3sJxZ6ixylb+vIUVzvvd6GOALpwQrYrtlPouMqd/vSbgehz6HaVk4+7Afhw==} engines: {node: '>=18'} cpu: [x64] os: [openbsd] - '@esbuild/openharmony-arm64@0.25.8': - resolution: {integrity: sha512-r2nVa5SIK9tSWd0kJd9HCffnDHKchTGikb//9c7HX+r+wHYCpQrSgxhlY6KWV1nFo1l4KFbsMlHk+L6fekLsUg==} + '@esbuild/openharmony-arm64@0.25.12': + resolution: {integrity: sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==} engines: {node: '>=18'} cpu: [arm64] os: [openharmony] @@ -1754,14 +1790,14 @@ packages: cpu: [x64] os: [sunos] - '@esbuild/sunos-x64@0.25.4': - resolution: {integrity: sha512-Mw+tzy4pp6wZEK0+Lwr76pWLjrtjmJyUB23tHKqEDP74R3q95luY/bXqXZeYl4NYlvwOqoRKlInQialgCKy67Q==} + '@esbuild/sunos-x64@0.25.12': + resolution: {integrity: sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==} engines: {node: '>=18'} cpu: [x64] os: [sunos] - '@esbuild/sunos-x64@0.25.8': - resolution: {integrity: sha512-zUlaP2S12YhQ2UzUfcCuMDHQFJyKABkAjvO5YSndMiIkMimPmxA+BYSBikWgsRpvyxuRnow4nS5NPnf9fpv41w==} + '@esbuild/sunos-x64@0.25.4': + resolution: {integrity: sha512-Mw+tzy4pp6wZEK0+Lwr76pWLjrtjmJyUB23tHKqEDP74R3q95luY/bXqXZeYl4NYlvwOqoRKlInQialgCKy67Q==} engines: {node: '>=18'} cpu: [x64] os: [sunos] @@ -1784,14 +1820,14 @@ packages: cpu: [arm64] os: [win32] - '@esbuild/win32-arm64@0.25.4': - resolution: {integrity: sha512-AVUP428VQTSddguz9dO9ngb+E5aScyg7nOeJDrF1HPYu555gmza3bDGMPhmVXL8svDSoqPCsCPjb265yG/kLKQ==} + '@esbuild/win32-arm64@0.25.12': + resolution: {integrity: sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==} engines: {node: '>=18'} cpu: [arm64] os: [win32] - '@esbuild/win32-arm64@0.25.8': - resolution: {integrity: sha512-YEGFFWESlPva8hGL+zvj2z/SaK+pH0SwOM0Nc/d+rVnW7GSTFlLBGzZkuSU9kFIGIo8q9X3ucpZhu8PDN5A2sQ==} + '@esbuild/win32-arm64@0.25.4': + resolution: {integrity: sha512-AVUP428VQTSddguz9dO9ngb+E5aScyg7nOeJDrF1HPYu555gmza3bDGMPhmVXL8svDSoqPCsCPjb265yG/kLKQ==} engines: {node: '>=18'} cpu: [arm64] os: [win32] @@ -1814,14 +1850,14 @@ packages: cpu: [ia32] os: [win32] - '@esbuild/win32-ia32@0.25.4': - resolution: {integrity: sha512-i1sW+1i+oWvQzSgfRcxxG2k4I9n3O9NRqy8U+uugaT2Dy7kLO9Y7wI72haOahxceMX8hZAzgGou1FhndRldxRg==} + '@esbuild/win32-ia32@0.25.12': + resolution: {integrity: sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==} engines: {node: '>=18'} cpu: [ia32] os: [win32] - '@esbuild/win32-ia32@0.25.8': - resolution: {integrity: sha512-hiGgGC6KZ5LZz58OL/+qVVoZiuZlUYlYHNAmczOm7bs2oE1XriPFi5ZHHrS8ACpV5EjySrnoCKmcbQMN+ojnHg==} + '@esbuild/win32-ia32@0.25.4': + resolution: {integrity: sha512-i1sW+1i+oWvQzSgfRcxxG2k4I9n3O9NRqy8U+uugaT2Dy7kLO9Y7wI72haOahxceMX8hZAzgGou1FhndRldxRg==} engines: {node: '>=18'} cpu: [ia32] os: [win32] @@ -1844,14 +1880,14 @@ packages: cpu: [x64] os: [win32] - '@esbuild/win32-x64@0.25.4': - resolution: {integrity: sha512-nOT2vZNw6hJ+z43oP1SPea/G/6AbN6X+bGNhNuq8NtRHy4wsMhw765IKLNmnjek7GvjWBYQ8Q5VBoYTFg9y1UQ==} + '@esbuild/win32-x64@0.25.12': + resolution: {integrity: sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==} engines: {node: '>=18'} cpu: [x64] os: [win32] - '@esbuild/win32-x64@0.25.8': - resolution: {integrity: sha512-cn3Yr7+OaaZq1c+2pe+8yxC8E144SReCQjN6/2ynubzYjvyqZjTXfQJpAcQpsdJq3My7XADANiYGHoFC69pLQw==} + '@esbuild/win32-x64@0.25.4': + resolution: {integrity: sha512-nOT2vZNw6hJ+z43oP1SPea/G/6AbN6X+bGNhNuq8NtRHy4wsMhw765IKLNmnjek7GvjWBYQ8Q5VBoYTFg9y1UQ==} engines: {node: '>=18'} cpu: [x64] os: [win32] @@ -4353,6 +4389,15 @@ packages: supports-color: optional: true + debug@4.4.3: + resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + decimal.js@10.6.0: resolution: {integrity: sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==} @@ -4637,13 +4682,13 @@ packages: engines: {node: '>=18'} hasBin: true - esbuild@0.25.4: - resolution: {integrity: sha512-8pgjLUcUjcgDg+2Q4NYXnPbo/vncAY4UmyaCm0jZevERqCHZIaWwdJHkf8XQtu4AxSKCdvrUbT0XUr1IdZzI8Q==} + esbuild@0.25.12: + resolution: {integrity: sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==} engines: {node: '>=18'} hasBin: true - esbuild@0.25.8: - resolution: {integrity: sha512-vVC0USHGtMi8+R4Kz8rt6JhEWLxsv9Rnu/lGYbPR8u47B+DCBksq9JarW0zOO7bs37hyOK1l2/oqtbciutL5+Q==} + esbuild@0.25.4: + resolution: {integrity: sha512-8pgjLUcUjcgDg+2Q4NYXnPbo/vncAY4UmyaCm0jZevERqCHZIaWwdJHkf8XQtu4AxSKCdvrUbT0XUr1IdZzI8Q==} engines: {node: '>=18'} hasBin: true @@ -4834,8 +4879,8 @@ packages: resolution: {integrity: sha512-JhFGDVJ7tmDJItKhYgJCGLOWjuK9vPxiXoUFLwLDc99NlmklilbiQJwoctZtt13+xMw91MCk/REan6MWHqDjyA==} engines: {node: '>=12.0.0'} - exponential-backoff@3.1.2: - resolution: {integrity: sha512-8QxYTVXUkuy7fIIoitQkPwGonB8F3Zj8eEO8Sqg9Zv/bkI7RJAzowee4gr81Hak/dUTpA2Z7VfQgoijjPNlUZA==} + exponential-backoff@3.1.3: + resolution: {integrity: sha512-ZgEeZXj30q+I0EN+CbSSpIyPaJ5HVQD18Z1m+u1FXbAeT94mr1zw50q4q6jiiC447Nl/YTcIYSAftiGqetwXCA==} express-rate-limit@7.5.1: resolution: {integrity: sha512-7iN8iPMDzOMHPUYllBEsQdWVB6fPDMPqwjBaFrgr4Jgr/+okjvzAy+UHlYYL/Vs0OsOrMkwS6PJDkFlJwoxUnw==} @@ -4998,6 +5043,10 @@ packages: resolution: {integrity: sha512-Z4XaCL6dUDHfP/jT25jJKMmtxvuwbkrD1vNSMFlo9lNLY2c5FHYSQgHPRZUjAB26TpDEoW9HCOgplrdbaPV/ew==} engines: {node: '>=14.14'} + fs-extra@11.3.3: + resolution: {integrity: sha512-VWSRii4t0AFm6ixFFmLLx1t7wS1gh+ckoa84aOeapGum0h+EZd1EhEumSB+ZdDLnEPuucsVB9oB7cxJHap6Afg==} + engines: {node: '>=14.14'} + fs-extra@7.0.1: resolution: {integrity: sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==} engines: {node: '>=6 <7 || >=8'} @@ -5089,7 +5138,7 @@ packages: glob@8.1.0: resolution: {integrity: sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==} engines: {node: '>=12'} - deprecated: Glob versions prior to v9 are no longer supported + deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me glob@9.3.5: resolution: {integrity: sha512-e1LleDykUz2Iu+MTYdkSsuWX8lvAjAcs0Xef0lNIu0S2wOAzuTxCJtcd9S3cijlwYF18EsU3rzb8jPVobxDh9Q==} @@ -5339,8 +5388,8 @@ packages: inline-style-parser@0.2.4: resolution: {integrity: sha512-0aO8FkhNZlj/ZIbNi7Lxxr12obT7cL1moPfE4tg1LkX7LlLfC6DeX4l2ZEud1ukP9jNQyNnfzQVqwbwmAATY4Q==} - ip-address@9.0.5: - resolution: {integrity: sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==} + ip-address@10.1.0: + resolution: {integrity: sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q==} engines: {node: '>= 12'} ipaddr.js@1.9.1: @@ -5524,9 +5573,6 @@ packages: resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} hasBin: true - jsbn@1.1.0: - resolution: {integrity: sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==} - jsdom@26.1.0: resolution: {integrity: sha512-Cvc9WUhxSMEo4McES3P7oK3QaXldCfNWp7pl2NNeiIFlCoLr3kfq9kb1fxftiwk1FLV7CvpvDfonxtzUDeSOPg==} engines: {node: '>=18'} @@ -5586,6 +5632,9 @@ packages: jsonfile@6.1.0: resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==} + jsonfile@6.2.0: + resolution: {integrity: sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==} + jspdf@2.5.2: resolution: {integrity: sha512-myeX9c+p7znDWPk0eTrujCzNjT+CXdXyk7YmJq5nD5V7uLLKmSXnlQ/Jn/kuo3X09Op70Apm0rQSnFWyGK8uEQ==} @@ -5651,6 +5700,9 @@ packages: lodash@4.17.21: resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + lodash@4.17.23: + resolution: {integrity: sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==} + log-symbols@4.1.0: resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==} engines: {node: '>=10'} @@ -7353,8 +7405,8 @@ packages: resolution: {integrity: sha512-Fgl0YPZ902wEsAyiQ+idGd1A7rSFx/ayC1CQVMw5P+EQx2V0SgpGtf6OKFhVjPflPUl9YMmEOnmfjCdMUsygww==} engines: {node: '>= 10'} - socks@2.8.6: - resolution: {integrity: sha512-pe4Y2yzru68lXCb38aAqRf5gvN8YdjP1lok5o0J7BOHljkyCGKVz7H3vpVIXKD27rj2giOJ7DwVyk/GWrPHDWA==} + socks@2.8.7: + resolution: {integrity: sha512-HLpt+uLy/pxB+bum/9DzAgiKS8CX1EvbWxI4zlmgGCExImLdiad2iCwXT5Z4c9c3Eq8rP2318mPW2c+QbtjK8A==} engines: {node: '>= 10.0.0', npm: '>= 3.0.0'} source-map-js@1.2.1: @@ -8303,6 +8355,13 @@ snapshots: '@ai-sdk/provider-utils': 1.0.9(zod@3.25.76) zod: 3.25.76 + '@ai-sdk/cerebras@0.2.16(zod@3.25.76)': + dependencies: + '@ai-sdk/openai-compatible': 0.2.16(zod@3.25.76) + '@ai-sdk/provider': 1.1.3 + '@ai-sdk/provider-utils': 2.2.8(zod@3.25.76) + zod: 3.25.76 + '@ai-sdk/cohere@1.0.3(zod@3.25.76)': dependencies: '@ai-sdk/provider': 1.0.1 @@ -8316,6 +8375,13 @@ snapshots: '@ai-sdk/provider-utils': 2.1.2(zod@3.25.76) zod: 3.25.76 + '@ai-sdk/fireworks@0.2.16(zod@3.25.76)': + dependencies: + '@ai-sdk/openai-compatible': 0.2.16(zod@3.25.76) + '@ai-sdk/provider': 1.1.3 + '@ai-sdk/provider-utils': 2.2.8(zod@3.25.76) + zod: 3.25.76 + '@ai-sdk/google@0.0.52(zod@3.25.76)': dependencies: '@ai-sdk/provider': 0.0.24 @@ -8335,6 +8401,12 @@ snapshots: '@ai-sdk/provider-utils': 2.1.2(zod@3.25.76) zod: 3.25.76 + '@ai-sdk/openai-compatible@0.2.16(zod@3.25.76)': + dependencies: + '@ai-sdk/provider': 1.1.3 + '@ai-sdk/provider-utils': 2.2.8(zod@3.25.76) + zod: 3.25.76 + '@ai-sdk/openai@1.1.2(zod@3.25.76)': dependencies: '@ai-sdk/provider': 1.0.6 @@ -8876,6 +8948,12 @@ snapshots: js-tokens: 4.0.0 picocolors: 1.1.1 + '@babel/code-frame@7.29.0': + dependencies: + '@babel/helper-validator-identifier': 7.28.5 + js-tokens: 4.0.0 + picocolors: 1.1.1 + '@babel/compat-data@7.28.0': {} '@babel/core@7.28.0': @@ -8982,6 +9060,8 @@ snapshots: '@babel/helper-validator-identifier@7.27.1': {} + '@babel/helper-validator-identifier@7.28.5': {} + '@babel/helper-validator-option@7.27.1': {} '@babel/helpers@7.27.6': @@ -9050,6 +9130,8 @@ snapshots: '@babel/runtime@7.27.6': {} + '@babel/runtime@7.28.6': {} + '@babel/template@7.27.2': dependencies: '@babel/code-frame': 7.27.1 @@ -9319,7 +9401,7 @@ snapshots: '@electron/node-gyp@https://codeload.github.com/electron/node-gyp/tar.gz/06b29aafb7708acef8b3669835c8a7857ebc92d2': dependencies: env-paths: 2.2.1 - exponential-backoff: 3.1.2 + exponential-backoff: 3.1.3 glob: 8.1.0 graceful-fs: 4.2.11 make-fetch-happen: 10.2.1 @@ -9386,8 +9468,8 @@ snapshots: '@electron/windows-sign@1.2.2': dependencies: cross-dirname: 0.1.0 - debug: 4.4.1 - fs-extra: 11.3.0 + debug: 4.4.3 + fs-extra: 11.3.3 minimist: 1.2.8 postject: 1.0.0-alpha.6 transitivePeerDependencies: @@ -9407,10 +9489,10 @@ snapshots: '@esbuild/aix-ppc64@0.23.1': optional: true - '@esbuild/aix-ppc64@0.25.4': + '@esbuild/aix-ppc64@0.25.12': optional: true - '@esbuild/aix-ppc64@0.25.8': + '@esbuild/aix-ppc64@0.25.4': optional: true '@esbuild/android-arm64@0.17.6': @@ -9422,10 +9504,10 @@ snapshots: '@esbuild/android-arm64@0.23.1': optional: true - '@esbuild/android-arm64@0.25.4': + '@esbuild/android-arm64@0.25.12': optional: true - '@esbuild/android-arm64@0.25.8': + '@esbuild/android-arm64@0.25.4': optional: true '@esbuild/android-arm@0.17.6': @@ -9437,10 +9519,10 @@ snapshots: '@esbuild/android-arm@0.23.1': optional: true - '@esbuild/android-arm@0.25.4': + '@esbuild/android-arm@0.25.12': optional: true - '@esbuild/android-arm@0.25.8': + '@esbuild/android-arm@0.25.4': optional: true '@esbuild/android-x64@0.17.6': @@ -9452,10 +9534,10 @@ snapshots: '@esbuild/android-x64@0.23.1': optional: true - '@esbuild/android-x64@0.25.4': + '@esbuild/android-x64@0.25.12': optional: true - '@esbuild/android-x64@0.25.8': + '@esbuild/android-x64@0.25.4': optional: true '@esbuild/darwin-arm64@0.17.6': @@ -9467,10 +9549,10 @@ snapshots: '@esbuild/darwin-arm64@0.23.1': optional: true - '@esbuild/darwin-arm64@0.25.4': + '@esbuild/darwin-arm64@0.25.12': optional: true - '@esbuild/darwin-arm64@0.25.8': + '@esbuild/darwin-arm64@0.25.4': optional: true '@esbuild/darwin-x64@0.17.6': @@ -9482,10 +9564,10 @@ snapshots: '@esbuild/darwin-x64@0.23.1': optional: true - '@esbuild/darwin-x64@0.25.4': + '@esbuild/darwin-x64@0.25.12': optional: true - '@esbuild/darwin-x64@0.25.8': + '@esbuild/darwin-x64@0.25.4': optional: true '@esbuild/freebsd-arm64@0.17.6': @@ -9497,10 +9579,10 @@ snapshots: '@esbuild/freebsd-arm64@0.23.1': optional: true - '@esbuild/freebsd-arm64@0.25.4': + '@esbuild/freebsd-arm64@0.25.12': optional: true - '@esbuild/freebsd-arm64@0.25.8': + '@esbuild/freebsd-arm64@0.25.4': optional: true '@esbuild/freebsd-x64@0.17.6': @@ -9512,10 +9594,10 @@ snapshots: '@esbuild/freebsd-x64@0.23.1': optional: true - '@esbuild/freebsd-x64@0.25.4': + '@esbuild/freebsd-x64@0.25.12': optional: true - '@esbuild/freebsd-x64@0.25.8': + '@esbuild/freebsd-x64@0.25.4': optional: true '@esbuild/linux-arm64@0.17.6': @@ -9527,10 +9609,10 @@ snapshots: '@esbuild/linux-arm64@0.23.1': optional: true - '@esbuild/linux-arm64@0.25.4': + '@esbuild/linux-arm64@0.25.12': optional: true - '@esbuild/linux-arm64@0.25.8': + '@esbuild/linux-arm64@0.25.4': optional: true '@esbuild/linux-arm@0.17.6': @@ -9542,10 +9624,10 @@ snapshots: '@esbuild/linux-arm@0.23.1': optional: true - '@esbuild/linux-arm@0.25.4': + '@esbuild/linux-arm@0.25.12': optional: true - '@esbuild/linux-arm@0.25.8': + '@esbuild/linux-arm@0.25.4': optional: true '@esbuild/linux-ia32@0.17.6': @@ -9557,10 +9639,10 @@ snapshots: '@esbuild/linux-ia32@0.23.1': optional: true - '@esbuild/linux-ia32@0.25.4': + '@esbuild/linux-ia32@0.25.12': optional: true - '@esbuild/linux-ia32@0.25.8': + '@esbuild/linux-ia32@0.25.4': optional: true '@esbuild/linux-loong64@0.17.6': @@ -9572,10 +9654,10 @@ snapshots: '@esbuild/linux-loong64@0.23.1': optional: true - '@esbuild/linux-loong64@0.25.4': + '@esbuild/linux-loong64@0.25.12': optional: true - '@esbuild/linux-loong64@0.25.8': + '@esbuild/linux-loong64@0.25.4': optional: true '@esbuild/linux-mips64el@0.17.6': @@ -9587,10 +9669,10 @@ snapshots: '@esbuild/linux-mips64el@0.23.1': optional: true - '@esbuild/linux-mips64el@0.25.4': + '@esbuild/linux-mips64el@0.25.12': optional: true - '@esbuild/linux-mips64el@0.25.8': + '@esbuild/linux-mips64el@0.25.4': optional: true '@esbuild/linux-ppc64@0.17.6': @@ -9602,10 +9684,10 @@ snapshots: '@esbuild/linux-ppc64@0.23.1': optional: true - '@esbuild/linux-ppc64@0.25.4': + '@esbuild/linux-ppc64@0.25.12': optional: true - '@esbuild/linux-ppc64@0.25.8': + '@esbuild/linux-ppc64@0.25.4': optional: true '@esbuild/linux-riscv64@0.17.6': @@ -9617,10 +9699,10 @@ snapshots: '@esbuild/linux-riscv64@0.23.1': optional: true - '@esbuild/linux-riscv64@0.25.4': + '@esbuild/linux-riscv64@0.25.12': optional: true - '@esbuild/linux-riscv64@0.25.8': + '@esbuild/linux-riscv64@0.25.4': optional: true '@esbuild/linux-s390x@0.17.6': @@ -9632,10 +9714,10 @@ snapshots: '@esbuild/linux-s390x@0.23.1': optional: true - '@esbuild/linux-s390x@0.25.4': + '@esbuild/linux-s390x@0.25.12': optional: true - '@esbuild/linux-s390x@0.25.8': + '@esbuild/linux-s390x@0.25.4': optional: true '@esbuild/linux-x64@0.17.6': @@ -9647,16 +9729,16 @@ snapshots: '@esbuild/linux-x64@0.23.1': optional: true - '@esbuild/linux-x64@0.25.4': + '@esbuild/linux-x64@0.25.12': optional: true - '@esbuild/linux-x64@0.25.8': + '@esbuild/linux-x64@0.25.4': optional: true - '@esbuild/netbsd-arm64@0.25.4': + '@esbuild/netbsd-arm64@0.25.12': optional: true - '@esbuild/netbsd-arm64@0.25.8': + '@esbuild/netbsd-arm64@0.25.4': optional: true '@esbuild/netbsd-x64@0.17.6': @@ -9668,19 +9750,19 @@ snapshots: '@esbuild/netbsd-x64@0.23.1': optional: true - '@esbuild/netbsd-x64@0.25.4': + '@esbuild/netbsd-x64@0.25.12': optional: true - '@esbuild/netbsd-x64@0.25.8': + '@esbuild/netbsd-x64@0.25.4': optional: true '@esbuild/openbsd-arm64@0.23.1': optional: true - '@esbuild/openbsd-arm64@0.25.4': + '@esbuild/openbsd-arm64@0.25.12': optional: true - '@esbuild/openbsd-arm64@0.25.8': + '@esbuild/openbsd-arm64@0.25.4': optional: true '@esbuild/openbsd-x64@0.17.6': @@ -9692,13 +9774,13 @@ snapshots: '@esbuild/openbsd-x64@0.23.1': optional: true - '@esbuild/openbsd-x64@0.25.4': + '@esbuild/openbsd-x64@0.25.12': optional: true - '@esbuild/openbsd-x64@0.25.8': + '@esbuild/openbsd-x64@0.25.4': optional: true - '@esbuild/openharmony-arm64@0.25.8': + '@esbuild/openharmony-arm64@0.25.12': optional: true '@esbuild/sunos-x64@0.17.6': @@ -9710,10 +9792,10 @@ snapshots: '@esbuild/sunos-x64@0.23.1': optional: true - '@esbuild/sunos-x64@0.25.4': + '@esbuild/sunos-x64@0.25.12': optional: true - '@esbuild/sunos-x64@0.25.8': + '@esbuild/sunos-x64@0.25.4': optional: true '@esbuild/win32-arm64@0.17.6': @@ -9725,10 +9807,10 @@ snapshots: '@esbuild/win32-arm64@0.23.1': optional: true - '@esbuild/win32-arm64@0.25.4': + '@esbuild/win32-arm64@0.25.12': optional: true - '@esbuild/win32-arm64@0.25.8': + '@esbuild/win32-arm64@0.25.4': optional: true '@esbuild/win32-ia32@0.17.6': @@ -9740,10 +9822,10 @@ snapshots: '@esbuild/win32-ia32@0.23.1': optional: true - '@esbuild/win32-ia32@0.25.4': + '@esbuild/win32-ia32@0.25.12': optional: true - '@esbuild/win32-ia32@0.25.8': + '@esbuild/win32-ia32@0.25.4': optional: true '@esbuild/win32-x64@0.17.6': @@ -9755,10 +9837,10 @@ snapshots: '@esbuild/win32-x64@0.23.1': optional: true - '@esbuild/win32-x64@0.25.4': + '@esbuild/win32-x64@0.25.12': optional: true - '@esbuild/win32-x64@0.25.8': + '@esbuild/win32-x64@0.25.4': optional: true '@eslint-community/eslint-utils@4.7.0(eslint@9.31.0(jiti@1.21.7))': @@ -11393,8 +11475,8 @@ snapshots: '@testing-library/dom@10.4.0': dependencies: - '@babel/code-frame': 7.27.1 - '@babel/runtime': 7.27.6 + '@babel/code-frame': 7.29.0 + '@babel/runtime': 7.28.6 '@types/aria-query': 5.0.4 aria-query: 5.3.0 chalk: 4.1.2 @@ -12006,7 +12088,7 @@ snapshots: agent-base@6.0.2: dependencies: - debug: 4.4.1 + debug: 4.4.3 transitivePeerDependencies: - supports-color @@ -12802,6 +12884,10 @@ snapshots: dependencies: ms: 2.1.3 + debug@4.4.3: + dependencies: + ms: 2.1.3 + decimal.js@10.6.0: {} decode-named-character-reference@1.2.0: @@ -13029,9 +13115,9 @@ snapshots: electron-winstaller@5.4.0: dependencies: '@electron/asar': 3.4.1 - debug: 4.4.1 + debug: 4.4.3 fs-extra: 7.0.1 - lodash: 4.17.21 + lodash: 4.17.23 temp: 0.9.4 optionalDependencies: '@electron/windows-sign': 1.2.2 @@ -13190,6 +13276,35 @@ snapshots: '@esbuild/win32-ia32': 0.23.1 '@esbuild/win32-x64': 0.23.1 + esbuild@0.25.12: + optionalDependencies: + '@esbuild/aix-ppc64': 0.25.12 + '@esbuild/android-arm': 0.25.12 + '@esbuild/android-arm64': 0.25.12 + '@esbuild/android-x64': 0.25.12 + '@esbuild/darwin-arm64': 0.25.12 + '@esbuild/darwin-x64': 0.25.12 + '@esbuild/freebsd-arm64': 0.25.12 + '@esbuild/freebsd-x64': 0.25.12 + '@esbuild/linux-arm': 0.25.12 + '@esbuild/linux-arm64': 0.25.12 + '@esbuild/linux-ia32': 0.25.12 + '@esbuild/linux-loong64': 0.25.12 + '@esbuild/linux-mips64el': 0.25.12 + '@esbuild/linux-ppc64': 0.25.12 + '@esbuild/linux-riscv64': 0.25.12 + '@esbuild/linux-s390x': 0.25.12 + '@esbuild/linux-x64': 0.25.12 + '@esbuild/netbsd-arm64': 0.25.12 + '@esbuild/netbsd-x64': 0.25.12 + '@esbuild/openbsd-arm64': 0.25.12 + '@esbuild/openbsd-x64': 0.25.12 + '@esbuild/openharmony-arm64': 0.25.12 + '@esbuild/sunos-x64': 0.25.12 + '@esbuild/win32-arm64': 0.25.12 + '@esbuild/win32-ia32': 0.25.12 + '@esbuild/win32-x64': 0.25.12 + esbuild@0.25.4: optionalDependencies: '@esbuild/aix-ppc64': 0.25.4 @@ -13218,35 +13333,6 @@ snapshots: '@esbuild/win32-ia32': 0.25.4 '@esbuild/win32-x64': 0.25.4 - esbuild@0.25.8: - optionalDependencies: - '@esbuild/aix-ppc64': 0.25.8 - '@esbuild/android-arm': 0.25.8 - '@esbuild/android-arm64': 0.25.8 - '@esbuild/android-x64': 0.25.8 - '@esbuild/darwin-arm64': 0.25.8 - '@esbuild/darwin-x64': 0.25.8 - '@esbuild/freebsd-arm64': 0.25.8 - '@esbuild/freebsd-x64': 0.25.8 - '@esbuild/linux-arm': 0.25.8 - '@esbuild/linux-arm64': 0.25.8 - '@esbuild/linux-ia32': 0.25.8 - '@esbuild/linux-loong64': 0.25.8 - '@esbuild/linux-mips64el': 0.25.8 - '@esbuild/linux-ppc64': 0.25.8 - '@esbuild/linux-riscv64': 0.25.8 - '@esbuild/linux-s390x': 0.25.8 - '@esbuild/linux-x64': 0.25.8 - '@esbuild/netbsd-arm64': 0.25.8 - '@esbuild/netbsd-x64': 0.25.8 - '@esbuild/openbsd-arm64': 0.25.8 - '@esbuild/openbsd-x64': 0.25.8 - '@esbuild/openharmony-arm64': 0.25.8 - '@esbuild/sunos-x64': 0.25.8 - '@esbuild/win32-arm64': 0.25.8 - '@esbuild/win32-ia32': 0.25.8 - '@esbuild/win32-x64': 0.25.8 - escalade@3.2.0: {} escape-html@1.0.3: {} @@ -13460,7 +13546,7 @@ snapshots: expect-type@1.2.2: {} - exponential-backoff@3.1.2: {} + exponential-backoff@3.1.3: {} express-rate-limit@7.5.1(express@5.1.0): dependencies: @@ -13695,6 +13781,13 @@ snapshots: jsonfile: 6.1.0 universalify: 2.0.1 + fs-extra@11.3.3: + dependencies: + graceful-fs: 4.2.11 + jsonfile: 6.2.0 + universalify: 2.0.1 + optional: true + fs-extra@7.0.1: dependencies: graceful-fs: 4.2.11 @@ -14058,7 +14151,7 @@ snapshots: dependencies: '@tootallnate/once': 2.0.0 agent-base: 6.0.2 - debug: 4.4.1 + debug: 4.4.3 transitivePeerDependencies: - supports-color @@ -14079,7 +14172,7 @@ snapshots: https-proxy-agent@5.0.1: dependencies: agent-base: 6.0.2 - debug: 4.4.1 + debug: 4.4.3 transitivePeerDependencies: - supports-color @@ -14162,10 +14255,7 @@ snapshots: inline-style-parser@0.2.4: {} - ip-address@9.0.5: - dependencies: - jsbn: 1.1.0 - sprintf-js: 1.1.3 + ip-address@10.1.0: {} ipaddr.js@1.9.1: {} @@ -14324,8 +14414,6 @@ snapshots: dependencies: argparse: 2.0.1 - jsbn@1.1.0: {} - jsdom@26.1.0: dependencies: cssstyle: 4.6.0 @@ -14397,6 +14485,13 @@ snapshots: optionalDependencies: graceful-fs: 4.2.11 + jsonfile@6.2.0: + dependencies: + universalify: 2.0.1 + optionalDependencies: + graceful-fs: 4.2.11 + optional: true + jspdf@2.5.2: dependencies: '@babel/runtime': 7.27.6 @@ -14463,6 +14558,8 @@ snapshots: lodash@4.17.21: {} + lodash@4.17.23: {} + log-symbols@4.1.0: dependencies: chalk: 4.1.2 @@ -16680,14 +16777,14 @@ snapshots: socks-proxy-agent@7.0.0: dependencies: agent-base: 6.0.2 - debug: 4.4.1 - socks: 2.8.6 + debug: 4.4.3 + socks: 2.8.7 transitivePeerDependencies: - supports-color - socks@2.8.6: + socks@2.8.7: dependencies: - ip-address: 9.0.5 + ip-address: 10.1.0 smart-buffer: 4.2.0 source-map-js@1.2.1: {} @@ -16721,7 +16818,8 @@ snapshots: spdx-license-ids@3.0.21: {} - sprintf-js@1.1.3: {} + sprintf-js@1.1.3: + optional: true ssri@10.0.6: dependencies: @@ -17006,7 +17104,7 @@ snapshots: tsx@4.20.3: dependencies: - esbuild: 0.25.8 + esbuild: 0.25.12 get-tsconfig: 4.10.1 optionalDependencies: fsevents: 2.3.3 diff --git a/vite.config.ts.timestamp-1770328346417-a90f095482a09.mjs b/vite.config.ts.timestamp-1770328346417-a90f095482a09.mjs new file mode 100644 index 0000000000..b22de5a82e --- /dev/null +++ b/vite.config.ts.timestamp-1770328346417-a90f095482a09.mjs @@ -0,0 +1,110 @@ +// vite.config.ts +import { cloudflareDevProxyVitePlugin as remixCloudflareDevProxy, vitePlugin as remixVitePlugin } from "file:///Users/stijnus/Documents/GitHub/bolt.diy/node_modules/.pnpm/@remix-run+dev@2.16.8_@remix-run+react@2.16.8_react-dom@18.3.1_react@18.3.1__react@18.3.1_typ_uozynh2jdinnz6binv6akofmd4/node_modules/@remix-run/dev/dist/index.js"; +import UnoCSS from "file:///Users/stijnus/Documents/GitHub/bolt.diy/node_modules/.pnpm/unocss@0.61.9_postcss@8.5.6_rollup@4.45.1_vite@5.4.19_@types+node@24.1.0_sass-embedded@1.89.2_/node_modules/unocss/dist/vite.mjs"; +import { defineConfig } from "file:///Users/stijnus/Documents/GitHub/bolt.diy/node_modules/.pnpm/vite@5.4.19_@types+node@24.1.0_sass-embedded@1.89.2/node_modules/vite/dist/node/index.js"; +import { nodePolyfills } from "file:///Users/stijnus/Documents/GitHub/bolt.diy/node_modules/.pnpm/vite-plugin-node-polyfills@0.22.0_rollup@4.45.1_vite@5.4.19_@types+node@24.1.0_sass-embedded@1.89.2_/node_modules/vite-plugin-node-polyfills/dist/index.js"; +import { optimizeCssModules } from "file:///Users/stijnus/Documents/GitHub/bolt.diy/node_modules/.pnpm/vite-plugin-optimize-css-modules@1.2.0_vite@5.4.19_@types+node@24.1.0_sass-embedded@1.89.2_/node_modules/vite-plugin-optimize-css-modules/dist/index.mjs"; +import tsconfigPaths from "file:///Users/stijnus/Documents/GitHub/bolt.diy/node_modules/.pnpm/vite-tsconfig-paths@4.3.2_typescript@5.8.3_vite@5.4.19_@types+node@24.1.0_sass-embedded@1.89.2_/node_modules/vite-tsconfig-paths/dist/index.mjs"; +import * as dotenv from "file:///Users/stijnus/Documents/GitHub/bolt.diy/node_modules/.pnpm/dotenv@16.6.1/node_modules/dotenv/lib/main.js"; +dotenv.config({ path: ".env.local" }); +dotenv.config({ path: ".env" }); +dotenv.config(); +var vite_config_default = defineConfig((config2) => { + return { + define: { + "process.env.NODE_ENV": JSON.stringify(process.env.NODE_ENV) + }, + build: { + target: "esnext" + }, + plugins: [ + nodePolyfills({ + include: ["buffer", "process", "util", "stream"], + globals: { + Buffer: true, + process: true, + global: true + }, + protocolImports: true, + exclude: ["child_process", "fs", "path"] + }), + { + name: "buffer-polyfill", + transform(code, id) { + if (id.includes("env.mjs")) { + return { + code: `import { Buffer } from 'buffer'; +${code}`, + map: null + }; + } + return null; + } + }, + config2.mode !== "test" && remixCloudflareDevProxy(), + remixVitePlugin({ + future: { + v3_fetcherPersist: true, + v3_relativeSplatPath: true, + v3_throwAbortReason: true, + v3_lazyRouteDiscovery: true + } + }), + UnoCSS(), + tsconfigPaths(), + chrome129IssuePlugin(), + config2.mode === "production" && optimizeCssModules({ apply: "build" }) + ], + envPrefix: [ + "VITE_", + "OPENAI_LIKE_API_BASE_URL", + "OPENAI_LIKE_API_MODELS", + "OLLAMA_API_BASE_URL", + "LMSTUDIO_API_BASE_URL", + "TOGETHER_API_BASE_URL" + ], + css: { + preprocessorOptions: { + scss: { + api: "modern-compiler" + } + } + }, + test: { + exclude: [ + "**/node_modules/**", + "**/dist/**", + "**/cypress/**", + "**/.{idea,git,cache,output,temp}/**", + "**/{karma,rollup,webpack,vite,vitest,jest,ava,babel,nyc,cypress,tsup,build}.config.*", + "**/tests/preview/**" + // Exclude preview tests that require Playwright + ] + } + }; +}); +function chrome129IssuePlugin() { + return { + name: "chrome129IssuePlugin", + configureServer(server) { + server.middlewares.use((req, res, next) => { + const raw = req.headers["user-agent"]?.match(/Chrom(e|ium)\/([0-9]+)\./); + if (raw) { + const version = parseInt(raw[2], 10); + if (version === 129) { + res.setHeader("content-type", "text/html"); + res.end( + '

Please use Chrome Canary for testing.

Chrome 129 has an issue with JavaScript modules & Vite local development, see for more information.

Note: This only impacts local development. `pnpm run build` and `pnpm run start` will work fine in this browser.

' + ); + return; + } + } + next(); + }); + } + }; +} +export { + vite_config_default as default +}; +//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsidml0ZS5jb25maWcudHMiXSwKICAic291cmNlc0NvbnRlbnQiOiBbImNvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9kaXJuYW1lID0gXCIvVXNlcnMvc3Rpam51cy9Eb2N1bWVudHMvR2l0SHViL2JvbHQuZGl5XCI7Y29uc3QgX192aXRlX2luamVjdGVkX29yaWdpbmFsX2ZpbGVuYW1lID0gXCIvVXNlcnMvc3Rpam51cy9Eb2N1bWVudHMvR2l0SHViL2JvbHQuZGl5L3ZpdGUuY29uZmlnLnRzXCI7Y29uc3QgX192aXRlX2luamVjdGVkX29yaWdpbmFsX2ltcG9ydF9tZXRhX3VybCA9IFwiZmlsZTovLy9Vc2Vycy9zdGlqbnVzL0RvY3VtZW50cy9HaXRIdWIvYm9sdC5kaXkvdml0ZS5jb25maWcudHNcIjtpbXBvcnQgeyBjbG91ZGZsYXJlRGV2UHJveHlWaXRlUGx1Z2luIGFzIHJlbWl4Q2xvdWRmbGFyZURldlByb3h5LCB2aXRlUGx1Z2luIGFzIHJlbWl4Vml0ZVBsdWdpbiB9IGZyb20gJ0ByZW1peC1ydW4vZGV2JztcbmltcG9ydCBVbm9DU1MgZnJvbSAndW5vY3NzL3ZpdGUnO1xuaW1wb3J0IHsgZGVmaW5lQ29uZmlnLCB0eXBlIFZpdGVEZXZTZXJ2ZXIgfSBmcm9tICd2aXRlJztcbmltcG9ydCB7IG5vZGVQb2x5ZmlsbHMgfSBmcm9tICd2aXRlLXBsdWdpbi1ub2RlLXBvbHlmaWxscyc7XG5pbXBvcnQgeyBvcHRpbWl6ZUNzc01vZHVsZXMgfSBmcm9tICd2aXRlLXBsdWdpbi1vcHRpbWl6ZS1jc3MtbW9kdWxlcyc7XG5pbXBvcnQgdHNjb25maWdQYXRocyBmcm9tICd2aXRlLXRzY29uZmlnLXBhdGhzJztcbmltcG9ydCAqIGFzIGRvdGVudiBmcm9tICdkb3RlbnYnO1xuXG4vLyBMb2FkIGVudmlyb25tZW50IHZhcmlhYmxlcyBmcm9tIG11bHRpcGxlIGZpbGVzXG5kb3RlbnYuY29uZmlnKHsgcGF0aDogJy5lbnYubG9jYWwnIH0pO1xuZG90ZW52LmNvbmZpZyh7IHBhdGg6ICcuZW52JyB9KTtcbmRvdGVudi5jb25maWcoKTtcblxuZXhwb3J0IGRlZmF1bHQgZGVmaW5lQ29uZmlnKChjb25maWcpID0+IHtcbiAgcmV0dXJuIHtcbiAgICBkZWZpbmU6IHtcbiAgICAgICdwcm9jZXNzLmVudi5OT0RFX0VOVic6IEpTT04uc3RyaW5naWZ5KHByb2Nlc3MuZW52Lk5PREVfRU5WKSxcbiAgICB9LFxuICAgIGJ1aWxkOiB7XG4gICAgICB0YXJnZXQ6ICdlc25leHQnLFxuICAgIH0sXG4gICAgcGx1Z2luczogW1xuICAgICAgbm9kZVBvbHlmaWxscyh7XG4gICAgICAgIGluY2x1ZGU6IFsnYnVmZmVyJywgJ3Byb2Nlc3MnLCAndXRpbCcsICdzdHJlYW0nXSxcbiAgICAgICAgZ2xvYmFsczoge1xuICAgICAgICAgIEJ1ZmZlcjogdHJ1ZSxcbiAgICAgICAgICBwcm9jZXNzOiB0cnVlLFxuICAgICAgICAgIGdsb2JhbDogdHJ1ZSxcbiAgICAgICAgfSxcbiAgICAgICAgcHJvdG9jb2xJbXBvcnRzOiB0cnVlLFxuICAgICAgICBleGNsdWRlOiBbJ2NoaWxkX3Byb2Nlc3MnLCAnZnMnLCAncGF0aCddLFxuICAgICAgfSksXG4gICAgICB7XG4gICAgICAgIG5hbWU6ICdidWZmZXItcG9seWZpbGwnLFxuICAgICAgICB0cmFuc2Zvcm0oY29kZSwgaWQpIHtcbiAgICAgICAgICBpZiAoaWQuaW5jbHVkZXMoJ2Vudi5tanMnKSkge1xuICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgY29kZTogYGltcG9ydCB7IEJ1ZmZlciB9IGZyb20gJ2J1ZmZlcic7XFxuJHtjb2RlfWAsXG4gICAgICAgICAgICAgIG1hcDogbnVsbCxcbiAgICAgICAgICAgIH07XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICAgIH0sXG4gICAgICB9LFxuICAgICAgY29uZmlnLm1vZGUgIT09ICd0ZXN0JyAmJiByZW1peENsb3VkZmxhcmVEZXZQcm94eSgpLFxuICAgICAgcmVtaXhWaXRlUGx1Z2luKHtcbiAgICAgICAgZnV0dXJlOiB7XG4gICAgICAgICAgdjNfZmV0Y2hlclBlcnNpc3Q6IHRydWUsXG4gICAgICAgICAgdjNfcmVsYXRpdmVTcGxhdFBhdGg6IHRydWUsXG4gICAgICAgICAgdjNfdGhyb3dBYm9ydFJlYXNvbjogdHJ1ZSxcbiAgICAgICAgICB2M19sYXp5Um91dGVEaXNjb3Zlcnk6IHRydWUsXG4gICAgICAgIH0sXG4gICAgICB9KSxcbiAgICAgIFVub0NTUygpLFxuICAgICAgdHNjb25maWdQYXRocygpLFxuICAgICAgY2hyb21lMTI5SXNzdWVQbHVnaW4oKSxcbiAgICAgIGNvbmZpZy5tb2RlID09PSAncHJvZHVjdGlvbicgJiYgb3B0aW1pemVDc3NNb2R1bGVzKHsgYXBwbHk6ICdidWlsZCcgfSksXG4gICAgXSxcbiAgICBlbnZQcmVmaXg6IFtcbiAgICAgICdWSVRFXycsXG4gICAgICAnT1BFTkFJX0xJS0VfQVBJX0JBU0VfVVJMJyxcbiAgICAgICdPUEVOQUlfTElLRV9BUElfTU9ERUxTJyxcbiAgICAgICdPTExBTUFfQVBJX0JBU0VfVVJMJyxcbiAgICAgICdMTVNUVURJT19BUElfQkFTRV9VUkwnLFxuICAgICAgJ1RPR0VUSEVSX0FQSV9CQVNFX1VSTCcsXG4gICAgXSxcbiAgICBjc3M6IHtcbiAgICAgIHByZXByb2Nlc3Nvck9wdGlvbnM6IHtcbiAgICAgICAgc2Nzczoge1xuICAgICAgICAgIGFwaTogJ21vZGVybi1jb21waWxlcicsXG4gICAgICAgIH0sXG4gICAgICB9LFxuICAgIH0sXG4gICAgdGVzdDoge1xuICAgICAgZXhjbHVkZTogW1xuICAgICAgICAnKiovbm9kZV9tb2R1bGVzLyoqJyxcbiAgICAgICAgJyoqL2Rpc3QvKionLFxuICAgICAgICAnKiovY3lwcmVzcy8qKicsXG4gICAgICAgICcqKi8ue2lkZWEsZ2l0LGNhY2hlLG91dHB1dCx0ZW1wfS8qKicsXG4gICAgICAgICcqKi97a2FybWEscm9sbHVwLHdlYnBhY2ssdml0ZSx2aXRlc3QsamVzdCxhdmEsYmFiZWwsbnljLGN5cHJlc3MsdHN1cCxidWlsZH0uY29uZmlnLionLFxuICAgICAgICAnKiovdGVzdHMvcHJldmlldy8qKicsIC8vIEV4Y2x1ZGUgcHJldmlldyB0ZXN0cyB0aGF0IHJlcXVpcmUgUGxheXdyaWdodFxuICAgICAgXSxcbiAgICB9LFxuICB9O1xufSk7XG5cbmZ1bmN0aW9uIGNocm9tZTEyOUlzc3VlUGx1Z2luKCkge1xuICByZXR1cm4ge1xuICAgIG5hbWU6ICdjaHJvbWUxMjlJc3N1ZVBsdWdpbicsXG4gICAgY29uZmlndXJlU2VydmVyKHNlcnZlcjogVml0ZURldlNlcnZlcikge1xuICAgICAgc2VydmVyLm1pZGRsZXdhcmVzLnVzZSgocmVxLCByZXMsIG5leHQpID0+IHtcbiAgICAgICAgY29uc3QgcmF3ID0gcmVxLmhlYWRlcnNbJ3VzZXItYWdlbnQnXT8ubWF0Y2goL0Nocm9tKGV8aXVtKVxcLyhbMC05XSspXFwuLyk7XG5cbiAgICAgICAgaWYgKHJhdykge1xuICAgICAgICAgIGNvbnN0IHZlcnNpb24gPSBwYXJzZUludChyYXdbMl0sIDEwKTtcblxuICAgICAgICAgIGlmICh2ZXJzaW9uID09PSAxMjkpIHtcbiAgICAgICAgICAgIHJlcy5zZXRIZWFkZXIoJ2NvbnRlbnQtdHlwZScsICd0ZXh0L2h0bWwnKTtcbiAgICAgICAgICAgIHJlcy5lbmQoXG4gICAgICAgICAgICAgICc8Ym9keT48aDE+UGxlYXNlIHVzZSBDaHJvbWUgQ2FuYXJ5IGZvciB0ZXN0aW5nLjwvaDE+PHA+Q2hyb21lIDEyOSBoYXMgYW4gaXNzdWUgd2l0aCBKYXZhU2NyaXB0IG1vZHVsZXMgJiBWaXRlIGxvY2FsIGRldmVsb3BtZW50LCBzZWUgPGEgaHJlZj1cImh0dHBzOi8vZ2l0aHViLmNvbS9zdGFja2JsaXR6L2JvbHQubmV3L2lzc3Vlcy84NiNpc3N1ZWNvbW1lbnQtMjM5NTUxOTI1OFwiPmZvciBtb3JlIGluZm9ybWF0aW9uLjwvYT48L3A+PHA+PGI+Tm90ZTo8L2I+IFRoaXMgb25seSBpbXBhY3RzIDx1PmxvY2FsIGRldmVsb3BtZW50PC91Pi4gYHBucG0gcnVuIGJ1aWxkYCBhbmQgYHBucG0gcnVuIHN0YXJ0YCB3aWxsIHdvcmsgZmluZSBpbiB0aGlzIGJyb3dzZXIuPC9wPjwvYm9keT4nLFxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIG5leHQoKTtcbiAgICAgIH0pO1xuICAgIH0sXG4gIH07XG59Il0sCiAgIm1hcHBpbmdzIjogIjtBQUEwUyxTQUFTLGdDQUFnQyx5QkFBeUIsY0FBYyx1QkFBdUI7QUFDalosT0FBTyxZQUFZO0FBQ25CLFNBQVMsb0JBQXdDO0FBQ2pELFNBQVMscUJBQXFCO0FBQzlCLFNBQVMsMEJBQTBCO0FBQ25DLE9BQU8sbUJBQW1CO0FBQzFCLFlBQVksWUFBWTtBQUdqQixjQUFPLEVBQUUsTUFBTSxhQUFhLENBQUM7QUFDN0IsY0FBTyxFQUFFLE1BQU0sT0FBTyxDQUFDO0FBQ3ZCLGNBQU87QUFFZCxJQUFPLHNCQUFRLGFBQWEsQ0FBQ0EsWUFBVztBQUN0QyxTQUFPO0FBQUEsSUFDTCxRQUFRO0FBQUEsTUFDTix3QkFBd0IsS0FBSyxVQUFVLFFBQVEsSUFBSSxRQUFRO0FBQUEsSUFDN0Q7QUFBQSxJQUNBLE9BQU87QUFBQSxNQUNMLFFBQVE7QUFBQSxJQUNWO0FBQUEsSUFDQSxTQUFTO0FBQUEsTUFDUCxjQUFjO0FBQUEsUUFDWixTQUFTLENBQUMsVUFBVSxXQUFXLFFBQVEsUUFBUTtBQUFBLFFBQy9DLFNBQVM7QUFBQSxVQUNQLFFBQVE7QUFBQSxVQUNSLFNBQVM7QUFBQSxVQUNULFFBQVE7QUFBQSxRQUNWO0FBQUEsUUFDQSxpQkFBaUI7QUFBQSxRQUNqQixTQUFTLENBQUMsaUJBQWlCLE1BQU0sTUFBTTtBQUFBLE1BQ3pDLENBQUM7QUFBQSxNQUNEO0FBQUEsUUFDRSxNQUFNO0FBQUEsUUFDTixVQUFVLE1BQU0sSUFBSTtBQUNsQixjQUFJLEdBQUcsU0FBUyxTQUFTLEdBQUc7QUFDMUIsbUJBQU87QUFBQSxjQUNMLE1BQU07QUFBQSxFQUFxQyxJQUFJO0FBQUEsY0FDL0MsS0FBSztBQUFBLFlBQ1A7QUFBQSxVQUNGO0FBRUEsaUJBQU87QUFBQSxRQUNUO0FBQUEsTUFDRjtBQUFBLE1BQ0FBLFFBQU8sU0FBUyxVQUFVLHdCQUF3QjtBQUFBLE1BQ2xELGdCQUFnQjtBQUFBLFFBQ2QsUUFBUTtBQUFBLFVBQ04sbUJBQW1CO0FBQUEsVUFDbkIsc0JBQXNCO0FBQUEsVUFDdEIscUJBQXFCO0FBQUEsVUFDckIsdUJBQXVCO0FBQUEsUUFDekI7QUFBQSxNQUNGLENBQUM7QUFBQSxNQUNELE9BQU87QUFBQSxNQUNQLGNBQWM7QUFBQSxNQUNkLHFCQUFxQjtBQUFBLE1BQ3JCQSxRQUFPLFNBQVMsZ0JBQWdCLG1CQUFtQixFQUFFLE9BQU8sUUFBUSxDQUFDO0FBQUEsSUFDdkU7QUFBQSxJQUNBLFdBQVc7QUFBQSxNQUNUO0FBQUEsTUFDQTtBQUFBLE1BQ0E7QUFBQSxNQUNBO0FBQUEsTUFDQTtBQUFBLE1BQ0E7QUFBQSxJQUNGO0FBQUEsSUFDQSxLQUFLO0FBQUEsTUFDSCxxQkFBcUI7QUFBQSxRQUNuQixNQUFNO0FBQUEsVUFDSixLQUFLO0FBQUEsUUFDUDtBQUFBLE1BQ0Y7QUFBQSxJQUNGO0FBQUEsSUFDQSxNQUFNO0FBQUEsTUFDSixTQUFTO0FBQUEsUUFDUDtBQUFBLFFBQ0E7QUFBQSxRQUNBO0FBQUEsUUFDQTtBQUFBLFFBQ0E7QUFBQSxRQUNBO0FBQUE7QUFBQSxNQUNGO0FBQUEsSUFDRjtBQUFBLEVBQ0Y7QUFDRixDQUFDO0FBRUQsU0FBUyx1QkFBdUI7QUFDOUIsU0FBTztBQUFBLElBQ0wsTUFBTTtBQUFBLElBQ04sZ0JBQWdCLFFBQXVCO0FBQ3JDLGFBQU8sWUFBWSxJQUFJLENBQUMsS0FBSyxLQUFLLFNBQVM7QUFDekMsY0FBTSxNQUFNLElBQUksUUFBUSxZQUFZLEdBQUcsTUFBTSwwQkFBMEI7QUFFdkUsWUFBSSxLQUFLO0FBQ1AsZ0JBQU0sVUFBVSxTQUFTLElBQUksQ0FBQyxHQUFHLEVBQUU7QUFFbkMsY0FBSSxZQUFZLEtBQUs7QUFDbkIsZ0JBQUksVUFBVSxnQkFBZ0IsV0FBVztBQUN6QyxnQkFBSTtBQUFBLGNBQ0Y7QUFBQSxZQUNGO0FBRUE7QUFBQSxVQUNGO0FBQUEsUUFDRjtBQUVBLGFBQUs7QUFBQSxNQUNQLENBQUM7QUFBQSxJQUNIO0FBQUEsRUFDRjtBQUNGOyIsCiAgIm5hbWVzIjogWyJjb25maWciXQp9Cg==