feat(aiCore): update vitest version and enhance provider validation

- Upgraded `vitest` dependency to version 3.2.4 in package.json and yarn.lock for improved testing capabilities.
- Removed console error logging in provider validation functions to streamline error handling.
- Added comprehensive tests for the AiProviderRegistry functionality, ensuring robust provider management and dynamic registration.
- Introduced new test cases for provider schemas to validate configurations and IDs.
- Deleted outdated registry test file to maintain a clean test suite.
This commit is contained in:
MyPrototypeWhat 2025-08-19 11:13:03 +08:00
parent d93a36e5c9
commit 5d0ab0a9a1
7 changed files with 971 additions and 443 deletions

View File

@ -48,7 +48,7 @@
"devDependencies": {
"tsdown": "^0.12.9",
"typescript": "^5.0.0",
"vitest": "^1.0.0"
"vitest": "^3.2.4"
},
"sideEffects": false,
"engines": {

View File

@ -0,0 +1,568 @@
/**
* AiProviderRegistry
*/
import { beforeEach, describe, expect, it, vi } from 'vitest'
// 模拟 AI SDK
vi.mock('@ai-sdk/openai', () => ({
createOpenAI: vi.fn(() => ({ name: 'openai-mock' }))
}))
vi.mock('@ai-sdk/anthropic', () => ({
createAnthropic: vi.fn(() => ({ name: 'anthropic-mock' }))
}))
vi.mock('@ai-sdk/azure', () => ({
createAzure: vi.fn(() => ({ name: 'azure-mock' }))
}))
vi.mock('@ai-sdk/deepseek', () => ({
createDeepSeek: vi.fn(() => ({ name: 'deepseek-mock' }))
}))
vi.mock('@ai-sdk/google', () => ({
createGoogleGenerativeAI: vi.fn(() => ({ name: 'google-mock' }))
}))
vi.mock('@ai-sdk/openai-compatible', () => ({
createOpenAICompatible: vi.fn(() => ({ name: 'openai-compatible-mock' }))
}))
vi.mock('@ai-sdk/xai', () => ({
createXai: vi.fn(() => ({ name: 'xai-mock' }))
}))
import {
AiProviderRegistry,
cleanup,
getAllDynamicMappings,
getAllProviders,
getAllValidProviderIds,
getDynamicProviders,
getProvider,
getProviderMapping,
isDynamicProvider,
isProviderSupported,
registerDynamicProvider,
registerMultipleProviders,
registerProvider,
validateProviderIdRegistry
} from '../registry'
import type { DynamicProviderRegistration, ProviderConfig } from '../schemas'
describe('AiProviderRegistry 功能测试', () => {
beforeEach(() => {
// 清理状态
cleanup()
})
describe('基础功能', () => {
it('能够获取所有 providers', () => {
const providers = getAllProviders()
expect(Array.isArray(providers)).toBe(true)
expect(providers.length).toBeGreaterThan(0)
// 包含基础 providers
const providerIds = providers.map((p) => p.id)
expect(providerIds).toContain('openai')
expect(providerIds).toContain('anthropic')
expect(providerIds).toContain('google')
})
it('能够检查 provider 支持状态', () => {
expect(isProviderSupported('openai')).toBe(true)
expect(isProviderSupported('anthropic')).toBe(true)
expect(isProviderSupported('google')).toBe(true)
expect(isProviderSupported('non-existent')).toBe(true) // validateProviderId 通过
expect(isProviderSupported('')).toBe(false)
})
it('能够获取有效的 provider IDs', () => {
const allIds = getAllValidProviderIds()
expect(Array.isArray(allIds)).toBe(true)
expect(allIds).toContain('openai')
expect(allIds).toContain('anthropic')
})
it('能够根据 ID 获取特定的 provider', () => {
// 获取存在的 provider
const openaiProvider = getProvider('openai')
expect(openaiProvider).toBeDefined()
expect(openaiProvider?.id).toBe('openai')
expect(openaiProvider?.name).toBe('OpenAI')
// 获取不存在的 providerfallback到openai-compatible
const nonExistentProvider = getProvider('non-existent')
expect(nonExistentProvider).toBeDefined()
expect(nonExistentProvider?.id).toBe('openai-compatible')
})
it('能够验证 provider ID', () => {
expect(validateProviderIdRegistry('valid-id')).toBe(true)
expect(validateProviderIdRegistry('another-valid-id')).toBe(true)
expect(validateProviderIdRegistry('')).toBe(false)
// 注意:单个空格字符被认为是有效的,因为它不是空字符串
// 如果需要更严格的验证schemas 包含更多验证规则
expect(validateProviderIdRegistry(' ')).toBe(true)
})
})
describe('动态 Provider 注册', () => {
it('能够注册动态 provider', () => {
const config = {
id: 'custom-provider',
name: 'Custom Provider',
creator: vi.fn(() => ({ name: 'custom' })),
supportsImageGeneration: false
}
const success = registerDynamicProvider(config)
expect(success).toBe(true)
expect(isDynamicProvider('custom-provider')).toBe(true)
expect(isProviderSupported('custom-provider')).toBe(true)
const allIds = getAllValidProviderIds()
expect(allIds).toContain('custom-provider')
})
it('拒绝与基础 provider 冲突的配置', () => {
const config = {
id: 'openai',
name: 'Duplicate OpenAI',
creator: vi.fn(() => ({ name: 'duplicate' })),
supportsImageGeneration: false
}
const success = registerDynamicProvider(config)
expect(success).toBe(false)
expect(isDynamicProvider('openai')).toBe(false)
})
it('拒绝无效的配置', () => {
// 缺少必要字段
const invalidConfig = {
id: 'invalid-provider'
// 缺少 name, creator 等
}
const success = registerDynamicProvider(invalidConfig as any)
expect(success).toBe(false)
})
it('能够批量注册动态 providers', () => {
const configs: DynamicProviderRegistration[] = [
{
id: 'provider-1',
name: 'Provider 1',
creator: vi.fn(() => ({ name: 'provider-1' })),
supportsImageGeneration: false
},
{
id: 'provider-2',
name: 'Provider 2',
creator: vi.fn(() => ({ name: 'provider-2' })),
supportsImageGeneration: true
},
{
id: 'openai', // 这个失败,因为与基础 provider 冲突
name: 'Invalid Provider',
creator: vi.fn(() => ({ name: 'invalid' })),
supportsImageGeneration: false
}
]
const successCount = registerMultipleProviders(configs)
expect(successCount).toBe(2) // 只有前两个成功
expect(isDynamicProvider('provider-1')).toBe(true)
expect(isDynamicProvider('provider-2')).toBe(true)
expect(isDynamicProvider('openai')).toBe(false) // 基础 provider不是动态的
})
it('支持带映射关系的动态 provider', () => {
const configWithMappings: DynamicProviderRegistration = {
id: 'custom-provider-with-mappings',
name: 'Custom Provider with Mappings',
creator: vi.fn(() => ({ name: 'custom-mapped' })),
supportsImageGeneration: false,
mappings: {
'custom-alias-1': 'custom-provider-with-mappings',
'custom-alias-2': 'custom-provider-with-mappings'
}
}
const success = registerDynamicProvider(configWithMappings)
expect(success).toBe(true)
// 验证映射关系
expect(getProviderMapping('custom-alias-1')).toBe('custom-provider-with-mappings')
expect(getProviderMapping('custom-alias-2')).toBe('custom-provider-with-mappings')
expect(getProviderMapping('custom-provider-with-mappings')).toBe('custom-provider-with-mappings')
})
})
describe('Registry 管理', () => {
it('能够清理动态 providers', () => {
// 注册动态 provider
registerDynamicProvider({
id: 'temp-provider',
name: 'Temp Provider',
creator: vi.fn(() => ({ name: 'temp' })),
supportsImageGeneration: false
})
expect(isDynamicProvider('temp-provider')).toBe(true)
// 清理
cleanup()
expect(isDynamicProvider('temp-provider')).toBe(false)
expect(isProviderSupported('openai')).toBe(true) // 基础 providers 仍存在
})
it('保持单例模式', () => {
const instance1 = AiProviderRegistry.getInstance()
const instance2 = AiProviderRegistry.getInstance()
expect(instance1).toBe(instance2)
})
it('能够注册基础 provider', () => {
const customConfig: ProviderConfig = {
id: 'custom-base-provider',
name: 'Custom Base Provider',
creator: vi.fn(() => ({ name: 'custom-base' })),
supportsImageGeneration: false
}
// 注册基础 provider 不抛出错误
expect(() => registerProvider(customConfig)).not.toThrow()
// 验证注册成功
const registeredProvider = getProvider('custom-base-provider')
expect(registeredProvider).toBeDefined()
expect(registeredProvider?.id).toBe('custom-base-provider')
expect(registeredProvider?.name).toBe('Custom Base Provider')
})
it('能够获取动态 providers 列表', () => {
// 初始状态没有动态 providers
expect(getDynamicProviders()).toEqual([])
// 注册一些动态 providers
registerDynamicProvider({
id: 'dynamic-1',
name: 'Dynamic 1',
creator: vi.fn(() => ({ name: 'dynamic-1' })),
supportsImageGeneration: false
})
registerDynamicProvider({
id: 'dynamic-2',
name: 'Dynamic 2',
creator: vi.fn(() => ({ name: 'dynamic-2' })),
supportsImageGeneration: true
})
const dynamicProviders = getDynamicProviders()
expect(Array.isArray(dynamicProviders)).toBe(true)
expect(dynamicProviders).toContain('dynamic-1')
expect(dynamicProviders).toContain('dynamic-2')
expect(dynamicProviders.length).toBe(2)
})
it('能够获取所有动态映射', () => {
// 初始状态没有动态映射
expect(getAllDynamicMappings()).toEqual({})
// 注册带映射的动态 provider
registerDynamicProvider({
id: 'mapped-provider',
name: 'Mapped Provider',
creator: vi.fn(() => ({ name: 'mapped' })),
supportsImageGeneration: false,
mappings: {
'alias-1': 'mapped-provider',
'alias-2': 'mapped-provider',
'custom-name': 'mapped-provider'
}
})
const allMappings = getAllDynamicMappings()
expect(allMappings).toEqual({
'alias-1': 'mapped-provider',
'alias-2': 'mapped-provider',
'custom-name': 'mapped-provider'
})
})
})
describe('错误处理', () => {
it('优雅处理空配置', () => {
const success = registerDynamicProvider(null as any)
expect(success).toBe(false)
})
it('优雅处理未定义配置', () => {
const success = registerDynamicProvider(undefined as any)
expect(success).toBe(false)
})
it('处理空字符串 ID', () => {
const config = {
id: '',
name: 'Empty ID Provider',
creator: vi.fn(() => ({ name: 'empty' })),
supportsImageGeneration: false
}
const success = registerDynamicProvider(config)
expect(success).toBe(false)
})
it('处理注册基础 provider 时的无效 ID', () => {
const invalidConfig: ProviderConfig = {
id: '', // 无效 ID
name: 'Invalid Provider',
creator: vi.fn(() => ({ name: 'invalid' })),
supportsImageGeneration: false
}
expect(() => registerProvider(invalidConfig)).toThrow('Invalid provider ID:')
})
it('处理获取不存在映射时的情况', () => {
expect(getProviderMapping('non-existent-mapping')).toBeUndefined()
})
it('处理批量注册时的部分失败', () => {
const mixedConfigs: DynamicProviderRegistration[] = [
{
id: 'valid-provider-1',
name: 'Valid Provider 1',
creator: vi.fn(() => ({ name: 'valid-1' })),
supportsImageGeneration: false
},
{
id: '', // 无效配置
name: 'Invalid Provider',
creator: vi.fn(() => ({ name: 'invalid' })),
supportsImageGeneration: false
},
{
id: 'valid-provider-2',
name: 'Valid Provider 2',
creator: vi.fn(() => ({ name: 'valid-2' })),
supportsImageGeneration: true
}
]
const successCount = registerMultipleProviders(mixedConfigs)
expect(successCount).toBe(2) // 只有两个有效配置成功
expect(isDynamicProvider('valid-provider-1')).toBe(true)
expect(isDynamicProvider('valid-provider-2')).toBe(true)
expect(getDynamicProviders()).not.toContain('')
})
})
describe('集成测试', () => {
it('正确处理复杂的注册、映射和清理场景', () => {
// 初始状态验证
const initialProviders = getAllProviders()
const initialIds = getAllValidProviderIds()
expect(initialProviders.length).toBeGreaterThan(0)
expect(getDynamicProviders()).toEqual([])
expect(getAllDynamicMappings()).toEqual({})
// 注册多个带映射的动态 providers
const configs: DynamicProviderRegistration[] = [
{
id: 'integration-provider-1',
name: 'Integration Provider 1',
creator: vi.fn(() => ({ name: 'integration-1' })),
supportsImageGeneration: false,
mappings: {
'alias-1': 'integration-provider-1',
'short-name-1': 'integration-provider-1'
}
},
{
id: 'integration-provider-2',
name: 'Integration Provider 2',
creator: vi.fn(() => ({ name: 'integration-2' })),
supportsImageGeneration: true,
mappings: {
'alias-2': 'integration-provider-2',
'short-name-2': 'integration-provider-2'
}
}
]
const successCount = registerMultipleProviders(configs)
expect(successCount).toBe(2)
// 验证注册后的状态
const afterRegisterProviders = getAllProviders()
const afterRegisterIds = getAllValidProviderIds()
expect(afterRegisterProviders.length).toBe(initialProviders.length + 2)
expect(afterRegisterIds.length).toBeGreaterThanOrEqual(initialIds.length + 2)
// 验证动态 providers
const dynamicProviders = getDynamicProviders()
expect(dynamicProviders).toContain('integration-provider-1')
expect(dynamicProviders).toContain('integration-provider-2')
// 验证映射
const mappings = getAllDynamicMappings()
expect(mappings['alias-1']).toBe('integration-provider-1')
expect(mappings['alias-2']).toBe('integration-provider-2')
expect(mappings['short-name-1']).toBe('integration-provider-1')
expect(mappings['short-name-2']).toBe('integration-provider-2')
// 验证通过映射能够获取 provider
expect(getProviderMapping('alias-1')).toBe('integration-provider-1')
expect(getProviderMapping('integration-provider-1')).toBe('integration-provider-1')
// 清理
cleanup()
// 验证清理后的状态
const afterCleanupProviders = getAllProviders()
const afterCleanupIds = getAllValidProviderIds()
expect(afterCleanupProviders.length).toBe(initialProviders.length)
expect(afterCleanupIds.length).toBe(initialIds.length)
expect(getDynamicProviders()).toEqual([])
expect(getAllDynamicMappings()).toEqual({})
})
it('正确处理 provider 的优先级和 fallback 机制', () => {
// 验证 getProvider 的 fallback 机制
const existingProvider = getProvider('openai')
expect(existingProvider?.id).toBe('openai')
const nonExistentProvider = getProvider('definitely-non-existent')
expect(nonExistentProvider?.id).toBe('openai-compatible') // fallback
// 注册自定义 provider 后能直接获取
registerDynamicProvider({
id: 'priority-test-provider',
name: 'Priority Test Provider',
creator: vi.fn(() => ({ name: 'priority-test' })),
supportsImageGeneration: false
})
const customProvider = getProvider('priority-test-provider')
expect(customProvider?.id).toBe('priority-test-provider')
expect(customProvider?.name).toBe('Priority Test Provider')
})
it('正确处理大量动态 providers 的注册和管理', () => {
const largeConfigList: DynamicProviderRegistration[] = []
// 生成100个动态 providers
for (let i = 0; i < 100; i++) {
largeConfigList.push({
id: `bulk-provider-${i}`,
name: `Bulk Provider ${i}`,
creator: vi.fn(() => ({ name: `bulk-${i}` })),
supportsImageGeneration: i % 2 === 0, // 偶数支持图像生成
mappings: {
[`alias-${i}`]: `bulk-provider-${i}`,
[`short-${i}`]: `bulk-provider-${i}`
}
})
}
const successCount = registerMultipleProviders(largeConfigList)
expect(successCount).toBe(100)
// 验证所有 providers 都被正确注册
const dynamicProviders = getDynamicProviders()
expect(dynamicProviders.length).toBe(100)
// 验证映射数量
const mappings = getAllDynamicMappings()
expect(Object.keys(mappings).length).toBe(200) // 每个 provider 有2个映射
// 随机验证几个 providers
expect(isDynamicProvider('bulk-provider-0')).toBe(true)
expect(isDynamicProvider('bulk-provider-50')).toBe(true)
expect(isDynamicProvider('bulk-provider-99')).toBe(true)
// 验证映射工作正常
expect(getProviderMapping('alias-25')).toBe('bulk-provider-25')
expect(getProviderMapping('short-75')).toBe('bulk-provider-75')
// 清理能正确处理大量数据
cleanup()
expect(getDynamicProviders()).toEqual([])
expect(getAllDynamicMappings()).toEqual({})
})
})
describe('边界测试', () => {
it('处理包含特殊字符的 provider IDs', () => {
const specialCharsConfigs: DynamicProviderRegistration[] = [
{
id: 'provider-with-dashes',
name: 'Provider With Dashes',
creator: vi.fn(() => ({ name: 'dashes' })),
supportsImageGeneration: false
},
{
id: 'provider_with_underscores',
name: 'Provider With Underscores',
creator: vi.fn(() => ({ name: 'underscores' })),
supportsImageGeneration: false
},
{
id: 'provider.with.dots',
name: 'Provider With Dots',
creator: vi.fn(() => ({ name: 'dots' })),
supportsImageGeneration: false
}
]
const successCount = registerMultipleProviders(specialCharsConfigs)
expect(successCount).toBeGreaterThan(0) // 至少有一些成功
// 验证支持的特殊字符格式
if (isDynamicProvider('provider-with-dashes')) {
expect(getProvider('provider-with-dashes')).toBeDefined()
}
if (isDynamicProvider('provider_with_underscores')) {
expect(getProvider('provider_with_underscores')).toBeDefined()
}
})
it('处理空的批量注册', () => {
const successCount = registerMultipleProviders([])
expect(successCount).toBe(0)
expect(getDynamicProviders()).toEqual([])
})
it('处理重复的 provider 注册', () => {
const config: DynamicProviderRegistration = {
id: 'duplicate-test-provider',
name: 'Duplicate Test Provider',
creator: vi.fn(() => ({ name: 'duplicate' })),
supportsImageGeneration: false
}
// 第一次注册成功
expect(registerDynamicProvider(config)).toBe(true)
expect(isDynamicProvider('duplicate-test-provider')).toBe(true)
// 重复注册相同的 provider
expect(registerDynamicProvider(config)).toBe(true) // 允许覆盖
expect(isDynamicProvider('duplicate-test-provider')).toBe(true)
// 验证只有一个实例
const dynamicProviders = getDynamicProviders()
const duplicateCount = dynamicProviders.filter((id) => id === 'duplicate-test-provider').length
expect(duplicateCount).toBe(1)
})
})
})

View File

@ -1,131 +0,0 @@
/**
* registry -
*/
import { beforeEach, describe, expect, it, vi } from 'vitest'
// 模拟 AI SDK - 使用简单版本
vi.mock('@ai-sdk/openai', () => ({
createOpenAI: vi.fn(() => ({ name: 'openai-mock' }))
}))
vi.mock('@ai-sdk/anthropic', () => ({
createAnthropic: vi.fn(() => ({ name: 'anthropic-mock' }))
}))
vi.mock('@ai-sdk/azure', () => ({
createAzure: vi.fn(() => ({ name: 'azure-mock' }))
}))
vi.mock('@ai-sdk/deepseek', () => ({
createDeepSeek: vi.fn(() => ({ name: 'deepseek-mock' }))
}))
vi.mock('@ai-sdk/google', () => ({
createGoogleGenerativeAI: vi.fn(() => ({ name: 'google-mock' }))
}))
vi.mock('@ai-sdk/openai-compatible', () => ({
createOpenAICompatible: vi.fn(() => ({ name: 'openai-compatible-mock' }))
}))
vi.mock('@ai-sdk/xai', () => ({
createXai: vi.fn(() => ({ name: 'xai-mock' }))
}))
describe('Real Registry Test', () => {
beforeEach(() => {
// 清理模块缓存,强制重新加载
vi.resetModules()
})
it('应该能够通过动态导入访问真正的 registry', async () => {
console.log('🔍 Real test - Testing dynamic import...')
try {
// 使用动态导入,每次都重新导入
const { AiProviderRegistry } = await import('../registry')
console.log('🔍 Real test - AiProviderRegistry imported:', {
type: typeof AiProviderRegistry,
isClass: AiProviderRegistry?.prototype?.constructor === AiProviderRegistry
})
if (AiProviderRegistry) {
// 创建新实例,跳过单例模式
const testRegistry = Object.create(AiProviderRegistry.prototype)
// 手动调用构造函数逻辑,但跳过有问题的初始化
testRegistry.registry = new Map()
testRegistry.dynamicMappings = new Map()
testRegistry.dynamicProviders = new Set()
// 手动添加一些测试数据
testRegistry.registry.set('test-provider', {
id: 'test-provider',
name: 'Test Provider',
creator: () => ({ name: 'test' }),
supportsImageGeneration: false
})
// 测试基本功能
const allIds = testRegistry.getAllValidProviderIds?.()
console.log('🔍 Real test - getAllValidProviderIds result:', allIds)
if (allIds) {
expect(Array.isArray(allIds)).toBe(true)
expect(allIds).toContain('test-provider')
}
}
} catch (error) {
console.error('🔍 Real test - Error:', error)
throw error
}
})
it('应该能够通过模块原型访问方法', async () => {
console.log('🔍 Real test - Testing prototype access...')
try {
const registryModule = await import('../registry')
console.log('🔍 Real test - Registry module keys:', Object.keys(registryModule))
// 检查是否有任何可用的导出
const availableExports = Object.keys(registryModule).filter((key) => registryModule[key] !== undefined)
console.log('🔍 Real test - Available exports:', availableExports)
if (availableExports.length === 0) {
console.log('🔍 Real test - No exports available, trying alternative approach...')
// 尝试直接访问模块的内部结构
const moduleEntries = Object.entries(registryModule)
console.log('🔍 Real test - Module entries:', moduleEntries)
}
} catch (error) {
console.error('🔍 Real test - Prototype access error:', error)
}
})
it('应该能够通过 require 访问模块', async () => {
console.log('🔍 Real test - Testing require access...')
try {
// 尝试使用 require 而不是 import
const path = require('path')
const moduleId = path.resolve(__dirname, '../registry.ts')
console.log('🔍 Real test - Module ID:', moduleId)
// 检查模块是否在缓存中
const cached = require.cache[moduleId]
console.log('🔍 Real test - Module cached:', !!cached)
if (cached) {
console.log('🔍 Real test - Cached exports:', Object.keys(cached.exports || {}))
}
} catch (error) {
console.error('🔍 Real test - Require access error:', error)
}
})
})

View File

@ -0,0 +1,393 @@
import { describe, expect, it, vi } from 'vitest'
import {
type BaseProviderId,
baseProviderIds,
baseProviderIdSchema,
baseProviders,
type DynamicProviderId,
dynamicProviderIdSchema,
dynamicProviderRegistrationSchema,
getBaseProviderConfig,
isBaseProviderId,
isValidDynamicProviderId,
providerConfigSchema,
type ProviderId,
providerIdSchema,
validateDynamicProviderRegistration,
validateProviderConfig,
validateProviderId
} from '../schemas'
describe('Provider Schemas', () => {
describe('baseProviders', () => {
it('包含所有预期的基础 providers', () => {
expect(baseProviders).toBeDefined()
expect(Array.isArray(baseProviders)).toBe(true)
expect(baseProviders.length).toBeGreaterThan(0)
const expectedIds = [
'openai',
'openai-responses',
'openai-compatible',
'anthropic',
'google',
'xai',
'azure',
'deepseek'
]
const actualIds = baseProviders.map((p) => p.id)
expectedIds.forEach((id) => {
expect(actualIds).toContain(id)
})
})
it('每个基础 provider 有必要的属性', () => {
baseProviders.forEach((provider) => {
expect(provider).toHaveProperty('id')
expect(provider).toHaveProperty('name')
expect(provider).toHaveProperty('creator')
expect(provider).toHaveProperty('supportsImageGeneration')
expect(typeof provider.id).toBe('string')
expect(typeof provider.name).toBe('string')
expect(typeof provider.creator).toBe('function')
expect(typeof provider.supportsImageGeneration).toBe('boolean')
})
})
it('provider ID 是唯一的', () => {
const ids = baseProviders.map((p) => p.id)
const uniqueIds = [...new Set(ids)]
expect(ids).toEqual(uniqueIds)
})
})
describe('baseProviderIds', () => {
it('正确提取所有基础 provider IDs', () => {
expect(baseProviderIds).toBeDefined()
expect(Array.isArray(baseProviderIds)).toBe(true)
expect(baseProviderIds.length).toBe(baseProviders.length)
baseProviders.forEach((provider) => {
expect(baseProviderIds).toContain(provider.id)
})
})
})
describe('baseProviderIdSchema', () => {
it('验证有效的基础 provider IDs', () => {
baseProviderIds.forEach((id) => {
expect(baseProviderIdSchema.safeParse(id).success).toBe(true)
})
})
it('拒绝无效的基础 provider IDs', () => {
const invalidIds = ['invalid', 'not-exists', '']
invalidIds.forEach((id) => {
expect(baseProviderIdSchema.safeParse(id).success).toBe(false)
})
})
})
describe('dynamicProviderIdSchema', () => {
it('接受有效的动态 provider IDs', () => {
const validIds = ['custom-provider', 'my-ai-service', 'company-llm-v2']
validIds.forEach((id) => {
expect(dynamicProviderIdSchema.safeParse(id).success).toBe(true)
})
})
it('拒绝与基础 provider IDs 冲突的 IDs', () => {
baseProviderIds.forEach((id) => {
expect(dynamicProviderIdSchema.safeParse(id).success).toBe(false)
})
})
it('拒绝空字符串', () => {
expect(dynamicProviderIdSchema.safeParse('').success).toBe(false)
})
})
describe('providerIdSchema', () => {
it('接受基础 provider IDs', () => {
baseProviderIds.forEach((id) => {
expect(providerIdSchema.safeParse(id).success).toBe(true)
})
})
it('接受有效的动态 provider IDs', () => {
const validDynamicIds = ['custom-provider', 'my-ai-service']
validDynamicIds.forEach((id) => {
expect(providerIdSchema.safeParse(id).success).toBe(true)
})
})
it('拒绝无效的 IDs', () => {
const invalidIds = ['', undefined, null, 123]
invalidIds.forEach((id) => {
expect(providerIdSchema.safeParse(id).success).toBe(false)
})
})
})
describe('providerConfigSchema', () => {
it('验证带有 creator 的有效配置', () => {
const validConfig = {
id: 'openai',
name: 'OpenAI',
creator: vi.fn(),
supportsImageGeneration: true
}
expect(providerConfigSchema.safeParse(validConfig).success).toBe(true)
})
it('验证带有 import 配置的有效配置', () => {
const validConfig = {
id: 'custom-provider',
name: 'Custom Provider',
import: vi.fn(),
creatorFunctionName: 'createCustom',
supportsImageGeneration: false
}
expect(providerConfigSchema.safeParse(validConfig).success).toBe(true)
})
it('拒绝既没有 creator 也没有 import 配置的配置', () => {
const invalidConfig = {
id: 'invalid',
name: 'Invalid Provider',
supportsImageGeneration: false
}
expect(providerConfigSchema.safeParse(invalidConfig).success).toBe(false)
})
it('为 supportsImageGeneration 设置默认值', () => {
const config = {
id: 'test',
name: 'Test',
creator: vi.fn()
}
const result = providerConfigSchema.safeParse(config)
expect(result.success).toBe(true)
if (result.success) {
expect(result.data.supportsImageGeneration).toBe(false)
}
})
it('拒绝缺少必需字段的配置', () => {
const invalidConfigs = [
{ name: 'Missing ID', creator: vi.fn() },
{ id: 'missing-name', creator: vi.fn() },
{ id: '', name: 'Empty ID', creator: vi.fn() },
{ id: 'valid', name: '', creator: vi.fn() }
]
invalidConfigs.forEach((config) => {
expect(providerConfigSchema.safeParse(config).success).toBe(false)
})
})
})
describe('dynamicProviderRegistrationSchema', () => {
it('验证有效的动态 provider 注册配置', () => {
const validConfig = {
id: 'custom-provider',
name: 'Custom Provider',
creator: vi.fn(),
supportsImageGeneration: true,
mappings: { model1: 'mapped-model1' }
}
expect(dynamicProviderRegistrationSchema.safeParse(validConfig).success).toBe(true)
})
it('拒绝使用基础 provider ID 的配置', () => {
const invalidConfig = {
id: 'openai',
name: 'Should Fail',
creator: vi.fn()
}
expect(dynamicProviderRegistrationSchema.safeParse(invalidConfig).success).toBe(false)
})
it('要求 creator 或 import 配置', () => {
const configWithoutCreator = {
id: 'custom-provider',
name: 'Custom Provider'
}
expect(dynamicProviderRegistrationSchema.safeParse(configWithoutCreator).success).toBe(false)
})
})
describe('validateProviderId', () => {
it('验证基础 provider IDs', () => {
baseProviderIds.forEach((id) => {
expect(validateProviderId(id)).toBe(true)
})
})
it('验证有效的动态 provider IDs', () => {
const validDynamicIds = ['custom-provider', 'my-service', 'company-llm']
validDynamicIds.forEach((id) => {
expect(validateProviderId(id)).toBe(true)
})
})
it('拒绝无效的 IDs', () => {
const invalidIds = [undefined as any, null as any, 123 as any]
invalidIds.forEach((id) => {
expect(validateProviderId(id)).toBe(false)
})
// 空字符串和只有空格的字符串会被当作有效的动态 provider ID
expect(validateProviderId('')).toBe(false)
})
})
describe('isBaseProviderId', () => {
it('正确识别基础 provider IDs', () => {
baseProviderIds.forEach((id) => {
expect(isBaseProviderId(id)).toBe(true)
})
})
it('拒绝动态 provider IDs', () => {
const dynamicIds = ['custom-provider', 'my-service']
dynamicIds.forEach((id) => {
expect(isBaseProviderId(id)).toBe(false)
})
})
it('拒绝无效的 IDs', () => {
const invalidIds = ['', 'invalid', undefined as any]
invalidIds.forEach((id) => {
expect(isBaseProviderId(id)).toBe(false)
})
})
})
describe('isValidDynamicProviderId', () => {
it('接受有效的动态 provider IDs', () => {
const validIds = ['custom-provider', 'my-ai-service', 'company-llm-v2']
validIds.forEach((id) => {
expect(isValidDynamicProviderId(id)).toBe(true)
})
})
it('拒绝基础 provider IDs', () => {
baseProviderIds.forEach((id) => {
expect(isValidDynamicProviderId(id)).toBe(false)
})
})
it('拒绝无效的 IDs', () => {
const invalidIds = [undefined as any, null as any]
invalidIds.forEach((id) => {
expect(isValidDynamicProviderId(id)).toBe(false)
})
// 空字符串会被 schema 拒绝
expect(isValidDynamicProviderId('')).toBe(false)
// 只有空格的字符串是有效的动态 provider ID但不推荐使用
expect(isValidDynamicProviderId(' ')).toBe(true)
})
})
describe('validateProviderConfig', () => {
it('返回有效配置', () => {
const validConfig = {
id: 'openai',
name: 'OpenAI',
creator: vi.fn(),
supportsImageGeneration: true
}
const result = validateProviderConfig(validConfig)
expect(result).not.toBeNull()
expect(result?.id).toBe('openai')
expect(result?.name).toBe('OpenAI')
})
it('对无效配置返回 null', () => {
const invalidConfig = {
id: '',
name: 'Invalid'
}
const result = validateProviderConfig(invalidConfig)
expect(result).toBeNull()
})
it('处理完全无效的输入', () => {
const invalidInputs = [undefined, null, 'string', 123, []]
invalidInputs.forEach((input) => {
const result = validateProviderConfig(input)
expect(result).toBeNull()
})
})
})
describe('validateDynamicProviderRegistration', () => {
it('返回有效的动态 provider 注册配置', () => {
const validConfig = {
id: 'custom-provider',
name: 'Custom Provider',
creator: vi.fn(),
mappings: { model1: 'mapped-model1' }
}
const result = validateDynamicProviderRegistration(validConfig)
expect(result).not.toBeNull()
expect(result?.id).toBe('custom-provider')
expect(result?.name).toBe('Custom Provider')
})
it('对无效配置返回 null', () => {
const invalidConfig = {
id: 'openai',
name: 'Should Fail'
}
const result = validateDynamicProviderRegistration(invalidConfig)
expect(result).toBeNull()
})
})
describe('getBaseProviderConfig', () => {
it('返回有效基础 provider ID 的配置', () => {
const config = getBaseProviderConfig('openai')
expect(config).toBeDefined()
expect(config?.id).toBe('openai')
expect(config?.name).toBe('OpenAI')
expect(config?.creator).toBeDefined()
})
it('对无效 ID 返回 undefined', () => {
const config = getBaseProviderConfig('invalid' as BaseProviderId)
expect(config).toBeUndefined()
})
it('返回所有基础 providers 的配置', () => {
baseProviderIds.forEach((id) => {
const config = getBaseProviderConfig(id)
expect(config).toBeDefined()
expect(config?.id).toBe(id)
})
})
})
describe('类型推导', () => {
it('BaseProviderId 类型正确', () => {
const id: BaseProviderId = 'openai'
expect(baseProviderIds).toContain(id)
})
it('DynamicProviderId 类型是字符串', () => {
const id: DynamicProviderId = 'custom-provider'
expect(typeof id).toBe('string')
})
it('ProviderId 类型支持基础和动态 IDs', () => {
const baseId: ProviderId = 'openai'
const dynamicId: ProviderId = 'custom-provider'
expect(typeof baseId).toBe('string')
expect(typeof dynamicId).toBe('string')
})
})
})

View File

@ -173,7 +173,6 @@ export function validateProviderConfig(config: unknown): ProviderConfig | null {
if (result.success) {
return result.data
}
console.error('Invalid provider config:', result.error.errors)
return null
}
@ -185,7 +184,6 @@ export function validateDynamicProviderRegistration(config: unknown): DynamicPro
if (result.success) {
return result.data
}
console.error('Invalid dynamic provider registration:', result.error.errors)
return null
}

