diff --git a/apps/backend/package.json b/apps/backend/package.json index 46d281c..d238301 100644 --- a/apps/backend/package.json +++ b/apps/backend/package.json @@ -24,6 +24,7 @@ "dependencies": { "@anthropic-ai/sdk": "^0.80.0", "@deepgram/sdk": "^5.0.0", + "@mastra/core": "^1.17.0", "@nestjs/common": "^11.1.17", "@nestjs/config": "^4.0.3", "@nestjs/core": "^11.1.17", @@ -46,7 +47,8 @@ "reflect-metadata": "^0.2.2", "rxjs": "^7.8.2", "socket.io": "^4.8.3", - "typeorm": "^0.3.28" + "typeorm": "^0.3.28", + "zod": "^4.3.6" }, "devDependencies": { "@nestjs/cli": "^11.0.16", diff --git a/apps/backend/src/adapters/outbound/cache/redis.adapter.ts b/apps/backend/src/adapters/outbound/cache/redis.adapter.ts new file mode 100644 index 0000000..172de20 --- /dev/null +++ b/apps/backend/src/adapters/outbound/cache/redis.adapter.ts @@ -0,0 +1,56 @@ +import { Injectable, Logger, OnModuleDestroy } from '@nestjs/common'; +import { ConfigService } from '@nestjs/config'; +import Redis from 'ioredis'; +import { ICachePort } from '../../../core/ports/outbound/cache.port'; + +@Injectable() +export class RedisAdapter implements ICachePort, OnModuleDestroy { + private readonly logger = new Logger(RedisAdapter.name); + private readonly redis: Redis; + + constructor(private readonly configService: ConfigService) { + this.redis = new Redis({ + host: this.configService.get('redis.host', 'localhost'), + port: this.configService.get('redis.port', 6379), + password: this.configService.get('redis.password'), + }); + + this.redis.on('connect', () => this.logger.log('Connected to Redis')); + this.redis.on('error', (err) => this.logger.error('Redis error:', err)); + } + + async get(key: string): Promise { + const value = await this.redis.get(key); + if (!value) return null; + return JSON.parse(value) as T; + } + + async set(key: string, value: T, ttlSeconds?: number): Promise { + const serialized = JSON.stringify(value); + if (ttlSeconds) { + await this.redis.set(key, serialized, 'EX', ttlSeconds); + } else { + await this.redis.set(key, serialized); + } + } + + async del(key: string): Promise { + await this.redis.del(key); + } + + async lpush(key: string, value: string): Promise { + await this.redis.lpush(key, value); + } + + async lrange(key: string, start: number, stop: number): Promise { + return this.redis.lrange(key, start, stop); + } + + async expire(key: string, ttlSeconds: number): Promise { + await this.redis.expire(key, ttlSeconds); + } + + async onModuleDestroy() { + await this.redis.quit(); + } +} diff --git a/apps/backend/src/app.module.ts b/apps/backend/src/app.module.ts index bdf07d7..7545866 100644 --- a/apps/backend/src/app.module.ts +++ b/apps/backend/src/app.module.ts @@ -24,11 +24,13 @@ import { DeepgramAdapter } from './adapters/outbound/stt/deepgram.adapter'; import { AnthropicAdapter } from './adapters/outbound/llm/anthropic.adapter'; import { OpenAIAdapter } from './adapters/outbound/llm/openai.adapter'; import { ElevenLabsAdapter } from './adapters/outbound/tts/elevenlabs.adapter'; +import { RedisAdapter } from './adapters/outbound/cache/redis.adapter'; import { CONVERSATION_PORT } from './core/ports/inbound/conversation.port'; import { STT_PORT } from './core/ports/outbound/stt.port'; import { LLM_PORT } from './core/ports/outbound/llm.port'; import { TTS_PORT } from './core/ports/outbound/tts.port'; import { DEVICE_GATEWAY_PORT } from './core/ports/outbound/device-gateway.port'; +import { CACHE_PORT } from './core/ports/outbound/cache.port'; @Module({ imports: [ @@ -83,6 +85,10 @@ import { DEVICE_GATEWAY_PORT } from './core/ports/outbound/device-gateway.port'; provide: TTS_PORT, useClass: ElevenLabsAdapter, }, + { + provide: CACHE_PORT, + useClass: RedisAdapter, + }, { provide: DEVICE_GATEWAY_PORT, useExisting: RobotGateway, diff --git a/apps/backend/src/core/services/conversation.service.ts b/apps/backend/src/core/services/conversation.service.ts index 1a75d79..f265a78 100644 --- a/apps/backend/src/core/services/conversation.service.ts +++ b/apps/backend/src/core/services/conversation.service.ts @@ -1,38 +1,79 @@ import { Inject, Injectable, Logger, forwardRef } from '@nestjs/common'; +import { ConfigService } from '@nestjs/config'; +import { Agent } from '@mastra/core/agent'; import { IConversationPort } from '../ports/inbound/conversation.port'; import { ISTTPort, ISTTStream, STT_PORT, TranscriptionResult } from '../ports/outbound/stt.port'; -import { ILLMPort, LLM_PORT, LLMMessage } from '../ports/outbound/llm.port'; import { ITTSPort, TTS_PORT } from '../ports/outbound/tts.port'; +import { ICachePort, CACHE_PORT } from '../ports/outbound/cache.port'; import { IDeviceGatewayPort, DEVICE_GATEWAY_PORT } from '../ports/outbound/device-gateway.port'; +import { datetimeTool, mathTool } from '../tools'; interface ActiveSession { deviceId: string; - transcription: string; - messages: LLMMessage[]; + finalTranscription: string; + interimTranscription: string; sttStream: ISTTStream | null; } const SYSTEM_PROMPT = `Tu es Ti-Pote, un petit robot de bureau animatronique, chaleureux et serviable. Tu parles en français. Tu es concis dans tes réponses car elles seront lues à voix haute. Tu as une personnalité enjouée mais tu restes utile et pertinent. -Réponds en 1 à 3 phrases maximum.`; +Réponds en 1 à 3 phrases maximum. +Tu as accès à des outils : utilise-les quand c'est pertinent au lieu de deviner.`; + +const SESSION_TTL = 60 * 30; +const MAX_MESSAGES = 50; @Injectable() export class ConversationService implements IConversationPort { private readonly logger = new Logger(ConversationService.name); private readonly activeSessions = new Map(); + private readonly agent: Agent; constructor( @Inject(STT_PORT) private readonly sttPort: ISTTPort, - @Inject(LLM_PORT) private readonly llmPort: ILLMPort, @Inject(TTS_PORT) private readonly ttsPort: ITTSPort, + @Inject(CACHE_PORT) private readonly cache: ICachePort, @Inject(forwardRef(() => DEVICE_GATEWAY_PORT)) private readonly deviceGateway: IDeviceGatewayPort, - ) {} + private readonly configService: ConfigService, + ) { + const provider = this.configService.get('LLM_PROVIDER', 'anthropic'); + const model = + provider === 'openai' + ? `openai/${this.configService.get('OPENAI_MODEL', 'gpt-4o')}` + : `anthropic/${this.configService.get('ANTHROPIC_MODEL', 'claude-sonnet-4-20250514')}`; + + this.agent = new Agent({ + id: 'ti-pote', + name: 'Ti-Pote', + instructions: SYSTEM_PROMPT, + model: model as any, + tools: { + datetimeTool, + mathTool, + }, + }); + + this.logger.log(`Agent created with model: ${model}`); + } + + private sessionKey(deviceId: string): string { + return `conversation:${deviceId}`; + } + + private async loadMessages(deviceId: string): Promise> { + const messages = await this.cache.get>(this.sessionKey(deviceId)); + return messages ?? []; + } + + private async saveMessages(deviceId: string, messages: Array<{ role: string; content: string }>): Promise { + const trimmed = messages.slice(-MAX_MESSAGES); + await this.cache.set(this.sessionKey(deviceId), trimmed, SESSION_TTL); + } async startListening(deviceId: string): Promise { this.logger.log(`Start listening for device ${deviceId}`); - // Close previous STT stream if any const existing = this.activeSessions.get(deviceId); if (existing?.sttStream) { await existing.sttStream.close(); @@ -40,8 +81,8 @@ export class ConversationService implements IConversationPort { const session: ActiveSession = { deviceId, - transcription: '', - messages: existing?.messages ?? [], + finalTranscription: '', + interimTranscription: '', sttStream: null, }; @@ -53,7 +94,10 @@ export class ConversationService implements IConversationPort { ); if (result.isFinal) { - session.transcription += result.text + ' '; + session.finalTranscription += result.text + ' '; + session.interimTranscription = ''; + } else { + session.interimTranscription = result.text; } }); @@ -82,29 +126,40 @@ export class ConversationService implements IConversationPort { session.sttStream = null; } - const finalText = session.transcription.trim() || null; + // Use final transcription, fall back to last interim result + const finalText = session.finalTranscription.trim() || session.interimTranscription.trim() || null; this.logger.log(`Final transcription for ${deviceId}: "${finalText}"`); if (!finalText) { return null; } - session.messages.push({ role: 'user', content: finalText }); - session.transcription = ''; + const messages = await this.loadMessages(deviceId); + messages.push({ role: 'user', content: finalText }); + session.finalTranscription = ''; + session.interimTranscription = ''; try { this.deviceGateway.sendStatus(deviceId, 'thinking'); - const llmMessages: LLMMessage[] = [ - { role: 'system', content: SYSTEM_PROMPT }, - ...session.messages, - ]; + const coreMessages = messages.map((m) => ({ + role: m.role as 'user' | 'assistant', + content: m.content, + })); - const llmResponse = await this.llmPort.chat(llmMessages); - const responseText = llmResponse.content ?? ''; - this.logger.log(`LLM response for ${deviceId}: "${responseText}"`); + const response = await this.agent.generate(coreMessages as any, { maxSteps: 5 }); - session.messages.push({ role: 'assistant', content: responseText }); + const responseText = response.text ?? ''; + this.logger.log(`Agent response for ${deviceId}: "${responseText}"`); + + if (response.toolCalls && response.toolCalls.length > 0) { + this.logger.log( + `Tools called: ${response.toolCalls.map((tc: any) => tc.toolName).join(', ')}`, + ); + } + + messages.push({ role: 'assistant', content: responseText }); + await this.saveMessages(deviceId, messages); if (responseText) { this.deviceGateway.sendStatus(deviceId, 'speaking'); @@ -119,6 +174,7 @@ export class ConversationService implements IConversationPort { } } catch (error) { this.logger.error(`Error processing conversation for ${deviceId}:`, error); + await this.saveMessages(deviceId, messages); this.deviceGateway.sendStatus(deviceId, 'idle'); } @@ -138,8 +194,8 @@ export class ConversationService implements IConversationPort { header.writeUInt32LE(dataSize + headerSize - 8, 4); header.write('WAVE', 8); header.write('fmt ', 12); - header.writeUInt32LE(16, 16); // subchunk1 size - header.writeUInt16LE(1, 20); // PCM format + header.writeUInt32LE(16, 16); + header.writeUInt16LE(1, 20); header.writeUInt16LE(numChannels, 22); header.writeUInt32LE(sampleRate, 24); header.writeUInt32LE(byteRate, 28); diff --git a/apps/backend/src/core/tools/datetime.tool.ts b/apps/backend/src/core/tools/datetime.tool.ts new file mode 100644 index 0000000..8674112 --- /dev/null +++ b/apps/backend/src/core/tools/datetime.tool.ts @@ -0,0 +1,30 @@ +import { createTool } from '@mastra/core/tools'; +import { z } from 'zod'; + +export const datetimeTool = createTool({ + id: 'get-datetime', + description: + "Donne la date et l'heure actuelles. Utilise cet outil quand l'utilisateur demande la date, l'heure, le jour de la semaine, etc.", + inputSchema: z.object({ + timezone: z + .string() + .optional() + .describe('Fuseau horaire (ex: "Europe/Paris"). Par défaut: Europe/Paris'), + }), + outputSchema: z.object({ + date: z.string(), + time: z.string(), + dayOfWeek: z.string(), + timestamp: z.number(), + }), + execute: async ({ context }) => { + const tz = context?.timezone || 'Europe/Paris'; + const now = new Date(); + + const date = now.toLocaleDateString('fr-FR', { timeZone: tz, day: 'numeric', month: 'long', year: 'numeric' }); + const time = now.toLocaleTimeString('fr-FR', { timeZone: tz, hour: '2-digit', minute: '2-digit' }); + const dayOfWeek = now.toLocaleDateString('fr-FR', { timeZone: tz, weekday: 'long' }); + + return { date, time, dayOfWeek, timestamp: now.getTime() }; + }, +}); diff --git a/apps/backend/src/core/tools/index.ts b/apps/backend/src/core/tools/index.ts new file mode 100644 index 0000000..ebaa164 --- /dev/null +++ b/apps/backend/src/core/tools/index.ts @@ -0,0 +1,2 @@ +export { datetimeTool } from './datetime.tool'; +export { mathTool } from './math.tool'; diff --git a/apps/backend/src/core/tools/math.tool.ts b/apps/backend/src/core/tools/math.tool.ts new file mode 100644 index 0000000..d4e7c4b --- /dev/null +++ b/apps/backend/src/core/tools/math.tool.ts @@ -0,0 +1,37 @@ +import { createTool } from '@mastra/core/tools'; +import { z } from 'zod'; + +export const mathTool = createTool({ + id: 'calculate', + description: + 'Effectue un calcul mathématique précis. Utilise cet outil pour toute opération arithmétique au lieu de calculer toi-même.', + inputSchema: z.object({ + expression: z.string().describe('Expression mathématique à évaluer (ex: "347 * 28", "sqrt(144)", "2^10")'), + }), + outputSchema: z.object({ + result: z.number(), + expression: z.string(), + }), + execute: async ({ context }) => { + const expr = context?.expression; + if (!expr) throw new Error('Expression manquante'); + + // Safe math evaluation — no eval() + const sanitized = expr.replace(/[^0-9+\-*/().,%^ sqrtpiePIE]/g, ''); + + const prepared = sanitized + .replace(/\^/g, '**') + .replace(/sqrt\(/gi, 'Math.sqrt(') + .replace(/pi/gi, 'Math.PI') + .replace(/e(?![a-z])/gi, 'Math.E'); + + const fn = new Function(`"use strict"; return (${prepared})`); + const result = fn(); + + if (typeof result !== 'number' || !isFinite(result)) { + throw new Error(`Expression invalide: "${expr}"`); + } + + return { result, expression: expr }; + }, +}); diff --git a/apps/simulator/index.html b/apps/simulator/index.html index 0bbf501..b380cc5 100644 --- a/apps/simulator/index.html +++ b/apps/simulator/index.html @@ -7,6 +7,7 @@ diff --git a/apps/simulator/src/App.tsx b/apps/simulator/src/App.tsx index 9a50873..311e6e8 100644 --- a/apps/simulator/src/App.tsx +++ b/apps/simulator/src/App.tsx @@ -4,24 +4,28 @@ import { useMicrophone } from './hooks/useMicrophone'; const STATE_COLORS: Record = { disconnected: '#666', - idle: '#888', + idle: '#4caf50', listening: '#2196f3', thinking: '#ff9800', - speaking: '#4caf50', + speaking: '#ab47bc', }; const STATE_LABELS: Record = { disconnected: 'Déconnecté', - idle: 'Veille', + idle: 'Prêt', listening: 'Écoute...', thinking: 'Réflexion...', speaking: 'Parle...', }; +const LS_KEY_TOKEN = 'tipote_device_token'; +const LS_KEY_URL = 'tipote_server_url'; + function App() { - const [serverUrl, setServerUrl] = useState('http://localhost:3000'); - const [deviceToken, setDeviceToken] = useState(''); + const [serverUrl, setServerUrl] = useState(() => localStorage.getItem(LS_KEY_URL) || 'http://localhost:3000'); + const [deviceToken, setDeviceToken] = useState(() => localStorage.getItem(LS_KEY_TOKEN) || ''); const [conversationActive, setConversationActive] = useState(false); + const [showLogs, setShowLogs] = useState(false); const { state, connected, logs, connect, disconnect, emit, clearLogs } = useSocket(); const logsEndRef = useRef(null); const prevStateRef = useRef('disconnected'); @@ -64,6 +68,17 @@ function App() { logsEndRef.current?.scrollIntoView({ behavior: 'smooth' }); }, [logs]); + // Persist settings to localStorage + const handleServerUrlChange = (value: string) => { + setServerUrl(value); + localStorage.setItem(LS_KEY_URL, value); + }; + + const handleTokenChange = (value: string) => { + setDeviceToken(value); + localStorage.setItem(LS_KEY_TOKEN, value); + }; + const handleConnect = () => { if (connected) { disconnect(); @@ -74,110 +89,147 @@ function App() { } }; - const handleWakeWord = () => { - setConversationActive(true); - emit('wake_word_detected'); - if (!recording) startMic(); - }; - - const handleInterrupt = () => { - setConversationActive(false); - emit('user_interrupt'); - if (recording) stopMic(); + const handleConversation = () => { + if (conversationActive) { + setConversationActive(false); + emit('user_interrupt'); + if (recording) stopMic(); + } else { + setConversationActive(true); + emit('wake_word_detected'); + startMic(); + } }; return (
-

Ti-Pote Simulator

- - {/* Connection panel */} -
-

Connexion

-
- - setServerUrl(e.target.value)} - disabled={connected} - /> -
-
- - setDeviceToken(e.target.value)} - disabled={connected} - placeholder="JWT du device" - /> -
- -
- - {/* Status */} -
-

État du robot

-
-
- {STATE_LABELS[state]} + {/* Header */} +
+

Ti-Pote Simulator

+
+ {STATE_LABELS[state]}
- {/* Controls */} -
-

Contrôles

-
- + {/* Connection */} + {!connected ? ( +
+

Connexion

+
+ + handleServerUrlChange(e.target.value)} + placeholder="http://localhost:3000" + /> +
+
+ + handleTokenChange(e.target.value)} + placeholder="Coller le JWT du device ici" + /> +
-
-
+ ) : ( + <> + {/* Main action */} +
+ - {/* Logs */} + {conversationActive && recording && ( +
+ + Micro actif — parlez, Ti-Pote écoute +
+ )} + + {conversationActive && state === 'thinking' && ( +
Ti-Pote réfléchit...
+ )} + + {conversationActive && state === 'speaking' && ( +
Ti-Pote parle...
+ )} +
+ + {/* Disconnect */} + + + )} + + {/* Logs (collapsible) */}
-

