feat(backend): replace custom aiClient with @bytelyst/llm platform package
- Import PerplexityProvider, OpenAIProvider, GeminiProvider from @bytelyst/llm - Use createFallbackChain() instead of manual axios fallback loop - Remove axios and @types/axios — no longer needed - Preserve AIClient class interface (generateAnalysis, getProviderHealth) — no changes required in apiServer.ts or AIAnalysisRule.ts - Fallback order still driven by config.AI.FALLBACK_LIST Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
bcb6bf4d71
commit
c3651f5696
@ -53,11 +53,11 @@
|
|||||||
"@azure/cosmos": "^4.3.0",
|
"@azure/cosmos": "^4.3.0",
|
||||||
"@bytelyst/auth": "link:../../../learning_ai/learning_ai_common_plat/packages/auth",
|
"@bytelyst/auth": "link:../../../learning_ai/learning_ai_common_plat/packages/auth",
|
||||||
"@bytelyst/cosmos": "link:../../../learning_ai/learning_ai_common_plat/packages/cosmos",
|
"@bytelyst/cosmos": "link:../../../learning_ai/learning_ai_common_plat/packages/cosmos",
|
||||||
|
"@bytelyst/llm": "link:../../../learning_ai/learning_ai_common_plat/packages/llm",
|
||||||
"@alpacahq/alpaca-trade-api": "^3.1.3",
|
"@alpacahq/alpaca-trade-api": "^3.1.3",
|
||||||
"@supabase/supabase-js": "^2.90.1",
|
"@supabase/supabase-js": "^2.90.1",
|
||||||
"@types/cors": "^2.8.19",
|
"@types/cors": "^2.8.19",
|
||||||
"@types/express": "^5.0.6",
|
"@types/express": "^5.0.6",
|
||||||
"axios": "^1.13.2",
|
|
||||||
"ccxt": "^4.5.31",
|
"ccxt": "^4.5.31",
|
||||||
"cors": "^2.8.5",
|
"cors": "^2.8.5",
|
||||||
"dotenv": "^17.2.3",
|
"dotenv": "^17.2.3",
|
||||||
@ -68,7 +68,6 @@
|
|||||||
"winston": "^3.19.0"
|
"winston": "^3.19.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/axios": "^0.14.4",
|
|
||||||
"@types/node": "^25.0.3",
|
"@types/node": "^25.0.3",
|
||||||
"c8": "^10.1.3",
|
"c8": "^10.1.3",
|
||||||
"ts-node": "^10.9.2",
|
"ts-node": "^10.9.2",
|
||||||
|
|||||||
@ -1,4 +1,10 @@
|
|||||||
import axios from 'axios';
|
import {
|
||||||
|
createFallbackChain,
|
||||||
|
GeminiProvider,
|
||||||
|
OpenAIProvider,
|
||||||
|
PerplexityProvider,
|
||||||
|
type LLMProvider,
|
||||||
|
} from '@bytelyst/llm';
|
||||||
import { config } from '../config/index.js';
|
import { config } from '../config/index.js';
|
||||||
import logger from '../utils/logger.js';
|
import logger from '../utils/logger.js';
|
||||||
|
|
||||||
@ -14,224 +20,106 @@ export interface AIProviderHealth {
|
|||||||
message: string;
|
message: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface ProviderEntry {
|
||||||
|
name: AIProvider;
|
||||||
|
make: () => LLMProvider;
|
||||||
|
defaultModel: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
function resolveModel(provider: AIProvider): string {
|
||||||
|
switch (provider) {
|
||||||
|
case 'perplexity':
|
||||||
|
return config.AI.MODEL.includes('sonar') ? config.AI.MODEL : 'sonar';
|
||||||
|
case 'openai':
|
||||||
|
return config.AI.MODEL.includes('gpt') ? config.AI.MODEL : 'gpt-4o-mini';
|
||||||
|
case 'gemini':
|
||||||
|
return config.AI.MODEL.includes('gemini') ? config.AI.MODEL : 'gemini-1.5-flash';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const PROVIDER_REGISTRY: ProviderEntry[] = [
|
||||||
|
{
|
||||||
|
name: 'perplexity',
|
||||||
|
make: () => new PerplexityProvider({ apiKey: config.AI.PERPLEXITY_API_KEY, model: resolveModel('perplexity') }),
|
||||||
|
defaultModel: 'sonar',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'openai',
|
||||||
|
make: () => new OpenAIProvider({ apiKey: config.AI.OPENAI_API_KEY, model: resolveModel('openai') }),
|
||||||
|
defaultModel: 'gpt-4o-mini',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'gemini',
|
||||||
|
make: () => new GeminiProvider({ apiKey: config.AI.GEMINI_API_KEY, model: resolveModel('gemini') }),
|
||||||
|
defaultModel: 'gemini-1.5-flash',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
export class AIClient {
|
export class AIClient {
|
||||||
public async generateAnalysis(prompt: string): Promise<string | null> {
|
public async generateAnalysis(prompt: string): Promise<string | null> {
|
||||||
const fallbackList = config.AI.FALLBACK_LIST;
|
const ordered = this.buildOrderedProviders();
|
||||||
|
const chain = createFallbackChain(ordered.map(e => e.make()));
|
||||||
for (const provider of fallbackList) {
|
|
||||||
try {
|
if (!chain.isConfigured()) {
|
||||||
logger.info(`[AI] Attempting analysis with provider: ${provider}...`);
|
logger.warn('[AI] No providers configured — skipping analysis');
|
||||||
let result: string | null = null;
|
return null;
|
||||||
|
}
|
||||||
switch (provider) {
|
|
||||||
case 'openai':
|
try {
|
||||||
result = await this.callOpenAI(prompt);
|
const result = await chain.chatCompletion({
|
||||||
break;
|
messages: [
|
||||||
case 'perplexity':
|
{ role: 'system', content: 'You are an expert crypto trading assistant. Strictly output JSON.' },
|
||||||
result = await this.callPerplexity(prompt);
|
{ role: 'user', content: prompt },
|
||||||
break;
|
],
|
||||||
case 'gemini':
|
temperature: 0.2,
|
||||||
result = await this.callGemini(prompt);
|
});
|
||||||
break;
|
logger.info('[AI] Analysis generated successfully');
|
||||||
default:
|
return result.content;
|
||||||
logger.warn(`[AI] Unsupported provider in fallback list: ${provider}`);
|
} catch (error: any) {
|
||||||
continue;
|
logger.error(`[AI] All providers failed: ${error.message}`);
|
||||||
}
|
return null;
|
||||||
|
}
|
||||||
if (result) {
|
|
||||||
logger.info(`[AI] Successfully generated analysis using ${provider}.`);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
} catch (error: any) {
|
|
||||||
logger.error(`[AI] Provider ${provider} failed: ${error.message}`);
|
|
||||||
// Continue to next provider in fallback list
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.error('[AI] All providers in fallback list failed or were not configured.');
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async getProviderHealth(probe: boolean = false): Promise<AIProviderHealth[]> {
|
public async getProviderHealth(probe: boolean = false): Promise<AIProviderHealth[]> {
|
||||||
const fallbackList = config.AI.FALLBACK_LIST;
|
const fallbackList = config.AI.FALLBACK_LIST;
|
||||||
const providers: AIProvider[] = ['openai', 'perplexity', 'gemini'];
|
|
||||||
|
|
||||||
const results: AIProviderHealth[] = [];
|
const results: AIProviderHealth[] = [];
|
||||||
for (const provider of providers) {
|
|
||||||
const configured = this.isProviderConfigured(provider);
|
for (const entry of PROVIDER_REGISTRY) {
|
||||||
const model = this.resolveModel(provider);
|
const provider = entry.make();
|
||||||
const fallbackIndex = fallbackList.indexOf(provider);
|
const configured = provider.isConfigured();
|
||||||
|
const fallbackIndex = fallbackList.indexOf(entry.name);
|
||||||
const inFallbackList = fallbackIndex >= 0;
|
const inFallbackList = fallbackIndex >= 0;
|
||||||
|
const model = resolveModel(entry.name);
|
||||||
|
|
||||||
if (!configured) {
|
if (!configured) {
|
||||||
results.push({
|
results.push({ provider: entry.name, configured: false, model, inFallbackList, fallbackIndex: inFallbackList ? fallbackIndex : null, status: 'missing_key', message: 'API key missing' });
|
||||||
provider,
|
|
||||||
configured: false,
|
|
||||||
model,
|
|
||||||
inFallbackList,
|
|
||||||
fallbackIndex: inFallbackList ? fallbackIndex : null,
|
|
||||||
status: 'missing_key',
|
|
||||||
message: 'API key missing'
|
|
||||||
});
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!probe) {
|
if (!probe) {
|
||||||
results.push({
|
results.push({ provider: entry.name, configured: true, model, inFallbackList, fallbackIndex: inFallbackList ? fallbackIndex : null, status: 'configured', message: 'Configured (probe skipped)' });
|
||||||
provider,
|
|
||||||
configured: true,
|
|
||||||
model,
|
|
||||||
inFallbackList,
|
|
||||||
fallbackIndex: inFallbackList ? fallbackIndex : null,
|
|
||||||
status: 'configured',
|
|
||||||
message: 'Configured (probe skipped)'
|
|
||||||
});
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await this.probeProvider(provider);
|
await provider.chatCompletion({
|
||||||
results.push({
|
messages: [{ role: 'user', content: 'Return JSON: {"action":"HOLD","confidence":0,"reasoning":"probe"}' }],
|
||||||
provider,
|
temperature: 0,
|
||||||
configured: true,
|
|
||||||
model,
|
|
||||||
inFallbackList,
|
|
||||||
fallbackIndex: inFallbackList ? fallbackIndex : null,
|
|
||||||
status: 'ok',
|
|
||||||
message: 'Provider probe succeeded'
|
|
||||||
});
|
});
|
||||||
|
results.push({ provider: entry.name, configured: true, model, inFallbackList, fallbackIndex: inFallbackList ? fallbackIndex : null, status: 'ok', message: 'Provider probe succeeded' });
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
results.push({
|
results.push({ provider: entry.name, configured: true, model, inFallbackList, fallbackIndex: inFallbackList ? fallbackIndex : null, status: 'error', message: error?.message || 'Provider probe failed' });
|
||||||
provider,
|
|
||||||
configured: true,
|
|
||||||
model,
|
|
||||||
inFallbackList,
|
|
||||||
fallbackIndex: inFallbackList ? fallbackIndex : null,
|
|
||||||
status: 'error',
|
|
||||||
message: error?.message || 'Provider probe failed'
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
private isProviderConfigured(provider: AIProvider): boolean {
|
private buildOrderedProviders(): ProviderEntry[] {
|
||||||
switch (provider) {
|
const fallbackList = config.AI.FALLBACK_LIST;
|
||||||
case 'openai':
|
return fallbackList
|
||||||
return !!config.AI.OPENAI_API_KEY;
|
.map(name => PROVIDER_REGISTRY.find(e => e.name === name))
|
||||||
case 'perplexity':
|
.filter((e): e is ProviderEntry => e !== undefined);
|
||||||
return !!config.AI.PERPLEXITY_API_KEY;
|
|
||||||
case 'gemini':
|
|
||||||
return !!config.AI.GEMINI_API_KEY;
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
private resolveModel(provider: AIProvider): string {
|
|
||||||
switch (provider) {
|
|
||||||
case 'openai':
|
|
||||||
return config.AI.MODEL.includes('gpt') ? config.AI.MODEL : 'gpt-4o-mini';
|
|
||||||
case 'perplexity':
|
|
||||||
return config.AI.MODEL.includes('sonar') ? config.AI.MODEL : 'sonar';
|
|
||||||
case 'gemini':
|
|
||||||
return config.AI.MODEL.includes('gemini') ? config.AI.MODEL : 'gemini-1.5-flash';
|
|
||||||
default:
|
|
||||||
return config.AI.MODEL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async probeProvider(provider: AIProvider): Promise<void> {
|
|
||||||
const probePrompt = 'Return JSON: {"action":"HOLD","confidence":0,"reasoning":"probe"}';
|
|
||||||
let response: string | null = null;
|
|
||||||
|
|
||||||
switch (provider) {
|
|
||||||
case 'openai':
|
|
||||||
response = await this.callOpenAI(probePrompt);
|
|
||||||
break;
|
|
||||||
case 'perplexity':
|
|
||||||
response = await this.callPerplexity(probePrompt);
|
|
||||||
break;
|
|
||||||
case 'gemini':
|
|
||||||
response = await this.callGemini(probePrompt);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new Error(`Unsupported provider: ${provider}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!response || !String(response).trim()) {
|
|
||||||
throw new Error('Empty response from provider');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async callOpenAI(prompt: string): Promise<string | null> {
|
|
||||||
const apiKey = config.AI.OPENAI_API_KEY;
|
|
||||||
if (!apiKey) return null;
|
|
||||||
|
|
||||||
const model = config.AI.MODEL.includes('gpt') ? config.AI.MODEL : 'gpt-4o-mini';
|
|
||||||
|
|
||||||
const response = await axios.post(
|
|
||||||
'https://api.openai.com/v1/chat/completions',
|
|
||||||
{
|
|
||||||
model: model,
|
|
||||||
messages: [
|
|
||||||
{ role: 'system', content: 'You are an expert crypto trading assistant. strictly output JSON.' },
|
|
||||||
{ role: 'user', content: prompt }
|
|
||||||
],
|
|
||||||
temperature: 0.2
|
|
||||||
},
|
|
||||||
{
|
|
||||||
headers: {
|
|
||||||
'Authorization': `Bearer ${apiKey}`,
|
|
||||||
'Content-Type': 'application/json'
|
|
||||||
},
|
|
||||||
timeout: 10000
|
|
||||||
}
|
|
||||||
);
|
|
||||||
return response.data.choices[0].message.content;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async callPerplexity(prompt: string): Promise<string | null> {
|
|
||||||
const apiKey = config.AI.PERPLEXITY_API_KEY;
|
|
||||||
if (!apiKey) return null;
|
|
||||||
|
|
||||||
const model = config.AI.MODEL.includes('sonar') ? config.AI.MODEL : 'sonar';
|
|
||||||
|
|
||||||
const response = await axios.post(
|
|
||||||
'https://api.perplexity.ai/chat/completions',
|
|
||||||
{
|
|
||||||
model: model,
|
|
||||||
messages: [
|
|
||||||
{ role: 'system', content: 'You are an expert crypto trading assistant. Strictly output JSON.' },
|
|
||||||
{ role: 'user', content: prompt }
|
|
||||||
],
|
|
||||||
temperature: 0.2
|
|
||||||
},
|
|
||||||
{
|
|
||||||
headers: {
|
|
||||||
'Authorization': `Bearer ${apiKey}`,
|
|
||||||
'Content-Type': 'application/json'
|
|
||||||
},
|
|
||||||
timeout: 10000
|
|
||||||
}
|
|
||||||
);
|
|
||||||
return response.data.choices[0].message.content;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async callGemini(prompt: string): Promise<string | null> {
|
|
||||||
const apiKey = config.AI.GEMINI_API_KEY;
|
|
||||||
if (!apiKey) return null;
|
|
||||||
|
|
||||||
const model = config.AI.MODEL.includes('gemini') ? config.AI.MODEL : 'gemini-1.5-flash';
|
|
||||||
const url = `https://generativelanguage.googleapis.com/v1beta/models/${model}:generateContent?key=${apiKey}`;
|
|
||||||
|
|
||||||
const response = await axios.post(url, {
|
|
||||||
contents: [{
|
|
||||||
parts: [{ text: `You are an expert crypto trading assistant. Strictly output JSON.\n\n${prompt}` }]
|
|
||||||
}]
|
|
||||||
}, { timeout: 10000 });
|
|
||||||
|
|
||||||
return response.data.candidates[0].content.parts[0].text;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
67
pnpm-lock.yaml
generated
67
pnpm-lock.yaml
generated
@ -39,6 +39,9 @@ importers:
|
|||||||
'@bytelyst/cosmos':
|
'@bytelyst/cosmos':
|
||||||
specifier: link:../../../learning_ai/learning_ai_common_plat/packages/cosmos
|
specifier: link:../../../learning_ai/learning_ai_common_plat/packages/cosmos
|
||||||
version: link:../../../learning_ai/learning_ai_common_plat/packages/cosmos
|
version: link:../../../learning_ai/learning_ai_common_plat/packages/cosmos
|
||||||
|
'@bytelyst/llm':
|
||||||
|
specifier: link:../../../learning_ai/learning_ai_common_plat/packages/llm
|
||||||
|
version: link:../../../learning_ai/learning_ai_common_plat/packages/llm
|
||||||
'@supabase/supabase-js':
|
'@supabase/supabase-js':
|
||||||
specifier: ^2.90.1
|
specifier: ^2.90.1
|
||||||
version: 2.101.1
|
version: 2.101.1
|
||||||
@ -48,9 +51,6 @@ importers:
|
|||||||
'@types/express':
|
'@types/express':
|
||||||
specifier: ^5.0.6
|
specifier: ^5.0.6
|
||||||
version: 5.0.6
|
version: 5.0.6
|
||||||
axios:
|
|
||||||
specifier: ^1.13.2
|
|
||||||
version: 1.14.0
|
|
||||||
ccxt:
|
ccxt:
|
||||||
specifier: ^4.5.31
|
specifier: ^4.5.31
|
||||||
version: 4.5.46
|
version: 4.5.46
|
||||||
@ -76,9 +76,6 @@ importers:
|
|||||||
specifier: ^3.19.0
|
specifier: ^3.19.0
|
||||||
version: 3.19.0
|
version: 3.19.0
|
||||||
devDependencies:
|
devDependencies:
|
||||||
'@types/axios':
|
|
||||||
specifier: ^0.14.4
|
|
||||||
version: 0.14.4
|
|
||||||
'@types/node':
|
'@types/node':
|
||||||
specifier: ^25.0.3
|
specifier: ^25.0.3
|
||||||
version: 25.5.2
|
version: 25.5.2
|
||||||
@ -2168,10 +2165,6 @@ packages:
|
|||||||
'@types/aria-query@5.0.4':
|
'@types/aria-query@5.0.4':
|
||||||
resolution: {integrity: sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==}
|
resolution: {integrity: sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==}
|
||||||
|
|
||||||
'@types/axios@0.14.4':
|
|
||||||
resolution: {integrity: sha512-9JgOaunvQdsQ/qW2OPmE5+hCeUB52lQSolecrFrthct55QekhmXEwT203s20RL+UHtCQc15y3VXpby9E7Kkh/g==}
|
|
||||||
deprecated: This is a stub types definition. axios provides its own type definitions, so you do not need this installed.
|
|
||||||
|
|
||||||
'@types/babel__core@7.20.5':
|
'@types/babel__core@7.20.5':
|
||||||
resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==}
|
resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==}
|
||||||
|
|
||||||
@ -2684,9 +2677,6 @@ packages:
|
|||||||
async@3.2.6:
|
async@3.2.6:
|
||||||
resolution: {integrity: sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==}
|
resolution: {integrity: sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==}
|
||||||
|
|
||||||
asynckit@0.4.0:
|
|
||||||
resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==}
|
|
||||||
|
|
||||||
autoprefixer@10.4.27:
|
autoprefixer@10.4.27:
|
||||||
resolution: {integrity: sha512-NP9APE+tO+LuJGn7/9+cohklunJsXWiaWEfV3si4Gi/XHDwVNgkwr1J3RQYFIvPy76GmJ9/bW8vyoU1LcxwKHA==}
|
resolution: {integrity: sha512-NP9APE+tO+LuJGn7/9+cohklunJsXWiaWEfV3si4Gi/XHDwVNgkwr1J3RQYFIvPy76GmJ9/bW8vyoU1LcxwKHA==}
|
||||||
engines: {node: ^10 || ^12 || >=14}
|
engines: {node: ^10 || ^12 || >=14}
|
||||||
@ -2701,9 +2691,6 @@ packages:
|
|||||||
axios@0.21.4:
|
axios@0.21.4:
|
||||||
resolution: {integrity: sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==}
|
resolution: {integrity: sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==}
|
||||||
|
|
||||||
axios@1.14.0:
|
|
||||||
resolution: {integrity: sha512-3Y8yrqLSwjuzpXuZ0oIYZ/XGgLwUIBU3uLvbcpb0pidD9ctpShJd43KSlEEkVQg6DS0G9NKyzOvBfUtDKEyHvQ==}
|
|
||||||
|
|
||||||
babel-jest@29.7.0:
|
babel-jest@29.7.0:
|
||||||
resolution: {integrity: sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==}
|
resolution: {integrity: sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==}
|
||||||
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
|
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
|
||||||
@ -2988,10 +2975,6 @@ packages:
|
|||||||
resolution: {integrity: sha512-ezmVcLR3xAVp8kYOm4GS45ZLLgIE6SPAFoduLr6hTDajwb3KZ2F46gulK3XpcwRFb5KKGCSezCBAY4Dw4HsyXA==}
|
resolution: {integrity: sha512-ezmVcLR3xAVp8kYOm4GS45ZLLgIE6SPAFoduLr6hTDajwb3KZ2F46gulK3XpcwRFb5KKGCSezCBAY4Dw4HsyXA==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
|
|
||||||
combined-stream@1.0.8:
|
|
||||||
resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==}
|
|
||||||
engines: {node: '>= 0.8'}
|
|
||||||
|
|
||||||
commander@12.1.0:
|
commander@12.1.0:
|
||||||
resolution: {integrity: sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==}
|
resolution: {integrity: sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
@ -3207,10 +3190,6 @@ packages:
|
|||||||
resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==}
|
resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
|
|
||||||
delayed-stream@1.0.0:
|
|
||||||
resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==}
|
|
||||||
engines: {node: '>=0.4.0'}
|
|
||||||
|
|
||||||
depd@2.0.0:
|
depd@2.0.0:
|
||||||
resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==}
|
resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==}
|
||||||
engines: {node: '>= 0.8'}
|
engines: {node: '>= 0.8'}
|
||||||
@ -3850,10 +3829,6 @@ packages:
|
|||||||
resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==}
|
resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==}
|
||||||
engines: {node: '>=14'}
|
engines: {node: '>=14'}
|
||||||
|
|
||||||
form-data@4.0.5:
|
|
||||||
resolution: {integrity: sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==}
|
|
||||||
engines: {node: '>= 6'}
|
|
||||||
|
|
||||||
forwarded@0.2.0:
|
forwarded@0.2.0:
|
||||||
resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==}
|
resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==}
|
||||||
engines: {node: '>= 0.6'}
|
engines: {node: '>= 0.6'}
|
||||||
@ -5105,10 +5080,6 @@ packages:
|
|||||||
resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==}
|
resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==}
|
||||||
engines: {node: '>= 0.10'}
|
engines: {node: '>= 0.10'}
|
||||||
|
|
||||||
proxy-from-env@2.1.0:
|
|
||||||
resolution: {integrity: sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==}
|
|
||||||
engines: {node: '>=10'}
|
|
||||||
|
|
||||||
punycode@2.3.1:
|
punycode@2.3.1:
|
||||||
resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
|
resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
|
||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
@ -8596,12 +8567,6 @@ snapshots:
|
|||||||
|
|
||||||
'@types/aria-query@5.0.4': {}
|
'@types/aria-query@5.0.4': {}
|
||||||
|
|
||||||
'@types/axios@0.14.4':
|
|
||||||
dependencies:
|
|
||||||
axios: 1.14.0
|
|
||||||
transitivePeerDependencies:
|
|
||||||
- debug
|
|
||||||
|
|
||||||
'@types/babel__core@7.20.5':
|
'@types/babel__core@7.20.5':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@babel/parser': 7.29.2
|
'@babel/parser': 7.29.2
|
||||||
@ -9171,8 +9136,6 @@ snapshots:
|
|||||||
|
|
||||||
async@3.2.6: {}
|
async@3.2.6: {}
|
||||||
|
|
||||||
asynckit@0.4.0: {}
|
|
||||||
|
|
||||||
autoprefixer@10.4.27(postcss@8.5.8):
|
autoprefixer@10.4.27(postcss@8.5.8):
|
||||||
dependencies:
|
dependencies:
|
||||||
browserslist: 4.28.2
|
browserslist: 4.28.2
|
||||||
@ -9192,14 +9155,6 @@ snapshots:
|
|||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- debug
|
- debug
|
||||||
|
|
||||||
axios@1.14.0:
|
|
||||||
dependencies:
|
|
||||||
follow-redirects: 1.15.11
|
|
||||||
form-data: 4.0.5
|
|
||||||
proxy-from-env: 2.1.0
|
|
||||||
transitivePeerDependencies:
|
|
||||||
- debug
|
|
||||||
|
|
||||||
babel-jest@29.7.0(@babel/core@7.29.0):
|
babel-jest@29.7.0(@babel/core@7.29.0):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@babel/core': 7.29.0
|
'@babel/core': 7.29.0
|
||||||
@ -9565,10 +9520,6 @@ snapshots:
|
|||||||
color-convert: 3.1.3
|
color-convert: 3.1.3
|
||||||
color-string: 2.1.4
|
color-string: 2.1.4
|
||||||
|
|
||||||
combined-stream@1.0.8:
|
|
||||||
dependencies:
|
|
||||||
delayed-stream: 1.0.0
|
|
||||||
|
|
||||||
commander@12.1.0: {}
|
commander@12.1.0: {}
|
||||||
|
|
||||||
commander@2.20.3: {}
|
commander@2.20.3: {}
|
||||||
@ -9777,8 +9728,6 @@ snapshots:
|
|||||||
has-property-descriptors: 1.0.2
|
has-property-descriptors: 1.0.2
|
||||||
object-keys: 1.1.1
|
object-keys: 1.1.1
|
||||||
|
|
||||||
delayed-stream@1.0.0: {}
|
|
||||||
|
|
||||||
depd@2.0.0: {}
|
depd@2.0.0: {}
|
||||||
|
|
||||||
dequal@2.0.3: {}
|
dequal@2.0.3: {}
|
||||||
@ -10667,14 +10616,6 @@ snapshots:
|
|||||||
cross-spawn: 7.0.6
|
cross-spawn: 7.0.6
|
||||||
signal-exit: 4.1.0
|
signal-exit: 4.1.0
|
||||||
|
|
||||||
form-data@4.0.5:
|
|
||||||
dependencies:
|
|
||||||
asynckit: 0.4.0
|
|
||||||
combined-stream: 1.0.8
|
|
||||||
es-set-tostringtag: 2.1.0
|
|
||||||
hasown: 2.0.2
|
|
||||||
mime-types: 2.1.35
|
|
||||||
|
|
||||||
forwarded@0.2.0: {}
|
forwarded@0.2.0: {}
|
||||||
|
|
||||||
fraction.js@5.3.4: {}
|
fraction.js@5.3.4: {}
|
||||||
@ -12135,8 +12076,6 @@ snapshots:
|
|||||||
forwarded: 0.2.0
|
forwarded: 0.2.0
|
||||||
ipaddr.js: 1.9.1
|
ipaddr.js: 1.9.1
|
||||||
|
|
||||||
proxy-from-env@2.1.0: {}
|
|
||||||
|
|
||||||
punycode@2.3.1: {}
|
punycode@2.3.1: {}
|
||||||
|
|
||||||
qrcode-terminal@0.11.0: {}
|
qrcode-terminal@0.11.0: {}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user