View File

@ -2,10 +2,7 @@ import { defineConfig } from 'vitest/config'
export default defineConfig({
test: {
globals: true,
environment: 'node',
setupFiles: ['./setupVitest.ts'],
include: ['src/**/*.{test,spec}.{ts,tsx}', 'src/**/__tests__/**/*.{test,spec}.{ts,tsx}']
globals: true
},
resolve: {
alias: {

313
yarn.lock
View File

@ -2205,7 +2205,7 @@ __metadata:
ai: "npm:5.0.0"
tsdown: "npm:^0.12.9"
typescript: "npm:^5.0.0"
vitest: "npm:^1.0.0"
vitest: "npm:^3.2.4"
zod: "npm:^3.25.0"
languageName: unknown
linkType: soft
@ -3737,15 +3737,6 @@ __metadata:
languageName: node
linkType: hard
"@jest/schemas@npm:^29.6.3":
version: 29.6.3
resolution: "@jest/schemas@npm:29.6.3"
dependencies:
"@sinclair/typebox": "npm:^0.27.8"
checksum: 10c0/b329e89cd5f20b9278ae1233df74016ebf7b385e0d14b9f4c1ad18d096c4c19d1e687aa113a9c976b16ec07f021ae53dea811fb8c1248a50ac34fbe009fdf6be
languageName: node
linkType: hard
"@jridgewell/gen-mapping@npm:^0.3.12, @jridgewell/gen-mapping@npm:^0.3.5":
version: 0.3.12
resolution: "@jridgewell/gen-mapping@npm:0.3.12"
@ -5849,13 +5840,6 @@ __metadata:
languageName: node
linkType: hard
"@sinclair/typebox@npm:^0.27.8":
version: 0.27.8
resolution: "@sinclair/typebox@npm:0.27.8"
checksum: 10c0/ef6351ae073c45c2ac89494dbb3e1f87cc60a93ce4cde797b782812b6f97da0d620ae81973f104b43c9b7eaa789ad20ba4f6a1359f1cc62f63729a55a7d22d4e
languageName: node
linkType: hard
"@sindresorhus/is@npm:^4.0.0":
version: 4.6.0
resolution: "@sindresorhus/is@npm:4.6.0"
@ -8642,17 +8626,6 @@ __metadata:
languageName: node
linkType: hard
"@vitest/expect@npm:1.6.1":
version: 1.6.1
resolution: "@vitest/expect@npm:1.6.1"
dependencies:
"@vitest/spy": "npm:1.6.1"
"@vitest/utils": "npm:1.6.1"
chai: "npm:^4.3.10"
checksum: 10c0/278164b2a32a7019b443444f21111c5e32e4cadee026cae047ae2a3b347d99dca1d1fb7b79509c88b67dc3db19fa9a16265b7d7a8377485f7e37f7851e44495a
languageName: node
linkType: hard
"@vitest/expect@npm:3.2.4":
version: 3.2.4
resolution: "@vitest/expect@npm:3.2.4"
@ -8694,17 +8667,6 @@ __metadata:
languageName: node
linkType: hard
"@vitest/runner@npm:1.6.1":
version: 1.6.1
resolution: "@vitest/runner@npm:1.6.1"
dependencies:
"@vitest/utils": "npm:1.6.1"
p-limit: "npm:^5.0.0"
pathe: "npm:^1.1.1"
checksum: 10c0/36333f1a596c4ad85d42c6126cc32959c984d584ef28d366d366fa3672678c1a0f5e5c2e8717a36675b6620b57e8830f765d6712d1687f163ed0a8ebf23c87db
languageName: node
linkType: hard
"@vitest/runner@npm:3.2.4":
version: 3.2.4
resolution: "@vitest/runner@npm:3.2.4"
@ -8716,17 +8678,6 @@ __metadata:
languageName: node
linkType: hard
"@vitest/snapshot@npm:1.6.1":
version: 1.6.1
resolution: "@vitest/snapshot@npm:1.6.1"
dependencies:
magic-string: "npm:^0.30.5"
pathe: "npm:^1.1.1"
pretty-format: "npm:^29.7.0"
checksum: 10c0/68bbc3132c195ec37376469e4b183fc408e0aeedd827dffcc899aac378e9ea324825f0873062786e18f00e3da9dd8a93c9bb871c07471ee483e8df963cb272eb
languageName: node
linkType: hard
"@vitest/snapshot@npm:3.2.4":
version: 3.2.4
resolution: "@vitest/snapshot@npm:3.2.4"
@ -8738,15 +8689,6 @@ __metadata:
languageName: node
linkType: hard
"@vitest/spy@npm:1.6.1":
version: 1.6.1
resolution: "@vitest/spy@npm:1.6.1"
dependencies:
tinyspy: "npm:^2.2.0"
checksum: 10c0/5207ec0e7882819f0e0811293ae6d14163e26927e781bb4de7d40b3bd99c1fae656934c437bb7a30443a3e7e736c5bccb037bbf4436dbbc83d29e65247888885
languageName: node
linkType: hard
"@vitest/spy@npm:3.2.4":
version: 3.2.4
resolution: "@vitest/spy@npm:3.2.4"
@ -8773,18 +8715,6 @@ __metadata:
languageName: node
linkType: hard
"@vitest/utils@npm:1.6.1":
version: 1.6.1
resolution: "@vitest/utils@npm:1.6.1"
dependencies:
diff-sequences: "npm:^29.6.3"
estree-walker: "npm:^3.0.3"
loupe: "npm:^2.3.7"
pretty-format: "npm:^29.7.0"
checksum: 10c0/0d4c619e5688cbc22a60c412719c6baa40376b7671bdbdc3072552f5c5a5ee5d24a96ea328b054018debd49e0626a5e3db672921b2c6b5b17b9a52edd296806a
languageName: node
linkType: hard
"@vitest/utils@npm:3.2.4":
version: 3.2.4
resolution: "@vitest/utils@npm:3.2.4"
@ -9169,24 +9099,6 @@ __metadata:
languageName: node
linkType: hard
"acorn-walk@npm:^8.3.2":
version: 8.3.4
resolution: "acorn-walk@npm:8.3.4"
dependencies:
acorn: "npm:^8.11.0"
checksum: 10c0/76537ac5fb2c37a64560feaf3342023dadc086c46da57da363e64c6148dc21b57d49ace26f949e225063acb6fb441eabffd89f7a3066de5ad37ab3e328927c62
languageName: node
linkType: hard
"acorn@npm:^8.11.0":
version: 8.15.0
resolution: "acorn@npm:8.15.0"
bin:
acorn: bin/acorn
checksum: 10c0/dec73ff59b7d6628a01eebaece7f2bdb8bb62b9b5926dcad0f8931f2b8b79c2be21f6c68ac095592adb5adb15831a3635d9343e6a91d028bbe85d564875ec3ec
languageName: node
linkType: hard
"acorn@npm:^8.14.0":
version: 8.14.1
resolution: "acorn@npm:8.14.1"
@ -9667,13 +9579,6 @@ __metadata:
languageName: node
linkType: hard
"assertion-error@npm:^1.1.0":
version: 1.1.0
resolution: "assertion-error@npm:1.1.0"
checksum: 10c0/25456b2aa333250f01143968e02e4884a34588a8538fbbf65c91a637f1dbfb8069249133cd2f4e530f10f624d206a664e7df30207830b659e9f5298b00a4099b
languageName: node
linkType: hard
"assertion-error@npm:^2.0.1":
version: 2.0.1
resolution: "assertion-error@npm:2.0.1"
@ -10268,21 +10173,6 @@ __metadata:
languageName: node
linkType: hard
"chai@npm:^4.3.10":
version: 4.5.0
resolution: "chai@npm:4.5.0"
dependencies:
assertion-error: "npm:^1.1.0"
check-error: "npm:^1.0.3"
deep-eql: "npm:^4.1.3"
get-func-name: "npm:^2.0.2"
loupe: "npm:^2.3.6"
pathval: "npm:^1.1.1"
type-detect: "npm:^4.1.0"
checksum: 10c0/b8cb596bd1aece1aec659e41a6e479290c7d9bee5b3ad63d2898ad230064e5b47889a3bc367b20100a0853b62e026e2dc514acf25a3c9385f936aa3614d4ab4d
languageName: node
linkType: hard
"chai@npm:^5.2.0":
version: 5.2.0
resolution: "chai@npm:5.2.0"
@ -10396,15 +10286,6 @@ __metadata:
languageName: node
linkType: hard
"check-error@npm:^1.0.3":
version: 1.0.3
resolution: "check-error@npm:1.0.3"
dependencies:
get-func-name: "npm:^2.0.2"
checksum: 10c0/94aa37a7315c0e8a83d0112b5bfb5a8624f7f0f81057c73e4707729cdd8077166c6aefb3d8e2b92c63ee130d4a2ff94bad46d547e12f3238cc1d78342a973841
languageName: node
linkType: hard
"check-error@npm:^2.1.1":
version: 2.1.1
resolution: "check-error@npm:2.1.1"
@ -11688,15 +11569,6 @@ __metadata:
languageName: node
linkType: hard
"deep-eql@npm:^4.1.3":
version: 4.1.4
resolution: "deep-eql@npm:4.1.4"
dependencies:
type-detect: "npm:^4.0.0"
checksum: 10c0/264e0613493b43552fc908f4ff87b8b445c0e6e075656649600e1b8a17a57ee03e960156fce7177646e4d2ddaf8e5ee616d76bd79929ff593e5c79e4e5e6c517
languageName: node
linkType: hard
"deep-eql@npm:^5.0.1":
version: 5.0.2
resolution: "deep-eql@npm:5.0.2"
@ -11896,13 +11768,6 @@ __metadata:
languageName: node
linkType: hard
"diff-sequences@npm:^29.6.3":
version: 29.6.3
resolution: "diff-sequences@npm:29.6.3"
checksum: 10c0/32e27ac7dbffdf2fb0eb5a84efd98a9ad084fbabd5ac9abb8757c6770d5320d2acd172830b28c4add29bb873d59420601dfc805ac4064330ce59b1adfd0593b2
languageName: node
linkType: hard
"diff@npm:^7.0.0":
version: 7.0.0
resolution: "diff@npm:7.0.0"
@ -13896,13 +13761,6 @@ __metadata:
languageName: node
linkType: hard
"get-func-name@npm:^2.0.1, get-func-name@npm:^2.0.2":
version: 2.0.2
resolution: "get-func-name@npm:2.0.2"
checksum: 10c0/89830fd07623fa73429a711b9daecdb304386d237c71268007f788f113505ef1d4cc2d0b9680e072c5082490aec9df5d7758bf5ac6f1c37062855e8e3dc0b9df
languageName: node
linkType: hard
"get-intrinsic@npm:^1.2.5, get-intrinsic@npm:^1.2.6, get-intrinsic@npm:^1.3.0":
version: 1.3.0
resolution: "get-intrinsic@npm:1.3.0"
@ -15912,16 +15770,6 @@ __metadata:
languageName: node
linkType: hard
"local-pkg@npm:^0.5.0":
version: 0.5.1
resolution: "local-pkg@npm:0.5.1"
dependencies:
mlly: "npm:^1.7.3"
pkg-types: "npm:^1.2.1"
checksum: 10c0/ade8346f1dc04875921461adee3c40774b00d4b74095261222ebd4d5fd0a444676e36e325f76760f21af6a60bc82480e154909b54d2d9f7173671e36dacf1808
languageName: node
linkType: hard
"local-pkg@npm:^1.0.0":
version: 1.1.1
resolution: "local-pkg@npm:1.1.1"
@ -16081,15 +15929,6 @@ __metadata:
languageName: node
linkType: hard
"loupe@npm:^2.3.6, loupe@npm:^2.3.7":
version: 2.3.7
resolution: "loupe@npm:2.3.7"
dependencies:
get-func-name: "npm:^2.0.1"
checksum: 10c0/71a781c8fc21527b99ed1062043f1f2bb30bdaf54fa4cf92463427e1718bc6567af2988300bc243c1f276e4f0876f29e3cbf7b58106fdc186915687456ce5bf4
languageName: node
linkType: hard
"loupe@npm:^3.1.0":
version: 3.1.3
resolution: "loupe@npm:3.1.3"
@ -16189,7 +16028,7 @@ __metadata:
languageName: node
linkType: hard
"magic-string@npm:^0.30.17, magic-string@npm:^0.30.5":
"magic-string@npm:^0.30.17":
version: 0.30.17
resolution: "magic-string@npm:0.30.17"
dependencies:
@ -17617,7 +17456,7 @@ __metadata:
languageName: node
linkType: hard
"mlly@npm:^1.7.3, mlly@npm:^1.7.4":
"mlly@npm:^1.7.4":
version: 1.7.4
resolution: "mlly@npm:1.7.4"
dependencies:
@ -18294,15 +18133,6 @@ __metadata:
languageName: node
linkType: hard
"p-limit@npm:^5.0.0":
version: 5.0.0
resolution: "p-limit@npm:5.0.0"
dependencies:
yocto-queue: "npm:^1.0.0"
checksum: 10c0/574e93b8895a26e8485eb1df7c4b58a1a6e8d8ae41b1750cc2cc440922b3d306044fc6e9a7f74578a883d46802d9db72b30f2e612690fcef838c173261b1ed83
languageName: node
linkType: hard
"p-locate@npm:^3.0.0":
version: 3.0.0
resolution: "p-locate@npm:3.0.0"
@ -18574,13 +18404,6 @@ __metadata:
languageName: node
linkType: hard
"pathe@npm:^1.1.1":
version: 1.1.2
resolution: "pathe@npm:1.1.2"
checksum: 10c0/64ee0a4e587fb0f208d9777a6c56e4f9050039268faaaaecd50e959ef01bf847b7872785c36483fa5cdcdbdfdb31fef2ff222684d4fc21c330ab60395c681897
languageName: node
linkType: hard
"pathe@npm:^2.0.1, pathe@npm:^2.0.3":
version: 2.0.3
resolution: "pathe@npm:2.0.3"
@ -18588,13 +18411,6 @@ __metadata:
languageName: node
linkType: hard
"pathval@npm:^1.1.1":
version: 1.1.1
resolution: "pathval@npm:1.1.1"
checksum: 10c0/f63e1bc1b33593cdf094ed6ff5c49c1c0dc5dc20a646ca9725cc7fe7cd9995002d51d5685b9b2ec6814342935748b711bafa840f84c0bb04e38ff40a335c94dc
languageName: node
linkType: hard
"pathval@npm:^2.0.0":
version: 2.0.0
resolution: "pathval@npm:2.0.0"
@ -18669,7 +18485,7 @@ __metadata:
languageName: node
linkType: hard
"picocolors@npm:^1.0.0, picocolors@npm:^1.1.1":
"picocolors@npm:^1.1.1":
version: 1.1.1
resolution: "picocolors@npm:1.1.1"
checksum: 10c0/e2e3e8170ab9d7c7421969adaa7e1b31434f789afb9b3f115f6b96d91945041ac3ceb02e9ec6fe6510ff036bcc0bf91e69a1772edc0b707e12b19c0f2d6bcf58
@ -18736,7 +18552,7 @@ __metadata:
languageName: node
linkType: hard
"pkg-types@npm:^1.2.1, pkg-types@npm:^1.3.0":
"pkg-types@npm:^1.3.0":
version: 1.3.1
resolution: "pkg-types@npm:1.3.1"
dependencies:
@ -18928,17 +18744,6 @@ __metadata:
languageName: node
linkType: hard
"pretty-format@npm:^29.7.0":
version: 29.7.0
resolution: "pretty-format@npm:29.7.0"
dependencies:
"@jest/schemas": "npm:^29.6.3"
ansi-styles: "npm:^5.0.0"
react-is: "npm:^18.0.0"
checksum: 10c0/edc5ff89f51916f036c62ed433506b55446ff739358de77207e63e88a28ca2894caac6e73dcb68166a606e51c8087d32d400473e6a9fdd2dbe743f46c9c0276f
languageName: node
linkType: hard
"proc-log@npm:^2.0.1":
version: 2.0.1
resolution: "proc-log@npm:2.0.1"
@ -21307,7 +21112,7 @@ __metadata:
languageName: node
linkType: hard
"std-env@npm:^3.5.0, std-env@npm:^3.9.0":
"std-env@npm:^3.9.0":
version: 3.9.0
resolution: "std-env@npm:3.9.0"
checksum: 10c0/4a6f9218aef3f41046c3c7ecf1f98df00b30a07f4f35c6d47b28329bc2531eef820828951c7d7b39a1c5eb19ad8a46e3ddfc7deb28f0a2f3ceebee11bab7ba50
@ -21514,15 +21319,6 @@ __metadata:
languageName: node
linkType: hard
"strip-literal@npm:^2.0.0":
version: 2.1.1
resolution: "strip-literal@npm:2.1.1"
dependencies:
js-tokens: "npm:^9.0.1"
checksum: 10c0/66a7353f5ba1ae6a4fb2805b4aba228171847200640083117c41512692e6b2c020e18580402984f55c0ae69c30f857f9a55abd672863e4ca8fdb463fdf93ba19
languageName: node
linkType: hard
"strip-literal@npm:^3.0.0":
version: 3.0.0
resolution: "strip-literal@npm:3.0.0"
@ -21850,7 +21646,7 @@ __metadata:
languageName: node
linkType: hard
"tinybench@npm:^2.5.1, tinybench@npm:^2.9.0":
"tinybench@npm:^2.9.0":
version: 2.9.0
resolution: "tinybench@npm:2.9.0"
checksum: 10c0/c3500b0f60d2eb8db65250afe750b66d51623057ee88720b7f064894a6cb7eb93360ca824a60a31ab16dab30c7b1f06efe0795b352e37914a9d4bad86386a20c
@ -21891,13 +21687,6 @@ __metadata:
languageName: node
linkType: hard
"tinypool@npm:^0.8.3":
version: 0.8.4
resolution: "tinypool@npm:0.8.4"
checksum: 10c0/779c790adcb0316a45359652f4b025958c1dff5a82460fe49f553c864309b12ad732c8288be52f852973bc76317f5e7b3598878aee0beb8a33322c0e72c4a66c
languageName: node
linkType: hard
"tinypool@npm:^1.1.1":
version: 1.1.1
resolution: "tinypool@npm:1.1.1"
@ -21912,13 +21701,6 @@ __metadata:
languageName: node
linkType: hard
"tinyspy@npm:^2.2.0":
version: 2.2.1
resolution: "tinyspy@npm:2.2.1"
checksum: 10c0/0b4cfd07c09871e12c592dfa7b91528124dc49a4766a0b23350638c62e6a483d5a2a667de7e6282246c0d4f09996482ddaacbd01f0c05b7ed7e0f79d32409bdc
languageName: node
linkType: hard
"tinyspy@npm:^4.0.3":
version: 4.0.3
resolution: "tinyspy@npm:4.0.3"
@ -22234,13 +22016,6 @@ __metadata:
languageName: node
linkType: hard
"type-detect@npm:^4.0.0, type-detect@npm:^4.1.0":
version: 4.1.0
resolution: "type-detect@npm:4.1.0"
checksum: 10c0/df8157ca3f5d311edc22885abc134e18ff8ffbc93d6a9848af5b682730ca6a5a44499259750197250479c5331a8a75b5537529df5ec410622041650a7f293e2a
languageName: node
linkType: hard
"type-fest@npm:^0.13.1":
version: 0.13.1
resolution: "type-fest@npm:0.13.1"
@ -22823,21 +22598,6 @@ __metadata:
languageName: node
linkType: hard
"vite-node@npm:1.6.1":
version: 1.6.1
resolution: "vite-node@npm:1.6.1"
dependencies:
cac: "npm:^6.7.14"
debug: "npm:^4.3.4"
pathe: "npm:^1.1.1"
picocolors: "npm:^1.0.0"
vite: "npm:^5.0.0"
bin:
vite-node: vite-node.mjs
checksum: 10c0/4d96da9f11bd0df8b60c46e65a740edaad7dd2d1aff3cdb3da5714ea8c10b5f2683111b60bfe45545c7e8c1f33e7e8a5095573d5e9ba55f50a845233292c2e02
languageName: node
linkType: hard
"vite-node@npm:3.2.4":
version: 3.2.4
resolution: "vite-node@npm:3.2.4"
@ -22908,56 +22668,6 @@ __metadata:
languageName: node
linkType: hard
"vitest@npm:^1.0.0":
version: 1.6.1
resolution: "vitest@npm:1.6.1"
dependencies:
"@vitest/expect": "npm:1.6.1"
"@vitest/runner": "npm:1.6.1"
"@vitest/snapshot": "npm:1.6.1"
"@vitest/spy": "npm:1.6.1"
"@vitest/utils": "npm:1.6.1"
acorn-walk: "npm:^8.3.2"
chai: "npm:^4.3.10"
debug: "npm:^4.3.4"
execa: "npm:^8.0.1"
local-pkg: "npm:^0.5.0"
magic-string: "npm:^0.30.5"
pathe: "npm:^1.1.1"
picocolors: "npm:^1.0.0"
std-env: "npm:^3.5.0"
strip-literal: "npm:^2.0.0"
tinybench: "npm:^2.5.1"
tinypool: "npm:^0.8.3"
vite: "npm:^5.0.0"
vite-node: "npm:1.6.1"
why-is-node-running: "npm:^2.2.2"
peerDependencies:
"@edge-runtime/vm": "*"
"@types/node": ^18.0.0 || >=20.0.0
"@vitest/browser": 1.6.1
"@vitest/ui": 1.6.1
happy-dom: "*"
jsdom: "*"
peerDependenciesMeta:
"@edge-runtime/vm":
optional: true
"@types/node":
optional: true
"@vitest/browser":
optional: true
"@vitest/ui":
optional: true
happy-dom:
optional: true
jsdom:
optional: true
bin:
vitest: vitest.mjs
checksum: 10c0/511d27d7f697683964826db2fad7ac303f9bc7eeb59d9422111dc488371ccf1f9eed47ac3a80eb47ca86b7242228ba5ca9cc3613290830d0e916973768cac215
languageName: node
linkType: hard
"vitest@npm:^3.2.4":
version: 3.2.4
resolution: "vitest@npm:3.2.4"
@ -23233,7 +22943,7 @@ __metadata:
languageName: node
linkType: hard
"why-is-node-running@npm:^2.2.2, why-is-node-running@npm:^2.3.0":
"why-is-node-running@npm:^2.3.0":
version: 2.3.0
resolution: "why-is-node-running@npm:2.3.0"
dependencies:
@ -23573,13 +23283,6 @@ __metadata:
languageName: node
linkType: hard
"yocto-queue@npm:^1.0.0":
version: 1.2.1
resolution: "yocto-queue@npm:1.2.1"
checksum: 10c0/5762caa3d0b421f4bdb7a1926b2ae2189fc6e4a14469258f183600028eb16db3e9e0306f46e8ebf5a52ff4b81a881f22637afefbef5399d6ad440824e9b27f9f
languageName: node
linkType: hard
"zip-stream@npm:^6.0.1":
version: 6.0.1
resolution: "zip-stream@npm:6.0.1"