Logs

- + {showLogs && ( + + )}
-
- {logs.map((log, i) => ( -
- {log.timestamp.toLocaleTimeString()} - - {log.direction === 'in' ? '◀' : log.direction === 'out' ? '▶' : '●'} - - {log.event} - {log.data && {log.data}} -
- ))} -
-
+ {showLogs && ( +
+ {logs.map((log, i) => ( +
+ {log.timestamp.toLocaleTimeString()} + + {log.direction === 'in' ? '◀' : log.direction === 'out' ? '▶' : '●'} + + {log.event} + {log.data && {log.data}} +
+ ))} +
+
+ )}
); @@ -185,36 +237,50 @@ function App() { const styles: Record = { container: { - maxWidth: 640, + maxWidth: 480, margin: '0 auto', - padding: 24, + padding: 20, fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif', color: '#e0e0e0', background: '#1a1a2e', minHeight: '100vh', }, - title: { - fontSize: 24, - fontWeight: 700, + header: { + display: 'flex', + justifyContent: 'space-between', + alignItems: 'center', marginBottom: 20, + }, + title: { + fontSize: 20, + fontWeight: 700, color: '#fff', + margin: 0, + }, + statusBadge: { + padding: '6px 14px', + borderRadius: 20, + fontSize: 12, + fontWeight: 600, + color: '#fff', + transition: 'all 0.3s', }, panel: { background: '#16213e', - borderRadius: 8, + borderRadius: 12, padding: 16, - marginBottom: 16, + marginBottom: 12, }, panelTitle: { - fontSize: 14, + fontSize: 13, fontWeight: 600, textTransform: 'uppercase' as const, letterSpacing: 1, - color: '#888', + color: '#666', margin: '0 0 12px 0', }, field: { - marginBottom: 10, + marginBottom: 12, }, label: { display: 'block', @@ -224,41 +290,61 @@ const styles: Record = { }, input: { width: '100%', - padding: '8px 12px', + padding: '10px 12px', border: '1px solid #333', - borderRadius: 4, + borderRadius: 8, background: '#0f3460', color: '#fff', fontSize: 14, boxSizing: 'border-box' as const, + outline: 'none', }, btn: { padding: '8px 20px', border: 'none', - borderRadius: 4, + borderRadius: 8, color: '#fff', fontSize: 14, fontWeight: 600, cursor: 'pointer', }, - btnRow: { - display: 'flex', - gap: 8, - }, - statusRow: { + listeningIndicator: { display: 'flex', alignItems: 'center', - gap: 12, + gap: 10, + marginTop: 12, + padding: '10px 14px', + background: '#1a237e', + borderRadius: 8, + fontSize: 13, + color: '#90caf9', }, - statusDot: { - width: 16, - height: 16, + pulse: { + display: 'inline-block', + width: 10, + height: 10, borderRadius: '50%', - transition: 'all 0.3s', + background: '#2196f3', + animation: 'pulse 1.5s infinite', + flexShrink: 0, }, - statusLabel: { - fontSize: 18, - fontWeight: 600, + thinkingIndicator: { + marginTop: 12, + padding: '10px 14px', + background: '#4a2800', + borderRadius: 8, + fontSize: 13, + color: '#ffb74d', + textAlign: 'center' as const, + }, + speakingIndicator: { + marginTop: 12, + padding: '10px 14px', + background: '#2a1040', + borderRadius: 8, + fontSize: 13, + color: '#ce93d8', + textAlign: 'center' as const, }, logHeader: { display: 'flex', @@ -266,24 +352,25 @@ const styles: Record = { alignItems: 'center', }, logContainer: { - height: 250, + maxHeight: 200, overflowY: 'auto' as const, fontFamily: 'monospace', - fontSize: 12, + fontSize: 11, background: '#0a0a1a', - borderRadius: 4, + borderRadius: 6, padding: 8, + marginTop: 8, }, logEntry: { display: 'flex', - gap: 8, + gap: 6, padding: '2px 0', borderBottom: '1px solid #1a1a2e', }, - logTime: { color: '#666', flexShrink: 0 }, + logTime: { color: '#555', flexShrink: 0 }, logDirection: { flexShrink: 0 }, - logEvent: { color: '#fff', fontWeight: 600, flexShrink: 0 }, - logData: { color: '#aaa', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' as const }, + logEvent: { color: '#ccc', fontWeight: 600, flexShrink: 0 }, + logData: { color: '#888', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' as const }, }; export default App; diff --git a/docs/business-plan.md b/docs/business-plan.md new file mode 100644 index 0000000..914e6ef --- /dev/null +++ b/docs/business-plan.md @@ -0,0 +1,224 @@ +# Ti-Pote — Business Plan & Analyse de Rentabilité + +## 1. Coûts de production hardware (par unité) + +Les coûts ci-dessous sont basés sur le BOM détaillé dans `hardware.md`, avec une estimation des coûts réels en petite série (10-50 unités) incluant l'assemblage. + +### 1.1 Configurations proposées + +| Config | Composants clés | Coût composants | Assemblage & divers | **Coût total unitaire** | +|--------|----------------|-----------------|---------------------|------------------------| +| **Starter** (voix seule) | Pi Zero 2W, ESP32-S3, micro, speaker, ampli, boîtier 3D | 60€ | ~15€ | **~75€** | +| **Standard** (voix + caméra + écran + LEDs + servos) | Starter + caméra, OLED, NeoPixel, 2× servos | 112€ | ~25€ | **~137€** | +| **Mobile** (tout + mobilité) | Standard + moteurs, driver, batterie, capteurs | 171€ | ~35€ | **~206€** | + +> **Note :** Les coûts d'assemblage incluent : soudure, câblage, impression 3D (filament + temps machine), carte PCB custom, tests QA. En petite série (fait main), c'est le poste le plus variable. + +### 1.2 Projection en volume + +| Volume de production | Réduction estimée sur composants | Coût unitaire Standard | +|---------------------|----------------------------------|----------------------| +| 1-10 unités | Prix catalogue (0%) | ~137€ | +| 10-50 unités | -10% (achats groupés) | ~125€ | +| 50-200 unités | -20% (fournisseurs directs) | ~115€ | +| 200+ unités | -30% (MOQ, PCB en série) | ~100€ | + +--- + +## 2. Coûts opérationnels cloud (mensuels) + +C'est le poste récurrent. Il augmente avec le nombre d'utilisateurs mais pas de façon linéaire grâce au mutualisation de l'infra. + +### 2.1 Infrastructure fixe + +| Service | Spec | Coût/mois | +|---------|------|-----------| +| VPS (Hetzner CPX31) | 4 vCPU, 8 Go RAM, 80 Go SSD | 15€ | +| Domaine + DNS | tipote.dev | ~1€ | +| Backups (S3-compatible) | pg_dump quotidien | ~2€ | +| **Total infra fixe** | | **~18€/mois** | + +> Ce VPS supporte confortablement 10-30 utilisateurs simultanés. Au-delà, upgrade vers un CPX41 (~30€/mois) pour 50+ utilisateurs. + +### 2.2 Coûts API par utilisateur (usage "raisonnable") + +**Hypothèse d'usage raisonnable** = ~20-30 min d'interaction/jour, ~25 requêtes vocales/jour. + +| Service | Provider | Tarif unitaire | Usage/user/mois | **Coût/user/mois** | +|---------|----------|---------------|-----------------|-------------------| +| **LLM** | Claude Haiku 3.5 | ~0.80$/M input, ~4$/M output | ~750 requêtes, ~2M tokens in, ~500K out | **~3.60€** | +| **LLM** | Claude Sonnet 4 | ~3$/M input, ~15$/M output | idem | **~13.50€** | +| **STT** | Deepgram Nova-2 | 0.0043$/min | ~450 min (15 min/jour) | **~1.95€** | +| **TTS** | OpenAI TTS | 15$/M chars | ~300K chars | **~4.50€** | +| **TTS** | ElevenLabs (Scale) | ~0.18$/1K chars | ~300K chars | **~5.40€** | +| **Embeddings** | OpenAI ada-002 | 0.10$/M tokens | ~100K tokens | **~0.01€** | + +### 2.3 Scénarios de coût mensuel total (10 utilisateurs) + +| Scénario | LLM | STT | TTS | Infra | **Total/mois** | **Par user** | +|----------|-----|-----|-----|-------|---------------|-------------| +| **Économique** (Haiku + Deepgram + OpenAI TTS) | 36€ | 19€ | 45€ | 18€ | **~118€** | **~11.80€** | +| **Équilibré** (Sonnet + Deepgram + OpenAI TTS) | 135€ | 19€ | 45€ | 18€ | **~217€** | **~21.70€** | +| **Premium** (Sonnet + Deepgram + ElevenLabs) | 135€ | 19€ | 54€ | 18€ | **~226€** | **~22.60€** | +| **Optimisé** (Haiku + cache agressif Redis) | 22€ | 19€ | 30€ | 18€ | **~89€** | **~8.90€** | + +--- + +## 3. Modèles de monétisation + +### 3.1 Option A — Vente du robot + abonnement cloud (recommandé) + +Le modèle le plus viable : marge sur le hardware + revenu récurrent sur le service. + +**Prix de vente du robot :** + +| Config | Coût prod. | Prix de vente | Marge brute | Marge % | +|--------|-----------|---------------|-------------|---------| +| Starter | 75€ | 149€ | 74€ | 50% | +| Standard | 137€ | 249€ | 112€ | 45% | +| Mobile | 206€ | 399€ | 193€ | 48% | + +**Abonnement mensuel :** + +| Plan | Fonctionnalités | Prix/mois | Coût réel/user | **Marge/user/mois** | Scénario coût | +|------|----------------|-----------|---------------|-------------------|--------------| +| **Gratuit** | 5 interactions/jour, Haiku only | 0€ | ~1€ | -1€ (acquisition) | Minimal | +| **Essentiel** | 50 interactions/jour, Haiku, mémoire basique | 9.99€ | ~7.10€ | **+2.89€** | Optimisé (Haiku + cache) | +| **Pro** | Illimité, Sonnet, mémoire complète, caméra, intégrations | 19.99€ | ~14€ | **+5.99€** | Équilibré (Sonnet + cache partiel) | +| **Famille** | Jusqu'à 4 profils, tout inclus (Sonnet) | 29.99€ | ~22€ | **+7.99€** | Premium × ~1.6 profils actifs | + +### 3.2 Option B — Vente du robot seul + self-hosted + +Pour les utilisateurs tech qui veulent héberger eux-mêmes le backend. + +- Robot vendu avec marge (149-399€) +- Code backend open-source ou licence one-time (~49€) +- Pas de revenu récurrent, mais aucun coût serveur +- Communauté = marketing gratuit + +### 3.3 Option C — Kit DIY + abonnement + +Vendre les composants en kit à monter soi-même (moins cher, plus fun pour les makers). + +| Kit | Contenu | Prix | Coût | Marge | +|-----|---------|------|------|-------| +| Kit Starter | PCB + composants + fichiers STL + instructions | 89€ | ~45€ | 44€ | +| Kit Standard | Idem + caméra + écran + servos | 179€ | ~95€ | 84€ | + ++ Abonnement cloud idem Option A. + +--- + +## 4. Projections financières + +### 4.1 Scénario réaliste — 10 utilisateurs (Mois 1-6) + +**Hypothèses :** Config Standard, plan Essentiel, vente directe. + +| | Revenus | Coûts | **Résultat** | +|---|---------|-------|-------------| +| **Vente initiale (×10)** | 2 490€ | 1 370€ (prod.) | +1 120€ | +| **Abonnements/mois (×10)** | 99.90€ | ~89€ (cloud) | +10.90€/mois | +| **Sur 6 mois** | 2 490€ + 599€ = 3 089€ | 1 370€ + 534€ = 1 904€ | **+1 185€** | + +> Avec 10 utilisateurs sur plan Essentiel, le projet est légèrement rentable mais la marge est très faible côté abonnement. Le hardware porte l'essentiel du profit. + +### 4.2 Scénario croissance — 50 utilisateurs (Mois 6-12) + +**Hypothèses :** Mix de plans, coûts réduits en volume. + +| | Mensuel | +|---|---------| +| Abonnements (20 Essentiel + 25 Pro + 5 Famille) | 200€ + 500€ + 150€ = **850€/mois** | +| Coûts cloud (50 users, VPS upgradé) | ~530€/mois | +| **Marge cloud/mois** | **+320€/mois** | +| Vente hardware (5 nouveaux/mois) | +560€ marge/mois | +| **Marge totale/mois** | **~880€/mois** | + +### 4.3 Seuil de rentabilité + +En comptant les coûts de développement comme du temps investi (pas de salaire), le seuil de rentabilité pour couvrir les frais courants (infra fixe + APIs variables) est atteint à : + +**Calcul :** Chaque abonné Essentiel rapporte 9.99€ et coûte ~7.10€ en APIs variables (LLM + STT + TTS, scénario optimisé). La marge de contribution par user est donc ~2.89€/mois. Il faut couvrir les coûts fixes d'infra (~18€/mois). + +| Scénario | Marge/user | Seuil pour couvrir l'infra fixe | Seuil total (fixe + variable) | +|----------|-----------|-------------------------------|------------------------------| +| Que des plans Essentiels (9.99€) | ~2.89€ | 18€ ÷ 2.89€ = **~7 abonnés** | Rentable dès ~7 abonnés | +| Mix Essentiel/Pro (marge moy. ~4.50€) | ~4.50€ | 18€ ÷ 4.50€ = **~4 abonnés** | Rentable dès ~4-5 abonnés | +| Self-hosted (0€ récurrent) | N/A | **Immédiat** (pas de frais cloud) | Immédiat | + +> **Note :** Ces seuils supposent un scénario optimisé (cache Redis, routing LLM intelligent). Sans optimisation, le coût variable par user monte à ~11.80€ et le plan Essentiel à 9.99€ serait **déficitaire**. L'optimisation des coûts API est donc un prérequis, pas un bonus. + +--- + +## 5. Leviers d'optimisation des coûts + +### 5.1 Réduire le coût LLM (le poste n°1) + +- **Routing intelligent** : utiliser Haiku pour les requêtes simples (timer, météo, heure) et Sonnet uniquement pour les conversations complexes. Économie estimée : -40%. +- **Cache sémantique Redis** : les mêmes questions reviennent souvent ("quelle heure est-il", "quel temps fait-il"). Cacher les réponses par similarité d'embedding. Économie : -15-25%. +- **Réduction du contexte** : résumer l'historique au lieu d'envoyer tous les messages. Moins de tokens = moins cher. +- **Modèles locaux (futur)** : si le VPS le permet, un petit modèle local (Mistral 7B, Phi-3) pour les requêtes triviales. + +### 5.2 Réduire le coût TTS + +- **TTS open-source** : Piper TTS (self-hosted, gratuit, qualité correcte) pour les réponses courtes et factuelles. ElevenLabs réservé aux conversations longues. +- **Cache audio** : les réponses types ("Minuteur de 10 minutes activé", "Il fait 22 degrés") peuvent être pré-générées. + +### 5.3 Réduire le coût hardware + +- **PCB en série** : passer de breakout boards à un PCB custom intégrant ESP32 + ampli + connecteurs. Réduit le coût de ~15€/unité et le temps d'assemblage. +- **Impression 3D en batch** : optimiser les placements sur le plateau pour imprimer 4-6 boîtiers d'un coup. +- **Approvisionnement direct** : acheter les composants sur LCSC/JLCPCB plutôt qu'Amazon/Adafruit. + +--- + +## 6. Stratégie de lancement recommandée + +### Phase 1 — Validation (0-3 mois, 0€ de revenu) +- Produire 5 prototypes (coût : ~700€) +- Les distribuer à des beta-testeurs (amis, makers, communauté) +- Valider l'usage réel, la latence, la fiabilité +- Itérer sur le hardware et le software +- **Budget nécessaire : ~1 000€** (prototypes + infra 3 mois) + +### Phase 2 — Early Adopters (3-6 mois) +- Lancer une pré-vente (Kickstarter ou site direct) avec 50-100 unités +- Proposer le plan Essentiel à 9.99€/mois +- Objectif : 30-50 ventes +- **Revenus attendus : 7 500€ - 12 500€ (hardware) + 300-500€/mois (abo)** + +### Phase 3 — Croissance (6-12 mois) +- Ajouter le plan Pro et Famille +- Ouvrir l'Option B (self-hosted) pour la communauté open-source +- Viser 100-200 utilisateurs actifs +- Explorer les partenariats (écoles, espaces de coworking, personnes âgées) + +--- + +## 7. Risques et points d'attention + +| Risque | Impact | Mitigation | +|--------|--------|------------| +| Hausse des prix API (LLM, TTS) | Marge cloud réduite ou négative | Routing intelligent, cache, modèles locaux en backup | +| SAV et retours hardware | Coût de remplacement + temps | Tests QA rigoureux, garantie limitée, pièces modulaires | +| Concurrence (Alexa, Google Home) | Difficulté à justifier le prix | Positionnement : privacy, personnalisable, open-source, mignon | +| Scalabilité VPS | Dégradation au-delà de 30 users | Prévoir migration vers cluster Docker / VPS plus gros | +| Réglementation (CE, données perso) | Blocage légal pour la vente | Anticiper la conformité CE et RGPD dès la Phase 1 | + +--- + +## 8. Résumé + +| Métrique | Valeur | +|----------|--------| +| Coût de production (Standard) | ~137€ | +| Prix de vente recommandé | 249€ | +| Marge brute hardware | ~45% | +| Coût cloud/user/mois (optimisé) | ~9€ | +| Abonnement recommandé (Essentiel) | 9.99€/mois | +| Seuil de rentabilité cloud | ~7-9 abonnés | +| Budget lancement (Phase 1) | ~1 000€ | +| Revenu potentiel à 50 users (mensuel) | ~880€/mois | + +**Conclusion :** Ti-Pote peut être rentable à partir de ~10 utilisateurs payants si on combine marge hardware + abonnement cloud. Le modèle économique tient à condition de maîtriser les coûts API (le poste principal) via du routing intelligent et du caching. La vraie valeur est dans le revenu récurrent des abonnements — le hardware sert de porte d'entrée. diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d86b7ef..fefcbd1 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -12,10 +12,13 @@ importers: dependencies: '@anthropic-ai/sdk': specifier: ^0.80.0 - version: 0.80.0 + version: 0.80.0(zod@4.3.6) '@deepgram/sdk': specifier: ^5.0.0 version: 5.0.0 + '@mastra/core': + specifier: ^1.17.0 + version: 1.17.0(@standard-community/standard-json@0.3.5(@standard-schema/spec@1.1.0)(@types/json-schema@7.0.15)(quansync@0.2.11)(zod-to-json-schema@3.25.2(zod@4.3.6))(zod@4.3.6))(@standard-community/standard-openapi@0.2.9(@standard-community/standard-json@0.3.5(@standard-schema/spec@1.1.0)(@types/json-schema@7.0.15)(quansync@0.2.11)(zod-to-json-schema@3.25.2(zod@4.3.6))(zod@4.3.6))(@standard-schema/spec@1.1.0)(openapi-types@12.1.3)(zod@4.3.6))(@types/json-schema@7.0.15)(openapi-types@12.1.3)(zod@4.3.6) '@nestjs/common': specifier: ^11.1.17 version: 11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2) @@ -63,7 +66,7 @@ importers: version: 5.10.1 openai: specifier: ^6.33.0 - version: 6.33.0(ws@8.18.3) + version: 6.33.0(ws@8.20.0)(zod@4.3.6) passport: specifier: ^0.7.0 version: 0.7.0 @@ -85,6 +88,9 @@ importers: typeorm: specifier: ^0.3.28 version: 0.3.28(ioredis@5.10.1)(pg@8.20.0)(ts-node@10.9.2(@types/node@25.5.0)(typescript@5.8.3)) + zod: + specifier: ^4.3.6 + version: 4.3.6 devDependencies: '@nestjs/cli': specifier: ^11.0.16 @@ -174,6 +180,50 @@ importers: packages: + '@a2a-js/sdk@0.2.5': + resolution: {integrity: sha512-VTDuRS5V0ATbJ/LkaQlisMnTAeYKXAK6scMguVBstf+KIBQ7HIuKhiXLv+G/hvejkV+THoXzoNifInAkU81P1g==} + engines: {node: '>=18'} + + '@ai-sdk/provider-utils@2.2.8': + resolution: {integrity: sha512-fqhG+4sCVv8x7nFzYnFo19ryhAa3w096Kmc3hWxMQfW/TubPOmt3A6tYZhl4mUfQWWQMsuSkLrtjlWuXBVSGQA==} + engines: {node: '>=18'} + peerDependencies: + zod: ^3.23.8 + + '@ai-sdk/provider-utils@3.0.20': + resolution: {integrity: sha512-iXHVe0apM2zUEzauqJwqmpC37A5rihrStAih5Ks+JE32iTe4LZ58y17UGBjpQQTCRw9YxMeo2UFLxLpBluyvLQ==} + engines: {node: '>=18'} + peerDependencies: + zod: ^3.25.76 || ^4.1.8 + + '@ai-sdk/provider-utils@4.0.0': + resolution: {integrity: sha512-HyCyOls9I3a3e38+gtvOJOEjuw9KRcvbBnCL5GBuSmJvS9Jh9v3fz7pRC6ha1EUo/ZH1zwvLWYXBMtic8MTguA==} + engines: {node: '>=18'} + peerDependencies: + zod: ^3.25.76 || ^4.1.8 + + '@ai-sdk/provider@1.1.3': + resolution: {integrity: sha512-qZMxYJ0qqX/RfnuIaab+zp8UAeJn/ygXXAffR5I4N0n1IrvA6qBsjc8hXLmBiMV2zoXlifkacF7sEFnYnjBcqg==} + engines: {node: '>=18'} + + '@ai-sdk/provider@2.0.1': + resolution: {integrity: sha512-KCUwswvsC5VsW2PWFqF8eJgSCu5Ysj7m1TxiHTVA6g7k360bk0RNQENT8KTMAYEs+8fWPD3Uu4dEmzGHc+jGng==} + engines: {node: '>=18'} + + '@ai-sdk/provider@3.0.0': + resolution: {integrity: sha512-m9ka3ptkPQbaHHZHqDXDF9C9B5/Mav0KTdky1k2HZ3/nrW2t1AgObxIVPyGDWQNS9FXT/FS6PIoSjpcP/No8rQ==} + engines: {node: '>=18'} + + '@ai-sdk/provider@3.0.5': + resolution: {integrity: sha512-2Xmoq6DBJqmSl80U6V9z5jJSJP7ehaJJQMy2iFUqTay06wdCqTnPVBBQbtEL8RCChenL+q5DC5H5WzU3vV3v8w==} + engines: {node: '>=18'} + + '@ai-sdk/ui-utils@1.2.11': + resolution: {integrity: sha512-3zcwCc8ezzFlwp3ZD15wAPjf2Au4s3vAbKsXQVyhxODHcmu0iyPO2Eua6D/vicq/AUm/BAo60r97O6HU+EI0+w==} + engines: {node: '>=18'} + peerDependencies: + zod: ^3.23.8 + '@angular-devkit/core@19.2.17': resolution: {integrity: sha512-Ah008x2RJkd0F+NLKqIpA34/vUGwjlprRCkvddjDopAWRzYn6xCkz1Tqwuhn0nR1Dy47wTLKYD999TYl5ONOAQ==} engines: {node: ^18.19.1 || ^20.11.1 || >=22.0.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'} @@ -593,6 +643,12 @@ packages: resolution: {integrity: sha512-iH1B076HoAshH1mLpHMgwdGeTs0CYwL0SPMkGuSebZrwBp16v415e9NZXg2jtrqPVQjf6IANe2Vtlr5KswtcZQ==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} + '@hono/node-server@1.19.11': + resolution: {integrity: sha512-dr8/3zEaB+p0D2n/IUrlPF1HZm586qgJNXK1a9fhg/PzdtkK7Ksd5l312tJX2yBuALqDYBlG20QEbayqPyxn+g==} + engines: {node: '>=18.14.1'} + peerDependencies: + hono: ^4 + '@humanfs/core@0.19.1': resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} engines: {node: '>=18.18.0'} @@ -759,6 +815,10 @@ packages: resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} engines: {node: '>=12'} + '@isaacs/ttlcache@2.1.4': + resolution: {integrity: sha512-7kMz0BJpMvgAMkyglums7B2vtrn5g0a0am77JY0GjkZZNetOBCFn7AG7gKCwT0QPiXyxW7YIQSgtARknUEOcxQ==} + engines: {node: '>=12'} + '@istanbuljs/load-nyc-config@1.1.0': resolution: {integrity: sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==} engines: {node: '>=8'} @@ -875,6 +935,32 @@ packages: resolution: {integrity: sha512-Z7C/xXCiGWsg0KuKsHTKJxbWhpI3Vs5GwLfOean7MGyVFGqdRgBbAjOCh6u4bbjPc/8MJ2pZmK/0DLdCbivLDA==} engines: {node: '>=8'} + '@lukeed/uuid@2.0.1': + resolution: {integrity: sha512-qC72D4+CDdjGqJvkFMMEAtancHUQ7/d/tAiHf64z8MopFDmcrtbcJuerDtFceuAfQJ2pDSfCKCtbqoGBNnwg0w==} + engines: {node: '>=8'} + + '@mastra/core@1.17.0': + resolution: {integrity: sha512-szJgYEXGj9ux5cM1wpi2HdouvKBugbnt3TEHEPvW9fI6fLvZTiYG0Nt0y8DPQgDK4nH0BPdL9HFxOf3PnevZ8Q==} + engines: {node: '>=22.13.0'} + peerDependencies: + zod: ^3.25.0 || ^4.0.0 + + '@mastra/schema-compat@1.2.7': + resolution: {integrity: sha512-t63E0f5HcH8neXPfs3D5x4qqQM6Pf/pbhFUVk0cTC0bFo6609sT/+189I+2HY4sbAF3uzurOgy2fXIS4vfMkOA==} + engines: {node: '>=22.13.0'} + peerDependencies: + zod: ^3.25.0 || ^4.0.0 + + '@modelcontextprotocol/sdk@1.28.0': + resolution: {integrity: sha512-gmloF+i+flI8ouQK7MWW4mOwuMh4RePBuPFAEPC6+pdqyWOUMDOixb6qZ69owLJpz6XmyllCouc4t8YWO+E2Nw==} + engines: {node: '>=18'} + peerDependencies: + '@cfworker/json-schema': ^4.1.1 + zod: ^3.25 || ^4.0 + peerDependenciesMeta: + '@cfworker/json-schema': + optional: true + '@napi-rs/wasm-runtime@0.2.12': resolution: {integrity: sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==} @@ -1111,9 +1197,24 @@ packages: '@rolldown/pluginutils@1.0.0-rc.7': resolution: {integrity: sha512-qujRfC8sFVInYSPPMLQByRh7zhwkGFS4+tyMQ83srV1qrxL4g8E2tyxVVyxd0+8QeBM1mIk9KbWxkegRr76XzA==} + '@sec-ant/readable-stream@0.4.1': + resolution: {integrity: sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==} + '@sinclair/typebox@0.34.48': resolution: {integrity: sha512-kKJTNuK3AQOrgjjotVxMrCn1sUJwM76wMszfq1kdU4uYVJjvEWuFQ6HgvLt4Xz3fSmZlTOxJ/Ie13KnIcWQXFA==} + '@sindresorhus/merge-streams@4.0.0': + resolution: {integrity: sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==} + engines: {node: '>=18'} + + '@sindresorhus/slugify@2.2.1': + resolution: {integrity: sha512-MkngSCRZ8JdSOCHRaYd+D01XhvU3Hjy6MGl06zhOk614hp9EOAp5gIkBeQg7wtmxpitU6eAL4kdiRMcJa2dlrw==} + engines: {node: '>=12'} + + '@sindresorhus/transliterate@1.6.0': + resolution: {integrity: sha512-doH1gimEu3A46VX6aVxpHTeHrytJAG6HgdxntYnCFiIFHEM/ZGpG8KiZGBChchjQmG0XFIBL552kBTjVcMZXwQ==} + engines: {node: '>=12'} + '@sinonjs/commons@3.0.1': resolution: {integrity: sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==} @@ -1126,6 +1227,70 @@ packages: '@sqltools/formatter@1.2.5': resolution: {integrity: sha512-Uy0+khmZqUrUGm5dmMqVlnvufZRSK0FbYzVgp0UMstm+F5+W2/jnEEQyc9vo1ZR/E5ZI/B1WjjoTqBqwJL6Krw==} + '@standard-community/standard-json@0.3.5': + resolution: {integrity: sha512-4+ZPorwDRt47i+O7RjyuaxHRK/37QY/LmgxlGrRrSTLYoFatEOzvqIc85GTlM18SFZ5E91C+v0o/M37wZPpUHA==} + peerDependencies: + '@standard-schema/spec': ^1.0.0 + '@types/json-schema': ^7.0.15 + '@valibot/to-json-schema': ^1.3.0 + arktype: ^2.1.20 + effect: ^3.16.8 + quansync: ^0.2.11 + sury: ^10.0.0 + typebox: ^1.0.17 + valibot: ^1.1.0 + zod: ^3.25.0 || ^4.0.0 + zod-to-json-schema: ^3.24.5 + peerDependenciesMeta: + '@valibot/to-json-schema': + optional: true + arktype: + optional: true + effect: + optional: true + sury: + optional: true + typebox: + optional: true + valibot: + optional: true + zod: + optional: true + zod-to-json-schema: + optional: true + + '@standard-community/standard-openapi@0.2.9': + resolution: {integrity: sha512-htj+yldvN1XncyZi4rehbf9kLbu8os2Ke/rfqoZHCMHuw34kiF3LP/yQPdA0tQ940y8nDq3Iou8R3wG+AGGyvg==} + peerDependencies: + '@standard-community/standard-json': ^0.3.5 + '@standard-schema/spec': ^1.0.0 + arktype: ^2.1.20 + effect: ^3.17.14 + openapi-types: ^12.1.3 + sury: ^10.0.0 + typebox: ^1.0.0 + valibot: ^1.1.0 + zod: ^3.25.0 || ^4.0.0 + zod-openapi: ^4 + peerDependenciesMeta: + arktype: + optional: true + effect: + optional: true + sury: + optional: true + typebox: + optional: true + valibot: + optional: true + zod: + optional: true + zod-openapi: + optional: true + + '@standard-schema/spec@1.1.0': + resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} + '@tokenizer/inflate@0.4.1': resolution: {integrity: sha512-2mAv+8pkG6GIZiF1kNg1jAjh27IDxEPKwdGul3snfztFerfPGI1LjDezZp3i7BElXompqEtPmoPx6c2wgtWsOA==} engines: {node: '>=18'} @@ -1184,9 +1349,15 @@ packages: '@types/estree@1.0.8': resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} + '@types/express-serve-static-core@4.19.8': + resolution: {integrity: sha512-02S5fmqeoKzVZCHPZid4b8JH2eM5HzQLZWN2FohQEy/0eXTq8VXZfSN6Pcr3F6N9R/vNrj7cpgbhjie6m/1tCA==} + '@types/express-serve-static-core@5.1.1': resolution: {integrity: sha512-v4zIMr/cX7/d2BpAEX3KNKL/JrT1s43s96lLvvdTmza1oEvDudCqK9aF/djc/SWgy8Yh0h30TZx5VpzqFCxk5A==} + '@types/express@4.17.25': + resolution: {integrity: sha512-dVd04UKsfpINUnK0yBoYHDF3xu7xVH4BuDotC/xGuycx4CgbP48X/KF/586bcObxT0HENHXEU8Nqtu6NR+eKhw==} + '@types/express@5.0.6': resolution: {integrity: sha512-sKYVuV7Sv9fbPIt/442koC7+IIwK5olP1KWeD88e/idgoJqDm3JV/YUiPwkoKK92ylff2MGxSz1CSjsXelx0YA==} @@ -1211,6 +1382,9 @@ packages: '@types/jsonwebtoken@9.0.10': resolution: {integrity: sha512-asx5hIG9Qmf/1oStypjanR7iKTv0gXQ1Ov/jfrX6kS/EO0OFni8orbmGCn0672NHR3kXHwpAwR+B368ZGN/2rA==} + '@types/mime@1.3.5': + resolution: {integrity: sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==} + '@types/ms@2.1.0': resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} @@ -1240,9 +1414,15 @@ packages: '@types/react@19.2.14': resolution: {integrity: sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==} + '@types/send@0.17.6': + resolution: {integrity: sha512-Uqt8rPBE8SY0RK8JB1EzVOIZ32uqy8HwdxCnoCOsYrvnswqmFZ/k+9Ikidlk/ImhsdvBsloHbAlewb2IEBV/Og==} + '@types/send@1.2.1': resolution: {integrity: sha512-arsCikDvlU99zl1g69TcAB3mzZPpxgw0UQnaHeC1Nwb015xp8bknZv5rIfri9xTOcMuaVgvabfIRA7PSZVuZIQ==} + '@types/serve-static@1.15.10': + resolution: {integrity: sha512-tRs1dB+g8Itk72rlSI2ZrW6vZg0YrLI81iQSTkMmOqnqCaNr/8Ek4VwWcN5vZgCYWbg/JJSGBlUaYGAOP73qBw==} + '@types/serve-static@2.2.0': resolution: {integrity: sha512-8mam4H1NHLtu7nmtalF7eyBH14QyOASmcxHhSfEoRyr0nP/YdoesEtU+uSRvMe96TW/HPTtkoKqQLl53N7UXMQ==} @@ -1609,6 +1789,9 @@ packages: argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + array-flatten@1.1.1: + resolution: {integrity: sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==} + array-timsort@1.0.3: resolution: {integrity: sha512-/+3GRL7dDAGEfM6TseQk/U+mi18TU2Ms9I3UlLdUMhz2hbvGNTKdj9xniwXfUqgYhHxRx0+8UnKkvlNwVU+cWQ==} @@ -1670,6 +1853,10 @@ packages: bl@4.1.0: resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} + body-parser@1.20.4: + resolution: {integrity: sha512-ZTgYYLMOXY9qKU/57FAo8F+HA2dGX7bqGc71txDRC1rS4frdFI5R7NhluHxH6M0YItAP0sHB4uqAOcYKxO6uGA==} + engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} + body-parser@2.2.2: resolution: {integrity: sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==} engines: {node: '>=18'} @@ -1846,6 +2033,10 @@ packages: resolution: {integrity: sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==} engines: {node: ^14.18.0 || >=16.10.0} + content-disposition@0.5.4: + resolution: {integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==} + engines: {node: '>= 0.6'} + content-disposition@1.0.1: resolution: {integrity: sha512-oIXISMynqSqm241k6kcQ5UwttDILMK4BiurCfGEREw6+X9jkkpEe5T9FZaApyLGGOnFuyMWZpdolTXMtvEJ08Q==} engines: {node: '>=18'} @@ -1857,6 +2048,9 @@ packages: convert-source-map@2.0.0: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + cookie-signature@1.0.7: + resolution: {integrity: sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==} + cookie-signature@1.2.2: resolution: {integrity: sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==} engines: {node: '>=6.6.0'} @@ -1894,6 +2088,14 @@ packages: dayjs@1.11.20: resolution: {integrity: sha512-YbwwqR/uYpeoP4pu043q+LTDLFBLApUP6VxRihdfNTqu4ubqMlGDLd6ErXhEgsyvY0K6nCs7nggYumAN+9uEuQ==} + debug@2.6.9: + resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + debug@4.4.3: resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} engines: {node: '>=6.0'} @@ -1937,6 +2139,10 @@ packages: resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} engines: {node: '>= 0.8'} + destroy@1.2.0: + resolution: {integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==} + engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} + detect-libc@2.1.2: resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} engines: {node: '>=8'} @@ -2056,6 +2262,10 @@ packages: resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} engines: {node: '>=10'} + escape-string-regexp@5.0.0: + resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==} + engines: {node: '>=12'} + eslint-config-prettier@10.1.8: resolution: {integrity: sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==} hasBin: true @@ -2143,10 +2353,22 @@ packages: resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} engines: {node: '>=0.8.x'} + eventsource-parser@3.0.6: + resolution: {integrity: sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg==} + engines: {node: '>=18.0.0'} + + eventsource@3.0.7: + resolution: {integrity: sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==} + engines: {node: '>=18.0.0'} + execa@5.1.1: resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} engines: {node: '>=10'} + execa@9.6.1: + resolution: {integrity: sha512-9Be3ZoN4LmYR90tUoVu2te2BsbzHfhJyfEiAVfz7N5/zv+jduIfLrV2xdQXOHbaD6KgpGdO9PRPM1Y4Q9QkPkA==} + engines: {node: ^18.19.0 || >=20.5.0} + exit-x@0.2.2: resolution: {integrity: sha512-+I6B/IkJc1o/2tiURyz/ivu/O0nKNEArIUB5O7zBrlDVJr22SCLH3xTeEry428LvFhRzIA1g8izguxJ/gbNcVQ==} engines: {node: '>= 0.8.0'} @@ -2155,10 +2377,24 @@ packages: resolution: {integrity: sha512-1zQrciTiQfRdo7qJM1uG4navm8DayFa2TgCSRlzUyNkhcJ6XUZF3hjnpkyr3VhAqPH7i/9GkG7Tv5abz6fqz0Q==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + express-rate-limit@8.3.1: + resolution: {integrity: sha512-D1dKN+cmyPWuvB+G2SREQDzPY1agpBIcTa9sJxOPMCNeH3gwzhqJRDWCXW3gg0y//+LQ/8j52JbMROWyrKdMdw==} + engines: {node: '>= 16'} + peerDependencies: + express: '>= 4.11' + + express@4.22.1: + resolution: {integrity: sha512-F2X8g9P1X7uCPZMA3MVf9wcTqlyNp7IhH5qPCI0izhaOIYXaW9L535tGA3qmjRzpH+bZczqq7hVKxTR4NWnu+g==} + engines: {node: '>= 0.10.0'} + express@5.2.1: resolution: {integrity: sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==} engines: {node: '>= 18'} + extend-shallow@2.0.1: + resolution: {integrity: sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==} + engines: {node: '>=0.10.0'} + fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} @@ -2189,6 +2425,10 @@ packages: picomatch: optional: true + figures@6.1.0: + resolution: {integrity: sha512-d+l3qxjSesT4V7v2fh+QnmFnUWv9lSpjarhShNTgBOfA0ttejbQUAlHLitbjkoRiDulW0OPoQPYIGhIC8ohejg==} + engines: {node: '>=18'} + file-entry-cache@8.0.0: resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} engines: {node: '>=16.0.0'} @@ -2197,6 +2437,10 @@ packages: resolution: {integrity: sha512-DLkUvGwep3poOV2wpzbHCOnSKGk1LzyXTv+aHFgN2VFl96wnp8YA9YjO2qPzg5PuL8q/SW9Pdi6WTkYOIh995w==} engines: {node: '>=20'} + finalhandler@1.3.2: + resolution: {integrity: sha512-aA4RyPcd3badbdABGDuTXCMTtOneUCAYH/gxoYRTZlIJdF0YPWuGqiAsIrhNnnqdXGswYk6dGujem4w80UJFhg==} + engines: {node: '>= 0.8'} + finalhandler@2.1.1: resolution: {integrity: sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==} engines: {node: '>= 18.0.0'} @@ -2247,6 +2491,10 @@ packages: resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} engines: {node: '>= 0.6'} + fresh@0.5.2: + resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==} + engines: {node: '>= 0.6'} + fresh@2.0.0: resolution: {integrity: sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==} engines: {node: '>= 0.8'} @@ -2293,6 +2541,10 @@ packages: resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} engines: {node: '>=10'} + get-stream@9.0.1: + resolution: {integrity: sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA==} + engines: {node: '>=18'} + get-tsconfig@4.13.7: resolution: {integrity: sha512-7tN6rFgBlMgpBML5j8typ92BKFi2sFQvIdpAqLA2beia5avZDrMs0FLZiM5etShWq5irVyGcGMEA1jcDaK7A/Q==} @@ -2323,6 +2575,10 @@ packages: graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + gray-matter@4.0.3: + resolution: {integrity: sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q==} + engines: {node: '>=6.0'} + handlebars@4.7.9: resolution: {integrity: sha512-4E71E0rpOaQuJR2A3xDZ+GM1HyWYv1clR58tC8emQNeQe3RH7MAzSbat+V0wG78LQBo6m6bzSG/L4pBuCsgnUQ==} engines: {node: '>=0.4.7'} @@ -2347,6 +2603,25 @@ packages: resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} engines: {node: '>= 0.4'} + hono-openapi@1.3.0: + resolution: {integrity: sha512-xDvCWpWEIv0weEmnl3EjRQzqbHIO8LnfzMuYOCmbuyE5aes6aXxLg4vM3ybnoZD5TiTUkA6PuRQPJs3R7WRBig==} + peerDependencies: + '@hono/standard-validator': ^0.2.0 + '@standard-community/standard-json': ^0.3.5 + '@standard-community/standard-openapi': ^0.2.9 + '@types/json-schema': ^7.0.15 + hono: ^4.8.3 + openapi-types: ^12.1.3 + peerDependenciesMeta: + '@hono/standard-validator': + optional: true + hono: + optional: true + + hono@4.12.9: + resolution: {integrity: sha512-wy3T8Zm2bsEvxKZM5w21VdHDDcwVS1yUFFY6i8UobSsKfFceT7TOwhbhfKsDyx7tYQlmRM5FLpIuYvNFyjctiA==} + engines: {node: '>=16.9.0'} + html-escaper@2.0.2: resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} @@ -2358,6 +2633,14 @@ packages: resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} engines: {node: '>=10.17.0'} + human-signals@8.0.1: + resolution: {integrity: sha512-eKCa6bwnJhvxj14kZk5NCPc6Hb6BdsU9DZcOnmQKSnO1VKrfV0zCvtttPZUsBvjmNDn8rpcJfpwSYnHBjc95MQ==} + engines: {node: '>=18.18.0'} + + iconv-lite@0.4.24: + resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} + engines: {node: '>=0.10.0'} + iconv-lite@0.7.2: resolution: {integrity: sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==} engines: {node: '>=0.10.0'} @@ -2397,6 +2680,10 @@ packages: resolution: {integrity: sha512-HuEDBTI70aYdx1v6U97SbNx9F1+svQKBDo30o0b9fw055LMepzpOOd0Ccg9Q6tbqmBSJaMuY0fB7yw9/vjBYCA==} engines: {node: '>=12.22.0'} + ip-address@10.1.0: + resolution: {integrity: sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q==} + engines: {node: '>= 12'} + ipaddr.js@1.9.1: resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} engines: {node: '>= 0.10'} @@ -2408,6 +2695,10 @@ packages: resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} engines: {node: '>= 0.4'} + is-extendable@0.1.1: + resolution: {integrity: sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==} + engines: {node: '>=0.10.0'} + is-extglob@2.1.1: resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} engines: {node: '>=0.10.0'} @@ -2428,6 +2719,14 @@ packages: resolution: {integrity: sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==} engines: {node: '>=8'} + is-network-error@1.3.1: + resolution: {integrity: sha512-6QCxa49rQbmUWLfk0nuGqzql9U8uaV2H6279bRErPBHe/109hCzsLUBUHfbEtvLIHBd6hyXbgedBSHevm43Edw==} + engines: {node: '>=16'} + + is-plain-obj@4.1.0: + resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==} + engines: {node: '>=12'} + is-promise@4.0.0: resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==} @@ -2435,6 +2734,10 @@ packages: resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} engines: {node: '>=8'} + is-stream@4.0.1: + resolution: {integrity: sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A==} + engines: {node: '>=18'} + is-typed-array@1.1.15: resolution: {integrity: sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==} engines: {node: '>= 0.4'} @@ -2443,6 +2746,10 @@ packages: resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==} engines: {node: '>=10'} + is-unicode-supported@2.1.0: + resolution: {integrity: sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==} + engines: {node: '>=18'} + isarray@2.0.5: resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} @@ -2608,6 +2915,12 @@ packages: node-notifier: optional: true + jose@6.2.2: + resolution: {integrity: sha512-d7kPDd34KO/YnzaDOlikGpOurfF0ByC2sEV4cANCtdqLlTfBlw2p14O/5d/zv40gJPbIQxfES3nSx1/oYNyuZQ==} + + js-tiktoken@1.0.21: + resolution: {integrity: sha512-biOj/6M5qdgx5TKjDnFT1ymSpM5tbd3ylwDtrQvFQSu0Z7bBYko2dF+W/aUkXUPuk6IVpRxk/3Q2sHOzGlS36g==} + js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} @@ -2634,12 +2947,22 @@ packages: resolution: {integrity: sha512-+DWg8jCJG2TEnpy7kOm/7/AxaYoaRbjVB4LFZLySZlWn8exGs3A4OLJR966cVvU26N7X9TWxl+Jsw7dzAqKT6g==} engines: {node: '>=16'} + json-schema-to-zod@2.7.0: + resolution: {integrity: sha512-eW59l3NQ6sa3HcB+Ahf7pP6iGU7MY4we5JsPqXQ2ZcIPF8QxSg/lkY8lN0Js/AG0NjMbk+nZGUfHlceiHF+bwQ==} + hasBin: true + json-schema-traverse@0.4.1: resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} json-schema-traverse@1.0.0: resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} + json-schema-typed@8.0.2: + resolution: {integrity: sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA==} + + json-schema@0.4.0: + resolution: {integrity: sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==} + json-stable-stringify-without-jsonify@1.0.1: resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} @@ -2667,6 +2990,10 @@ packages: keyv@4.5.4: resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + kind-of@6.0.3: + resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==} + engines: {node: '>=0.10.0'} + leven@3.1.0: resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==} engines: {node: '>=6'} @@ -2847,6 +3174,9 @@ packages: resolution: {integrity: sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==} engines: {node: '>= 4.0.0'} + merge-descriptors@1.0.3: + resolution: {integrity: sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==} + merge-descriptors@2.0.0: resolution: {integrity: sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==} engines: {node: '>=18'} @@ -2854,6 +3184,10 @@ packages: merge-stream@2.0.0: resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} + methods@1.1.2: + resolution: {integrity: sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==} + engines: {node: '>= 0.6'} + mime-db@1.52.0: resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} engines: {node: '>= 0.6'} @@ -2870,6 +3204,11 @@ packages: resolution: {integrity: sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==} engines: {node: '>=18'} + mime@1.6.0: + resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==} + engines: {node: '>=4'} + hasBin: true + mimic-fn@2.1.0: resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} engines: {node: '>=6'} @@ -2892,6 +3231,9 @@ packages: resolution: {integrity: sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==} engines: {node: '>=16 || 14 >=14.17'} + ms@2.0.0: + resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} + ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} @@ -2964,6 +3306,10 @@ packages: resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} engines: {node: '>=8'} + npm-run-path@6.0.0: + resolution: {integrity: sha512-9qny7Z9DsQU8Ou39ERsPU4OZQlSTP47ShQzuKZ6PRXpYLtIFgl/DEBYEXKlvcEa+9tHVcK8CF81Y2V72qaZhWA==} + engines: {node: '>=18'} + object-assign@4.1.1: resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} engines: {node: '>=0.10.0'} @@ -2999,6 +3345,9 @@ packages: zod: optional: true + openapi-types@12.1.3: + resolution: {integrity: sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw==} + optionator@0.9.4: resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} engines: {node: '>= 0.8.0'} @@ -3023,6 +3372,14 @@ packages: resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} engines: {node: '>=10'} + p-map@7.0.4: + resolution: {integrity: sha512-tkAQEw8ysMzmkhgw8k+1U/iPhWNhykKnSk4Rd5zLoPJCuJaGRPo6YposrZgaxHKzDHdDWWZvE/Sk7hsL2X/CpQ==} + engines: {node: '>=18'} + + p-retry@7.1.1: + resolution: {integrity: sha512-J5ApzjyRkkf601HpEeykoiCvzHQjWxPAHhyjFcEUP2SWq0+35NKh8TLhpLw+Dkq5TZBFvUM6UigdE9hIVYTl5w==} + engines: {node: '>=20'} + p-try@2.2.0: resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} engines: {node: '>=6'} @@ -3038,6 +3395,10 @@ packages: resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} engines: {node: '>=8'} + parse-ms@4.0.0: + resolution: {integrity: sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw==} + engines: {node: '>=18'} + parseurl@1.3.3: resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} engines: {node: '>= 0.8'} @@ -3065,6 +3426,10 @@ packages: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} + path-key@4.0.0: + resolution: {integrity: sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==} + engines: {node: '>=12'} + path-scurry@1.11.1: resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} engines: {node: '>=16 || 14 >=14.18'} @@ -3073,6 +3438,9 @@ packages: resolution: {integrity: sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==} engines: {node: 18 || 20 || >=22} + path-to-regexp@0.1.13: + resolution: {integrity: sha512-A/AGNMFN3c8bOlvV9RreMdrv7jsmF9XIfDeCd87+I8RNg6s78BhJxMu69NEMHBSJFxKidViTEdruRwEk/WIKqA==} + path-to-regexp@8.3.0: resolution: {integrity: sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==} @@ -3136,6 +3504,10 @@ packages: resolution: {integrity: sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==} engines: {node: '>= 6'} + pkce-challenge@5.0.1: + resolution: {integrity: sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ==} + engines: {node: '>=16.20.0'} + pkg-dir@4.2.0: resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==} engines: {node: '>=8'} @@ -3185,6 +3557,10 @@ packages: resolution: {integrity: sha512-oG4T3wCbfeuvljnyAzhBvpN45E8iOTXCU/TD3zXW80HA3dQ4ahdqMkWGiPWZvjpQwlbyHrPTWUAqUzGzv4l1JQ==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + pretty-ms@9.3.0: + resolution: {integrity: sha512-gjVS5hOP+M3wMm5nmNOucbIrqudzs9v/57bWRHQWLYklXqoXKrVfYW2W9+glfGsqtPgpiz5WwyEEB+ksXIx3gQ==} + engines: {node: '>=18'} + process@0.11.10: resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==} engines: {node: '>= 0.6.0'} @@ -3200,14 +3576,29 @@ packages: pure-rand@7.0.1: resolution: {integrity: sha512-oTUZM/NAZS8p7ANR3SHh30kXB+zK2r2BPcEn/awJIbOvq82WoMN4p62AWWp3Hhw50G0xMsw1mhIBLqHw64EcNQ==} + qs@6.14.2: + resolution: {integrity: sha512-V/yCWTTF7VJ9hIh18Ugr2zhJMP01MY7c5kh4J870L7imm6/DIzBsNLTXzMwUA3yZ5b/KBqLx8Kp3uRvd7xSe3Q==} + engines: {node: '>=0.6'} + qs@6.15.0: resolution: {integrity: sha512-mAZTtNCeetKMH+pSjrb76NAM8V9a05I9aBZOHztWy/UqcJdQYNsf59vrRKWnojAT9Y+GbIvoTBC++CPHqpDBhQ==} engines: {node: '>=0.6'} + quansync@0.2.11: + resolution: {integrity: sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA==} + + radash@12.1.1: + resolution: {integrity: sha512-h36JMxKRqrAxVD8201FrCpyeNuUY9Y5zZwujr20fFO77tpUtGa6EZzfKw/3WaiBX95fq7+MpsuMLNdSnORAwSA==} + engines: {node: '>=14.18.0'} + range-parser@1.2.1: resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} engines: {node: '>= 0.6'} + raw-body@2.5.3: + resolution: {integrity: sha512-s4VSOf6yN0rvbRZGxs8Om5CWj6seneMwK3oDb4lWDH0UPhWcxwOWw5+qk24bxq87szX1ydrwylIOp2uG1ojUpA==} + engines: {node: '>= 0.8'} + raw-body@3.0.2: resolution: {integrity: sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==} engines: {node: '>= 0.10'} @@ -3306,6 +3697,13 @@ packages: resolution: {integrity: sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==} engines: {node: '>= 10.13.0'} + section-matter@1.0.0: + resolution: {integrity: sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA==} + engines: {node: '>=4'} + + secure-json-parse@2.7.0: + resolution: {integrity: sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw==} + semver@6.3.1: resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} hasBin: true @@ -3315,10 +3713,18 @@ packages: engines: {node: '>=10'} hasBin: true + send@0.19.2: + resolution: {integrity: sha512-VMbMxbDeehAxpOtWJXlcUS5E8iXh6QmN+BkRX1GARS3wRaXEEgzCcB10gTQazO42tpNIya8xIyNx8fll1OFPrg==} + engines: {node: '>= 0.8.0'} + send@1.2.1: resolution: {integrity: sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==} engines: {node: '>= 18'} + serve-static@1.16.3: + resolution: {integrity: sha512-x0RTqQel6g5SY7Lg6ZreMmsOzncHFU7nhnRWkKgWuMTu5NN0DR5oruckMqRvacAN9d5w6ARnRBXl9xhDCgfMeA==} + engines: {node: '>= 0.8.0'} + serve-static@2.2.1: resolution: {integrity: sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==} engines: {node: '>= 18'} @@ -3452,6 +3858,10 @@ packages: resolution: {integrity: sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==} engines: {node: '>=12'} + strip-bom-string@1.0.0: + resolution: {integrity: sha512-uCC2VHvQRYu+lMh4My/sFNmF2klFymLX1wHJeXnbEJERpV/ZsVuonzerjfrGpIGF7LBVa1O7i9kjiWvJiFck8g==} + engines: {node: '>=0.10.0'} + strip-bom@3.0.0: resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} engines: {node: '>=4'} @@ -3464,6 +3874,10 @@ packages: resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==} engines: {node: '>=6'} + strip-final-newline@4.0.0: + resolution: {integrity: sha512-aulFJcD6YK8V1G7iRB5tigAP4TsHBZZrOV8pjV++zdUwmeV8uzbY7yn6h9MswN62adStNZFuCIx4haBnRuMDaw==} + engines: {node: '>=18'} + strip-json-comments@3.1.1: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} @@ -3717,6 +4131,10 @@ packages: undici-types@7.18.2: resolution: {integrity: sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==} + unicorn-magic@0.3.0: + resolution: {integrity: sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==} + engines: {node: '>=18'} + universalify@2.0.1: resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} engines: {node: '>= 10.0.0'} @@ -3890,6 +4308,18 @@ packages: utf-8-validate: optional: true + ws@8.20.0: + resolution: {integrity: sha512-sAt8BhgNbzCtgGbt2OxmpuryO63ZoDk/sqaB/znQm94T4fCEsy/yV+7CdC1kJhOU9lboAEU7R3kquuycDoibVA==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + xmlhttprequest-ssl@2.1.2: resolution: {integrity: sha512-TEU+nJVUUnA4CYJFLvK5X9AOeH4KvDvhIfm0vV1GaQRtchnG0hgK5p8hw/xjv8cunWYCsiPCSDzObPyhEwq3KQ==} engines: {node: '>=0.4.0'} @@ -3898,6 +4328,9 @@ packages: resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} engines: {node: '>=0.4'} + xxhash-wasm@1.1.0: + resolution: {integrity: sha512-147y/6YNh+tlp6nd/2pWq38i9h6mz/EuQ6njIrmW8D1BS5nCqs0P6DG+m6zTGnNz5I+uhZ0SHxBs9BsPrwcKDA==} + y18n@5.0.8: resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} engines: {node: '>=10'} @@ -3925,8 +4358,84 @@ packages: resolution: {integrity: sha512-U/PBtDf35ff0D8X8D0jfdzHYEPFxAI7jJlxZXwCSez5M3190m+QobIfh+sWDWSHMCWWJN2AWamkegn6vr6YBTw==} engines: {node: '>=18'} + yoctocolors@2.1.2: + resolution: {integrity: sha512-CzhO+pFNo8ajLM2d2IW/R93ipy99LWjtwblvC1RsoSUMZgyLbYFr221TnSNT7GjGdYui6P459mw9JH/g/zW2ug==} + engines: {node: '>=18'} + + zod-from-json-schema@0.0.5: + resolution: {integrity: sha512-zYEoo86M1qpA1Pq6329oSyHLS785z/mTwfr9V1Xf/ZLhuuBGaMlDGu/pDVGVUe4H4oa1EFgWZT53DP0U3oT9CQ==} + + zod-from-json-schema@0.5.2: + resolution: {integrity: sha512-/dNaicfdhJTOuUd4RImbLUE2g5yrSzzDjI/S6C2vO2ecAGZzn9UcRVgtyLSnENSmAOBRiSpUdzDS6fDWX3Z35g==} + + zod-to-json-schema@3.25.2: + resolution: {integrity: sha512-O/PgfnpT1xKSDeQYSCfRI5Gy3hPf91mKVDuYLUHZJMiDFptvP41MSnWofm8dnCm0256ZNfZIM7DSzuSMAFnjHA==} + peerDependencies: + zod: ^3.25.28 || ^4 + + zod@3.25.76: + resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==} + + zod@4.3.6: + resolution: {integrity: sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==} + snapshots: + '@a2a-js/sdk@0.2.5': + dependencies: + '@types/cors': 2.8.19 + '@types/express': 4.17.25 + body-parser: 2.2.2 + cors: 2.8.6 + express: 4.22.1 + uuid: 11.1.0 + transitivePeerDependencies: + - supports-color + + '@ai-sdk/provider-utils@2.2.8(zod@4.3.6)': + dependencies: + '@ai-sdk/provider': 1.1.3 + nanoid: 3.3.11 + secure-json-parse: 2.7.0 + zod: 4.3.6 + + '@ai-sdk/provider-utils@3.0.20(zod@4.3.6)': + dependencies: + '@ai-sdk/provider': 2.0.1 + '@standard-schema/spec': 1.1.0 + eventsource-parser: 3.0.6 + zod: 4.3.6 + + '@ai-sdk/provider-utils@4.0.0(zod@4.3.6)': + dependencies: + '@ai-sdk/provider': 3.0.0 + '@standard-schema/spec': 1.1.0 + eventsource-parser: 3.0.6 + zod: 4.3.6 + + '@ai-sdk/provider@1.1.3': + dependencies: + json-schema: 0.4.0 + + '@ai-sdk/provider@2.0.1': + dependencies: + json-schema: 0.4.0 + + '@ai-sdk/provider@3.0.0': + dependencies: + json-schema: 0.4.0 + + '@ai-sdk/provider@3.0.5': + dependencies: + json-schema: 0.4.0 + + '@ai-sdk/ui-utils@1.2.11(zod@4.3.6)': + dependencies: + '@ai-sdk/provider': 1.1.3 + '@ai-sdk/provider-utils': 2.2.8(zod@4.3.6) + zod: 4.3.6 + zod-to-json-schema: 3.25.2(zod@4.3.6) + '@angular-devkit/core@19.2.17(chokidar@4.0.3)': dependencies: ajv: 8.17.1 @@ -3981,9 +4490,11 @@ snapshots: transitivePeerDependencies: - chokidar - '@anthropic-ai/sdk@0.80.0': + '@anthropic-ai/sdk@0.80.0(zod@4.3.6)': dependencies: json-schema-to-ts: 3.1.1 + optionalDependencies: + zod: 4.3.6 '@babel/code-frame@7.29.0': dependencies: @@ -4316,6 +4827,10 @@ snapshots: '@eslint/core': 1.1.1 levn: 0.4.1 + '@hono/node-server@1.19.11(hono@4.12.9)': + dependencies: + hono: 4.12.9 + '@humanfs/core@0.19.1': {} '@humanfs/node@0.16.7': @@ -4478,6 +4993,8 @@ snapshots: wrap-ansi: 8.1.0 wrap-ansi-cjs: wrap-ansi@7.0.0 + '@isaacs/ttlcache@2.1.4': {} + '@istanbuljs/load-nyc-config@1.1.0': dependencies: camelcase: 5.3.1 @@ -4696,6 +5213,82 @@ snapshots: '@lukeed/csprng@1.1.0': {} + '@lukeed/uuid@2.0.1': + dependencies: + '@lukeed/csprng': 1.1.0 + + '@mastra/core@1.17.0(@standard-community/standard-json@0.3.5(@standard-schema/spec@1.1.0)(@types/json-schema@7.0.15)(quansync@0.2.11)(zod-to-json-schema@3.25.2(zod@4.3.6))(zod@4.3.6))(@standard-community/standard-openapi@0.2.9(@standard-community/standard-json@0.3.5(@standard-schema/spec@1.1.0)(@types/json-schema@7.0.15)(quansync@0.2.11)(zod-to-json-schema@3.25.2(zod@4.3.6))(zod@4.3.6))(@standard-schema/spec@1.1.0)(openapi-types@12.1.3)(zod@4.3.6))(@types/json-schema@7.0.15)(openapi-types@12.1.3)(zod@4.3.6)': + dependencies: + '@a2a-js/sdk': 0.2.5 + '@ai-sdk/provider-utils-v5': '@ai-sdk/provider-utils@3.0.20(zod@4.3.6)' + '@ai-sdk/provider-utils-v6': '@ai-sdk/provider-utils@4.0.0(zod@4.3.6)' + '@ai-sdk/provider-v5': '@ai-sdk/provider@2.0.1' + '@ai-sdk/provider-v6': '@ai-sdk/provider@3.0.5' + '@ai-sdk/ui-utils-v5': '@ai-sdk/ui-utils@1.2.11(zod@4.3.6)' + '@isaacs/ttlcache': 2.1.4 + '@lukeed/uuid': 2.0.1 + '@mastra/schema-compat': 1.2.7(zod@4.3.6) + '@modelcontextprotocol/sdk': 1.28.0(zod@4.3.6) + '@sindresorhus/slugify': 2.2.1 + '@standard-schema/spec': 1.1.0 + ajv: 8.18.0 + dotenv: 17.3.1 + execa: 9.6.1 + gray-matter: 4.0.3 + hono: 4.12.9 + hono-openapi: 1.3.0(@standard-community/standard-json@0.3.5(@standard-schema/spec@1.1.0)(@types/json-schema@7.0.15)(quansync@0.2.11)(zod-to-json-schema@3.25.2(zod@4.3.6))(zod@4.3.6))(@standard-community/standard-openapi@0.2.9(@standard-community/standard-json@0.3.5(@standard-schema/spec@1.1.0)(@types/json-schema@7.0.15)(quansync@0.2.11)(zod-to-json-schema@3.25.2(zod@4.3.6))(zod@4.3.6))(@standard-schema/spec@1.1.0)(openapi-types@12.1.3)(zod@4.3.6))(@types/json-schema@7.0.15)(hono@4.12.9)(openapi-types@12.1.3) + ignore: 7.0.5 + js-tiktoken: 1.0.21 + json-schema: 0.4.0 + lru-cache: 11.2.7 + p-map: 7.0.4 + p-retry: 7.1.1 + picomatch: 4.0.4 + radash: 12.1.1 + ws: 8.20.0 + xxhash-wasm: 1.1.0 + zod: 4.3.6 + transitivePeerDependencies: + - '@cfworker/json-schema' + - '@hono/standard-validator' + - '@standard-community/standard-json' + - '@standard-community/standard-openapi' + - '@types/json-schema' + - bufferutil + - openapi-types + - supports-color + - utf-8-validate + + '@mastra/schema-compat@1.2.7(zod@4.3.6)': + dependencies: + json-schema-to-zod: 2.7.0 + zod: 4.3.6 + zod-from-json-schema: 0.5.2 + zod-from-json-schema-v3: zod-from-json-schema@0.0.5 + zod-to-json-schema: 3.25.2(zod@4.3.6) + + '@modelcontextprotocol/sdk@1.28.0(zod@4.3.6)': + dependencies: + '@hono/node-server': 1.19.11(hono@4.12.9) + ajv: 8.18.0 + ajv-formats: 3.0.1(ajv@8.18.0) + content-type: 1.0.5 + cors: 2.8.6 + cross-spawn: 7.0.6 + eventsource: 3.0.7 + eventsource-parser: 3.0.6 + express: 5.2.1 + express-rate-limit: 8.3.1(express@5.2.1) + hono: 4.12.9 + jose: 6.2.2 + json-schema-typed: 8.0.2 + pkce-challenge: 5.0.1 + raw-body: 3.0.2 + zod: 4.3.6 + zod-to-json-schema: 3.25.2(zod@4.3.6) + transitivePeerDependencies: + - supports-color + '@napi-rs/wasm-runtime@0.2.12': dependencies: '@emnapi/core': 1.9.1 @@ -4921,8 +5514,21 @@ snapshots: '@rolldown/pluginutils@1.0.0-rc.7': {} + '@sec-ant/readable-stream@0.4.1': {} + '@sinclair/typebox@0.34.48': {} + '@sindresorhus/merge-streams@4.0.0': {} + + '@sindresorhus/slugify@2.2.1': + dependencies: + '@sindresorhus/transliterate': 1.6.0 + escape-string-regexp: 5.0.0 + + '@sindresorhus/transliterate@1.6.0': + dependencies: + escape-string-regexp: 5.0.0 + '@sinonjs/commons@3.0.1': dependencies: type-detect: 4.0.8 @@ -4935,6 +5541,25 @@ snapshots: '@sqltools/formatter@1.2.5': {} + '@standard-community/standard-json@0.3.5(@standard-schema/spec@1.1.0)(@types/json-schema@7.0.15)(quansync@0.2.11)(zod-to-json-schema@3.25.2(zod@4.3.6))(zod@4.3.6)': + dependencies: + '@standard-schema/spec': 1.1.0 + '@types/json-schema': 7.0.15 + quansync: 0.2.11 + optionalDependencies: + zod: 4.3.6 + zod-to-json-schema: 3.25.2(zod@4.3.6) + + '@standard-community/standard-openapi@0.2.9(@standard-community/standard-json@0.3.5(@standard-schema/spec@1.1.0)(@types/json-schema@7.0.15)(quansync@0.2.11)(zod-to-json-schema@3.25.2(zod@4.3.6))(zod@4.3.6))(@standard-schema/spec@1.1.0)(openapi-types@12.1.3)(zod@4.3.6)': + dependencies: + '@standard-community/standard-json': 0.3.5(@standard-schema/spec@1.1.0)(@types/json-schema@7.0.15)(quansync@0.2.11)(zod-to-json-schema@3.25.2(zod@4.3.6))(zod@4.3.6) + '@standard-schema/spec': 1.1.0 + openapi-types: 12.1.3 + optionalDependencies: + zod: 4.3.6 + + '@standard-schema/spec@1.1.0': {} + '@tokenizer/inflate@0.4.1': dependencies: debug: 4.4.3 @@ -5009,6 +5634,13 @@ snapshots: '@types/estree@1.0.8': {} + '@types/express-serve-static-core@4.19.8': + dependencies: + '@types/node': 25.5.0 + '@types/qs': 6.15.0 + '@types/range-parser': 1.2.7 + '@types/send': 1.2.1 + '@types/express-serve-static-core@5.1.1': dependencies: '@types/node': 25.5.0 @@ -5016,6 +5648,13 @@ snapshots: '@types/range-parser': 1.2.7 '@types/send': 1.2.1 + '@types/express@4.17.25': + dependencies: + '@types/body-parser': 1.19.6 + '@types/express-serve-static-core': 4.19.8 + '@types/qs': 6.15.0 + '@types/serve-static': 1.15.10 + '@types/express@5.0.6': dependencies: '@types/body-parser': 1.19.6 @@ -5046,6 +5685,8 @@ snapshots: '@types/ms': 2.1.0 '@types/node': 25.5.0 + '@types/mime@1.3.5': {} + '@types/ms@2.1.0': {} '@types/node@25.5.0': @@ -5078,10 +5719,21 @@ snapshots: dependencies: csstype: 3.2.3 + '@types/send@0.17.6': + dependencies: + '@types/mime': 1.3.5 + '@types/node': 25.5.0 + '@types/send@1.2.1': dependencies: '@types/node': 25.5.0 + '@types/serve-static@1.15.10': + dependencies: + '@types/http-errors': 2.0.5 + '@types/node': 25.5.0 + '@types/send': 0.17.6 + '@types/serve-static@2.2.0': dependencies: '@types/http-errors': 2.0.5 @@ -5374,6 +6026,10 @@ snapshots: optionalDependencies: ajv: 8.17.1 + ajv-formats@3.0.1(ajv@8.18.0): + optionalDependencies: + ajv: 8.18.0 + ajv-keywords@3.5.2(ajv@6.14.0): dependencies: ajv: 6.14.0 @@ -5441,6 +6097,8 @@ snapshots: argparse@2.0.1: {} + array-flatten@1.1.1: {} + array-timsort@1.0.3: {} asynckit@0.4.0: {} @@ -5522,6 +6180,23 @@ snapshots: inherits: 2.0.4 readable-stream: 3.6.2 + body-parser@1.20.4: + dependencies: + bytes: 3.1.2 + content-type: 1.0.5 + debug: 2.6.9 + depd: 2.0.0 + destroy: 1.2.0 + http-errors: 2.0.1 + iconv-lite: 0.4.24 + on-finished: 2.4.1 + qs: 6.14.2 + raw-body: 2.5.3 + type-is: 1.6.18 + unpipe: 1.0.0 + transitivePeerDependencies: + - supports-color + body-parser@2.2.2: dependencies: bytes: 3.1.2 @@ -5698,12 +6373,18 @@ snapshots: consola@3.4.2: {} + content-disposition@0.5.4: + dependencies: + safe-buffer: 5.2.1 + content-disposition@1.0.1: {} content-type@1.0.5: {} convert-source-map@2.0.0: {} + cookie-signature@1.0.7: {} + cookie-signature@1.2.2: {} cookie@0.7.2: {} @@ -5736,6 +6417,10 @@ snapshots: dayjs@1.11.20: {} + debug@2.6.9: + dependencies: + ms: 2.0.0 + debug@4.4.3: dependencies: ms: 2.1.3 @@ -5762,6 +6447,8 @@ snapshots: depd@2.0.0: {} + destroy@1.2.0: {} + detect-libc@2.1.2: {} detect-newline@3.1.0: {} @@ -5910,6 +6597,8 @@ snapshots: escape-string-regexp@4.0.0: {} + escape-string-regexp@5.0.0: {} + eslint-config-prettier@10.1.8(eslint@10.1.0): dependencies: eslint: 10.1.0 @@ -6003,6 +6692,12 @@ snapshots: events@3.3.0: {} + eventsource-parser@3.0.6: {} + + eventsource@3.0.7: + dependencies: + eventsource-parser: 3.0.6 + execa@5.1.1: dependencies: cross-spawn: 7.0.6 @@ -6015,6 +6710,21 @@ snapshots: signal-exit: 3.0.7 strip-final-newline: 2.0.0 + execa@9.6.1: + dependencies: + '@sindresorhus/merge-streams': 4.0.0 + cross-spawn: 7.0.6 + figures: 6.1.0 + get-stream: 9.0.1 + human-signals: 8.0.1 + is-plain-obj: 4.1.0 + is-stream: 4.0.1 + npm-run-path: 6.0.0 + pretty-ms: 9.3.0 + signal-exit: 4.1.0 + strip-final-newline: 4.0.0 + yoctocolors: 2.1.2 + exit-x@0.2.2: {} expect@30.3.0: @@ -6026,6 +6736,47 @@ snapshots: jest-mock: 30.3.0 jest-util: 30.3.0 + express-rate-limit@8.3.1(express@5.2.1): + dependencies: + express: 5.2.1 + ip-address: 10.1.0 + + express@4.22.1: + dependencies: + accepts: 1.3.8 + array-flatten: 1.1.1 + body-parser: 1.20.4 + content-disposition: 0.5.4 + content-type: 1.0.5 + cookie: 0.7.2 + cookie-signature: 1.0.7 + debug: 2.6.9 + depd: 2.0.0 + encodeurl: 2.0.0 + escape-html: 1.0.3 + etag: 1.8.1 + finalhandler: 1.3.2 + fresh: 0.5.2 + http-errors: 2.0.1 + merge-descriptors: 1.0.3 + methods: 1.1.2 + on-finished: 2.4.1 + parseurl: 1.3.3 + path-to-regexp: 0.1.13 + proxy-addr: 2.0.7 + qs: 6.14.2 + range-parser: 1.2.1 + safe-buffer: 5.2.1 + send: 0.19.2 + serve-static: 1.16.3 + setprototypeof: 1.2.0 + statuses: 2.0.2 + type-is: 1.6.18 + utils-merge: 1.0.1 + vary: 1.1.2 + transitivePeerDependencies: + - supports-color + express@5.2.1: dependencies: accepts: 2.0.0 @@ -6059,6 +6810,10 @@ snapshots: transitivePeerDependencies: - supports-color + extend-shallow@2.0.1: + dependencies: + is-extendable: 0.1.1 + fast-deep-equal@3.1.3: {} fast-diff@1.3.0: {} @@ -6079,6 +6834,10 @@ snapshots: optionalDependencies: picomatch: 4.0.4 + figures@6.1.0: + dependencies: + is-unicode-supported: 2.1.0 + file-entry-cache@8.0.0: dependencies: flat-cache: 4.0.1 @@ -6092,6 +6851,18 @@ snapshots: transitivePeerDependencies: - supports-color + finalhandler@1.3.2: + dependencies: + debug: 2.6.9 + encodeurl: 2.0.0 + escape-html: 1.0.3 + on-finished: 2.4.1 + parseurl: 1.3.3 + statuses: 2.0.2 + unpipe: 1.0.0 + transitivePeerDependencies: + - supports-color + finalhandler@2.1.1: dependencies: debug: 4.4.3 @@ -6160,6 +6931,8 @@ snapshots: forwarded@0.2.0: {} + fresh@0.5.2: {} + fresh@2.0.0: {} fs-extra@10.1.0: @@ -6203,6 +6976,11 @@ snapshots: get-stream@6.0.1: {} + get-stream@9.0.1: + dependencies: + '@sec-ant/readable-stream': 0.4.1 + is-stream: 4.0.1 + get-tsconfig@4.13.7: dependencies: resolve-pkg-maps: 1.0.0 @@ -6241,6 +7019,13 @@ snapshots: graceful-fs@4.2.11: {} + gray-matter@4.0.3: + dependencies: + js-yaml: 3.14.2 + kind-of: 6.0.3 + section-matter: 1.0.0 + strip-bom-string: 1.0.0 + handlebars@4.7.9: dependencies: minimist: 1.2.8 @@ -6266,6 +7051,17 @@ snapshots: dependencies: function-bind: 1.1.2 + hono-openapi@1.3.0(@standard-community/standard-json@0.3.5(@standard-schema/spec@1.1.0)(@types/json-schema@7.0.15)(quansync@0.2.11)(zod-to-json-schema@3.25.2(zod@4.3.6))(zod@4.3.6))(@standard-community/standard-openapi@0.2.9(@standard-community/standard-json@0.3.5(@standard-schema/spec@1.1.0)(@types/json-schema@7.0.15)(quansync@0.2.11)(zod-to-json-schema@3.25.2(zod@4.3.6))(zod@4.3.6))(@standard-schema/spec@1.1.0)(openapi-types@12.1.3)(zod@4.3.6))(@types/json-schema@7.0.15)(hono@4.12.9)(openapi-types@12.1.3): + dependencies: + '@standard-community/standard-json': 0.3.5(@standard-schema/spec@1.1.0)(@types/json-schema@7.0.15)(quansync@0.2.11)(zod-to-json-schema@3.25.2(zod@4.3.6))(zod@4.3.6) + '@standard-community/standard-openapi': 0.2.9(@standard-community/standard-json@0.3.5(@standard-schema/spec@1.1.0)(@types/json-schema@7.0.15)(quansync@0.2.11)(zod-to-json-schema@3.25.2(zod@4.3.6))(zod@4.3.6))(@standard-schema/spec@1.1.0)(openapi-types@12.1.3)(zod@4.3.6) + '@types/json-schema': 7.0.15 + openapi-types: 12.1.3 + optionalDependencies: + hono: 4.12.9 + + hono@4.12.9: {} + html-escaper@2.0.2: {} http-errors@2.0.1: @@ -6278,6 +7074,12 @@ snapshots: human-signals@2.1.0: {} + human-signals@8.0.1: {} + + iconv-lite@0.4.24: + dependencies: + safer-buffer: 2.1.2 + iconv-lite@0.7.2: dependencies: safer-buffer: 2.1.2 @@ -6321,12 +7123,16 @@ snapshots: transitivePeerDependencies: - supports-color + ip-address@10.1.0: {} + ipaddr.js@1.9.1: {} is-arrayish@0.2.1: {} is-callable@1.2.7: {} + is-extendable@0.1.1: {} + is-extglob@2.1.1: {} is-fullwidth-code-point@3.0.0: {} @@ -6339,16 +7145,24 @@ snapshots: is-interactive@1.0.0: {} + is-network-error@1.3.1: {} + + is-plain-obj@4.1.0: {} + is-promise@4.0.0: {} is-stream@2.0.1: {} + is-stream@4.0.1: {} + is-typed-array@1.1.15: dependencies: which-typed-array: 1.1.20 is-unicode-supported@0.1.0: {} + is-unicode-supported@2.1.0: {} + isarray@2.0.5: {} isexe@2.0.0: {} @@ -6709,6 +7523,12 @@ snapshots: - supports-color - ts-node + jose@6.2.2: {} + + js-tiktoken@1.0.21: + dependencies: + base64-js: 1.5.1 + js-tokens@4.0.0: {} js-yaml@3.14.2: @@ -6731,10 +7551,16 @@ snapshots: '@babel/runtime': 7.29.2 ts-algebra: 2.0.0 + json-schema-to-zod@2.7.0: {} + json-schema-traverse@0.4.1: {} json-schema-traverse@1.0.0: {} + json-schema-typed@8.0.2: {} + + json-schema@0.4.0: {} + json-stable-stringify-without-jsonify@1.0.1: {} json5@2.2.3: {} @@ -6775,6 +7601,8 @@ snapshots: dependencies: json-buffer: 3.0.1 + kind-of@6.0.3: {} + leven@3.1.0: {} levn@0.4.1: @@ -6906,10 +7734,14 @@ snapshots: dependencies: fs-monkey: 1.1.0 + merge-descriptors@1.0.3: {} + merge-descriptors@2.0.0: {} merge-stream@2.0.0: {} + methods@1.1.2: {} + mime-db@1.52.0: {} mime-db@1.54.0: {} @@ -6922,6 +7754,8 @@ snapshots: dependencies: mime-db: 1.54.0 + mime@1.6.0: {} + mimic-fn@2.1.0: {} minimatch@10.2.4: @@ -6940,6 +7774,8 @@ snapshots: minipass@7.1.3: {} + ms@2.0.0: {} + ms@2.1.3: {} multer@2.1.1: @@ -6987,6 +7823,11 @@ snapshots: dependencies: path-key: 3.1.1 + npm-run-path@6.0.0: + dependencies: + path-key: 4.0.0 + unicorn-magic: 0.3.0 + object-assign@4.1.1: {} object-hash@3.0.0: {} @@ -7005,9 +7846,12 @@ snapshots: dependencies: mimic-fn: 2.1.0 - openai@6.33.0(ws@8.18.3): + openai@6.33.0(ws@8.20.0)(zod@4.3.6): optionalDependencies: - ws: 8.18.3 + ws: 8.20.0 + zod: 4.3.6 + + openapi-types@12.1.3: {} optionator@0.9.4: dependencies: @@ -7046,6 +7890,12 @@ snapshots: dependencies: p-limit: 3.1.0 + p-map@7.0.4: {} + + p-retry@7.1.1: + dependencies: + is-network-error: 1.3.1 + p-try@2.2.0: {} package-json-from-dist@1.0.1: {} @@ -7061,6 +7911,8 @@ snapshots: json-parse-even-better-errors: 2.3.1 lines-and-columns: 1.2.4 + parse-ms@4.0.0: {} + parseurl@1.3.3: {} passport-jwt@4.0.1: @@ -7082,6 +7934,8 @@ snapshots: path-key@3.1.1: {} + path-key@4.0.0: {} + path-scurry@1.11.1: dependencies: lru-cache: 10.4.3 @@ -7092,6 +7946,8 @@ snapshots: lru-cache: 11.2.7 minipass: 7.1.3 + path-to-regexp@0.1.13: {} + path-to-regexp@8.3.0: {} path-type@4.0.0: {} @@ -7143,6 +7999,8 @@ snapshots: pirates@4.0.7: {} + pkce-challenge@5.0.1: {} + pkg-dir@4.2.0: dependencies: find-up: 4.1.0 @@ -7181,6 +8039,10 @@ snapshots: ansi-styles: 5.2.0 react-is: 18.3.1 + pretty-ms@9.3.0: + dependencies: + parse-ms: 4.0.0 + process@0.11.10: {} proxy-addr@2.0.7: @@ -7192,12 +8054,27 @@ snapshots: pure-rand@7.0.1: {} + qs@6.14.2: + dependencies: + side-channel: 1.1.0 + qs@6.15.0: dependencies: side-channel: 1.1.0 + quansync@0.2.11: {} + + radash@12.1.1: {} + range-parser@1.2.1: {} + raw-body@2.5.3: + dependencies: + bytes: 3.1.2 + http-errors: 2.0.1 + iconv-lite: 0.4.24 + unpipe: 1.0.0 + raw-body@3.0.2: dependencies: bytes: 3.1.2 @@ -7315,10 +8192,35 @@ snapshots: ajv-formats: 2.1.1(ajv@8.18.0) ajv-keywords: 5.1.0(ajv@8.18.0) + section-matter@1.0.0: + dependencies: + extend-shallow: 2.0.1 + kind-of: 6.0.3 + + secure-json-parse@2.7.0: {} + semver@6.3.1: {} semver@7.7.4: {} + send@0.19.2: + dependencies: + debug: 2.6.9 + depd: 2.0.0 + destroy: 1.2.0 + encodeurl: 2.0.0 + escape-html: 1.0.3 + etag: 1.8.1 + fresh: 0.5.2 + http-errors: 2.0.1 + mime: 1.6.0 + ms: 2.1.3 + on-finished: 2.4.1 + range-parser: 1.2.1 + statuses: 2.0.2 + transitivePeerDependencies: + - supports-color + send@1.2.1: dependencies: debug: 4.4.3 @@ -7335,6 +8237,15 @@ snapshots: transitivePeerDependencies: - supports-color + serve-static@1.16.3: + dependencies: + encodeurl: 2.0.0 + escape-html: 1.0.3 + parseurl: 1.3.3 + send: 0.19.2 + transitivePeerDependencies: + - supports-color + serve-static@2.2.1: dependencies: encodeurl: 2.0.0 @@ -7503,12 +8414,16 @@ snapshots: dependencies: ansi-regex: 6.2.2 + strip-bom-string@1.0.0: {} + strip-bom@3.0.0: {} strip-bom@4.0.0: {} strip-final-newline@2.0.0: {} + strip-final-newline@4.0.0: {} + strip-json-comments@3.1.1: {} strtok3@10.3.5: @@ -7710,6 +8625,8 @@ snapshots: undici-types@7.18.2: {} + unicorn-magic@0.3.0: {} + universalify@2.0.1: {} unpipe@1.0.0: {} @@ -7883,10 +8800,14 @@ snapshots: ws@8.18.3: {} + ws@8.20.0: {} + xmlhttprequest-ssl@2.1.2: {} xtend@4.0.2: {} + xxhash-wasm@1.1.0: {} + y18n@5.0.8: {} yallist@3.1.1: {} @@ -7908,3 +8829,21 @@ snapshots: yocto-queue@0.1.0: {} yoctocolors-cjs@2.1.3: {} + + yoctocolors@2.1.2: {} + + zod-from-json-schema@0.0.5: + dependencies: + zod: 3.25.76 + + zod-from-json-schema@0.5.2: + dependencies: + zod: 4.3.6 + + zod-to-json-schema@3.25.2(zod@4.3.6): + dependencies: + zod: 4.3.6 + + zod@3.25.76: {} + + zod@4.3.6: {}