From 22d4737b77f0a89e7a90e538679cc143e28b5494 Mon Sep 17 00:00:00 2001
From: Jack Herrington
Date: Tue, 20 Jan 2026 07:06:00 -0800
Subject: [PATCH 01/31] Realtime chat basically working
---
examples/ts-react-chat/.env.example | 10 +-
examples/ts-react-chat/package.json | 1 +
.../ts-react-chat/src/components/Header.tsx | 15 +-
examples/ts-react-chat/src/routeTree.gen.ts | 48 +-
.../src/routes/api.realtime-token.ts | 86 +++
.../ts-react-chat/src/routes/realtime.tsx | 501 +++++++++++++++
packages/typescript/ai-client/src/index.ts | 8 +
.../ai-client/src/realtime-client.ts | 451 ++++++++++++++
.../ai-client/src/realtime-types.ts | 142 +++++
packages/typescript/ai-elevenlabs/README.md | 76 +++
.../typescript/ai-elevenlabs/package.json | 55 ++
.../typescript/ai-elevenlabs/src/index.ts | 16 +
.../ai-elevenlabs/src/realtime/adapter.ts | 251 ++++++++
.../ai-elevenlabs/src/realtime/index.ts | 14 +
.../ai-elevenlabs/src/realtime/token.ts | 103 +++
.../ai-elevenlabs/src/realtime/types.ts | 62 ++
.../typescript/ai-elevenlabs/tsconfig.json | 8 +
.../typescript/ai-elevenlabs/vite.config.ts | 37 ++
packages/typescript/ai-openai/package.json | 2 +
packages/typescript/ai-openai/src/index.ts | 19 +
.../ai-openai/src/realtime/adapter.ts | 585 ++++++++++++++++++
.../ai-openai/src/realtime/index.ts | 16 +
.../ai-openai/src/realtime/token.ts | 153 +++++
.../ai-openai/src/realtime/types.ts | 127 ++++
packages/typescript/ai-react/src/index.ts | 5 +
.../typescript/ai-react/src/realtime-types.ts | 109 ++++
.../ai-react/src/use-realtime-chat.ts | 241 ++++++++
packages/typescript/ai/src/index.ts | 24 +
packages/typescript/ai/src/realtime/index.ts | 38 ++
packages/typescript/ai/src/realtime/types.ts | 266 ++++++++
pnpm-lock.yaml | 115 ++++
31 files changed, 3581 insertions(+), 3 deletions(-)
create mode 100644 examples/ts-react-chat/src/routes/api.realtime-token.ts
create mode 100644 examples/ts-react-chat/src/routes/realtime.tsx
create mode 100644 packages/typescript/ai-client/src/realtime-client.ts
create mode 100644 packages/typescript/ai-client/src/realtime-types.ts
create mode 100644 packages/typescript/ai-elevenlabs/README.md
create mode 100644 packages/typescript/ai-elevenlabs/package.json
create mode 100644 packages/typescript/ai-elevenlabs/src/index.ts
create mode 100644 packages/typescript/ai-elevenlabs/src/realtime/adapter.ts
create mode 100644 packages/typescript/ai-elevenlabs/src/realtime/index.ts
create mode 100644 packages/typescript/ai-elevenlabs/src/realtime/token.ts
create mode 100644 packages/typescript/ai-elevenlabs/src/realtime/types.ts
create mode 100644 packages/typescript/ai-elevenlabs/tsconfig.json
create mode 100644 packages/typescript/ai-elevenlabs/vite.config.ts
create mode 100644 packages/typescript/ai-openai/src/realtime/adapter.ts
create mode 100644 packages/typescript/ai-openai/src/realtime/index.ts
create mode 100644 packages/typescript/ai-openai/src/realtime/token.ts
create mode 100644 packages/typescript/ai-openai/src/realtime/types.ts
create mode 100644 packages/typescript/ai-react/src/realtime-types.ts
create mode 100644 packages/typescript/ai-react/src/use-realtime-chat.ts
create mode 100644 packages/typescript/ai/src/realtime/index.ts
create mode 100644 packages/typescript/ai/src/realtime/types.ts
diff --git a/examples/ts-react-chat/.env.example b/examples/ts-react-chat/.env.example
index 613cb664b2..2bdb43f49d 100644
--- a/examples/ts-react-chat/.env.example
+++ b/examples/ts-react-chat/.env.example
@@ -1,3 +1,11 @@
# OpenAI API Key
# Get yours at: https://platform.openai.com/api-keys
-OPENAI_API_KEY=sk-...
\ No newline at end of file
+OPENAI_API_KEY=sk-...
+
+# ElevenLabs API Key (for realtime voice)
+# Get yours at: https://elevenlabs.io/app/settings/api-keys
+ELEVENLABS_API_KEY=xi-...
+
+# ElevenLabs Agent ID (for realtime voice)
+# Create an agent at: https://elevenlabs.io/app/conversational-ai
+ELEVENLABS_AGENT_ID=...
diff --git a/examples/ts-react-chat/package.json b/examples/ts-react-chat/package.json
index f58f54bda1..42935c5104 100644
--- a/examples/ts-react-chat/package.json
+++ b/examples/ts-react-chat/package.json
@@ -17,6 +17,7 @@
"@tanstack/ai-grok": "workspace:*",
"@tanstack/ai-ollama": "workspace:*",
"@tanstack/ai-openai": "workspace:*",
+ "@tanstack/ai-elevenlabs": "workspace:*",
"@tanstack/ai-openrouter": "workspace:*",
"@tanstack/ai-react": "workspace:*",
"@tanstack/ai-react-ui": "workspace:*",
diff --git a/examples/ts-react-chat/src/components/Header.tsx b/examples/ts-react-chat/src/components/Header.tsx
index 57745b7b0a..6af310b711 100644
--- a/examples/ts-react-chat/src/components/Header.tsx
+++ b/examples/ts-react-chat/src/components/Header.tsx
@@ -1,7 +1,7 @@
import { Link } from '@tanstack/react-router'
import { useState } from 'react'
-import { Guitar, Home, Menu, X } from 'lucide-react'
+import { Guitar, Home, Menu, Mic, X } from 'lucide-react'
export default function Header() {
const [isOpen, setIsOpen] = useState(false)
@@ -71,6 +71,19 @@ export default function Header() {
Guitar Demo
+
+ setIsOpen(false)}
+ className="flex items-center gap-3 p-3 rounded-lg hover:bg-gray-800 transition-colors mb-2"
+ activeProps={{
+ className:
+ 'flex items-center gap-3 p-3 rounded-lg bg-cyan-600 hover:bg-cyan-700 transition-colors mb-2',
+ }}
+ >
+
+ Voice Chat (Realtime)
+
>
diff --git a/examples/ts-react-chat/src/routeTree.gen.ts b/examples/ts-react-chat/src/routeTree.gen.ts
index 627a240cfc..a8525c1c4c 100644
--- a/examples/ts-react-chat/src/routeTree.gen.ts
+++ b/examples/ts-react-chat/src/routeTree.gen.ts
@@ -9,11 +9,18 @@
// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified.
import { Route as rootRouteImport } from './routes/__root'
+import { Route as RealtimeRouteImport } from './routes/realtime'
import { Route as IndexRouteImport } from './routes/index'
import { Route as ApiTanchatRouteImport } from './routes/api.tanchat'
+import { Route as ApiRealtimeTokenRouteImport } from './routes/api.realtime-token'
import { Route as ExampleGuitarsIndexRouteImport } from './routes/example.guitars/index'
import { Route as ExampleGuitarsGuitarIdRouteImport } from './routes/example.guitars/$guitarId'
+const RealtimeRoute = RealtimeRouteImport.update({
+ id: '/realtime',
+ path: '/realtime',
+ getParentRoute: () => rootRouteImport,
+} as any)
const IndexRoute = IndexRouteImport.update({
id: '/',
path: '/',
@@ -24,6 +31,11 @@ const ApiTanchatRoute = ApiTanchatRouteImport.update({
path: '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/api/tanchat',
getParentRoute: () => rootRouteImport,
} as any)
+const ApiRealtimeTokenRoute = ApiRealtimeTokenRouteImport.update({
+ id: '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/api/realtime-token',
+ path: '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/api/realtime-token',
+ getParentRoute: () => rootRouteImport,
+} as any)
const ExampleGuitarsIndexRoute = ExampleGuitarsIndexRouteImport.update({
id: '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/example/guitars/',
path: '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/example/guitars/',
@@ -37,12 +49,16 @@ const ExampleGuitarsGuitarIdRoute = ExampleGuitarsGuitarIdRouteImport.update({
export interface FileRoutesByFullPath {
'/': typeof IndexRoute
+ '/realtime': typeof RealtimeRoute
+ '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/api/realtime-token': typeof ApiRealtimeTokenRoute
'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/api/tanchat': typeof ApiTanchatRoute
'/example/guitars/$guitarId': typeof ExampleGuitarsGuitarIdRoute
'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/example/guitars': typeof ExampleGuitarsIndexRoute
}
export interface FileRoutesByTo {
'/': typeof IndexRoute
+ '/realtime': typeof RealtimeRoute
+ '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/api/realtime-token': typeof ApiRealtimeTokenRoute
'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/api/tanchat': typeof ApiTanchatRoute
'/example/guitars/$guitarId': typeof ExampleGuitarsGuitarIdRoute
'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/example/guitars': typeof ExampleGuitarsIndexRoute
@@ -50,6 +66,8 @@ export interface FileRoutesByTo {
export interface FileRoutesById {
__root__: typeof rootRouteImport
'/': typeof IndexRoute
+ '/realtime': typeof RealtimeRoute
+ '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/api/realtime-token': typeof ApiRealtimeTokenRoute
'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/api/tanchat': typeof ApiTanchatRoute
'/example/guitars/$guitarId': typeof ExampleGuitarsGuitarIdRoute
'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/example/guitars/': typeof ExampleGuitarsIndexRoute
@@ -58,14 +76,24 @@ export interface FileRouteTypes {
fileRoutesByFullPath: FileRoutesByFullPath
fullPaths:
| '/'
+ | '/realtime'
+ | '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/api/realtime-token'
| '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/api/tanchat'
| '/example/guitars/$guitarId'
| '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/example/guitars'
fileRoutesByTo: FileRoutesByTo
- to: '/' | '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/api/tanchat' | '/example/guitars/$guitarId' | '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/example/guitars'
+ to:
+ | '/'
+ | '/realtime'
+ | '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/api/realtime-token'
+ | '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/api/tanchat'
+ | '/example/guitars/$guitarId'
+ | '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/example/guitars'
id:
| '__root__'
| '/'
+ | '/realtime'
+ | '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/api/realtime-token'
| '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/api/tanchat'
| '/example/guitars/$guitarId'
| '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/example/guitars/'
@@ -73,6 +101,8 @@ export interface FileRouteTypes {
}
export interface RootRouteChildren {
IndexRoute: typeof IndexRoute
+ RealtimeRoute: typeof RealtimeRoute
+ ApiRealtimeTokenRoute: typeof ApiRealtimeTokenRoute
ApiTanchatRoute: typeof ApiTanchatRoute
ExampleGuitarsGuitarIdRoute: typeof ExampleGuitarsGuitarIdRoute
ExampleGuitarsIndexRoute: typeof ExampleGuitarsIndexRoute
@@ -80,6 +110,13 @@ export interface RootRouteChildren {
declare module '@tanstack/react-router' {
interface FileRoutesByPath {
+ '/realtime': {
+ id: '/realtime'
+ path: '/realtime'
+ fullPath: '/realtime'
+ preLoaderRoute: typeof RealtimeRouteImport
+ parentRoute: typeof rootRouteImport
+ }
'/': {
id: '/'
path: '/'
@@ -94,6 +131,13 @@ declare module '@tanstack/react-router' {
preLoaderRoute: typeof ApiTanchatRouteImport
parentRoute: typeof rootRouteImport
}
+ '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/api/realtime-token': {
+ id: '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/api/realtime-token'
+ path: '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/api/realtime-token'
+ fullPath: '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/api/realtime-token'
+ preLoaderRoute: typeof ApiRealtimeTokenRouteImport
+ parentRoute: typeof rootRouteImport
+ }
'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/example/guitars/': {
id: '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/example/guitars/'
path: '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/example/guitars'
@@ -113,6 +157,8 @@ declare module '@tanstack/react-router' {
const rootRouteChildren: RootRouteChildren = {
IndexRoute: IndexRoute,
+ RealtimeRoute: RealtimeRoute,
+ ApiRealtimeTokenRoute: ApiRealtimeTokenRoute,
ApiTanchatRoute: ApiTanchatRoute,
ExampleGuitarsGuitarIdRoute: ExampleGuitarsGuitarIdRoute,
ExampleGuitarsIndexRoute: ExampleGuitarsIndexRoute,
diff --git a/examples/ts-react-chat/src/routes/api.realtime-token.ts b/examples/ts-react-chat/src/routes/api.realtime-token.ts
new file mode 100644
index 0000000000..0f7a46bdaa
--- /dev/null
+++ b/examples/ts-react-chat/src/routes/api.realtime-token.ts
@@ -0,0 +1,86 @@
+import { createFileRoute } from '@tanstack/react-router'
+import { realtimeToken } from '@tanstack/ai'
+import { openaiRealtimeToken } from '@tanstack/ai-openai'
+import { elevenlabsRealtimeToken } from '@tanstack/ai-elevenlabs'
+
+type Provider = 'openai' | 'elevenlabs'
+
+export const Route = createFileRoute('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/api/realtime-token')({
+ server: {
+ handlers: {
+ POST: async ({ request }) => {
+ try {
+ const body = await request.json()
+ const provider: Provider = body.provider || 'openai'
+
+ let token
+
+ if (provider === 'openai') {
+ token = await realtimeToken({
+ adapter: openaiRealtimeToken({
+ model: 'gpt-4o-realtime-preview',
+ voice: 'alloy',
+ instructions: `You are a helpful, friendly assistant.
+
+Keep your responses concise and conversational since this is a voice interface.
+Be natural and engaging in your responses.`,
+ turnDetection: {
+ type: 'server_vad',
+ threshold: 0.5,
+ prefix_padding_ms: 300,
+ silence_duration_ms: 500,
+ },
+ inputAudioTranscription: {
+ model: 'whisper-1',
+ },
+ }),
+ })
+ } else if (provider === 'elevenlabs') {
+ const agentId = body.agentId || process.env.ELEVENLABS_AGENT_ID
+
+ if (!agentId) {
+ return new Response(
+ JSON.stringify({
+ error: 'ElevenLabs agent ID is required. Set ELEVENLABS_AGENT_ID or pass agentId in request body.',
+ }),
+ {
+ status: 400,
+ headers: { 'Content-Type': 'application/json' },
+ },
+ )
+ }
+
+ token = await realtimeToken({
+ adapter: elevenlabsRealtimeToken({
+ agentId,
+ }),
+ })
+ } else {
+ return new Response(
+ JSON.stringify({ error: `Unknown provider: ${provider}` }),
+ {
+ status: 400,
+ headers: { 'Content-Type': 'application/json' },
+ },
+ )
+ }
+
+ return new Response(JSON.stringify(token), {
+ headers: { 'Content-Type': 'application/json' },
+ })
+ } catch (error: any) {
+ console.error('[Realtime Token API] Error:', error)
+ return new Response(
+ JSON.stringify({
+ error: error.message || 'Failed to generate realtime token',
+ }),
+ {
+ status: 500,
+ headers: { 'Content-Type': 'application/json' },
+ },
+ )
+ }
+ },
+ },
+ },
+})
diff --git a/examples/ts-react-chat/src/routes/realtime.tsx b/examples/ts-react-chat/src/routes/realtime.tsx
new file mode 100644
index 0000000000..fcc954cb16
--- /dev/null
+++ b/examples/ts-react-chat/src/routes/realtime.tsx
@@ -0,0 +1,501 @@
+import { useEffect, useRef, useState } from 'react'
+import { createFileRoute } from '@tanstack/react-router'
+import { useRealtimeChat } from '@tanstack/ai-react'
+import { openaiRealtime } from '@tanstack/ai-openai'
+import { elevenlabsRealtime } from '@tanstack/ai-elevenlabs'
+import { Mic, MicOff, Phone, PhoneOff, Volume2 } from 'lucide-react'
+
+type Provider = 'openai' | 'elevenlabs'
+
+const PROVIDER_OPTIONS: Array<{ value: Provider; label: string }> = [
+ { value: 'openai', label: 'OpenAI Realtime' },
+ { value: 'elevenlabs', label: 'ElevenLabs' },
+]
+
+// Sparkline component to visualize audio waveform
+function AudioSparkline({
+ getData,
+ color,
+ label,
+}: {
+ getData: () => Uint8Array
+ color: string
+ label: string
+}) {
+ const canvasRef = useRef(null)
+ const animationRef = useRef(null)
+
+ useEffect(() => {
+ const canvas = canvasRef.current
+ if (!canvas) return
+
+ const ctx = canvas.getContext('2d')
+ if (!ctx) return
+
+ function draw() {
+ const data = getData()
+ const width = canvas!.width
+ const height = canvas!.height
+
+ // Clear canvas
+ ctx!.fillStyle = '#1f2937' // gray-800
+ ctx!.fillRect(0, 0, width, height)
+
+ // Draw waveform
+ ctx!.strokeStyle = color
+ ctx!.lineWidth = 1
+ ctx!.beginPath()
+
+ // Sample the data to fit the canvas width
+ const step = Math.max(1, Math.floor(data.length / width))
+
+ for (let i = 0; i < width; i++) {
+ const dataIndex = Math.min(i * step, data.length - 1)
+ const value = data[dataIndex] ?? 128
+ // Convert 0-255 to canvas height (128 is center/silence)
+ const y = height - ((value / 255) * height)
+
+ if (i === 0) {
+ ctx!.moveTo(i, y)
+ } else {
+ ctx!.lineTo(i, y)
+ }
+ }
+
+ ctx!.stroke()
+
+ // Draw center line (silence level)
+ ctx!.strokeStyle = '#4b5563' // gray-600
+ ctx!.setLineDash([2, 2])
+ ctx!.beginPath()
+ ctx!.moveTo(0, height / 2)
+ ctx!.lineTo(width, height / 2)
+ ctx!.stroke()
+ ctx!.setLineDash([])
+
+ animationRef.current = requestAnimationFrame(draw)
+ }
+
+ draw()
+
+ return () => {
+ if (animationRef.current) {
+ cancelAnimationFrame(animationRef.current)
+ }
+ }
+ }, [getData, color])
+
+ return (
+
+ {label}
+
+
+ )
+}
+
+// Debug component to show raw audio data stats
+function AudioDebug({
+ getData,
+ label
+}: {
+ getData: () => Uint8Array
+ label: string
+}) {
+ const [stats, setStats] = useState({ length: 0, min: 0, max: 0, allSame: true, sample: '[]' })
+
+ useEffect(() => {
+ function update() {
+ const data = getData()
+ const min = Math.min(...data)
+ const max = Math.max(...data)
+ const allSame = data.every(v => v === data[0])
+ // Get a few samples from different parts of the array
+ const samples = data.length > 0 ? [
+ data[0],
+ data[Math.floor(data.length / 4)],
+ data[Math.floor(data.length / 2)],
+ data[Math.floor(data.length * 3 / 4)],
+ data[data.length - 1]
+ ] : []
+ setStats({
+ length: data.length,
+ min,
+ max,
+ allSame,
+ sample: `[${samples.join(', ')}]`
+ })
+ requestAnimationFrame(update)
+ }
+ const id = requestAnimationFrame(update)
+ return () => cancelAnimationFrame(id)
+ }, [getData])
+
+ return (
+
+ {label}: len={stats.length}, min={stats.min}, max={stats.max},
+ {stats.allSame ? ALL SAME! : varying }
+ {stats.sample}
+
+ )
+}
+
+function RealtimePage() {
+ const [provider, setProvider] = useState('openai')
+ const [agentId, setAgentId] = useState('')
+ const [showDebug, setShowDebug] = useState(true)
+ const messagesEndRef = useRef(null)
+
+ // Get the appropriate adapter based on provider
+ const adapter = provider === 'openai' ? openaiRealtime() : elevenlabsRealtime()
+
+ const {
+ status,
+ mode,
+ messages,
+ pendingUserTranscript,
+ pendingAssistantTranscript,
+ error,
+ connect,
+ disconnect,
+ interrupt,
+ inputLevel,
+ outputLevel,
+ sendText,
+ getInputTimeDomainData,
+ getOutputTimeDomainData,
+ } = useRealtimeChat({
+ getToken: async () => {
+ const body: Record = { provider }
+ if (provider === 'elevenlabs' && agentId) {
+ body.agentId = agentId
+ }
+ const response = await fetch('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/api/realtime-token', {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify(body),
+ })
+ if (!response.ok) {
+ const error = await response.json()
+ throw new Error(error.error || 'Failed to get token')
+ }
+ return response.json()
+ },
+ adapter,
+ onError: (err) => {
+ console.error('Realtime error:', err)
+ },
+ })
+
+ // Auto-scroll to bottom when messages change
+ useEffect(() => {
+ messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' })
+ }, [messages, pendingUserTranscript, pendingAssistantTranscript])
+
+ // Get status color
+ const getStatusColor = () => {
+ switch (status) {
+ case 'connected':
+ return 'bg-green-500'
+ case 'connecting':
+ case 'reconnecting':
+ return 'bg-yellow-500'
+ case 'error':
+ return 'bg-red-500'
+ default:
+ return 'bg-gray-500'
+ }
+ }
+
+ // Get mode icon
+ const getModeIndicator = () => {
+ switch (mode) {
+ case 'listening':
+ return (
+
+
+ Listening...
+
+ )
+ case 'thinking':
+ return (
+
+ )
+ case 'speaking':
+ return (
+
+
+ Speaking...
+
+ )
+ default:
+ return (
+
+
+ Idle
+
+ )
+ }
+ }
+
+ return (
+
+
+ {/* Header */}
+
+
+
+ {/* Provider selector */}
+
+
+ Provider
+
+ setProvider(e.target.value as Provider)}
+ disabled={status !== 'idle'}
+ className="rounded-lg border border-orange-500/20 bg-gray-900 px-3 py-2 text-sm text-white focus:outline-none focus:ring-2 focus:ring-orange-500/50 disabled:opacity-50"
+ >
+ {PROVIDER_OPTIONS.map((opt) => (
+
+ {opt.label}
+
+ ))}
+
+
+
+ {/* ElevenLabs Agent ID (conditional) */}
+ {provider === 'elevenlabs' && (
+
+
+ Agent ID
+
+ setAgentId(e.target.value)}
+ placeholder="Your ElevenLabs Agent ID"
+ disabled={status !== 'idle'}
+ className="rounded-lg border border-orange-500/20 bg-gray-900 px-3 py-2 text-sm text-white focus:outline-none focus:ring-2 focus:ring-orange-500/50 disabled:opacity-50 w-64"
+ />
+
+ )}
+
+
+ {/* Status */}
+
+
+ {getModeIndicator()}
+
+
+
+
+ {/* Messages area */}
+
+ {messages.length === 0 && status === 'idle' && (
+
+
+
Voice Chat
+
+ Click "Start Conversation" to begin talking with the AI
+
+
+ )}
+
+ {messages.map((message) => (
+
+
+ {message.role === 'assistant' ? (
+
+ AI
+
+ ) : (
+
+ U
+
+ )}
+
+ {message.parts.map((part, idx) => {
+ if (part.type === 'audio') {
+ return (
+
+ {part.transcript}
+
+ )
+ }
+ if (part.type === 'text') {
+ return (
+
+ {part.content}
+
+ )
+ }
+ return null
+ })}
+ {message.interrupted && (
+
+ (interrupted)
+
+ )}
+
+
+
+ ))}
+
+ {/* Pending transcripts */}
+ {pendingUserTranscript && (
+
+
+
+ U
+
+
{pendingUserTranscript}...
+
+
+ )}
+
+ {pendingAssistantTranscript && (
+
+
+
+ AI
+
+
+ {pendingAssistantTranscript}...
+
+
+
+ )}
+
+
+
+
+ {/* Error display */}
+ {error && (
+
+ Error: {error.message}
+
+ )}
+
+ {/* Audio visualization & controls */}
+
+ {/* Volume meters and waveforms */}
+ {status === 'connected' && (
+
+ {/* Input (Microphone) */}
+
+
+
+
+ {Math.round(inputLevel * 100)}%
+
+
+
+ {/* Output (Speaker) */}
+
+
+
+
+ {Math.round(outputLevel * 100)}%
+
+
+
+
+ {/* Debug info */}
+ {showDebug && (
+
+
+ Audio Debug
+ setShowDebug(false)}
+ className="text-xs text-gray-500 hover:text-gray-400"
+ >
+ Hide
+
+
+
+
+
+ inputLevel: {inputLevel.toFixed(4)}, outputLevel: {outputLevel.toFixed(4)}
+
+
+ )}
+
+ )}
+
+ {/* Controls */}
+
+ {status === 'idle' ? (
+
+
+ Start Conversation
+
+ ) : (
+ <>
+ {mode === 'speaking' && (
+
+ Interrupt
+
+ )}
+
+
+ End Conversation
+
+ >
+ )}
+
+
+
+
+ )
+}
+
+export const Route = createFileRoute('/realtime')({
+ component: RealtimePage,
+})
diff --git a/packages/typescript/ai-client/src/index.ts b/packages/typescript/ai-client/src/index.ts
index 5bc664c0a3..02a9ce3ff0 100644
--- a/packages/typescript/ai-client/src/index.ts
+++ b/packages/typescript/ai-client/src/index.ts
@@ -1,4 +1,5 @@
export { ChatClient } from './chat-client'
+export { RealtimeClient } from './realtime-client'
export type {
// Core message types (re-exported from @tanstack/ai via types.ts)
UIMessage,
@@ -19,6 +20,13 @@ export type {
ExtractToolOutput,
} from './tool-types'
export type { AnyClientTool } from '@tanstack/ai'
+export type {
+ RealtimeAdapter,
+ RealtimeConnection,
+ RealtimeClientOptions,
+ RealtimeClientState,
+ RealtimeStateChangeCallback,
+} from './realtime-types'
export {
fetchServerSentEvents,
fetchHttpStream,
diff --git a/packages/typescript/ai-client/src/realtime-client.ts b/packages/typescript/ai-client/src/realtime-client.ts
new file mode 100644
index 0000000000..0672fe23eb
--- /dev/null
+++ b/packages/typescript/ai-client/src/realtime-client.ts
@@ -0,0 +1,451 @@
+import type {
+ AudioVisualization,
+ RealtimeMessage,
+ RealtimeMode,
+ RealtimeStatus,
+ RealtimeToken,
+} from '@tanstack/ai'
+import type { AnyClientTool } from '@tanstack/ai'
+import type {
+ RealtimeClientOptions,
+ RealtimeClientState,
+ RealtimeConnection,
+ RealtimeStateChangeCallback,
+} from './realtime-types'
+
+// Token refresh buffer - refresh 1 minute before expiry
+const TOKEN_REFRESH_BUFFER_MS = 60_000
+
+/**
+ * Client for managing realtime voice conversations.
+ *
+ * Handles connection lifecycle, audio I/O, message state,
+ * and tool execution for realtime voice-to-voice AI interactions.
+ *
+ * @example
+ * ```typescript
+ * import { RealtimeClient } from '@tanstack/ai-client'
+ * import { openaiRealtime } from '@tanstack/ai-openai'
+ *
+ * const client = new RealtimeClient({
+ * getToken: () => fetch('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/api/realtime-token').then(r => r.json()),
+ * adapter: openaiRealtime(),
+ * tools: [myTool.client(handler)],
+ * onMessage: (msg) => console.log('Message:', msg),
+ * })
+ *
+ * await client.connect()
+ * ```
+ */
+let clientIdCounter = 0
+
+export class RealtimeClient {
+ private instanceId: number
+ private options: RealtimeClientOptions
+ private connection: RealtimeConnection | null = null
+ private token: RealtimeToken | null = null
+ private tokenRefreshTimeout: ReturnType | null = null
+ private clientTools: Map
+ private stateChangeCallbacks: Set = new Set()
+ private unsubscribers: Array<() => void> = []
+
+ private state: RealtimeClientState = {
+ status: 'idle',
+ mode: 'idle',
+ messages: [],
+ pendingUserTranscript: null,
+ pendingAssistantTranscript: null,
+ error: null,
+ }
+
+ constructor(options: RealtimeClientOptions) {
+ this.instanceId = ++clientIdCounter
+ console.log(`[RealtimeClient #${this.instanceId}] Created`)
+
+ this.options = {
+ autoPlayback: true,
+ autoCapture: true,
+ vadMode: 'server',
+ ...options,
+ }
+
+ // Build client tools map
+ this.clientTools = new Map()
+ if (options.tools) {
+ for (const tool of options.tools) {
+ this.clientTools.set(tool.name, tool)
+ }
+ }
+ }
+
+ // ============================================================================
+ // Connection Lifecycle
+ // ============================================================================
+
+ /**
+ * Connect to the realtime session.
+ * Fetches a token and establishes the connection.
+ */
+ async connect(): Promise {
+ if (this.state.status === 'connected') {
+ return
+ }
+
+ this.updateState({ status: 'connecting', error: null })
+
+ try {
+ // Fetch token from server
+ this.token = await this.options.getToken()
+
+ // Schedule token refresh
+ this.scheduleTokenRefresh()
+
+ // Connect via adapter
+ this.connection = await this.options.adapter.connect(this.token)
+ console.log(`[RealtimeClient #${this.instanceId}] Connection established:`, !!this.connection)
+
+ // Subscribe to connection events
+ this.subscribeToConnectionEvents()
+
+ // Start audio capture if configured
+ if (this.options.autoCapture) {
+ await this.connection.startAudioCapture()
+ }
+
+ this.updateState({ status: 'connected', mode: 'listening' })
+ this.options.onConnect?.()
+ } catch (error) {
+ const err = error instanceof Error ? error : new Error(String(error))
+ this.updateState({ status: 'error', error: err })
+ this.options.onError?.(err)
+ throw err
+ }
+ }
+
+ /**
+ * Disconnect from the realtime session.
+ */
+ async disconnect(): Promise {
+ if (this.tokenRefreshTimeout) {
+ clearTimeout(this.tokenRefreshTimeout)
+ this.tokenRefreshTimeout = null
+ }
+
+ // Unsubscribe from all events
+ for (const unsub of this.unsubscribers) {
+ unsub()
+ }
+ this.unsubscribers = []
+
+ if (this.connection) {
+ await this.connection.disconnect()
+ this.connection = null
+ }
+
+ this.token = null
+ this.updateState({
+ status: 'idle',
+ mode: 'idle',
+ pendingUserTranscript: null,
+ pendingAssistantTranscript: null,
+ })
+ this.options.onDisconnect?.()
+ }
+
+ // ============================================================================
+ // Voice Control
+ // ============================================================================
+
+ /**
+ * Start listening for voice input.
+ * Only needed when vadMode is 'manual'.
+ */
+ startListening(): void {
+ if (!this.connection || this.state.status !== 'connected') {
+ return
+ }
+ this.connection.startAudioCapture()
+ this.updateState({ mode: 'listening' })
+ }
+
+ /**
+ * Stop listening for voice input.
+ * Only needed when vadMode is 'manual'.
+ */
+ stopListening(): void {
+ if (!this.connection) {
+ return
+ }
+ this.connection.stopAudioCapture()
+ this.updateState({ mode: 'idle' })
+ }
+
+ /**
+ * Interrupt the current assistant response.
+ */
+ interrupt(): void {
+ if (!this.connection) {
+ return
+ }
+ this.connection.interrupt()
+ }
+
+ // ============================================================================
+ // Text Input
+ // ============================================================================
+
+ /**
+ * Send a text message instead of voice.
+ */
+ sendText(text: string): void {
+ if (!this.connection || this.state.status !== 'connected') {
+ return
+ }
+
+ // Add user message
+ const userMessage: RealtimeMessage = {
+ id: this.generateId(),
+ role: 'user',
+ timestamp: Date.now(),
+ parts: [{ type: 'text', content: text }],
+ }
+ this.addMessage(userMessage)
+
+ // Send to provider
+ this.connection.sendText(text)
+ }
+
+ // ============================================================================
+ // State Access
+ // ============================================================================
+
+ /** Get current connection status */
+ get status(): RealtimeStatus {
+ return this.state.status
+ }
+
+ /** Get current mode */
+ get mode(): RealtimeMode {
+ return this.state.mode
+ }
+
+ /** Get conversation messages */
+ get messages(): Array {
+ return this.state.messages
+ }
+
+ /** Get current error, if any */
+ get error(): Error | null {
+ return this.state.error
+ }
+
+ /** Get pending user transcript (while user is speaking) */
+ get pendingUserTranscript(): string | null {
+ return this.state.pendingUserTranscript
+ }
+
+ /** Get pending assistant transcript (while assistant is speaking) */
+ get pendingAssistantTranscript(): string | null {
+ return this.state.pendingAssistantTranscript
+ }
+
+ /** Get audio visualization data */
+ get audio(): AudioVisualization | null {
+ console.log(`[RealtimeClient #${this.instanceId}] audio getter, connection:`, !!this.connection)
+ return this.connection?.getAudioVisualization() ?? null
+ }
+
+ // ============================================================================
+ // State Subscription
+ // ============================================================================
+
+ /**
+ * Subscribe to state changes.
+ * @returns Unsubscribe function
+ */
+ onStateChange(callback: RealtimeStateChangeCallback): () => void {
+ this.stateChangeCallbacks.add(callback)
+ return () => {
+ this.stateChangeCallbacks.delete(callback)
+ }
+ }
+
+ // ============================================================================
+ // Cleanup
+ // ============================================================================
+
+ /**
+ * Clean up resources.
+ * Call this when disposing of the client.
+ */
+ destroy(): void {
+ this.disconnect()
+ this.stateChangeCallbacks.clear()
+ }
+
+ // ============================================================================
+ // Private Methods
+ // ============================================================================
+
+ private updateState(updates: Partial): void {
+ this.state = { ...this.state, ...updates }
+
+ // Notify callbacks
+ for (const callback of this.stateChangeCallbacks) {
+ callback(this.state)
+ }
+
+ // Notify specific callbacks
+ if ('status' in updates && updates.status !== undefined) {
+ this.options.onStatusChange?.(updates.status)
+ }
+ if ('mode' in updates && updates.mode !== undefined) {
+ this.options.onModeChange?.(updates.mode)
+ }
+ }
+
+ private addMessage(message: RealtimeMessage): void {
+ this.updateState({
+ messages: [...this.state.messages, message],
+ })
+ this.options.onMessage?.(message)
+ }
+
+ private scheduleTokenRefresh(): void {
+ if (!this.token) return
+
+ const timeUntilExpiry = this.token.expiresAt - Date.now()
+ const refreshIn = Math.max(0, timeUntilExpiry - TOKEN_REFRESH_BUFFER_MS)
+
+ this.tokenRefreshTimeout = setTimeout(() => {
+ this.refreshToken()
+ }, refreshIn)
+ }
+
+ private async refreshToken(): Promise {
+ try {
+ this.token = await this.options.getToken()
+ this.scheduleTokenRefresh()
+ // Note: Some providers may require reconnection with new token
+ // This is handled by the adapter implementation
+ } catch (error) {
+ const err = error instanceof Error ? error : new Error(String(error))
+ this.updateState({ error: err })
+ this.options.onError?.(err)
+ }
+ }
+
+ private subscribeToConnectionEvents(): void {
+ if (!this.connection) return
+
+ // Status changes
+ this.unsubscribers.push(
+ this.connection.on('status_change', ({ status }) => {
+ this.updateState({ status })
+ }),
+ )
+
+ // Mode changes
+ this.unsubscribers.push(
+ this.connection.on('mode_change', ({ mode }) => {
+ this.updateState({ mode })
+ }),
+ )
+
+ // Transcripts (streaming)
+ // User transcripts are added as messages when final (no separate message_complete for user input)
+ // Assistant transcripts are streamed, final message comes via message_complete
+ this.unsubscribers.push(
+ this.connection.on('transcript', ({ role, transcript, isFinal }) => {
+ if (role === 'user') {
+ this.updateState({
+ pendingUserTranscript: isFinal ? null : transcript,
+ })
+ // Add user message when transcript is finalized
+ if (isFinal && transcript) {
+ this.addMessage({
+ id: this.generateId(),
+ role: 'user',
+ timestamp: Date.now(),
+ parts: [{ type: 'audio', transcript, durationMs: 0 }],
+ })
+ }
+ } else {
+ // Assistant transcripts - just update pending, message_complete handles final
+ this.updateState({
+ pendingAssistantTranscript: isFinal ? null : transcript,
+ })
+ }
+ }),
+ )
+
+ // Tool calls
+ this.unsubscribers.push(
+ this.connection.on('tool_call', async ({ toolCallId, toolName, input }) => {
+ const tool = this.clientTools.get(toolName)
+ if (tool?.execute) {
+ try {
+ const output = await tool.execute(input)
+ this.connection?.sendToolResult(
+ toolCallId,
+ typeof output === 'string' ? output : JSON.stringify(output),
+ )
+ } catch (error) {
+ const errMsg =
+ error instanceof Error ? error.message : String(error)
+ this.connection?.sendToolResult(
+ toolCallId,
+ JSON.stringify({ error: errMsg }),
+ )
+ }
+ }
+ }),
+ )
+
+ // Message complete
+ this.unsubscribers.push(
+ this.connection.on('message_complete', ({ message }) => {
+ // Replace pending message with final version if needed
+ const existingIndex = this.state.messages.findIndex(
+ (m) => m.id === message.id,
+ )
+ if (existingIndex >= 0) {
+ const newMessages = [...this.state.messages]
+ newMessages[existingIndex] = message
+ this.updateState({ messages: newMessages })
+ } else {
+ this.addMessage(message)
+ }
+ }),
+ )
+
+ // Interruption
+ this.unsubscribers.push(
+ this.connection.on('interrupted', ({ messageId }) => {
+ if (messageId) {
+ const newMessages = this.state.messages.map((m) =>
+ m.id === messageId ? { ...m, interrupted: true } : m,
+ )
+ this.updateState({ messages: newMessages })
+ }
+ this.updateState({
+ mode: 'listening',
+ pendingAssistantTranscript: null,
+ })
+ this.options.onInterrupted?.()
+ }),
+ )
+
+ // Errors
+ this.unsubscribers.push(
+ this.connection.on('error', ({ error }) => {
+ this.updateState({ error })
+ this.options.onError?.(error)
+ }),
+ )
+ }
+
+ private generateId(): string {
+ return `msg-${Date.now()}-${Math.random().toString(36).substring(7)}`
+ }
+}
diff --git a/packages/typescript/ai-client/src/realtime-types.ts b/packages/typescript/ai-client/src/realtime-types.ts
new file mode 100644
index 0000000000..3393ee92c6
--- /dev/null
+++ b/packages/typescript/ai-client/src/realtime-types.ts
@@ -0,0 +1,142 @@
+import type {
+ AudioVisualization,
+ RealtimeEvent,
+ RealtimeEventHandler,
+ RealtimeMessage,
+ RealtimeMode,
+ RealtimeSessionConfig,
+ RealtimeStatus,
+ RealtimeToken,
+} from '@tanstack/ai'
+import type { AnyClientTool } from '@tanstack/ai'
+
+// ============================================================================
+// Adapter Interface
+// ============================================================================
+
+/**
+ * Adapter interface for connecting to realtime providers.
+ * Each provider (OpenAI, ElevenLabs, etc.) implements this interface.
+ */
+export interface RealtimeAdapter {
+ /** Provider identifier */
+ provider: string
+
+ /**
+ * Create a connection using the provided token
+ * @param token - The ephemeral token from the server
+ * @returns A connection instance
+ */
+ connect(token: RealtimeToken): Promise
+}
+
+/**
+ * Connection interface representing an active realtime session.
+ * Handles audio I/O, events, and session management.
+ */
+export interface RealtimeConnection {
+ // Lifecycle
+ /** Disconnect from the realtime session */
+ disconnect(): Promise
+
+ // Audio I/O
+ /** Start capturing audio from the microphone */
+ startAudioCapture(): Promise
+ /** Stop capturing audio */
+ stopAudioCapture(): void
+
+ // Text input
+ /** Send a text message (fallback for when voice isn't available) */
+ sendText(text: string): void
+
+ // Tool results
+ /** Send a tool execution result back to the provider */
+ sendToolResult(callId: string, result: string): void
+
+ // Session management
+ /** Update session configuration */
+ updateSession(config: Partial): void
+ /** Interrupt the current response */
+ interrupt(): void
+
+ // Events
+ /** Subscribe to connection events */
+ on(
+ event: E,
+ handler: RealtimeEventHandler,
+ ): () => void
+
+ // Audio visualization
+ /** Get audio visualization data */
+ getAudioVisualization(): AudioVisualization
+}
+
+// ============================================================================
+// Client Options
+// ============================================================================
+
+/**
+ * Options for the RealtimeClient
+ */
+export interface RealtimeClientOptions {
+ /**
+ * Function to fetch a realtime token from the server.
+ * Called on connect and when token needs refresh.
+ */
+ getToken: () => Promise
+
+ /**
+ * The realtime adapter to use (e.g., openaiRealtime())
+ */
+ adapter: RealtimeAdapter
+
+ /**
+ * Client-side tools with execution logic
+ */
+ tools?: ReadonlyArray
+
+ /**
+ * Auto-play assistant audio (default: true)
+ */
+ autoPlayback?: boolean
+
+ /**
+ * Request microphone access on connect (default: true)
+ */
+ autoCapture?: boolean
+
+ /**
+ * Voice activity detection mode (default: 'server')
+ */
+ vadMode?: 'server' | 'semantic' | 'manual'
+
+ // Callbacks
+ onStatusChange?: (status: RealtimeStatus) => void
+ onModeChange?: (mode: RealtimeMode) => void
+ onMessage?: (message: RealtimeMessage) => void
+ onError?: (error: Error) => void
+ onConnect?: () => void
+ onDisconnect?: () => void
+ onInterrupted?: () => void
+}
+
+// ============================================================================
+// Client State
+// ============================================================================
+
+/**
+ * Internal state of the RealtimeClient
+ */
+export interface RealtimeClientState {
+ status: RealtimeStatus
+ mode: RealtimeMode
+ messages: Array
+ pendingUserTranscript: string | null
+ pendingAssistantTranscript: string | null
+ error: Error | null
+}
+
+/**
+ * Callback type for state changes
+ */
+export type RealtimeStateChangeCallback = (state: RealtimeClientState) => void
diff --git a/packages/typescript/ai-elevenlabs/README.md b/packages/typescript/ai-elevenlabs/README.md
new file mode 100644
index 0000000000..6f85bb8ede
--- /dev/null
+++ b/packages/typescript/ai-elevenlabs/README.md
@@ -0,0 +1,76 @@
+# @tanstack/ai-elevenlabs
+
+ElevenLabs adapter for TanStack AI realtime voice conversations.
+
+## Installation
+
+```bash
+npm install @tanstack/ai-elevenlabs @tanstack/ai @tanstack/ai-client
+```
+
+## Usage
+
+### Server-Side Token Generation
+
+```typescript
+import { realtimeToken } from '@tanstack/ai'
+import { elevenlabsRealtimeToken } from '@tanstack/ai-elevenlabs'
+
+// Generate a signed URL for client use
+const token = await realtimeToken({
+ adapter: elevenlabsRealtimeToken({
+ agentId: 'your-agent-id',
+ }),
+})
+```
+
+### Client-Side Usage
+
+```typescript
+import { RealtimeClient } from '@tanstack/ai-client'
+import { elevenlabsRealtime } from '@tanstack/ai-elevenlabs'
+
+const client = new RealtimeClient({
+ getToken: () => fetch('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/api/realtime-token').then(r => r.json()),
+ adapter: elevenlabsRealtime(),
+})
+
+await client.connect()
+```
+
+### With React
+
+```typescript
+import { useRealtimeChat } from '@tanstack/ai-react'
+import { elevenlabsRealtime } from '@tanstack/ai-elevenlabs'
+
+function VoiceChat() {
+ const { status, mode, messages, connect, disconnect } = useRealtimeChat({
+ getToken: () => fetch('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/api/realtime-token').then(r => r.json()),
+ adapter: elevenlabsRealtime(),
+ })
+
+ return (
+
+
Status: {status}
+
Mode: {mode}
+
+ {status === 'idle' ? 'Start' : 'Stop'}
+
+
+ )
+}
+```
+
+## Environment Variables
+
+Set `ELEVENLABS_API_KEY` in your environment for server-side token generation.
+
+## Requirements
+
+- ElevenLabs account with Conversational AI agent configured
+- Agent ID from ElevenLabs dashboard
+
+## License
+
+MIT
diff --git a/packages/typescript/ai-elevenlabs/package.json b/packages/typescript/ai-elevenlabs/package.json
new file mode 100644
index 0000000000..0edafe92a4
--- /dev/null
+++ b/packages/typescript/ai-elevenlabs/package.json
@@ -0,0 +1,55 @@
+{
+ "name": "@tanstack/ai-elevenlabs",
+ "version": "0.0.1",
+ "description": "ElevenLabs adapter for TanStack AI realtime voice",
+ "author": "",
+ "license": "MIT",
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/TanStack/ai.git",
+ "directory": "packages/typescript/ai-elevenlabs"
+ },
+ "keywords": [
+ "ai",
+ "elevenlabs",
+ "voice",
+ "realtime",
+ "tanstack",
+ "adapter"
+ ],
+ "type": "module",
+ "module": "./dist/esm/index.js",
+ "types": "./dist/esm/index.d.ts",
+ "exports": {
+ ".": {
+ "types": "./dist/esm/index.d.ts",
+ "import": "./dist/esm/index.js"
+ }
+ },
+ "files": [
+ "dist",
+ "src"
+ ],
+ "scripts": {
+ "build": "vite build",
+ "clean": "premove ./build ./dist",
+ "lint:fix": "eslint ./src --fix",
+ "test:build": "publint --strict",
+ "test:eslint": "eslint ./src",
+ "test:lib": "vitest",
+ "test:lib:dev": "pnpm test:lib --watch",
+ "test:types": "tsc"
+ },
+ "dependencies": {
+ "@11labs/client": "^0.2.0"
+ },
+ "peerDependencies": {
+ "@tanstack/ai": "workspace:^",
+ "@tanstack/ai-client": "workspace:^"
+ },
+ "devDependencies": {
+ "@tanstack/ai": "workspace:*",
+ "@tanstack/ai-client": "workspace:*",
+ "@vitest/coverage-v8": "4.0.14"
+ }
+}
diff --git a/packages/typescript/ai-elevenlabs/src/index.ts b/packages/typescript/ai-elevenlabs/src/index.ts
new file mode 100644
index 0000000000..14702a1daa
--- /dev/null
+++ b/packages/typescript/ai-elevenlabs/src/index.ts
@@ -0,0 +1,16 @@
+// ============================================================================
+// ElevenLabs Realtime (Voice) Adapters
+// ============================================================================
+
+export {
+ elevenlabsRealtimeToken,
+ elevenlabsRealtime,
+} from './realtime/index'
+
+export type {
+ ElevenLabsRealtimeTokenOptions,
+ ElevenLabsRealtimeOptions,
+ ElevenLabsConversationMode,
+ ElevenLabsVADConfig,
+ ElevenLabsClientTool,
+} from './realtime/index'
diff --git a/packages/typescript/ai-elevenlabs/src/realtime/adapter.ts b/packages/typescript/ai-elevenlabs/src/realtime/adapter.ts
new file mode 100644
index 0000000000..cb193485ca
--- /dev/null
+++ b/packages/typescript/ai-elevenlabs/src/realtime/adapter.ts
@@ -0,0 +1,251 @@
+import { Conversation } from '@11labs/client'
+import type {
+ AudioVisualization,
+ RealtimeEvent,
+ RealtimeEventHandler,
+ RealtimeMessage,
+ RealtimeMode,
+ RealtimeSessionConfig,
+ RealtimeStatus,
+ RealtimeToken,
+} from '@tanstack/ai'
+import type { RealtimeAdapter, RealtimeConnection } from '@tanstack/ai-client'
+import type { ElevenLabsRealtimeOptions } from './types'
+
+/**
+ * Creates an ElevenLabs realtime adapter for client-side use.
+ *
+ * Wraps the @11labs/client SDK for voice conversations.
+ *
+ * @param options - Optional configuration
+ * @returns A RealtimeAdapter for use with RealtimeClient
+ *
+ * @example
+ * ```typescript
+ * import { RealtimeClient } from '@tanstack/ai-client'
+ * import { elevenlabsRealtime } from '@tanstack/ai-elevenlabs'
+ *
+ * const client = new RealtimeClient({
+ * getToken: () => fetch('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/api/realtime-token').then(r => r.json()),
+ * adapter: elevenlabsRealtime(),
+ * })
+ * ```
+ */
+export function elevenlabsRealtime(
+ options: ElevenLabsRealtimeOptions = {},
+): RealtimeAdapter {
+ return {
+ provider: 'elevenlabs',
+
+ async connect(token: RealtimeToken): Promise {
+ return createElevenLabsConnection(token, options)
+ },
+ }
+}
+
+/**
+ * Creates a connection to ElevenLabs conversational AI
+ */
+async function createElevenLabsConnection(
+ token: RealtimeToken,
+ _options: ElevenLabsRealtimeOptions,
+): Promise {
+ const eventHandlers = new Map>>()
+ let conversation: Awaited> | null = null
+ let messageIdCounter = 0
+
+ // Empty arrays for when visualization isn't available
+ const emptyFrequencyData = new Uint8Array(128)
+ const emptyTimeDomainData = new Uint8Array(128).fill(128)
+
+ // Helper to emit events
+ function emit(
+ event: E,
+ payload: Parameters>[0],
+ ) {
+ const handlers = eventHandlers.get(event)
+ if (handlers) {
+ for (const handler of handlers) {
+ handler(payload)
+ }
+ }
+ }
+
+ function generateMessageId(): string {
+ return `el-msg-${Date.now()}-${++messageIdCounter}`
+ }
+
+ // Start the conversation session
+ conversation = await Conversation.startSession({
+ signedUrl: token.token,
+
+ onConnect: () => {
+ emit('status_change', { status: 'connected' as RealtimeStatus })
+ emit('mode_change', { mode: 'listening' })
+ },
+
+ onDisconnect: () => {
+ emit('status_change', { status: 'idle' as RealtimeStatus })
+ emit('mode_change', { mode: 'idle' })
+ },
+
+ onModeChange: ({ mode }) => {
+ const mappedMode: RealtimeMode =
+ mode === 'speaking' ? 'speaking' : 'listening'
+ emit('mode_change', { mode: mappedMode })
+ },
+
+ onMessage: ({ message, source }) => {
+ const role = source === 'user' ? 'user' : 'assistant'
+
+ // Emit transcript update
+ emit('transcript', {
+ role,
+ transcript: message,
+ isFinal: true,
+ })
+
+ // Create and emit message
+ const realtimeMessage: RealtimeMessage = {
+ id: generateMessageId(),
+ role,
+ timestamp: Date.now(),
+ parts: [{ type: 'audio', transcript: message }],
+ }
+ emit('message_complete', { message: realtimeMessage })
+ },
+
+ onError: (error: string | Error) => {
+ emit('error', {
+ error: new Error(
+ typeof error === 'string' ? error : error.message || 'Unknown error',
+ ),
+ })
+ },
+ })
+
+ // Connection implementation
+ const connection: RealtimeConnection = {
+ async disconnect() {
+ if (conversation) {
+ await conversation.endSession()
+ conversation = null
+ }
+ emit('status_change', { status: 'idle' as RealtimeStatus })
+ },
+
+ async startAudioCapture() {
+ // ElevenLabs SDK handles audio capture automatically
+ // This is called when the session starts
+ emit('mode_change', { mode: 'listening' })
+ },
+
+ stopAudioCapture() {
+ // ElevenLabs SDK handles this
+ emit('mode_change', { mode: 'idle' })
+ },
+
+ sendText(text: string) {
+ // ElevenLabs doesn't support direct text input in the same way
+ // The SDK is voice-first. Log a warning.
+ console.warn(
+ 'ElevenLabs realtime adapter does not support sendText. Use voice input.',
+ )
+ },
+
+ sendToolResult(callId: string, result: string) {
+ // ElevenLabs handles client tools differently - they're registered at session start
+ console.warn(
+ 'ElevenLabs tool results are handled via clientTools option during session creation.',
+ )
+ },
+
+ updateSession(_config: Partial) {
+ // ElevenLabs session config is set at creation time
+ console.warn(
+ 'ElevenLabs does not support runtime session updates. Configure at connection time.',
+ )
+ },
+
+ interrupt() {
+ // ElevenLabs handles interruption automatically via barge-in
+ // No explicit API to call
+ emit('mode_change', { mode: 'listening' })
+ emit('interrupted', {})
+ },
+
+ on(
+ event: E,
+ handler: RealtimeEventHandler,
+ ): () => void {
+ if (!eventHandlers.has(event)) {
+ eventHandlers.set(event, new Set())
+ }
+ eventHandlers.get(event)!.add(handler)
+
+ return () => {
+ eventHandlers.get(event)?.delete(handler)
+ }
+ },
+
+ getAudioVisualization(): AudioVisualization {
+ return {
+ get inputLevel() {
+ if (!conversation) return 0
+ try {
+ return conversation.getInputVolume()
+ } catch {
+ return 0
+ }
+ },
+
+ get outputLevel() {
+ if (!conversation) return 0
+ try {
+ return conversation.getOutputVolume()
+ } catch {
+ return 0
+ }
+ },
+
+ getInputFrequencyData() {
+ if (!conversation) return emptyFrequencyData
+ try {
+ return conversation.getInputByteFrequencyData()
+ } catch {
+ return emptyFrequencyData
+ }
+ },
+
+ getOutputFrequencyData() {
+ if (!conversation) return emptyFrequencyData
+ try {
+ return conversation.getOutputByteFrequencyData()
+ } catch {
+ return emptyFrequencyData
+ }
+ },
+
+ getInputTimeDomainData() {
+ // ElevenLabs SDK doesn't expose time domain data
+ return emptyTimeDomainData
+ },
+
+ getOutputTimeDomainData() {
+ // ElevenLabs SDK doesn't expose time domain data
+ return emptyTimeDomainData
+ },
+
+ get inputSampleRate() {
+ return 16000
+ },
+
+ get outputSampleRate() {
+ return 16000
+ },
+ }
+ },
+ }
+
+ return connection
+}
diff --git a/packages/typescript/ai-elevenlabs/src/realtime/index.ts b/packages/typescript/ai-elevenlabs/src/realtime/index.ts
new file mode 100644
index 0000000000..db176897e4
--- /dev/null
+++ b/packages/typescript/ai-elevenlabs/src/realtime/index.ts
@@ -0,0 +1,14 @@
+// Token adapter for server-side use
+export { elevenlabsRealtimeToken } from './token'
+
+// Client adapter for browser use
+export { elevenlabsRealtime } from './adapter'
+
+// Types
+export type {
+ ElevenLabsRealtimeTokenOptions,
+ ElevenLabsRealtimeOptions,
+ ElevenLabsConversationMode,
+ ElevenLabsVADConfig,
+ ElevenLabsClientTool,
+} from './types'
diff --git a/packages/typescript/ai-elevenlabs/src/realtime/token.ts b/packages/typescript/ai-elevenlabs/src/realtime/token.ts
new file mode 100644
index 0000000000..99989b06b7
--- /dev/null
+++ b/packages/typescript/ai-elevenlabs/src/realtime/token.ts
@@ -0,0 +1,103 @@
+import type { RealtimeToken, RealtimeTokenAdapter } from '@tanstack/ai'
+import type { ElevenLabsRealtimeTokenOptions } from './types'
+
+const ELEVENLABS_API_URL = 'https://api.elevenlabs.io/v1'
+
+/**
+ * Get ElevenLabs API key from environment
+ */
+function getElevenLabsApiKey(): string {
+ // Check process.env (Node.js)
+ if (typeof process !== 'undefined' && process.env?.ELEVENLABS_API_KEY) {
+ return process.env.ELEVENLABS_API_KEY
+ }
+
+ // Check window.env (Browser with injected env)
+ if (
+ typeof window !== 'undefined' &&
+ (window as unknown as { env?: { ELEVENLABS_API_KEY?: string } }).env
+ ?.ELEVENLABS_API_KEY
+ ) {
+ return (window as unknown as { env: { ELEVENLABS_API_KEY: string } }).env
+ .ELEVENLABS_API_KEY
+ }
+
+ throw new Error(
+ 'ELEVENLABS_API_KEY not found in environment variables. ' +
+ 'Please set ELEVENLABS_API_KEY in your environment.',
+ )
+}
+
+/**
+ * Creates an ElevenLabs realtime token adapter.
+ *
+ * This adapter generates signed URLs for client-side connections.
+ * The signed URL is valid for 30 minutes.
+ *
+ * @param options - Configuration options including agentId
+ * @returns A RealtimeTokenAdapter for use with realtimeToken()
+ *
+ * @example
+ * ```typescript
+ * import { realtimeToken } from '@tanstack/ai'
+ * import { elevenlabsRealtimeToken } from '@tanstack/ai-elevenlabs'
+ *
+ * const token = await realtimeToken({
+ * adapter: elevenlabsRealtimeToken({
+ * agentId: 'your-agent-id',
+ * }),
+ * })
+ * ```
+ */
+export function elevenlabsRealtimeToken(
+ options: ElevenLabsRealtimeTokenOptions,
+): RealtimeTokenAdapter {
+ const apiKey = getElevenLabsApiKey()
+
+ return {
+ provider: 'elevenlabs',
+
+ async generateToken(): Promise {
+ const { agentId, overrides } = options
+
+ // Get signed URL from ElevenLabs
+ const response = await fetch(
+ `${ELEVENLABS_API_URL}/convai/conversation/get_signed_url?agent_id=${agentId}`,
+ {
+ method: 'GET',
+ headers: {
+ 'xi-api-key': apiKey,
+ },
+ },
+ )
+
+ if (!response.ok) {
+ const errorText = await response.text()
+ throw new Error(
+ `ElevenLabs signed URL request failed: ${response.status} ${errorText}`,
+ )
+ }
+
+ const data = await response.json()
+ const signedUrl = data.signed_url as string
+
+ // Signed URLs are valid for 30 minutes
+ const expiresAt = Date.now() + 30 * 60 * 1000
+
+ return {
+ provider: 'elevenlabs',
+ token: signedUrl,
+ expiresAt,
+ config: {
+ voice: overrides?.voiceId,
+ instructions: overrides?.systemPrompt,
+ providerOptions: {
+ agentId,
+ firstMessage: overrides?.firstMessage,
+ language: overrides?.language,
+ },
+ },
+ }
+ },
+ }
+}
diff --git a/packages/typescript/ai-elevenlabs/src/realtime/types.ts b/packages/typescript/ai-elevenlabs/src/realtime/types.ts
new file mode 100644
index 0000000000..ff2166f088
--- /dev/null
+++ b/packages/typescript/ai-elevenlabs/src/realtime/types.ts
@@ -0,0 +1,62 @@
+/**
+ * Options for the ElevenLabs realtime token adapter
+ */
+export interface ElevenLabsRealtimeTokenOptions {
+ /** Agent ID configured in ElevenLabs dashboard */
+ agentId: string
+ /** Optional override values for the agent */
+ overrides?: {
+ /** Custom voice ID to use */
+ voiceId?: string
+ /** Custom system prompt */
+ systemPrompt?: string
+ /** First message the agent should speak */
+ firstMessage?: string
+ /** Language code (e.g., 'en') */
+ language?: string
+ }
+}
+
+/**
+ * Options for the ElevenLabs realtime client adapter
+ */
+export interface ElevenLabsRealtimeOptions {
+ /** Connection mode (default: auto-detect) */
+ connectionMode?: 'websocket' | 'webrtc'
+ /** Enable debug logging */
+ debug?: boolean
+}
+
+/**
+ * ElevenLabs conversation mode
+ */
+export type ElevenLabsConversationMode = 'speaking' | 'listening'
+
+/**
+ * ElevenLabs voice activity detection configuration
+ */
+export interface ElevenLabsVADConfig {
+ /** VAD threshold (0.1-0.9) */
+ vadThreshold?: number
+ /** Silence threshold in seconds (0.3-3.0) */
+ vadSilenceThresholdSecs?: number
+ /** Minimum speech duration in ms */
+ minSpeechDurationMs?: number
+ /** Minimum silence duration in ms */
+ minSilenceDurationMs?: number
+}
+
+/**
+ * Client tool definition for ElevenLabs
+ */
+export interface ElevenLabsClientTool {
+ /** Tool handler function */
+ handler: (params: TParams) => Promise | TResult
+}
+
+/**
+ * ElevenLabs signed URL response
+ */
+export interface ElevenLabsSignedUrlResponse {
+ signed_url: string
+}
diff --git a/packages/typescript/ai-elevenlabs/tsconfig.json b/packages/typescript/ai-elevenlabs/tsconfig.json
new file mode 100644
index 0000000000..e5e8727417
--- /dev/null
+++ b/packages/typescript/ai-elevenlabs/tsconfig.json
@@ -0,0 +1,8 @@
+{
+ "extends": "../../../tsconfig.json",
+ "compilerOptions": {
+ "outDir": "dist"
+ },
+ "include": ["vite.config.ts", "./src"],
+ "exclude": ["node_modules", "dist", "**/*.config.ts"]
+}
diff --git a/packages/typescript/ai-elevenlabs/vite.config.ts b/packages/typescript/ai-elevenlabs/vite.config.ts
new file mode 100644
index 0000000000..11f5b20b70
--- /dev/null
+++ b/packages/typescript/ai-elevenlabs/vite.config.ts
@@ -0,0 +1,37 @@
+import { defineConfig, mergeConfig } from 'vitest/config'
+import { tanstackViteConfig } from '@tanstack/vite-config'
+import packageJson from './package.json'
+
+const config = defineConfig({
+ test: {
+ name: packageJson.name,
+ dir: './',
+ watch: false,
+
+ globals: true,
+ environment: 'node',
+ include: ['tests/**/*.test.ts'],
+ coverage: {
+ provider: 'v8',
+ reporter: ['text', 'json', 'html', 'lcov'],
+ exclude: [
+ 'node_modules/',
+ 'dist/',
+ 'tests/',
+ '**/*.test.ts',
+ '**/*.config.ts',
+ '**/types.ts',
+ ],
+ include: ['src/**/*.ts'],
+ },
+ },
+})
+
+export default mergeConfig(
+ config,
+ tanstackViteConfig({
+ entry: ['./src/index.ts'],
+ srcDir: './src',
+ cjs: false,
+ }),
+)
diff --git a/packages/typescript/ai-openai/package.json b/packages/typescript/ai-openai/package.json
index 60f3d1abe1..2483cb13d1 100644
--- a/packages/typescript/ai-openai/package.json
+++ b/packages/typescript/ai-openai/package.json
@@ -44,10 +44,12 @@
},
"peerDependencies": {
"@tanstack/ai": "workspace:^",
+ "@tanstack/ai-client": "workspace:^",
"zod": "^4.0.0"
},
"devDependencies": {
"@tanstack/ai": "workspace:*",
+ "@tanstack/ai-client": "workspace:*",
"@vitest/coverage-v8": "4.0.14",
"vite": "^7.2.7",
"zod": "^4.2.0"
diff --git a/packages/typescript/ai-openai/src/index.ts b/packages/typescript/ai-openai/src/index.ts
index cf2759f221..adfc0254e1 100644
--- a/packages/typescript/ai-openai/src/index.ts
+++ b/packages/typescript/ai-openai/src/index.ts
@@ -94,3 +94,22 @@ export type {
OpenAIDocumentMetadata,
OpenAIMessageMetadataByModality,
} from './message-types'
+
+// ============================================================================
+// Realtime (Voice) Adapters
+// ============================================================================
+
+export {
+ openaiRealtimeToken,
+ openaiRealtime,
+} from './realtime/index'
+
+export type {
+ OpenAIRealtimeVoice,
+ OpenAIRealtimeModel,
+ OpenAIRealtimeTokenOptions,
+ OpenAIRealtimeOptions,
+ OpenAITurnDetection,
+ OpenAISemanticVADConfig,
+ OpenAIServerVADConfig,
+} from './realtime/index'
diff --git a/packages/typescript/ai-openai/src/realtime/adapter.ts b/packages/typescript/ai-openai/src/realtime/adapter.ts
new file mode 100644
index 0000000000..51745a26cd
--- /dev/null
+++ b/packages/typescript/ai-openai/src/realtime/adapter.ts
@@ -0,0 +1,585 @@
+import type {
+ AudioVisualization,
+ RealtimeEvent,
+ RealtimeEventHandler,
+ RealtimeMessage,
+ RealtimeMode,
+ RealtimeSessionConfig,
+ RealtimeStatus,
+ RealtimeToken,
+} from '@tanstack/ai'
+import type {
+ RealtimeAdapter,
+ RealtimeConnection,
+} from '@tanstack/ai-client'
+import type { OpenAIRealtimeOptions } from './types'
+
+const OPENAI_REALTIME_URL = 'https://api.openai.com/v1/realtime'
+
+/**
+ * Creates an OpenAI realtime adapter for client-side use.
+ *
+ * Uses WebRTC for browser connections (default) or WebSocket for Node.js.
+ *
+ * @param options - Optional configuration
+ * @returns A RealtimeAdapter for use with RealtimeClient
+ *
+ * @example
+ * ```typescript
+ * import { RealtimeClient } from '@tanstack/ai-client'
+ * import { openaiRealtime } from '@tanstack/ai-openai'
+ *
+ * const client = new RealtimeClient({
+ * getToken: () => fetch('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/api/realtime-token').then(r => r.json()),
+ * adapter: openaiRealtime(),
+ * })
+ * ```
+ */
+export function openaiRealtime(
+ options: OpenAIRealtimeOptions = {},
+): RealtimeAdapter {
+ const connectionMode = options.connectionMode ?? 'webrtc'
+
+ return {
+ provider: 'openai',
+
+ async connect(token: RealtimeToken): Promise {
+ if (connectionMode === 'webrtc') {
+ return createWebRTCConnection(token)
+ }
+ throw new Error('WebSocket connection mode not yet implemented')
+ },
+ }
+}
+
+/**
+ * Creates a WebRTC connection to OpenAI's realtime API
+ */
+async function createWebRTCConnection(
+ token: RealtimeToken,
+): Promise {
+ const model = token.config.model ?? 'gpt-4o-realtime-preview'
+ const eventHandlers = new Map>>()
+
+ // WebRTC peer connection
+ const pc = new RTCPeerConnection()
+
+ // Audio context for visualization
+ let audioContext: AudioContext | null = null
+ let inputAnalyser: AnalyserNode | null = null
+ let outputAnalyser: AnalyserNode | null = null
+ let inputSource: MediaStreamAudioSourceNode | null = null
+ let outputSource: MediaStreamAudioSourceNode | null = null
+ let localStream: MediaStream | null = null
+
+ // Audio element for playback (more reliable than AudioContext.destination)
+ let audioElement: HTMLAudioElement | null = null
+
+ // Data channel for events
+ let dataChannel: RTCDataChannel | null = null
+
+ // Current state
+ let currentMode: RealtimeMode = 'idle'
+ let currentMessageId: string | null = null
+
+ // Empty arrays for when visualization isn't available
+ // frequencyBinCount = fftSize / 2 = 1024
+ const emptyFrequencyData = new Uint8Array(1024)
+ const emptyTimeDomainData = new Uint8Array(2048).fill(128) // 128 is silence
+
+ // Helper to emit events (defined early so it can be used during setup)
+ function emit(
+ event: E,
+ payload: Parameters>[0],
+ ) {
+ const handlers = eventHandlers.get(event)
+ if (handlers) {
+ for (const handler of handlers) {
+ handler(payload)
+ }
+ }
+ }
+
+ // Set up data channel for bidirectional communication
+ dataChannel = pc.createDataChannel('oai-events')
+
+ dataChannel.onopen = () => {
+ emit('status_change', { status: 'connected' as RealtimeStatus })
+ }
+
+ dataChannel.onmessage = (event) => {
+ try {
+ const message = JSON.parse(event.data)
+ handleServerEvent(message)
+ } catch (e) {
+ console.error('Failed to parse realtime event:', e)
+ }
+ }
+
+ dataChannel.onerror = (error) => {
+ emit('error', { error: new Error(`Data channel error: ${error}`) })
+ }
+
+ // Handle incoming audio track
+ pc.ontrack = (event) => {
+ console.log('[Realtime] ontrack event:', event.track.kind, event.streams[0])
+ if (event.track.kind === 'audio' && event.streams[0]) {
+ setupOutputAudioAnalysis(event.streams[0])
+ console.log('[Realtime] Output analyser created:', outputAnalyser)
+ }
+ }
+
+ // IMPORTANT: Request microphone access and add audio track BEFORE creating offer
+ // OpenAI's Realtime API requires an audio track in the SDP offer
+ try {
+ localStream = await navigator.mediaDevices.getUserMedia({
+ audio: {
+ echoCancellation: true,
+ noiseSuppression: true,
+ sampleRate: 24000,
+ },
+ })
+
+ // Add audio track to peer connection
+ for (const track of localStream.getAudioTracks()) {
+ pc.addTrack(track, localStream)
+ }
+ } catch (error) {
+ throw new Error(
+ `Microphone access required for realtime voice: ${error instanceof Error ? error.message : error}`,
+ )
+ }
+
+ // Create and set local description (now includes audio track)
+ const offer = await pc.createOffer()
+ await pc.setLocalDescription(offer)
+
+ // Send SDP to OpenAI and get answer
+ const sdpResponse = await fetch(`${OPENAI_REALTIME_URL}?model=${model}`, {
+ method: 'POST',
+ headers: {
+ Authorization: `Bearer ${token.token}`,
+ 'Content-Type': 'application/sdp',
+ },
+ body: offer.sdp,
+ })
+
+ if (!sdpResponse.ok) {
+ const errorText = await sdpResponse.text()
+ throw new Error(
+ `Failed to establish WebRTC connection: ${sdpResponse.status} - ${errorText}`,
+ )
+ }
+
+ const answerSdp = await sdpResponse.text()
+ await pc.setRemoteDescription({ type: 'answer', sdp: answerSdp })
+
+ // Set up input audio analysis now that we have the stream
+ console.log('[Realtime] Setting up input audio analysis, localStream:', localStream)
+ setupInputAudioAnalysis(localStream)
+ console.log('[Realtime] Input analyser created:', inputAnalyser)
+
+ // Handle server events
+ function handleServerEvent(event: Record) {
+ const type = event.type as string
+
+ switch (type) {
+ case 'session.created':
+ case 'session.updated':
+ // Session ready
+ break
+
+ case 'input_audio_buffer.speech_started':
+ currentMode = 'listening'
+ emit('mode_change', { mode: 'listening' })
+ break
+
+ case 'input_audio_buffer.speech_stopped':
+ currentMode = 'thinking'
+ emit('mode_change', { mode: 'thinking' })
+ break
+
+ case 'input_audio_buffer.committed':
+ // Audio buffer committed for processing
+ break
+
+ case 'conversation.item.input_audio_transcription.completed': {
+ const transcript = event.transcript as string
+ emit('transcript', { role: 'user', transcript, isFinal: true })
+ break
+ }
+
+ case 'response.created':
+ currentMode = 'thinking'
+ emit('mode_change', { mode: 'thinking' })
+ break
+
+ case 'response.output_item.added': {
+ const item = event.item as Record
+ if (item.type === 'message') {
+ currentMessageId = item.id as string
+ }
+ break
+ }
+
+ case 'response.audio_transcript.delta': {
+ const delta = event.delta as string
+ emit('transcript', { role: 'assistant', transcript: delta, isFinal: false })
+ break
+ }
+
+ case 'response.audio_transcript.done': {
+ const transcript = event.transcript as string
+ emit('transcript', { role: 'assistant', transcript, isFinal: true })
+ break
+ }
+
+ case 'response.audio.delta':
+ if (currentMode !== 'speaking') {
+ currentMode = 'speaking'
+ emit('mode_change', { mode: 'speaking' })
+ }
+ break
+
+ case 'response.audio.done':
+ break
+
+ case 'response.function_call_arguments.done': {
+ const callId = event.call_id as string
+ const name = event.name as string
+ const args = event.arguments as string
+ try {
+ const input = JSON.parse(args)
+ emit('tool_call', { toolCallId: callId, toolName: name, input })
+ } catch {
+ emit('tool_call', { toolCallId: callId, toolName: name, input: args })
+ }
+ break
+ }
+
+ case 'response.done': {
+ currentMode = 'listening'
+ emit('mode_change', { mode: 'listening' })
+
+ // Emit message complete if we have a current message
+ if (currentMessageId) {
+ const response = event.response as Record
+ const output = response.output as Array>
+
+ const message: RealtimeMessage = {
+ id: currentMessageId,
+ role: 'assistant',
+ timestamp: Date.now(),
+ parts: [],
+ }
+
+ // Extract content from output items
+ for (const item of output || []) {
+ if (item.type === 'message' && item.content) {
+ const content = item.content as Array>
+ for (const part of content) {
+ if (part.type === 'audio' && part.transcript) {
+ message.parts.push({
+ type: 'audio',
+ transcript: part.transcript as string,
+ })
+ } else if (part.type === 'text' && part.text) {
+ message.parts.push({
+ type: 'text',
+ content: part.text as string,
+ })
+ }
+ }
+ }
+ }
+
+ emit('message_complete', { message })
+ currentMessageId = null
+ }
+ break
+ }
+
+ case 'conversation.item.truncated':
+ emit('interrupted', { messageId: currentMessageId ?? undefined })
+ break
+
+ case 'error': {
+ const error = event.error as Record
+ emit('error', {
+ error: new Error((error.message as string) || 'Unknown error'),
+ })
+ break
+ }
+ }
+ }
+
+ // Set up audio analysis for output
+ function setupOutputAudioAnalysis(stream: MediaStream) {
+ // Create audio element for playback - this is the standard way to play WebRTC audio
+ audioElement = new Audio()
+ audioElement.srcObject = stream
+ audioElement.autoplay = true
+ // Some browsers require this for autoplay
+ audioElement.play().catch((e) => {
+ console.warn('Audio autoplay failed:', e)
+ })
+
+ // Set up AudioContext for visualization only (not playback)
+ if (!audioContext) {
+ audioContext = new AudioContext()
+ }
+
+ // Resume AudioContext if suspended (browsers require user interaction)
+ if (audioContext.state === 'suspended') {
+ audioContext.resume().catch(() => {
+ // Ignore - visualization just won't work
+ })
+ }
+
+ outputAnalyser = audioContext.createAnalyser()
+ outputAnalyser.fftSize = 2048 // Larger size for more accurate level detection
+ outputAnalyser.smoothingTimeConstant = 0.3
+
+ outputSource = audioContext.createMediaStreamSource(stream)
+ outputSource.connect(outputAnalyser)
+ // Don't connect to destination - the Audio element handles playback
+ }
+
+ // Set up audio analysis for input
+ function setupInputAudioAnalysis(stream: MediaStream) {
+ if (!audioContext) {
+ audioContext = new AudioContext()
+ }
+
+ // Resume AudioContext if suspended (browsers require user interaction)
+ if (audioContext.state === 'suspended') {
+ audioContext.resume().catch(() => {
+ // Ignore - visualization just won't work
+ })
+ }
+
+ inputAnalyser = audioContext.createAnalyser()
+ inputAnalyser.fftSize = 2048 // Larger size for more accurate level detection
+ inputAnalyser.smoothingTimeConstant = 0.3
+
+ inputSource = audioContext.createMediaStreamSource(stream)
+ inputSource.connect(inputAnalyser)
+ }
+
+ // Send event to server
+ function sendEvent(event: Record) {
+ if (dataChannel?.readyState === 'open') {
+ dataChannel.send(JSON.stringify(event))
+ }
+ }
+
+ // Connection implementation
+ const connection: RealtimeConnection = {
+ async disconnect() {
+ if (localStream) {
+ for (const track of localStream.getTracks()) {
+ track.stop()
+ }
+ localStream = null
+ }
+
+ if (audioElement) {
+ audioElement.pause()
+ audioElement.srcObject = null
+ audioElement = null
+ }
+
+ if (dataChannel) {
+ dataChannel.close()
+ dataChannel = null
+ }
+
+ pc.close()
+
+ if (audioContext) {
+ await audioContext.close()
+ audioContext = null
+ }
+
+ emit('status_change', { status: 'idle' as RealtimeStatus })
+ },
+
+ async startAudioCapture() {
+ // Audio capture is established during connection setup
+ // This method enables the tracks and signals listening mode
+ if (localStream) {
+ for (const track of localStream.getAudioTracks()) {
+ track.enabled = true
+ }
+ }
+ currentMode = 'listening'
+ emit('mode_change', { mode: 'listening' })
+ },
+
+ stopAudioCapture() {
+ // Disable tracks rather than stopping them to allow re-enabling
+ if (localStream) {
+ for (const track of localStream.getAudioTracks()) {
+ track.enabled = false
+ }
+ }
+ currentMode = 'idle'
+ emit('mode_change', { mode: 'idle' })
+ },
+
+ sendText(text: string) {
+ sendEvent({
+ type: 'conversation.item.create',
+ item: {
+ type: 'message',
+ role: 'user',
+ content: [{ type: 'input_text', text }],
+ },
+ })
+ sendEvent({ type: 'response.create' })
+ },
+
+ sendToolResult(callId: string, result: string) {
+ sendEvent({
+ type: 'conversation.item.create',
+ item: {
+ type: 'function_call_output',
+ call_id: callId,
+ output: result,
+ },
+ })
+ sendEvent({ type: 'response.create' })
+ },
+
+ updateSession(config: Partial) {
+ const sessionUpdate: Record = {}
+
+ if (config.instructions) {
+ sessionUpdate.instructions = config.instructions
+ }
+
+ if (config.voice) {
+ sessionUpdate.voice = config.voice
+ }
+
+ if (config.vadMode) {
+ if (config.vadMode === 'semantic') {
+ sessionUpdate.turn_detection = {
+ type: 'semantic_vad',
+ eagerness: 'medium',
+ }
+ } else if (config.vadMode === 'server') {
+ sessionUpdate.turn_detection = {
+ type: 'server_vad',
+ threshold: config.vadConfig?.threshold ?? 0.5,
+ prefix_padding_ms: config.vadConfig?.prefixPaddingMs ?? 300,
+ silence_duration_ms: config.vadConfig?.silenceDurationMs ?? 500,
+ }
+ } else {
+ sessionUpdate.turn_detection = null
+ }
+ }
+
+ if (Object.keys(sessionUpdate).length > 0) {
+ sendEvent({
+ type: 'session.update',
+ session: sessionUpdate,
+ })
+ }
+ },
+
+ interrupt() {
+ sendEvent({ type: 'response.cancel' })
+ currentMode = 'listening'
+ emit('mode_change', { mode: 'listening' })
+ emit('interrupted', { messageId: currentMessageId ?? undefined })
+ },
+
+ on(
+ event: E,
+ handler: RealtimeEventHandler,
+ ): () => void {
+ if (!eventHandlers.has(event)) {
+ eventHandlers.set(event, new Set())
+ }
+ eventHandlers.get(event)!.add(handler)
+
+ return () => {
+ eventHandlers.get(event)?.delete(handler)
+ }
+ },
+
+ getAudioVisualization(): AudioVisualization {
+ // Log analyser state for debugging
+ console.log('[Realtime] getAudioVisualization called, inputAnalyser:', !!inputAnalyser, 'outputAnalyser:', !!outputAnalyser)
+
+ // Helper to calculate RMS (Root Mean Square) from time domain data
+ // This gives a better measure of perceived loudness than frequency data
+ function calculateRMS(analyser: AnalyserNode): number {
+ const data = new Uint8Array(analyser.fftSize)
+ analyser.getByteTimeDomainData(data)
+
+ // Calculate RMS - values are 0-255 with 128 being silence
+ let sumSquares = 0
+ for (const sample of data) {
+ const normalized = (sample - 128) / 128 // Convert to -1 to 1 range
+ sumSquares += normalized * normalized
+ }
+ const rms = Math.sqrt(sumSquares / data.length)
+
+ // Scale and clamp to 0-1 range (RMS of full-scale sine is ~0.707)
+ return Math.min(1, rms * 1.5)
+ }
+
+ return {
+ get inputLevel() {
+ if (!inputAnalyser) return 0
+ return calculateRMS(inputAnalyser)
+ },
+
+ get outputLevel() {
+ if (!outputAnalyser) return 0
+ return calculateRMS(outputAnalyser)
+ },
+
+ getInputFrequencyData() {
+ if (!inputAnalyser) return emptyFrequencyData
+ const data = new Uint8Array(inputAnalyser.frequencyBinCount)
+ inputAnalyser.getByteFrequencyData(data)
+ return data
+ },
+
+ getOutputFrequencyData() {
+ if (!outputAnalyser) return emptyFrequencyData
+ const data = new Uint8Array(outputAnalyser.frequencyBinCount)
+ outputAnalyser.getByteFrequencyData(data)
+ return data
+ },
+
+ getInputTimeDomainData() {
+ if (!inputAnalyser) return emptyTimeDomainData
+ const data = new Uint8Array(inputAnalyser.fftSize)
+ inputAnalyser.getByteTimeDomainData(data)
+ return data
+ },
+
+ getOutputTimeDomainData() {
+ if (!outputAnalyser) return emptyTimeDomainData
+ const data = new Uint8Array(outputAnalyser.fftSize)
+ outputAnalyser.getByteTimeDomainData(data)
+ return data
+ },
+
+ get inputSampleRate() {
+ return 24000
+ },
+
+ get outputSampleRate() {
+ return 24000
+ },
+ }
+ },
+ }
+
+ return connection
+}
diff --git a/packages/typescript/ai-openai/src/realtime/index.ts b/packages/typescript/ai-openai/src/realtime/index.ts
new file mode 100644
index 0000000000..d5ea156e6e
--- /dev/null
+++ b/packages/typescript/ai-openai/src/realtime/index.ts
@@ -0,0 +1,16 @@
+// Token adapter for server-side use
+export { openaiRealtimeToken } from './token'
+
+// Client adapter for browser use
+export { openaiRealtime } from './adapter'
+
+// Types
+export type {
+ OpenAIRealtimeVoice,
+ OpenAIRealtimeModel,
+ OpenAIRealtimeTokenOptions,
+ OpenAIRealtimeOptions,
+ OpenAITurnDetection,
+ OpenAISemanticVADConfig,
+ OpenAIServerVADConfig,
+} from './types'
diff --git a/packages/typescript/ai-openai/src/realtime/token.ts b/packages/typescript/ai-openai/src/realtime/token.ts
new file mode 100644
index 0000000000..d226cacbba
--- /dev/null
+++ b/packages/typescript/ai-openai/src/realtime/token.ts
@@ -0,0 +1,153 @@
+import type { RealtimeToken, RealtimeTokenAdapter, Tool } from '@tanstack/ai'
+import { getOpenAIApiKeyFromEnv } from '../utils'
+import type {
+ OpenAIRealtimeModel,
+ OpenAIRealtimeSessionResponse,
+ OpenAIRealtimeTokenOptions,
+} from './types'
+
+const OPENAI_REALTIME_SESSIONS_URL =
+ 'https://api.openai.com/v1/realtime/sessions'
+
+/**
+ * Creates an OpenAI realtime token adapter.
+ *
+ * This adapter generates ephemeral tokens for client-side WebRTC connections.
+ * The token is valid for 10 minutes.
+ *
+ * @param options - Configuration options for the realtime session
+ * @returns A RealtimeTokenAdapter for use with realtimeToken()
+ *
+ * @example
+ * ```typescript
+ * import { realtimeToken } from '@tanstack/ai'
+ * import { openaiRealtimeToken } from '@tanstack/ai-openai'
+ *
+ * const token = await realtimeToken({
+ * adapter: openaiRealtimeToken({
+ * model: 'gpt-4o-realtime-preview',
+ * voice: 'alloy',
+ * instructions: 'You are a helpful assistant.',
+ * turnDetection: {
+ * type: 'semantic_vad',
+ * eagerness: 'medium',
+ * },
+ * }),
+ * })
+ * ```
+ */
+export function openaiRealtimeToken(
+ options: OpenAIRealtimeTokenOptions = {},
+): RealtimeTokenAdapter {
+ const apiKey = getOpenAIApiKeyFromEnv()
+
+ return {
+ provider: 'openai',
+
+ async generateToken(): Promise {
+ const model: OpenAIRealtimeModel =
+ options.model ?? 'gpt-4o-realtime-preview'
+ const voice = options.voice ?? 'alloy'
+
+ // Build request body
+ const body: Record = {
+ model,
+ voice,
+ }
+
+ if (options.instructions) {
+ body.instructions = options.instructions
+ }
+
+ if (options.turnDetection !== undefined) {
+ body.turn_detection = options.turnDetection
+ }
+
+ if (options.inputAudioFormat) {
+ body.input_audio_format = options.inputAudioFormat
+ }
+
+ if (options.outputAudioFormat) {
+ body.output_audio_format = options.outputAudioFormat
+ }
+
+ if (options.inputAudioTranscription) {
+ body.input_audio_transcription = options.inputAudioTranscription
+ }
+
+ if (options.tools) {
+ body.tools = options.tools
+ }
+
+ if (options.toolChoice) {
+ body.tool_choice = options.toolChoice
+ }
+
+ if (options.temperature !== undefined) {
+ body.temperature = options.temperature
+ }
+
+ if (options.maxResponseOutputTokens !== undefined) {
+ body.max_response_output_tokens = options.maxResponseOutputTokens
+ }
+
+ // Call OpenAI API to create session and get ephemeral token
+ const response = await fetch(OPENAI_REALTIME_SESSIONS_URL, {
+ method: 'POST',
+ headers: {
+ Authorization: `Bearer ${apiKey}`,
+ 'Content-Type': 'application/json',
+ },
+ body: JSON.stringify(body),
+ })
+
+ if (!response.ok) {
+ const errorText = await response.text()
+ throw new Error(
+ `OpenAI realtime session creation failed: ${response.status} ${errorText}`,
+ )
+ }
+
+ const sessionData: OpenAIRealtimeSessionResponse = await response.json()
+
+ // Convert tools to our format
+ const tools: Array = (sessionData.tools || []).map((t) => ({
+ name: t.name,
+ description: t.description,
+ inputSchema: t.parameters,
+ }))
+
+ return {
+ provider: 'openai',
+ token: sessionData.client_secret.value,
+ expiresAt: sessionData.client_secret.expires_at * 1000, // Convert to ms
+ config: {
+ model: sessionData.model,
+ voice: sessionData.voice,
+ instructions: sessionData.instructions,
+ tools,
+ vadMode: sessionData.turn_detection?.type === 'semantic_vad'
+ ? 'semantic'
+ : sessionData.turn_detection?.type === 'server_vad'
+ ? 'server'
+ : 'manual',
+ vadConfig: sessionData.turn_detection
+ ? {
+ threshold: sessionData.turn_detection.threshold,
+ prefixPaddingMs: sessionData.turn_detection.prefix_padding_ms,
+ silenceDurationMs:
+ sessionData.turn_detection.silence_duration_ms,
+ }
+ : undefined,
+ providerOptions: {
+ inputAudioFormat: sessionData.input_audio_format,
+ outputAudioFormat: sessionData.output_audio_format,
+ inputAudioTranscription: sessionData.input_audio_transcription,
+ temperature: sessionData.temperature,
+ maxResponseOutputTokens: sessionData.max_response_output_tokens,
+ },
+ },
+ }
+ },
+ }
+}
diff --git a/packages/typescript/ai-openai/src/realtime/types.ts b/packages/typescript/ai-openai/src/realtime/types.ts
new file mode 100644
index 0000000000..713bd2b4cf
--- /dev/null
+++ b/packages/typescript/ai-openai/src/realtime/types.ts
@@ -0,0 +1,127 @@
+import type { VADConfig } from '@tanstack/ai'
+
+/**
+ * OpenAI realtime voice options
+ */
+export type OpenAIRealtimeVoice =
+ | 'alloy'
+ | 'ash'
+ | 'ballad'
+ | 'coral'
+ | 'echo'
+ | 'sage'
+ | 'shimmer'
+ | 'verse'
+
+/**
+ * OpenAI realtime model options
+ */
+export type OpenAIRealtimeModel =
+ | 'gpt-4o-realtime-preview'
+ | 'gpt-4o-realtime-preview-2024-10-01'
+ | 'gpt-4o-mini-realtime-preview'
+ | 'gpt-4o-mini-realtime-preview-2024-12-17'
+
+/**
+ * OpenAI semantic VAD configuration
+ */
+export interface OpenAISemanticVADConfig {
+ type: 'semantic_vad'
+ /** Eagerness level for turn detection */
+ eagerness?: 'low' | 'medium' | 'high'
+}
+
+/**
+ * OpenAI server VAD configuration
+ */
+export interface OpenAIServerVADConfig extends VADConfig {
+ type: 'server_vad'
+}
+
+/**
+ * OpenAI turn detection configuration
+ */
+export type OpenAITurnDetection =
+ | OpenAISemanticVADConfig
+ | OpenAIServerVADConfig
+ | null
+
+/**
+ * Options for the OpenAI realtime token adapter
+ */
+export interface OpenAIRealtimeTokenOptions {
+ /** Model to use (default: 'gpt-4o-realtime-preview') */
+ model?: OpenAIRealtimeModel
+ /** Voice to use (default: 'alloy') */
+ voice?: OpenAIRealtimeVoice
+ /** System instructions */
+ instructions?: string
+ /** Turn detection configuration */
+ turnDetection?: OpenAITurnDetection
+ /** Input audio format (default: 'pcm16') */
+ inputAudioFormat?: 'pcm16' | 'g711_ulaw' | 'g711_alaw'
+ /** Output audio format (default: 'pcm16') */
+ outputAudioFormat?: 'pcm16' | 'g711_ulaw' | 'g711_alaw'
+ /** Input audio transcription model */
+ inputAudioTranscription?: {
+ model: 'whisper-1'
+ }
+ /** Tools available in the session */
+ tools?: Array<{
+ type: 'function'
+ name: string
+ description: string
+ parameters: Record
+ }>
+ /** Tool choice strategy */
+ toolChoice?: 'auto' | 'none' | 'required' | { type: 'function'; name: string }
+ /** Temperature for response generation */
+ temperature?: number
+ /** Maximum response output tokens */
+ maxResponseOutputTokens?: number | 'inf'
+}
+
+/**
+ * Options for the OpenAI realtime client adapter
+ */
+export interface OpenAIRealtimeOptions {
+ /** Connection mode (default: 'webrtc' in browser) */
+ connectionMode?: 'webrtc' | 'websocket'
+}
+
+/**
+ * OpenAI realtime session response from the API
+ */
+export interface OpenAIRealtimeSessionResponse {
+ id: string
+ object: 'realtime.session'
+ model: string
+ modalities: Array
+ instructions: string
+ voice: string
+ input_audio_format: string
+ output_audio_format: string
+ input_audio_transcription: {
+ model: string
+ } | null
+ turn_detection: {
+ type: string
+ threshold?: number
+ prefix_padding_ms?: number
+ silence_duration_ms?: number
+ eagerness?: string
+ } | null
+ tools: Array<{
+ type: string
+ name: string
+ description: string
+ parameters: Record
+ }>
+ tool_choice: string
+ temperature: number
+ max_response_output_tokens: number | string
+ client_secret: {
+ value: string
+ expires_at: number
+ }
+}
diff --git a/packages/typescript/ai-react/src/index.ts b/packages/typescript/ai-react/src/index.ts
index b08f90e361..175db7bb1d 100644
--- a/packages/typescript/ai-react/src/index.ts
+++ b/packages/typescript/ai-react/src/index.ts
@@ -1,10 +1,15 @@
export { useChat } from './use-chat'
+export { useRealtimeChat } from './use-realtime-chat'
export type {
UseChatOptions,
UseChatReturn,
UIMessage,
ChatRequestBody,
} from './types'
+export type {
+ UseRealtimeChatOptions,
+ UseRealtimeChatReturn,
+} from './realtime-types'
// Re-export from ai-client for convenience
export {
diff --git a/packages/typescript/ai-react/src/realtime-types.ts b/packages/typescript/ai-react/src/realtime-types.ts
new file mode 100644
index 0000000000..f3a403464e
--- /dev/null
+++ b/packages/typescript/ai-react/src/realtime-types.ts
@@ -0,0 +1,109 @@
+import type {
+ RealtimeMessage,
+ RealtimeMode,
+ RealtimeStatus,
+ RealtimeToken,
+} from '@tanstack/ai'
+import type { RealtimeAdapter } from '@tanstack/ai-client'
+import type { AnyClientTool } from '@tanstack/ai'
+
+/**
+ * Options for the useRealtimeChat hook.
+ */
+export interface UseRealtimeChatOptions {
+ /**
+ * Function to fetch a realtime token from the server.
+ * Called on connect and when token needs refresh.
+ */
+ getToken: () => Promise
+
+ /**
+ * The realtime adapter to use (e.g., openaiRealtime())
+ */
+ adapter: RealtimeAdapter
+
+ /**
+ * Client-side tools with execution logic
+ */
+ tools?: ReadonlyArray
+
+ /**
+ * Auto-play assistant audio (default: true)
+ */
+ autoPlayback?: boolean
+
+ /**
+ * Request microphone access on connect (default: true)
+ */
+ autoCapture?: boolean
+
+ /**
+ * Voice activity detection mode (default: 'server')
+ */
+ vadMode?: 'server' | 'semantic' | 'manual'
+
+ // Callbacks
+ onConnect?: () => void
+ onDisconnect?: () => void
+ onError?: (error: Error) => void
+ onMessage?: (message: RealtimeMessage) => void
+ onModeChange?: (mode: RealtimeMode) => void
+ onInterrupted?: () => void
+}
+
+/**
+ * Return type for the useRealtimeChat hook.
+ */
+export interface UseRealtimeChatReturn {
+ // Connection state
+ /** Current connection status */
+ status: RealtimeStatus
+ /** Current error, if any */
+ error: Error | null
+ /** Connect to the realtime session */
+ connect: () => Promise
+ /** Disconnect from the realtime session */
+ disconnect: () => Promise
+
+ // Conversation state
+ /** Current mode (idle, listening, thinking, speaking) */
+ mode: RealtimeMode
+ /** Conversation messages */
+ messages: Array
+ /** User transcript while speaking (before finalized) */
+ pendingUserTranscript: string | null
+ /** Assistant transcript while speaking (before finalized) */
+ pendingAssistantTranscript: string | null
+
+ // Voice control
+ /** Start listening for voice input (manual VAD mode) */
+ startListening: () => void
+ /** Stop listening for voice input (manual VAD mode) */
+ stopListening: () => void
+ /** Interrupt the current assistant response */
+ interrupt: () => void
+
+ // Text input
+ /** Send a text message instead of voice */
+ sendText: (text: string) => void
+
+ // Audio visualization (0-1 normalized)
+ /** Current input (microphone) volume level */
+ inputLevel: number
+ /** Current output (speaker) volume level */
+ outputLevel: number
+ /** Get frequency data for input audio visualization */
+ getInputFrequencyData: () => Uint8Array
+ /** Get frequency data for output audio visualization */
+ getOutputFrequencyData: () => Uint8Array
+ /** Get time domain data for input waveform */
+ getInputTimeDomainData: () => Uint8Array
+ /** Get time domain data for output waveform */
+ getOutputTimeDomainData: () => Uint8Array
+
+ // VAD control
+ /** Current VAD mode */
+ vadMode: 'server' | 'semantic' | 'manual'
+ /** Change VAD mode at runtime */
+ setVADMode: (mode: 'server' | 'semantic' | 'manual') => void
+}
diff --git a/packages/typescript/ai-react/src/use-realtime-chat.ts b/packages/typescript/ai-react/src/use-realtime-chat.ts
new file mode 100644
index 0000000000..3434db607d
--- /dev/null
+++ b/packages/typescript/ai-react/src/use-realtime-chat.ts
@@ -0,0 +1,241 @@
+import { useCallback, useEffect, useRef, useState } from 'react'
+import { RealtimeClient } from '@tanstack/ai-client'
+import type { RealtimeMessage, RealtimeMode, RealtimeStatus } from '@tanstack/ai'
+import type { UseRealtimeChatOptions, UseRealtimeChatReturn } from './realtime-types'
+
+// Empty frequency data for when client is not connected
+const emptyFrequencyData = new Uint8Array(128)
+const emptyTimeDomainData = new Uint8Array(128).fill(128)
+
+/**
+ * React hook for realtime voice conversations.
+ *
+ * Provides a simple interface for voice-to-voice AI interactions
+ * with support for multiple providers (OpenAI, ElevenLabs, etc.).
+ *
+ * @param options - Configuration options including adapter and callbacks
+ * @returns Hook return value with state and control methods
+ *
+ * @example
+ * ```typescript
+ * import { useRealtimeChat } from '@tanstack/ai-react'
+ * import { openaiRealtime } from '@tanstack/ai-openai'
+ *
+ * function VoiceChat() {
+ * const {
+ * status,
+ * mode,
+ * messages,
+ * connect,
+ * disconnect,
+ * inputLevel,
+ * outputLevel,
+ * } = useRealtimeChat({
+ * getToken: () => fetch('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/api/realtime-token').then(r => r.json()),
+ * adapter: openaiRealtime(),
+ * })
+ *
+ * return (
+ *
+ *
Status: {status}
+ *
Mode: {mode}
+ *
+ * {status === 'idle' ? 'Start' : 'Stop'}
+ *
+ *
+ * )
+ * }
+ * ```
+ */
+export function useRealtimeChat(
+ options: UseRealtimeChatOptions,
+): UseRealtimeChatReturn {
+ // State
+ const [status, setStatus] = useState('idle')
+ const [mode, setMode] = useState('idle')
+ const [messages, setMessages] = useState>([])
+ const [pendingUserTranscript, setPendingUserTranscript] = useState(null)
+ const [pendingAssistantTranscript, setPendingAssistantTranscript] = useState(null)
+ const [error, setError] = useState(null)
+ const [inputLevel, setInputLevel] = useState(0)
+ const [outputLevel, setOutputLevel] = useState(0)
+ const [vadMode, setVADModeState] = useState<'server' | 'semantic' | 'manual'>(
+ options.vadMode ?? 'server',
+ )
+
+ // Refs
+ const clientRef = useRef(null)
+ const optionsRef = useRef(options)
+ optionsRef.current = options
+ const animationFrameRef = useRef(null)
+
+ // Create client instance - use ref to ensure we reuse the same instance
+ // This handles React StrictMode double-rendering
+ if (!clientRef.current) {
+ clientRef.current = new RealtimeClient({
+ getToken: optionsRef.current.getToken,
+ adapter: optionsRef.current.adapter,
+ tools: optionsRef.current.tools,
+ autoPlayback: optionsRef.current.autoPlayback,
+ autoCapture: optionsRef.current.autoCapture,
+ vadMode: optionsRef.current.vadMode,
+ onStatusChange: (newStatus) => {
+ setStatus(newStatus)
+ },
+ onModeChange: (newMode) => {
+ setMode(newMode)
+ optionsRef.current.onModeChange?.(newMode)
+ },
+ onMessage: (message) => {
+ setMessages((prev) => [...prev, message])
+ optionsRef.current.onMessage?.(message)
+ },
+ onError: (err) => {
+ setError(err)
+ optionsRef.current.onError?.(err)
+ },
+ onConnect: () => {
+ setError(null)
+ optionsRef.current.onConnect?.()
+ },
+ onDisconnect: () => {
+ optionsRef.current.onDisconnect?.()
+ },
+ onInterrupted: () => {
+ setPendingAssistantTranscript(null)
+ optionsRef.current.onInterrupted?.()
+ },
+ })
+
+ // Subscribe to state changes for transcripts
+ clientRef.current.onStateChange((state) => {
+ setPendingUserTranscript(state.pendingUserTranscript)
+ setPendingAssistantTranscript(state.pendingAssistantTranscript)
+ })
+ }
+
+ const client = clientRef.current
+
+ // Audio level animation loop
+ useEffect(() => {
+ function updateLevels() {
+ if (clientRef.current?.audio) {
+ setInputLevel(clientRef.current.audio.inputLevel)
+ setOutputLevel(clientRef.current.audio.outputLevel)
+ }
+ animationFrameRef.current = requestAnimationFrame(updateLevels)
+ }
+
+ if (status === 'connected') {
+ updateLevels()
+ }
+
+ return () => {
+ if (animationFrameRef.current) {
+ cancelAnimationFrame(animationFrameRef.current)
+ animationFrameRef.current = null
+ }
+ }
+ }, [status])
+
+ // Cleanup on unmount
+ useEffect(() => {
+ return () => {
+ clientRef.current?.destroy()
+ }
+ }, [])
+
+ // Connection methods
+ const connect = useCallback(async () => {
+ setError(null)
+ setMessages([])
+ setPendingUserTranscript(null)
+ setPendingAssistantTranscript(null)
+ await client.connect()
+ }, [client])
+
+ const disconnect = useCallback(async () => {
+ await client.disconnect()
+ }, [client])
+
+ // Voice control methods
+ const startListening = useCallback(() => {
+ client.startListening()
+ }, [client])
+
+ const stopListening = useCallback(() => {
+ client.stopListening()
+ }, [client])
+
+ const interrupt = useCallback(() => {
+ client.interrupt()
+ }, [client])
+
+ // Text input
+ const sendText = useCallback(
+ (text: string) => {
+ client.sendText(text)
+ },
+ [client],
+ )
+
+ // Audio visualization
+ const getInputFrequencyData = useCallback(() => {
+ return clientRef.current?.audio?.getInputFrequencyData() ?? emptyFrequencyData
+ }, [])
+
+ const getOutputFrequencyData = useCallback(() => {
+ return clientRef.current?.audio?.getOutputFrequencyData() ?? emptyFrequencyData
+ }, [])
+
+ const getInputTimeDomainData = useCallback(() => {
+ return clientRef.current?.audio?.getInputTimeDomainData() ?? emptyTimeDomainData
+ }, [])
+
+ const getOutputTimeDomainData = useCallback(() => {
+ return clientRef.current?.audio?.getOutputTimeDomainData() ?? emptyTimeDomainData
+ }, [])
+
+ // VAD mode control
+ const setVADMode = useCallback(
+ (newMode: 'server' | 'semantic' | 'manual') => {
+ setVADModeState(newMode)
+ // TODO: Update session config if connected
+ },
+ [],
+ )
+
+ return {
+ // Connection state
+ status,
+ error,
+ connect,
+ disconnect,
+
+ // Conversation state
+ mode,
+ messages,
+ pendingUserTranscript,
+ pendingAssistantTranscript,
+
+ // Voice control
+ startListening,
+ stopListening,
+ interrupt,
+
+ // Text input
+ sendText,
+
+ // Audio visualization
+ inputLevel,
+ outputLevel,
+ getInputFrequencyData,
+ getOutputFrequencyData,
+ getInputTimeDomainData,
+ getOutputTimeDomainData,
+
+ // VAD control
+ vadMode,
+ setVADMode,
+ }
+}
diff --git a/packages/typescript/ai/src/index.ts b/packages/typescript/ai/src/index.ts
index 0476457d52..34ec893a6b 100644
--- a/packages/typescript/ai/src/index.ts
+++ b/packages/typescript/ai/src/index.ts
@@ -76,6 +76,30 @@ export * from './types'
// Event client
export { aiEventClient } from './event-client'
+// Realtime
+export { realtimeToken } from './realtime/index'
+export type {
+ RealtimeToken,
+ RealtimeTokenAdapter,
+ RealtimeTokenOptions,
+ RealtimeSessionConfig,
+ VADConfig,
+ RealtimeMessage,
+ RealtimeMessagePart,
+ RealtimeTextPart,
+ RealtimeAudioPart,
+ RealtimeToolCallPart,
+ RealtimeToolResultPart,
+ RealtimeStatus,
+ RealtimeMode,
+ AudioVisualization,
+ RealtimeEvent,
+ RealtimeEventPayloads,
+ RealtimeEventHandler,
+ RealtimeErrorCode,
+ RealtimeError,
+} from './realtime/index'
+
// Message converters
export {
convertMessagesToModelMessages,
diff --git a/packages/typescript/ai/src/realtime/index.ts b/packages/typescript/ai/src/realtime/index.ts
new file mode 100644
index 0000000000..74c450c1d4
--- /dev/null
+++ b/packages/typescript/ai/src/realtime/index.ts
@@ -0,0 +1,38 @@
+import type { RealtimeToken, RealtimeTokenOptions } from './types'
+
+// Re-export all types
+export * from './types'
+
+/**
+ * Generate a realtime token using the provided adapter.
+ *
+ * This function is used on the server to generate ephemeral tokens
+ * that clients can use to establish realtime connections.
+ *
+ * @param options - Token generation options including the adapter
+ * @returns Promise resolving to a RealtimeToken
+ *
+ * @example
+ * ```typescript
+ * import { realtimeToken } from '@tanstack/ai'
+ * import { openaiRealtimeToken } from '@tanstack/ai-openai'
+ *
+ * // Server function (TanStack Start example)
+ * export const getRealtimeToken = createServerFn()
+ * .handler(async () => {
+ * return realtimeToken({
+ * adapter: openaiRealtimeToken({
+ * model: 'gpt-4o-realtime-preview',
+ * voice: 'alloy',
+ * instructions: 'You are a helpful assistant...',
+ * }),
+ * })
+ * })
+ * ```
+ */
+export async function realtimeToken(
+ options: RealtimeTokenOptions,
+): Promise {
+ const { adapter } = options
+ return adapter.generateToken()
+}
diff --git a/packages/typescript/ai/src/realtime/types.ts b/packages/typescript/ai/src/realtime/types.ts
new file mode 100644
index 0000000000..e563a2ae75
--- /dev/null
+++ b/packages/typescript/ai/src/realtime/types.ts
@@ -0,0 +1,266 @@
+import type { Tool } from '../types'
+
+// ============================================================================
+// Token Types
+// ============================================================================
+
+/**
+ * Voice activity detection configuration
+ */
+export interface VADConfig {
+ /** Sensitivity threshold (0.0-1.0) */
+ threshold?: number
+ /** Audio to include before speech detection (ms) */
+ prefixPaddingMs?: number
+ /** Silence duration to end turn (ms) */
+ silenceDurationMs?: number
+}
+
+/**
+ * Configuration for a realtime session
+ */
+export interface RealtimeSessionConfig {
+ /** Model to use for the session */
+ model?: string
+ /** Voice to use for audio output */
+ voice?: string
+ /** System instructions for the assistant */
+ instructions?: string
+ /** Tools available in the session */
+ tools?: Array
+ /** VAD mode */
+ vadMode?: 'server' | 'semantic' | 'manual'
+ /** VAD configuration */
+ vadConfig?: VADConfig
+ /** Provider-specific options */
+ providerOptions?: Record
+}
+
+/**
+ * Token returned by the server for client authentication
+ */
+export interface RealtimeToken {
+ /** Provider identifier */
+ provider: string
+ /** The ephemeral token value */
+ token: string
+ /** Token expiration timestamp (ms since epoch) */
+ expiresAt: number
+ /** Session configuration embedded in the token */
+ config: RealtimeSessionConfig
+}
+
+/**
+ * Adapter interface for generating provider-specific tokens
+ */
+export interface RealtimeTokenAdapter {
+ /** Provider identifier */
+ provider: string
+ /** Generate an ephemeral token for client use */
+ generateToken(): Promise
+}
+
+/**
+ * Options for the realtimeToken function
+ */
+export interface RealtimeTokenOptions {
+ /** The token adapter to use */
+ adapter: RealtimeTokenAdapter
+}
+
+// ============================================================================
+// Message Types
+// ============================================================================
+
+/**
+ * Text content part in a realtime message
+ */
+export interface RealtimeTextPart {
+ type: 'text'
+ content: string
+}
+
+/**
+ * Audio content part in a realtime message
+ */
+export interface RealtimeAudioPart {
+ type: 'audio'
+ /** Transcription of the audio */
+ transcript: string
+ /** Raw audio data (optional, if stored) */
+ audioData?: ArrayBuffer
+ /** Duration of the audio in milliseconds */
+ durationMs?: number
+}
+
+/**
+ * Tool call part in a realtime message
+ */
+export interface RealtimeToolCallPart {
+ type: 'tool-call'
+ id: string
+ name: string
+ arguments: string
+ input?: unknown
+ output?: unknown
+}
+
+/**
+ * Tool result part in a realtime message
+ */
+export interface RealtimeToolResultPart {
+ type: 'tool-result'
+ toolCallId: string
+ content: string
+}
+
+/**
+ * Union of all realtime message parts
+ */
+export type RealtimeMessagePart =
+ | RealtimeTextPart
+ | RealtimeAudioPart
+ | RealtimeToolCallPart
+ | RealtimeToolResultPart
+
+/**
+ * A message in a realtime conversation
+ */
+export interface RealtimeMessage {
+ /** Unique message identifier */
+ id: string
+ /** Message role */
+ role: 'user' | 'assistant'
+ /** Timestamp when the message was created */
+ timestamp: number
+ /** Content parts of the message */
+ parts: Array
+ /** Whether this message was interrupted */
+ interrupted?: boolean
+ /** Reference to audio buffer if stored */
+ audioId?: string
+ /** Duration of the audio in milliseconds */
+ durationMs?: number
+}
+
+// ============================================================================
+// Status Types
+// ============================================================================
+
+/**
+ * Connection status of the realtime client
+ */
+export type RealtimeStatus =
+ | 'idle'
+ | 'connecting'
+ | 'connected'
+ | 'reconnecting'
+ | 'error'
+
+/**
+ * Current mode of the realtime session
+ */
+export type RealtimeMode = 'idle' | 'listening' | 'thinking' | 'speaking'
+
+// ============================================================================
+// Audio Visualization Types
+// ============================================================================
+
+/**
+ * Interface for accessing audio visualization data
+ */
+export interface AudioVisualization {
+ /** Input volume level (0-1 normalized) */
+ readonly inputLevel: number
+ /** Output volume level (0-1 normalized) */
+ readonly outputLevel: number
+
+ /** Get frequency data for input audio visualization */
+ getInputFrequencyData(): Uint8Array
+ /** Get frequency data for output audio visualization */
+ getOutputFrequencyData(): Uint8Array
+
+ /** Get time domain data for input waveform */
+ getInputTimeDomainData(): Uint8Array
+ /** Get time domain data for output waveform */
+ getOutputTimeDomainData(): Uint8Array
+
+ /** Input sample rate */
+ readonly inputSampleRate: number
+ /** Output sample rate */
+ readonly outputSampleRate: number
+
+ /** Subscribe to raw input audio samples */
+ onInputAudio?(
+ callback: (samples: Float32Array, sampleRate: number) => void,
+ ): () => void
+ /** Subscribe to raw output audio samples */
+ onOutputAudio?(
+ callback: (samples: Float32Array, sampleRate: number) => void,
+ ): () => void
+}
+
+// ============================================================================
+// Event Types
+// ============================================================================
+
+/**
+ * Events emitted by the realtime connection
+ */
+export type RealtimeEvent =
+ | 'status_change'
+ | 'mode_change'
+ | 'transcript'
+ | 'audio_chunk'
+ | 'tool_call'
+ | 'message_complete'
+ | 'interrupted'
+ | 'error'
+
+/**
+ * Event payloads for realtime events
+ */
+export interface RealtimeEventPayloads {
+ status_change: { status: RealtimeStatus }
+ mode_change: { mode: RealtimeMode }
+ transcript: {
+ role: 'user' | 'assistant'
+ transcript: string
+ isFinal: boolean
+ }
+ audio_chunk: { data: ArrayBuffer; sampleRate: number }
+ tool_call: { toolCallId: string; toolName: string; input: unknown }
+ message_complete: { message: RealtimeMessage }
+ interrupted: { messageId?: string }
+ error: { error: Error }
+}
+
+/**
+ * Handler type for realtime events
+ */
+export type RealtimeEventHandler = (
+ payload: RealtimeEventPayloads[E],
+) => void
+
+// ============================================================================
+// Error Types
+// ============================================================================
+
+/**
+ * Error codes for realtime errors
+ */
+export type RealtimeErrorCode =
+ | 'TOKEN_EXPIRED'
+ | 'CONNECTION_FAILED'
+ | 'PERMISSION_DENIED'
+ | 'PROVIDER_ERROR'
+ | 'UNKNOWN'
+
+/**
+ * Extended error with realtime-specific information
+ */
+export interface RealtimeError extends Error {
+ code: RealtimeErrorCode
+ provider?: string
+ details?: unknown
+}
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index bac9571754..f53f865f57 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -201,6 +201,9 @@ importers:
'@tanstack/ai-client':
specifier: workspace:*
version: link:../../packages/typescript/ai-client
+ '@tanstack/ai-elevenlabs':
+ specifier: workspace:*
+ version: link:../../packages/typescript/ai-elevenlabs
'@tanstack/ai-gemini':
specifier: workspace:*
version: link:../../packages/typescript/ai-gemini
@@ -685,6 +688,22 @@ importers:
specifier: ^2.11.10
version: 2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@25.0.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+ packages/typescript/ai-elevenlabs:
+ dependencies:
+ '@11labs/client':
+ specifier: ^0.2.0
+ version: 0.2.0(@types/dom-mediacapture-record@1.0.22)
+ devDependencies:
+ '@tanstack/ai':
+ specifier: workspace:*
+ version: link:../ai
+ '@tanstack/ai-client':
+ specifier: workspace:*
+ version: link:../ai-client
+ '@vitest/coverage-v8':
+ specifier: 4.0.14
+ version: 4.0.14(vitest@4.0.17(@types/node@25.0.1)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+
packages/typescript/ai-gemini:
dependencies:
'@google/genai':
@@ -745,6 +764,9 @@ importers:
'@tanstack/ai':
specifier: workspace:*
version: link:../ai
+ '@tanstack/ai-client':
+ specifier: workspace:*
+ version: link:../ai-client
'@vitest/coverage-v8':
specifier: 4.0.14
version: 4.0.14(vitest@4.0.17(@types/node@25.0.1)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
@@ -1317,6 +1339,10 @@ importers:
packages:
+ '@11labs/client@0.2.0':
+ resolution: {integrity: sha512-GBplAV4WDbcoThsIzdSDPN3xbcitK0ZZ4iJfJZKfltqvgvS6Uw8GZxHwVgiPwnQoA3uosYyY3L9TuPwmel18xQ==}
+ deprecated: This package is no longer maintained. Please use @elevenlabs/client for the latest version
+
'@acemir/cssom@0.9.29':
resolution: {integrity: sha512-G90x0VW+9nW4dFajtjCoT+NM0scAfH9Mb08IcjgFHYbfiL/lU04dTF9JuVOi3/OH+DJCQdcIseSXkdCB9Ky6JA==}
@@ -1500,6 +1526,9 @@ packages:
resolution: {integrity: sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==}
engines: {node: '>=18'}
+ '@bufbuild/protobuf@1.10.1':
+ resolution: {integrity: sha512-wJ8ReQbHxsAfXhrf9ixl0aYbZorRuOWpBNzm8pL8ftmSxQx/wnJD5Eg861NwJU/czy2VXFIebCeZnZrI9rktIQ==}
+
'@changesets/apply-release-plan@7.0.14':
resolution: {integrity: sha512-ddBvf9PHdy2YY0OUiEl3TV78mH9sckndJR14QAt87KLEbIov81XO0q0QAmvooBxXlqRRP8I9B7XOzZwQG7JkWA==}
@@ -2362,6 +2391,12 @@ packages:
'@jridgewell/trace-mapping@0.3.31':
resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==}
+ '@livekit/mutex@1.1.1':
+ resolution: {integrity: sha512-EsshAucklmpuUAfkABPxJNhzj9v2sG7JuzFDL4ML1oJQSV14sqrpTYnsaOudMAw9yOaW53NU3QQTlUQoRs4czw==}
+
+ '@livekit/protocol@1.42.2':
+ resolution: {integrity: sha512-0jeCwoMJKcwsZICg5S6RZM4xhJoF78qMvQELjACJQn6/VB+jmiySQKOSELTXvPBVafHfEbMlqxUw2UR1jTXs2g==}
+
'@manypkg/find-root@1.1.0':
resolution: {integrity: sha512-mki5uBvhHzO8kYYix/WRy2WX8S3B5wdVSc9D6KcU5lQNglP2yt58/VfLuAK49glRXChosY8ap2oJ1qgma3GUVA==}
@@ -3887,6 +3922,9 @@ packages:
'@types/deep-eql@4.0.2':
resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==}
+ '@types/dom-mediacapture-record@1.0.22':
+ resolution: {integrity: sha512-mUMZLK3NvwRLcAAT9qmcK+9p7tpU2FHdDsntR3YI4+GY88XrgG4XiE7u1Q2LAN2/FZOz/tdMDC3GQCR4T8nFuw==}
+
'@types/estree-jsx@1.0.5':
resolution: {integrity: sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==}
@@ -6017,6 +6055,9 @@ packages:
jju@1.4.0:
resolution: {integrity: sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA==}
+ jose@6.1.3:
+ resolution: {integrity: sha512-0TpaTfihd4QMNwrz/ob2Bp7X04yuxJkjRGi4aKmOqwhov54i6u79oCv7T+C7lo70MKH6BesI3vscD1yb/yzKXQ==}
+
js-beautify@1.15.4:
resolution: {integrity: sha512-9/KXeZUKKJwqCXUdBxFJ3vPh467OCckSBmYDwSK/EtV090K+iMJ7zx2S3HLVDIWFQdqMIsZWbnaGiba18aWhaA==}
engines: {node: '>=14'}
@@ -6217,6 +6258,11 @@ packages:
resolution: {integrity: sha512-I8oW2+QL5KJo8zXNWX046M134WchxsXC7SawLPvRQpogCbkyQIaFxPE89A2HiwR7vAK2Dm2ERBAmyjTYGYEpBg==}
hasBin: true
+ livekit-client@2.17.0:
+ resolution: {integrity: sha512-BD1QUS44ancVTBdnAher0aO7DV5holFYH2lYradYT/HgXtn6R8xPyvtDAH3UH40jGcesDo9fEopCFwEdOgrIhg==}
+ peerDependencies:
+ '@types/dom-mediacapture-record': ^1
+
local-pkg@0.5.1:
resolution: {integrity: sha512-9rrA30MRRP3gBD3HTGnC6cDFpaE1kVDWxWgqWJUN0RvDNAo+Nz/9GxB+nHOH0ifbVFy0hSA1V6vFDvnx54lTEQ==}
engines: {node: '>=14'}
@@ -6255,6 +6301,10 @@ packages:
resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==}
engines: {node: '>=10'}
+ loglevel@1.9.2:
+ resolution: {integrity: sha512-HgMmCqIJSAKqo68l0rS2AanEWfkxaZ5wNiEFb5ggm08lDs9Xl2KxBlX3PTcaD2chBM1gXAYf491/M2Rv8Jwayg==}
+ engines: {node: '>= 0.6.0'}
+
longest-streak@3.1.0:
resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==}
@@ -7270,6 +7320,13 @@ packages:
scule@1.3.0:
resolution: {integrity: sha512-6FtHJEvt+pVMIB9IBY+IcCJ6Z5f1iQnytgyfKMhDKgmzYG+TeH/wx1y3l27rshSbLiSanrR9ffZDrEsmjlQF2g==}
+ sdp-transform@2.15.0:
+ resolution: {integrity: sha512-KrOH82c/W+GYQ0LHqtr3caRpM3ITglq3ljGUIb8LTki7ByacJZ9z+piSGiwZDsRyhQbYBOBJgr2k6X4BZXi3Kw==}
+ hasBin: true
+
+ sdp@3.2.1:
+ resolution: {integrity: sha512-lwsAIzOPlH8/7IIjjz3K0zYBk7aBVVcvjMwt3M4fLxpjMYyy7i3I97SLHebgn4YBjirkzfp3RvRDWSKsh/+WFw==}
+
semver@6.3.1:
resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==}
hasBin: true
@@ -7718,6 +7775,9 @@ packages:
peerDependencies:
typescript: '>=4.8.4'
+ ts-debounce@4.0.0:
+ resolution: {integrity: sha512-+1iDGY6NmOGidq7i7xZGA4cm8DAa6fqdYcvO5Z6yBevH++Bdo9Qt/mN0TzHUgcCcKv1gmh9+W5dHqz8pMWbCbg==}
+
ts-declaration-location@1.0.7:
resolution: {integrity: sha512-EDyGAwH1gO0Ausm9gV6T2nUvBgXT5kGoCMJPllOaooZ+4VvJiKBdZE7wK18N1deEowhcUptS+5GXZK8U/fvpwA==}
peerDependencies:
@@ -7787,6 +7847,9 @@ packages:
resolution: {integrity: sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==}
engines: {node: '>= 0.6'}
+ typed-emitter@2.1.0:
+ resolution: {integrity: sha512-g/KzbYKbH5C2vPkaXGu8DJlHrGKHLsM25Zg9WuC9pMGfuvT+X25tZQWo5fK1BjBm8+UrVE9LDCvaY0CQk+fXDA==}
+
typedoc-plugin-frontmatter@1.3.0:
resolution: {integrity: sha512-xYQFMAecMlsRUjmf9oM/Sq2FVz4zlgcbIeVFNLdO118CHTN06gIKJNSlyExh9+Xl8sK0YhIvoQwViUURxritWA==}
peerDependencies:
@@ -8327,6 +8390,10 @@ packages:
webpack-virtual-modules@0.6.2:
resolution: {integrity: sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==}
+ webrtc-adapter@9.0.3:
+ resolution: {integrity: sha512-5fALBcroIl31OeXAdd1YUntxiZl1eHlZZWzNg3U4Fn+J9/cGL3eT80YlrsWGvj2ojuz1rZr2OXkgCzIxAZ7vRQ==}
+ engines: {node: '>=6.0.0', npm: '>=3.10.0'}
+
whatwg-encoding@3.1.1:
resolution: {integrity: sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==}
engines: {node: '>=18'}
@@ -8477,6 +8544,12 @@ packages:
snapshots:
+ '@11labs/client@0.2.0(@types/dom-mediacapture-record@1.0.22)':
+ dependencies:
+ livekit-client: 2.17.0(@types/dom-mediacapture-record@1.0.22)
+ transitivePeerDependencies:
+ - '@types/dom-mediacapture-record'
+
'@acemir/cssom@0.9.29': {}
'@alcyone-labs/zod-to-json-schema@4.0.10(zod@4.2.1)':
@@ -8717,6 +8790,8 @@ snapshots:
'@bcoe/v8-coverage@1.0.2': {}
+ '@bufbuild/protobuf@1.10.1': {}
+
'@changesets/apply-release-plan@7.0.14':
dependencies:
'@changesets/config': 3.1.2
@@ -9379,6 +9454,12 @@ snapshots:
'@jridgewell/resolve-uri': 3.1.2
'@jridgewell/sourcemap-codec': 1.5.5
+ '@livekit/mutex@1.1.1': {}
+
+ '@livekit/protocol@1.42.2':
+ dependencies:
+ '@bufbuild/protobuf': 1.10.1
+
'@manypkg/find-root@1.1.0':
dependencies:
'@babel/runtime': 7.28.4
@@ -11380,6 +11461,8 @@ snapshots:
'@types/deep-eql@4.0.2': {}
+ '@types/dom-mediacapture-record@1.0.22': {}
+
'@types/estree-jsx@1.0.5':
dependencies:
'@types/estree': 1.0.8
@@ -13896,6 +13979,8 @@ snapshots:
jju@1.4.0: {}
+ jose@6.1.3: {}
+
js-beautify@1.15.4:
dependencies:
config-chain: 1.1.13
@@ -14113,6 +14198,20 @@ snapshots:
untun: 0.1.3
uqr: 0.1.2
+ livekit-client@2.17.0(@types/dom-mediacapture-record@1.0.22):
+ dependencies:
+ '@livekit/mutex': 1.1.1
+ '@livekit/protocol': 1.42.2
+ '@types/dom-mediacapture-record': 1.0.22
+ events: 3.3.0
+ jose: 6.1.3
+ loglevel: 1.9.2
+ sdp-transform: 2.15.0
+ ts-debounce: 4.0.0
+ tslib: 2.8.1
+ typed-emitter: 2.1.0
+ webrtc-adapter: 9.0.3
+
local-pkg@0.5.1:
dependencies:
mlly: 1.8.0
@@ -14149,6 +14248,8 @@ snapshots:
chalk: 4.1.2
is-unicode-supported: 0.1.0
+ loglevel@1.9.2: {}
+
longest-streak@3.1.0: {}
lowlight@3.3.0:
@@ -15551,6 +15652,10 @@ snapshots:
scule@1.3.0: {}
+ sdp-transform@2.15.0: {}
+
+ sdp@3.2.1: {}
+
semver@6.3.1: {}
semver@7.5.4:
@@ -16031,6 +16136,8 @@ snapshots:
dependencies:
typescript: 5.9.3
+ ts-debounce@4.0.0: {}
+
ts-declaration-location@1.0.7(typescript@5.9.3):
dependencies:
picomatch: 4.0.3
@@ -16098,6 +16205,10 @@ snapshots:
media-typer: 1.1.0
mime-types: 3.0.2
+ typed-emitter@2.1.0:
+ optionalDependencies:
+ rxjs: 7.8.2
+
typedoc-plugin-frontmatter@1.3.0(typedoc-plugin-markdown@4.9.0(typedoc@0.28.14(typescript@5.9.3))):
dependencies:
typedoc-plugin-markdown: 4.9.0(typedoc@0.28.14(typescript@5.9.3))
@@ -16769,6 +16880,10 @@ snapshots:
webpack-virtual-modules@0.6.2: {}
+ webrtc-adapter@9.0.3:
+ dependencies:
+ sdp: 3.2.1
+
whatwg-encoding@3.1.1:
dependencies:
iconv-lite: 0.6.3
From 71ad066469625d12de3c7108b9ae5c92a93497e4 Mon Sep 17 00:00:00 2001
From: Jack Herrington
Date: Tue, 20 Jan 2026 07:10:18 -0800
Subject: [PATCH 02/31] Realtime chat basically working
---
docs/architecture/realtime-chat.md | 313 +++++++++++++++++++++++++++++
1 file changed, 313 insertions(+)
create mode 100644 docs/architecture/realtime-chat.md
diff --git a/docs/architecture/realtime-chat.md b/docs/architecture/realtime-chat.md
new file mode 100644
index 0000000000..305029c3ec
--- /dev/null
+++ b/docs/architecture/realtime-chat.md
@@ -0,0 +1,313 @@
+---
+title: Realtime Voice Chat Architecture
+id: realtime-chat-architecture
+---
+
+# Realtime Voice Chat Architecture
+
+This document describes the architecture of TanStack AI's realtime voice-to-voice chat capability, which enables browser-based voice conversations with AI models.
+
+## Overview
+
+The realtime chat system provides a vendor-neutral, type-safe abstraction for voice-to-voice AI interactions. It currently supports:
+
+- **OpenAI Realtime API** - WebRTC-based connection with GPT-4o realtime models
+- **ElevenLabs Conversational AI** - SDK-based connection for voice conversations
+
+## Architecture Layers
+
+```
+┌─────────────────────────────────────────────────────────────────┐
+│ React Application │
+│ ┌─────────────────────────────────────────────────────────┐ │
+│ │ useRealtimeChat() │ │
+│ │ - Connection state (status, mode) │ │
+│ │ - Messages & transcripts │ │
+│ │ - Audio visualization (levels, waveforms) │ │
+│ │ - Control methods (connect, disconnect, interrupt) │ │
+│ └─────────────────────────────────────────────────────────┘ │
+└─────────────────────────────────────────────────────────────────┘
+ │
+ ▼
+┌─────────────────────────────────────────────────────────────────┐
+│ @tanstack/ai-client │
+│ ┌─────────────────────────────────────────────────────────┐ │
+│ │ RealtimeClient │ │
+│ │ - Connection lifecycle management │ │
+│ │ - Token refresh scheduling │ │
+│ │ - Event subscription & dispatch │ │
+│ │ - Tool execution coordination │ │
+│ └─────────────────────────────────────────────────────────┘ │
+└─────────────────────────────────────────────────────────────────┘
+ │
+ ▼
+┌─────────────────────────────────────────────────────────────────┐
+│ Provider Adapters │
+│ ┌──────────────────────┐ ┌──────────────────────┐ │
+│ │ openaiRealtime() │ │ elevenlabsRealtime() │ │
+│ │ - WebRTC connection │ │ - SDK wrapper │ │
+│ │ - Audio I/O │ │ - Signed URL auth │ │
+│ │ - Event mapping │ │ - Event mapping │ │
+│ └──────────────────────┘ └──────────────────────┘ │
+└─────────────────────────────────────────────────────────────────┘
+ │
+ ▼
+┌─────────────────────────────────────────────────────────────────┐
+│ Server-Side │
+│ ┌─────────────────────────────────────────────────────────┐ │
+│ │ Token Generation Endpoint │ │
+│ │ - openaiRealtimeToken() - ephemeral client secrets │ │
+│ │ - elevenlabsRealtimeToken() - signed URLs │ │
+│ └─────────────────────────────────────────────────────────┘ │
+└─────────────────────────────────────────────────────────────────┘
+```
+
+## Key Components
+
+### 1. Token Adapters (Server-Side)
+
+Token adapters generate short-lived credentials for client-side connections. This keeps API keys secure on the server.
+
+```typescript
+// Server-side token endpoint
+import { realtimeToken } from '@tanstack/ai'
+import { openaiRealtimeToken } from '@tanstack/ai-openai'
+
+const token = await realtimeToken({
+ adapter: openaiRealtimeToken({
+ model: 'gpt-4o-realtime-preview',
+ voice: 'alloy',
+ instructions: 'You are a helpful assistant.',
+ turnDetection: {
+ type: 'server_vad',
+ threshold: 0.5,
+ silence_duration_ms: 500,
+ },
+ }),
+})
+```
+
+**Token Structure:**
+```typescript
+interface RealtimeToken {
+ provider: string // 'openai' | 'elevenlabs'
+ token: string // Ephemeral token or signed URL
+ expiresAt: number // Expiration timestamp (ms)
+ config: RealtimeSessionConfig // Session configuration
+}
+```
+
+### 2. Client Adapters (Browser-Side)
+
+Client adapters handle the actual connection to provider APIs, managing:
+- WebRTC or WebSocket connections
+- Audio capture and playback
+- Event translation to common format
+- Audio visualization data
+
+```typescript
+// Client-side adapter usage
+import { openaiRealtime } from '@tanstack/ai-openai'
+
+const adapter = openaiRealtime({
+ connectionMode: 'webrtc', // default
+})
+```
+
+### 3. RealtimeClient
+
+The `RealtimeClient` class manages the connection lifecycle:
+
+- **Connection Management**: Connect, disconnect, reconnect
+- **Token Refresh**: Automatically refreshes tokens before expiry
+- **Event Handling**: Subscribes to adapter events and dispatches to callbacks
+- **State Management**: Tracks status, mode, messages, transcripts
+- **Tool Execution**: Coordinates client-side tool calls
+
+### 4. useRealtimeChat Hook
+
+The React hook provides a reactive interface:
+
+```typescript
+const {
+ // Connection state
+ status, // 'idle' | 'connecting' | 'connected' | 'reconnecting' | 'error'
+ error,
+ connect,
+ disconnect,
+
+ // Conversation state
+ mode, // 'idle' | 'listening' | 'thinking' | 'speaking'
+ messages,
+ pendingUserTranscript,
+ pendingAssistantTranscript,
+
+ // Voice control
+ startListening,
+ stopListening,
+ interrupt,
+
+ // Audio visualization
+ inputLevel,
+ outputLevel,
+ getInputTimeDomainData,
+ getOutputTimeDomainData,
+} = useRealtimeChat({
+ getToken: () => fetch('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/api/realtime-token').then(r => r.json()),
+ adapter: openaiRealtime(),
+})
+```
+
+## Connection Flow
+
+### OpenAI WebRTC Flow
+
+```mermaid
+sequenceDiagram
+ participant Browser
+ participant Server
+ participant OpenAI
+
+ Browser->>Server: POST /api/realtime-token
+ Server->>OpenAI: POST /v1/realtime/sessions
+ OpenAI-->>Server: { client_secret, expires_at }
+ Server-->>Browser: RealtimeToken
+
+ Browser->>Browser: getUserMedia() - request mic
+ Browser->>Browser: Create RTCPeerConnection
+ Browser->>Browser: Add audio track to PC
+ Browser->>Browser: createOffer()
+
+ Browser->>OpenAI: POST /v1/realtime?model=...
+ Note right of Browser: SDP offer + ephemeral token
+ OpenAI-->>Browser: SDP answer
+
+ Browser->>Browser: setRemoteDescription()
+ Note over Browser,OpenAI: WebRTC connection established
+
+ Browser->>OpenAI: Audio via WebRTC
+ OpenAI-->>Browser: Audio + events via WebRTC
+```
+
+### ElevenLabs Flow
+
+```mermaid
+sequenceDiagram
+ participant Browser
+ participant Server
+ participant ElevenLabs
+
+ Browser->>Server: POST /api/realtime-token
+ Server->>ElevenLabs: POST /v1/convai/conversation/get_signed_url
+ ElevenLabs-->>Server: { signed_url }
+ Server-->>Browser: RealtimeToken
+
+ Browser->>ElevenLabs: Conversation.startSession(signedUrl)
+ Note over Browser,ElevenLabs: SDK handles WebSocket/WebRTC
+
+ Browser->>ElevenLabs: Audio via SDK
+ ElevenLabs-->>Browser: Audio + events via SDK
+```
+
+## Audio Visualization
+
+The system provides real-time audio visualization through the `AudioVisualization` interface:
+
+```typescript
+interface AudioVisualization {
+ inputLevel: number // 0-1 normalized input volume (RMS)
+ outputLevel: number // 0-1 normalized output volume (RMS)
+ getInputFrequencyData(): Uint8Array // FFT frequency bins
+ getOutputFrequencyData(): Uint8Array
+ getInputTimeDomainData(): Uint8Array // Raw waveform samples
+ getOutputTimeDomainData(): Uint8Array
+ inputSampleRate: number
+ outputSampleRate: number
+}
+```
+
+The OpenAI adapter uses Web Audio API `AnalyserNode` for visualization:
+- `fftSize: 2048` for high-resolution analysis
+- RMS (Root Mean Square) calculation for accurate volume levels
+- Separate analysers for input (microphone) and output (AI voice)
+
+## Event System
+
+Adapters emit standardized events:
+
+| Event | Payload | Description |
+|-------|---------|-------------|
+| `status_change` | `{ status }` | Connection status changed |
+| `mode_change` | `{ mode }` | Conversation mode changed |
+| `transcript` | `{ role, transcript, isFinal }` | Speech-to-text update |
+| `message_complete` | `{ message }` | Full message received |
+| `tool_call` | `{ toolCallId, toolName, input }` | Tool invocation requested |
+| `interrupted` | `{ messageId? }` | Response was interrupted |
+| `error` | `{ error }` | Error occurred |
+
+## Current Status
+
+### Implemented Features
+
+- [x] OpenAI Realtime API integration (WebRTC)
+- [x] ElevenLabs Conversational AI integration
+- [x] Token generation and refresh
+- [x] Audio capture and playback
+- [x] Real-time transcription display
+- [x] Audio visualization (levels, waveforms)
+- [x] Interrupt capability
+- [x] React hook (`useRealtimeChat`)
+- [x] Demo application at `/realtime` route
+
+### Known Limitations
+
+- **Device Selection**: Currently uses system default audio devices. Custom device selection not yet implemented.
+- **ElevenLabs SDK**: Using `@11labs/client@0.2.0` which has limited TypeScript support.
+- **Push-to-Talk**: Manual VAD mode implemented but not exposed in demo UI.
+- **Tool Calling**: Framework supports tools but demo doesn't showcase them.
+
+### Demo Application
+
+The `examples/ts-react-chat` application includes a realtime voice chat demo at the `/realtime` route:
+
+**Features:**
+- Provider selection (OpenAI / ElevenLabs)
+- Connection status indicator
+- Conversation mode indicator (Listening/Thinking/Speaking)
+- Message history with transcripts
+- Audio level meters
+- Waveform visualization (debug mode)
+- Interrupt button during AI speech
+
+**Required Environment Variables:**
+```bash
+OPENAI_API_KEY=sk-...
+ELEVENLABS_API_KEY=xi-... # Optional, for ElevenLabs
+ELEVENLABS_AGENT_ID=... # Optional, for ElevenLabs
+```
+
+## Files Reference
+
+### Core Types
+- `packages/typescript/ai/src/realtime/types.ts` - Core type definitions
+- `packages/typescript/ai-client/src/realtime-types.ts` - Client-side types
+
+### Token Generation (Server)
+- `packages/typescript/ai/src/realtime/index.ts` - `realtimeToken()` function
+- `packages/typescript/ai-openai/src/realtime/token.ts` - OpenAI token adapter
+- `packages/typescript/ai-elevenlabs/src/realtime/token.ts` - ElevenLabs token adapter
+
+### Client Adapters
+- `packages/typescript/ai-openai/src/realtime/adapter.ts` - OpenAI WebRTC adapter
+- `packages/typescript/ai-elevenlabs/src/realtime/adapter.ts` - ElevenLabs SDK adapter
+
+### Client Library
+- `packages/typescript/ai-client/src/realtime-client.ts` - RealtimeClient class
+
+### React Integration
+- `packages/typescript/ai-react/src/use-realtime-chat.ts` - React hook
+- `packages/typescript/ai-react/src/realtime-types.ts` - Hook types
+
+### Demo Application
+- `examples/ts-react-chat/src/routes/realtime.tsx` - Demo UI component
+- `examples/ts-react-chat/src/routes/api.realtime-token.ts` - Token API endpoint
From 5ad2d2c035afb3426f1f8f3bfd2862186f063b23 Mon Sep 17 00:00:00 2001
From: Jack Herrington
Date: Wed, 21 Jan 2026 16:15:17 -0800
Subject: [PATCH 03/31] more updates
---
.../ts-react-chat/src/lib/realtime-tools.ts | 141 ++++++++++++++++++
.../src/routes/api.realtime-token.ts | 50 ++++++-
.../ts-react-chat/src/routes/realtime.tsx | 95 ++++--------
.../ai-openai/src/realtime/adapter.ts | 29 ++--
4 files changed, 230 insertions(+), 85 deletions(-)
create mode 100644 examples/ts-react-chat/src/lib/realtime-tools.ts
diff --git a/examples/ts-react-chat/src/lib/realtime-tools.ts b/examples/ts-react-chat/src/lib/realtime-tools.ts
new file mode 100644
index 0000000000..2cf28d7bd3
--- /dev/null
+++ b/examples/ts-react-chat/src/lib/realtime-tools.ts
@@ -0,0 +1,141 @@
+import { toolDefinition } from '@tanstack/ai'
+import { z } from 'zod'
+
+// Tool to get current time - useful for voice assistants
+export const getCurrentTimeToolDef = toolDefinition({
+ name: 'getCurrentTime',
+ description: 'Get the current date and time. Use this when the user asks what time it is or the current date.',
+ inputSchema: z.object({
+ timezone: z.string().optional().describe('Optional timezone like "America/New_York" or "Europe/London"'),
+ }),
+ outputSchema: z.object({
+ time: z.string(),
+ date: z.string(),
+ timezone: z.string(),
+ }),
+})
+
+// Tool to get weather - common voice assistant use case
+export const getWeatherToolDef = toolDefinition({
+ name: 'getWeather',
+ description: 'Get the current weather for a location. Use this when the user asks about the weather.',
+ inputSchema: z.object({
+ location: z.string().describe('The city and state/country, e.g. "San Francisco, CA" or "London, UK"'),
+ }),
+ outputSchema: z.object({
+ location: z.string(),
+ temperature: z.number(),
+ unit: z.string(),
+ condition: z.string(),
+ humidity: z.number(),
+ }),
+})
+
+// Tool to set a reminder - demonstrates user interaction
+export const setReminderToolDef = toolDefinition({
+ name: 'setReminder',
+ description: 'Set a reminder for the user. Use this when the user asks to be reminded about something.',
+ inputSchema: z.object({
+ message: z.string().describe('What to remind the user about'),
+ inMinutes: z.number().describe('How many minutes from now to remind'),
+ }),
+ outputSchema: z.object({
+ success: z.boolean(),
+ message: z.string(),
+ remindAt: z.string(),
+ }),
+})
+
+// Tool to search knowledge base - useful for assistants with specific knowledge
+export const searchKnowledgeToolDef = toolDefinition({
+ name: 'searchKnowledge',
+ description: 'Search a knowledge base for information. Use this to find specific facts or documentation.',
+ inputSchema: z.object({
+ query: z.string().describe('The search query'),
+ }),
+ outputSchema: z.object({
+ results: z.array(z.object({
+ title: z.string(),
+ snippet: z.string(),
+ })),
+ }),
+})
+
+// Client-side implementation of getCurrentTime
+export const getCurrentTimeClient = getCurrentTimeToolDef.client(({ timezone }) => {
+ const now = new Date()
+ const tz = timezone || Intl.DateTimeFormat().resolvedOptions().timeZone
+
+ return {
+ time: now.toLocaleTimeString('en-US', { timeZone: tz }),
+ date: now.toLocaleDateString('en-US', {
+ weekday: 'long',
+ year: 'numeric',
+ month: 'long',
+ day: 'numeric',
+ timeZone: tz,
+ }),
+ timezone: tz,
+ }
+})
+
+// Client-side implementation of getWeather (mock data for demo)
+export const getWeatherClient = getWeatherToolDef.client(({ location }) => {
+ // Mock weather data for demo purposes
+ const conditions = ['Sunny', 'Partly Cloudy', 'Cloudy', 'Rainy', 'Snowy']
+ const randomCondition = conditions[Math.floor(Math.random() * conditions.length)]!
+ const randomTemp = Math.floor(Math.random() * 30) + 50 // 50-80°F
+ const randomHumidity = Math.floor(Math.random() * 50) + 30 // 30-80%
+
+ return {
+ location,
+ temperature: randomTemp,
+ unit: 'F',
+ condition: randomCondition,
+ humidity: randomHumidity,
+ }
+})
+
+// Client-side implementation of setReminder
+export const setReminderClient = setReminderToolDef.client(({ message, inMinutes }) => {
+ const remindAt = new Date(Date.now() + inMinutes * 60 * 1000)
+
+ // In a real app, you'd schedule a notification here
+ console.log(`[Reminder] Will remind about "${message}" at ${remindAt.toLocaleTimeString()}`)
+
+ // For demo purposes, show an alert after the specified time
+ setTimeout(() => {
+ alert(`Reminder: ${message}`)
+ }, inMinutes * 60 * 1000)
+
+ return {
+ success: true,
+ message: `Reminder set: "${message}"`,
+ remindAt: remindAt.toLocaleTimeString(),
+ }
+})
+
+// Client-side implementation of searchKnowledge (mock data for demo)
+export const searchKnowledgeClient = searchKnowledgeToolDef.client(({ query }) => {
+ // Mock search results for demo
+ const mockResults = [
+ {
+ title: `Result for: ${query}`,
+ snippet: `This is a mock search result for the query "${query}". In a real application, this would return actual search results from a knowledge base.`,
+ },
+ {
+ title: 'Additional Information',
+ snippet: 'More relevant information would appear here based on your search query.',
+ },
+ ]
+
+ return { results: mockResults }
+})
+
+// Export all client tools as an array for easy use
+export const realtimeClientTools = [
+ getCurrentTimeClient,
+ getWeatherClient,
+ setReminderClient,
+ searchKnowledgeClient,
+] as const
diff --git a/examples/ts-react-chat/src/routes/api.realtime-token.ts b/examples/ts-react-chat/src/routes/api.realtime-token.ts
index 0f7a46bdaa..c9367ad196 100644
--- a/examples/ts-react-chat/src/routes/api.realtime-token.ts
+++ b/examples/ts-react-chat/src/routes/api.realtime-token.ts
@@ -2,9 +2,36 @@ import { createFileRoute } from '@tanstack/react-router'
import { realtimeToken } from '@tanstack/ai'
import { openaiRealtimeToken } from '@tanstack/ai-openai'
import { elevenlabsRealtimeToken } from '@tanstack/ai-elevenlabs'
+import {
+ getCurrentTimeToolDef,
+ getWeatherToolDef,
+ setReminderToolDef,
+ searchKnowledgeToolDef,
+} from '@/lib/realtime-tools'
+import * as z from 'zod'
type Provider = 'openai' | 'elevenlabs'
+// Convert tool definitions to OpenAI's format using Zod's native toJSONSchema
+function toolDefToOpenAI(toolDef: { name: string; description: string; inputSchema?: unknown }) {
+ let parameters: Record = { type: 'object', properties: {} }
+
+ if (toolDef.inputSchema) {
+ // Use Zod's native toJSONSchema for Zod v4+
+ const jsonSchema = z.toJSONSchema(toolDef.inputSchema as z.ZodType)
+ // Remove $schema as OpenAI doesn't need it
+ const { $schema, ...rest } = jsonSchema as Record
+ parameters = rest
+ }
+
+ return {
+ type: 'function' as const,
+ name: toolDef.name,
+ description: toolDef.description,
+ parameters,
+ }
+}
+
export const Route = createFileRoute('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/api/realtime-token')({
server: {
handlers: {
@@ -16,14 +43,29 @@ export const Route = createFileRoute('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/api/realtime-token')({
let token
if (provider === 'openai') {
+ // Convert tool definitions to OpenAI format
+ const tools = [
+ toolDefToOpenAI(getCurrentTimeToolDef),
+ toolDefToOpenAI(getWeatherToolDef),
+ toolDefToOpenAI(setReminderToolDef),
+ toolDefToOpenAI(searchKnowledgeToolDef),
+ ]
+
token = await realtimeToken({
adapter: openaiRealtimeToken({
model: 'gpt-4o-realtime-preview',
voice: 'alloy',
- instructions: `You are a helpful, friendly assistant.
-
+ instructions: `You are a helpful, friendly voice assistant with access to several tools.
+
+You can:
+- Tell the user the current time and date (getCurrentTime)
+- Get weather information for any location (getWeather)
+- Set reminders for the user (setReminder)
+- Search a knowledge base for information (searchKnowledge)
+
Keep your responses concise and conversational since this is a voice interface.
-Be natural and engaging in your responses.`,
+When using tools, briefly explain what you're doing and then share the results naturally.
+Be friendly and engaging!`,
turnDetection: {
type: 'server_vad',
threshold: 0.5,
@@ -33,6 +75,8 @@ Be natural and engaging in your responses.`,
inputAudioTranscription: {
model: 'whisper-1',
},
+ tools,
+ toolChoice: 'auto',
}),
})
} else if (provider === 'elevenlabs') {
diff --git a/examples/ts-react-chat/src/routes/realtime.tsx b/examples/ts-react-chat/src/routes/realtime.tsx
index fcc954cb16..4be974a8fc 100644
--- a/examples/ts-react-chat/src/routes/realtime.tsx
+++ b/examples/ts-react-chat/src/routes/realtime.tsx
@@ -3,7 +3,8 @@ import { createFileRoute } from '@tanstack/react-router'
import { useRealtimeChat } from '@tanstack/ai-react'
import { openaiRealtime } from '@tanstack/ai-openai'
import { elevenlabsRealtime } from '@tanstack/ai-elevenlabs'
-import { Mic, MicOff, Phone, PhoneOff, Volume2 } from 'lucide-react'
+import { Mic, MicOff, Phone, PhoneOff, Volume2, Wrench } from 'lucide-react'
+import { realtimeClientTools } from '@/lib/realtime-tools'
type Provider = 'openai' | 'elevenlabs'
@@ -98,56 +99,9 @@ function AudioSparkline({
)
}
-// Debug component to show raw audio data stats
-function AudioDebug({
- getData,
- label
-}: {
- getData: () => Uint8Array
- label: string
-}) {
- const [stats, setStats] = useState({ length: 0, min: 0, max: 0, allSame: true, sample: '[]' })
-
- useEffect(() => {
- function update() {
- const data = getData()
- const min = Math.min(...data)
- const max = Math.max(...data)
- const allSame = data.every(v => v === data[0])
- // Get a few samples from different parts of the array
- const samples = data.length > 0 ? [
- data[0],
- data[Math.floor(data.length / 4)],
- data[Math.floor(data.length / 2)],
- data[Math.floor(data.length * 3 / 4)],
- data[data.length - 1]
- ] : []
- setStats({
- length: data.length,
- min,
- max,
- allSame,
- sample: `[${samples.join(', ')}]`
- })
- requestAnimationFrame(update)
- }
- const id = requestAnimationFrame(update)
- return () => cancelAnimationFrame(id)
- }, [getData])
-
- return (
-
- {label}: len={stats.length}, min={stats.min}, max={stats.max},
- {stats.allSame ? ALL SAME! : varying }
- {stats.sample}
-
- )
-}
-
function RealtimePage() {
const [provider, setProvider] = useState('openai')
const [agentId, setAgentId] = useState('')
- const [showDebug, setShowDebug] = useState(true)
const messagesEndRef = useRef(null)
// Get the appropriate adapter based on provider
@@ -165,7 +119,6 @@ function RealtimePage() {
interrupt,
inputLevel,
outputLevel,
- sendText,
getInputTimeDomainData,
getOutputTimeDomainData,
} = useRealtimeChat({
@@ -186,6 +139,8 @@ function RealtimePage() {
return response.json()
},
adapter,
+ // Pass the client tools - these execute locally when the AI calls them
+ tools: realtimeClientTools,
onError: (err) => {
console.error('Realtime error:', err)
},
@@ -302,15 +257,35 @@ function RealtimePage() {
+ {/* Tools indicator */}
+ {provider === 'openai' && (
+
+
+
+ Tools enabled:
+ getCurrentTime
+ •
+ getWeather
+ •
+ setReminder
+ •
+ searchKnowledge
+
+
+ )}
+
{/* Messages area */}
{messages.length === 0 && status === 'idle' && (
-
Voice Chat
+
Voice Chat with Tools
Click "Start Conversation" to begin talking with the AI
+
+ Try asking: "What time is it?" or "What's the weather in San Francisco?"
+
)}
@@ -437,26 +412,6 @@ function RealtimePage() {
label="Output"
/>
-
- {/* Debug info */}
- {showDebug && (
-
-
- Audio Debug
- setShowDebug(false)}
- className="text-xs text-gray-500 hover:text-gray-400"
- >
- Hide
-
-
-
-
-
- inputLevel: {inputLevel.toFixed(4)}, outputLevel: {outputLevel.toFixed(4)}
-
-
- )}
)}
diff --git a/packages/typescript/ai-openai/src/realtime/adapter.ts b/packages/typescript/ai-openai/src/realtime/adapter.ts
index 51745a26cd..645a5e7168 100644
--- a/packages/typescript/ai-openai/src/realtime/adapter.ts
+++ b/packages/typescript/ai-openai/src/realtime/adapter.ts
@@ -513,33 +513,38 @@ async function createWebRTCConnection(
// Log analyser state for debugging
console.log('[Realtime] getAudioVisualization called, inputAnalyser:', !!inputAnalyser, 'outputAnalyser:', !!outputAnalyser)
- // Helper to calculate RMS (Root Mean Square) from time domain data
- // This gives a better measure of perceived loudness than frequency data
- function calculateRMS(analyser: AnalyserNode): number {
+ // Helper to calculate audio level from time domain data
+ // Uses peak amplitude which is more responsive for voice audio meters
+ function calculateLevel(analyser: AnalyserNode): number {
const data = new Uint8Array(analyser.fftSize)
analyser.getByteTimeDomainData(data)
- // Calculate RMS - values are 0-255 with 128 being silence
- let sumSquares = 0
+ // Find peak deviation from center (128 is silence)
+ // This is more responsive than RMS for voice level meters
+ let maxDeviation = 0
for (const sample of data) {
- const normalized = (sample - 128) / 128 // Convert to -1 to 1 range
- sumSquares += normalized * normalized
+ const deviation = Math.abs(sample - 128)
+ if (deviation > maxDeviation) {
+ maxDeviation = deviation
+ }
}
- const rms = Math.sqrt(sumSquares / data.length)
- // Scale and clamp to 0-1 range (RMS of full-scale sine is ~0.707)
- return Math.min(1, rms * 1.5)
+ // Normalize to 0-1 range (max deviation is 128)
+ // Scale by 1.5x so that ~66% amplitude reads as full scale
+ // This provides good visual feedback without pegging too early
+ const normalized = maxDeviation / 128
+ return Math.min(1, normalized * 1.5)
}
return {
get inputLevel() {
if (!inputAnalyser) return 0
- return calculateRMS(inputAnalyser)
+ return calculateLevel(inputAnalyser)
},
get outputLevel() {
if (!outputAnalyser) return 0
- return calculateRMS(outputAnalyser)
+ return calculateLevel(outputAnalyser)
},
getInputFrequencyData() {
From 41a5e97ff987c6992a847535db54ca16f768b4f0 Mon Sep 17 00:00:00 2001
From: Jack Herrington
Date: Thu, 19 Feb 2026 10:18:57 -0800
Subject: [PATCH 04/31] chore: update pnpm-lock.yaml and latest realtime chat
changes
Co-Authored-By: Warp
---
.changeset/realtime-chat.md | 11 ++
examples/ts-react-chat/package.json | 2 +-
.../ai-client/src/realtime-client.ts | 2 +-
.../ai-client/src/realtime-types.ts | 28 ++---
.../typescript/ai-elevenlabs/package.json | 2 +-
.../ai-elevenlabs/src/realtime/adapter.ts | 16 +--
.../ai-elevenlabs/src/realtime/token.ts | 2 +-
.../ai-elevenlabs/src/realtime/types.ts | 7 --
.../ai-openai/src/realtime/adapter.ts | 14 +--
.../ai-openai/src/realtime/token.ts | 4 +-
.../typescript/ai-react/src/realtime-types.ts | 2 +-
packages/typescript/ai/src/realtime/types.ts | 22 ++--
pnpm-lock.yaml | 115 ++++++++++++++++++
13 files changed, 173 insertions(+), 54 deletions(-)
create mode 100644 .changeset/realtime-chat.md
diff --git a/.changeset/realtime-chat.md b/.changeset/realtime-chat.md
new file mode 100644
index 0000000000..11cc3cca14
--- /dev/null
+++ b/.changeset/realtime-chat.md
@@ -0,0 +1,11 @@
+---
+'@tanstack/ai': minor
+'@tanstack/ai-client': minor
+'@tanstack/ai-openai': minor
+'@tanstack/ai-elevenlabs': minor
+'@tanstack/ai-react': minor
+---
+
+feat: add realtime chat support with OpenAI and ElevenLabs adapters
+
+Adds realtime voice/text chat capabilities including a provider-agnostic realtime client, OpenAI Realtime API adapter, ElevenLabs conversational AI adapter, React `useRealtimeChat` hook, and shared realtime types across the core, client, and framework packages.
diff --git a/examples/ts-react-chat/package.json b/examples/ts-react-chat/package.json
index cd160a2f8f..9580b8e769 100644
--- a/examples/ts-react-chat/package.json
+++ b/examples/ts-react-chat/package.json
@@ -13,11 +13,11 @@
"@tanstack/ai": "workspace:*",
"@tanstack/ai-anthropic": "workspace:*",
"@tanstack/ai-client": "workspace:*",
+ "@tanstack/ai-elevenlabs": "workspace:*",
"@tanstack/ai-gemini": "workspace:*",
"@tanstack/ai-grok": "workspace:*",
"@tanstack/ai-ollama": "workspace:*",
"@tanstack/ai-openai": "workspace:*",
- "@tanstack/ai-elevenlabs": "workspace:*",
"@tanstack/ai-openrouter": "workspace:*",
"@tanstack/ai-react": "workspace:*",
"@tanstack/ai-react-ui": "workspace:*",
diff --git a/packages/typescript/ai-client/src/realtime-client.ts b/packages/typescript/ai-client/src/realtime-client.ts
index 0672fe23eb..f49d4d25ea 100644
--- a/packages/typescript/ai-client/src/realtime-client.ts
+++ b/packages/typescript/ai-client/src/realtime-client.ts
@@ -1,11 +1,11 @@
import type {
+ AnyClientTool,
AudioVisualization,
RealtimeMessage,
RealtimeMode,
RealtimeStatus,
RealtimeToken,
} from '@tanstack/ai'
-import type { AnyClientTool } from '@tanstack/ai'
import type {
RealtimeClientOptions,
RealtimeClientState,
diff --git a/packages/typescript/ai-client/src/realtime-types.ts b/packages/typescript/ai-client/src/realtime-types.ts
index 3393ee92c6..4ff6bf9bd5 100644
--- a/packages/typescript/ai-client/src/realtime-types.ts
+++ b/packages/typescript/ai-client/src/realtime-types.ts
@@ -1,4 +1,5 @@
import type {
+ AnyClientTool,
AudioVisualization,
RealtimeEvent,
RealtimeEventHandler,
@@ -8,7 +9,6 @@ import type {
RealtimeStatus,
RealtimeToken,
} from '@tanstack/ai'
-import type { AnyClientTool } from '@tanstack/ai'
// ============================================================================
// Adapter Interface
@@ -27,7 +27,7 @@ export interface RealtimeAdapter {
* @param token - The ephemeral token from the server
* @returns A connection instance
*/
- connect(token: RealtimeToken): Promise
+ connect: (token: RealtimeToken) => Promise
}
/**
@@ -37,38 +37,38 @@ export interface RealtimeAdapter {
export interface RealtimeConnection {
// Lifecycle
/** Disconnect from the realtime session */
- disconnect(): Promise
+ disconnect: () => Promise
// Audio I/O
/** Start capturing audio from the microphone */
- startAudioCapture(): Promise
+ startAudioCapture: () => Promise
/** Stop capturing audio */
- stopAudioCapture(): void
+ stopAudioCapture: () => void
// Text input
/** Send a text message (fallback for when voice isn't available) */
- sendText(text: string): void
+ sendText: (text: string) => void
// Tool results
/** Send a tool execution result back to the provider */
- sendToolResult(callId: string, result: string): void
+ sendToolResult: (callId: string, result: string) => void
// Session management
/** Update session configuration */
- updateSession(config: Partial): void
+ updateSession: (config: Partial) => void
/** Interrupt the current response */
- interrupt(): void
+ interrupt: () => void
// Events
/** Subscribe to connection events */
- on(
- event: E,
- handler: RealtimeEventHandler,
- ): () => void
+ on: (
+ event: TEvent,
+ handler: RealtimeEventHandler,
+ ) => () => void
// Audio visualization
/** Get audio visualization data */
- getAudioVisualization(): AudioVisualization
+ getAudioVisualization: () => AudioVisualization
}
// ============================================================================
diff --git a/packages/typescript/ai-elevenlabs/package.json b/packages/typescript/ai-elevenlabs/package.json
index 0edafe92a4..4ff1754e8d 100644
--- a/packages/typescript/ai-elevenlabs/package.json
+++ b/packages/typescript/ai-elevenlabs/package.json
@@ -36,7 +36,7 @@
"lint:fix": "eslint ./src --fix",
"test:build": "publint --strict",
"test:eslint": "eslint ./src",
- "test:lib": "vitest",
+ "test:lib": "vitest --passWithNoTests",
"test:lib:dev": "pnpm test:lib --watch",
"test:types": "tsc"
},
diff --git a/packages/typescript/ai-elevenlabs/src/realtime/adapter.ts b/packages/typescript/ai-elevenlabs/src/realtime/adapter.ts
index cb193485ca..39ee355bdb 100644
--- a/packages/typescript/ai-elevenlabs/src/realtime/adapter.ts
+++ b/packages/typescript/ai-elevenlabs/src/realtime/adapter.ts
@@ -59,9 +59,9 @@ async function createElevenLabsConnection(
const emptyTimeDomainData = new Uint8Array(128).fill(128)
// Helper to emit events
- function emit(
- event: E,
- payload: Parameters>[0],
+ function emit(
+ event: TEvent,
+ payload: Parameters>[0],
) {
const handlers = eventHandlers.get(event)
if (handlers) {
@@ -145,7 +145,7 @@ async function createElevenLabsConnection(
emit('mode_change', { mode: 'idle' })
},
- sendText(text: string) {
+ sendText(_text: string) {
// ElevenLabs doesn't support direct text input in the same way
// The SDK is voice-first. Log a warning.
console.warn(
@@ -153,7 +153,7 @@ async function createElevenLabsConnection(
)
},
- sendToolResult(callId: string, result: string) {
+ sendToolResult(_callId: string, _result: string) {
// ElevenLabs handles client tools differently - they're registered at session start
console.warn(
'ElevenLabs tool results are handled via clientTools option during session creation.',
@@ -174,9 +174,9 @@ async function createElevenLabsConnection(
emit('interrupted', {})
},
- on(
- event: E,
- handler: RealtimeEventHandler,
+ on(
+ event: TEvent,
+ handler: RealtimeEventHandler,
): () => void {
if (!eventHandlers.has(event)) {
eventHandlers.set(event, new Set())
diff --git a/packages/typescript/ai-elevenlabs/src/realtime/token.ts b/packages/typescript/ai-elevenlabs/src/realtime/token.ts
index 99989b06b7..030d0c9a95 100644
--- a/packages/typescript/ai-elevenlabs/src/realtime/token.ts
+++ b/packages/typescript/ai-elevenlabs/src/realtime/token.ts
@@ -8,7 +8,7 @@ const ELEVENLABS_API_URL = 'https://api.elevenlabs.io/v1'
*/
function getElevenLabsApiKey(): string {
// Check process.env (Node.js)
- if (typeof process !== 'undefined' && process.env?.ELEVENLABS_API_KEY) {
+ if (typeof process !== 'undefined' && process.env.ELEVENLABS_API_KEY) {
return process.env.ELEVENLABS_API_KEY
}
diff --git a/packages/typescript/ai-elevenlabs/src/realtime/types.ts b/packages/typescript/ai-elevenlabs/src/realtime/types.ts
index ff2166f088..c3f5227f7f 100644
--- a/packages/typescript/ai-elevenlabs/src/realtime/types.ts
+++ b/packages/typescript/ai-elevenlabs/src/realtime/types.ts
@@ -53,10 +53,3 @@ export interface ElevenLabsClientTool {
/** Tool handler function */
handler: (params: TParams) => Promise | TResult
}
-
-/**
- * ElevenLabs signed URL response
- */
-export interface ElevenLabsSignedUrlResponse {
- signed_url: string
-}
diff --git a/packages/typescript/ai-openai/src/realtime/adapter.ts b/packages/typescript/ai-openai/src/realtime/adapter.ts
index 645a5e7168..6245a3c05c 100644
--- a/packages/typescript/ai-openai/src/realtime/adapter.ts
+++ b/packages/typescript/ai-openai/src/realtime/adapter.ts
@@ -88,9 +88,9 @@ async function createWebRTCConnection(
const emptyTimeDomainData = new Uint8Array(2048).fill(128) // 128 is silence
// Helper to emit events (defined early so it can be used during setup)
- function emit(
- event: E,
- payload: Parameters>[0],
+ function emit(
+ event: TEvent,
+ payload: Parameters>[0],
) {
const handlers = eventHandlers.get(event)
if (handlers) {
@@ -264,7 +264,7 @@ async function createWebRTCConnection(
// Emit message complete if we have a current message
if (currentMessageId) {
const response = event.response as Record
- const output = response.output as Array>
+ const output = response.output as Array> | undefined
const message: RealtimeMessage = {
id: currentMessageId,
@@ -495,9 +495,9 @@ async function createWebRTCConnection(
emit('interrupted', { messageId: currentMessageId ?? undefined })
},
- on(
- event: E,
- handler: RealtimeEventHandler,
+ on(
+ event: TEvent,
+ handler: RealtimeEventHandler,
): () => void {
if (!eventHandlers.has(event)) {
eventHandlers.set(event, new Set())
diff --git a/packages/typescript/ai-openai/src/realtime/token.ts b/packages/typescript/ai-openai/src/realtime/token.ts
index d226cacbba..e09d8c7668 100644
--- a/packages/typescript/ai-openai/src/realtime/token.ts
+++ b/packages/typescript/ai-openai/src/realtime/token.ts
@@ -1,5 +1,5 @@
+import { getOpenAIApiKeyFromEnv } from '../utils/client'
import type { RealtimeToken, RealtimeTokenAdapter, Tool } from '@tanstack/ai'
-import { getOpenAIApiKeyFromEnv } from '../utils'
import type {
OpenAIRealtimeModel,
OpenAIRealtimeSessionResponse,
@@ -111,7 +111,7 @@ export function openaiRealtimeToken(
const sessionData: OpenAIRealtimeSessionResponse = await response.json()
// Convert tools to our format
- const tools: Array = (sessionData.tools || []).map((t) => ({
+ const tools: Array = sessionData.tools.map((t) => ({
name: t.name,
description: t.description,
inputSchema: t.parameters,
diff --git a/packages/typescript/ai-react/src/realtime-types.ts b/packages/typescript/ai-react/src/realtime-types.ts
index f3a403464e..9b44269d9e 100644
--- a/packages/typescript/ai-react/src/realtime-types.ts
+++ b/packages/typescript/ai-react/src/realtime-types.ts
@@ -1,11 +1,11 @@
import type {
+ AnyClientTool,
RealtimeMessage,
RealtimeMode,
RealtimeStatus,
RealtimeToken,
} from '@tanstack/ai'
import type { RealtimeAdapter } from '@tanstack/ai-client'
-import type { AnyClientTool } from '@tanstack/ai'
/**
* Options for the useRealtimeChat hook.
diff --git a/packages/typescript/ai/src/realtime/types.ts b/packages/typescript/ai/src/realtime/types.ts
index e563a2ae75..8a4be3a98a 100644
--- a/packages/typescript/ai/src/realtime/types.ts
+++ b/packages/typescript/ai/src/realtime/types.ts
@@ -57,7 +57,7 @@ export interface RealtimeTokenAdapter {
/** Provider identifier */
provider: string
/** Generate an ephemeral token for client use */
- generateToken(): Promise
+ generateToken: () => Promise
}
/**
@@ -176,14 +176,14 @@ export interface AudioVisualization {
readonly outputLevel: number
/** Get frequency data for input audio visualization */
- getInputFrequencyData(): Uint8Array
+ getInputFrequencyData: () => Uint8Array
/** Get frequency data for output audio visualization */
- getOutputFrequencyData(): Uint8Array
+ getOutputFrequencyData: () => Uint8Array
/** Get time domain data for input waveform */
- getInputTimeDomainData(): Uint8Array
+ getInputTimeDomainData: () => Uint8Array
/** Get time domain data for output waveform */
- getOutputTimeDomainData(): Uint8Array
+ getOutputTimeDomainData: () => Uint8Array
/** Input sample rate */
readonly inputSampleRate: number
@@ -191,13 +191,13 @@ export interface AudioVisualization {
readonly outputSampleRate: number
/** Subscribe to raw input audio samples */
- onInputAudio?(
+ onInputAudio?: (
callback: (samples: Float32Array, sampleRate: number) => void,
- ): () => void
+ ) => () => void
/** Subscribe to raw output audio samples */
- onOutputAudio?(
+ onOutputAudio?: (
callback: (samples: Float32Array, sampleRate: number) => void,
- ): () => void
+ ) => () => void
}
// ============================================================================
@@ -238,8 +238,8 @@ export interface RealtimeEventPayloads {
/**
* Handler type for realtime events
*/
-export type RealtimeEventHandler = (
- payload: RealtimeEventPayloads[E],
+export type RealtimeEventHandler = (
+ payload: RealtimeEventPayloads[TEvent],
) => void
// ============================================================================
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 9b669fda9e..cb260e5697 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -201,6 +201,9 @@ importers:
'@tanstack/ai-client':
specifier: workspace:*
version: link:../../packages/typescript/ai-client
+ '@tanstack/ai-elevenlabs':
+ specifier: workspace:*
+ version: link:../../packages/typescript/ai-elevenlabs
'@tanstack/ai-gemini':
specifier: workspace:*
version: link:../../packages/typescript/ai-gemini
@@ -743,6 +746,22 @@ importers:
specifier: ^2.11.10
version: 2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@25.0.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+ packages/typescript/ai-elevenlabs:
+ dependencies:
+ '@11labs/client':
+ specifier: ^0.2.0
+ version: 0.2.0(@types/dom-mediacapture-record@1.0.22)
+ devDependencies:
+ '@tanstack/ai':
+ specifier: workspace:*
+ version: link:../ai
+ '@tanstack/ai-client':
+ specifier: workspace:*
+ version: link:../ai-client
+ '@vitest/coverage-v8':
+ specifier: 4.0.14
+ version: 4.0.14(vitest@4.0.18(@types/node@25.0.1)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+
packages/typescript/ai-fal:
dependencies:
'@fal-ai/client':
@@ -819,6 +838,9 @@ importers:
'@tanstack/ai':
specifier: workspace:*
version: link:../ai
+ '@tanstack/ai-client':
+ specifier: workspace:*
+ version: link:../ai-client
'@vitest/coverage-v8':
specifier: 4.0.14
version: 4.0.14(vitest@4.0.18(@types/node@25.0.1)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
@@ -1409,6 +1431,10 @@ importers:
packages:
+ '@11labs/client@0.2.0':
+ resolution: {integrity: sha512-GBplAV4WDbcoThsIzdSDPN3xbcitK0ZZ4iJfJZKfltqvgvS6Uw8GZxHwVgiPwnQoA3uosYyY3L9TuPwmel18xQ==}
+ deprecated: This package is no longer maintained. Please use @elevenlabs/client for the latest version
+
'@acemir/cssom@0.9.29':
resolution: {integrity: sha512-G90x0VW+9nW4dFajtjCoT+NM0scAfH9Mb08IcjgFHYbfiL/lU04dTF9JuVOi3/OH+DJCQdcIseSXkdCB9Ky6JA==}
@@ -1601,6 +1627,9 @@ packages:
resolution: {integrity: sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==}
engines: {node: '>=18'}
+ '@bufbuild/protobuf@1.10.1':
+ resolution: {integrity: sha512-wJ8ReQbHxsAfXhrf9ixl0aYbZorRuOWpBNzm8pL8ftmSxQx/wnJD5Eg861NwJU/czy2VXFIebCeZnZrI9rktIQ==}
+
'@changesets/apply-release-plan@7.0.14':
resolution: {integrity: sha512-ddBvf9PHdy2YY0OUiEl3TV78mH9sckndJR14QAt87KLEbIov81XO0q0QAmvooBxXlqRRP8I9B7XOzZwQG7JkWA==}
@@ -2474,6 +2503,12 @@ packages:
'@jridgewell/trace-mapping@0.3.31':
resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==}
+ '@livekit/mutex@1.1.1':
+ resolution: {integrity: sha512-EsshAucklmpuUAfkABPxJNhzj9v2sG7JuzFDL4ML1oJQSV14sqrpTYnsaOudMAw9yOaW53NU3QQTlUQoRs4czw==}
+
+ '@livekit/protocol@1.44.0':
+ resolution: {integrity: sha512-/vfhDUGcUKO8Q43r6i+5FrDhl5oZjm/X3U4x2Iciqvgn5C8qbj+57YPcWSJ1kyIZm5Cm6AV2nAPjMm3ETD/iyg==}
+
'@manypkg/find-root@1.1.0':
resolution: {integrity: sha512-mki5uBvhHzO8kYYix/WRy2WX8S3B5wdVSc9D6KcU5lQNglP2yt58/VfLuAK49glRXChosY8ap2oJ1qgma3GUVA==}
@@ -4367,6 +4402,9 @@ packages:
'@types/deep-eql@4.0.2':
resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==}
+ '@types/dom-mediacapture-record@1.0.22':
+ resolution: {integrity: sha512-mUMZLK3NvwRLcAAT9qmcK+9p7tpU2FHdDsntR3YI4+GY88XrgG4XiE7u1Q2LAN2/FZOz/tdMDC3GQCR4T8nFuw==}
+
'@types/estree-jsx@1.0.5':
resolution: {integrity: sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==}
@@ -6555,6 +6593,9 @@ packages:
jju@1.4.0:
resolution: {integrity: sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA==}
+ jose@6.1.3:
+ resolution: {integrity: sha512-0TpaTfihd4QMNwrz/ob2Bp7X04yuxJkjRGi4aKmOqwhov54i6u79oCv7T+C7lo70MKH6BesI3vscD1yb/yzKXQ==}
+
js-beautify@1.15.4:
resolution: {integrity: sha512-9/KXeZUKKJwqCXUdBxFJ3vPh467OCckSBmYDwSK/EtV090K+iMJ7zx2S3HLVDIWFQdqMIsZWbnaGiba18aWhaA==}
engines: {node: '>=14'}
@@ -6758,6 +6799,11 @@ packages:
resolution: {integrity: sha512-I8oW2+QL5KJo8zXNWX046M134WchxsXC7SawLPvRQpogCbkyQIaFxPE89A2HiwR7vAK2Dm2ERBAmyjTYGYEpBg==}
hasBin: true
+ livekit-client@2.17.2:
+ resolution: {integrity: sha512-+67y2EtAWZabARlY7kANl/VT1Uu1EJYR5a8qwpT2ub/uBCltsEgEDOxCIMwE9HFR5w+z41HR6GL9hyEvW/y6CQ==}
+ peerDependencies:
+ '@types/dom-mediacapture-record': ^1
+
local-pkg@0.5.1:
resolution: {integrity: sha512-9rrA30MRRP3gBD3HTGnC6cDFpaE1kVDWxWgqWJUN0RvDNAo+Nz/9GxB+nHOH0ifbVFy0hSA1V6vFDvnx54lTEQ==}
engines: {node: '>=14'}
@@ -6796,6 +6842,10 @@ packages:
resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==}
engines: {node: '>=10'}
+ loglevel@1.9.2:
+ resolution: {integrity: sha512-HgMmCqIJSAKqo68l0rS2AanEWfkxaZ5wNiEFb5ggm08lDs9Xl2KxBlX3PTcaD2chBM1gXAYf491/M2Rv8Jwayg==}
+ engines: {node: '>= 0.6.0'}
+
longest-streak@3.1.0:
resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==}
@@ -7861,6 +7911,13 @@ packages:
scule@1.3.0:
resolution: {integrity: sha512-6FtHJEvt+pVMIB9IBY+IcCJ6Z5f1iQnytgyfKMhDKgmzYG+TeH/wx1y3l27rshSbLiSanrR9ffZDrEsmjlQF2g==}
+ sdp-transform@2.15.0:
+ resolution: {integrity: sha512-KrOH82c/W+GYQ0LHqtr3caRpM3ITglq3ljGUIb8LTki7ByacJZ9z+piSGiwZDsRyhQbYBOBJgr2k6X4BZXi3Kw==}
+ hasBin: true
+
+ sdp@3.2.1:
+ resolution: {integrity: sha512-lwsAIzOPlH8/7IIjjz3K0zYBk7aBVVcvjMwt3M4fLxpjMYyy7i3I97SLHebgn4YBjirkzfp3RvRDWSKsh/+WFw==}
+
semver@6.3.1:
resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==}
hasBin: true
@@ -8339,6 +8396,9 @@ packages:
peerDependencies:
typescript: '>=4.8.4'
+ ts-debounce@4.0.0:
+ resolution: {integrity: sha512-+1iDGY6NmOGidq7i7xZGA4cm8DAa6fqdYcvO5Z6yBevH++Bdo9Qt/mN0TzHUgcCcKv1gmh9+W5dHqz8pMWbCbg==}
+
ts-declaration-location@1.0.7:
resolution: {integrity: sha512-EDyGAwH1gO0Ausm9gV6T2nUvBgXT5kGoCMJPllOaooZ+4VvJiKBdZE7wK18N1deEowhcUptS+5GXZK8U/fvpwA==}
peerDependencies:
@@ -8408,6 +8468,9 @@ packages:
resolution: {integrity: sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==}
engines: {node: '>= 0.6'}
+ typed-emitter@2.1.0:
+ resolution: {integrity: sha512-g/KzbYKbH5C2vPkaXGu8DJlHrGKHLsM25Zg9WuC9pMGfuvT+X25tZQWo5fK1BjBm8+UrVE9LDCvaY0CQk+fXDA==}
+
typedoc-plugin-frontmatter@1.3.0:
resolution: {integrity: sha512-xYQFMAecMlsRUjmf9oM/Sq2FVz4zlgcbIeVFNLdO118CHTN06gIKJNSlyExh9+Xl8sK0YhIvoQwViUURxritWA==}
peerDependencies:
@@ -9105,6 +9168,10 @@ packages:
webpack-virtual-modules@0.6.2:
resolution: {integrity: sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==}
+ webrtc-adapter@9.0.3:
+ resolution: {integrity: sha512-5fALBcroIl31OeXAdd1YUntxiZl1eHlZZWzNg3U4Fn+J9/cGL3eT80YlrsWGvj2ojuz1rZr2OXkgCzIxAZ7vRQ==}
+ engines: {node: '>=6.0.0', npm: '>=3.10.0'}
+
whatwg-encoding@3.1.1:
resolution: {integrity: sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==}
engines: {node: '>=18'}
@@ -9259,6 +9326,12 @@ packages:
snapshots:
+ '@11labs/client@0.2.0(@types/dom-mediacapture-record@1.0.22)':
+ dependencies:
+ livekit-client: 2.17.2(@types/dom-mediacapture-record@1.0.22)
+ transitivePeerDependencies:
+ - '@types/dom-mediacapture-record'
+
'@acemir/cssom@0.9.29': {}
'@alcyone-labs/zod-to-json-schema@4.0.10(zod@4.2.1)':
@@ -9508,6 +9581,8 @@ snapshots:
'@bcoe/v8-coverage@1.0.2': {}
+ '@bufbuild/protobuf@1.10.1': {}
+
'@changesets/apply-release-plan@7.0.14':
dependencies:
'@changesets/config': 3.1.2
@@ -10180,6 +10255,12 @@ snapshots:
'@jridgewell/resolve-uri': 3.1.2
'@jridgewell/sourcemap-codec': 1.5.5
+ '@livekit/mutex@1.1.1': {}
+
+ '@livekit/protocol@1.44.0':
+ dependencies:
+ '@bufbuild/protobuf': 1.10.1
+
'@manypkg/find-root@1.1.0':
dependencies:
'@babel/runtime': 7.28.4
@@ -12648,6 +12729,8 @@ snapshots:
'@types/deep-eql@4.0.2': {}
+ '@types/dom-mediacapture-record@1.0.22': {}
+
'@types/estree-jsx@1.0.5':
dependencies:
'@types/estree': 1.0.8
@@ -15291,6 +15374,8 @@ snapshots:
jju@1.4.0: {}
+ jose@6.1.3: {}
+
js-beautify@1.15.4:
dependencies:
config-chain: 1.1.13
@@ -15510,6 +15595,20 @@ snapshots:
untun: 0.1.3
uqr: 0.1.2
+ livekit-client@2.17.2(@types/dom-mediacapture-record@1.0.22):
+ dependencies:
+ '@livekit/mutex': 1.1.1
+ '@livekit/protocol': 1.44.0
+ '@types/dom-mediacapture-record': 1.0.22
+ events: 3.3.0
+ jose: 6.1.3
+ loglevel: 1.9.2
+ sdp-transform: 2.15.0
+ ts-debounce: 4.0.0
+ tslib: 2.8.1
+ typed-emitter: 2.1.0
+ webrtc-adapter: 9.0.3
+
local-pkg@0.5.1:
dependencies:
mlly: 1.8.0
@@ -15546,6 +15645,8 @@ snapshots:
chalk: 4.1.2
is-unicode-supported: 0.1.0
+ loglevel@1.9.2: {}
+
longest-streak@3.1.0: {}
lowlight@3.3.0:
@@ -17166,6 +17267,10 @@ snapshots:
scule@1.3.0: {}
+ sdp-transform@2.15.0: {}
+
+ sdp@3.2.1: {}
+
semver@6.3.1: {}
semver@7.5.4:
@@ -17667,6 +17772,8 @@ snapshots:
dependencies:
typescript: 5.9.3
+ ts-debounce@4.0.0: {}
+
ts-declaration-location@1.0.7(typescript@5.9.3):
dependencies:
picomatch: 4.0.3
@@ -17734,6 +17841,10 @@ snapshots:
media-typer: 1.1.0
mime-types: 3.0.2
+ typed-emitter@2.1.0:
+ optionalDependencies:
+ rxjs: 7.8.2
+
typedoc-plugin-frontmatter@1.3.0(typedoc-plugin-markdown@4.9.0(typedoc@0.28.14(typescript@5.9.3))):
dependencies:
typedoc-plugin-markdown: 4.9.0(typedoc@0.28.14(typescript@5.9.3))
@@ -18509,6 +18620,10 @@ snapshots:
webpack-virtual-modules@0.6.2: {}
+ webrtc-adapter@9.0.3:
+ dependencies:
+ sdp: 3.2.1
+
whatwg-encoding@3.1.1:
dependencies:
iconv-lite: 0.6.3
From aa48ba285f9db6b511a9d54c67d9643572829356 Mon Sep 17 00:00:00 2001
From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com>
Date: Thu, 19 Feb 2026 18:21:02 +0000
Subject: [PATCH 05/31] ci: apply automated fixes
---
.../ts-react-chat/src/lib/realtime-tools.ts | 146 +++++++++++-------
.../src/routes/api.realtime-token.ts | 13 +-
.../ts-react-chat/src/routes/realtime.tsx | 40 ++---
.../ai-client/src/realtime-client.ts | 51 +++---
packages/typescript/ai-elevenlabs/README.md | 2 +-
.../typescript/ai-elevenlabs/src/index.ts | 5 +-
.../ai-elevenlabs/src/realtime/adapter.ts | 4 +-
packages/typescript/ai-openai/src/index.ts | 5 +-
.../ai-openai/src/realtime/adapter.ts | 35 +++--
.../ai-openai/src/realtime/token.ts | 11 +-
.../ai-react/src/use-realtime-chat.ts | 35 ++++-
11 files changed, 208 insertions(+), 139 deletions(-)
diff --git a/examples/ts-react-chat/src/lib/realtime-tools.ts b/examples/ts-react-chat/src/lib/realtime-tools.ts
index 2cf28d7bd3..e19c52226e 100644
--- a/examples/ts-react-chat/src/lib/realtime-tools.ts
+++ b/examples/ts-react-chat/src/lib/realtime-tools.ts
@@ -4,9 +4,13 @@ import { z } from 'zod'
// Tool to get current time - useful for voice assistants
export const getCurrentTimeToolDef = toolDefinition({
name: 'getCurrentTime',
- description: 'Get the current date and time. Use this when the user asks what time it is or the current date.',
+ description:
+ 'Get the current date and time. Use this when the user asks what time it is or the current date.',
inputSchema: z.object({
- timezone: z.string().optional().describe('Optional timezone like "America/New_York" or "Europe/London"'),
+ timezone: z
+ .string()
+ .optional()
+ .describe('Optional timezone like "America/New_York" or "Europe/London"'),
}),
outputSchema: z.object({
time: z.string(),
@@ -18,9 +22,14 @@ export const getCurrentTimeToolDef = toolDefinition({
// Tool to get weather - common voice assistant use case
export const getWeatherToolDef = toolDefinition({
name: 'getWeather',
- description: 'Get the current weather for a location. Use this when the user asks about the weather.',
+ description:
+ 'Get the current weather for a location. Use this when the user asks about the weather.',
inputSchema: z.object({
- location: z.string().describe('The city and state/country, e.g. "San Francisco, CA" or "London, UK"'),
+ location: z
+ .string()
+ .describe(
+ 'The city and state/country, e.g. "San Francisco, CA" or "London, UK"',
+ ),
}),
outputSchema: z.object({
location: z.string(),
@@ -34,7 +43,8 @@ export const getWeatherToolDef = toolDefinition({
// Tool to set a reminder - demonstrates user interaction
export const setReminderToolDef = toolDefinition({
name: 'setReminder',
- description: 'Set a reminder for the user. Use this when the user asks to be reminded about something.',
+ description:
+ 'Set a reminder for the user. Use this when the user asks to be reminded about something.',
inputSchema: z.object({
message: z.string().describe('What to remind the user about'),
inMinutes: z.number().describe('How many minutes from now to remind'),
@@ -49,44 +59,50 @@ export const setReminderToolDef = toolDefinition({
// Tool to search knowledge base - useful for assistants with specific knowledge
export const searchKnowledgeToolDef = toolDefinition({
name: 'searchKnowledge',
- description: 'Search a knowledge base for information. Use this to find specific facts or documentation.',
+ description:
+ 'Search a knowledge base for information. Use this to find specific facts or documentation.',
inputSchema: z.object({
query: z.string().describe('The search query'),
}),
outputSchema: z.object({
- results: z.array(z.object({
- title: z.string(),
- snippet: z.string(),
- })),
+ results: z.array(
+ z.object({
+ title: z.string(),
+ snippet: z.string(),
+ }),
+ ),
}),
})
// Client-side implementation of getCurrentTime
-export const getCurrentTimeClient = getCurrentTimeToolDef.client(({ timezone }) => {
- const now = new Date()
- const tz = timezone || Intl.DateTimeFormat().resolvedOptions().timeZone
-
- return {
- time: now.toLocaleTimeString('en-US', { timeZone: tz }),
- date: now.toLocaleDateString('en-US', {
- weekday: 'long',
- year: 'numeric',
- month: 'long',
- day: 'numeric',
- timeZone: tz,
- }),
- timezone: tz,
- }
-})
+export const getCurrentTimeClient = getCurrentTimeToolDef.client(
+ ({ timezone }) => {
+ const now = new Date()
+ const tz = timezone || Intl.DateTimeFormat().resolvedOptions().timeZone
+
+ return {
+ time: now.toLocaleTimeString('en-US', { timeZone: tz }),
+ date: now.toLocaleDateString('en-US', {
+ weekday: 'long',
+ year: 'numeric',
+ month: 'long',
+ day: 'numeric',
+ timeZone: tz,
+ }),
+ timezone: tz,
+ }
+ },
+)
// Client-side implementation of getWeather (mock data for demo)
export const getWeatherClient = getWeatherToolDef.client(({ location }) => {
// Mock weather data for demo purposes
const conditions = ['Sunny', 'Partly Cloudy', 'Cloudy', 'Rainy', 'Snowy']
- const randomCondition = conditions[Math.floor(Math.random() * conditions.length)]!
+ const randomCondition =
+ conditions[Math.floor(Math.random() * conditions.length)]!
const randomTemp = Math.floor(Math.random() * 30) + 50 // 50-80°F
const randomHumidity = Math.floor(Math.random() * 50) + 30 // 30-80%
-
+
return {
location,
temperature: randomTemp,
@@ -97,40 +113,50 @@ export const getWeatherClient = getWeatherToolDef.client(({ location }) => {
})
// Client-side implementation of setReminder
-export const setReminderClient = setReminderToolDef.client(({ message, inMinutes }) => {
- const remindAt = new Date(Date.now() + inMinutes * 60 * 1000)
-
- // In a real app, you'd schedule a notification here
- console.log(`[Reminder] Will remind about "${message}" at ${remindAt.toLocaleTimeString()}`)
-
- // For demo purposes, show an alert after the specified time
- setTimeout(() => {
- alert(`Reminder: ${message}`)
- }, inMinutes * 60 * 1000)
-
- return {
- success: true,
- message: `Reminder set: "${message}"`,
- remindAt: remindAt.toLocaleTimeString(),
- }
-})
+export const setReminderClient = setReminderToolDef.client(
+ ({ message, inMinutes }) => {
+ const remindAt = new Date(Date.now() + inMinutes * 60 * 1000)
+
+ // In a real app, you'd schedule a notification here
+ console.log(
+ `[Reminder] Will remind about "${message}" at ${remindAt.toLocaleTimeString()}`,
+ )
+
+ // For demo purposes, show an alert after the specified time
+ setTimeout(
+ () => {
+ alert(`Reminder: ${message}`)
+ },
+ inMinutes * 60 * 1000,
+ )
+
+ return {
+ success: true,
+ message: `Reminder set: "${message}"`,
+ remindAt: remindAt.toLocaleTimeString(),
+ }
+ },
+)
// Client-side implementation of searchKnowledge (mock data for demo)
-export const searchKnowledgeClient = searchKnowledgeToolDef.client(({ query }) => {
- // Mock search results for demo
- const mockResults = [
- {
- title: `Result for: ${query}`,
- snippet: `This is a mock search result for the query "${query}". In a real application, this would return actual search results from a knowledge base.`,
- },
- {
- title: 'Additional Information',
- snippet: 'More relevant information would appear here based on your search query.',
- },
- ]
-
- return { results: mockResults }
-})
+export const searchKnowledgeClient = searchKnowledgeToolDef.client(
+ ({ query }) => {
+ // Mock search results for demo
+ const mockResults = [
+ {
+ title: `Result for: ${query}`,
+ snippet: `This is a mock search result for the query "${query}". In a real application, this would return actual search results from a knowledge base.`,
+ },
+ {
+ title: 'Additional Information',
+ snippet:
+ 'More relevant information would appear here based on your search query.',
+ },
+ ]
+
+ return { results: mockResults }
+ },
+)
// Export all client tools as an array for easy use
export const realtimeClientTools = [
diff --git a/examples/ts-react-chat/src/routes/api.realtime-token.ts b/examples/ts-react-chat/src/routes/api.realtime-token.ts
index c9367ad196..807623ecf5 100644
--- a/examples/ts-react-chat/src/routes/api.realtime-token.ts
+++ b/examples/ts-react-chat/src/routes/api.realtime-token.ts
@@ -13,9 +13,13 @@ import * as z from 'zod'
type Provider = 'openai' | 'elevenlabs'
// Convert tool definitions to OpenAI's format using Zod's native toJSONSchema
-function toolDefToOpenAI(toolDef: { name: string; description: string; inputSchema?: unknown }) {
+function toolDefToOpenAI(toolDef: {
+ name: string
+ description: string
+ inputSchema?: unknown
+}) {
let parameters: Record = { type: 'object', properties: {} }
-
+
if (toolDef.inputSchema) {
// Use Zod's native toJSONSchema for Zod v4+
const jsonSchema = z.toJSONSchema(toolDef.inputSchema as z.ZodType)
@@ -23,7 +27,7 @@ function toolDefToOpenAI(toolDef: { name: string; description: string; inputSche
const { $schema, ...rest } = jsonSchema as Record
parameters = rest
}
-
+
return {
type: 'function' as const,
name: toolDef.name,
@@ -85,7 +89,8 @@ Be friendly and engaging!`,
if (!agentId) {
return new Response(
JSON.stringify({
- error: 'ElevenLabs agent ID is required. Set ELEVENLABS_AGENT_ID or pass agentId in request body.',
+ error:
+ 'ElevenLabs agent ID is required. Set ELEVENLABS_AGENT_ID or pass agentId in request body.',
}),
{
status: 400,
diff --git a/examples/ts-react-chat/src/routes/realtime.tsx b/examples/ts-react-chat/src/routes/realtime.tsx
index 4be974a8fc..107b839e57 100644
--- a/examples/ts-react-chat/src/routes/realtime.tsx
+++ b/examples/ts-react-chat/src/routes/realtime.tsx
@@ -14,11 +14,11 @@ const PROVIDER_OPTIONS: Array<{ value: Provider; label: string }> = [
]
// Sparkline component to visualize audio waveform
-function AudioSparkline({
- getData,
+function AudioSparkline({
+ getData,
color,
label,
-}: {
+}: {
getData: () => Uint8Array
color: string
label: string
@@ -49,20 +49,20 @@ function AudioSparkline({
// Sample the data to fit the canvas width
const step = Math.max(1, Math.floor(data.length / width))
-
+
for (let i = 0; i < width; i++) {
const dataIndex = Math.min(i * step, data.length - 1)
const value = data[dataIndex] ?? 128
// Convert 0-255 to canvas height (128 is center/silence)
- const y = height - ((value / 255) * height)
-
+ const y = height - (value / 255) * height
+
if (i === 0) {
ctx!.moveTo(i, y)
} else {
ctx!.lineTo(i, y)
}
}
-
+
ctx!.stroke()
// Draw center line (silence level)
@@ -89,10 +89,10 @@ function AudioSparkline({
return (
{label}
-
@@ -105,7 +105,8 @@ function RealtimePage() {
const messagesEndRef = useRef(null)
// Get the appropriate adapter based on provider
- const adapter = provider === 'openai' ? openaiRealtime() : elevenlabsRealtime()
+ const adapter =
+ provider === 'openai' ? openaiRealtime() : elevenlabsRealtime()
const {
status,
@@ -284,7 +285,8 @@ function RealtimePage() {
Click "Start Conversation" to begin talking with the AI
- Try asking: "What time is it?" or "What's the weather in San Francisco?"
+ Try asking: "What time is it?" or "What's the weather in San
+ Francisco?"
)}
@@ -388,9 +390,9 @@ function RealtimePage() {
{Math.round(inputLevel * 100)}%
-
@@ -406,9 +408,9 @@ function RealtimePage() {
{Math.round(outputLevel * 100)}%
-
diff --git a/packages/typescript/ai-client/src/realtime-client.ts b/packages/typescript/ai-client/src/realtime-client.ts
index f49d4d25ea..170a4d5855 100644
--- a/packages/typescript/ai-client/src/realtime-client.ts
+++ b/packages/typescript/ai-client/src/realtime-client.ts
@@ -61,7 +61,7 @@ export class RealtimeClient {
constructor(options: RealtimeClientOptions) {
this.instanceId = ++clientIdCounter
console.log(`[RealtimeClient #${this.instanceId}] Created`)
-
+
this.options = {
autoPlayback: true,
autoCapture: true,
@@ -102,7 +102,10 @@ export class RealtimeClient {
// Connect via adapter
this.connection = await this.options.adapter.connect(this.token)
- console.log(`[RealtimeClient #${this.instanceId}] Connection established:`, !!this.connection)
+ console.log(
+ `[RealtimeClient #${this.instanceId}] Connection established:`,
+ !!this.connection,
+ )
// Subscribe to connection events
this.subscribeToConnectionEvents()
@@ -251,7 +254,10 @@ export class RealtimeClient {
/** Get audio visualization data */
get audio(): AudioVisualization | null {
- console.log(`[RealtimeClient #${this.instanceId}] audio getter, connection:`, !!this.connection)
+ console.log(
+ `[RealtimeClient #${this.instanceId}] audio getter, connection:`,
+ !!this.connection,
+ )
return this.connection?.getAudioVisualization() ?? null
}
@@ -381,25 +387,28 @@ export class RealtimeClient {
// Tool calls
this.unsubscribers.push(
- this.connection.on('tool_call', async ({ toolCallId, toolName, input }) => {
- const tool = this.clientTools.get(toolName)
- if (tool?.execute) {
- try {
- const output = await tool.execute(input)
- this.connection?.sendToolResult(
- toolCallId,
- typeof output === 'string' ? output : JSON.stringify(output),
- )
- } catch (error) {
- const errMsg =
- error instanceof Error ? error.message : String(error)
- this.connection?.sendToolResult(
- toolCallId,
- JSON.stringify({ error: errMsg }),
- )
+ this.connection.on(
+ 'tool_call',
+ async ({ toolCallId, toolName, input }) => {
+ const tool = this.clientTools.get(toolName)
+ if (tool?.execute) {
+ try {
+ const output = await tool.execute(input)
+ this.connection?.sendToolResult(
+ toolCallId,
+ typeof output === 'string' ? output : JSON.stringify(output),
+ )
+ } catch (error) {
+ const errMsg =
+ error instanceof Error ? error.message : String(error)
+ this.connection?.sendToolResult(
+ toolCallId,
+ JSON.stringify({ error: errMsg }),
+ )
+ }
}
- }
- }),
+ },
+ ),
)
// Message complete
diff --git a/packages/typescript/ai-elevenlabs/README.md b/packages/typescript/ai-elevenlabs/README.md
index 6f85bb8ede..71b0d979b5 100644
--- a/packages/typescript/ai-elevenlabs/README.md
+++ b/packages/typescript/ai-elevenlabs/README.md
@@ -31,7 +31,7 @@ import { RealtimeClient } from '@tanstack/ai-client'
import { elevenlabsRealtime } from '@tanstack/ai-elevenlabs'
const client = new RealtimeClient({
- getToken: () => fetch('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/api/realtime-token').then(r => r.json()),
+ getToken: () => fetch('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/api/realtime-token').then((r) => r.json()),
adapter: elevenlabsRealtime(),
})
diff --git a/packages/typescript/ai-elevenlabs/src/index.ts b/packages/typescript/ai-elevenlabs/src/index.ts
index 14702a1daa..8f3789e848 100644
--- a/packages/typescript/ai-elevenlabs/src/index.ts
+++ b/packages/typescript/ai-elevenlabs/src/index.ts
@@ -2,10 +2,7 @@
// ElevenLabs Realtime (Voice) Adapters
// ============================================================================
-export {
- elevenlabsRealtimeToken,
- elevenlabsRealtime,
-} from './realtime/index'
+export { elevenlabsRealtimeToken, elevenlabsRealtime } from './realtime/index'
export type {
ElevenLabsRealtimeTokenOptions,
diff --git a/packages/typescript/ai-elevenlabs/src/realtime/adapter.ts b/packages/typescript/ai-elevenlabs/src/realtime/adapter.ts
index 39ee355bdb..dfe33d3182 100644
--- a/packages/typescript/ai-elevenlabs/src/realtime/adapter.ts
+++ b/packages/typescript/ai-elevenlabs/src/realtime/adapter.ts
@@ -51,7 +51,9 @@ async function createElevenLabsConnection(
_options: ElevenLabsRealtimeOptions,
): Promise {
const eventHandlers = new Map>>()
- let conversation: Awaited> | null = null
+ let conversation: Awaited<
+ ReturnType
+ > | null = null
let messageIdCounter = 0
// Empty arrays for when visualization isn't available
diff --git a/packages/typescript/ai-openai/src/index.ts b/packages/typescript/ai-openai/src/index.ts
index 2b7916a37e..afadc4529c 100644
--- a/packages/typescript/ai-openai/src/index.ts
+++ b/packages/typescript/ai-openai/src/index.ts
@@ -105,10 +105,7 @@ export type { OpenAIClientConfig } from './utils/client'
// Realtime (Voice) Adapters
// ============================================================================
-export {
- openaiRealtimeToken,
- openaiRealtime,
-} from './realtime/index'
+export { openaiRealtimeToken, openaiRealtime } from './realtime/index'
export type {
OpenAIRealtimeVoice,
diff --git a/packages/typescript/ai-openai/src/realtime/adapter.ts b/packages/typescript/ai-openai/src/realtime/adapter.ts
index 6245a3c05c..e25a7dbd30 100644
--- a/packages/typescript/ai-openai/src/realtime/adapter.ts
+++ b/packages/typescript/ai-openai/src/realtime/adapter.ts
@@ -8,10 +8,7 @@ import type {
RealtimeStatus,
RealtimeToken,
} from '@tanstack/ai'
-import type {
- RealtimeAdapter,
- RealtimeConnection,
-} from '@tanstack/ai-client'
+import type { RealtimeAdapter, RealtimeConnection } from '@tanstack/ai-client'
import type { OpenAIRealtimeOptions } from './types'
const OPENAI_REALTIME_URL = 'https://api.openai.com/v1/realtime'
@@ -175,7 +172,10 @@ async function createWebRTCConnection(
await pc.setRemoteDescription({ type: 'answer', sdp: answerSdp })
// Set up input audio analysis now that we have the stream
- console.log('[Realtime] Setting up input audio analysis, localStream:', localStream)
+ console.log(
+ '[Realtime] Setting up input audio analysis, localStream:',
+ localStream,
+ )
setupInputAudioAnalysis(localStream)
console.log('[Realtime] Input analyser created:', inputAnalyser)
@@ -224,7 +224,11 @@ async function createWebRTCConnection(
case 'response.audio_transcript.delta': {
const delta = event.delta as string
- emit('transcript', { role: 'assistant', transcript: delta, isFinal: false })
+ emit('transcript', {
+ role: 'assistant',
+ transcript: delta,
+ isFinal: false,
+ })
break
}
@@ -264,8 +268,10 @@ async function createWebRTCConnection(
// Emit message complete if we have a current message
if (currentMessageId) {
const response = event.response as Record
- const output = response.output as Array> | undefined
-
+ const output = response.output as
+ | Array>
+ | undefined
+
const message: RealtimeMessage = {
id: currentMessageId,
role: 'assistant',
@@ -511,14 +517,19 @@ async function createWebRTCConnection(
getAudioVisualization(): AudioVisualization {
// Log analyser state for debugging
- console.log('[Realtime] getAudioVisualization called, inputAnalyser:', !!inputAnalyser, 'outputAnalyser:', !!outputAnalyser)
-
+ console.log(
+ '[Realtime] getAudioVisualization called, inputAnalyser:',
+ !!inputAnalyser,
+ 'outputAnalyser:',
+ !!outputAnalyser,
+ )
+
// Helper to calculate audio level from time domain data
// Uses peak amplitude which is more responsive for voice audio meters
function calculateLevel(analyser: AnalyserNode): number {
const data = new Uint8Array(analyser.fftSize)
analyser.getByteTimeDomainData(data)
-
+
// Find peak deviation from center (128 is silence)
// This is more responsive than RMS for voice level meters
let maxDeviation = 0
@@ -528,7 +539,7 @@ async function createWebRTCConnection(
maxDeviation = deviation
}
}
-
+
// Normalize to 0-1 range (max deviation is 128)
// Scale by 1.5x so that ~66% amplitude reads as full scale
// This provides good visual feedback without pegging too early
diff --git a/packages/typescript/ai-openai/src/realtime/token.ts b/packages/typescript/ai-openai/src/realtime/token.ts
index e09d8c7668..832adaa79c 100644
--- a/packages/typescript/ai-openai/src/realtime/token.ts
+++ b/packages/typescript/ai-openai/src/realtime/token.ts
@@ -126,11 +126,12 @@ export function openaiRealtimeToken(
voice: sessionData.voice,
instructions: sessionData.instructions,
tools,
- vadMode: sessionData.turn_detection?.type === 'semantic_vad'
- ? 'semantic'
- : sessionData.turn_detection?.type === 'server_vad'
- ? 'server'
- : 'manual',
+ vadMode:
+ sessionData.turn_detection?.type === 'semantic_vad'
+ ? 'semantic'
+ : sessionData.turn_detection?.type === 'server_vad'
+ ? 'server'
+ : 'manual',
vadConfig: sessionData.turn_detection
? {
threshold: sessionData.turn_detection.threshold,
diff --git a/packages/typescript/ai-react/src/use-realtime-chat.ts b/packages/typescript/ai-react/src/use-realtime-chat.ts
index 3434db607d..9d3f0af41c 100644
--- a/packages/typescript/ai-react/src/use-realtime-chat.ts
+++ b/packages/typescript/ai-react/src/use-realtime-chat.ts
@@ -1,7 +1,14 @@
import { useCallback, useEffect, useRef, useState } from 'react'
import { RealtimeClient } from '@tanstack/ai-client'
-import type { RealtimeMessage, RealtimeMode, RealtimeStatus } from '@tanstack/ai'
-import type { UseRealtimeChatOptions, UseRealtimeChatReturn } from './realtime-types'
+import type {
+ RealtimeMessage,
+ RealtimeMode,
+ RealtimeStatus,
+} from '@tanstack/ai'
+import type {
+ UseRealtimeChatOptions,
+ UseRealtimeChatReturn,
+} from './realtime-types'
// Empty frequency data for when client is not connected
const emptyFrequencyData = new Uint8Array(128)
@@ -54,8 +61,12 @@ export function useRealtimeChat(
const [status, setStatus] = useState('idle')
const [mode, setMode] = useState('idle')
const [messages, setMessages] = useState>([])
- const [pendingUserTranscript, setPendingUserTranscript] = useState(null)
- const [pendingAssistantTranscript, setPendingAssistantTranscript] = useState(null)
+ const [pendingUserTranscript, setPendingUserTranscript] = useState<
+ string | null
+ >(null)
+ const [pendingAssistantTranscript, setPendingAssistantTranscript] = useState<
+ string | null
+ >(null)
const [error, setError] = useState(null)
const [inputLevel, setInputLevel] = useState(0)
const [outputLevel, setOutputLevel] = useState(0)
@@ -181,19 +192,27 @@ export function useRealtimeChat(
// Audio visualization
const getInputFrequencyData = useCallback(() => {
- return clientRef.current?.audio?.getInputFrequencyData() ?? emptyFrequencyData
+ return (
+ clientRef.current?.audio?.getInputFrequencyData() ?? emptyFrequencyData
+ )
}, [])
const getOutputFrequencyData = useCallback(() => {
- return clientRef.current?.audio?.getOutputFrequencyData() ?? emptyFrequencyData
+ return (
+ clientRef.current?.audio?.getOutputFrequencyData() ?? emptyFrequencyData
+ )
}, [])
const getInputTimeDomainData = useCallback(() => {
- return clientRef.current?.audio?.getInputTimeDomainData() ?? emptyTimeDomainData
+ return (
+ clientRef.current?.audio?.getInputTimeDomainData() ?? emptyTimeDomainData
+ )
}, [])
const getOutputTimeDomainData = useCallback(() => {
- return clientRef.current?.audio?.getOutputTimeDomainData() ?? emptyTimeDomainData
+ return (
+ clientRef.current?.audio?.getOutputTimeDomainData() ?? emptyTimeDomainData
+ )
}, [])
// VAD mode control
From 8bc5a93604db6cf04ec1a0760e15b80a26845312 Mon Sep 17 00:00:00 2001
From: Jack Herrington
Date: Thu, 5 Mar 2026 17:55:12 -0800
Subject: [PATCH 06/31] API improved
---
docs/architecture/realtime-chat.md | 112 ++++++++++++++---
.../src/routes/api.realtime-token.ts | 62 ----------
.../ts-react-chat/src/routes/realtime.tsx | 13 +-
.../ai-client/src/realtime-client.ts | 43 ++++---
.../ai-client/src/realtime-types.ts | 10 ++
.../ai-openai/src/realtime/adapter.ts | 70 +++++++----
.../ai-openai/src/realtime/token.ts | 84 +------------
.../ai-openai/src/realtime/types.ts | 27 ----
.../typescript/ai-react/src/realtime-types.ts | 10 ++
.../ai-react/src/use-realtime-chat.ts | 2 +
pnpm-lock.yaml | 115 ++++++++++++++++++
11 files changed, 326 insertions(+), 222 deletions(-)
diff --git a/docs/architecture/realtime-chat.md b/docs/architecture/realtime-chat.md
index 305029c3ec..fcf15a0f0e 100644
--- a/docs/architecture/realtime-chat.md
+++ b/docs/architecture/realtime-chat.md
@@ -25,6 +25,7 @@ The realtime chat system provides a vendor-neutral, type-safe abstraction for vo
│ │ - Messages & transcripts │ │
│ │ - Audio visualization (levels, waveforms) │ │
│ │ - Control methods (connect, disconnect, interrupt) │ │
+│ │ - Client-side tool configuration │ │
│ └─────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
│
@@ -35,6 +36,7 @@ The realtime chat system provides a vendor-neutral, type-safe abstraction for vo
│ │ RealtimeClient │ │
│ │ - Connection lifecycle management │ │
│ │ - Token refresh scheduling │ │
+│ │ - Client-side session configuration (tools, voice, etc) │ │
│ │ - Event subscription & dispatch │ │
│ │ - Tool execution coordination │ │
│ └─────────────────────────────────────────────────────────┘ │
@@ -48,6 +50,7 @@ The realtime chat system provides a vendor-neutral, type-safe abstraction for vo
│ │ - WebRTC connection │ │ - SDK wrapper │ │
│ │ - Audio I/O │ │ - Signed URL auth │ │
│ │ - Event mapping │ │ - Event mapping │ │
+│ │ - Session updates │ │ │ │
│ └──────────────────────┘ └──────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
│
@@ -58,6 +61,8 @@ The realtime chat system provides a vendor-neutral, type-safe abstraction for vo
│ │ Token Generation Endpoint │ │
│ │ - openaiRealtimeToken() - ephemeral client secrets │ │
│ │ - elevenlabsRealtimeToken() - signed URLs │ │
+│ │ (Minimal config: model only — session config is │ │
+│ │ applied client-side via session.update) │ │
│ └─────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
```
@@ -66,7 +71,7 @@ The realtime chat system provides a vendor-neutral, type-safe abstraction for vo
### 1. Token Adapters (Server-Side)
-Token adapters generate short-lived credentials for client-side connections. This keeps API keys secure on the server.
+Token adapters generate short-lived credentials for client-side connections. This keeps API keys secure on the server. The token endpoint sends **only the model** to the provider; all other session configuration (instructions, voice, tools, VAD) is applied client-side.
```typescript
// Server-side token endpoint
@@ -76,13 +81,6 @@ import { openaiRealtimeToken } from '@tanstack/ai-openai'
const token = await realtimeToken({
adapter: openaiRealtimeToken({
model: 'gpt-4o-realtime-preview',
- voice: 'alloy',
- instructions: 'You are a helpful assistant.',
- turnDetection: {
- type: 'server_vad',
- threshold: 0.5,
- silence_duration_ms: 500,
- },
}),
})
```
@@ -104,6 +102,7 @@ Client adapters handle the actual connection to provider APIs, managing:
- Audio capture and playback
- Event translation to common format
- Audio visualization data
+- Session configuration updates (tools, instructions, voice, VAD)
```typescript
// Client-side adapter usage
@@ -114,15 +113,18 @@ const adapter = openaiRealtime({
})
```
+**Data Channel Readiness:** The OpenAI adapter waits for the WebRTC data channel to be fully open before returning the connection. If `updateSession()` is called before the channel is ready, events are queued and flushed once the channel opens.
+
### 3. RealtimeClient
The `RealtimeClient` class manages the connection lifecycle:
- **Connection Management**: Connect, disconnect, reconnect
- **Token Refresh**: Automatically refreshes tokens before expiry
+- **Session Configuration**: Applies client-side config (instructions, voice, tools, VAD) via `session.update` after connecting
- **Event Handling**: Subscribes to adapter events and dispatches to callbacks
- **State Management**: Tracks status, mode, messages, transcripts
-- **Tool Execution**: Coordinates client-side tool calls
+- **Tool Execution**: Looks up client-side tools by name, executes them, and sends results back to the provider
### 4. useRealtimeChat Hook
@@ -155,6 +157,9 @@ const {
} = useRealtimeChat({
getToken: () => fetch('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/api/realtime-token').then(r => r.json()),
adapter: openaiRealtime(),
+ instructions: 'You are a helpful voice assistant.',
+ voice: 'alloy',
+ tools: myClientTools,
})
```
@@ -169,7 +174,7 @@ sequenceDiagram
participant OpenAI
Browser->>Server: POST /api/realtime-token
- Server->>OpenAI: POST /v1/realtime/sessions
+ Server->>OpenAI: POST /v1/realtime/sessions (model only)
OpenAI-->>Server: { client_secret, expires_at }
Server-->>Browser: RealtimeToken
@@ -183,8 +188,12 @@ sequenceDiagram
OpenAI-->>Browser: SDP answer
Browser->>Browser: setRemoteDescription()
+ Browser->>Browser: Wait for data channel open
Note over Browser,OpenAI: WebRTC connection established
+ Browser->>OpenAI: session.update (tools, instructions, voice, VAD)
+ OpenAI-->>Browser: session.updated (confirms config)
+
Browser->>OpenAI: Audio via WebRTC
OpenAI-->>Browser: Audio + events via WebRTC
```
@@ -209,14 +218,82 @@ sequenceDiagram
ElevenLabs-->>Browser: Audio + events via SDK
```
+## Client-Side Tool Calling
+
+Tools are defined once using `toolDefinition()` and instantiated for client-side execution with `.client()`. When the AI model invokes a tool, the `RealtimeClient` executes it locally in the browser and sends the result back to the provider.
+
+### Tool Definition
+
+```typescript
+import { toolDefinition } from '@tanstack/ai'
+import { z } from 'zod'
+
+const getWeatherToolDef = toolDefinition({
+ name: 'getWeather',
+ description: 'Get the current weather for a location.',
+ inputSchema: z.object({
+ location: z.string().describe('City and state/country'),
+ }),
+ outputSchema: z.object({
+ location: z.string(),
+ temperature: z.number(),
+ condition: z.string(),
+ }),
+})
+
+// Create client-side implementation
+const getWeatherClient = getWeatherToolDef.client(({ location }) => ({
+ location,
+ temperature: 72,
+ condition: 'Sunny',
+}))
+```
+
+### Tool Call Flow
+
+```mermaid
+sequenceDiagram
+ participant User
+ participant Browser as Browser (RealtimeClient)
+ participant OpenAI
+
+ User->>Browser: "What's the weather in London?"
+ Browser->>OpenAI: Audio via WebRTC
+
+ OpenAI->>Browser: response.function_call_arguments.done
+ Note right of OpenAI: { name: "getWeather", arguments: '{"location":"London"}' }
+
+ Browser->>Browser: Look up tool in clientTools Map
+ Browser->>Browser: Execute tool.execute(input)
+ Browser->>OpenAI: conversation.item.create (function_call_output)
+ Browser->>OpenAI: response.create
+
+ OpenAI->>Browser: response.audio_transcript.delta
+ Note right of OpenAI: "The weather in London is 72°F and sunny!"
+ OpenAI->>Browser: response.done
+ Browser->>User: Display message + play audio
+```
+
+### Session Configuration
+
+When connecting, the `RealtimeClient` calls `applySessionConfig()` which sends a `session.update` event to the provider with:
+
+- **instructions** — System prompt for the assistant
+- **voice** — Voice to use for audio output (e.g., `'alloy'`)
+- **tools** — Array of tool definitions with JSON Schema parameters, plus `tool_choice: 'auto'`
+- **turn_detection** — VAD configuration (server_vad, semantic_vad, or manual)
+- **input_audio_transcription** — Enables user speech transcription (e.g., Whisper)
+
+Tool schemas are converted from Zod (or any Standard JSON Schema compliant library) to JSON Schema using `convertSchemaToJsonSchema()` before being sent to the provider.
+
## Audio Visualization
The system provides real-time audio visualization through the `AudioVisualization` interface:
```typescript
interface AudioVisualization {
- inputLevel: number // 0-1 normalized input volume (RMS)
- outputLevel: number // 0-1 normalized output volume (RMS)
+ inputLevel: number // 0-1 normalized input volume
+ outputLevel: number // 0-1 normalized output volume
getInputFrequencyData(): Uint8Array // FFT frequency bins
getOutputFrequencyData(): Uint8Array
getInputTimeDomainData(): Uint8Array // Raw waveform samples
@@ -228,7 +305,7 @@ interface AudioVisualization {
The OpenAI adapter uses Web Audio API `AnalyserNode` for visualization:
- `fftSize: 2048` for high-resolution analysis
-- RMS (Root Mean Square) calculation for accurate volume levels
+- Peak amplitude detection for responsive volume meters
- Separate analysers for input (microphone) and output (AI voice)
## Event System
@@ -256,15 +333,16 @@ Adapters emit standardized events:
- [x] Real-time transcription display
- [x] Audio visualization (levels, waveforms)
- [x] Interrupt capability
+- [x] Client-side tool calling (define, execute, return results)
+- [x] Client-side session configuration (instructions, voice, tools, VAD)
- [x] React hook (`useRealtimeChat`)
-- [x] Demo application at `/realtime` route
+- [x] Demo application at `/realtime` route with tool examples
### Known Limitations
- **Device Selection**: Currently uses system default audio devices. Custom device selection not yet implemented.
- **ElevenLabs SDK**: Using `@11labs/client@0.2.0` which has limited TypeScript support.
- **Push-to-Talk**: Manual VAD mode implemented but not exposed in demo UI.
-- **Tool Calling**: Framework supports tools but demo doesn't showcase them.
### Demo Application
@@ -276,8 +354,9 @@ The `examples/ts-react-chat` application includes a realtime voice chat demo at
- Conversation mode indicator (Listening/Thinking/Speaking)
- Message history with transcripts
- Audio level meters
-- Waveform visualization (debug mode)
+- Waveform visualization
- Interrupt button during AI speech
+- Client-side tool execution (getCurrentTime, getWeather, setReminder, searchKnowledge)
**Required Environment Variables:**
```bash
@@ -311,3 +390,4 @@ ELEVENLABS_AGENT_ID=... # Optional, for ElevenLabs
### Demo Application
- `examples/ts-react-chat/src/routes/realtime.tsx` - Demo UI component
- `examples/ts-react-chat/src/routes/api.realtime-token.ts` - Token API endpoint
+- `examples/ts-react-chat/src/lib/realtime-tools.ts` - Client-side tool definitions
diff --git a/examples/ts-react-chat/src/routes/api.realtime-token.ts b/examples/ts-react-chat/src/routes/api.realtime-token.ts
index 807623ecf5..62fb08d8d2 100644
--- a/examples/ts-react-chat/src/routes/api.realtime-token.ts
+++ b/examples/ts-react-chat/src/routes/api.realtime-token.ts
@@ -2,40 +2,9 @@ import { createFileRoute } from '@tanstack/react-router'
import { realtimeToken } from '@tanstack/ai'
import { openaiRealtimeToken } from '@tanstack/ai-openai'
import { elevenlabsRealtimeToken } from '@tanstack/ai-elevenlabs'
-import {
- getCurrentTimeToolDef,
- getWeatherToolDef,
- setReminderToolDef,
- searchKnowledgeToolDef,
-} from '@/lib/realtime-tools'
-import * as z from 'zod'
type Provider = 'openai' | 'elevenlabs'
-// Convert tool definitions to OpenAI's format using Zod's native toJSONSchema
-function toolDefToOpenAI(toolDef: {
- name: string
- description: string
- inputSchema?: unknown
-}) {
- let parameters: Record = { type: 'object', properties: {} }
-
- if (toolDef.inputSchema) {
- // Use Zod's native toJSONSchema for Zod v4+
- const jsonSchema = z.toJSONSchema(toolDef.inputSchema as z.ZodType)
- // Remove $schema as OpenAI doesn't need it
- const { $schema, ...rest } = jsonSchema as Record
- parameters = rest
- }
-
- return {
- type: 'function' as const,
- name: toolDef.name,
- description: toolDef.description,
- parameters,
- }
-}
-
export const Route = createFileRoute('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/api/realtime-token')({
server: {
handlers: {
@@ -47,40 +16,9 @@ export const Route = createFileRoute('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/api/realtime-token')({
let token
if (provider === 'openai') {
- // Convert tool definitions to OpenAI format
- const tools = [
- toolDefToOpenAI(getCurrentTimeToolDef),
- toolDefToOpenAI(getWeatherToolDef),
- toolDefToOpenAI(setReminderToolDef),
- toolDefToOpenAI(searchKnowledgeToolDef),
- ]
-
token = await realtimeToken({
adapter: openaiRealtimeToken({
model: 'gpt-4o-realtime-preview',
- voice: 'alloy',
- instructions: `You are a helpful, friendly voice assistant with access to several tools.
-
-You can:
-- Tell the user the current time and date (getCurrentTime)
-- Get weather information for any location (getWeather)
-- Set reminders for the user (setReminder)
-- Search a knowledge base for information (searchKnowledge)
-
-Keep your responses concise and conversational since this is a voice interface.
-When using tools, briefly explain what you're doing and then share the results naturally.
-Be friendly and engaging!`,
- turnDetection: {
- type: 'server_vad',
- threshold: 0.5,
- prefix_padding_ms: 300,
- silence_duration_ms: 500,
- },
- inputAudioTranscription: {
- model: 'whisper-1',
- },
- tools,
- toolChoice: 'auto',
}),
})
} else if (provider === 'elevenlabs') {
diff --git a/examples/ts-react-chat/src/routes/realtime.tsx b/examples/ts-react-chat/src/routes/realtime.tsx
index 107b839e57..272243aa82 100644
--- a/examples/ts-react-chat/src/routes/realtime.tsx
+++ b/examples/ts-react-chat/src/routes/realtime.tsx
@@ -140,7 +140,18 @@ function RealtimePage() {
return response.json()
},
adapter,
- // Pass the client tools - these execute locally when the AI calls them
+ instructions: `You are a helpful, friendly voice assistant with access to several tools.
+
+You can:
+- Tell the user the current time and date (getCurrentTime)
+- Get weather information for any location (getWeather)
+- Set reminders for the user (setReminder)
+- Search a knowledge base for information (searchKnowledge)
+
+Keep your responses concise and conversational since this is a voice interface.
+When using tools, briefly explain what you're doing and then share the results naturally.
+Be friendly and engaging!`,
+ voice: 'alloy',
tools: realtimeClientTools,
onError: (err) => {
console.error('Realtime error:', err)
diff --git a/packages/typescript/ai-client/src/realtime-client.ts b/packages/typescript/ai-client/src/realtime-client.ts
index 170a4d5855..4ce1502147 100644
--- a/packages/typescript/ai-client/src/realtime-client.ts
+++ b/packages/typescript/ai-client/src/realtime-client.ts
@@ -1,3 +1,4 @@
+import { convertSchemaToJsonSchema } from '@tanstack/ai'
import type {
AnyClientTool,
AudioVisualization,
@@ -37,10 +38,7 @@ const TOKEN_REFRESH_BUFFER_MS = 60_000
* await client.connect()
* ```
*/
-let clientIdCounter = 0
-
export class RealtimeClient {
- private instanceId: number
private options: RealtimeClientOptions
private connection: RealtimeConnection | null = null
private token: RealtimeToken | null = null
@@ -59,9 +57,6 @@ export class RealtimeClient {
}
constructor(options: RealtimeClientOptions) {
- this.instanceId = ++clientIdCounter
- console.log(`[RealtimeClient #${this.instanceId}] Created`)
-
this.options = {
autoPlayback: true,
autoCapture: true,
@@ -102,14 +97,13 @@ export class RealtimeClient {
// Connect via adapter
this.connection = await this.options.adapter.connect(this.token)
- console.log(
- `[RealtimeClient #${this.instanceId}] Connection established:`,
- !!this.connection,
- )
// Subscribe to connection events
this.subscribeToConnectionEvents()
+ // Auto-configure session with client-provided settings
+ this.applySessionConfig()
+
// Start audio capture if configured
if (this.options.autoCapture) {
await this.connection.startAudioCapture()
@@ -254,10 +248,6 @@ export class RealtimeClient {
/** Get audio visualization data */
get audio(): AudioVisualization | null {
- console.log(
- `[RealtimeClient #${this.instanceId}] audio getter, connection:`,
- !!this.connection,
- )
return this.connection?.getAudioVisualization() ?? null
}
@@ -454,6 +444,31 @@ export class RealtimeClient {
)
}
+ private applySessionConfig(): void {
+ if (!this.connection) return
+
+ const { instructions, voice, vadMode, tools } = this.options
+ const hasConfig = instructions || voice || vadMode || (tools && tools.length > 0)
+ if (!hasConfig) return
+
+ const toolsConfig = tools
+ ? Array.from(this.clientTools.values()).map((t) => ({
+ name: t.name,
+ description: t.description,
+ inputSchema: t.inputSchema
+ ? convertSchemaToJsonSchema(t.inputSchema)
+ : undefined,
+ }))
+ : undefined
+
+ this.connection.updateSession({
+ instructions,
+ voice,
+ vadMode,
+ tools: toolsConfig,
+ })
+ }
+
private generateId(): string {
return `msg-${Date.now()}-${Math.random().toString(36).substring(7)}`
}
diff --git a/packages/typescript/ai-client/src/realtime-types.ts b/packages/typescript/ai-client/src/realtime-types.ts
index 4ff6bf9bd5..859d5dea60 100644
--- a/packages/typescript/ai-client/src/realtime-types.ts
+++ b/packages/typescript/ai-client/src/realtime-types.ts
@@ -105,6 +105,16 @@ export interface RealtimeClientOptions {
*/
autoCapture?: boolean
+ /**
+ * System instructions for the assistant
+ */
+ instructions?: string
+
+ /**
+ * Voice to use for audio output
+ */
+ voice?: string
+
/**
* Voice activity detection mode (default: 'server')
*/
diff --git a/packages/typescript/ai-openai/src/realtime/adapter.ts b/packages/typescript/ai-openai/src/realtime/adapter.ts
index e25a7dbd30..03bc7da7aa 100644
--- a/packages/typescript/ai-openai/src/realtime/adapter.ts
+++ b/packages/typescript/ai-openai/src/realtime/adapter.ts
@@ -100,9 +100,14 @@ async function createWebRTCConnection(
// Set up data channel for bidirectional communication
dataChannel = pc.createDataChannel('oai-events')
- dataChannel.onopen = () => {
- emit('status_change', { status: 'connected' as RealtimeStatus })
- }
+ // Promise that resolves when the data channel is open and ready
+ const dataChannelReady = new Promise((resolve) => {
+ dataChannel!.onopen = () => {
+ flushPendingEvents()
+ emit('status_change', { status: 'connected' as RealtimeStatus })
+ resolve()
+ }
+ })
dataChannel.onmessage = (event) => {
try {
@@ -119,10 +124,8 @@ async function createWebRTCConnection(
// Handle incoming audio track
pc.ontrack = (event) => {
- console.log('[Realtime] ontrack event:', event.track.kind, event.streams[0])
if (event.track.kind === 'audio' && event.streams[0]) {
setupOutputAudioAnalysis(event.streams[0])
- console.log('[Realtime] Output analyser created:', outputAnalyser)
}
}
@@ -172,12 +175,7 @@ async function createWebRTCConnection(
await pc.setRemoteDescription({ type: 'answer', sdp: answerSdp })
// Set up input audio analysis now that we have the stream
- console.log(
- '[Realtime] Setting up input audio analysis, localStream:',
- localStream,
- )
setupInputAudioAnalysis(localStream)
- console.log('[Realtime] Input analyser created:', inputAnalyser)
// Handle server events
function handleServerEvent(event: Record) {
@@ -262,16 +260,16 @@ async function createWebRTCConnection(
}
case 'response.done': {
+ const response = event.response as Record
+ const output = response.output as
+ | Array>
+ | undefined
+
currentMode = 'listening'
emit('mode_change', { mode: 'listening' })
// Emit message complete if we have a current message
if (currentMessageId) {
- const response = event.response as Record
- const output = response.output as
- | Array>
- | undefined
-
const message: RealtimeMessage = {
id: currentMessageId,
role: 'assistant',
@@ -372,11 +370,24 @@ async function createWebRTCConnection(
inputSource.connect(inputAnalyser)
}
- // Send event to server
+ // Queue for events sent before the data channel is open
+ const pendingEvents: Array> = []
+
+ // Send event to server (queues if data channel not yet open)
function sendEvent(event: Record) {
if (dataChannel?.readyState === 'open') {
dataChannel.send(JSON.stringify(event))
+ } else {
+ pendingEvents.push(event)
+ }
+ }
+
+ // Flush any queued events (called when data channel opens)
+ function flushPendingEvents() {
+ for (const event of pendingEvents) {
+ dataChannel!.send(JSON.stringify(event))
}
+ pendingEvents.length = 0
}
// Connection implementation
@@ -486,6 +497,21 @@ async function createWebRTCConnection(
}
}
+ if (config.tools !== undefined) {
+ sessionUpdate.tools = config.tools.map((t) => ({
+ type: 'function',
+ name: t.name,
+ description: t.description,
+ parameters: t.inputSchema
+ ? (t.inputSchema as Record)
+ : { type: 'object', properties: {} },
+ }))
+ sessionUpdate.tool_choice = 'auto'
+ }
+
+ // Always enable input audio transcription so user speech is transcribed
+ sessionUpdate.input_audio_transcription = { model: 'whisper-1' }
+
if (Object.keys(sessionUpdate).length > 0) {
sendEvent({
type: 'session.update',
@@ -516,14 +542,6 @@ async function createWebRTCConnection(
},
getAudioVisualization(): AudioVisualization {
- // Log analyser state for debugging
- console.log(
- '[Realtime] getAudioVisualization called, inputAnalyser:',
- !!inputAnalyser,
- 'outputAnalyser:',
- !!outputAnalyser,
- )
-
// Helper to calculate audio level from time domain data
// Uses peak amplitude which is more responsive for voice audio meters
function calculateLevel(analyser: AnalyserNode): number {
@@ -597,5 +615,9 @@ async function createWebRTCConnection(
},
}
+ // Wait for the data channel to be open before returning the connection.
+ // This ensures session.update (tools, instructions, etc.) can be sent immediately.
+ await dataChannelReady
+
return connection
}
diff --git a/packages/typescript/ai-openai/src/realtime/token.ts b/packages/typescript/ai-openai/src/realtime/token.ts
index 832adaa79c..6bff9c9c26 100644
--- a/packages/typescript/ai-openai/src/realtime/token.ts
+++ b/packages/typescript/ai-openai/src/realtime/token.ts
@@ -1,5 +1,5 @@
import { getOpenAIApiKeyFromEnv } from '../utils/client'
-import type { RealtimeToken, RealtimeTokenAdapter, Tool } from '@tanstack/ai'
+import type { RealtimeToken, RealtimeTokenAdapter } from '@tanstack/ai'
import type {
OpenAIRealtimeModel,
OpenAIRealtimeSessionResponse,
@@ -47,58 +47,17 @@ export function openaiRealtimeToken(
async generateToken(): Promise {
const model: OpenAIRealtimeModel =
options.model ?? 'gpt-4o-realtime-preview'
- const voice = options.voice ?? 'alloy'
- // Build request body
- const body: Record = {
- model,
- voice,
- }
-
- if (options.instructions) {
- body.instructions = options.instructions
- }
-
- if (options.turnDetection !== undefined) {
- body.turn_detection = options.turnDetection
- }
-
- if (options.inputAudioFormat) {
- body.input_audio_format = options.inputAudioFormat
- }
-
- if (options.outputAudioFormat) {
- body.output_audio_format = options.outputAudioFormat
- }
-
- if (options.inputAudioTranscription) {
- body.input_audio_transcription = options.inputAudioTranscription
- }
-
- if (options.tools) {
- body.tools = options.tools
- }
-
- if (options.toolChoice) {
- body.tool_choice = options.toolChoice
- }
-
- if (options.temperature !== undefined) {
- body.temperature = options.temperature
- }
-
- if (options.maxResponseOutputTokens !== undefined) {
- body.max_response_output_tokens = options.maxResponseOutputTokens
- }
-
- // Call OpenAI API to create session and get ephemeral token
+ // Call OpenAI API to create session and get ephemeral token.
+ // Only the model is sent server-side; all other session config
+ // (instructions, voice, tools, VAD) is applied client-side via session.update.
const response = await fetch(OPENAI_REALTIME_SESSIONS_URL, {
method: 'POST',
headers: {
Authorization: `Bearer ${apiKey}`,
'Content-Type': 'application/json',
},
- body: JSON.stringify(body),
+ body: JSON.stringify({ model }),
})
if (!response.ok) {
@@ -110,43 +69,12 @@ export function openaiRealtimeToken(
const sessionData: OpenAIRealtimeSessionResponse = await response.json()
- // Convert tools to our format
- const tools: Array = sessionData.tools.map((t) => ({
- name: t.name,
- description: t.description,
- inputSchema: t.parameters,
- }))
-
return {
provider: 'openai',
token: sessionData.client_secret.value,
- expiresAt: sessionData.client_secret.expires_at * 1000, // Convert to ms
+ expiresAt: sessionData.client_secret.expires_at * 1000,
config: {
model: sessionData.model,
- voice: sessionData.voice,
- instructions: sessionData.instructions,
- tools,
- vadMode:
- sessionData.turn_detection?.type === 'semantic_vad'
- ? 'semantic'
- : sessionData.turn_detection?.type === 'server_vad'
- ? 'server'
- : 'manual',
- vadConfig: sessionData.turn_detection
- ? {
- threshold: sessionData.turn_detection.threshold,
- prefixPaddingMs: sessionData.turn_detection.prefix_padding_ms,
- silenceDurationMs:
- sessionData.turn_detection.silence_duration_ms,
- }
- : undefined,
- providerOptions: {
- inputAudioFormat: sessionData.input_audio_format,
- outputAudioFormat: sessionData.output_audio_format,
- inputAudioTranscription: sessionData.input_audio_transcription,
- temperature: sessionData.temperature,
- maxResponseOutputTokens: sessionData.max_response_output_tokens,
- },
},
}
},
diff --git a/packages/typescript/ai-openai/src/realtime/types.ts b/packages/typescript/ai-openai/src/realtime/types.ts
index 713bd2b4cf..815099866d 100644
--- a/packages/typescript/ai-openai/src/realtime/types.ts
+++ b/packages/typescript/ai-openai/src/realtime/types.ts
@@ -52,33 +52,6 @@ export type OpenAITurnDetection =
export interface OpenAIRealtimeTokenOptions {
/** Model to use (default: 'gpt-4o-realtime-preview') */
model?: OpenAIRealtimeModel
- /** Voice to use (default: 'alloy') */
- voice?: OpenAIRealtimeVoice
- /** System instructions */
- instructions?: string
- /** Turn detection configuration */
- turnDetection?: OpenAITurnDetection
- /** Input audio format (default: 'pcm16') */
- inputAudioFormat?: 'pcm16' | 'g711_ulaw' | 'g711_alaw'
- /** Output audio format (default: 'pcm16') */
- outputAudioFormat?: 'pcm16' | 'g711_ulaw' | 'g711_alaw'
- /** Input audio transcription model */
- inputAudioTranscription?: {
- model: 'whisper-1'
- }
- /** Tools available in the session */
- tools?: Array<{
- type: 'function'
- name: string
- description: string
- parameters: Record
- }>
- /** Tool choice strategy */
- toolChoice?: 'auto' | 'none' | 'required' | { type: 'function'; name: string }
- /** Temperature for response generation */
- temperature?: number
- /** Maximum response output tokens */
- maxResponseOutputTokens?: number | 'inf'
}
/**
diff --git a/packages/typescript/ai-react/src/realtime-types.ts b/packages/typescript/ai-react/src/realtime-types.ts
index 9b44269d9e..7687bbc42a 100644
--- a/packages/typescript/ai-react/src/realtime-types.ts
+++ b/packages/typescript/ai-react/src/realtime-types.ts
@@ -37,6 +37,16 @@ export interface UseRealtimeChatOptions {
*/
autoCapture?: boolean
+ /**
+ * System instructions for the assistant
+ */
+ instructions?: string
+
+ /**
+ * Voice to use for audio output
+ */
+ voice?: string
+
/**
* Voice activity detection mode (default: 'server')
*/
diff --git a/packages/typescript/ai-react/src/use-realtime-chat.ts b/packages/typescript/ai-react/src/use-realtime-chat.ts
index 9d3f0af41c..c40d26e784 100644
--- a/packages/typescript/ai-react/src/use-realtime-chat.ts
+++ b/packages/typescript/ai-react/src/use-realtime-chat.ts
@@ -87,6 +87,8 @@ export function useRealtimeChat(
getToken: optionsRef.current.getToken,
adapter: optionsRef.current.adapter,
tools: optionsRef.current.tools,
+ instructions: optionsRef.current.instructions,
+ voice: optionsRef.current.voice,
autoPlayback: optionsRef.current.autoPlayback,
autoCapture: optionsRef.current.autoCapture,
vadMode: optionsRef.current.vadMode,
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 6e975a75cc..5fae8867f0 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -201,6 +201,9 @@ importers:
'@tanstack/ai-client':
specifier: workspace:*
version: link:../../packages/typescript/ai-client
+ '@tanstack/ai-elevenlabs':
+ specifier: workspace:*
+ version: link:../../packages/typescript/ai-elevenlabs
'@tanstack/ai-gemini':
specifier: workspace:*
version: link:../../packages/typescript/ai-gemini
@@ -746,6 +749,22 @@ importers:
specifier: ^2.11.10
version: 2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@25.0.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+ packages/typescript/ai-elevenlabs:
+ dependencies:
+ '@11labs/client':
+ specifier: ^0.2.0
+ version: 0.2.0(@types/dom-mediacapture-record@1.0.22)
+ devDependencies:
+ '@tanstack/ai':
+ specifier: workspace:*
+ version: link:../ai
+ '@tanstack/ai-client':
+ specifier: workspace:*
+ version: link:../ai-client
+ '@vitest/coverage-v8':
+ specifier: 4.0.14
+ version: 4.0.14(vitest@4.0.18(@types/node@25.0.1)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+
packages/typescript/ai-fal:
dependencies:
'@fal-ai/client':
@@ -822,6 +841,9 @@ importers:
'@tanstack/ai':
specifier: workspace:*
version: link:../ai
+ '@tanstack/ai-client':
+ specifier: workspace:*
+ version: link:../ai-client
'@vitest/coverage-v8':
specifier: 4.0.14
version: 4.0.14(vitest@4.0.18(@types/node@25.0.1)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
@@ -1412,6 +1434,10 @@ importers:
packages:
+ '@11labs/client@0.2.0':
+ resolution: {integrity: sha512-GBplAV4WDbcoThsIzdSDPN3xbcitK0ZZ4iJfJZKfltqvgvS6Uw8GZxHwVgiPwnQoA3uosYyY3L9TuPwmel18xQ==}
+ deprecated: This package is no longer maintained. Please use @elevenlabs/client for the latest version
+
'@acemir/cssom@0.9.29':
resolution: {integrity: sha512-G90x0VW+9nW4dFajtjCoT+NM0scAfH9Mb08IcjgFHYbfiL/lU04dTF9JuVOi3/OH+DJCQdcIseSXkdCB9Ky6JA==}
@@ -1604,6 +1630,9 @@ packages:
resolution: {integrity: sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==}
engines: {node: '>=18'}
+ '@bufbuild/protobuf@1.10.1':
+ resolution: {integrity: sha512-wJ8ReQbHxsAfXhrf9ixl0aYbZorRuOWpBNzm8pL8ftmSxQx/wnJD5Eg861NwJU/czy2VXFIebCeZnZrI9rktIQ==}
+
'@changesets/apply-release-plan@7.0.14':
resolution: {integrity: sha512-ddBvf9PHdy2YY0OUiEl3TV78mH9sckndJR14QAt87KLEbIov81XO0q0QAmvooBxXlqRRP8I9B7XOzZwQG7JkWA==}
@@ -2477,6 +2506,12 @@ packages:
'@jridgewell/trace-mapping@0.3.31':
resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==}
+ '@livekit/mutex@1.1.1':
+ resolution: {integrity: sha512-EsshAucklmpuUAfkABPxJNhzj9v2sG7JuzFDL4ML1oJQSV14sqrpTYnsaOudMAw9yOaW53NU3QQTlUQoRs4czw==}
+
+ '@livekit/protocol@1.44.0':
+ resolution: {integrity: sha512-/vfhDUGcUKO8Q43r6i+5FrDhl5oZjm/X3U4x2Iciqvgn5C8qbj+57YPcWSJ1kyIZm5Cm6AV2nAPjMm3ETD/iyg==}
+
'@manypkg/find-root@1.1.0':
resolution: {integrity: sha512-mki5uBvhHzO8kYYix/WRy2WX8S3B5wdVSc9D6KcU5lQNglP2yt58/VfLuAK49glRXChosY8ap2oJ1qgma3GUVA==}
@@ -4400,6 +4435,9 @@ packages:
'@types/deep-eql@4.0.2':
resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==}
+ '@types/dom-mediacapture-record@1.0.22':
+ resolution: {integrity: sha512-mUMZLK3NvwRLcAAT9qmcK+9p7tpU2FHdDsntR3YI4+GY88XrgG4XiE7u1Q2LAN2/FZOz/tdMDC3GQCR4T8nFuw==}
+
'@types/estree-jsx@1.0.5':
resolution: {integrity: sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==}
@@ -6588,6 +6626,9 @@ packages:
jju@1.4.0:
resolution: {integrity: sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA==}
+ jose@6.2.0:
+ resolution: {integrity: sha512-xsfE1TcSCbUdo6U07tR0mvhg0flGxU8tPLbF03mirl2ukGQENhUg4ubGYQnhVH0b5stLlPM+WOqDkEl1R1y5sQ==}
+
js-beautify@1.15.4:
resolution: {integrity: sha512-9/KXeZUKKJwqCXUdBxFJ3vPh467OCckSBmYDwSK/EtV090K+iMJ7zx2S3HLVDIWFQdqMIsZWbnaGiba18aWhaA==}
engines: {node: '>=14'}
@@ -6791,6 +6832,11 @@ packages:
resolution: {integrity: sha512-I8oW2+QL5KJo8zXNWX046M134WchxsXC7SawLPvRQpogCbkyQIaFxPE89A2HiwR7vAK2Dm2ERBAmyjTYGYEpBg==}
hasBin: true
+ livekit-client@2.17.2:
+ resolution: {integrity: sha512-+67y2EtAWZabARlY7kANl/VT1Uu1EJYR5a8qwpT2ub/uBCltsEgEDOxCIMwE9HFR5w+z41HR6GL9hyEvW/y6CQ==}
+ peerDependencies:
+ '@types/dom-mediacapture-record': ^1
+
local-pkg@0.5.1:
resolution: {integrity: sha512-9rrA30MRRP3gBD3HTGnC6cDFpaE1kVDWxWgqWJUN0RvDNAo+Nz/9GxB+nHOH0ifbVFy0hSA1V6vFDvnx54lTEQ==}
engines: {node: '>=14'}
@@ -6829,6 +6875,10 @@ packages:
resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==}
engines: {node: '>=10'}
+ loglevel@1.9.2:
+ resolution: {integrity: sha512-HgMmCqIJSAKqo68l0rS2AanEWfkxaZ5wNiEFb5ggm08lDs9Xl2KxBlX3PTcaD2chBM1gXAYf491/M2Rv8Jwayg==}
+ engines: {node: '>= 0.6.0'}
+
long@5.3.2:
resolution: {integrity: sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==}
@@ -7909,6 +7959,13 @@ packages:
scule@1.3.0:
resolution: {integrity: sha512-6FtHJEvt+pVMIB9IBY+IcCJ6Z5f1iQnytgyfKMhDKgmzYG+TeH/wx1y3l27rshSbLiSanrR9ffZDrEsmjlQF2g==}
+ sdp-transform@2.15.0:
+ resolution: {integrity: sha512-KrOH82c/W+GYQ0LHqtr3caRpM3ITglq3ljGUIb8LTki7ByacJZ9z+piSGiwZDsRyhQbYBOBJgr2k6X4BZXi3Kw==}
+ hasBin: true
+
+ sdp@3.2.1:
+ resolution: {integrity: sha512-lwsAIzOPlH8/7IIjjz3K0zYBk7aBVVcvjMwt3M4fLxpjMYyy7i3I97SLHebgn4YBjirkzfp3RvRDWSKsh/+WFw==}
+
semver@6.3.1:
resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==}
hasBin: true
@@ -8387,6 +8444,9 @@ packages:
peerDependencies:
typescript: '>=4.8.4'
+ ts-debounce@4.0.0:
+ resolution: {integrity: sha512-+1iDGY6NmOGidq7i7xZGA4cm8DAa6fqdYcvO5Z6yBevH++Bdo9Qt/mN0TzHUgcCcKv1gmh9+W5dHqz8pMWbCbg==}
+
ts-declaration-location@1.0.7:
resolution: {integrity: sha512-EDyGAwH1gO0Ausm9gV6T2nUvBgXT5kGoCMJPllOaooZ+4VvJiKBdZE7wK18N1deEowhcUptS+5GXZK8U/fvpwA==}
peerDependencies:
@@ -8456,6 +8516,9 @@ packages:
resolution: {integrity: sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==}
engines: {node: '>= 0.6'}
+ typed-emitter@2.1.0:
+ resolution: {integrity: sha512-g/KzbYKbH5C2vPkaXGu8DJlHrGKHLsM25Zg9WuC9pMGfuvT+X25tZQWo5fK1BjBm8+UrVE9LDCvaY0CQk+fXDA==}
+
typedoc-plugin-frontmatter@1.3.0:
resolution: {integrity: sha512-xYQFMAecMlsRUjmf9oM/Sq2FVz4zlgcbIeVFNLdO118CHTN06gIKJNSlyExh9+Xl8sK0YhIvoQwViUURxritWA==}
peerDependencies:
@@ -9091,6 +9154,10 @@ packages:
webpack-virtual-modules@0.6.2:
resolution: {integrity: sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==}
+ webrtc-adapter@9.0.4:
+ resolution: {integrity: sha512-5ZZY1+lGq8LEKuDlg9M2RPJHlH3R7OVwyHqMcUsLKCgd9Wvf+QrFTCItkXXYPmrJn8H6gRLXbSgxLLdexiqHxw==}
+ engines: {node: '>=6.0.0', npm: '>=3.10.0'}
+
whatwg-encoding@3.1.1:
resolution: {integrity: sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==}
engines: {node: '>=18'}
@@ -9245,6 +9312,12 @@ packages:
snapshots:
+ '@11labs/client@0.2.0(@types/dom-mediacapture-record@1.0.22)':
+ dependencies:
+ livekit-client: 2.17.2(@types/dom-mediacapture-record@1.0.22)
+ transitivePeerDependencies:
+ - '@types/dom-mediacapture-record'
+
'@acemir/cssom@0.9.29': {}
'@alcyone-labs/zod-to-json-schema@4.0.10(zod@4.2.1)':
@@ -9494,6 +9567,8 @@ snapshots:
'@bcoe/v8-coverage@1.0.2': {}
+ '@bufbuild/protobuf@1.10.1': {}
+
'@changesets/apply-release-plan@7.0.14':
dependencies:
'@changesets/config': 3.1.2
@@ -10168,6 +10243,12 @@ snapshots:
'@jridgewell/resolve-uri': 3.1.2
'@jridgewell/sourcemap-codec': 1.5.5
+ '@livekit/mutex@1.1.1': {}
+
+ '@livekit/protocol@1.44.0':
+ dependencies:
+ '@bufbuild/protobuf': 1.10.1
+
'@manypkg/find-root@1.1.0':
dependencies:
'@babel/runtime': 7.28.4
@@ -12659,6 +12740,8 @@ snapshots:
'@types/deep-eql@4.0.2': {}
+ '@types/dom-mediacapture-record@1.0.22': {}
+
'@types/estree-jsx@1.0.5':
dependencies:
'@types/estree': 1.0.8
@@ -15292,6 +15375,8 @@ snapshots:
jju@1.4.0: {}
+ jose@6.2.0: {}
+
js-beautify@1.15.4:
dependencies:
config-chain: 1.1.13
@@ -15511,6 +15596,20 @@ snapshots:
untun: 0.1.3
uqr: 0.1.2
+ livekit-client@2.17.2(@types/dom-mediacapture-record@1.0.22):
+ dependencies:
+ '@livekit/mutex': 1.1.1
+ '@livekit/protocol': 1.44.0
+ '@types/dom-mediacapture-record': 1.0.22
+ events: 3.3.0
+ jose: 6.2.0
+ loglevel: 1.9.2
+ sdp-transform: 2.15.0
+ ts-debounce: 4.0.0
+ tslib: 2.8.1
+ typed-emitter: 2.1.0
+ webrtc-adapter: 9.0.4
+
local-pkg@0.5.1:
dependencies:
mlly: 1.8.0
@@ -15547,6 +15646,8 @@ snapshots:
chalk: 4.1.2
is-unicode-supported: 0.1.0
+ loglevel@1.9.2: {}
+
long@5.3.2: {}
longest-streak@3.1.0: {}
@@ -17191,6 +17292,10 @@ snapshots:
scule@1.3.0: {}
+ sdp-transform@2.15.0: {}
+
+ sdp@3.2.1: {}
+
semver@6.3.1: {}
semver@7.5.4:
@@ -17692,6 +17797,8 @@ snapshots:
dependencies:
typescript: 5.9.3
+ ts-debounce@4.0.0: {}
+
ts-declaration-location@1.0.7(typescript@5.9.3):
dependencies:
picomatch: 4.0.3
@@ -17759,6 +17866,10 @@ snapshots:
media-typer: 1.1.0
mime-types: 3.0.2
+ typed-emitter@2.1.0:
+ optionalDependencies:
+ rxjs: 7.8.2
+
typedoc-plugin-frontmatter@1.3.0(typedoc-plugin-markdown@4.9.0(typedoc@0.28.14(typescript@5.9.3))):
dependencies:
typedoc-plugin-markdown: 4.9.0(typedoc@0.28.14(typescript@5.9.3))
@@ -18520,6 +18631,10 @@ snapshots:
webpack-virtual-modules@0.6.2: {}
+ webrtc-adapter@9.0.4:
+ dependencies:
+ sdp: 3.2.1
+
whatwg-encoding@3.1.1:
dependencies:
iconv-lite: 0.6.3
From dc7c45fe07f4a945feca9623fe381b500f395362 Mon Sep 17 00:00:00 2001
From: Jack Herrington
Date: Thu, 5 Mar 2026 18:49:52 -0800
Subject: [PATCH 07/31] API further improved
---
.../src/components/AudioSparkline.tsx | 81 +++++++++++
.../ts-react-chat/src/lib/use-realtime.ts | 80 +++++++++++
.../src/routes/api.realtime-token.ts | 73 ----------
.../ts-react-chat/src/routes/realtime.tsx | 132 +-----------------
.../ai-openai/src/realtime/adapter.ts | 4 +-
packages/typescript/ai/src/realtime/types.ts | 16 ++-
6 files changed, 177 insertions(+), 209 deletions(-)
create mode 100644 examples/ts-react-chat/src/components/AudioSparkline.tsx
create mode 100644 examples/ts-react-chat/src/lib/use-realtime.ts
delete mode 100644 examples/ts-react-chat/src/routes/api.realtime-token.ts
diff --git a/examples/ts-react-chat/src/components/AudioSparkline.tsx b/examples/ts-react-chat/src/components/AudioSparkline.tsx
new file mode 100644
index 0000000000..edc51b4a62
--- /dev/null
+++ b/examples/ts-react-chat/src/components/AudioSparkline.tsx
@@ -0,0 +1,81 @@
+import { useEffect, useRef } from 'react'
+
+export function AudioSparkline({
+ getData,
+ color,
+ label,
+}: {
+ getData: () => Uint8Array
+ color: string
+ label: string
+}) {
+ const canvasRef = useRef(null)
+ const animationRef = useRef(null)
+
+ useEffect(() => {
+ const canvas = canvasRef.current
+ if (!canvas) return
+
+ const ctx = canvas.getContext('2d')
+ if (!ctx) return
+
+ function draw() {
+ const data = getData()
+ const width = canvas!.width
+ const height = canvas!.height
+
+ ctx!.fillStyle = '#1f2937'
+ ctx!.fillRect(0, 0, width, height)
+
+ ctx!.strokeStyle = color
+ ctx!.lineWidth = 1
+ ctx!.beginPath()
+
+ const step = Math.max(1, Math.floor(data.length / width))
+
+ for (let i = 0; i < width; i++) {
+ const dataIndex = Math.min(i * step, data.length - 1)
+ const value = data[dataIndex] ?? 128
+ const y = height - (value / 255) * height
+
+ if (i === 0) {
+ ctx!.moveTo(i, y)
+ } else {
+ ctx!.lineTo(i, y)
+ }
+ }
+
+ ctx!.stroke()
+
+ ctx!.strokeStyle = '#4b5563'
+ ctx!.setLineDash([2, 2])
+ ctx!.beginPath()
+ ctx!.moveTo(0, height / 2)
+ ctx!.lineTo(width, height / 2)
+ ctx!.stroke()
+ ctx!.setLineDash([])
+
+ animationRef.current = requestAnimationFrame(draw)
+ }
+
+ draw()
+
+ return () => {
+ if (animationRef.current) {
+ cancelAnimationFrame(animationRef.current)
+ }
+ }
+ }, [getData, color])
+
+ return (
+
+ {label}
+
+
+ )
+}
diff --git a/examples/ts-react-chat/src/lib/use-realtime.ts b/examples/ts-react-chat/src/lib/use-realtime.ts
new file mode 100644
index 0000000000..df450efa7f
--- /dev/null
+++ b/examples/ts-react-chat/src/lib/use-realtime.ts
@@ -0,0 +1,80 @@
+import { createServerFn } from '@tanstack/react-start'
+import { realtimeToken } from '@tanstack/ai'
+import { useRealtimeChat } from '@tanstack/ai-react'
+import { openaiRealtime, openaiRealtimeToken } from '@tanstack/ai-openai'
+import {
+ elevenlabsRealtime,
+ elevenlabsRealtimeToken,
+} from '@tanstack/ai-elevenlabs'
+import { realtimeClientTools } from '@/lib/realtime-tools'
+
+type Provider = 'openai' | 'elevenlabs'
+
+const getRealtimeTokenFn = createServerFn({ method: 'POST' })
+ .inputValidator(
+ (data: { provider: Provider; agentId?: string }) => {
+ if (!data.provider) throw new Error('Provider is required')
+ return data
+ },
+ )
+ .handler(async ({ data }) => {
+ if (data.provider === 'openai') {
+ return realtimeToken({
+ adapter: openaiRealtimeToken({
+ model: 'gpt-4o-realtime-preview',
+ }),
+ })
+ }
+
+ if (data.provider === 'elevenlabs') {
+ const agentId = data.agentId || process.env.ELEVENLABS_AGENT_ID
+ if (!agentId) {
+ throw new Error(
+ 'ElevenLabs agent ID is required. Set ELEVENLABS_AGENT_ID or pass agentId in request body.',
+ )
+ }
+ return realtimeToken({
+ adapter: elevenlabsRealtimeToken({ agentId }),
+ })
+ }
+
+ throw new Error(`Unknown provider: ${data.provider}`)
+ })
+
+export function useRealtime({
+ provider,
+ agentId,
+}: {
+ provider: Provider
+ agentId: string
+}) {
+ const adapter =
+ provider === 'openai' ? openaiRealtime() : elevenlabsRealtime()
+
+ return useRealtimeChat({
+ getToken: () =>
+ getRealtimeTokenFn({
+ data: {
+ provider,
+ ...(provider === 'elevenlabs' && agentId ? { agentId } : {}),
+ },
+ }),
+ adapter,
+ instructions: `You are a helpful, friendly voice assistant with access to several tools.
+
+You can:
+- Tell the user the current time and date (getCurrentTime)
+- Get weather information for any location (getWeather)
+- Set reminders for the user (setReminder)
+- Search a knowledge base for information (searchKnowledge)
+
+Keep your responses concise and conversational since this is a voice interface.
+When using tools, briefly explain what you're doing and then share the results naturally.
+Be friendly and engaging!`,
+ voice: 'alloy',
+ tools: realtimeClientTools,
+ onError: (err) => {
+ console.error('Realtime error:', err)
+ },
+ })
+}
diff --git a/examples/ts-react-chat/src/routes/api.realtime-token.ts b/examples/ts-react-chat/src/routes/api.realtime-token.ts
deleted file mode 100644
index 62fb08d8d2..0000000000
--- a/examples/ts-react-chat/src/routes/api.realtime-token.ts
+++ /dev/null
@@ -1,73 +0,0 @@
-import { createFileRoute } from '@tanstack/react-router'
-import { realtimeToken } from '@tanstack/ai'
-import { openaiRealtimeToken } from '@tanstack/ai-openai'
-import { elevenlabsRealtimeToken } from '@tanstack/ai-elevenlabs'
-
-type Provider = 'openai' | 'elevenlabs'
-
-export const Route = createFileRoute('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/api/realtime-token')({
- server: {
- handlers: {
- POST: async ({ request }) => {
- try {
- const body = await request.json()
- const provider: Provider = body.provider || 'openai'
-
- let token
-
- if (provider === 'openai') {
- token = await realtimeToken({
- adapter: openaiRealtimeToken({
- model: 'gpt-4o-realtime-preview',
- }),
- })
- } else if (provider === 'elevenlabs') {
- const agentId = body.agentId || process.env.ELEVENLABS_AGENT_ID
-
- if (!agentId) {
- return new Response(
- JSON.stringify({
- error:
- 'ElevenLabs agent ID is required. Set ELEVENLABS_AGENT_ID or pass agentId in request body.',
- }),
- {
- status: 400,
- headers: { 'Content-Type': 'application/json' },
- },
- )
- }
-
- token = await realtimeToken({
- adapter: elevenlabsRealtimeToken({
- agentId,
- }),
- })
- } else {
- return new Response(
- JSON.stringify({ error: `Unknown provider: ${provider}` }),
- {
- status: 400,
- headers: { 'Content-Type': 'application/json' },
- },
- )
- }
-
- return new Response(JSON.stringify(token), {
- headers: { 'Content-Type': 'application/json' },
- })
- } catch (error: any) {
- console.error('[Realtime Token API] Error:', error)
- return new Response(
- JSON.stringify({
- error: error.message || 'Failed to generate realtime token',
- }),
- {
- status: 500,
- headers: { 'Content-Type': 'application/json' },
- },
- )
- }
- },
- },
- },
-})
diff --git a/examples/ts-react-chat/src/routes/realtime.tsx b/examples/ts-react-chat/src/routes/realtime.tsx
index 272243aa82..13d4c3adfd 100644
--- a/examples/ts-react-chat/src/routes/realtime.tsx
+++ b/examples/ts-react-chat/src/routes/realtime.tsx
@@ -1,10 +1,8 @@
import { useEffect, useRef, useState } from 'react'
import { createFileRoute } from '@tanstack/react-router'
-import { useRealtimeChat } from '@tanstack/ai-react'
-import { openaiRealtime } from '@tanstack/ai-openai'
-import { elevenlabsRealtime } from '@tanstack/ai-elevenlabs'
import { Mic, MicOff, Phone, PhoneOff, Volume2, Wrench } from 'lucide-react'
-import { realtimeClientTools } from '@/lib/realtime-tools'
+import { AudioSparkline } from '@/components/AudioSparkline'
+import { useRealtime } from '@/lib/use-realtime'
type Provider = 'openai' | 'elevenlabs'
@@ -13,101 +11,11 @@ const PROVIDER_OPTIONS: Array<{ value: Provider; label: string }> = [
{ value: 'elevenlabs', label: 'ElevenLabs' },
]
-// Sparkline component to visualize audio waveform
-function AudioSparkline({
- getData,
- color,
- label,
-}: {
- getData: () => Uint8Array
- color: string
- label: string
-}) {
- const canvasRef = useRef(null)
- const animationRef = useRef(null)
-
- useEffect(() => {
- const canvas = canvasRef.current
- if (!canvas) return
-
- const ctx = canvas.getContext('2d')
- if (!ctx) return
-
- function draw() {
- const data = getData()
- const width = canvas!.width
- const height = canvas!.height
-
- // Clear canvas
- ctx!.fillStyle = '#1f2937' // gray-800
- ctx!.fillRect(0, 0, width, height)
-
- // Draw waveform
- ctx!.strokeStyle = color
- ctx!.lineWidth = 1
- ctx!.beginPath()
-
- // Sample the data to fit the canvas width
- const step = Math.max(1, Math.floor(data.length / width))
-
- for (let i = 0; i < width; i++) {
- const dataIndex = Math.min(i * step, data.length - 1)
- const value = data[dataIndex] ?? 128
- // Convert 0-255 to canvas height (128 is center/silence)
- const y = height - (value / 255) * height
-
- if (i === 0) {
- ctx!.moveTo(i, y)
- } else {
- ctx!.lineTo(i, y)
- }
- }
-
- ctx!.stroke()
-
- // Draw center line (silence level)
- ctx!.strokeStyle = '#4b5563' // gray-600
- ctx!.setLineDash([2, 2])
- ctx!.beginPath()
- ctx!.moveTo(0, height / 2)
- ctx!.lineTo(width, height / 2)
- ctx!.stroke()
- ctx!.setLineDash([])
-
- animationRef.current = requestAnimationFrame(draw)
- }
-
- draw()
-
- return () => {
- if (animationRef.current) {
- cancelAnimationFrame(animationRef.current)
- }
- }
- }, [getData, color])
-
- return (
-
- {label}
-
-
- )
-}
-
function RealtimePage() {
const [provider, setProvider] = useState('openai')
const [agentId, setAgentId] = useState('')
const messagesEndRef = useRef(null)
- // Get the appropriate adapter based on provider
- const adapter =
- provider === 'openai' ? openaiRealtime() : elevenlabsRealtime()
-
const {
status,
mode,
@@ -122,41 +30,7 @@ function RealtimePage() {
outputLevel,
getInputTimeDomainData,
getOutputTimeDomainData,
- } = useRealtimeChat({
- getToken: async () => {
- const body: Record = { provider }
- if (provider === 'elevenlabs' && agentId) {
- body.agentId = agentId
- }
- const response = await fetch('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/api/realtime-token', {
- method: 'POST',
- headers: { 'Content-Type': 'application/json' },
- body: JSON.stringify(body),
- })
- if (!response.ok) {
- const error = await response.json()
- throw new Error(error.error || 'Failed to get token')
- }
- return response.json()
- },
- adapter,
- instructions: `You are a helpful, friendly voice assistant with access to several tools.
-
-You can:
-- Tell the user the current time and date (getCurrentTime)
-- Get weather information for any location (getWeather)
-- Set reminders for the user (setReminder)
-- Search a knowledge base for information (searchKnowledge)
-
-Keep your responses concise and conversational since this is a voice interface.
-When using tools, briefly explain what you're doing and then share the results naturally.
-Be friendly and engaging!`,
- voice: 'alloy',
- tools: realtimeClientTools,
- onError: (err) => {
- console.error('Realtime error:', err)
- },
- })
+ } = useRealtime({ provider, agentId })
// Auto-scroll to bottom when messages change
useEffect(() => {
diff --git a/packages/typescript/ai-openai/src/realtime/adapter.ts b/packages/typescript/ai-openai/src/realtime/adapter.ts
index 03bc7da7aa..0f9fbcf133 100644
--- a/packages/typescript/ai-openai/src/realtime/adapter.ts
+++ b/packages/typescript/ai-openai/src/realtime/adapter.ts
@@ -502,9 +502,7 @@ async function createWebRTCConnection(
type: 'function',
name: t.name,
description: t.description,
- parameters: t.inputSchema
- ? (t.inputSchema as Record)
- : { type: 'object', properties: {} },
+ parameters: t.inputSchema ?? { type: 'object', properties: {} },
}))
sessionUpdate.tool_choice = 'auto'
}
diff --git a/packages/typescript/ai/src/realtime/types.ts b/packages/typescript/ai/src/realtime/types.ts
index 8a4be3a98a..94ae56b32c 100644
--- a/packages/typescript/ai/src/realtime/types.ts
+++ b/packages/typescript/ai/src/realtime/types.ts
@@ -1,5 +1,3 @@
-import type { Tool } from '../types'
-
// ============================================================================
// Token Types
// ============================================================================
@@ -16,6 +14,16 @@ export interface VADConfig {
silenceDurationMs?: number
}
+/**
+ * Serializable tool descriptor for realtime session configuration.
+ * Contains only the metadata needed by providers, not Zod schemas or execute functions.
+ */
+export interface RealtimeToolConfig {
+ name: string
+ description: string
+ inputSchema?: Record
+}
+
/**
* Configuration for a realtime session
*/
@@ -27,13 +35,13 @@ export interface RealtimeSessionConfig {
/** System instructions for the assistant */
instructions?: string
/** Tools available in the session */
- tools?: Array
+ tools?: Array
/** VAD mode */
vadMode?: 'server' | 'semantic' | 'manual'
/** VAD configuration */
vadConfig?: VADConfig
/** Provider-specific options */
- providerOptions?: Record
+ providerOptions?: Record
}
/**
From ddca0d6bbf01f927cb2aa886eb9538b9f9a45d0f Mon Sep 17 00:00:00 2001
From: Jack Herrington
Date: Thu, 5 Mar 2026 19:11:21 -0800
Subject: [PATCH 08/31] API further improved
---
examples/ts-react-chat/src/routeTree.gen.ts | 21 ---------------------
1 file changed, 21 deletions(-)
diff --git a/examples/ts-react-chat/src/routeTree.gen.ts b/examples/ts-react-chat/src/routeTree.gen.ts
index 89221b1ded..7888fee4bb 100644
--- a/examples/ts-react-chat/src/routeTree.gen.ts
+++ b/examples/ts-react-chat/src/routeTree.gen.ts
@@ -12,7 +12,6 @@ import { Route as rootRouteImport } from './routes/__root'
import { Route as RealtimeRouteImport } from './routes/realtime'
import { Route as IndexRouteImport } from './routes/index'
import { Route as ApiTanchatRouteImport } from './routes/api.tanchat'
-import { Route as ApiRealtimeTokenRouteImport } from './routes/api.realtime-token'
import { Route as ExampleGuitarsIndexRouteImport } from './routes/example.guitars/index'
import { Route as ExampleGuitarsGuitarIdRouteImport } from './routes/example.guitars/$guitarId'
@@ -31,11 +30,6 @@ const ApiTanchatRoute = ApiTanchatRouteImport.update({
path: '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/api/tanchat',
getParentRoute: () => rootRouteImport,
} as any)
-const ApiRealtimeTokenRoute = ApiRealtimeTokenRouteImport.update({
- id: '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/api/realtime-token',
- path: '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/api/realtime-token',
- getParentRoute: () => rootRouteImport,
-} as any)
const ExampleGuitarsIndexRoute = ExampleGuitarsIndexRouteImport.update({
id: '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/example/guitars/',
path: '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/example/guitars/',
@@ -50,7 +44,6 @@ const ExampleGuitarsGuitarIdRoute = ExampleGuitarsGuitarIdRouteImport.update({
export interface FileRoutesByFullPath {
'/': typeof IndexRoute
'/realtime': typeof RealtimeRoute
- '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/api/realtime-token': typeof ApiRealtimeTokenRoute
'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/api/tanchat': typeof ApiTanchatRoute
'/example/guitars/$guitarId': typeof ExampleGuitarsGuitarIdRoute
'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/example/guitars/': typeof ExampleGuitarsIndexRoute
@@ -58,7 +51,6 @@ export interface FileRoutesByFullPath {
export interface FileRoutesByTo {
'/': typeof IndexRoute
'/realtime': typeof RealtimeRoute
- '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/api/realtime-token': typeof ApiRealtimeTokenRoute
'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/api/tanchat': typeof ApiTanchatRoute
'/example/guitars/$guitarId': typeof ExampleGuitarsGuitarIdRoute
'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/example/guitars': typeof ExampleGuitarsIndexRoute
@@ -67,7 +59,6 @@ export interface FileRoutesById {
__root__: typeof rootRouteImport
'/': typeof IndexRoute
'/realtime': typeof RealtimeRoute
- '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/api/realtime-token': typeof ApiRealtimeTokenRoute
'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/api/tanchat': typeof ApiTanchatRoute
'/example/guitars/$guitarId': typeof ExampleGuitarsGuitarIdRoute
'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/example/guitars/': typeof ExampleGuitarsIndexRoute
@@ -77,7 +68,6 @@ export interface FileRouteTypes {
fullPaths:
| '/'
| '/realtime'
- | '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/api/realtime-token'
| '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/api/tanchat'
| '/example/guitars/$guitarId'
| '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/example/guitars/'
@@ -85,7 +75,6 @@ export interface FileRouteTypes {
to:
| '/'
| '/realtime'
- | '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/api/realtime-token'
| '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/api/tanchat'
| '/example/guitars/$guitarId'
| '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/example/guitars'
@@ -93,7 +82,6 @@ export interface FileRouteTypes {
| '__root__'
| '/'
| '/realtime'
- | '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/api/realtime-token'
| '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/api/tanchat'
| '/example/guitars/$guitarId'
| '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/example/guitars/'
@@ -102,7 +90,6 @@ export interface FileRouteTypes {
export interface RootRouteChildren {
IndexRoute: typeof IndexRoute
RealtimeRoute: typeof RealtimeRoute
- ApiRealtimeTokenRoute: typeof ApiRealtimeTokenRoute
ApiTanchatRoute: typeof ApiTanchatRoute
ExampleGuitarsGuitarIdRoute: typeof ExampleGuitarsGuitarIdRoute
ExampleGuitarsIndexRoute: typeof ExampleGuitarsIndexRoute
@@ -131,13 +118,6 @@ declare module '@tanstack/react-router' {
preLoaderRoute: typeof ApiTanchatRouteImport
parentRoute: typeof rootRouteImport
}
- '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/api/realtime-token': {
- id: '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/api/realtime-token'
- path: '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/api/realtime-token'
- fullPath: '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/api/realtime-token'
- preLoaderRoute: typeof ApiRealtimeTokenRouteImport
- parentRoute: typeof rootRouteImport
- }
'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/example/guitars/': {
id: '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/example/guitars/'
path: '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/example/guitars'
@@ -158,7 +138,6 @@ declare module '@tanstack/react-router' {
const rootRouteChildren: RootRouteChildren = {
IndexRoute: IndexRoute,
RealtimeRoute: RealtimeRoute,
- ApiRealtimeTokenRoute: ApiRealtimeTokenRoute,
ApiTanchatRoute: ApiTanchatRoute,
ExampleGuitarsGuitarIdRoute: ExampleGuitarsGuitarIdRoute,
ExampleGuitarsIndexRoute: ExampleGuitarsIndexRoute,
From 4025e8777eac1ab2e39cce55220055305fdedd52 Mon Sep 17 00:00:00 2001
From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com>
Date: Fri, 6 Mar 2026 03:14:29 +0000
Subject: [PATCH 09/31] ci: apply automated fixes
---
examples/ts-react-chat/src/lib/use-realtime.ts | 10 ++++------
packages/typescript/ai-client/src/realtime-client.ts | 3 ++-
2 files changed, 6 insertions(+), 7 deletions(-)
diff --git a/examples/ts-react-chat/src/lib/use-realtime.ts b/examples/ts-react-chat/src/lib/use-realtime.ts
index df450efa7f..f54da4ef72 100644
--- a/examples/ts-react-chat/src/lib/use-realtime.ts
+++ b/examples/ts-react-chat/src/lib/use-realtime.ts
@@ -11,12 +11,10 @@ import { realtimeClientTools } from '@/lib/realtime-tools'
type Provider = 'openai' | 'elevenlabs'
const getRealtimeTokenFn = createServerFn({ method: 'POST' })
- .inputValidator(
- (data: { provider: Provider; agentId?: string }) => {
- if (!data.provider) throw new Error('Provider is required')
- return data
- },
- )
+ .inputValidator((data: { provider: Provider; agentId?: string }) => {
+ if (!data.provider) throw new Error('Provider is required')
+ return data
+ })
.handler(async ({ data }) => {
if (data.provider === 'openai') {
return realtimeToken({
diff --git a/packages/typescript/ai-client/src/realtime-client.ts b/packages/typescript/ai-client/src/realtime-client.ts
index 4ce1502147..1a4bd97106 100644
--- a/packages/typescript/ai-client/src/realtime-client.ts
+++ b/packages/typescript/ai-client/src/realtime-client.ts
@@ -448,7 +448,8 @@ export class RealtimeClient {
if (!this.connection) return
const { instructions, voice, vadMode, tools } = this.options
- const hasConfig = instructions || voice || vadMode || (tools && tools.length > 0)
+ const hasConfig =
+ instructions || voice || vadMode || (tools && tools.length > 0)
if (!hasConfig) return
const toolsConfig = tools
From a5f98794ec14a33173345a1bcee6a90517dd0744 Mon Sep 17 00:00:00 2001
From: Jack Herrington
Date: Thu, 5 Mar 2026 19:25:52 -0800
Subject: [PATCH 10/31] Updating the docs
---
docs/architecture/realtime-chat.md | 29 +++++++++++++++++------------
1 file changed, 17 insertions(+), 12 deletions(-)
diff --git a/docs/architecture/realtime-chat.md b/docs/architecture/realtime-chat.md
index fcf15a0f0e..315482a51e 100644
--- a/docs/architecture/realtime-chat.md
+++ b/docs/architecture/realtime-chat.md
@@ -58,7 +58,7 @@ The realtime chat system provides a vendor-neutral, type-safe abstraction for vo
┌─────────────────────────────────────────────────────────────────┐
│ Server-Side │
│ ┌─────────────────────────────────────────────────────────┐ │
-│ │ Token Generation Endpoint │ │
+│ │ Token Generation (Server Function) │ │
│ │ - openaiRealtimeToken() - ephemeral client secrets │ │
│ │ - elevenlabsRealtimeToken() - signed URLs │ │
│ │ (Minimal config: model only — session config is │ │
@@ -74,15 +74,19 @@ The realtime chat system provides a vendor-neutral, type-safe abstraction for vo
Token adapters generate short-lived credentials for client-side connections. This keeps API keys secure on the server. The token endpoint sends **only the model** to the provider; all other session configuration (instructions, voice, tools, VAD) is applied client-side.
```typescript
-// Server-side token endpoint
+// Server function (TanStack Start)
+import { createServerFn } from '@tanstack/react-start'
import { realtimeToken } from '@tanstack/ai'
import { openaiRealtimeToken } from '@tanstack/ai-openai'
-const token = await realtimeToken({
- adapter: openaiRealtimeToken({
- model: 'gpt-4o-realtime-preview',
- }),
-})
+const getRealtimeTokenFn = createServerFn({ method: 'POST' })
+ .handler(async () => {
+ return realtimeToken({
+ adapter: openaiRealtimeToken({
+ model: 'gpt-4o-realtime-preview',
+ }),
+ })
+ })
```
**Token Structure:**
@@ -155,7 +159,7 @@ const {
getInputTimeDomainData,
getOutputTimeDomainData,
} = useRealtimeChat({
- getToken: () => fetch('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/api/realtime-token').then(r => r.json()),
+ getToken: () => getRealtimeTokenFn(),
adapter: openaiRealtime(),
instructions: 'You are a helpful voice assistant.',
voice: 'alloy',
@@ -173,7 +177,7 @@ sequenceDiagram
participant Server
participant OpenAI
- Browser->>Server: POST /api/realtime-token
+ Browser->>Server: getRealtimeTokenFn() (server function)
Server->>OpenAI: POST /v1/realtime/sessions (model only)
OpenAI-->>Server: { client_secret, expires_at }
Server-->>Browser: RealtimeToken
@@ -206,7 +210,7 @@ sequenceDiagram
participant Server
participant ElevenLabs
- Browser->>Server: POST /api/realtime-token
+ Browser->>Server: getRealtimeTokenFn() (server function)
Server->>ElevenLabs: POST /v1/convai/conversation/get_signed_url
ElevenLabs-->>Server: { signed_url }
Server-->>Browser: RealtimeToken
@@ -280,7 +284,7 @@ When connecting, the `RealtimeClient` calls `applySessionConfig()` which sends a
- **instructions** — System prompt for the assistant
- **voice** — Voice to use for audio output (e.g., `'alloy'`)
-- **tools** — Array of tool definitions with JSON Schema parameters, plus `tool_choice: 'auto'`
+- **tools** — Array of `RealtimeToolConfig` descriptors (name, description, JSON Schema parameters), plus `tool_choice: 'auto'`
- **turn_detection** — VAD configuration (server_vad, semantic_vad, or manual)
- **input_audio_transcription** — Enables user speech transcription (e.g., Whisper)
@@ -389,5 +393,6 @@ ELEVENLABS_AGENT_ID=... # Optional, for ElevenLabs
### Demo Application
- `examples/ts-react-chat/src/routes/realtime.tsx` - Demo UI component
-- `examples/ts-react-chat/src/routes/api.realtime-token.ts` - Token API endpoint
+- `examples/ts-react-chat/src/lib/use-realtime.ts` - Custom hook with server function for token generation
- `examples/ts-react-chat/src/lib/realtime-tools.ts` - Client-side tool definitions
+- `examples/ts-react-chat/src/components/AudioSparkline.tsx` - Audio waveform visualization component
From 2d8990eef6156d5498ef4a9823911869e5d07631 Mon Sep 17 00:00:00 2001
From: Jack Herrington
Date: Thu, 5 Mar 2026 20:22:03 -0800
Subject: [PATCH 11/31] text chat
---
.../ts-react-chat/src/routes/realtime.tsx | 43 ++++++++++++++++++-
.../ai-elevenlabs/src/realtime/adapter.ts | 9 ++--
.../ai-openai/src/realtime/adapter.ts | 21 ++++++++-
3 files changed, 65 insertions(+), 8 deletions(-)
diff --git a/examples/ts-react-chat/src/routes/realtime.tsx b/examples/ts-react-chat/src/routes/realtime.tsx
index 13d4c3adfd..df7c7d8871 100644
--- a/examples/ts-react-chat/src/routes/realtime.tsx
+++ b/examples/ts-react-chat/src/routes/realtime.tsx
@@ -1,6 +1,14 @@
import { useEffect, useRef, useState } from 'react'
import { createFileRoute } from '@tanstack/react-router'
-import { Mic, MicOff, Phone, PhoneOff, Volume2, Wrench } from 'lucide-react'
+import {
+ Mic,
+ MicOff,
+ Phone,
+ PhoneOff,
+ Send,
+ Volume2,
+ Wrench,
+} from 'lucide-react'
import { AudioSparkline } from '@/components/AudioSparkline'
import { useRealtime } from '@/lib/use-realtime'
@@ -14,6 +22,7 @@ const PROVIDER_OPTIONS: Array<{ value: Provider; label: string }> = [
function RealtimePage() {
const [provider, setProvider] = useState('openai')
const [agentId, setAgentId] = useState('')
+ const [textInput, setTextInput] = useState('')
const messagesEndRef = useRef(null)
const {
@@ -26,6 +35,7 @@ function RealtimePage() {
connect,
disconnect,
interrupt,
+ sendText,
inputLevel,
outputLevel,
getInputTimeDomainData,
@@ -258,6 +268,37 @@ function RealtimePage() {
)}
+ {/* Text input */}
+ {status === 'connected' && (
+
+
+
+ )}
+
{/* Audio visualization & controls */}
{/* Volume meters and waveforms */}
diff --git a/packages/typescript/ai-elevenlabs/src/realtime/adapter.ts b/packages/typescript/ai-elevenlabs/src/realtime/adapter.ts
index dfe33d3182..042e3ce733 100644
--- a/packages/typescript/ai-elevenlabs/src/realtime/adapter.ts
+++ b/packages/typescript/ai-elevenlabs/src/realtime/adapter.ts
@@ -147,12 +147,9 @@ async function createElevenLabsConnection(
emit('mode_change', { mode: 'idle' })
},
- sendText(_text: string) {
- // ElevenLabs doesn't support direct text input in the same way
- // The SDK is voice-first. Log a warning.
- console.warn(
- 'ElevenLabs realtime adapter does not support sendText. Use voice input.',
- )
+ sendText(text: string) {
+ if (!conversation) return
+ conversation.sendUserMessage(text)
},
sendToolResult(_callId: string, _result: string) {
diff --git a/packages/typescript/ai-openai/src/realtime/adapter.ts b/packages/typescript/ai-openai/src/realtime/adapter.ts
index 0f9fbcf133..043f60771c 100644
--- a/packages/typescript/ai-openai/src/realtime/adapter.ts
+++ b/packages/typescript/ai-openai/src/realtime/adapter.ts
@@ -236,6 +236,22 @@ async function createWebRTCConnection(
break
}
+ case 'response.output_text.delta': {
+ const delta = event.delta as string
+ emit('transcript', {
+ role: 'assistant',
+ transcript: delta,
+ isFinal: false,
+ })
+ break
+ }
+
+ case 'response.output_text.done': {
+ const text = event.text as string
+ emit('transcript', { role: 'assistant', transcript: text, isFinal: true })
+ break
+ }
+
case 'response.audio.delta':
if (currentMode !== 'speaking') {
currentMode = 'speaking'
@@ -453,7 +469,10 @@ async function createWebRTCConnection(
content: [{ type: 'input_text', text }],
},
})
- sendEvent({ type: 'response.create' })
+ sendEvent({
+ type: 'response.create',
+ response: { output_modalities: ['text'] },
+ })
},
sendToolResult(callId: string, result: string) {
From 62301f630421a4022ec901afdf8f130756c9bd1f Mon Sep 17 00:00:00 2001
From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com>
Date: Fri, 6 Mar 2026 04:25:37 +0000
Subject: [PATCH 12/31] ci: apply automated fixes
---
packages/typescript/ai-openai/src/realtime/adapter.ts | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/packages/typescript/ai-openai/src/realtime/adapter.ts b/packages/typescript/ai-openai/src/realtime/adapter.ts
index 043f60771c..2ca879e7ae 100644
--- a/packages/typescript/ai-openai/src/realtime/adapter.ts
+++ b/packages/typescript/ai-openai/src/realtime/adapter.ts
@@ -248,7 +248,11 @@ async function createWebRTCConnection(
case 'response.output_text.done': {
const text = event.text as string
- emit('transcript', { role: 'assistant', transcript: text, isFinal: true })
+ emit('transcript', {
+ role: 'assistant',
+ transcript: text,
+ isFinal: true,
+ })
break
}
From 2ca3efc833827feb491aa02a89c0fb3246a821d2 Mon Sep 17 00:00:00 2001
From: Jack Herrington
Date: Fri, 6 Mar 2026 14:08:22 -0800
Subject: [PATCH 13/31] Getting close to releasable
---
docs/architecture/realtime-chat.md | 398 ----------------
docs/config.json | 8 +
docs/guides/realtime-chat.md | 446 ++++++++++++++++++
docs/reference/classes/RealtimeClient.md | 276 +++++++++++
docs/reference/functions/realtimeToken.md | 75 +++
.../interfaces/AudioVisualization.md | 126 +++++
docs/reference/interfaces/RealtimeAdapter.md | 48 ++
.../interfaces/RealtimeClientOptions.md | 204 ++++++++
.../interfaces/RealtimeConnection.md | 210 +++++++++
docs/reference/interfaces/RealtimeMessage.md | 80 ++++
.../interfaces/RealtimeSessionConfig.md | 120 +++++
docs/reference/interfaces/RealtimeToken.md | 50 ++
.../interfaces/RealtimeTokenAdapter.md | 34 ++
.../interfaces/RealtimeTokenOptions.md | 23 +
docs/reference/type-aliases/RealtimeEvent.md | 33 ++
.../type-aliases/RealtimeMessagePart.md | 27 ++
docs/reference/type-aliases/RealtimeMode.md | 21 +
docs/reference/type-aliases/RealtimeStatus.md | 22 +
.../ts-react-chat/src/lib/use-realtime.ts | 13 +
.../ts-react-chat/src/routes/realtime.tsx | 164 ++++++-
.../ai-client/src/realtime-client.ts | 58 ++-
.../ai-client/src/realtime-types.ts | 30 +-
.../ai-elevenlabs/src/realtime/adapter.ts | 62 ++-
.../ai-openai/src/realtime/adapter.ts | 42 +-
.../ai-openai/src/realtime/types.ts | 4 +
.../typescript/ai-react/src/realtime-types.ts | 24 +
.../ai-react/src/use-realtime-chat.ts | 15 +
packages/typescript/ai/src/index.ts | 1 +
packages/typescript/ai/src/realtime/types.ts | 20 +
29 files changed, 2214 insertions(+), 420 deletions(-)
delete mode 100644 docs/architecture/realtime-chat.md
create mode 100644 docs/guides/realtime-chat.md
create mode 100644 docs/reference/classes/RealtimeClient.md
create mode 100644 docs/reference/functions/realtimeToken.md
create mode 100644 docs/reference/interfaces/AudioVisualization.md
create mode 100644 docs/reference/interfaces/RealtimeAdapter.md
create mode 100644 docs/reference/interfaces/RealtimeClientOptions.md
create mode 100644 docs/reference/interfaces/RealtimeConnection.md
create mode 100644 docs/reference/interfaces/RealtimeMessage.md
create mode 100644 docs/reference/interfaces/RealtimeSessionConfig.md
create mode 100644 docs/reference/interfaces/RealtimeToken.md
create mode 100644 docs/reference/interfaces/RealtimeTokenAdapter.md
create mode 100644 docs/reference/interfaces/RealtimeTokenOptions.md
create mode 100644 docs/reference/type-aliases/RealtimeEvent.md
create mode 100644 docs/reference/type-aliases/RealtimeMessagePart.md
create mode 100644 docs/reference/type-aliases/RealtimeMode.md
create mode 100644 docs/reference/type-aliases/RealtimeStatus.md
diff --git a/docs/architecture/realtime-chat.md b/docs/architecture/realtime-chat.md
deleted file mode 100644
index 315482a51e..0000000000
--- a/docs/architecture/realtime-chat.md
+++ /dev/null
@@ -1,398 +0,0 @@
----
-title: Realtime Voice Chat Architecture
-id: realtime-chat-architecture
----
-
-# Realtime Voice Chat Architecture
-
-This document describes the architecture of TanStack AI's realtime voice-to-voice chat capability, which enables browser-based voice conversations with AI models.
-
-## Overview
-
-The realtime chat system provides a vendor-neutral, type-safe abstraction for voice-to-voice AI interactions. It currently supports:
-
-- **OpenAI Realtime API** - WebRTC-based connection with GPT-4o realtime models
-- **ElevenLabs Conversational AI** - SDK-based connection for voice conversations
-
-## Architecture Layers
-
-```
-┌─────────────────────────────────────────────────────────────────┐
-│ React Application │
-│ ┌─────────────────────────────────────────────────────────┐ │
-│ │ useRealtimeChat() │ │
-│ │ - Connection state (status, mode) │ │
-│ │ - Messages & transcripts │ │
-│ │ - Audio visualization (levels, waveforms) │ │
-│ │ - Control methods (connect, disconnect, interrupt) │ │
-│ │ - Client-side tool configuration │ │
-│ └─────────────────────────────────────────────────────────┘ │
-└─────────────────────────────────────────────────────────────────┘
- │
- ▼
-┌─────────────────────────────────────────────────────────────────┐
-│ @tanstack/ai-client │
-│ ┌─────────────────────────────────────────────────────────┐ │
-│ │ RealtimeClient │ │
-│ │ - Connection lifecycle management │ │
-│ │ - Token refresh scheduling │ │
-│ │ - Client-side session configuration (tools, voice, etc) │ │
-│ │ - Event subscription & dispatch │ │
-│ │ - Tool execution coordination │ │
-│ └─────────────────────────────────────────────────────────┘ │
-└─────────────────────────────────────────────────────────────────┘
- │
- ▼
-┌─────────────────────────────────────────────────────────────────┐
-│ Provider Adapters │
-│ ┌──────────────────────┐ ┌──────────────────────┐ │
-│ │ openaiRealtime() │ │ elevenlabsRealtime() │ │
-│ │ - WebRTC connection │ │ - SDK wrapper │ │
-│ │ - Audio I/O │ │ - Signed URL auth │ │
-│ │ - Event mapping │ │ - Event mapping │ │
-│ │ - Session updates │ │ │ │
-│ └──────────────────────┘ └──────────────────────┘ │
-└─────────────────────────────────────────────────────────────────┘
- │
- ▼
-┌─────────────────────────────────────────────────────────────────┐
-│ Server-Side │
-│ ┌─────────────────────────────────────────────────────────┐ │
-│ │ Token Generation (Server Function) │ │
-│ │ - openaiRealtimeToken() - ephemeral client secrets │ │
-│ │ - elevenlabsRealtimeToken() - signed URLs │ │
-│ │ (Minimal config: model only — session config is │ │
-│ │ applied client-side via session.update) │ │
-│ └─────────────────────────────────────────────────────────┘ │
-└─────────────────────────────────────────────────────────────────┘
-```
-
-## Key Components
-
-### 1. Token Adapters (Server-Side)
-
-Token adapters generate short-lived credentials for client-side connections. This keeps API keys secure on the server. The token endpoint sends **only the model** to the provider; all other session configuration (instructions, voice, tools, VAD) is applied client-side.
-
-```typescript
-// Server function (TanStack Start)
-import { createServerFn } from '@tanstack/react-start'
-import { realtimeToken } from '@tanstack/ai'
-import { openaiRealtimeToken } from '@tanstack/ai-openai'
-
-const getRealtimeTokenFn = createServerFn({ method: 'POST' })
- .handler(async () => {
- return realtimeToken({
- adapter: openaiRealtimeToken({
- model: 'gpt-4o-realtime-preview',
- }),
- })
- })
-```
-
-**Token Structure:**
-```typescript
-interface RealtimeToken {
- provider: string // 'openai' | 'elevenlabs'
- token: string // Ephemeral token or signed URL
- expiresAt: number // Expiration timestamp (ms)
- config: RealtimeSessionConfig // Session configuration
-}
-```
-
-### 2. Client Adapters (Browser-Side)
-
-Client adapters handle the actual connection to provider APIs, managing:
-- WebRTC or WebSocket connections
-- Audio capture and playback
-- Event translation to common format
-- Audio visualization data
-- Session configuration updates (tools, instructions, voice, VAD)
-
-```typescript
-// Client-side adapter usage
-import { openaiRealtime } from '@tanstack/ai-openai'
-
-const adapter = openaiRealtime({
- connectionMode: 'webrtc', // default
-})
-```
-
-**Data Channel Readiness:** The OpenAI adapter waits for the WebRTC data channel to be fully open before returning the connection. If `updateSession()` is called before the channel is ready, events are queued and flushed once the channel opens.
-
-### 3. RealtimeClient
-
-The `RealtimeClient` class manages the connection lifecycle:
-
-- **Connection Management**: Connect, disconnect, reconnect
-- **Token Refresh**: Automatically refreshes tokens before expiry
-- **Session Configuration**: Applies client-side config (instructions, voice, tools, VAD) via `session.update` after connecting
-- **Event Handling**: Subscribes to adapter events and dispatches to callbacks
-- **State Management**: Tracks status, mode, messages, transcripts
-- **Tool Execution**: Looks up client-side tools by name, executes them, and sends results back to the provider
-
-### 4. useRealtimeChat Hook
-
-The React hook provides a reactive interface:
-
-```typescript
-const {
- // Connection state
- status, // 'idle' | 'connecting' | 'connected' | 'reconnecting' | 'error'
- error,
- connect,
- disconnect,
-
- // Conversation state
- mode, // 'idle' | 'listening' | 'thinking' | 'speaking'
- messages,
- pendingUserTranscript,
- pendingAssistantTranscript,
-
- // Voice control
- startListening,
- stopListening,
- interrupt,
-
- // Audio visualization
- inputLevel,
- outputLevel,
- getInputTimeDomainData,
- getOutputTimeDomainData,
-} = useRealtimeChat({
- getToken: () => getRealtimeTokenFn(),
- adapter: openaiRealtime(),
- instructions: 'You are a helpful voice assistant.',
- voice: 'alloy',
- tools: myClientTools,
-})
-```
-
-## Connection Flow
-
-### OpenAI WebRTC Flow
-
-```mermaid
-sequenceDiagram
- participant Browser
- participant Server
- participant OpenAI
-
- Browser->>Server: getRealtimeTokenFn() (server function)
- Server->>OpenAI: POST /v1/realtime/sessions (model only)
- OpenAI-->>Server: { client_secret, expires_at }
- Server-->>Browser: RealtimeToken
-
- Browser->>Browser: getUserMedia() - request mic
- Browser->>Browser: Create RTCPeerConnection
- Browser->>Browser: Add audio track to PC
- Browser->>Browser: createOffer()
-
- Browser->>OpenAI: POST /v1/realtime?model=...
- Note right of Browser: SDP offer + ephemeral token
- OpenAI-->>Browser: SDP answer
-
- Browser->>Browser: setRemoteDescription()
- Browser->>Browser: Wait for data channel open
- Note over Browser,OpenAI: WebRTC connection established
-
- Browser->>OpenAI: session.update (tools, instructions, voice, VAD)
- OpenAI-->>Browser: session.updated (confirms config)
-
- Browser->>OpenAI: Audio via WebRTC
- OpenAI-->>Browser: Audio + events via WebRTC
-```
-
-### ElevenLabs Flow
-
-```mermaid
-sequenceDiagram
- participant Browser
- participant Server
- participant ElevenLabs
-
- Browser->>Server: getRealtimeTokenFn() (server function)
- Server->>ElevenLabs: POST /v1/convai/conversation/get_signed_url
- ElevenLabs-->>Server: { signed_url }
- Server-->>Browser: RealtimeToken
-
- Browser->>ElevenLabs: Conversation.startSession(signedUrl)
- Note over Browser,ElevenLabs: SDK handles WebSocket/WebRTC
-
- Browser->>ElevenLabs: Audio via SDK
- ElevenLabs-->>Browser: Audio + events via SDK
-```
-
-## Client-Side Tool Calling
-
-Tools are defined once using `toolDefinition()` and instantiated for client-side execution with `.client()`. When the AI model invokes a tool, the `RealtimeClient` executes it locally in the browser and sends the result back to the provider.
-
-### Tool Definition
-
-```typescript
-import { toolDefinition } from '@tanstack/ai'
-import { z } from 'zod'
-
-const getWeatherToolDef = toolDefinition({
- name: 'getWeather',
- description: 'Get the current weather for a location.',
- inputSchema: z.object({
- location: z.string().describe('City and state/country'),
- }),
- outputSchema: z.object({
- location: z.string(),
- temperature: z.number(),
- condition: z.string(),
- }),
-})
-
-// Create client-side implementation
-const getWeatherClient = getWeatherToolDef.client(({ location }) => ({
- location,
- temperature: 72,
- condition: 'Sunny',
-}))
-```
-
-### Tool Call Flow
-
-```mermaid
-sequenceDiagram
- participant User
- participant Browser as Browser (RealtimeClient)
- participant OpenAI
-
- User->>Browser: "What's the weather in London?"
- Browser->>OpenAI: Audio via WebRTC
-
- OpenAI->>Browser: response.function_call_arguments.done
- Note right of OpenAI: { name: "getWeather", arguments: '{"location":"London"}' }
-
- Browser->>Browser: Look up tool in clientTools Map
- Browser->>Browser: Execute tool.execute(input)
- Browser->>OpenAI: conversation.item.create (function_call_output)
- Browser->>OpenAI: response.create
-
- OpenAI->>Browser: response.audio_transcript.delta
- Note right of OpenAI: "The weather in London is 72°F and sunny!"
- OpenAI->>Browser: response.done
- Browser->>User: Display message + play audio
-```
-
-### Session Configuration
-
-When connecting, the `RealtimeClient` calls `applySessionConfig()` which sends a `session.update` event to the provider with:
-
-- **instructions** — System prompt for the assistant
-- **voice** — Voice to use for audio output (e.g., `'alloy'`)
-- **tools** — Array of `RealtimeToolConfig` descriptors (name, description, JSON Schema parameters), plus `tool_choice: 'auto'`
-- **turn_detection** — VAD configuration (server_vad, semantic_vad, or manual)
-- **input_audio_transcription** — Enables user speech transcription (e.g., Whisper)
-
-Tool schemas are converted from Zod (or any Standard JSON Schema compliant library) to JSON Schema using `convertSchemaToJsonSchema()` before being sent to the provider.
-
-## Audio Visualization
-
-The system provides real-time audio visualization through the `AudioVisualization` interface:
-
-```typescript
-interface AudioVisualization {
- inputLevel: number // 0-1 normalized input volume
- outputLevel: number // 0-1 normalized output volume
- getInputFrequencyData(): Uint8Array // FFT frequency bins
- getOutputFrequencyData(): Uint8Array
- getInputTimeDomainData(): Uint8Array // Raw waveform samples
- getOutputTimeDomainData(): Uint8Array
- inputSampleRate: number
- outputSampleRate: number
-}
-```
-
-The OpenAI adapter uses Web Audio API `AnalyserNode` for visualization:
-- `fftSize: 2048` for high-resolution analysis
-- Peak amplitude detection for responsive volume meters
-- Separate analysers for input (microphone) and output (AI voice)
-
-## Event System
-
-Adapters emit standardized events:
-
-| Event | Payload | Description |
-|-------|---------|-------------|
-| `status_change` | `{ status }` | Connection status changed |
-| `mode_change` | `{ mode }` | Conversation mode changed |
-| `transcript` | `{ role, transcript, isFinal }` | Speech-to-text update |
-| `message_complete` | `{ message }` | Full message received |
-| `tool_call` | `{ toolCallId, toolName, input }` | Tool invocation requested |
-| `interrupted` | `{ messageId? }` | Response was interrupted |
-| `error` | `{ error }` | Error occurred |
-
-## Current Status
-
-### Implemented Features
-
-- [x] OpenAI Realtime API integration (WebRTC)
-- [x] ElevenLabs Conversational AI integration
-- [x] Token generation and refresh
-- [x] Audio capture and playback
-- [x] Real-time transcription display
-- [x] Audio visualization (levels, waveforms)
-- [x] Interrupt capability
-- [x] Client-side tool calling (define, execute, return results)
-- [x] Client-side session configuration (instructions, voice, tools, VAD)
-- [x] React hook (`useRealtimeChat`)
-- [x] Demo application at `/realtime` route with tool examples
-
-### Known Limitations
-
-- **Device Selection**: Currently uses system default audio devices. Custom device selection not yet implemented.
-- **ElevenLabs SDK**: Using `@11labs/client@0.2.0` which has limited TypeScript support.
-- **Push-to-Talk**: Manual VAD mode implemented but not exposed in demo UI.
-
-### Demo Application
-
-The `examples/ts-react-chat` application includes a realtime voice chat demo at the `/realtime` route:
-
-**Features:**
-- Provider selection (OpenAI / ElevenLabs)
-- Connection status indicator
-- Conversation mode indicator (Listening/Thinking/Speaking)
-- Message history with transcripts
-- Audio level meters
-- Waveform visualization
-- Interrupt button during AI speech
-- Client-side tool execution (getCurrentTime, getWeather, setReminder, searchKnowledge)
-
-**Required Environment Variables:**
-```bash
-OPENAI_API_KEY=sk-...
-ELEVENLABS_API_KEY=xi-... # Optional, for ElevenLabs
-ELEVENLABS_AGENT_ID=... # Optional, for ElevenLabs
-```
-
-## Files Reference
-
-### Core Types
-- `packages/typescript/ai/src/realtime/types.ts` - Core type definitions
-- `packages/typescript/ai-client/src/realtime-types.ts` - Client-side types
-
-### Token Generation (Server)
-- `packages/typescript/ai/src/realtime/index.ts` - `realtimeToken()` function
-- `packages/typescript/ai-openai/src/realtime/token.ts` - OpenAI token adapter
-- `packages/typescript/ai-elevenlabs/src/realtime/token.ts` - ElevenLabs token adapter
-
-### Client Adapters
-- `packages/typescript/ai-openai/src/realtime/adapter.ts` - OpenAI WebRTC adapter
-- `packages/typescript/ai-elevenlabs/src/realtime/adapter.ts` - ElevenLabs SDK adapter
-
-### Client Library
-- `packages/typescript/ai-client/src/realtime-client.ts` - RealtimeClient class
-
-### React Integration
-- `packages/typescript/ai-react/src/use-realtime-chat.ts` - React hook
-- `packages/typescript/ai-react/src/realtime-types.ts` - Hook types
-
-### Demo Application
-- `examples/ts-react-chat/src/routes/realtime.tsx` - Demo UI component
-- `examples/ts-react-chat/src/lib/use-realtime.ts` - Custom hook with server function for token generation
-- `examples/ts-react-chat/src/lib/realtime-tools.ts` - Client-side tool definitions
-- `examples/ts-react-chat/src/components/AudioSparkline.tsx` - Audio waveform visualization component
diff --git a/docs/config.json b/docs/config.json
index 1439169ae0..05d2f8932d 100644
--- a/docs/config.json
+++ b/docs/config.json
@@ -78,6 +78,10 @@
"label": "Runtime Adapter Switching",
"to": "guides/runtime-adapter-switching"
},
+ {
+ "label": "Realtime Voice Chat",
+ "to": "guides/realtime-chat"
+ },
{
"label": "Text-to-Speech",
"to": "guides/text-to-speech"
@@ -224,6 +228,10 @@
"label": "ToolCallManager",
"to": "reference/classes/ToolCallManager"
},
+ {
+ "label": "RealtimeClient",
+ "to": "reference/classes/RealtimeClient"
+ },
{
"label": "WordBoundaryStrategy",
"to": "reference/classes/WordBoundaryStrategy"
diff --git a/docs/guides/realtime-chat.md b/docs/guides/realtime-chat.md
new file mode 100644
index 0000000000..afe2943c62
--- /dev/null
+++ b/docs/guides/realtime-chat.md
@@ -0,0 +1,446 @@
+---
+title: Realtime Voice Chat
+id: realtime-chat
+order: 14
+---
+
+TanStack AI provides a complete realtime voice chat system for building voice-to-voice AI interactions. The realtime API supports multiple providers (OpenAI, ElevenLabs), automatic tool execution, audio visualization, and multimodal input including images.
+
+## Overview
+
+Realtime voice chat differs from text-based chat in several key ways:
+
+- **Bidirectional audio** - Users speak into a microphone, and the AI responds with synthesized voice
+- **Voice Activity Detection (VAD)** - Automatically detects when the user starts and stops speaking
+- **Interruptions** - Users can interrupt the AI mid-response
+- **Low latency** - Uses WebRTC or WebSocket connections for near-instant communication
+- **Multimodal** - Supports text input, image input, and tool calling alongside voice
+
+The realtime system follows the same adapter architecture as the rest of TanStack AI:
+
+1. **Server** generates ephemeral tokens using `realtimeToken()` with a provider-specific token adapter
+2. **Client** connects using `RealtimeClient` (or `useRealtimeChat` in React) with a provider-specific connection adapter
+3. **Provider adapters** handle the protocol differences between OpenAI WebRTC, ElevenLabs WebSocket, etc.
+
+## Quick Start
+
+### 1. Set Up the Server Token Endpoint
+
+The server generates short-lived tokens so your API keys never reach the client:
+
+```typescript
+import { realtimeToken } from '@tanstack/ai'
+import { openaiRealtimeToken } from '@tanstack/ai-openai'
+import { createServerFn } from '@tanstack/react-start'
+
+const getRealtimeToken = createServerFn({ method: 'POST' })
+ .handler(async () => {
+ return realtimeToken({
+ adapter: openaiRealtimeToken({
+ model: 'gpt-4o-realtime-preview',
+ }),
+ })
+ })
+```
+
+> **Note:** The `realtimeToken()` function works with any server framework. The example above uses TanStack Start, but you can use Express, Hono, Fastify, or any other framework that can handle HTTP requests.
+
+### 2. Connect from the Client (React)
+
+```typescript
+import { useRealtimeChat } from '@tanstack/ai-react'
+import { openaiRealtime } from '@tanstack/ai-openai'
+
+function VoiceChat() {
+ const {
+ status,
+ mode,
+ messages,
+ connect,
+ disconnect,
+ pendingUserTranscript,
+ pendingAssistantTranscript,
+ inputLevel,
+ outputLevel,
+ } = useRealtimeChat({
+ getToken: () => fetch('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/api/realtime-token', { method: 'POST' }).then(r => r.json()),
+ adapter: openaiRealtime(),
+ instructions: 'You are a helpful voice assistant.',
+ voice: 'alloy',
+ })
+
+ return (
+
+
Status: {status}
+
Mode: {mode}
+
+ {status === 'idle' ? 'Start Conversation' : 'End Conversation'}
+
+ {pendingUserTranscript &&
You: {pendingUserTranscript}...
}
+ {pendingAssistantTranscript &&
AI: {pendingAssistantTranscript}...
}
+ {messages.map((msg) => (
+
+ {msg.role}:
+ {msg.parts.map((part, i) => (
+
+ {part.type === 'text' ? part.content : null}
+ {part.type === 'audio' ? part.transcript : null}
+
+ ))}
+
+ ))}
+
+ )
+}
+```
+
+## Providers
+
+### OpenAI Realtime
+
+OpenAI's realtime API uses WebRTC for low-latency voice communication.
+
+**Server (token generation):**
+
+```typescript
+import { realtimeToken } from '@tanstack/ai'
+import { openaiRealtimeToken } from '@tanstack/ai-openai'
+
+const token = await realtimeToken({
+ adapter: openaiRealtimeToken({
+ model: 'gpt-4o-realtime-preview',
+ }),
+})
+```
+
+**Client (connection):**
+
+```typescript
+import { openaiRealtime } from '@tanstack/ai-openai'
+
+const adapter = openaiRealtime()
+```
+
+**Environment variables:** `OPENAI_API_KEY`
+
+**Available models:**
+
+| Model | Description |
+|-------|-------------|
+| `gpt-4o-realtime-preview` | Full realtime model |
+| `gpt-4o-mini-realtime-preview` | Smaller, faster realtime model |
+| `gpt-realtime` | Latest realtime model |
+| `gpt-realtime-mini` | Latest mini realtime model |
+
+**Available voices:** `alloy`, `ash`, `ballad`, `coral`, `echo`, `sage`, `shimmer`, `verse`, `marin`, `cedar`
+
+### ElevenLabs Realtime
+
+ElevenLabs uses WebSocket connections and requires an agent configured in their dashboard.
+
+**Server (token generation):**
+
+```typescript
+import { realtimeToken } from '@tanstack/ai'
+import { elevenlabsRealtimeToken } from '@tanstack/ai-elevenlabs'
+
+const token = await realtimeToken({
+ adapter: elevenlabsRealtimeToken({
+ agentId: 'your-agent-id',
+ }),
+})
+```
+
+**Client (connection):**
+
+```typescript
+import { elevenlabsRealtime } from '@tanstack/ai-elevenlabs'
+
+const adapter = elevenlabsRealtime()
+```
+
+**Environment variables:** `ELEVENLABS_API_KEY`, `ELEVENLABS_AGENT_ID` (optional)
+
+## Voice Activity Detection (VAD)
+
+VAD controls how the system detects when the user is speaking. Three modes are available:
+
+| Mode | Description |
+|------|-------------|
+| `server` | Provider handles speech detection server-side (default) |
+| `semantic` | Uses semantic understanding to detect turn boundaries (OpenAI only) |
+| `manual` | Application controls when to listen via `startListening()`/`stopListening()` |
+
+```typescript
+const chat = useRealtimeChat({
+ // ...
+ vadMode: 'semantic',
+ semanticEagerness: 'medium', // 'low' | 'medium' | 'high'
+})
+```
+
+With `manual` VAD mode, use push-to-talk style interactions:
+
+```typescript
+const { startListening, stopListening } = useRealtimeChat({
+ vadMode: 'manual',
+ autoCapture: false,
+ // ...
+})
+
+// In your UI
+
+ Hold to talk
+
+```
+
+## Tools
+
+Realtime sessions support client-side tools. Define tools using the standard `toolDefinition()` API and pass their client implementations:
+
+```typescript
+import { toolDefinition } from '@tanstack/ai'
+import { z } from 'zod'
+
+const getWeatherDef = toolDefinition({
+ name: 'getWeather',
+ description: 'Get weather for a location',
+ inputSchema: z.object({
+ location: z.string().meta({ description: 'City name' }),
+ }),
+ outputSchema: z.object({
+ temperature: z.number(),
+ conditions: z.string(),
+ }),
+})
+
+const getWeather = getWeatherDef.client(async ({ location }) => {
+ const res = await fetch(`/api/weather?location=${location}`)
+ return res.json()
+})
+
+// Pass tools to the hook
+const chat = useRealtimeChat({
+ // ...
+ tools: [getWeather],
+})
+```
+
+The realtime client automatically executes tool calls and sends results back to the provider. Tool calls appear as `tool-call` and `tool-result` parts in messages.
+
+## Text and Image Input
+
+In addition to voice, you can send text messages and images:
+
+```typescript
+const { sendText, sendImage } = useRealtimeChat({ /* ... */ })
+
+// Send a text message
+sendText('What is the weather like today?')
+
+// Send an image (base64 data or URL)
+sendImage(base64ImageData, 'image/png')
+```
+
+## Audio Visualization
+
+The hook provides real-time audio level data for building visualizations:
+
+```typescript
+const {
+ inputLevel, // 0-1 normalized microphone volume
+ outputLevel, // 0-1 normalized speaker volume
+ getInputFrequencyData, // Uint8Array for frequency spectrum
+ getOutputFrequencyData,
+ getInputTimeDomainData, // Uint8Array for waveform
+ getOutputTimeDomainData,
+} = useRealtimeChat({ /* ... */ })
+```
+
+The `inputLevel` and `outputLevel` values update on every animation frame while connected, making them suitable for driving CSS animations or canvas visualizations:
+
+```typescript
+function AudioIndicator({ level }: { level: number }) {
+ return (
+
+ )
+}
+```
+
+For more detailed visualizations, use the frequency and time-domain data getters inside a `requestAnimationFrame` loop.
+
+## Session Configuration
+
+Configure the realtime session through the hook options:
+
+| Option | Type | Default | Description |
+|--------|------|---------|-------------|
+| `getToken` | `() => Promise` | required | Function to fetch a token from the server |
+| `adapter` | `RealtimeAdapter` | required | Provider adapter (`openaiRealtime()`, `elevenlabsRealtime()`) |
+| `instructions` | `string` | — | System instructions for the assistant |
+| `voice` | `string` | — | Voice to use for audio output |
+| `tools` | `AnyClientTool[]` | — | Client-side tools with execution logic |
+| `vadMode` | `'server' \| 'semantic' \| 'manual'` | `'server'` | Voice activity detection mode |
+| `semanticEagerness` | `'low' \| 'medium' \| 'high'` | — | Eagerness for semantic VAD |
+| `autoPlayback` | `boolean` | `true` | Auto-play assistant audio |
+| `autoCapture` | `boolean` | `true` | Request microphone on connect |
+| `outputModalities` | `Array<'audio' \| 'text'>` | — | Response modalities |
+| `temperature` | `number` | — | Generation temperature |
+| `maxOutputTokens` | `number \| 'inf'` | — | Max tokens in a response |
+
+## Connection Lifecycle
+
+The realtime client manages a connection lifecycle with these statuses:
+
+| Status | Description |
+|--------|-------------|
+| `idle` | Not connected |
+| `connecting` | Establishing connection |
+| `connected` | Active session |
+| `reconnecting` | Reconnecting after interruption |
+| `error` | Connection error occurred |
+
+And these modes while connected:
+
+| Mode | Description |
+|------|-------------|
+| `idle` | Connected but not actively interacting |
+| `listening` | Capturing user audio input |
+| `thinking` | Processing user input |
+| `speaking` | AI is generating a response |
+
+```typescript
+const { status, mode, error, connect, disconnect } = useRealtimeChat({ /* ... */ })
+
+// Handle connection
+useEffect(() => {
+ if (status === 'error' && error) {
+ console.error('Connection error:', error.message)
+ }
+}, [status, error])
+```
+
+## Interruptions
+
+Users can interrupt the AI while it's speaking:
+
+```typescript
+const { interrupt, mode } = useRealtimeChat({ /* ... */ })
+
+// Programmatically interrupt
+if (mode === 'speaking') {
+ interrupt()
+}
+```
+
+With server or semantic VAD, interruptions happen automatically when the user starts speaking. Interrupted messages are marked with `interrupted: true` in the messages array.
+
+## Using RealtimeClient Directly
+
+For non-React applications or more control, use `RealtimeClient` directly:
+
+```typescript
+import { RealtimeClient } from '@tanstack/ai-client'
+import { openaiRealtime } from '@tanstack/ai-openai'
+
+const client = new RealtimeClient({
+ getToken: () => fetch('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/api/realtime-token', { method: 'POST' }).then(r => r.json()),
+ adapter: openaiRealtime(),
+ instructions: 'You are a helpful assistant.',
+ voice: 'alloy',
+ onMessage: (message) => {
+ console.log(`${message.role}:`, message.parts)
+ },
+ onStatusChange: (status) => {
+ console.log('Status:', status)
+ },
+ onModeChange: (mode) => {
+ console.log('Mode:', mode)
+ },
+})
+
+// Connect
+await client.connect()
+
+// Send text
+client.sendText('Hello!')
+
+// Subscribe to state changes
+const unsub = client.onStateChange((state) => {
+ console.log('Messages:', state.messages.length)
+})
+
+// Disconnect when done
+await client.disconnect()
+
+// Clean up
+client.destroy()
+```
+
+## Message Structure
+
+Realtime messages use a `parts`-based structure similar to `UIMessage`:
+
+```typescript
+interface RealtimeMessage {
+ id: string
+ role: 'user' | 'assistant'
+ timestamp: number
+ parts: Array
+ interrupted?: boolean
+}
+```
+
+Each part can be one of:
+
+| Part Type | Fields | Description |
+|-----------|--------|-------------|
+| `text` | `content` | Text content from `sendText()` |
+| `audio` | `transcript`, `durationMs` | Transcribed voice content |
+| `tool-call` | `id`, `name`, `arguments`, `input`, `output` | Tool invocation |
+| `tool-result` | `toolCallId`, `content` | Tool execution result |
+| `image` | `data`, `mimeType` | Image sent via `sendImage()` |
+
+## Error Handling
+
+Handle errors through the `onError` callback or the `error` state:
+
+```typescript
+const { error } = useRealtimeChat({
+ // ...
+ onError: (err) => {
+ if (err.message.includes('Permission denied')) {
+ alert('Microphone access is required for voice chat.')
+ } else {
+ console.error('Realtime error:', err)
+ }
+ },
+})
+```
+
+## Best Practices
+
+1. **Token security** - Always generate tokens server-side. Never expose API keys to the client.
+2. **Microphone permissions** - Handle the case where the user denies microphone access gracefully.
+3. **Cleanup** - Always disconnect when unmounting components. The `useRealtimeChat` hook handles this automatically.
+4. **Instructions** - Keep voice assistant instructions concise. Remind the model it's in a voice interface so responses stay conversational.
+5. **Tool design** - Keep tool descriptions clear and tool outputs small, since results are processed in real time.
+6. **Error recovery** - Implement retry logic for transient connection failures.
+
+## Next Steps
+
+- [Tools](./tools) - Learn about the isomorphic tool system
+- [Text-to-Speech](./text-to-speech) - Non-realtime speech generation
+- [Multimodal Content](./multimodal-content) - Working with images, audio, and video
diff --git a/docs/reference/classes/RealtimeClient.md b/docs/reference/classes/RealtimeClient.md
new file mode 100644
index 0000000000..6e78100def
--- /dev/null
+++ b/docs/reference/classes/RealtimeClient.md
@@ -0,0 +1,276 @@
+---
+id: RealtimeClient
+title: RealtimeClient
+---
+
+# Class: RealtimeClient
+
+Defined in: [realtime-client.ts](https://github.com/TanStack/ai/blob/main/packages/typescript/ai-client/src/realtime-client.ts)
+
+Client for managing realtime voice conversations.
+
+Handles connection lifecycle, audio I/O, message state, and tool execution for realtime voice-to-voice AI interactions. This is the framework-agnostic core that powers `useRealtimeChat` in React.
+
+## Example
+
+```typescript
+import { RealtimeClient } from '@tanstack/ai-client'
+import { openaiRealtime } from '@tanstack/ai-openai'
+
+const client = new RealtimeClient({
+ getToken: () => fetch('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/api/realtime-token').then(r => r.json()),
+ adapter: openaiRealtime(),
+ tools: [myTool.client(handler)],
+ onMessage: (msg) => console.log('Message:', msg),
+})
+
+await client.connect()
+```
+
+## Constructors
+
+### Constructor
+
+```ts
+new RealtimeClient(options): RealtimeClient;
+```
+
+#### Parameters
+
+##### options
+
+[`RealtimeClientOptions`](../interfaces/RealtimeClientOptions.md)
+
+Configuration options for the client.
+
+#### Returns
+
+`RealtimeClient`
+
+## Properties
+
+### status
+
+```ts
+readonly status: RealtimeStatus;
+```
+
+Current connection status (`'idle'`, `'connecting'`, `'connected'`, `'reconnecting'`, `'error'`).
+
+***
+
+### mode
+
+```ts
+readonly mode: RealtimeMode;
+```
+
+Current session mode (`'idle'`, `'listening'`, `'thinking'`, `'speaking'`).
+
+***
+
+### messages
+
+```ts
+readonly messages: Array;
+```
+
+Array of conversation messages. Updated as transcripts are finalized and messages complete.
+
+***
+
+### error
+
+```ts
+readonly error: Error | null;
+```
+
+Current error, if any.
+
+***
+
+### pendingUserTranscript
+
+```ts
+readonly pendingUserTranscript: string | null;
+```
+
+Partial transcript of what the user is currently saying (before finalization).
+
+***
+
+### pendingAssistantTranscript
+
+```ts
+readonly pendingAssistantTranscript: string | null;
+```
+
+Partial transcript of the assistant's current response (while speaking).
+
+***
+
+### audio
+
+```ts
+readonly audio: AudioVisualization | null;
+```
+
+Audio visualization data for the current connection. Returns `null` when not connected.
+
+## Methods
+
+### connect()
+
+```ts
+connect(): Promise;
+```
+
+Connect to the realtime session. Fetches a token via `getToken()` and establishes the connection through the adapter.
+
+#### Returns
+
+`Promise`
+
+#### Throws
+
+If token fetch or connection fails.
+
+***
+
+### disconnect()
+
+```ts
+disconnect(): Promise;
+```
+
+Disconnect from the realtime session. Cleans up audio resources, event subscriptions, and token refresh timers.
+
+#### Returns
+
+`Promise`
+
+***
+
+### startListening()
+
+```ts
+startListening(): void;
+```
+
+Start listening for voice input. Only needed when `vadMode` is `'manual'`.
+
+#### Returns
+
+`void`
+
+***
+
+### stopListening()
+
+```ts
+stopListening(): void;
+```
+
+Stop listening for voice input. Only needed when `vadMode` is `'manual'`.
+
+#### Returns
+
+`void`
+
+***
+
+### interrupt()
+
+```ts
+interrupt(): void;
+```
+
+Interrupt the current assistant response.
+
+#### Returns
+
+`void`
+
+***
+
+### sendText()
+
+```ts
+sendText(text): void;
+```
+
+Send a text message instead of voice.
+
+#### Parameters
+
+##### text
+
+`string`
+
+#### Returns
+
+`void`
+
+***
+
+### sendImage()
+
+```ts
+sendImage(imageData, mimeType): void;
+```
+
+Send an image to the conversation.
+
+#### Parameters
+
+##### imageData
+
+`string`
+
+Base64-encoded image data or a URL.
+
+##### mimeType
+
+`string`
+
+MIME type of the image (e.g., `'image/png'`, `'image/jpeg'`).
+
+#### Returns
+
+`void`
+
+***
+
+### onStateChange()
+
+```ts
+onStateChange(callback): () => void;
+```
+
+Subscribe to state changes. The callback is invoked whenever the internal state updates (status, mode, messages, transcripts, errors).
+
+#### Parameters
+
+##### callback
+
+[`RealtimeStateChangeCallback`](../type-aliases/RealtimeStateChangeCallback.md)
+
+#### Returns
+
+`() => void`
+
+Unsubscribe function.
+
+***
+
+### destroy()
+
+```ts
+destroy(): void;
+```
+
+Clean up all resources. Disconnects, clears subscriptions, and releases audio resources. Call this when disposing of the client.
+
+#### Returns
+
+`void`
diff --git a/docs/reference/functions/realtimeToken.md b/docs/reference/functions/realtimeToken.md
new file mode 100644
index 0000000000..22515aef9d
--- /dev/null
+++ b/docs/reference/functions/realtimeToken.md
@@ -0,0 +1,75 @@
+---
+id: realtimeToken
+title: realtimeToken
+---
+
+# Function: realtimeToken()
+
+```ts
+function realtimeToken(options): Promise;
+```
+
+Defined in: [realtime/index.ts:33](https://github.com/TanStack/ai/blob/main/packages/typescript/ai/src/realtime/index.ts#L33)
+
+Generate a realtime token using the provided adapter.
+
+This function is used on the **server** to generate ephemeral tokens that clients can use to establish realtime connections. The token contains authentication credentials and session configuration, and is typically short-lived (e.g., 10 minutes for OpenAI, 30 minutes for ElevenLabs).
+
+## Parameters
+
+### options
+
+[`RealtimeTokenOptions`](../interfaces/RealtimeTokenOptions.md)
+
+Token generation options including the provider-specific adapter.
+
+## Returns
+
+`Promise<`[`RealtimeToken`](../interfaces/RealtimeToken.md)`>`
+
+A token containing the provider credentials, expiration, and session config.
+
+## Examples
+
+### OpenAI
+
+```typescript
+import { realtimeToken } from '@tanstack/ai'
+import { openaiRealtimeToken } from '@tanstack/ai-openai'
+
+const token = await realtimeToken({
+ adapter: openaiRealtimeToken({
+ model: 'gpt-4o-realtime-preview',
+ }),
+})
+```
+
+### ElevenLabs
+
+```typescript
+import { realtimeToken } from '@tanstack/ai'
+import { elevenlabsRealtimeToken } from '@tanstack/ai-elevenlabs'
+
+const token = await realtimeToken({
+ adapter: elevenlabsRealtimeToken({
+ agentId: 'your-agent-id',
+ }),
+})
+```
+
+### TanStack Start Server Function
+
+```typescript
+import { createServerFn } from '@tanstack/react-start'
+import { realtimeToken } from '@tanstack/ai'
+import { openaiRealtimeToken } from '@tanstack/ai-openai'
+
+export const getRealtimeToken = createServerFn({ method: 'POST' })
+ .handler(async () => {
+ return realtimeToken({
+ adapter: openaiRealtimeToken({
+ model: 'gpt-4o-realtime-preview',
+ }),
+ })
+ })
+```
diff --git a/docs/reference/interfaces/AudioVisualization.md b/docs/reference/interfaces/AudioVisualization.md
new file mode 100644
index 0000000000..48f9a8a2f0
--- /dev/null
+++ b/docs/reference/interfaces/AudioVisualization.md
@@ -0,0 +1,126 @@
+---
+id: AudioVisualization
+title: AudioVisualization
+---
+
+# Interface: AudioVisualization
+
+Defined in: [realtime/types.ts](https://github.com/TanStack/ai/blob/main/packages/typescript/ai/src/realtime/types.ts)
+
+Interface for accessing audio visualization data from a realtime connection. Provides volume levels, frequency data, and time-domain data for both input (microphone) and output (speaker) audio.
+
+## Properties
+
+### inputLevel
+
+```ts
+readonly inputLevel: number;
+```
+
+Input volume level (0-1 normalized).
+
+***
+
+### outputLevel
+
+```ts
+readonly outputLevel: number;
+```
+
+Output volume level (0-1 normalized).
+
+***
+
+### inputSampleRate
+
+```ts
+readonly inputSampleRate: number;
+```
+
+Input audio sample rate in Hz.
+
+***
+
+### outputSampleRate
+
+```ts
+readonly outputSampleRate: number;
+```
+
+Output audio sample rate in Hz.
+
+## Methods
+
+### getInputFrequencyData()
+
+```ts
+getInputFrequencyData(): Uint8Array;
+```
+
+Get frequency data for input audio visualization.
+
+#### Returns
+
+`Uint8Array`
+
+***
+
+### getOutputFrequencyData()
+
+```ts
+getOutputFrequencyData(): Uint8Array;
+```
+
+Get frequency data for output audio visualization.
+
+#### Returns
+
+`Uint8Array`
+
+***
+
+### getInputTimeDomainData()
+
+```ts
+getInputTimeDomainData(): Uint8Array;
+```
+
+Get time domain data for input waveform visualization.
+
+#### Returns
+
+`Uint8Array`
+
+***
+
+### getOutputTimeDomainData()
+
+```ts
+getOutputTimeDomainData(): Uint8Array;
+```
+
+Get time domain data for output waveform visualization.
+
+#### Returns
+
+`Uint8Array`
+
+***
+
+### onInputAudio?
+
+```ts
+optional onInputAudio: (callback: (samples: Float32Array, sampleRate: number) => void) => () => void;
+```
+
+Subscribe to raw input audio samples. Returns an unsubscribe function.
+
+***
+
+### onOutputAudio?
+
+```ts
+optional onOutputAudio: (callback: (samples: Float32Array, sampleRate: number) => void) => () => void;
+```
+
+Subscribe to raw output audio samples. Returns an unsubscribe function.
diff --git a/docs/reference/interfaces/RealtimeAdapter.md b/docs/reference/interfaces/RealtimeAdapter.md
new file mode 100644
index 0000000000..caea97869a
--- /dev/null
+++ b/docs/reference/interfaces/RealtimeAdapter.md
@@ -0,0 +1,48 @@
+---
+id: RealtimeAdapter
+title: RealtimeAdapter
+---
+
+# Interface: RealtimeAdapter
+
+Defined in: [realtime-types.ts](https://github.com/TanStack/ai/blob/main/packages/typescript/ai-client/src/realtime-types.ts)
+
+Adapter interface for connecting to realtime providers. Each provider (OpenAI, ElevenLabs, etc.) implements this interface.
+
+## Properties
+
+### provider
+
+```ts
+provider: string;
+```
+
+Provider identifier (e.g., `'openai'`, `'elevenlabs'`).
+
+## Methods
+
+### connect()
+
+```ts
+connect(token, clientTools?): Promise;
+```
+
+Create a connection using the provided token.
+
+#### Parameters
+
+##### token
+
+[`RealtimeToken`](./RealtimeToken.md)
+
+The ephemeral token from the server.
+
+##### clientTools?
+
+`ReadonlyArray`
+
+Optional client-side tools to register with the provider.
+
+#### Returns
+
+`Promise<`[`RealtimeConnection`](./RealtimeConnection.md)`>`
diff --git a/docs/reference/interfaces/RealtimeClientOptions.md b/docs/reference/interfaces/RealtimeClientOptions.md
new file mode 100644
index 0000000000..7a3a62034a
--- /dev/null
+++ b/docs/reference/interfaces/RealtimeClientOptions.md
@@ -0,0 +1,204 @@
+---
+id: RealtimeClientOptions
+title: RealtimeClientOptions
+---
+
+# Interface: RealtimeClientOptions
+
+Defined in: [realtime-types.ts](https://github.com/TanStack/ai/blob/main/packages/typescript/ai-client/src/realtime-types.ts)
+
+Options for the `RealtimeClient` and `useRealtimeChat` hook.
+
+## Properties
+
+### getToken
+
+```ts
+getToken: () => Promise;
+```
+
+Function to fetch a realtime token from the server. Called on connect and when the token needs refresh.
+
+***
+
+### adapter
+
+```ts
+adapter: RealtimeAdapter;
+```
+
+The realtime adapter to use (e.g., `openaiRealtime()`, `elevenlabsRealtime()`).
+
+***
+
+### tools?
+
+```ts
+optional tools: ReadonlyArray;
+```
+
+Client-side tools with execution logic.
+
+***
+
+### autoPlayback?
+
+```ts
+optional autoPlayback: boolean;
+```
+
+Auto-play assistant audio responses. Default: `true`.
+
+***
+
+### autoCapture?
+
+```ts
+optional autoCapture: boolean;
+```
+
+Request microphone access on connect. Default: `true`.
+
+***
+
+### instructions?
+
+```ts
+optional instructions: string;
+```
+
+System instructions for the assistant.
+
+***
+
+### voice?
+
+```ts
+optional voice: string;
+```
+
+Voice to use for audio output (provider-specific, e.g., `'alloy'` for OpenAI).
+
+***
+
+### vadMode?
+
+```ts
+optional vadMode: 'server' | 'semantic' | 'manual';
+```
+
+Voice activity detection mode. Default: `'server'`.
+
+- `'server'` — Provider handles speech detection server-side
+- `'semantic'` — Semantic turn detection (OpenAI only)
+- `'manual'` — Application controls via `startListening()`/`stopListening()`
+
+***
+
+### outputModalities?
+
+```ts
+optional outputModalities: Array<'audio' | 'text'>;
+```
+
+Output modalities for responses.
+
+***
+
+### temperature?
+
+```ts
+optional temperature: number;
+```
+
+Temperature for generation (provider-specific range).
+
+***
+
+### maxOutputTokens?
+
+```ts
+optional maxOutputTokens: number | 'inf';
+```
+
+Maximum number of tokens in a response.
+
+***
+
+### semanticEagerness?
+
+```ts
+optional semanticEagerness: 'low' | 'medium' | 'high';
+```
+
+Eagerness level for semantic VAD.
+
+***
+
+### onStatusChange?
+
+```ts
+optional onStatusChange: (status: RealtimeStatus) => void;
+```
+
+Called when connection status changes.
+
+***
+
+### onModeChange?
+
+```ts
+optional onModeChange: (mode: RealtimeMode) => void;
+```
+
+Called when session mode changes.
+
+***
+
+### onMessage?
+
+```ts
+optional onMessage: (message: RealtimeMessage) => void;
+```
+
+Called when a new message is added to the conversation.
+
+***
+
+### onError?
+
+```ts
+optional onError: (error: Error) => void;
+```
+
+Called when an error occurs.
+
+***
+
+### onConnect?
+
+```ts
+optional onConnect: () => void;
+```
+
+Called when connection is established.
+
+***
+
+### onDisconnect?
+
+```ts
+optional onDisconnect: () => void;
+```
+
+Called when disconnected.
+
+***
+
+### onInterrupted?
+
+```ts
+optional onInterrupted: () => void;
+```
+
+Called when the assistant's response is interrupted.
diff --git a/docs/reference/interfaces/RealtimeConnection.md b/docs/reference/interfaces/RealtimeConnection.md
new file mode 100644
index 0000000000..00eff5fafb
--- /dev/null
+++ b/docs/reference/interfaces/RealtimeConnection.md
@@ -0,0 +1,210 @@
+---
+id: RealtimeConnection
+title: RealtimeConnection
+---
+
+# Interface: RealtimeConnection
+
+Defined in: [realtime-types.ts](https://github.com/TanStack/ai/blob/main/packages/typescript/ai-client/src/realtime-types.ts)
+
+Connection interface representing an active realtime session. Handles audio I/O, events, and session management. Returned by `RealtimeAdapter.connect()`.
+
+## Methods
+
+### disconnect()
+
+```ts
+disconnect(): Promise;
+```
+
+Disconnect from the realtime session.
+
+#### Returns
+
+`Promise`
+
+***
+
+### startAudioCapture()
+
+```ts
+startAudioCapture(): Promise;
+```
+
+Start capturing audio from the microphone.
+
+#### Returns
+
+`Promise`
+
+***
+
+### stopAudioCapture()
+
+```ts
+stopAudioCapture(): void;
+```
+
+Stop capturing audio.
+
+#### Returns
+
+`void`
+
+***
+
+### sendText()
+
+```ts
+sendText(text): void;
+```
+
+Send a text message (fallback for when voice isn't available).
+
+#### Parameters
+
+##### text
+
+`string`
+
+#### Returns
+
+`void`
+
+***
+
+### sendImage()
+
+```ts
+sendImage(imageData, mimeType): void;
+```
+
+Send an image to the conversation.
+
+#### Parameters
+
+##### imageData
+
+`string`
+
+Base64-encoded image data or a URL.
+
+##### mimeType
+
+`string`
+
+MIME type of the image.
+
+#### Returns
+
+`void`
+
+***
+
+### sendToolResult()
+
+```ts
+sendToolResult(callId, result): void;
+```
+
+Send a tool execution result back to the provider.
+
+#### Parameters
+
+##### callId
+
+`string`
+
+The tool call identifier.
+
+##### result
+
+`string`
+
+JSON-serialized result.
+
+#### Returns
+
+`void`
+
+***
+
+### updateSession()
+
+```ts
+updateSession(config): void;
+```
+
+Update session configuration.
+
+#### Parameters
+
+##### config
+
+`Partial`
+
+#### Returns
+
+`void`
+
+***
+
+### interrupt()
+
+```ts
+interrupt(): void;
+```
+
+Interrupt the current response.
+
+#### Returns
+
+`void`
+
+***
+
+### on()
+
+```ts
+on(event, handler): () => void;
+```
+
+Subscribe to connection events.
+
+#### Type Parameters
+
+##### TEvent
+
+`TEvent` *extends* `RealtimeEvent`
+
+#### Parameters
+
+##### event
+
+`TEvent`
+
+The event name (`'status_change'`, `'mode_change'`, `'transcript'`, `'audio_chunk'`, `'tool_call'`, `'message_complete'`, `'interrupted'`, `'error'`).
+
+##### handler
+
+`RealtimeEventHandler`
+
+#### Returns
+
+`() => void`
+
+Unsubscribe function.
+
+***
+
+### getAudioVisualization()
+
+```ts
+getAudioVisualization(): AudioVisualization;
+```
+
+Get audio visualization data for rendering level meters or waveforms.
+
+#### Returns
+
+[`AudioVisualization`](./AudioVisualization.md)
diff --git a/docs/reference/interfaces/RealtimeMessage.md b/docs/reference/interfaces/RealtimeMessage.md
new file mode 100644
index 0000000000..ea83dfef88
--- /dev/null
+++ b/docs/reference/interfaces/RealtimeMessage.md
@@ -0,0 +1,80 @@
+---
+id: RealtimeMessage
+title: RealtimeMessage
+---
+
+# Interface: RealtimeMessage
+
+Defined in: [realtime/types.ts](https://github.com/TanStack/ai/blob/main/packages/typescript/ai/src/realtime/types.ts)
+
+A message in a realtime conversation. Contains one or more content parts representing text, audio, tool calls, or images.
+
+## Properties
+
+### id
+
+```ts
+id: string;
+```
+
+Unique message identifier.
+
+***
+
+### role
+
+```ts
+role: 'user' | 'assistant';
+```
+
+Message role.
+
+***
+
+### timestamp
+
+```ts
+timestamp: number;
+```
+
+Timestamp when the message was created (milliseconds since epoch).
+
+***
+
+### parts
+
+```ts
+parts: Array;
+```
+
+Content parts of the message. Can include `RealtimeTextPart`, `RealtimeAudioPart`, `RealtimeToolCallPart`, `RealtimeToolResultPart`, or `RealtimeImagePart`.
+
+***
+
+### interrupted?
+
+```ts
+optional interrupted: boolean;
+```
+
+Whether this message was interrupted by the user.
+
+***
+
+### audioId?
+
+```ts
+optional audioId: string;
+```
+
+Reference to audio buffer if stored.
+
+***
+
+### durationMs?
+
+```ts
+optional durationMs: number;
+```
+
+Duration of the audio in milliseconds.
diff --git a/docs/reference/interfaces/RealtimeSessionConfig.md b/docs/reference/interfaces/RealtimeSessionConfig.md
new file mode 100644
index 0000000000..8986a73fc0
--- /dev/null
+++ b/docs/reference/interfaces/RealtimeSessionConfig.md
@@ -0,0 +1,120 @@
+---
+id: RealtimeSessionConfig
+title: RealtimeSessionConfig
+---
+
+# Interface: RealtimeSessionConfig
+
+Defined in: [realtime/types.ts](https://github.com/TanStack/ai/blob/main/packages/typescript/ai/src/realtime/types.ts)
+
+Configuration for a realtime session. Passed to the provider to configure model behavior, voice, tools, and VAD settings.
+
+## Properties
+
+### model?
+
+```ts
+optional model: string;
+```
+
+Model to use for the session.
+
+***
+
+### voice?
+
+```ts
+optional voice: string;
+```
+
+Voice to use for audio output.
+
+***
+
+### instructions?
+
+```ts
+optional instructions: string;
+```
+
+System instructions for the assistant.
+
+***
+
+### tools?
+
+```ts
+optional tools: Array;
+```
+
+Tools available in the session.
+
+***
+
+### vadMode?
+
+```ts
+optional vadMode: 'server' | 'semantic' | 'manual';
+```
+
+Voice activity detection mode.
+
+***
+
+### vadConfig?
+
+```ts
+optional vadConfig: VADConfig;
+```
+
+Detailed VAD configuration (threshold, padding, silence duration).
+
+***
+
+### outputModalities?
+
+```ts
+optional outputModalities: Array<'audio' | 'text'>;
+```
+
+Output modalities for responses (e.g., `['audio', 'text']`).
+
+***
+
+### temperature?
+
+```ts
+optional temperature: number;
+```
+
+Temperature for generation (provider-specific range, e.g., 0.6-1.2 for OpenAI).
+
+***
+
+### maxOutputTokens?
+
+```ts
+optional maxOutputTokens: number | 'inf';
+```
+
+Maximum number of tokens in a response.
+
+***
+
+### semanticEagerness?
+
+```ts
+optional semanticEagerness: 'low' | 'medium' | 'high';
+```
+
+Eagerness level for semantic VAD.
+
+***
+
+### providerOptions?
+
+```ts
+optional providerOptions: Record;
+```
+
+Provider-specific options.
diff --git a/docs/reference/interfaces/RealtimeToken.md b/docs/reference/interfaces/RealtimeToken.md
new file mode 100644
index 0000000000..43479fb1fb
--- /dev/null
+++ b/docs/reference/interfaces/RealtimeToken.md
@@ -0,0 +1,50 @@
+---
+id: RealtimeToken
+title: RealtimeToken
+---
+
+# Interface: RealtimeToken
+
+Defined in: [realtime/types.ts](https://github.com/TanStack/ai/blob/main/packages/typescript/ai/src/realtime/types.ts)
+
+Token returned by the server for client authentication. Contains the ephemeral credentials, expiration time, and session configuration for a realtime connection.
+
+## Properties
+
+### provider
+
+```ts
+provider: string;
+```
+
+Provider identifier (e.g., `'openai'`, `'elevenlabs'`).
+
+***
+
+### token
+
+```ts
+token: string;
+```
+
+The ephemeral token value. For OpenAI, this is a client secret. For ElevenLabs, this is a signed URL.
+
+***
+
+### expiresAt
+
+```ts
+expiresAt: number;
+```
+
+Token expiration timestamp in milliseconds since epoch.
+
+***
+
+### config
+
+```ts
+config: RealtimeSessionConfig;
+```
+
+Session configuration embedded in the token (model, voice, instructions, etc.).
diff --git a/docs/reference/interfaces/RealtimeTokenAdapter.md b/docs/reference/interfaces/RealtimeTokenAdapter.md
new file mode 100644
index 0000000000..2239781038
--- /dev/null
+++ b/docs/reference/interfaces/RealtimeTokenAdapter.md
@@ -0,0 +1,34 @@
+---
+id: RealtimeTokenAdapter
+title: RealtimeTokenAdapter
+---
+
+# Interface: RealtimeTokenAdapter
+
+Defined in: [realtime/types.ts](https://github.com/TanStack/ai/blob/main/packages/typescript/ai/src/realtime/types.ts)
+
+Adapter interface for generating provider-specific tokens. Implemented by `openaiRealtimeToken()` and `elevenlabsRealtimeToken()`.
+
+## Properties
+
+### provider
+
+```ts
+provider: string;
+```
+
+Provider identifier (e.g., `'openai'`, `'elevenlabs'`).
+
+## Methods
+
+### generateToken()
+
+```ts
+generateToken(): Promise;
+```
+
+Generate an ephemeral token for client use.
+
+#### Returns
+
+`Promise<`[`RealtimeToken`](./RealtimeToken.md)`>`
diff --git a/docs/reference/interfaces/RealtimeTokenOptions.md b/docs/reference/interfaces/RealtimeTokenOptions.md
new file mode 100644
index 0000000000..d34f43faf8
--- /dev/null
+++ b/docs/reference/interfaces/RealtimeTokenOptions.md
@@ -0,0 +1,23 @@
+---
+id: RealtimeTokenOptions
+title: RealtimeTokenOptions
+---
+
+# Interface: RealtimeTokenOptions
+
+Defined in: [realtime/types.ts](https://github.com/TanStack/ai/blob/main/packages/typescript/ai/src/realtime/types.ts)
+
+Options for the `realtimeToken()` function.
+
+## Properties
+
+### adapter
+
+```ts
+adapter: RealtimeTokenAdapter;
+```
+
+The token adapter to use. Each provider has its own token adapter:
+
+- `openaiRealtimeToken()` from `@tanstack/ai-openai`
+- `elevenlabsRealtimeToken()` from `@tanstack/ai-elevenlabs`
diff --git a/docs/reference/type-aliases/RealtimeEvent.md b/docs/reference/type-aliases/RealtimeEvent.md
new file mode 100644
index 0000000000..0d7011b81f
--- /dev/null
+++ b/docs/reference/type-aliases/RealtimeEvent.md
@@ -0,0 +1,33 @@
+---
+id: RealtimeEvent
+title: RealtimeEvent
+---
+
+# Type Alias: RealtimeEvent
+
+```ts
+type RealtimeEvent =
+ | 'status_change'
+ | 'mode_change'
+ | 'transcript'
+ | 'audio_chunk'
+ | 'tool_call'
+ | 'message_complete'
+ | 'interrupted'
+ | 'error';
+```
+
+Defined in: [realtime/types.ts](https://github.com/TanStack/ai/blob/main/packages/typescript/ai/src/realtime/types.ts)
+
+Events emitted by the realtime connection. Used with `RealtimeConnection.on()` to subscribe to specific events.
+
+| Event | Payload | Description |
+|-------|---------|-------------|
+| `'status_change'` | `{ status: RealtimeStatus }` | Connection status changed |
+| `'mode_change'` | `{ mode: RealtimeMode }` | Session mode changed |
+| `'transcript'` | `{ role, transcript, isFinal }` | Speech transcript (partial or final) |
+| `'audio_chunk'` | `{ data: ArrayBuffer, sampleRate }` | Raw audio data received |
+| `'tool_call'` | `{ toolCallId, toolName, input }` | Tool call requested by the model |
+| `'message_complete'` | `{ message: RealtimeMessage }` | Complete message received |
+| `'interrupted'` | `{ messageId?: string }` | Response was interrupted |
+| `'error'` | `{ error: Error }` | Error occurred |
diff --git a/docs/reference/type-aliases/RealtimeMessagePart.md b/docs/reference/type-aliases/RealtimeMessagePart.md
new file mode 100644
index 0000000000..75dae4b648
--- /dev/null
+++ b/docs/reference/type-aliases/RealtimeMessagePart.md
@@ -0,0 +1,27 @@
+---
+id: RealtimeMessagePart
+title: RealtimeMessagePart
+---
+
+# Type Alias: RealtimeMessagePart
+
+```ts
+type RealtimeMessagePart =
+ | RealtimeTextPart
+ | RealtimeAudioPart
+ | RealtimeToolCallPart
+ | RealtimeToolResultPart
+ | RealtimeImagePart;
+```
+
+Defined in: [realtime/types.ts](https://github.com/TanStack/ai/blob/main/packages/typescript/ai/src/realtime/types.ts)
+
+Union of all realtime message part types.
+
+| Part | `type` Field | Key Properties |
+|------|-------------|----------------|
+| `RealtimeTextPart` | `'text'` | `content: string` |
+| `RealtimeAudioPart` | `'audio'` | `transcript: string`, `durationMs?: number` |
+| `RealtimeToolCallPart` | `'tool-call'` | `id`, `name`, `arguments`, `input?`, `output?` |
+| `RealtimeToolResultPart` | `'tool-result'` | `toolCallId`, `content` |
+| `RealtimeImagePart` | `'image'` | `data: string`, `mimeType: string` |
diff --git a/docs/reference/type-aliases/RealtimeMode.md b/docs/reference/type-aliases/RealtimeMode.md
new file mode 100644
index 0000000000..bb0f8beb60
--- /dev/null
+++ b/docs/reference/type-aliases/RealtimeMode.md
@@ -0,0 +1,21 @@
+---
+id: RealtimeMode
+title: RealtimeMode
+---
+
+# Type Alias: RealtimeMode
+
+```ts
+type RealtimeMode = 'idle' | 'listening' | 'thinking' | 'speaking';
+```
+
+Defined in: [realtime/types.ts](https://github.com/TanStack/ai/blob/main/packages/typescript/ai/src/realtime/types.ts)
+
+Current mode of the realtime session.
+
+| Value | Description |
+|-------|-------------|
+| `'idle'` | Connected but not actively interacting |
+| `'listening'` | Capturing user audio input |
+| `'thinking'` | Processing user input |
+| `'speaking'` | AI is generating a response |
diff --git a/docs/reference/type-aliases/RealtimeStatus.md b/docs/reference/type-aliases/RealtimeStatus.md
new file mode 100644
index 0000000000..1872253d56
--- /dev/null
+++ b/docs/reference/type-aliases/RealtimeStatus.md
@@ -0,0 +1,22 @@
+---
+id: RealtimeStatus
+title: RealtimeStatus
+---
+
+# Type Alias: RealtimeStatus
+
+```ts
+type RealtimeStatus = 'idle' | 'connecting' | 'connected' | 'reconnecting' | 'error';
+```
+
+Defined in: [realtime/types.ts](https://github.com/TanStack/ai/blob/main/packages/typescript/ai/src/realtime/types.ts)
+
+Connection status of the realtime client.
+
+| Value | Description |
+|-------|-------------|
+| `'idle'` | Not connected |
+| `'connecting'` | Establishing connection |
+| `'connected'` | Active session |
+| `'reconnecting'` | Reconnecting after interruption |
+| `'error'` | Connection error occurred |
diff --git a/examples/ts-react-chat/src/lib/use-realtime.ts b/examples/ts-react-chat/src/lib/use-realtime.ts
index f54da4ef72..848c702ca0 100644
--- a/examples/ts-react-chat/src/lib/use-realtime.ts
+++ b/examples/ts-react-chat/src/lib/use-realtime.ts
@@ -42,9 +42,17 @@ const getRealtimeTokenFn = createServerFn({ method: 'POST' })
export function useRealtime({
provider,
agentId,
+ outputModalities,
+ temperature,
+ maxOutputTokens,
+ semanticEagerness,
}: {
provider: Provider
agentId: string
+ outputModalities?: Array<'audio' | 'text'>
+ temperature?: number
+ maxOutputTokens?: number | 'inf'
+ semanticEagerness?: 'low' | 'medium' | 'high'
}) {
const adapter =
provider === 'openai' ? openaiRealtime() : elevenlabsRealtime()
@@ -68,9 +76,14 @@ You can:
Keep your responses concise and conversational since this is a voice interface.
When using tools, briefly explain what you're doing and then share the results naturally.
+If the user sends an image, describe what you see and answer any questions about it.
Be friendly and engaging!`,
voice: 'alloy',
tools: realtimeClientTools,
+ outputModalities,
+ temperature,
+ maxOutputTokens,
+ semanticEagerness,
onError: (err) => {
console.error('Realtime error:', err)
},
diff --git a/examples/ts-react-chat/src/routes/realtime.tsx b/examples/ts-react-chat/src/routes/realtime.tsx
index df7c7d8871..d67aafb3f4 100644
--- a/examples/ts-react-chat/src/routes/realtime.tsx
+++ b/examples/ts-react-chat/src/routes/realtime.tsx
@@ -1,6 +1,7 @@
import { useEffect, useRef, useState } from 'react'
import { createFileRoute } from '@tanstack/react-router'
import {
+ Image,
Mic,
MicOff,
Phone,
@@ -13,17 +14,45 @@ import { AudioSparkline } from '@/components/AudioSparkline'
import { useRealtime } from '@/lib/use-realtime'
type Provider = 'openai' | 'elevenlabs'
+type OutputMode = 'audio+text' | 'text-only' | 'audio-only'
const PROVIDER_OPTIONS: Array<{ value: Provider; label: string }> = [
{ value: 'openai', label: 'OpenAI Realtime' },
{ value: 'elevenlabs', label: 'ElevenLabs' },
]
+const OUTPUT_MODE_OPTIONS: Array<{ value: OutputMode; label: string }> = [
+ { value: 'audio+text', label: 'Audio + Text' },
+ { value: 'text-only', label: 'Text Only' },
+ { value: 'audio-only', label: 'Audio Only' },
+]
+
+function outputModeToModalities(
+ mode: OutputMode,
+): Array<'audio' | 'text'> | undefined {
+ switch (mode) {
+ case 'text-only':
+ return ['text']
+ case 'audio-only':
+ return ['audio']
+ case 'audio+text':
+ return ['audio', 'text']
+ default:
+ return undefined
+ }
+}
+
function RealtimePage() {
const [provider, setProvider] = useState('openai')
const [agentId, setAgentId] = useState('')
const [textInput, setTextInput] = useState('')
+ const [outputMode, setOutputMode] = useState('audio+text')
+ const [temperature, setTemperature] = useState(0.8)
+ const [semanticEagerness, setSemanticEagerness] = useState<
+ 'low' | 'medium' | 'high'
+ >('medium')
const messagesEndRef = useRef(null)
+ const imageInputRef = useRef(null)
const {
status,
@@ -36,11 +65,38 @@ function RealtimePage() {
disconnect,
interrupt,
sendText,
+ sendImage,
inputLevel,
outputLevel,
getInputTimeDomainData,
getOutputTimeDomainData,
- } = useRealtime({ provider, agentId })
+ } = useRealtime({
+ provider,
+ agentId,
+ outputModalities: outputModeToModalities(outputMode),
+ temperature,
+ semanticEagerness,
+ })
+
+ // Handle image file selection
+ const handleImageUpload = (e: React.ChangeEvent) => {
+ const file = e.target.files?.[0]
+ if (!file) return
+
+ const reader = new FileReader()
+ reader.onload = () => {
+ const result = reader.result as string
+ // Extract base64 data (remove data:image/xxx;base64, prefix)
+ const base64 = result.split(',')[1]
+ if (base64) {
+ sendImage(base64, file.type)
+ }
+ }
+ reader.readAsDataURL(file)
+
+ // Reset input so the same file can be selected again
+ e.target.value = ''
+ }
// Auto-scroll to bottom when messages change
useEffect(() => {
@@ -138,6 +194,73 @@ function RealtimePage() {
/>
)}
+
+ {/* Output mode selector (OpenAI only) */}
+ {provider === 'openai' && (
+
+
+ Output
+
+
+ setOutputMode(e.target.value as OutputMode)
+ }
+ disabled={status !== 'idle'}
+ className="rounded-lg border border-orange-500/20 bg-gray-900 px-3 py-2 text-sm text-white focus:outline-none focus:ring-2 focus:ring-orange-500/50 disabled:opacity-50"
+ >
+ {OUTPUT_MODE_OPTIONS.map((opt) => (
+
+ {opt.label}
+
+ ))}
+
+
+ )}
+
+ {/* Temperature slider */}
+ {provider === 'openai' && (
+
+
+ Temp: {temperature.toFixed(1)}
+
+
+ setTemperature(parseFloat(e.target.value))
+ }
+ disabled={status !== 'idle'}
+ className="w-24 accent-orange-500 disabled:opacity-50"
+ />
+
+ )}
+
+ {/* Semantic eagerness */}
+ {provider === 'openai' && (
+
+
+ Eagerness
+
+
+ setSemanticEagerness(
+ e.target.value as 'low' | 'medium' | 'high',
+ )
+ }
+ disabled={status !== 'idle'}
+ className="rounded-lg border border-orange-500/20 bg-gray-900 px-3 py-2 text-sm text-white focus:outline-none focus:ring-2 focus:ring-orange-500/50 disabled:opacity-50"
+ >
+ Low
+ Medium
+ High
+
+
+ )}
{/* Status */}
@@ -175,13 +298,13 @@ function RealtimePage() {
{messages.length === 0 && status === 'idle' && (
-
Voice Chat with Tools
+
Voice Chat with Tools & Vision
Click "Start Conversation" to begin talking with the AI
- Try asking: "What time is it?" or "What's the weather in San
- Francisco?"
+ Try asking: "What time is it?" or "What's the weather?" — or
+ send an image!
)}
@@ -221,6 +344,19 @@ function RealtimePage() {
)
}
+ if (part.type === 'image') {
+ const src = part.data.startsWith('http')
+ ? part.data
+ : `data:${part.mimeType};base64,${part.data}`
+ return (
+
+ )
+ }
return null
})}
{message.interrupted && (
@@ -288,6 +424,26 @@ function RealtimePage() {
placeholder="Type a message..."
className="flex-1 rounded-lg border border-orange-500/20 bg-gray-800 px-4 py-2 text-sm text-white placeholder-gray-500 focus:outline-none focus:ring-2 focus:ring-orange-500/50"
/>
+ {/* Image upload button (OpenAI only) */}
+ {provider === 'openai' && (
+ <>
+
+ imageInputRef.current?.click()}
+ title="Send an image"
+ className="flex items-center justify-center w-10 h-10 rounded-lg bg-gray-700 hover:bg-gray-600 text-white transition-colors"
+ >
+
+
+ >
+ )}
0
+ ? Array.from(this.clientTools.values())
+ : undefined
+ this.connection = await this.options.adapter.connect(
+ this.token,
+ toolsList,
+ )
// Subscribe to connection events
this.subscribeToConnectionEvents()
@@ -212,6 +219,29 @@ export class RealtimeClient {
this.connection.sendText(text)
}
+ /**
+ * Send an image to the conversation.
+ * @param imageData - Base64-encoded image data or a URL
+ * @param mimeType - MIME type of the image (e.g., 'image/png', 'image/jpeg')
+ */
+ sendImage(imageData: string, mimeType: string): void {
+ if (!this.connection || this.state.status !== 'connected') {
+ return
+ }
+
+ // Add user message with image part
+ const userMessage: RealtimeMessage = {
+ id: this.generateId(),
+ role: 'user',
+ timestamp: Date.now(),
+ parts: [{ type: 'image', data: imageData, mimeType }],
+ }
+ this.addMessage(userMessage)
+
+ // Send to provider
+ this.connection.sendImage(imageData, mimeType)
+ }
+
// ============================================================================
// State Access
// ============================================================================
@@ -447,9 +477,25 @@ export class RealtimeClient {
private applySessionConfig(): void {
if (!this.connection) return
- const { instructions, voice, vadMode, tools } = this.options
+ const {
+ instructions,
+ voice,
+ vadMode,
+ tools,
+ outputModalities,
+ temperature,
+ maxOutputTokens,
+ semanticEagerness,
+ } = this.options
const hasConfig =
- instructions || voice || vadMode || (tools && tools.length > 0)
+ instructions ||
+ voice ||
+ vadMode ||
+ (tools && tools.length > 0) ||
+ outputModalities ||
+ temperature !== undefined ||
+ maxOutputTokens !== undefined ||
+ semanticEagerness
if (!hasConfig) return
const toolsConfig = tools
@@ -467,6 +513,10 @@ export class RealtimeClient {
voice,
vadMode,
tools: toolsConfig,
+ outputModalities,
+ temperature,
+ maxOutputTokens,
+ semanticEagerness,
})
}
diff --git a/packages/typescript/ai-client/src/realtime-types.ts b/packages/typescript/ai-client/src/realtime-types.ts
index 859d5dea60..bffd6df34c 100644
--- a/packages/typescript/ai-client/src/realtime-types.ts
+++ b/packages/typescript/ai-client/src/realtime-types.ts
@@ -25,9 +25,13 @@ export interface RealtimeAdapter {
/**
* Create a connection using the provided token
* @param token - The ephemeral token from the server
+ * @param clientTools - Optional client-side tools to register with the provider
* @returns A connection instance
*/
- connect: (token: RealtimeToken) => Promise
+ connect: (
+ token: RealtimeToken,
+ clientTools?: ReadonlyArray,
+ ) => Promise
}
/**
@@ -49,6 +53,10 @@ export interface RealtimeConnection {
/** Send a text message (fallback for when voice isn't available) */
sendText: (text: string) => void
+ // Image input
+ /** Send an image to the conversation */
+ sendImage: (imageData: string, mimeType: string) => void
+
// Tool results
/** Send a tool execution result back to the provider */
sendToolResult: (callId: string, result: string) => void
@@ -120,6 +128,26 @@ export interface RealtimeClientOptions {
*/
vadMode?: 'server' | 'semantic' | 'manual'
+ /**
+ * Output modalities for responses (e.g., ['audio', 'text'])
+ */
+ outputModalities?: Array<'audio' | 'text'>
+
+ /**
+ * Temperature for generation (provider-specific range)
+ */
+ temperature?: number
+
+ /**
+ * Maximum number of tokens in a response
+ */
+ maxOutputTokens?: number | 'inf'
+
+ /**
+ * Eagerness level for semantic VAD ('low', 'medium', 'high')
+ */
+ semanticEagerness?: 'low' | 'medium' | 'high'
+
// Callbacks
onStatusChange?: (status: RealtimeStatus) => void
onModeChange?: (mode: RealtimeMode) => void
diff --git a/packages/typescript/ai-elevenlabs/src/realtime/adapter.ts b/packages/typescript/ai-elevenlabs/src/realtime/adapter.ts
index 042e3ce733..3b946866e9 100644
--- a/packages/typescript/ai-elevenlabs/src/realtime/adapter.ts
+++ b/packages/typescript/ai-elevenlabs/src/realtime/adapter.ts
@@ -1,5 +1,6 @@
import { Conversation } from '@11labs/client'
import type {
+ AnyClientTool,
AudioVisualization,
RealtimeEvent,
RealtimeEventHandler,
@@ -37,8 +38,11 @@ export function elevenlabsRealtime(
return {
provider: 'elevenlabs',
- async connect(token: RealtimeToken): Promise {
- return createElevenLabsConnection(token, options)
+ async connect(
+ token: RealtimeToken,
+ clientToolDefs?: ReadonlyArray,
+ ): Promise {
+ return createElevenLabsConnection(token, options, clientToolDefs)
},
}
}
@@ -49,6 +53,7 @@ export function elevenlabsRealtime(
async function createElevenLabsConnection(
token: RealtimeToken,
_options: ElevenLabsRealtimeOptions,
+ clientToolDefs?: ReadonlyArray,
): Promise {
const eventHandlers = new Map>>()
let conversation: Awaited<
@@ -77,8 +82,32 @@ async function createElevenLabsConnection(
return `el-msg-${Date.now()}-${++messageIdCounter}`
}
- // Start the conversation session
- conversation = await Conversation.startSession({
+ // Convert TanStack tool definitions to ElevenLabs clientTools format
+ const elevenLabsClientTools: Record<
+ string,
+ { handler: (params: unknown) => Promise; description: string; parameters: Record }
+ > = {}
+
+ if (clientToolDefs) {
+ for (const tool of clientToolDefs) {
+ elevenLabsClientTools[tool.name] = {
+ handler: async (params: unknown) => {
+ if (tool.execute) {
+ const result = await tool.execute(params)
+ return typeof result === 'string' ? result : JSON.stringify(result)
+ }
+ return JSON.stringify({ error: `No execute function for tool ${tool.name}` })
+ },
+ description: tool.description,
+ parameters: tool.inputSchema
+ ? (tool.inputSchema as Record)
+ : { type: 'object', properties: {} },
+ }
+ }
+ }
+
+ // Build session options
+ const sessionOptions: Record = {
signedUrl: token.token,
onConnect: () => {
@@ -91,13 +120,13 @@ async function createElevenLabsConnection(
emit('mode_change', { mode: 'idle' })
},
- onModeChange: ({ mode }) => {
+ onModeChange: ({ mode }: { mode: string }) => {
const mappedMode: RealtimeMode =
mode === 'speaking' ? 'speaking' : 'listening'
emit('mode_change', { mode: mappedMode })
},
- onMessage: ({ message, source }) => {
+ onMessage: ({ message, source }: { message: string; source: string }) => {
const role = source === 'user' ? 'user' : 'assistant'
// Emit transcript update
@@ -124,7 +153,15 @@ async function createElevenLabsConnection(
),
})
},
- })
+ }
+
+ // Only add clientTools if we have any
+ if (Object.keys(elevenLabsClientTools).length > 0) {
+ sessionOptions.clientTools = elevenLabsClientTools
+ }
+
+ // Start the conversation session
+ conversation = await Conversation.startSession(sessionOptions as Parameters[0])
// Connection implementation
const connection: RealtimeConnection = {
@@ -152,13 +189,18 @@ async function createElevenLabsConnection(
conversation.sendUserMessage(text)
},
- sendToolResult(_callId: string, _result: string) {
- // ElevenLabs handles client tools differently - they're registered at session start
+ sendImage(_imageData: string, _mimeType: string) {
+ // ElevenLabs does not support direct image input in the conversation API
console.warn(
- 'ElevenLabs tool results are handled via clientTools option during session creation.',
+ 'ElevenLabs realtime does not support sending images directly.',
)
},
+ sendToolResult(_callId: string, _result: string) {
+ // ElevenLabs client tools are handled via the clientTools handlers
+ // registered at session start — results are returned automatically
+ },
+
updateSession(_config: Partial) {
// ElevenLabs session config is set at creation time
console.warn(
diff --git a/packages/typescript/ai-openai/src/realtime/adapter.ts b/packages/typescript/ai-openai/src/realtime/adapter.ts
index 2ca879e7ae..93a6dc8339 100644
--- a/packages/typescript/ai-openai/src/realtime/adapter.ts
+++ b/packages/typescript/ai-openai/src/realtime/adapter.ts
@@ -1,4 +1,5 @@
import type {
+ AnyClientTool,
AudioVisualization,
RealtimeEvent,
RealtimeEventHandler,
@@ -40,7 +41,10 @@ export function openaiRealtime(
return {
provider: 'openai',
- async connect(token: RealtimeToken): Promise {
+ async connect(
+ token: RealtimeToken,
+ _clientTools?: ReadonlyArray,
+ ): Promise {
if (connectionMode === 'webrtc') {
return createWebRTCConnection(token)
}
@@ -475,7 +479,27 @@ async function createWebRTCConnection(
})
sendEvent({
type: 'response.create',
- response: { output_modalities: ['text'] },
+ })
+ },
+
+ sendImage(imageData: string, mimeType: string) {
+ // Determine if imageData is a URL or base64 data
+ const isUrl =
+ imageData.startsWith('http://') || imageData.startsWith('https://')
+ const imageContent = isUrl
+ ? { type: 'input_image', image_url: imageData }
+ : { type: 'input_image', image_url: `data:${mimeType};base64,${imageData}` }
+
+ sendEvent({
+ type: 'conversation.item.create',
+ item: {
+ type: 'message',
+ role: 'user',
+ content: [imageContent],
+ },
+ })
+ sendEvent({
+ type: 'response.create',
})
},
@@ -506,7 +530,7 @@ async function createWebRTCConnection(
if (config.vadMode === 'semantic') {
sessionUpdate.turn_detection = {
type: 'semantic_vad',
- eagerness: 'medium',
+ eagerness: config.semanticEagerness ?? 'medium',
}
} else if (config.vadMode === 'server') {
sessionUpdate.turn_detection = {
@@ -530,6 +554,18 @@ async function createWebRTCConnection(
sessionUpdate.tool_choice = 'auto'
}
+ if (config.outputModalities) {
+ sessionUpdate.modalities = config.outputModalities
+ }
+
+ if (config.temperature !== undefined) {
+ sessionUpdate.temperature = config.temperature
+ }
+
+ if (config.maxOutputTokens !== undefined) {
+ sessionUpdate.max_response_output_tokens = config.maxOutputTokens
+ }
+
// Always enable input audio transcription so user speech is transcribed
sessionUpdate.input_audio_transcription = { model: 'whisper-1' }
diff --git a/packages/typescript/ai-openai/src/realtime/types.ts b/packages/typescript/ai-openai/src/realtime/types.ts
index 815099866d..f4d36d9cc6 100644
--- a/packages/typescript/ai-openai/src/realtime/types.ts
+++ b/packages/typescript/ai-openai/src/realtime/types.ts
@@ -12,6 +12,8 @@ export type OpenAIRealtimeVoice =
| 'sage'
| 'shimmer'
| 'verse'
+ | 'marin'
+ | 'cedar'
/**
* OpenAI realtime model options
@@ -21,6 +23,8 @@ export type OpenAIRealtimeModel =
| 'gpt-4o-realtime-preview-2024-10-01'
| 'gpt-4o-mini-realtime-preview'
| 'gpt-4o-mini-realtime-preview-2024-12-17'
+ | 'gpt-realtime'
+ | 'gpt-realtime-mini'
/**
* OpenAI semantic VAD configuration
diff --git a/packages/typescript/ai-react/src/realtime-types.ts b/packages/typescript/ai-react/src/realtime-types.ts
index 7687bbc42a..bad512d29f 100644
--- a/packages/typescript/ai-react/src/realtime-types.ts
+++ b/packages/typescript/ai-react/src/realtime-types.ts
@@ -52,6 +52,26 @@ export interface UseRealtimeChatOptions {
*/
vadMode?: 'server' | 'semantic' | 'manual'
+ /**
+ * Output modalities for responses (e.g., ['audio', 'text'])
+ */
+ outputModalities?: Array<'audio' | 'text'>
+
+ /**
+ * Temperature for generation (provider-specific range)
+ */
+ temperature?: number
+
+ /**
+ * Maximum number of tokens in a response
+ */
+ maxOutputTokens?: number | 'inf'
+
+ /**
+ * Eagerness level for semantic VAD ('low', 'medium', 'high')
+ */
+ semanticEagerness?: 'low' | 'medium' | 'high'
+
// Callbacks
onConnect?: () => void
onDisconnect?: () => void
@@ -97,6 +117,10 @@ export interface UseRealtimeChatReturn {
/** Send a text message instead of voice */
sendText: (text: string) => void
+ // Image input
+ /** Send an image to the conversation */
+ sendImage: (imageData: string, mimeType: string) => void
+
// Audio visualization (0-1 normalized)
/** Current input (microphone) volume level */
inputLevel: number
diff --git a/packages/typescript/ai-react/src/use-realtime-chat.ts b/packages/typescript/ai-react/src/use-realtime-chat.ts
index c40d26e784..63272821f7 100644
--- a/packages/typescript/ai-react/src/use-realtime-chat.ts
+++ b/packages/typescript/ai-react/src/use-realtime-chat.ts
@@ -92,6 +92,10 @@ export function useRealtimeChat(
autoPlayback: optionsRef.current.autoPlayback,
autoCapture: optionsRef.current.autoCapture,
vadMode: optionsRef.current.vadMode,
+ outputModalities: optionsRef.current.outputModalities,
+ temperature: optionsRef.current.temperature,
+ maxOutputTokens: optionsRef.current.maxOutputTokens,
+ semanticEagerness: optionsRef.current.semanticEagerness,
onStatusChange: (newStatus) => {
setStatus(newStatus)
},
@@ -192,6 +196,14 @@ export function useRealtimeChat(
[client],
)
+ // Image input
+ const sendImage = useCallback(
+ (imageData: string, mimeType: string) => {
+ client.sendImage(imageData, mimeType)
+ },
+ [client],
+ )
+
// Audio visualization
const getInputFrequencyData = useCallback(() => {
return (
@@ -247,6 +259,9 @@ export function useRealtimeChat(
// Text input
sendText,
+ // Image input
+ sendImage,
+
// Audio visualization
inputLevel,
outputLevel,
diff --git a/packages/typescript/ai/src/index.ts b/packages/typescript/ai/src/index.ts
index 1698a0556b..8bf6d0a830 100644
--- a/packages/typescript/ai/src/index.ts
+++ b/packages/typescript/ai/src/index.ts
@@ -93,6 +93,7 @@ export type {
RealtimeAudioPart,
RealtimeToolCallPart,
RealtimeToolResultPart,
+ RealtimeImagePart,
RealtimeStatus,
RealtimeMode,
AudioVisualization,
diff --git a/packages/typescript/ai/src/realtime/types.ts b/packages/typescript/ai/src/realtime/types.ts
index 94ae56b32c..daaf6f57c5 100644
--- a/packages/typescript/ai/src/realtime/types.ts
+++ b/packages/typescript/ai/src/realtime/types.ts
@@ -40,6 +40,14 @@ export interface RealtimeSessionConfig {
vadMode?: 'server' | 'semantic' | 'manual'
/** VAD configuration */
vadConfig?: VADConfig
+ /** Output modalities for responses (e.g., ['audio', 'text'], ['text']) */
+ outputModalities?: Array<'audio' | 'text'>
+ /** Temperature for generation (provider-specific range, e.g., 0.6-1.2 for OpenAI) */
+ temperature?: number
+ /** Maximum number of tokens in a response */
+ maxOutputTokens?: number | 'inf'
+ /** Eagerness level for semantic VAD ('low', 'medium', 'high') */
+ semanticEagerness?: 'low' | 'medium' | 'high'
/** Provider-specific options */
providerOptions?: Record
}
@@ -122,6 +130,17 @@ export interface RealtimeToolResultPart {
content: string
}
+/**
+ * Image content part in a realtime message
+ */
+export interface RealtimeImagePart {
+ type: 'image'
+ /** Base64-encoded image data or a URL */
+ data: string
+ /** MIME type of the image (e.g., 'image/png', 'image/jpeg') */
+ mimeType: string
+}
+
/**
* Union of all realtime message parts
*/
@@ -130,6 +149,7 @@ export type RealtimeMessagePart =
| RealtimeAudioPart
| RealtimeToolCallPart
| RealtimeToolResultPart
+ | RealtimeImagePart
/**
* A message in a realtime conversation
From d0233b52ff7fea81d31a402cb94953aa86d794f9 Mon Sep 17 00:00:00 2001
From: Jack Herrington
Date: Sat, 7 Mar 2026 07:14:08 -0800
Subject: [PATCH 14/31] updating changeset
---
.changeset/realtime-chat.md | 11 ++++++--
docs/config.json | 56 +++++++++++++++++++++++++++++++++++++
2 files changed, 65 insertions(+), 2 deletions(-)
diff --git a/.changeset/realtime-chat.md b/.changeset/realtime-chat.md
index 11cc3cca14..43d570b19a 100644
--- a/.changeset/realtime-chat.md
+++ b/.changeset/realtime-chat.md
@@ -6,6 +6,13 @@
'@tanstack/ai-react': minor
---
-feat: add realtime chat support with OpenAI and ElevenLabs adapters
+feat: add realtime voice chat with OpenAI and ElevenLabs adapters
-Adds realtime voice/text chat capabilities including a provider-agnostic realtime client, OpenAI Realtime API adapter, ElevenLabs conversational AI adapter, React `useRealtimeChat` hook, and shared realtime types across the core, client, and framework packages.
+Adds realtime voice/text chat capabilities:
+
+- **@tanstack/ai**: `realtimeToken()` function and shared realtime types (`RealtimeToken`, `RealtimeMessage`, `RealtimeSessionConfig`, `RealtimeStatus`, `RealtimeMode`, `AudioVisualization`, events, and error types)
+- **@tanstack/ai-client**: Framework-agnostic `RealtimeClient` class with connection lifecycle, audio I/O, message state management, tool execution, and `RealtimeAdapter`/`RealtimeConnection` interfaces
+- **@tanstack/ai-openai**: `openaiRealtime()` client adapter (WebRTC) and `openaiRealtimeToken()` server token adapter with support for semantic VAD, multiple voices, and all realtime models
+- **@tanstack/ai-elevenlabs**: `elevenlabsRealtime()` client adapter (WebSocket) and `elevenlabsRealtimeToken()` server token adapter for ElevenLabs conversational AI agents
+- **@tanstack/ai-react**: `useRealtimeChat()` hook with reactive state for status, mode, messages, pending transcripts, audio visualization levels, VAD control, text/image input, and interruptions
+- **Docs**: Realtime Voice Chat guide and full API reference for all realtime classes, interfaces, functions, and type aliases
diff --git a/docs/config.json b/docs/config.json
index 05d2f8932d..cb21c6792e 100644
--- a/docs/config.json
+++ b/docs/config.json
@@ -319,6 +319,10 @@
"label": "uiMessageToModelMessages",
"to": "reference/functions/uiMessageToModelMessages"
},
+ {
+ "label": "realtimeToken",
+ "to": "reference/functions/realtimeToken"
+ },
{
"label": "untilFinishReason",
"to": "reference/functions/untilFinishReason"
@@ -350,6 +354,10 @@
"label": "AudioPart",
"to": "reference/interfaces/AudioPart"
},
+ {
+ "label": "AudioVisualization",
+ "to": "reference/interfaces/AudioVisualization"
+ },
{
"label": "BaseStreamChunk",
"to": "reference/interfaces/BaseStreamChunk"
@@ -430,6 +438,38 @@
"label": "ProcessorState",
"to": "reference/interfaces/ProcessorState"
},
+ {
+ "label": "RealtimeAdapter",
+ "to": "reference/interfaces/RealtimeAdapter"
+ },
+ {
+ "label": "RealtimeClientOptions",
+ "to": "reference/interfaces/RealtimeClientOptions"
+ },
+ {
+ "label": "RealtimeConnection",
+ "to": "reference/interfaces/RealtimeConnection"
+ },
+ {
+ "label": "RealtimeMessage",
+ "to": "reference/interfaces/RealtimeMessage"
+ },
+ {
+ "label": "RealtimeSessionConfig",
+ "to": "reference/interfaces/RealtimeSessionConfig"
+ },
+ {
+ "label": "RealtimeToken",
+ "to": "reference/interfaces/RealtimeToken"
+ },
+ {
+ "label": "RealtimeTokenAdapter",
+ "to": "reference/interfaces/RealtimeTokenAdapter"
+ },
+ {
+ "label": "RealtimeTokenOptions",
+ "to": "reference/interfaces/RealtimeTokenOptions"
+ },
{
"label": "ResponseFormat",
"to": "reference/interfaces/ResponseFormat"
@@ -585,6 +625,22 @@
"label": "MessagePart",
"to": "reference/type-aliases/MessagePart"
},
+ {
+ "label": "RealtimeEvent",
+ "to": "reference/type-aliases/RealtimeEvent"
+ },
+ {
+ "label": "RealtimeMessagePart",
+ "to": "reference/type-aliases/RealtimeMessagePart"
+ },
+ {
+ "label": "RealtimeMode",
+ "to": "reference/type-aliases/RealtimeMode"
+ },
+ {
+ "label": "RealtimeStatus",
+ "to": "reference/type-aliases/RealtimeStatus"
+ },
{
"label": "ModalitiesArrayToUnion",
"to": "reference/type-aliases/ModalitiesArrayToUnion"
From 1b4e0f13533917308454f529b66f717d2070fef2 Mon Sep 17 00:00:00 2001
From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com>
Date: Sat, 7 Mar 2026 15:15:18 +0000
Subject: [PATCH 15/31] ci: apply automated fixes
---
examples/ts-react-chat/src/routes/realtime.tsx | 4 +---
.../ai-elevenlabs/src/realtime/adapter.ts | 14 +++++++++++---
.../typescript/ai-openai/src/realtime/adapter.ts | 5 ++++-
3 files changed, 16 insertions(+), 7 deletions(-)
diff --git a/examples/ts-react-chat/src/routes/realtime.tsx b/examples/ts-react-chat/src/routes/realtime.tsx
index d67aafb3f4..3225249e2c 100644
--- a/examples/ts-react-chat/src/routes/realtime.tsx
+++ b/examples/ts-react-chat/src/routes/realtime.tsx
@@ -230,9 +230,7 @@ function RealtimePage() {
max="1.2"
step="0.1"
value={temperature}
- onChange={(e) =>
- setTemperature(parseFloat(e.target.value))
- }
+ onChange={(e) => setTemperature(parseFloat(e.target.value))}
disabled={status !== 'idle'}
className="w-24 accent-orange-500 disabled:opacity-50"
/>
diff --git a/packages/typescript/ai-elevenlabs/src/realtime/adapter.ts b/packages/typescript/ai-elevenlabs/src/realtime/adapter.ts
index 3b946866e9..33bc5344e9 100644
--- a/packages/typescript/ai-elevenlabs/src/realtime/adapter.ts
+++ b/packages/typescript/ai-elevenlabs/src/realtime/adapter.ts
@@ -85,7 +85,11 @@ async function createElevenLabsConnection(
// Convert TanStack tool definitions to ElevenLabs clientTools format
const elevenLabsClientTools: Record<
string,
- { handler: (params: unknown) => Promise; description: string; parameters: Record }
+ {
+ handler: (params: unknown) => Promise
+ description: string
+ parameters: Record
+ }
> = {}
if (clientToolDefs) {
@@ -96,7 +100,9 @@ async function createElevenLabsConnection(
const result = await tool.execute(params)
return typeof result === 'string' ? result : JSON.stringify(result)
}
- return JSON.stringify({ error: `No execute function for tool ${tool.name}` })
+ return JSON.stringify({
+ error: `No execute function for tool ${tool.name}`,
+ })
},
description: tool.description,
parameters: tool.inputSchema
@@ -161,7 +167,9 @@ async function createElevenLabsConnection(
}
// Start the conversation session
- conversation = await Conversation.startSession(sessionOptions as Parameters[0])
+ conversation = await Conversation.startSession(
+ sessionOptions as Parameters[0],
+ )
// Connection implementation
const connection: RealtimeConnection = {
diff --git a/packages/typescript/ai-openai/src/realtime/adapter.ts b/packages/typescript/ai-openai/src/realtime/adapter.ts
index 93a6dc8339..35187a5d27 100644
--- a/packages/typescript/ai-openai/src/realtime/adapter.ts
+++ b/packages/typescript/ai-openai/src/realtime/adapter.ts
@@ -488,7 +488,10 @@ async function createWebRTCConnection(
imageData.startsWith('http://') || imageData.startsWith('https://')
const imageContent = isUrl
? { type: 'input_image', image_url: imageData }
- : { type: 'input_image', image_url: `data:${mimeType};base64,${imageData}` }
+ : {
+ type: 'input_image',
+ image_url: `data:${mimeType};base64,${imageData}`,
+ }
sendEvent({
type: 'conversation.item.create',
From f4e62acd07193eea8815b5be90bac3fbfd062819 Mon Sep 17 00:00:00 2001
From: Jack Herrington
Date: Tue, 20 Jan 2026 07:06:00 -0800
Subject: [PATCH 16/31] Realtime chat basically working
---
examples/ts-react-chat/.env.example | 10 +-
examples/ts-react-chat/package.json | 1 +
.../ts-react-chat/src/components/Header.tsx | 15 +-
examples/ts-react-chat/src/routeTree.gen.ts | 48 +-
.../src/routes/api.realtime-token.ts | 86 +
.../ts-react-chat/src/routes/realtime.tsx | 501 +++
packages/typescript/ai-client/src/index.ts | 8 +
.../ai-client/src/realtime-client.ts | 451 ++
.../ai-client/src/realtime-types.ts | 142 +
packages/typescript/ai-elevenlabs/README.md | 76 +
.../typescript/ai-elevenlabs/package.json | 55 +
.../typescript/ai-elevenlabs/src/index.ts | 16 +
.../ai-elevenlabs/src/realtime/adapter.ts | 251 ++
.../ai-elevenlabs/src/realtime/index.ts | 14 +
.../ai-elevenlabs/src/realtime/token.ts | 103 +
.../ai-elevenlabs/src/realtime/types.ts | 62 +
.../typescript/ai-elevenlabs/tsconfig.json | 8 +
.../typescript/ai-elevenlabs/vite.config.ts | 37 +
packages/typescript/ai-openai/package.json | 2 +
packages/typescript/ai-openai/src/index.ts | 19 +
.../ai-openai/src/realtime/adapter.ts | 585 +++
.../ai-openai/src/realtime/index.ts | 16 +
.../ai-openai/src/realtime/token.ts | 153 +
.../ai-openai/src/realtime/types.ts | 127 +
packages/typescript/ai-react/src/index.ts | 5 +
.../typescript/ai-react/src/realtime-types.ts | 109 +
.../ai-react/src/use-realtime-chat.ts | 241 ++
packages/typescript/ai/src/index.ts | 24 +
packages/typescript/ai/src/realtime/index.ts | 38 +
packages/typescript/ai/src/realtime/types.ts | 266 ++
pnpm-lock.yaml | 3722 ++++-------------
31 files changed, 4314 insertions(+), 2877 deletions(-)
create mode 100644 examples/ts-react-chat/src/routes/api.realtime-token.ts
create mode 100644 examples/ts-react-chat/src/routes/realtime.tsx
create mode 100644 packages/typescript/ai-client/src/realtime-client.ts
create mode 100644 packages/typescript/ai-client/src/realtime-types.ts
create mode 100644 packages/typescript/ai-elevenlabs/README.md
create mode 100644 packages/typescript/ai-elevenlabs/package.json
create mode 100644 packages/typescript/ai-elevenlabs/src/index.ts
create mode 100644 packages/typescript/ai-elevenlabs/src/realtime/adapter.ts
create mode 100644 packages/typescript/ai-elevenlabs/src/realtime/index.ts
create mode 100644 packages/typescript/ai-elevenlabs/src/realtime/token.ts
create mode 100644 packages/typescript/ai-elevenlabs/src/realtime/types.ts
create mode 100644 packages/typescript/ai-elevenlabs/tsconfig.json
create mode 100644 packages/typescript/ai-elevenlabs/vite.config.ts
create mode 100644 packages/typescript/ai-openai/src/realtime/adapter.ts
create mode 100644 packages/typescript/ai-openai/src/realtime/index.ts
create mode 100644 packages/typescript/ai-openai/src/realtime/token.ts
create mode 100644 packages/typescript/ai-openai/src/realtime/types.ts
create mode 100644 packages/typescript/ai-react/src/realtime-types.ts
create mode 100644 packages/typescript/ai-react/src/use-realtime-chat.ts
create mode 100644 packages/typescript/ai/src/realtime/index.ts
create mode 100644 packages/typescript/ai/src/realtime/types.ts
diff --git a/examples/ts-react-chat/.env.example b/examples/ts-react-chat/.env.example
index 613cb664b2..2bdb43f49d 100644
--- a/examples/ts-react-chat/.env.example
+++ b/examples/ts-react-chat/.env.example
@@ -1,3 +1,11 @@
# OpenAI API Key
# Get yours at: https://platform.openai.com/api-keys
-OPENAI_API_KEY=sk-...
\ No newline at end of file
+OPENAI_API_KEY=sk-...
+
+# ElevenLabs API Key (for realtime voice)
+# Get yours at: https://elevenlabs.io/app/settings/api-keys
+ELEVENLABS_API_KEY=xi-...
+
+# ElevenLabs Agent ID (for realtime voice)
+# Create an agent at: https://elevenlabs.io/app/conversational-ai
+ELEVENLABS_AGENT_ID=...
diff --git a/examples/ts-react-chat/package.json b/examples/ts-react-chat/package.json
index db2974a561..746713f7de 100644
--- a/examples/ts-react-chat/package.json
+++ b/examples/ts-react-chat/package.json
@@ -18,6 +18,7 @@
"@tanstack/ai-groq": "workspace:*",
"@tanstack/ai-ollama": "workspace:*",
"@tanstack/ai-openai": "workspace:*",
+ "@tanstack/ai-elevenlabs": "workspace:*",
"@tanstack/ai-openrouter": "workspace:*",
"@tanstack/ai-react": "workspace:*",
"@tanstack/ai-react-ui": "workspace:*",
diff --git a/examples/ts-react-chat/src/components/Header.tsx b/examples/ts-react-chat/src/components/Header.tsx
index 57745b7b0a..6af310b711 100644
--- a/examples/ts-react-chat/src/components/Header.tsx
+++ b/examples/ts-react-chat/src/components/Header.tsx
@@ -1,7 +1,7 @@
import { Link } from '@tanstack/react-router'
import { useState } from 'react'
-import { Guitar, Home, Menu, X } from 'lucide-react'
+import { Guitar, Home, Menu, Mic, X } from 'lucide-react'
export default function Header() {
const [isOpen, setIsOpen] = useState(false)
@@ -71,6 +71,19 @@ export default function Header() {
Guitar Demo
+
+ setIsOpen(false)}
+ className="flex items-center gap-3 p-3 rounded-lg hover:bg-gray-800 transition-colors mb-2"
+ activeProps={{
+ className:
+ 'flex items-center gap-3 p-3 rounded-lg bg-cyan-600 hover:bg-cyan-700 transition-colors mb-2',
+ }}
+ >
+
+ Voice Chat (Realtime)
+
>
diff --git a/examples/ts-react-chat/src/routeTree.gen.ts b/examples/ts-react-chat/src/routeTree.gen.ts
index f7099165f3..89221b1ded 100644
--- a/examples/ts-react-chat/src/routeTree.gen.ts
+++ b/examples/ts-react-chat/src/routeTree.gen.ts
@@ -9,11 +9,18 @@
// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified.
import { Route as rootRouteImport } from './routes/__root'
+import { Route as RealtimeRouteImport } from './routes/realtime'
import { Route as IndexRouteImport } from './routes/index'
import { Route as ApiTanchatRouteImport } from './routes/api.tanchat'
+import { Route as ApiRealtimeTokenRouteImport } from './routes/api.realtime-token'
import { Route as ExampleGuitarsIndexRouteImport } from './routes/example.guitars/index'
import { Route as ExampleGuitarsGuitarIdRouteImport } from './routes/example.guitars/$guitarId'
+const RealtimeRoute = RealtimeRouteImport.update({
+ id: '/realtime',
+ path: '/realtime',
+ getParentRoute: () => rootRouteImport,
+} as any)
const IndexRoute = IndexRouteImport.update({
id: '/',
path: '/',
@@ -24,6 +31,11 @@ const ApiTanchatRoute = ApiTanchatRouteImport.update({
path: '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/api/tanchat',
getParentRoute: () => rootRouteImport,
} as any)
+const ApiRealtimeTokenRoute = ApiRealtimeTokenRouteImport.update({
+ id: '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/api/realtime-token',
+ path: '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/api/realtime-token',
+ getParentRoute: () => rootRouteImport,
+} as any)
const ExampleGuitarsIndexRoute = ExampleGuitarsIndexRouteImport.update({
id: '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/example/guitars/',
path: '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/example/guitars/',
@@ -37,12 +49,16 @@ const ExampleGuitarsGuitarIdRoute = ExampleGuitarsGuitarIdRouteImport.update({
export interface FileRoutesByFullPath {
'/': typeof IndexRoute
+ '/realtime': typeof RealtimeRoute
+ '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/api/realtime-token': typeof ApiRealtimeTokenRoute
'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/api/tanchat': typeof ApiTanchatRoute
'/example/guitars/$guitarId': typeof ExampleGuitarsGuitarIdRoute
'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/example/guitars/': typeof ExampleGuitarsIndexRoute
}
export interface FileRoutesByTo {
'/': typeof IndexRoute
+ '/realtime': typeof RealtimeRoute
+ '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/api/realtime-token': typeof ApiRealtimeTokenRoute
'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/api/tanchat': typeof ApiTanchatRoute
'/example/guitars/$guitarId': typeof ExampleGuitarsGuitarIdRoute
'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/example/guitars': typeof ExampleGuitarsIndexRoute
@@ -50,6 +66,8 @@ export interface FileRoutesByTo {
export interface FileRoutesById {
__root__: typeof rootRouteImport
'/': typeof IndexRoute
+ '/realtime': typeof RealtimeRoute
+ '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/api/realtime-token': typeof ApiRealtimeTokenRoute
'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/api/tanchat': typeof ApiTanchatRoute
'/example/guitars/$guitarId': typeof ExampleGuitarsGuitarIdRoute
'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/example/guitars/': typeof ExampleGuitarsIndexRoute
@@ -58,14 +76,24 @@ export interface FileRouteTypes {
fileRoutesByFullPath: FileRoutesByFullPath
fullPaths:
| '/'
+ | '/realtime'
+ | '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/api/realtime-token'
| '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/api/tanchat'
| '/example/guitars/$guitarId'
| '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/example/guitars/'
fileRoutesByTo: FileRoutesByTo
- to: '/' | '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/api/tanchat' | '/example/guitars/$guitarId' | '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/example/guitars'
+ to:
+ | '/'
+ | '/realtime'
+ | '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/api/realtime-token'
+ | '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/api/tanchat'
+ | '/example/guitars/$guitarId'
+ | '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/example/guitars'
id:
| '__root__'
| '/'
+ | '/realtime'
+ | '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/api/realtime-token'
| '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/api/tanchat'
| '/example/guitars/$guitarId'
| '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/example/guitars/'
@@ -73,6 +101,8 @@ export interface FileRouteTypes {
}
export interface RootRouteChildren {
IndexRoute: typeof IndexRoute
+ RealtimeRoute: typeof RealtimeRoute
+ ApiRealtimeTokenRoute: typeof ApiRealtimeTokenRoute
ApiTanchatRoute: typeof ApiTanchatRoute
ExampleGuitarsGuitarIdRoute: typeof ExampleGuitarsGuitarIdRoute
ExampleGuitarsIndexRoute: typeof ExampleGuitarsIndexRoute
@@ -80,6 +110,13 @@ export interface RootRouteChildren {
declare module '@tanstack/react-router' {
interface FileRoutesByPath {
+ '/realtime': {
+ id: '/realtime'
+ path: '/realtime'
+ fullPath: '/realtime'
+ preLoaderRoute: typeof RealtimeRouteImport
+ parentRoute: typeof rootRouteImport
+ }
'/': {
id: '/'
path: '/'
@@ -94,6 +131,13 @@ declare module '@tanstack/react-router' {
preLoaderRoute: typeof ApiTanchatRouteImport
parentRoute: typeof rootRouteImport
}
+ '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/api/realtime-token': {
+ id: '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/api/realtime-token'
+ path: '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/api/realtime-token'
+ fullPath: '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/api/realtime-token'
+ preLoaderRoute: typeof ApiRealtimeTokenRouteImport
+ parentRoute: typeof rootRouteImport
+ }
'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/example/guitars/': {
id: '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/example/guitars/'
path: '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/example/guitars'
@@ -113,6 +157,8 @@ declare module '@tanstack/react-router' {
const rootRouteChildren: RootRouteChildren = {
IndexRoute: IndexRoute,
+ RealtimeRoute: RealtimeRoute,
+ ApiRealtimeTokenRoute: ApiRealtimeTokenRoute,
ApiTanchatRoute: ApiTanchatRoute,
ExampleGuitarsGuitarIdRoute: ExampleGuitarsGuitarIdRoute,
ExampleGuitarsIndexRoute: ExampleGuitarsIndexRoute,
diff --git a/examples/ts-react-chat/src/routes/api.realtime-token.ts b/examples/ts-react-chat/src/routes/api.realtime-token.ts
new file mode 100644
index 0000000000..0f7a46bdaa
--- /dev/null
+++ b/examples/ts-react-chat/src/routes/api.realtime-token.ts
@@ -0,0 +1,86 @@
+import { createFileRoute } from '@tanstack/react-router'
+import { realtimeToken } from '@tanstack/ai'
+import { openaiRealtimeToken } from '@tanstack/ai-openai'
+import { elevenlabsRealtimeToken } from '@tanstack/ai-elevenlabs'
+
+type Provider = 'openai' | 'elevenlabs'
+
+export const Route = createFileRoute('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/api/realtime-token')({
+ server: {
+ handlers: {
+ POST: async ({ request }) => {
+ try {
+ const body = await request.json()
+ const provider: Provider = body.provider || 'openai'
+
+ let token
+
+ if (provider === 'openai') {
+ token = await realtimeToken({
+ adapter: openaiRealtimeToken({
+ model: 'gpt-4o-realtime-preview',
+ voice: 'alloy',
+ instructions: `You are a helpful, friendly assistant.
+
+Keep your responses concise and conversational since this is a voice interface.
+Be natural and engaging in your responses.`,
+ turnDetection: {
+ type: 'server_vad',
+ threshold: 0.5,
+ prefix_padding_ms: 300,
+ silence_duration_ms: 500,
+ },
+ inputAudioTranscription: {
+ model: 'whisper-1',
+ },
+ }),
+ })
+ } else if (provider === 'elevenlabs') {
+ const agentId = body.agentId || process.env.ELEVENLABS_AGENT_ID
+
+ if (!agentId) {
+ return new Response(
+ JSON.stringify({
+ error: 'ElevenLabs agent ID is required. Set ELEVENLABS_AGENT_ID or pass agentId in request body.',
+ }),
+ {
+ status: 400,
+ headers: { 'Content-Type': 'application/json' },
+ },
+ )
+ }
+
+ token = await realtimeToken({
+ adapter: elevenlabsRealtimeToken({
+ agentId,
+ }),
+ })
+ } else {
+ return new Response(
+ JSON.stringify({ error: `Unknown provider: ${provider}` }),
+ {
+ status: 400,
+ headers: { 'Content-Type': 'application/json' },
+ },
+ )
+ }
+
+ return new Response(JSON.stringify(token), {
+ headers: { 'Content-Type': 'application/json' },
+ })
+ } catch (error: any) {
+ console.error('[Realtime Token API] Error:', error)
+ return new Response(
+ JSON.stringify({
+ error: error.message || 'Failed to generate realtime token',
+ }),
+ {
+ status: 500,
+ headers: { 'Content-Type': 'application/json' },
+ },
+ )
+ }
+ },
+ },
+ },
+})
diff --git a/examples/ts-react-chat/src/routes/realtime.tsx b/examples/ts-react-chat/src/routes/realtime.tsx
new file mode 100644
index 0000000000..fcc954cb16
--- /dev/null
+++ b/examples/ts-react-chat/src/routes/realtime.tsx
@@ -0,0 +1,501 @@
+import { useEffect, useRef, useState } from 'react'
+import { createFileRoute } from '@tanstack/react-router'
+import { useRealtimeChat } from '@tanstack/ai-react'
+import { openaiRealtime } from '@tanstack/ai-openai'
+import { elevenlabsRealtime } from '@tanstack/ai-elevenlabs'
+import { Mic, MicOff, Phone, PhoneOff, Volume2 } from 'lucide-react'
+
+type Provider = 'openai' | 'elevenlabs'
+
+const PROVIDER_OPTIONS: Array<{ value: Provider; label: string }> = [
+ { value: 'openai', label: 'OpenAI Realtime' },
+ { value: 'elevenlabs', label: 'ElevenLabs' },
+]
+
+// Sparkline component to visualize audio waveform
+function AudioSparkline({
+ getData,
+ color,
+ label,
+}: {
+ getData: () => Uint8Array
+ color: string
+ label: string
+}) {
+ const canvasRef = useRef(null)
+ const animationRef = useRef(null)
+
+ useEffect(() => {
+ const canvas = canvasRef.current
+ if (!canvas) return
+
+ const ctx = canvas.getContext('2d')
+ if (!ctx) return
+
+ function draw() {
+ const data = getData()
+ const width = canvas!.width
+ const height = canvas!.height
+
+ // Clear canvas
+ ctx!.fillStyle = '#1f2937' // gray-800
+ ctx!.fillRect(0, 0, width, height)
+
+ // Draw waveform
+ ctx!.strokeStyle = color
+ ctx!.lineWidth = 1
+ ctx!.beginPath()
+
+ // Sample the data to fit the canvas width
+ const step = Math.max(1, Math.floor(data.length / width))
+
+ for (let i = 0; i < width; i++) {
+ const dataIndex = Math.min(i * step, data.length - 1)
+ const value = data[dataIndex] ?? 128
+ // Convert 0-255 to canvas height (128 is center/silence)
+ const y = height - ((value / 255) * height)
+
+ if (i === 0) {
+ ctx!.moveTo(i, y)
+ } else {
+ ctx!.lineTo(i, y)
+ }
+ }
+
+ ctx!.stroke()
+
+ // Draw center line (silence level)
+ ctx!.strokeStyle = '#4b5563' // gray-600
+ ctx!.setLineDash([2, 2])
+ ctx!.beginPath()
+ ctx!.moveTo(0, height / 2)
+ ctx!.lineTo(width, height / 2)
+ ctx!.stroke()
+ ctx!.setLineDash([])
+
+ animationRef.current = requestAnimationFrame(draw)
+ }
+
+ draw()
+
+ return () => {
+ if (animationRef.current) {
+ cancelAnimationFrame(animationRef.current)
+ }
+ }
+ }, [getData, color])
+
+ return (
+
+ {label}
+
+
+ )
+}
+
+// Debug component to show raw audio data stats
+function AudioDebug({
+ getData,
+ label
+}: {
+ getData: () => Uint8Array
+ label: string
+}) {
+ const [stats, setStats] = useState({ length: 0, min: 0, max: 0, allSame: true, sample: '[]' })
+
+ useEffect(() => {
+ function update() {
+ const data = getData()
+ const min = Math.min(...data)
+ const max = Math.max(...data)
+ const allSame = data.every(v => v === data[0])
+ // Get a few samples from different parts of the array
+ const samples = data.length > 0 ? [
+ data[0],
+ data[Math.floor(data.length / 4)],
+ data[Math.floor(data.length / 2)],
+ data[Math.floor(data.length * 3 / 4)],
+ data[data.length - 1]
+ ] : []
+ setStats({
+ length: data.length,
+ min,
+ max,
+ allSame,
+ sample: `[${samples.join(', ')}]`
+ })
+ requestAnimationFrame(update)
+ }
+ const id = requestAnimationFrame(update)
+ return () => cancelAnimationFrame(id)
+ }, [getData])
+
+ return (
+
+ {label}: len={stats.length}, min={stats.min}, max={stats.max},
+ {stats.allSame ? ALL SAME! : varying }
+ {stats.sample}
+
+ )
+}
+
+function RealtimePage() {
+ const [provider, setProvider] = useState('openai')
+ const [agentId, setAgentId] = useState('')
+ const [showDebug, setShowDebug] = useState(true)
+ const messagesEndRef = useRef(null)
+
+ // Get the appropriate adapter based on provider
+ const adapter = provider === 'openai' ? openaiRealtime() : elevenlabsRealtime()
+
+ const {
+ status,
+ mode,
+ messages,
+ pendingUserTranscript,
+ pendingAssistantTranscript,
+ error,
+ connect,
+ disconnect,
+ interrupt,
+ inputLevel,
+ outputLevel,
+ sendText,
+ getInputTimeDomainData,
+ getOutputTimeDomainData,
+ } = useRealtimeChat({
+ getToken: async () => {
+ const body: Record = { provider }
+ if (provider === 'elevenlabs' && agentId) {
+ body.agentId = agentId
+ }
+ const response = await fetch('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/api/realtime-token', {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify(body),
+ })
+ if (!response.ok) {
+ const error = await response.json()
+ throw new Error(error.error || 'Failed to get token')
+ }
+ return response.json()
+ },
+ adapter,
+ onError: (err) => {
+ console.error('Realtime error:', err)
+ },
+ })
+
+ // Auto-scroll to bottom when messages change
+ useEffect(() => {
+ messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' })
+ }, [messages, pendingUserTranscript, pendingAssistantTranscript])
+
+ // Get status color
+ const getStatusColor = () => {
+ switch (status) {
+ case 'connected':
+ return 'bg-green-500'
+ case 'connecting':
+ case 'reconnecting':
+ return 'bg-yellow-500'
+ case 'error':
+ return 'bg-red-500'
+ default:
+ return 'bg-gray-500'
+ }
+ }
+
+ // Get mode icon
+ const getModeIndicator = () => {
+ switch (mode) {
+ case 'listening':
+ return (
+
+
+ Listening...
+
+ )
+ case 'thinking':
+ return (
+
+ )
+ case 'speaking':
+ return (
+
+
+ Speaking...
+
+ )
+ default:
+ return (
+
+
+ Idle
+
+ )
+ }
+ }
+
+ return (
+
+
+ {/* Header */}
+
+
+
+ {/* Provider selector */}
+
+
+ Provider
+
+ setProvider(e.target.value as Provider)}
+ disabled={status !== 'idle'}
+ className="rounded-lg border border-orange-500/20 bg-gray-900 px-3 py-2 text-sm text-white focus:outline-none focus:ring-2 focus:ring-orange-500/50 disabled:opacity-50"
+ >
+ {PROVIDER_OPTIONS.map((opt) => (
+
+ {opt.label}
+
+ ))}
+
+
+
+ {/* ElevenLabs Agent ID (conditional) */}
+ {provider === 'elevenlabs' && (
+
+
+ Agent ID
+
+ setAgentId(e.target.value)}
+ placeholder="Your ElevenLabs Agent ID"
+ disabled={status !== 'idle'}
+ className="rounded-lg border border-orange-500/20 bg-gray-900 px-3 py-2 text-sm text-white focus:outline-none focus:ring-2 focus:ring-orange-500/50 disabled:opacity-50 w-64"
+ />
+
+ )}
+
+
+ {/* Status */}
+
+
+ {getModeIndicator()}
+
+
+
+
+ {/* Messages area */}
+
+ {messages.length === 0 && status === 'idle' && (
+
+
+
Voice Chat
+
+ Click "Start Conversation" to begin talking with the AI
+
+
+ )}
+
+ {messages.map((message) => (
+
+
+ {message.role === 'assistant' ? (
+
+ AI
+
+ ) : (
+
+ U
+
+ )}
+
+ {message.parts.map((part, idx) => {
+ if (part.type === 'audio') {
+ return (
+
+ {part.transcript}
+
+ )
+ }
+ if (part.type === 'text') {
+ return (
+
+ {part.content}
+
+ )
+ }
+ return null
+ })}
+ {message.interrupted && (
+
+ (interrupted)
+
+ )}
+
+
+
+ ))}
+
+ {/* Pending transcripts */}
+ {pendingUserTranscript && (
+
+
+
+ U
+
+
{pendingUserTranscript}...
+
+
+ )}
+
+ {pendingAssistantTranscript && (
+
+
+
+ AI
+
+
+ {pendingAssistantTranscript}...
+
+
+
+ )}
+
+
+
+
+ {/* Error display */}
+ {error && (
+
+ Error: {error.message}
+
+ )}
+
+ {/* Audio visualization & controls */}
+
+ {/* Volume meters and waveforms */}
+ {status === 'connected' && (
+
+ {/* Input (Microphone) */}
+
+
+
+
+ {Math.round(inputLevel * 100)}%
+
+
+
+ {/* Output (Speaker) */}
+
+
+
+
+ {Math.round(outputLevel * 100)}%
+
+
+
+
+ {/* Debug info */}
+ {showDebug && (
+
+
+ Audio Debug
+ setShowDebug(false)}
+ className="text-xs text-gray-500 hover:text-gray-400"
+ >
+ Hide
+
+
+
+
+
+ inputLevel: {inputLevel.toFixed(4)}, outputLevel: {outputLevel.toFixed(4)}
+
+
+ )}
+
+ )}
+
+ {/* Controls */}
+
+ {status === 'idle' ? (
+
+
+ Start Conversation
+
+ ) : (
+ <>
+ {mode === 'speaking' && (
+
+ Interrupt
+
+ )}
+
+
+ End Conversation
+
+ >
+ )}
+
+
+
+
+ )
+}
+
+export const Route = createFileRoute('/realtime')({
+ component: RealtimePage,
+})
diff --git a/packages/typescript/ai-client/src/index.ts b/packages/typescript/ai-client/src/index.ts
index b279605d13..33471f2887 100644
--- a/packages/typescript/ai-client/src/index.ts
+++ b/packages/typescript/ai-client/src/index.ts
@@ -1,4 +1,5 @@
export { ChatClient } from './chat-client'
+export { RealtimeClient } from './realtime-client'
export type {
// Core message types (re-exported from @tanstack/ai via types.ts)
UIMessage,
@@ -22,6 +23,13 @@ export type {
ExtractToolOutput,
} from './tool-types'
export type { AnyClientTool } from '@tanstack/ai'
+export type {
+ RealtimeAdapter,
+ RealtimeConnection,
+ RealtimeClientOptions,
+ RealtimeClientState,
+ RealtimeStateChangeCallback,
+} from './realtime-types'
export {
fetchServerSentEvents,
fetchHttpStream,
diff --git a/packages/typescript/ai-client/src/realtime-client.ts b/packages/typescript/ai-client/src/realtime-client.ts
new file mode 100644
index 0000000000..0672fe23eb
--- /dev/null
+++ b/packages/typescript/ai-client/src/realtime-client.ts
@@ -0,0 +1,451 @@
+import type {
+ AudioVisualization,
+ RealtimeMessage,
+ RealtimeMode,
+ RealtimeStatus,
+ RealtimeToken,
+} from '@tanstack/ai'
+import type { AnyClientTool } from '@tanstack/ai'
+import type {
+ RealtimeClientOptions,
+ RealtimeClientState,
+ RealtimeConnection,
+ RealtimeStateChangeCallback,
+} from './realtime-types'
+
+// Token refresh buffer - refresh 1 minute before expiry
+const TOKEN_REFRESH_BUFFER_MS = 60_000
+
+/**
+ * Client for managing realtime voice conversations.
+ *
+ * Handles connection lifecycle, audio I/O, message state,
+ * and tool execution for realtime voice-to-voice AI interactions.
+ *
+ * @example
+ * ```typescript
+ * import { RealtimeClient } from '@tanstack/ai-client'
+ * import { openaiRealtime } from '@tanstack/ai-openai'
+ *
+ * const client = new RealtimeClient({
+ * getToken: () => fetch('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/api/realtime-token').then(r => r.json()),
+ * adapter: openaiRealtime(),
+ * tools: [myTool.client(handler)],
+ * onMessage: (msg) => console.log('Message:', msg),
+ * })
+ *
+ * await client.connect()
+ * ```
+ */
+let clientIdCounter = 0
+
+export class RealtimeClient {
+ private instanceId: number
+ private options: RealtimeClientOptions
+ private connection: RealtimeConnection | null = null
+ private token: RealtimeToken | null = null
+ private tokenRefreshTimeout: ReturnType | null = null
+ private clientTools: Map
+ private stateChangeCallbacks: Set = new Set()
+ private unsubscribers: Array<() => void> = []
+
+ private state: RealtimeClientState = {
+ status: 'idle',
+ mode: 'idle',
+ messages: [],
+ pendingUserTranscript: null,
+ pendingAssistantTranscript: null,
+ error: null,
+ }
+
+ constructor(options: RealtimeClientOptions) {
+ this.instanceId = ++clientIdCounter
+ console.log(`[RealtimeClient #${this.instanceId}] Created`)
+
+ this.options = {
+ autoPlayback: true,
+ autoCapture: true,
+ vadMode: 'server',
+ ...options,
+ }
+
+ // Build client tools map
+ this.clientTools = new Map()
+ if (options.tools) {
+ for (const tool of options.tools) {
+ this.clientTools.set(tool.name, tool)
+ }
+ }
+ }
+
+ // ============================================================================
+ // Connection Lifecycle
+ // ============================================================================
+
+ /**
+ * Connect to the realtime session.
+ * Fetches a token and establishes the connection.
+ */
+ async connect(): Promise {
+ if (this.state.status === 'connected') {
+ return
+ }
+
+ this.updateState({ status: 'connecting', error: null })
+
+ try {
+ // Fetch token from server
+ this.token = await this.options.getToken()
+
+ // Schedule token refresh
+ this.scheduleTokenRefresh()
+
+ // Connect via adapter
+ this.connection = await this.options.adapter.connect(this.token)
+ console.log(`[RealtimeClient #${this.instanceId}] Connection established:`, !!this.connection)
+
+ // Subscribe to connection events
+ this.subscribeToConnectionEvents()
+
+ // Start audio capture if configured
+ if (this.options.autoCapture) {
+ await this.connection.startAudioCapture()
+ }
+
+ this.updateState({ status: 'connected', mode: 'listening' })
+ this.options.onConnect?.()
+ } catch (error) {
+ const err = error instanceof Error ? error : new Error(String(error))
+ this.updateState({ status: 'error', error: err })
+ this.options.onError?.(err)
+ throw err
+ }
+ }
+
+ /**
+ * Disconnect from the realtime session.
+ */
+ async disconnect(): Promise {
+ if (this.tokenRefreshTimeout) {
+ clearTimeout(this.tokenRefreshTimeout)
+ this.tokenRefreshTimeout = null
+ }
+
+ // Unsubscribe from all events
+ for (const unsub of this.unsubscribers) {
+ unsub()
+ }
+ this.unsubscribers = []
+
+ if (this.connection) {
+ await this.connection.disconnect()
+ this.connection = null
+ }
+
+ this.token = null
+ this.updateState({
+ status: 'idle',
+ mode: 'idle',
+ pendingUserTranscript: null,
+ pendingAssistantTranscript: null,
+ })
+ this.options.onDisconnect?.()
+ }
+
+ // ============================================================================
+ // Voice Control
+ // ============================================================================
+
+ /**
+ * Start listening for voice input.
+ * Only needed when vadMode is 'manual'.
+ */
+ startListening(): void {
+ if (!this.connection || this.state.status !== 'connected') {
+ return
+ }
+ this.connection.startAudioCapture()
+ this.updateState({ mode: 'listening' })
+ }
+
+ /**
+ * Stop listening for voice input.
+ * Only needed when vadMode is 'manual'.
+ */
+ stopListening(): void {
+ if (!this.connection) {
+ return
+ }
+ this.connection.stopAudioCapture()
+ this.updateState({ mode: 'idle' })
+ }
+
+ /**
+ * Interrupt the current assistant response.
+ */
+ interrupt(): void {
+ if (!this.connection) {
+ return
+ }
+ this.connection.interrupt()
+ }
+
+ // ============================================================================
+ // Text Input
+ // ============================================================================
+
+ /**
+ * Send a text message instead of voice.
+ */
+ sendText(text: string): void {
+ if (!this.connection || this.state.status !== 'connected') {
+ return
+ }
+
+ // Add user message
+ const userMessage: RealtimeMessage = {
+ id: this.generateId(),
+ role: 'user',
+ timestamp: Date.now(),
+ parts: [{ type: 'text', content: text }],
+ }
+ this.addMessage(userMessage)
+
+ // Send to provider
+ this.connection.sendText(text)
+ }
+
+ // ============================================================================
+ // State Access
+ // ============================================================================
+
+ /** Get current connection status */
+ get status(): RealtimeStatus {
+ return this.state.status
+ }
+
+ /** Get current mode */
+ get mode(): RealtimeMode {
+ return this.state.mode
+ }
+
+ /** Get conversation messages */
+ get messages(): Array {
+ return this.state.messages
+ }
+
+ /** Get current error, if any */
+ get error(): Error | null {
+ return this.state.error
+ }
+
+ /** Get pending user transcript (while user is speaking) */
+ get pendingUserTranscript(): string | null {
+ return this.state.pendingUserTranscript
+ }
+
+ /** Get pending assistant transcript (while assistant is speaking) */
+ get pendingAssistantTranscript(): string | null {
+ return this.state.pendingAssistantTranscript
+ }
+
+ /** Get audio visualization data */
+ get audio(): AudioVisualization | null {
+ console.log(`[RealtimeClient #${this.instanceId}] audio getter, connection:`, !!this.connection)
+ return this.connection?.getAudioVisualization() ?? null
+ }
+
+ // ============================================================================
+ // State Subscription
+ // ============================================================================
+
+ /**
+ * Subscribe to state changes.
+ * @returns Unsubscribe function
+ */
+ onStateChange(callback: RealtimeStateChangeCallback): () => void {
+ this.stateChangeCallbacks.add(callback)
+ return () => {
+ this.stateChangeCallbacks.delete(callback)
+ }
+ }
+
+ // ============================================================================
+ // Cleanup
+ // ============================================================================
+
+ /**
+ * Clean up resources.
+ * Call this when disposing of the client.
+ */
+ destroy(): void {
+ this.disconnect()
+ this.stateChangeCallbacks.clear()
+ }
+
+ // ============================================================================
+ // Private Methods
+ // ============================================================================
+
+ private updateState(updates: Partial): void {
+ this.state = { ...this.state, ...updates }
+
+ // Notify callbacks
+ for (const callback of this.stateChangeCallbacks) {
+ callback(this.state)
+ }
+
+ // Notify specific callbacks
+ if ('status' in updates && updates.status !== undefined) {
+ this.options.onStatusChange?.(updates.status)
+ }
+ if ('mode' in updates && updates.mode !== undefined) {
+ this.options.onModeChange?.(updates.mode)
+ }
+ }
+
+ private addMessage(message: RealtimeMessage): void {
+ this.updateState({
+ messages: [...this.state.messages, message],
+ })
+ this.options.onMessage?.(message)
+ }
+
+ private scheduleTokenRefresh(): void {
+ if (!this.token) return
+
+ const timeUntilExpiry = this.token.expiresAt - Date.now()
+ const refreshIn = Math.max(0, timeUntilExpiry - TOKEN_REFRESH_BUFFER_MS)
+
+ this.tokenRefreshTimeout = setTimeout(() => {
+ this.refreshToken()
+ }, refreshIn)
+ }
+
+ private async refreshToken(): Promise {
+ try {
+ this.token = await this.options.getToken()
+ this.scheduleTokenRefresh()
+ // Note: Some providers may require reconnection with new token
+ // This is handled by the adapter implementation
+ } catch (error) {
+ const err = error instanceof Error ? error : new Error(String(error))
+ this.updateState({ error: err })
+ this.options.onError?.(err)
+ }
+ }
+
+ private subscribeToConnectionEvents(): void {
+ if (!this.connection) return
+
+ // Status changes
+ this.unsubscribers.push(
+ this.connection.on('status_change', ({ status }) => {
+ this.updateState({ status })
+ }),
+ )
+
+ // Mode changes
+ this.unsubscribers.push(
+ this.connection.on('mode_change', ({ mode }) => {
+ this.updateState({ mode })
+ }),
+ )
+
+ // Transcripts (streaming)
+ // User transcripts are added as messages when final (no separate message_complete for user input)
+ // Assistant transcripts are streamed, final message comes via message_complete
+ this.unsubscribers.push(
+ this.connection.on('transcript', ({ role, transcript, isFinal }) => {
+ if (role === 'user') {
+ this.updateState({
+ pendingUserTranscript: isFinal ? null : transcript,
+ })
+ // Add user message when transcript is finalized
+ if (isFinal && transcript) {
+ this.addMessage({
+ id: this.generateId(),
+ role: 'user',
+ timestamp: Date.now(),
+ parts: [{ type: 'audio', transcript, durationMs: 0 }],
+ })
+ }
+ } else {
+ // Assistant transcripts - just update pending, message_complete handles final
+ this.updateState({
+ pendingAssistantTranscript: isFinal ? null : transcript,
+ })
+ }
+ }),
+ )
+
+ // Tool calls
+ this.unsubscribers.push(
+ this.connection.on('tool_call', async ({ toolCallId, toolName, input }) => {
+ const tool = this.clientTools.get(toolName)
+ if (tool?.execute) {
+ try {
+ const output = await tool.execute(input)
+ this.connection?.sendToolResult(
+ toolCallId,
+ typeof output === 'string' ? output : JSON.stringify(output),
+ )
+ } catch (error) {
+ const errMsg =
+ error instanceof Error ? error.message : String(error)
+ this.connection?.sendToolResult(
+ toolCallId,
+ JSON.stringify({ error: errMsg }),
+ )
+ }
+ }
+ }),
+ )
+
+ // Message complete
+ this.unsubscribers.push(
+ this.connection.on('message_complete', ({ message }) => {
+ // Replace pending message with final version if needed
+ const existingIndex = this.state.messages.findIndex(
+ (m) => m.id === message.id,
+ )
+ if (existingIndex >= 0) {
+ const newMessages = [...this.state.messages]
+ newMessages[existingIndex] = message
+ this.updateState({ messages: newMessages })
+ } else {
+ this.addMessage(message)
+ }
+ }),
+ )
+
+ // Interruption
+ this.unsubscribers.push(
+ this.connection.on('interrupted', ({ messageId }) => {
+ if (messageId) {
+ const newMessages = this.state.messages.map((m) =>
+ m.id === messageId ? { ...m, interrupted: true } : m,
+ )
+ this.updateState({ messages: newMessages })
+ }
+ this.updateState({
+ mode: 'listening',
+ pendingAssistantTranscript: null,
+ })
+ this.options.onInterrupted?.()
+ }),
+ )
+
+ // Errors
+ this.unsubscribers.push(
+ this.connection.on('error', ({ error }) => {
+ this.updateState({ error })
+ this.options.onError?.(error)
+ }),
+ )
+ }
+
+ private generateId(): string {
+ return `msg-${Date.now()}-${Math.random().toString(36).substring(7)}`
+ }
+}
diff --git a/packages/typescript/ai-client/src/realtime-types.ts b/packages/typescript/ai-client/src/realtime-types.ts
new file mode 100644
index 0000000000..3393ee92c6
--- /dev/null
+++ b/packages/typescript/ai-client/src/realtime-types.ts
@@ -0,0 +1,142 @@
+import type {
+ AudioVisualization,
+ RealtimeEvent,
+ RealtimeEventHandler,
+ RealtimeMessage,
+ RealtimeMode,
+ RealtimeSessionConfig,
+ RealtimeStatus,
+ RealtimeToken,
+} from '@tanstack/ai'
+import type { AnyClientTool } from '@tanstack/ai'
+
+// ============================================================================
+// Adapter Interface
+// ============================================================================
+
+/**
+ * Adapter interface for connecting to realtime providers.
+ * Each provider (OpenAI, ElevenLabs, etc.) implements this interface.
+ */
+export interface RealtimeAdapter {
+ /** Provider identifier */
+ provider: string
+
+ /**
+ * Create a connection using the provided token
+ * @param token - The ephemeral token from the server
+ * @returns A connection instance
+ */
+ connect(token: RealtimeToken): Promise
+}
+
+/**
+ * Connection interface representing an active realtime session.
+ * Handles audio I/O, events, and session management.
+ */
+export interface RealtimeConnection {
+ // Lifecycle
+ /** Disconnect from the realtime session */
+ disconnect(): Promise
+
+ // Audio I/O
+ /** Start capturing audio from the microphone */
+ startAudioCapture(): Promise
+ /** Stop capturing audio */
+ stopAudioCapture(): void
+
+ // Text input
+ /** Send a text message (fallback for when voice isn't available) */
+ sendText(text: string): void
+
+ // Tool results
+ /** Send a tool execution result back to the provider */
+ sendToolResult(callId: string, result: string): void
+
+ // Session management
+ /** Update session configuration */
+ updateSession(config: Partial): void
+ /** Interrupt the current response */
+ interrupt(): void
+
+ // Events
+ /** Subscribe to connection events */
+ on(
+ event: E,
+ handler: RealtimeEventHandler,
+ ): () => void
+
+ // Audio visualization
+ /** Get audio visualization data */
+ getAudioVisualization(): AudioVisualization
+}
+
+// ============================================================================
+// Client Options
+// ============================================================================
+
+/**
+ * Options for the RealtimeClient
+ */
+export interface RealtimeClientOptions {
+ /**
+ * Function to fetch a realtime token from the server.
+ * Called on connect and when token needs refresh.
+ */
+ getToken: () => Promise
+
+ /**
+ * The realtime adapter to use (e.g., openaiRealtime())
+ */
+ adapter: RealtimeAdapter
+
+ /**
+ * Client-side tools with execution logic
+ */
+ tools?: ReadonlyArray
+
+ /**
+ * Auto-play assistant audio (default: true)
+ */
+ autoPlayback?: boolean
+
+ /**
+ * Request microphone access on connect (default: true)
+ */
+ autoCapture?: boolean
+
+ /**
+ * Voice activity detection mode (default: 'server')
+ */
+ vadMode?: 'server' | 'semantic' | 'manual'
+
+ // Callbacks
+ onStatusChange?: (status: RealtimeStatus) => void
+ onModeChange?: (mode: RealtimeMode) => void
+ onMessage?: (message: RealtimeMessage) => void
+ onError?: (error: Error) => void
+ onConnect?: () => void
+ onDisconnect?: () => void
+ onInterrupted?: () => void
+}
+
+// ============================================================================
+// Client State
+// ============================================================================
+
+/**
+ * Internal state of the RealtimeClient
+ */
+export interface RealtimeClientState {
+ status: RealtimeStatus
+ mode: RealtimeMode
+ messages: Array
+ pendingUserTranscript: string | null
+ pendingAssistantTranscript: string | null
+ error: Error | null
+}
+
+/**
+ * Callback type for state changes
+ */
+export type RealtimeStateChangeCallback = (state: RealtimeClientState) => void
diff --git a/packages/typescript/ai-elevenlabs/README.md b/packages/typescript/ai-elevenlabs/README.md
new file mode 100644
index 0000000000..6f85bb8ede
--- /dev/null
+++ b/packages/typescript/ai-elevenlabs/README.md
@@ -0,0 +1,76 @@
+# @tanstack/ai-elevenlabs
+
+ElevenLabs adapter for TanStack AI realtime voice conversations.
+
+## Installation
+
+```bash
+npm install @tanstack/ai-elevenlabs @tanstack/ai @tanstack/ai-client
+```
+
+## Usage
+
+### Server-Side Token Generation
+
+```typescript
+import { realtimeToken } from '@tanstack/ai'
+import { elevenlabsRealtimeToken } from '@tanstack/ai-elevenlabs'
+
+// Generate a signed URL for client use
+const token = await realtimeToken({
+ adapter: elevenlabsRealtimeToken({
+ agentId: 'your-agent-id',
+ }),
+})
+```
+
+### Client-Side Usage
+
+```typescript
+import { RealtimeClient } from '@tanstack/ai-client'
+import { elevenlabsRealtime } from '@tanstack/ai-elevenlabs'
+
+const client = new RealtimeClient({
+ getToken: () => fetch('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/api/realtime-token').then(r => r.json()),
+ adapter: elevenlabsRealtime(),
+})
+
+await client.connect()
+```
+
+### With React
+
+```typescript
+import { useRealtimeChat } from '@tanstack/ai-react'
+import { elevenlabsRealtime } from '@tanstack/ai-elevenlabs'
+
+function VoiceChat() {
+ const { status, mode, messages, connect, disconnect } = useRealtimeChat({
+ getToken: () => fetch('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/api/realtime-token').then(r => r.json()),
+ adapter: elevenlabsRealtime(),
+ })
+
+ return (
+
+
Status: {status}
+
Mode: {mode}
+
+ {status === 'idle' ? 'Start' : 'Stop'}
+
+
+ )
+}
+```
+
+## Environment Variables
+
+Set `ELEVENLABS_API_KEY` in your environment for server-side token generation.
+
+## Requirements
+
+- ElevenLabs account with Conversational AI agent configured
+- Agent ID from ElevenLabs dashboard
+
+## License
+
+MIT
diff --git a/packages/typescript/ai-elevenlabs/package.json b/packages/typescript/ai-elevenlabs/package.json
new file mode 100644
index 0000000000..0edafe92a4
--- /dev/null
+++ b/packages/typescript/ai-elevenlabs/package.json
@@ -0,0 +1,55 @@
+{
+ "name": "@tanstack/ai-elevenlabs",
+ "version": "0.0.1",
+ "description": "ElevenLabs adapter for TanStack AI realtime voice",
+ "author": "",
+ "license": "MIT",
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/TanStack/ai.git",
+ "directory": "packages/typescript/ai-elevenlabs"
+ },
+ "keywords": [
+ "ai",
+ "elevenlabs",
+ "voice",
+ "realtime",
+ "tanstack",
+ "adapter"
+ ],
+ "type": "module",
+ "module": "./dist/esm/index.js",
+ "types": "./dist/esm/index.d.ts",
+ "exports": {
+ ".": {
+ "types": "./dist/esm/index.d.ts",
+ "import": "./dist/esm/index.js"
+ }
+ },
+ "files": [
+ "dist",
+ "src"
+ ],
+ "scripts": {
+ "build": "vite build",
+ "clean": "premove ./build ./dist",
+ "lint:fix": "eslint ./src --fix",
+ "test:build": "publint --strict",
+ "test:eslint": "eslint ./src",
+ "test:lib": "vitest",
+ "test:lib:dev": "pnpm test:lib --watch",
+ "test:types": "tsc"
+ },
+ "dependencies": {
+ "@11labs/client": "^0.2.0"
+ },
+ "peerDependencies": {
+ "@tanstack/ai": "workspace:^",
+ "@tanstack/ai-client": "workspace:^"
+ },
+ "devDependencies": {
+ "@tanstack/ai": "workspace:*",
+ "@tanstack/ai-client": "workspace:*",
+ "@vitest/coverage-v8": "4.0.14"
+ }
+}
diff --git a/packages/typescript/ai-elevenlabs/src/index.ts b/packages/typescript/ai-elevenlabs/src/index.ts
new file mode 100644
index 0000000000..14702a1daa
--- /dev/null
+++ b/packages/typescript/ai-elevenlabs/src/index.ts
@@ -0,0 +1,16 @@
+// ============================================================================
+// ElevenLabs Realtime (Voice) Adapters
+// ============================================================================
+
+export {
+ elevenlabsRealtimeToken,
+ elevenlabsRealtime,
+} from './realtime/index'
+
+export type {
+ ElevenLabsRealtimeTokenOptions,
+ ElevenLabsRealtimeOptions,
+ ElevenLabsConversationMode,
+ ElevenLabsVADConfig,
+ ElevenLabsClientTool,
+} from './realtime/index'
diff --git a/packages/typescript/ai-elevenlabs/src/realtime/adapter.ts b/packages/typescript/ai-elevenlabs/src/realtime/adapter.ts
new file mode 100644
index 0000000000..cb193485ca
--- /dev/null
+++ b/packages/typescript/ai-elevenlabs/src/realtime/adapter.ts
@@ -0,0 +1,251 @@
+import { Conversation } from '@11labs/client'
+import type {
+ AudioVisualization,
+ RealtimeEvent,
+ RealtimeEventHandler,
+ RealtimeMessage,
+ RealtimeMode,
+ RealtimeSessionConfig,
+ RealtimeStatus,
+ RealtimeToken,
+} from '@tanstack/ai'
+import type { RealtimeAdapter, RealtimeConnection } from '@tanstack/ai-client'
+import type { ElevenLabsRealtimeOptions } from './types'
+
+/**
+ * Creates an ElevenLabs realtime adapter for client-side use.
+ *
+ * Wraps the @11labs/client SDK for voice conversations.
+ *
+ * @param options - Optional configuration
+ * @returns A RealtimeAdapter for use with RealtimeClient
+ *
+ * @example
+ * ```typescript
+ * import { RealtimeClient } from '@tanstack/ai-client'
+ * import { elevenlabsRealtime } from '@tanstack/ai-elevenlabs'
+ *
+ * const client = new RealtimeClient({
+ * getToken: () => fetch('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/api/realtime-token').then(r => r.json()),
+ * adapter: elevenlabsRealtime(),
+ * })
+ * ```
+ */
+export function elevenlabsRealtime(
+ options: ElevenLabsRealtimeOptions = {},
+): RealtimeAdapter {
+ return {
+ provider: 'elevenlabs',
+
+ async connect(token: RealtimeToken): Promise {
+ return createElevenLabsConnection(token, options)
+ },
+ }
+}
+
+/**
+ * Creates a connection to ElevenLabs conversational AI
+ */
+async function createElevenLabsConnection(
+ token: RealtimeToken,
+ _options: ElevenLabsRealtimeOptions,
+): Promise {
+ const eventHandlers = new Map>>()
+ let conversation: Awaited> | null = null
+ let messageIdCounter = 0
+
+ // Empty arrays for when visualization isn't available
+ const emptyFrequencyData = new Uint8Array(128)
+ const emptyTimeDomainData = new Uint8Array(128).fill(128)
+
+ // Helper to emit events
+ function emit(
+ event: E,
+ payload: Parameters>[0],
+ ) {
+ const handlers = eventHandlers.get(event)
+ if (handlers) {
+ for (const handler of handlers) {
+ handler(payload)
+ }
+ }
+ }
+
+ function generateMessageId(): string {
+ return `el-msg-${Date.now()}-${++messageIdCounter}`
+ }
+
+ // Start the conversation session
+ conversation = await Conversation.startSession({
+ signedUrl: token.token,
+
+ onConnect: () => {
+ emit('status_change', { status: 'connected' as RealtimeStatus })
+ emit('mode_change', { mode: 'listening' })
+ },
+
+ onDisconnect: () => {
+ emit('status_change', { status: 'idle' as RealtimeStatus })
+ emit('mode_change', { mode: 'idle' })
+ },
+
+ onModeChange: ({ mode }) => {
+ const mappedMode: RealtimeMode =
+ mode === 'speaking' ? 'speaking' : 'listening'
+ emit('mode_change', { mode: mappedMode })
+ },
+
+ onMessage: ({ message, source }) => {
+ const role = source === 'user' ? 'user' : 'assistant'
+
+ // Emit transcript update
+ emit('transcript', {
+ role,
+ transcript: message,
+ isFinal: true,
+ })
+
+ // Create and emit message
+ const realtimeMessage: RealtimeMessage = {
+ id: generateMessageId(),
+ role,
+ timestamp: Date.now(),
+ parts: [{ type: 'audio', transcript: message }],
+ }
+ emit('message_complete', { message: realtimeMessage })
+ },
+
+ onError: (error: string | Error) => {
+ emit('error', {
+ error: new Error(
+ typeof error === 'string' ? error : error.message || 'Unknown error',
+ ),
+ })
+ },
+ })
+
+ // Connection implementation
+ const connection: RealtimeConnection = {
+ async disconnect() {
+ if (conversation) {
+ await conversation.endSession()
+ conversation = null
+ }
+ emit('status_change', { status: 'idle' as RealtimeStatus })
+ },
+
+ async startAudioCapture() {
+ // ElevenLabs SDK handles audio capture automatically
+ // This is called when the session starts
+ emit('mode_change', { mode: 'listening' })
+ },
+
+ stopAudioCapture() {
+ // ElevenLabs SDK handles this
+ emit('mode_change', { mode: 'idle' })
+ },
+
+ sendText(text: string) {
+ // ElevenLabs doesn't support direct text input in the same way
+ // The SDK is voice-first. Log a warning.
+ console.warn(
+ 'ElevenLabs realtime adapter does not support sendText. Use voice input.',
+ )
+ },
+
+ sendToolResult(callId: string, result: string) {
+ // ElevenLabs handles client tools differently - they're registered at session start
+ console.warn(
+ 'ElevenLabs tool results are handled via clientTools option during session creation.',
+ )
+ },
+
+ updateSession(_config: Partial) {
+ // ElevenLabs session config is set at creation time
+ console.warn(
+ 'ElevenLabs does not support runtime session updates. Configure at connection time.',
+ )
+ },
+
+ interrupt() {
+ // ElevenLabs handles interruption automatically via barge-in
+ // No explicit API to call
+ emit('mode_change', { mode: 'listening' })
+ emit('interrupted', {})
+ },
+
+ on(
+ event: E,
+ handler: RealtimeEventHandler,
+ ): () => void {
+ if (!eventHandlers.has(event)) {
+ eventHandlers.set(event, new Set())
+ }
+ eventHandlers.get(event)!.add(handler)
+
+ return () => {
+ eventHandlers.get(event)?.delete(handler)
+ }
+ },
+
+ getAudioVisualization(): AudioVisualization {
+ return {
+ get inputLevel() {
+ if (!conversation) return 0
+ try {
+ return conversation.getInputVolume()
+ } catch {
+ return 0
+ }
+ },
+
+ get outputLevel() {
+ if (!conversation) return 0
+ try {
+ return conversation.getOutputVolume()
+ } catch {
+ return 0
+ }
+ },
+
+ getInputFrequencyData() {
+ if (!conversation) return emptyFrequencyData
+ try {
+ return conversation.getInputByteFrequencyData()
+ } catch {
+ return emptyFrequencyData
+ }
+ },
+
+ getOutputFrequencyData() {
+ if (!conversation) return emptyFrequencyData
+ try {
+ return conversation.getOutputByteFrequencyData()
+ } catch {
+ return emptyFrequencyData
+ }
+ },
+
+ getInputTimeDomainData() {
+ // ElevenLabs SDK doesn't expose time domain data
+ return emptyTimeDomainData
+ },
+
+ getOutputTimeDomainData() {
+ // ElevenLabs SDK doesn't expose time domain data
+ return emptyTimeDomainData
+ },
+
+ get inputSampleRate() {
+ return 16000
+ },
+
+ get outputSampleRate() {
+ return 16000
+ },
+ }
+ },
+ }
+
+ return connection
+}
diff --git a/packages/typescript/ai-elevenlabs/src/realtime/index.ts b/packages/typescript/ai-elevenlabs/src/realtime/index.ts
new file mode 100644
index 0000000000..db176897e4
--- /dev/null
+++ b/packages/typescript/ai-elevenlabs/src/realtime/index.ts
@@ -0,0 +1,14 @@
+// Token adapter for server-side use
+export { elevenlabsRealtimeToken } from './token'
+
+// Client adapter for browser use
+export { elevenlabsRealtime } from './adapter'
+
+// Types
+export type {
+ ElevenLabsRealtimeTokenOptions,
+ ElevenLabsRealtimeOptions,
+ ElevenLabsConversationMode,
+ ElevenLabsVADConfig,
+ ElevenLabsClientTool,
+} from './types'
diff --git a/packages/typescript/ai-elevenlabs/src/realtime/token.ts b/packages/typescript/ai-elevenlabs/src/realtime/token.ts
new file mode 100644
index 0000000000..99989b06b7
--- /dev/null
+++ b/packages/typescript/ai-elevenlabs/src/realtime/token.ts
@@ -0,0 +1,103 @@
+import type { RealtimeToken, RealtimeTokenAdapter } from '@tanstack/ai'
+import type { ElevenLabsRealtimeTokenOptions } from './types'
+
+const ELEVENLABS_API_URL = 'https://api.elevenlabs.io/v1'
+
+/**
+ * Get ElevenLabs API key from environment
+ */
+function getElevenLabsApiKey(): string {
+ // Check process.env (Node.js)
+ if (typeof process !== 'undefined' && process.env?.ELEVENLABS_API_KEY) {
+ return process.env.ELEVENLABS_API_KEY
+ }
+
+ // Check window.env (Browser with injected env)
+ if (
+ typeof window !== 'undefined' &&
+ (window as unknown as { env?: { ELEVENLABS_API_KEY?: string } }).env
+ ?.ELEVENLABS_API_KEY
+ ) {
+ return (window as unknown as { env: { ELEVENLABS_API_KEY: string } }).env
+ .ELEVENLABS_API_KEY
+ }
+
+ throw new Error(
+ 'ELEVENLABS_API_KEY not found in environment variables. ' +
+ 'Please set ELEVENLABS_API_KEY in your environment.',
+ )
+}
+
+/**
+ * Creates an ElevenLabs realtime token adapter.
+ *
+ * This adapter generates signed URLs for client-side connections.
+ * The signed URL is valid for 30 minutes.
+ *
+ * @param options - Configuration options including agentId
+ * @returns A RealtimeTokenAdapter for use with realtimeToken()
+ *
+ * @example
+ * ```typescript
+ * import { realtimeToken } from '@tanstack/ai'
+ * import { elevenlabsRealtimeToken } from '@tanstack/ai-elevenlabs'
+ *
+ * const token = await realtimeToken({
+ * adapter: elevenlabsRealtimeToken({
+ * agentId: 'your-agent-id',
+ * }),
+ * })
+ * ```
+ */
+export function elevenlabsRealtimeToken(
+ options: ElevenLabsRealtimeTokenOptions,
+): RealtimeTokenAdapter {
+ const apiKey = getElevenLabsApiKey()
+
+ return {
+ provider: 'elevenlabs',
+
+ async generateToken(): Promise {
+ const { agentId, overrides } = options
+
+ // Get signed URL from ElevenLabs
+ const response = await fetch(
+ `${ELEVENLABS_API_URL}/convai/conversation/get_signed_url?agent_id=${agentId}`,
+ {
+ method: 'GET',
+ headers: {
+ 'xi-api-key': apiKey,
+ },
+ },
+ )
+
+ if (!response.ok) {
+ const errorText = await response.text()
+ throw new Error(
+ `ElevenLabs signed URL request failed: ${response.status} ${errorText}`,
+ )
+ }
+
+ const data = await response.json()
+ const signedUrl = data.signed_url as string
+
+ // Signed URLs are valid for 30 minutes
+ const expiresAt = Date.now() + 30 * 60 * 1000
+
+ return {
+ provider: 'elevenlabs',
+ token: signedUrl,
+ expiresAt,
+ config: {
+ voice: overrides?.voiceId,
+ instructions: overrides?.systemPrompt,
+ providerOptions: {
+ agentId,
+ firstMessage: overrides?.firstMessage,
+ language: overrides?.language,
+ },
+ },
+ }
+ },
+ }
+}
diff --git a/packages/typescript/ai-elevenlabs/src/realtime/types.ts b/packages/typescript/ai-elevenlabs/src/realtime/types.ts
new file mode 100644
index 0000000000..ff2166f088
--- /dev/null
+++ b/packages/typescript/ai-elevenlabs/src/realtime/types.ts
@@ -0,0 +1,62 @@
+/**
+ * Options for the ElevenLabs realtime token adapter
+ */
+export interface ElevenLabsRealtimeTokenOptions {
+ /** Agent ID configured in ElevenLabs dashboard */
+ agentId: string
+ /** Optional override values for the agent */
+ overrides?: {
+ /** Custom voice ID to use */
+ voiceId?: string
+ /** Custom system prompt */
+ systemPrompt?: string
+ /** First message the agent should speak */
+ firstMessage?: string
+ /** Language code (e.g., 'en') */
+ language?: string
+ }
+}
+
+/**
+ * Options for the ElevenLabs realtime client adapter
+ */
+export interface ElevenLabsRealtimeOptions {
+ /** Connection mode (default: auto-detect) */
+ connectionMode?: 'websocket' | 'webrtc'
+ /** Enable debug logging */
+ debug?: boolean
+}
+
+/**
+ * ElevenLabs conversation mode
+ */
+export type ElevenLabsConversationMode = 'speaking' | 'listening'
+
+/**
+ * ElevenLabs voice activity detection configuration
+ */
+export interface ElevenLabsVADConfig {
+ /** VAD threshold (0.1-0.9) */
+ vadThreshold?: number
+ /** Silence threshold in seconds (0.3-3.0) */
+ vadSilenceThresholdSecs?: number
+ /** Minimum speech duration in ms */
+ minSpeechDurationMs?: number
+ /** Minimum silence duration in ms */
+ minSilenceDurationMs?: number
+}
+
+/**
+ * Client tool definition for ElevenLabs
+ */
+export interface ElevenLabsClientTool {
+ /** Tool handler function */
+ handler: (params: TParams) => Promise | TResult
+}
+
+/**
+ * ElevenLabs signed URL response
+ */
+export interface ElevenLabsSignedUrlResponse {
+ signed_url: string
+}
diff --git a/packages/typescript/ai-elevenlabs/tsconfig.json b/packages/typescript/ai-elevenlabs/tsconfig.json
new file mode 100644
index 0000000000..e5e8727417
--- /dev/null
+++ b/packages/typescript/ai-elevenlabs/tsconfig.json
@@ -0,0 +1,8 @@
+{
+ "extends": "../../../tsconfig.json",
+ "compilerOptions": {
+ "outDir": "dist"
+ },
+ "include": ["vite.config.ts", "./src"],
+ "exclude": ["node_modules", "dist", "**/*.config.ts"]
+}
diff --git a/packages/typescript/ai-elevenlabs/vite.config.ts b/packages/typescript/ai-elevenlabs/vite.config.ts
new file mode 100644
index 0000000000..11f5b20b70
--- /dev/null
+++ b/packages/typescript/ai-elevenlabs/vite.config.ts
@@ -0,0 +1,37 @@
+import { defineConfig, mergeConfig } from 'vitest/config'
+import { tanstackViteConfig } from '@tanstack/vite-config'
+import packageJson from './package.json'
+
+const config = defineConfig({
+ test: {
+ name: packageJson.name,
+ dir: './',
+ watch: false,
+
+ globals: true,
+ environment: 'node',
+ include: ['tests/**/*.test.ts'],
+ coverage: {
+ provider: 'v8',
+ reporter: ['text', 'json', 'html', 'lcov'],
+ exclude: [
+ 'node_modules/',
+ 'dist/',
+ 'tests/',
+ '**/*.test.ts',
+ '**/*.config.ts',
+ '**/types.ts',
+ ],
+ include: ['src/**/*.ts'],
+ },
+ },
+})
+
+export default mergeConfig(
+ config,
+ tanstackViteConfig({
+ entry: ['./src/index.ts'],
+ srcDir: './src',
+ cjs: false,
+ }),
+)
diff --git a/packages/typescript/ai-openai/package.json b/packages/typescript/ai-openai/package.json
index 917eb13aa0..a137eed03e 100644
--- a/packages/typescript/ai-openai/package.json
+++ b/packages/typescript/ai-openai/package.json
@@ -44,10 +44,12 @@
},
"peerDependencies": {
"@tanstack/ai": "workspace:^",
+ "@tanstack/ai-client": "workspace:^",
"zod": "^4.0.0"
},
"devDependencies": {
"@tanstack/ai": "workspace:*",
+ "@tanstack/ai-client": "workspace:*",
"@vitest/coverage-v8": "4.0.14",
"vite": "^7.2.7",
"zod": "^4.2.0"
diff --git a/packages/typescript/ai-openai/src/index.ts b/packages/typescript/ai-openai/src/index.ts
index ffba8da874..2b7916a37e 100644
--- a/packages/typescript/ai-openai/src/index.ts
+++ b/packages/typescript/ai-openai/src/index.ts
@@ -100,3 +100,22 @@ export type {
OpenAIMessageMetadataByModality,
} from './message-types'
export type { OpenAIClientConfig } from './utils/client'
+
+// ============================================================================
+// Realtime (Voice) Adapters
+// ============================================================================
+
+export {
+ openaiRealtimeToken,
+ openaiRealtime,
+} from './realtime/index'
+
+export type {
+ OpenAIRealtimeVoice,
+ OpenAIRealtimeModel,
+ OpenAIRealtimeTokenOptions,
+ OpenAIRealtimeOptions,
+ OpenAITurnDetection,
+ OpenAISemanticVADConfig,
+ OpenAIServerVADConfig,
+} from './realtime/index'
diff --git a/packages/typescript/ai-openai/src/realtime/adapter.ts b/packages/typescript/ai-openai/src/realtime/adapter.ts
new file mode 100644
index 0000000000..51745a26cd
--- /dev/null
+++ b/packages/typescript/ai-openai/src/realtime/adapter.ts
@@ -0,0 +1,585 @@
+import type {
+ AudioVisualization,
+ RealtimeEvent,
+ RealtimeEventHandler,
+ RealtimeMessage,
+ RealtimeMode,
+ RealtimeSessionConfig,
+ RealtimeStatus,
+ RealtimeToken,
+} from '@tanstack/ai'
+import type {
+ RealtimeAdapter,
+ RealtimeConnection,
+} from '@tanstack/ai-client'
+import type { OpenAIRealtimeOptions } from './types'
+
+const OPENAI_REALTIME_URL = 'https://api.openai.com/v1/realtime'
+
+/**
+ * Creates an OpenAI realtime adapter for client-side use.
+ *
+ * Uses WebRTC for browser connections (default) or WebSocket for Node.js.
+ *
+ * @param options - Optional configuration
+ * @returns A RealtimeAdapter for use with RealtimeClient
+ *
+ * @example
+ * ```typescript
+ * import { RealtimeClient } from '@tanstack/ai-client'
+ * import { openaiRealtime } from '@tanstack/ai-openai'
+ *
+ * const client = new RealtimeClient({
+ * getToken: () => fetch('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/api/realtime-token').then(r => r.json()),
+ * adapter: openaiRealtime(),
+ * })
+ * ```
+ */
+export function openaiRealtime(
+ options: OpenAIRealtimeOptions = {},
+): RealtimeAdapter {
+ const connectionMode = options.connectionMode ?? 'webrtc'
+
+ return {
+ provider: 'openai',
+
+ async connect(token: RealtimeToken): Promise {
+ if (connectionMode === 'webrtc') {
+ return createWebRTCConnection(token)
+ }
+ throw new Error('WebSocket connection mode not yet implemented')
+ },
+ }
+}
+
+/**
+ * Creates a WebRTC connection to OpenAI's realtime API
+ */
+async function createWebRTCConnection(
+ token: RealtimeToken,
+): Promise {
+ const model = token.config.model ?? 'gpt-4o-realtime-preview'
+ const eventHandlers = new Map>>()
+
+ // WebRTC peer connection
+ const pc = new RTCPeerConnection()
+
+ // Audio context for visualization
+ let audioContext: AudioContext | null = null
+ let inputAnalyser: AnalyserNode | null = null
+ let outputAnalyser: AnalyserNode | null = null
+ let inputSource: MediaStreamAudioSourceNode | null = null
+ let outputSource: MediaStreamAudioSourceNode | null = null
+ let localStream: MediaStream | null = null
+
+ // Audio element for playback (more reliable than AudioContext.destination)
+ let audioElement: HTMLAudioElement | null = null
+
+ // Data channel for events
+ let dataChannel: RTCDataChannel | null = null
+
+ // Current state
+ let currentMode: RealtimeMode = 'idle'
+ let currentMessageId: string | null = null
+
+ // Empty arrays for when visualization isn't available
+ // frequencyBinCount = fftSize / 2 = 1024
+ const emptyFrequencyData = new Uint8Array(1024)
+ const emptyTimeDomainData = new Uint8Array(2048).fill(128) // 128 is silence
+
+ // Helper to emit events (defined early so it can be used during setup)
+ function emit(
+ event: E,
+ payload: Parameters>[0],
+ ) {
+ const handlers = eventHandlers.get(event)
+ if (handlers) {
+ for (const handler of handlers) {
+ handler(payload)
+ }
+ }
+ }
+
+ // Set up data channel for bidirectional communication
+ dataChannel = pc.createDataChannel('oai-events')
+
+ dataChannel.onopen = () => {
+ emit('status_change', { status: 'connected' as RealtimeStatus })
+ }
+
+ dataChannel.onmessage = (event) => {
+ try {
+ const message = JSON.parse(event.data)
+ handleServerEvent(message)
+ } catch (e) {
+ console.error('Failed to parse realtime event:', e)
+ }
+ }
+
+ dataChannel.onerror = (error) => {
+ emit('error', { error: new Error(`Data channel error: ${error}`) })
+ }
+
+ // Handle incoming audio track
+ pc.ontrack = (event) => {
+ console.log('[Realtime] ontrack event:', event.track.kind, event.streams[0])
+ if (event.track.kind === 'audio' && event.streams[0]) {
+ setupOutputAudioAnalysis(event.streams[0])
+ console.log('[Realtime] Output analyser created:', outputAnalyser)
+ }
+ }
+
+ // IMPORTANT: Request microphone access and add audio track BEFORE creating offer
+ // OpenAI's Realtime API requires an audio track in the SDP offer
+ try {
+ localStream = await navigator.mediaDevices.getUserMedia({
+ audio: {
+ echoCancellation: true,
+ noiseSuppression: true,
+ sampleRate: 24000,
+ },
+ })
+
+ // Add audio track to peer connection
+ for (const track of localStream.getAudioTracks()) {
+ pc.addTrack(track, localStream)
+ }
+ } catch (error) {
+ throw new Error(
+ `Microphone access required for realtime voice: ${error instanceof Error ? error.message : error}`,
+ )
+ }
+
+ // Create and set local description (now includes audio track)
+ const offer = await pc.createOffer()
+ await pc.setLocalDescription(offer)
+
+ // Send SDP to OpenAI and get answer
+ const sdpResponse = await fetch(`${OPENAI_REALTIME_URL}?model=${model}`, {
+ method: 'POST',
+ headers: {
+ Authorization: `Bearer ${token.token}`,
+ 'Content-Type': 'application/sdp',
+ },
+ body: offer.sdp,
+ })
+
+ if (!sdpResponse.ok) {
+ const errorText = await sdpResponse.text()
+ throw new Error(
+ `Failed to establish WebRTC connection: ${sdpResponse.status} - ${errorText}`,
+ )
+ }
+
+ const answerSdp = await sdpResponse.text()
+ await pc.setRemoteDescription({ type: 'answer', sdp: answerSdp })
+
+ // Set up input audio analysis now that we have the stream
+ console.log('[Realtime] Setting up input audio analysis, localStream:', localStream)
+ setupInputAudioAnalysis(localStream)
+ console.log('[Realtime] Input analyser created:', inputAnalyser)
+
+ // Handle server events
+ function handleServerEvent(event: Record) {
+ const type = event.type as string
+
+ switch (type) {
+ case 'session.created':
+ case 'session.updated':
+ // Session ready
+ break
+
+ case 'input_audio_buffer.speech_started':
+ currentMode = 'listening'
+ emit('mode_change', { mode: 'listening' })
+ break
+
+ case 'input_audio_buffer.speech_stopped':
+ currentMode = 'thinking'
+ emit('mode_change', { mode: 'thinking' })
+ break
+
+ case 'input_audio_buffer.committed':
+ // Audio buffer committed for processing
+ break
+
+ case 'conversation.item.input_audio_transcription.completed': {
+ const transcript = event.transcript as string
+ emit('transcript', { role: 'user', transcript, isFinal: true })
+ break
+ }
+
+ case 'response.created':
+ currentMode = 'thinking'
+ emit('mode_change', { mode: 'thinking' })
+ break
+
+ case 'response.output_item.added': {
+ const item = event.item as Record
+ if (item.type === 'message') {
+ currentMessageId = item.id as string
+ }
+ break
+ }
+
+ case 'response.audio_transcript.delta': {
+ const delta = event.delta as string
+ emit('transcript', { role: 'assistant', transcript: delta, isFinal: false })
+ break
+ }
+
+ case 'response.audio_transcript.done': {
+ const transcript = event.transcript as string
+ emit('transcript', { role: 'assistant', transcript, isFinal: true })
+ break
+ }
+
+ case 'response.audio.delta':
+ if (currentMode !== 'speaking') {
+ currentMode = 'speaking'
+ emit('mode_change', { mode: 'speaking' })
+ }
+ break
+
+ case 'response.audio.done':
+ break
+
+ case 'response.function_call_arguments.done': {
+ const callId = event.call_id as string
+ const name = event.name as string
+ const args = event.arguments as string
+ try {
+ const input = JSON.parse(args)
+ emit('tool_call', { toolCallId: callId, toolName: name, input })
+ } catch {
+ emit('tool_call', { toolCallId: callId, toolName: name, input: args })
+ }
+ break
+ }
+
+ case 'response.done': {
+ currentMode = 'listening'
+ emit('mode_change', { mode: 'listening' })
+
+ // Emit message complete if we have a current message
+ if (currentMessageId) {
+ const response = event.response as Record
+ const output = response.output as Array>
+
+ const message: RealtimeMessage = {
+ id: currentMessageId,
+ role: 'assistant',
+ timestamp: Date.now(),
+ parts: [],
+ }
+
+ // Extract content from output items
+ for (const item of output || []) {
+ if (item.type === 'message' && item.content) {
+ const content = item.content as Array>
+ for (const part of content) {
+ if (part.type === 'audio' && part.transcript) {
+ message.parts.push({
+ type: 'audio',
+ transcript: part.transcript as string,
+ })
+ } else if (part.type === 'text' && part.text) {
+ message.parts.push({
+ type: 'text',
+ content: part.text as string,
+ })
+ }
+ }
+ }
+ }
+
+ emit('message_complete', { message })
+ currentMessageId = null
+ }
+ break
+ }
+
+ case 'conversation.item.truncated':
+ emit('interrupted', { messageId: currentMessageId ?? undefined })
+ break
+
+ case 'error': {
+ const error = event.error as Record
+ emit('error', {
+ error: new Error((error.message as string) || 'Unknown error'),
+ })
+ break
+ }
+ }
+ }
+
+ // Set up audio analysis for output
+ function setupOutputAudioAnalysis(stream: MediaStream) {
+ // Create audio element for playback - this is the standard way to play WebRTC audio
+ audioElement = new Audio()
+ audioElement.srcObject = stream
+ audioElement.autoplay = true
+ // Some browsers require this for autoplay
+ audioElement.play().catch((e) => {
+ console.warn('Audio autoplay failed:', e)
+ })
+
+ // Set up AudioContext for visualization only (not playback)
+ if (!audioContext) {
+ audioContext = new AudioContext()
+ }
+
+ // Resume AudioContext if suspended (browsers require user interaction)
+ if (audioContext.state === 'suspended') {
+ audioContext.resume().catch(() => {
+ // Ignore - visualization just won't work
+ })
+ }
+
+ outputAnalyser = audioContext.createAnalyser()
+ outputAnalyser.fftSize = 2048 // Larger size for more accurate level detection
+ outputAnalyser.smoothingTimeConstant = 0.3
+
+ outputSource = audioContext.createMediaStreamSource(stream)
+ outputSource.connect(outputAnalyser)
+ // Don't connect to destination - the Audio element handles playback
+ }
+
+ // Set up audio analysis for input
+ function setupInputAudioAnalysis(stream: MediaStream) {
+ if (!audioContext) {
+ audioContext = new AudioContext()
+ }
+
+ // Resume AudioContext if suspended (browsers require user interaction)
+ if (audioContext.state === 'suspended') {
+ audioContext.resume().catch(() => {
+ // Ignore - visualization just won't work
+ })
+ }
+
+ inputAnalyser = audioContext.createAnalyser()
+ inputAnalyser.fftSize = 2048 // Larger size for more accurate level detection
+ inputAnalyser.smoothingTimeConstant = 0.3
+
+ inputSource = audioContext.createMediaStreamSource(stream)
+ inputSource.connect(inputAnalyser)
+ }
+
+ // Send event to server
+ function sendEvent(event: Record) {
+ if (dataChannel?.readyState === 'open') {
+ dataChannel.send(JSON.stringify(event))
+ }
+ }
+
+ // Connection implementation
+ const connection: RealtimeConnection = {
+ async disconnect() {
+ if (localStream) {
+ for (const track of localStream.getTracks()) {
+ track.stop()
+ }
+ localStream = null
+ }
+
+ if (audioElement) {
+ audioElement.pause()
+ audioElement.srcObject = null
+ audioElement = null
+ }
+
+ if (dataChannel) {
+ dataChannel.close()
+ dataChannel = null
+ }
+
+ pc.close()
+
+ if (audioContext) {
+ await audioContext.close()
+ audioContext = null
+ }
+
+ emit('status_change', { status: 'idle' as RealtimeStatus })
+ },
+
+ async startAudioCapture() {
+ // Audio capture is established during connection setup
+ // This method enables the tracks and signals listening mode
+ if (localStream) {
+ for (const track of localStream.getAudioTracks()) {
+ track.enabled = true
+ }
+ }
+ currentMode = 'listening'
+ emit('mode_change', { mode: 'listening' })
+ },
+
+ stopAudioCapture() {
+ // Disable tracks rather than stopping them to allow re-enabling
+ if (localStream) {
+ for (const track of localStream.getAudioTracks()) {
+ track.enabled = false
+ }
+ }
+ currentMode = 'idle'
+ emit('mode_change', { mode: 'idle' })
+ },
+
+ sendText(text: string) {
+ sendEvent({
+ type: 'conversation.item.create',
+ item: {
+ type: 'message',
+ role: 'user',
+ content: [{ type: 'input_text', text }],
+ },
+ })
+ sendEvent({ type: 'response.create' })
+ },
+
+ sendToolResult(callId: string, result: string) {
+ sendEvent({
+ type: 'conversation.item.create',
+ item: {
+ type: 'function_call_output',
+ call_id: callId,
+ output: result,
+ },
+ })
+ sendEvent({ type: 'response.create' })
+ },
+
+ updateSession(config: Partial) {
+ const sessionUpdate: Record = {}
+
+ if (config.instructions) {
+ sessionUpdate.instructions = config.instructions
+ }
+
+ if (config.voice) {
+ sessionUpdate.voice = config.voice
+ }
+
+ if (config.vadMode) {
+ if (config.vadMode === 'semantic') {
+ sessionUpdate.turn_detection = {
+ type: 'semantic_vad',
+ eagerness: 'medium',
+ }
+ } else if (config.vadMode === 'server') {
+ sessionUpdate.turn_detection = {
+ type: 'server_vad',
+ threshold: config.vadConfig?.threshold ?? 0.5,
+ prefix_padding_ms: config.vadConfig?.prefixPaddingMs ?? 300,
+ silence_duration_ms: config.vadConfig?.silenceDurationMs ?? 500,
+ }
+ } else {
+ sessionUpdate.turn_detection = null
+ }
+ }
+
+ if (Object.keys(sessionUpdate).length > 0) {
+ sendEvent({
+ type: 'session.update',
+ session: sessionUpdate,
+ })
+ }
+ },
+
+ interrupt() {
+ sendEvent({ type: 'response.cancel' })
+ currentMode = 'listening'
+ emit('mode_change', { mode: 'listening' })
+ emit('interrupted', { messageId: currentMessageId ?? undefined })
+ },
+
+ on(
+ event: E,
+ handler: RealtimeEventHandler,
+ ): () => void {
+ if (!eventHandlers.has(event)) {
+ eventHandlers.set(event, new Set())
+ }
+ eventHandlers.get(event)!.add(handler)
+
+ return () => {
+ eventHandlers.get(event)?.delete(handler)
+ }
+ },
+
+ getAudioVisualization(): AudioVisualization {
+ // Log analyser state for debugging
+ console.log('[Realtime] getAudioVisualization called, inputAnalyser:', !!inputAnalyser, 'outputAnalyser:', !!outputAnalyser)
+
+ // Helper to calculate RMS (Root Mean Square) from time domain data
+ // This gives a better measure of perceived loudness than frequency data
+ function calculateRMS(analyser: AnalyserNode): number {
+ const data = new Uint8Array(analyser.fftSize)
+ analyser.getByteTimeDomainData(data)
+
+ // Calculate RMS - values are 0-255 with 128 being silence
+ let sumSquares = 0
+ for (const sample of data) {
+ const normalized = (sample - 128) / 128 // Convert to -1 to 1 range
+ sumSquares += normalized * normalized
+ }
+ const rms = Math.sqrt(sumSquares / data.length)
+
+ // Scale and clamp to 0-1 range (RMS of full-scale sine is ~0.707)
+ return Math.min(1, rms * 1.5)
+ }
+
+ return {
+ get inputLevel() {
+ if (!inputAnalyser) return 0
+ return calculateRMS(inputAnalyser)
+ },
+
+ get outputLevel() {
+ if (!outputAnalyser) return 0
+ return calculateRMS(outputAnalyser)
+ },
+
+ getInputFrequencyData() {
+ if (!inputAnalyser) return emptyFrequencyData
+ const data = new Uint8Array(inputAnalyser.frequencyBinCount)
+ inputAnalyser.getByteFrequencyData(data)
+ return data
+ },
+
+ getOutputFrequencyData() {
+ if (!outputAnalyser) return emptyFrequencyData
+ const data = new Uint8Array(outputAnalyser.frequencyBinCount)
+ outputAnalyser.getByteFrequencyData(data)
+ return data
+ },
+
+ getInputTimeDomainData() {
+ if (!inputAnalyser) return emptyTimeDomainData
+ const data = new Uint8Array(inputAnalyser.fftSize)
+ inputAnalyser.getByteTimeDomainData(data)
+ return data
+ },
+
+ getOutputTimeDomainData() {
+ if (!outputAnalyser) return emptyTimeDomainData
+ const data = new Uint8Array(outputAnalyser.fftSize)
+ outputAnalyser.getByteTimeDomainData(data)
+ return data
+ },
+
+ get inputSampleRate() {
+ return 24000
+ },
+
+ get outputSampleRate() {
+ return 24000
+ },
+ }
+ },
+ }
+
+ return connection
+}
diff --git a/packages/typescript/ai-openai/src/realtime/index.ts b/packages/typescript/ai-openai/src/realtime/index.ts
new file mode 100644
index 0000000000..d5ea156e6e
--- /dev/null
+++ b/packages/typescript/ai-openai/src/realtime/index.ts
@@ -0,0 +1,16 @@
+// Token adapter for server-side use
+export { openaiRealtimeToken } from './token'
+
+// Client adapter for browser use
+export { openaiRealtime } from './adapter'
+
+// Types
+export type {
+ OpenAIRealtimeVoice,
+ OpenAIRealtimeModel,
+ OpenAIRealtimeTokenOptions,
+ OpenAIRealtimeOptions,
+ OpenAITurnDetection,
+ OpenAISemanticVADConfig,
+ OpenAIServerVADConfig,
+} from './types'
diff --git a/packages/typescript/ai-openai/src/realtime/token.ts b/packages/typescript/ai-openai/src/realtime/token.ts
new file mode 100644
index 0000000000..d226cacbba
--- /dev/null
+++ b/packages/typescript/ai-openai/src/realtime/token.ts
@@ -0,0 +1,153 @@
+import type { RealtimeToken, RealtimeTokenAdapter, Tool } from '@tanstack/ai'
+import { getOpenAIApiKeyFromEnv } from '../utils'
+import type {
+ OpenAIRealtimeModel,
+ OpenAIRealtimeSessionResponse,
+ OpenAIRealtimeTokenOptions,
+} from './types'
+
+const OPENAI_REALTIME_SESSIONS_URL =
+ 'https://api.openai.com/v1/realtime/sessions'
+
+/**
+ * Creates an OpenAI realtime token adapter.
+ *
+ * This adapter generates ephemeral tokens for client-side WebRTC connections.
+ * The token is valid for 10 minutes.
+ *
+ * @param options - Configuration options for the realtime session
+ * @returns A RealtimeTokenAdapter for use with realtimeToken()
+ *
+ * @example
+ * ```typescript
+ * import { realtimeToken } from '@tanstack/ai'
+ * import { openaiRealtimeToken } from '@tanstack/ai-openai'
+ *
+ * const token = await realtimeToken({
+ * adapter: openaiRealtimeToken({
+ * model: 'gpt-4o-realtime-preview',
+ * voice: 'alloy',
+ * instructions: 'You are a helpful assistant.',
+ * turnDetection: {
+ * type: 'semantic_vad',
+ * eagerness: 'medium',
+ * },
+ * }),
+ * })
+ * ```
+ */
+export function openaiRealtimeToken(
+ options: OpenAIRealtimeTokenOptions = {},
+): RealtimeTokenAdapter {
+ const apiKey = getOpenAIApiKeyFromEnv()
+
+ return {
+ provider: 'openai',
+
+ async generateToken(): Promise {
+ const model: OpenAIRealtimeModel =
+ options.model ?? 'gpt-4o-realtime-preview'
+ const voice = options.voice ?? 'alloy'
+
+ // Build request body
+ const body: Record = {
+ model,
+ voice,
+ }
+
+ if (options.instructions) {
+ body.instructions = options.instructions
+ }
+
+ if (options.turnDetection !== undefined) {
+ body.turn_detection = options.turnDetection
+ }
+
+ if (options.inputAudioFormat) {
+ body.input_audio_format = options.inputAudioFormat
+ }
+
+ if (options.outputAudioFormat) {
+ body.output_audio_format = options.outputAudioFormat
+ }
+
+ if (options.inputAudioTranscription) {
+ body.input_audio_transcription = options.inputAudioTranscription
+ }
+
+ if (options.tools) {
+ body.tools = options.tools
+ }
+
+ if (options.toolChoice) {
+ body.tool_choice = options.toolChoice
+ }
+
+ if (options.temperature !== undefined) {
+ body.temperature = options.temperature
+ }
+
+ if (options.maxResponseOutputTokens !== undefined) {
+ body.max_response_output_tokens = options.maxResponseOutputTokens
+ }
+
+ // Call OpenAI API to create session and get ephemeral token
+ const response = await fetch(OPENAI_REALTIME_SESSIONS_URL, {
+ method: 'POST',
+ headers: {
+ Authorization: `Bearer ${apiKey}`,
+ 'Content-Type': 'application/json',
+ },
+ body: JSON.stringify(body),
+ })
+
+ if (!response.ok) {
+ const errorText = await response.text()
+ throw new Error(
+ `OpenAI realtime session creation failed: ${response.status} ${errorText}`,
+ )
+ }
+
+ const sessionData: OpenAIRealtimeSessionResponse = await response.json()
+
+ // Convert tools to our format
+ const tools: Array = (sessionData.tools || []).map((t) => ({
+ name: t.name,
+ description: t.description,
+ inputSchema: t.parameters,
+ }))
+
+ return {
+ provider: 'openai',
+ token: sessionData.client_secret.value,
+ expiresAt: sessionData.client_secret.expires_at * 1000, // Convert to ms
+ config: {
+ model: sessionData.model,
+ voice: sessionData.voice,
+ instructions: sessionData.instructions,
+ tools,
+ vadMode: sessionData.turn_detection?.type === 'semantic_vad'
+ ? 'semantic'
+ : sessionData.turn_detection?.type === 'server_vad'
+ ? 'server'
+ : 'manual',
+ vadConfig: sessionData.turn_detection
+ ? {
+ threshold: sessionData.turn_detection.threshold,
+ prefixPaddingMs: sessionData.turn_detection.prefix_padding_ms,
+ silenceDurationMs:
+ sessionData.turn_detection.silence_duration_ms,
+ }
+ : undefined,
+ providerOptions: {
+ inputAudioFormat: sessionData.input_audio_format,
+ outputAudioFormat: sessionData.output_audio_format,
+ inputAudioTranscription: sessionData.input_audio_transcription,
+ temperature: sessionData.temperature,
+ maxResponseOutputTokens: sessionData.max_response_output_tokens,
+ },
+ },
+ }
+ },
+ }
+}
diff --git a/packages/typescript/ai-openai/src/realtime/types.ts b/packages/typescript/ai-openai/src/realtime/types.ts
new file mode 100644
index 0000000000..713bd2b4cf
--- /dev/null
+++ b/packages/typescript/ai-openai/src/realtime/types.ts
@@ -0,0 +1,127 @@
+import type { VADConfig } from '@tanstack/ai'
+
+/**
+ * OpenAI realtime voice options
+ */
+export type OpenAIRealtimeVoice =
+ | 'alloy'
+ | 'ash'
+ | 'ballad'
+ | 'coral'
+ | 'echo'
+ | 'sage'
+ | 'shimmer'
+ | 'verse'
+
+/**
+ * OpenAI realtime model options
+ */
+export type OpenAIRealtimeModel =
+ | 'gpt-4o-realtime-preview'
+ | 'gpt-4o-realtime-preview-2024-10-01'
+ | 'gpt-4o-mini-realtime-preview'
+ | 'gpt-4o-mini-realtime-preview-2024-12-17'
+
+/**
+ * OpenAI semantic VAD configuration
+ */
+export interface OpenAISemanticVADConfig {
+ type: 'semantic_vad'
+ /** Eagerness level for turn detection */
+ eagerness?: 'low' | 'medium' | 'high'
+}
+
+/**
+ * OpenAI server VAD configuration
+ */
+export interface OpenAIServerVADConfig extends VADConfig {
+ type: 'server_vad'
+}
+
+/**
+ * OpenAI turn detection configuration
+ */
+export type OpenAITurnDetection =
+ | OpenAISemanticVADConfig
+ | OpenAIServerVADConfig
+ | null
+
+/**
+ * Options for the OpenAI realtime token adapter
+ */
+export interface OpenAIRealtimeTokenOptions {
+ /** Model to use (default: 'gpt-4o-realtime-preview') */
+ model?: OpenAIRealtimeModel
+ /** Voice to use (default: 'alloy') */
+ voice?: OpenAIRealtimeVoice
+ /** System instructions */
+ instructions?: string
+ /** Turn detection configuration */
+ turnDetection?: OpenAITurnDetection
+ /** Input audio format (default: 'pcm16') */
+ inputAudioFormat?: 'pcm16' | 'g711_ulaw' | 'g711_alaw'
+ /** Output audio format (default: 'pcm16') */
+ outputAudioFormat?: 'pcm16' | 'g711_ulaw' | 'g711_alaw'
+ /** Input audio transcription model */
+ inputAudioTranscription?: {
+ model: 'whisper-1'
+ }
+ /** Tools available in the session */
+ tools?: Array<{
+ type: 'function'
+ name: string
+ description: string
+ parameters: Record
+ }>
+ /** Tool choice strategy */
+ toolChoice?: 'auto' | 'none' | 'required' | { type: 'function'; name: string }
+ /** Temperature for response generation */
+ temperature?: number
+ /** Maximum response output tokens */
+ maxResponseOutputTokens?: number | 'inf'
+}
+
+/**
+ * Options for the OpenAI realtime client adapter
+ */
+export interface OpenAIRealtimeOptions {
+ /** Connection mode (default: 'webrtc' in browser) */
+ connectionMode?: 'webrtc' | 'websocket'
+}
+
+/**
+ * OpenAI realtime session response from the API
+ */
+export interface OpenAIRealtimeSessionResponse {
+ id: string
+ object: 'realtime.session'
+ model: string
+ modalities: Array
+ instructions: string
+ voice: string
+ input_audio_format: string
+ output_audio_format: string
+ input_audio_transcription: {
+ model: string
+ } | null
+ turn_detection: {
+ type: string
+ threshold?: number
+ prefix_padding_ms?: number
+ silence_duration_ms?: number
+ eagerness?: string
+ } | null
+ tools: Array<{
+ type: string
+ name: string
+ description: string
+ parameters: Record
+ }>
+ tool_choice: string
+ temperature: number
+ max_response_output_tokens: number | string
+ client_secret: {
+ value: string
+ expires_at: number
+ }
+}
diff --git a/packages/typescript/ai-react/src/index.ts b/packages/typescript/ai-react/src/index.ts
index b08f90e361..175db7bb1d 100644
--- a/packages/typescript/ai-react/src/index.ts
+++ b/packages/typescript/ai-react/src/index.ts
@@ -1,10 +1,15 @@
export { useChat } from './use-chat'
+export { useRealtimeChat } from './use-realtime-chat'
export type {
UseChatOptions,
UseChatReturn,
UIMessage,
ChatRequestBody,
} from './types'
+export type {
+ UseRealtimeChatOptions,
+ UseRealtimeChatReturn,
+} from './realtime-types'
// Re-export from ai-client for convenience
export {
diff --git a/packages/typescript/ai-react/src/realtime-types.ts b/packages/typescript/ai-react/src/realtime-types.ts
new file mode 100644
index 0000000000..f3a403464e
--- /dev/null
+++ b/packages/typescript/ai-react/src/realtime-types.ts
@@ -0,0 +1,109 @@
+import type {
+ RealtimeMessage,
+ RealtimeMode,
+ RealtimeStatus,
+ RealtimeToken,
+} from '@tanstack/ai'
+import type { RealtimeAdapter } from '@tanstack/ai-client'
+import type { AnyClientTool } from '@tanstack/ai'
+
+/**
+ * Options for the useRealtimeChat hook.
+ */
+export interface UseRealtimeChatOptions {
+ /**
+ * Function to fetch a realtime token from the server.
+ * Called on connect and when token needs refresh.
+ */
+ getToken: () => Promise
+
+ /**
+ * The realtime adapter to use (e.g., openaiRealtime())
+ */
+ adapter: RealtimeAdapter
+
+ /**
+ * Client-side tools with execution logic
+ */
+ tools?: ReadonlyArray
+
+ /**
+ * Auto-play assistant audio (default: true)
+ */
+ autoPlayback?: boolean
+
+ /**
+ * Request microphone access on connect (default: true)
+ */
+ autoCapture?: boolean
+
+ /**
+ * Voice activity detection mode (default: 'server')
+ */
+ vadMode?: 'server' | 'semantic' | 'manual'
+
+ // Callbacks
+ onConnect?: () => void
+ onDisconnect?: () => void
+ onError?: (error: Error) => void
+ onMessage?: (message: RealtimeMessage) => void
+ onModeChange?: (mode: RealtimeMode) => void
+ onInterrupted?: () => void
+}
+
+/**
+ * Return type for the useRealtimeChat hook.
+ */
+export interface UseRealtimeChatReturn {
+ // Connection state
+ /** Current connection status */
+ status: RealtimeStatus
+ /** Current error, if any */
+ error: Error | null
+ /** Connect to the realtime session */
+ connect: () => Promise
+ /** Disconnect from the realtime session */
+ disconnect: () => Promise
+
+ // Conversation state
+ /** Current mode (idle, listening, thinking, speaking) */
+ mode: RealtimeMode
+ /** Conversation messages */
+ messages: Array
+ /** User transcript while speaking (before finalized) */
+ pendingUserTranscript: string | null
+ /** Assistant transcript while speaking (before finalized) */
+ pendingAssistantTranscript: string | null
+
+ // Voice control
+ /** Start listening for voice input (manual VAD mode) */
+ startListening: () => void
+ /** Stop listening for voice input (manual VAD mode) */
+ stopListening: () => void
+ /** Interrupt the current assistant response */
+ interrupt: () => void
+
+ // Text input
+ /** Send a text message instead of voice */
+ sendText: (text: string) => void
+
+ // Audio visualization (0-1 normalized)
+ /** Current input (microphone) volume level */
+ inputLevel: number
+ /** Current output (speaker) volume level */
+ outputLevel: number
+ /** Get frequency data for input audio visualization */
+ getInputFrequencyData: () => Uint8Array
+ /** Get frequency data for output audio visualization */
+ getOutputFrequencyData: () => Uint8Array
+ /** Get time domain data for input waveform */
+ getInputTimeDomainData: () => Uint8Array
+ /** Get time domain data for output waveform */
+ getOutputTimeDomainData: () => Uint8Array
+
+ // VAD control
+ /** Current VAD mode */
+ vadMode: 'server' | 'semantic' | 'manual'
+ /** Change VAD mode at runtime */
+ setVADMode: (mode: 'server' | 'semantic' | 'manual') => void
+}
diff --git a/packages/typescript/ai-react/src/use-realtime-chat.ts b/packages/typescript/ai-react/src/use-realtime-chat.ts
new file mode 100644
index 0000000000..3434db607d
--- /dev/null
+++ b/packages/typescript/ai-react/src/use-realtime-chat.ts
@@ -0,0 +1,241 @@
+import { useCallback, useEffect, useRef, useState } from 'react'
+import { RealtimeClient } from '@tanstack/ai-client'
+import type { RealtimeMessage, RealtimeMode, RealtimeStatus } from '@tanstack/ai'
+import type { UseRealtimeChatOptions, UseRealtimeChatReturn } from './realtime-types'
+
+// Empty frequency data for when client is not connected
+const emptyFrequencyData = new Uint8Array(128)
+const emptyTimeDomainData = new Uint8Array(128).fill(128)
+
+/**
+ * React hook for realtime voice conversations.
+ *
+ * Provides a simple interface for voice-to-voice AI interactions
+ * with support for multiple providers (OpenAI, ElevenLabs, etc.).
+ *
+ * @param options - Configuration options including adapter and callbacks
+ * @returns Hook return value with state and control methods
+ *
+ * @example
+ * ```typescript
+ * import { useRealtimeChat } from '@tanstack/ai-react'
+ * import { openaiRealtime } from '@tanstack/ai-openai'
+ *
+ * function VoiceChat() {
+ * const {
+ * status,
+ * mode,
+ * messages,
+ * connect,
+ * disconnect,
+ * inputLevel,
+ * outputLevel,
+ * } = useRealtimeChat({
+ * getToken: () => fetch('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/api/realtime-token').then(r => r.json()),
+ * adapter: openaiRealtime(),
+ * })
+ *
+ * return (
+ *
+ *
Status: {status}
+ *
Mode: {mode}
+ *
+ * {status === 'idle' ? 'Start' : 'Stop'}
+ *
+ *
+ * )
+ * }
+ * ```
+ */
+export function useRealtimeChat(
+ options: UseRealtimeChatOptions,
+): UseRealtimeChatReturn {
+ // State
+ const [status, setStatus] = useState('idle')
+ const [mode, setMode] = useState('idle')
+ const [messages, setMessages] = useState>([])
+ const [pendingUserTranscript, setPendingUserTranscript] = useState(null)
+ const [pendingAssistantTranscript, setPendingAssistantTranscript] = useState(null)
+ const [error, setError] = useState(null)
+ const [inputLevel, setInputLevel] = useState(0)
+ const [outputLevel, setOutputLevel] = useState(0)
+ const [vadMode, setVADModeState] = useState<'server' | 'semantic' | 'manual'>(
+ options.vadMode ?? 'server',
+ )
+
+ // Refs
+ const clientRef = useRef(null)
+ const optionsRef = useRef(options)
+ optionsRef.current = options
+ const animationFrameRef = useRef(null)
+
+ // Create client instance - use ref to ensure we reuse the same instance
+ // This handles React StrictMode double-rendering
+ if (!clientRef.current) {
+ clientRef.current = new RealtimeClient({
+ getToken: optionsRef.current.getToken,
+ adapter: optionsRef.current.adapter,
+ tools: optionsRef.current.tools,
+ autoPlayback: optionsRef.current.autoPlayback,
+ autoCapture: optionsRef.current.autoCapture,
+ vadMode: optionsRef.current.vadMode,
+ onStatusChange: (newStatus) => {
+ setStatus(newStatus)
+ },
+ onModeChange: (newMode) => {
+ setMode(newMode)
+ optionsRef.current.onModeChange?.(newMode)
+ },
+ onMessage: (message) => {
+ setMessages((prev) => [...prev, message])
+ optionsRef.current.onMessage?.(message)
+ },
+ onError: (err) => {
+ setError(err)
+ optionsRef.current.onError?.(err)
+ },
+ onConnect: () => {
+ setError(null)
+ optionsRef.current.onConnect?.()
+ },
+ onDisconnect: () => {
+ optionsRef.current.onDisconnect?.()
+ },
+ onInterrupted: () => {
+ setPendingAssistantTranscript(null)
+ optionsRef.current.onInterrupted?.()
+ },
+ })
+
+ // Subscribe to state changes for transcripts
+ clientRef.current.onStateChange((state) => {
+ setPendingUserTranscript(state.pendingUserTranscript)
+ setPendingAssistantTranscript(state.pendingAssistantTranscript)
+ })
+ }
+
+ const client = clientRef.current
+
+ // Audio level animation loop
+ useEffect(() => {
+ function updateLevels() {
+ if (clientRef.current?.audio) {
+ setInputLevel(clientRef.current.audio.inputLevel)
+ setOutputLevel(clientRef.current.audio.outputLevel)
+ }
+ animationFrameRef.current = requestAnimationFrame(updateLevels)
+ }
+
+ if (status === 'connected') {
+ updateLevels()
+ }
+
+ return () => {
+ if (animationFrameRef.current) {
+ cancelAnimationFrame(animationFrameRef.current)
+ animationFrameRef.current = null
+ }
+ }
+ }, [status])
+
+ // Cleanup on unmount
+ useEffect(() => {
+ return () => {
+ clientRef.current?.destroy()
+ }
+ }, [])
+
+ // Connection methods
+ const connect = useCallback(async () => {
+ setError(null)
+ setMessages([])
+ setPendingUserTranscript(null)
+ setPendingAssistantTranscript(null)
+ await client.connect()
+ }, [client])
+
+ const disconnect = useCallback(async () => {
+ await client.disconnect()
+ }, [client])
+
+ // Voice control methods
+ const startListening = useCallback(() => {
+ client.startListening()
+ }, [client])
+
+ const stopListening = useCallback(() => {
+ client.stopListening()
+ }, [client])
+
+ const interrupt = useCallback(() => {
+ client.interrupt()
+ }, [client])
+
+ // Text input
+ const sendText = useCallback(
+ (text: string) => {
+ client.sendText(text)
+ },
+ [client],
+ )
+
+ // Audio visualization
+ const getInputFrequencyData = useCallback(() => {
+ return clientRef.current?.audio?.getInputFrequencyData() ?? emptyFrequencyData
+ }, [])
+
+ const getOutputFrequencyData = useCallback(() => {
+ return clientRef.current?.audio?.getOutputFrequencyData() ?? emptyFrequencyData
+ }, [])
+
+ const getInputTimeDomainData = useCallback(() => {
+ return clientRef.current?.audio?.getInputTimeDomainData() ?? emptyTimeDomainData
+ }, [])
+
+ const getOutputTimeDomainData = useCallback(() => {
+ return clientRef.current?.audio?.getOutputTimeDomainData() ?? emptyTimeDomainData
+ }, [])
+
+ // VAD mode control
+ const setVADMode = useCallback(
+ (newMode: 'server' | 'semantic' | 'manual') => {
+ setVADModeState(newMode)
+ // TODO: Update session config if connected
+ },
+ [],
+ )
+
+ return {
+ // Connection state
+ status,
+ error,
+ connect,
+ disconnect,
+
+ // Conversation state
+ mode,
+ messages,
+ pendingUserTranscript,
+ pendingAssistantTranscript,
+
+ // Voice control
+ startListening,
+ stopListening,
+ interrupt,
+
+ // Text input
+ sendText,
+
+ // Audio visualization
+ inputLevel,
+ outputLevel,
+ getInputFrequencyData,
+ getOutputFrequencyData,
+ getInputTimeDomainData,
+ getOutputTimeDomainData,
+
+ // VAD control
+ vadMode,
+ setVADMode,
+ }
+}
diff --git a/packages/typescript/ai/src/index.ts b/packages/typescript/ai/src/index.ts
index 7f0d4fecef..1698a0556b 100644
--- a/packages/typescript/ai/src/index.ts
+++ b/packages/typescript/ai/src/index.ts
@@ -79,6 +79,30 @@ export { detectImageMimeType } from './utils'
// Event client + event types
export * from './event-client'
+// Realtime
+export { realtimeToken } from './realtime/index'
+export type {
+ RealtimeToken,
+ RealtimeTokenAdapter,
+ RealtimeTokenOptions,
+ RealtimeSessionConfig,
+ VADConfig,
+ RealtimeMessage,
+ RealtimeMessagePart,
+ RealtimeTextPart,
+ RealtimeAudioPart,
+ RealtimeToolCallPart,
+ RealtimeToolResultPart,
+ RealtimeStatus,
+ RealtimeMode,
+ AudioVisualization,
+ RealtimeEvent,
+ RealtimeEventPayloads,
+ RealtimeEventHandler,
+ RealtimeErrorCode,
+ RealtimeError,
+} from './realtime/index'
+
// Message converters
export {
convertMessagesToModelMessages,
diff --git a/packages/typescript/ai/src/realtime/index.ts b/packages/typescript/ai/src/realtime/index.ts
new file mode 100644
index 0000000000..74c450c1d4
--- /dev/null
+++ b/packages/typescript/ai/src/realtime/index.ts
@@ -0,0 +1,38 @@
+import type { RealtimeToken, RealtimeTokenOptions } from './types'
+
+// Re-export all types
+export * from './types'
+
+/**
+ * Generate a realtime token using the provided adapter.
+ *
+ * This function is used on the server to generate ephemeral tokens
+ * that clients can use to establish realtime connections.
+ *
+ * @param options - Token generation options including the adapter
+ * @returns Promise resolving to a RealtimeToken
+ *
+ * @example
+ * ```typescript
+ * import { realtimeToken } from '@tanstack/ai'
+ * import { openaiRealtimeToken } from '@tanstack/ai-openai'
+ *
+ * // Server function (TanStack Start example)
+ * export const getRealtimeToken = createServerFn()
+ * .handler(async () => {
+ * return realtimeToken({
+ * adapter: openaiRealtimeToken({
+ * model: 'gpt-4o-realtime-preview',
+ * voice: 'alloy',
+ * instructions: 'You are a helpful assistant...',
+ * }),
+ * })
+ * })
+ * ```
+ */
+export async function realtimeToken(
+ options: RealtimeTokenOptions,
+): Promise {
+ const { adapter } = options
+ return adapter.generateToken()
+}
diff --git a/packages/typescript/ai/src/realtime/types.ts b/packages/typescript/ai/src/realtime/types.ts
new file mode 100644
index 0000000000..e563a2ae75
--- /dev/null
+++ b/packages/typescript/ai/src/realtime/types.ts
@@ -0,0 +1,266 @@
+import type { Tool } from '../types'
+
+// ============================================================================
+// Token Types
+// ============================================================================
+
+/**
+ * Voice activity detection configuration
+ */
+export interface VADConfig {
+ /** Sensitivity threshold (0.0-1.0) */
+ threshold?: number
+ /** Audio to include before speech detection (ms) */
+ prefixPaddingMs?: number
+ /** Silence duration to end turn (ms) */
+ silenceDurationMs?: number
+}
+
+/**
+ * Configuration for a realtime session
+ */
+export interface RealtimeSessionConfig {
+ /** Model to use for the session */
+ model?: string
+ /** Voice to use for audio output */
+ voice?: string
+ /** System instructions for the assistant */
+ instructions?: string
+ /** Tools available in the session */
+ tools?: Array
+ /** VAD mode */
+ vadMode?: 'server' | 'semantic' | 'manual'
+ /** VAD configuration */
+ vadConfig?: VADConfig
+ /** Provider-specific options */
+ providerOptions?: Record
+}
+
+/**
+ * Token returned by the server for client authentication
+ */
+export interface RealtimeToken {
+ /** Provider identifier */
+ provider: string
+ /** The ephemeral token value */
+ token: string
+ /** Token expiration timestamp (ms since epoch) */
+ expiresAt: number
+ /** Session configuration embedded in the token */
+ config: RealtimeSessionConfig
+}
+
+/**
+ * Adapter interface for generating provider-specific tokens
+ */
+export interface RealtimeTokenAdapter {
+ /** Provider identifier */
+ provider: string
+ /** Generate an ephemeral token for client use */
+ generateToken(): Promise
+}
+
+/**
+ * Options for the realtimeToken function
+ */
+export interface RealtimeTokenOptions {
+ /** The token adapter to use */
+ adapter: RealtimeTokenAdapter
+}
+
+// ============================================================================
+// Message Types
+// ============================================================================
+
+/**
+ * Text content part in a realtime message
+ */
+export interface RealtimeTextPart {
+ type: 'text'
+ content: string
+}
+
+/**
+ * Audio content part in a realtime message
+ */
+export interface RealtimeAudioPart {
+ type: 'audio'
+ /** Transcription of the audio */
+ transcript: string
+ /** Raw audio data (optional, if stored) */
+ audioData?: ArrayBuffer
+ /** Duration of the audio in milliseconds */
+ durationMs?: number
+}
+
+/**
+ * Tool call part in a realtime message
+ */
+export interface RealtimeToolCallPart {
+ type: 'tool-call'
+ id: string
+ name: string
+ arguments: string
+ input?: unknown
+ output?: unknown
+}
+
+/**
+ * Tool result part in a realtime message
+ */
+export interface RealtimeToolResultPart {
+ type: 'tool-result'
+ toolCallId: string
+ content: string
+}
+
+/**
+ * Union of all realtime message parts
+ */
+export type RealtimeMessagePart =
+ | RealtimeTextPart
+ | RealtimeAudioPart
+ | RealtimeToolCallPart
+ | RealtimeToolResultPart
+
+/**
+ * A message in a realtime conversation
+ */
+export interface RealtimeMessage {
+ /** Unique message identifier */
+ id: string
+ /** Message role */
+ role: 'user' | 'assistant'
+ /** Timestamp when the message was created */
+ timestamp: number
+ /** Content parts of the message */
+ parts: Array
+ /** Whether this message was interrupted */
+ interrupted?: boolean
+ /** Reference to audio buffer if stored */
+ audioId?: string
+ /** Duration of the audio in milliseconds */
+ durationMs?: number
+}
+
+// ============================================================================
+// Status Types
+// ============================================================================
+
+/**
+ * Connection status of the realtime client
+ */
+export type RealtimeStatus =
+ | 'idle'
+ | 'connecting'
+ | 'connected'
+ | 'reconnecting'
+ | 'error'
+
+/**
+ * Current mode of the realtime session
+ */
+export type RealtimeMode = 'idle' | 'listening' | 'thinking' | 'speaking'
+
+// ============================================================================
+// Audio Visualization Types
+// ============================================================================
+
+/**
+ * Interface for accessing audio visualization data
+ */
+export interface AudioVisualization {
+ /** Input volume level (0-1 normalized) */
+ readonly inputLevel: number
+ /** Output volume level (0-1 normalized) */
+ readonly outputLevel: number
+
+ /** Get frequency data for input audio visualization */
+ getInputFrequencyData(): Uint8Array
+ /** Get frequency data for output audio visualization */
+ getOutputFrequencyData(): Uint8Array
+
+ /** Get time domain data for input waveform */
+ getInputTimeDomainData(): Uint8Array
+ /** Get time domain data for output waveform */
+ getOutputTimeDomainData(): Uint8Array
+
+ /** Input sample rate */
+ readonly inputSampleRate: number
+ /** Output sample rate */
+ readonly outputSampleRate: number
+
+ /** Subscribe to raw input audio samples */
+ onInputAudio?(
+ callback: (samples: Float32Array, sampleRate: number) => void,
+ ): () => void
+ /** Subscribe to raw output audio samples */
+ onOutputAudio?(
+ callback: (samples: Float32Array, sampleRate: number) => void,
+ ): () => void
+}
+
+// ============================================================================
+// Event Types
+// ============================================================================
+
+/**
+ * Events emitted by the realtime connection
+ */
+export type RealtimeEvent =
+ | 'status_change'
+ | 'mode_change'
+ | 'transcript'
+ | 'audio_chunk'
+ | 'tool_call'
+ | 'message_complete'
+ | 'interrupted'
+ | 'error'
+
+/**
+ * Event payloads for realtime events
+ */
+export interface RealtimeEventPayloads {
+ status_change: { status: RealtimeStatus }
+ mode_change: { mode: RealtimeMode }
+ transcript: {
+ role: 'user' | 'assistant'
+ transcript: string
+ isFinal: boolean
+ }
+ audio_chunk: { data: ArrayBuffer; sampleRate: number }
+ tool_call: { toolCallId: string; toolName: string; input: unknown }
+ message_complete: { message: RealtimeMessage }
+ interrupted: { messageId?: string }
+ error: { error: Error }
+}
+
+/**
+ * Handler type for realtime events
+ */
+export type RealtimeEventHandler = (
+ payload: RealtimeEventPayloads[E],
+) => void
+
+// ============================================================================
+// Error Types
+// ============================================================================
+
+/**
+ * Error codes for realtime errors
+ */
+export type RealtimeErrorCode =
+ | 'TOKEN_EXPIRED'
+ | 'CONNECTION_FAILED'
+ | 'PERMISSION_DENIED'
+ | 'PROVIDER_ERROR'
+ | 'UNKNOWN'
+
+/**
+ * Extended error with realtime-specific information
+ */
+export interface RealtimeError extends Error {
+ code: RealtimeErrorCode
+ provider?: string
+ details?: unknown
+}
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index e6c1ee2188..f53f865f57 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -28,7 +28,7 @@ importers:
version: 0.3.1(typescript@5.9.3)
'@tanstack/vite-config':
specifier: 0.4.1
- version: 0.4.1(@types/node@24.10.3)(rollup@4.57.1)(typescript@5.9.3)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+ version: 0.4.1(@types/node@24.10.3)(rollup@4.55.1)(typescript@5.9.3)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
'@types/node':
specifier: ^24.10.1
version: 24.10.3
@@ -111,23 +111,23 @@ importers:
specifier: workspace:*
version: link:../../packages/typescript/ai-react
'@tanstack/react-devtools':
- specifier: ^0.9.10
- version: 0.9.10(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(csstype@3.2.3)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(solid-js@1.9.10)
+ specifier: ^0.8.2
+ version: 0.8.4(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(csstype@3.2.3)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(solid-js@1.9.10)
'@tanstack/react-router':
- specifier: ^1.158.4
- version: 1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
+ specifier: ^1.141.1
+ version: 1.141.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
'@tanstack/react-router-devtools':
- specifier: ^1.158.4
- version: 1.159.5(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(@tanstack/router-core@1.159.4)(csstype@3.2.3)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
+ specifier: ^1.139.7
+ version: 1.141.1(@tanstack/react-router@1.141.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(@tanstack/router-core@1.141.1)(csstype@3.2.3)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(solid-js@1.9.10)
'@tanstack/react-router-ssr-query':
- specifier: ^1.158.4
- version: 1.159.5(@tanstack/query-core@5.90.12)(@tanstack/react-query@5.90.12(react@19.2.3))(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(@tanstack/router-core@1.159.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
+ specifier: ^1.139.7
+ version: 1.141.1(@tanstack/query-core@5.90.12)(@tanstack/react-query@5.90.12(react@19.2.3))(@tanstack/react-router@1.141.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(@tanstack/router-core@1.141.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
'@tanstack/react-start':
- specifier: ^1.159.0
- version: 1.159.5(crossws@0.4.4(srvx@0.11.2))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+ specifier: ^1.141.1
+ version: 1.141.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
'@tanstack/router-plugin':
- specifier: ^1.158.4
- version: 1.159.5(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+ specifier: ^1.139.7
+ version: 1.141.1(@tanstack/react-router@1.141.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
capnweb:
specifier: ^0.1.0
version: 0.1.0
@@ -148,8 +148,8 @@ importers:
version: 8.18.3
devDependencies:
'@tanstack/devtools-vite':
- specifier: ^0.5.3
- version: 0.5.3(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+ specifier: ^0.3.11
+ version: 0.3.12(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
'@testing-library/dom':
specifier: ^10.4.1
version: 10.4.1
@@ -201,15 +201,15 @@ importers:
'@tanstack/ai-client':
specifier: workspace:*
version: link:../../packages/typescript/ai-client
+ '@tanstack/ai-elevenlabs':
+ specifier: workspace:*
+ version: link:../../packages/typescript/ai-elevenlabs
'@tanstack/ai-gemini':
specifier: workspace:*
version: link:../../packages/typescript/ai-gemini
'@tanstack/ai-grok':
specifier: workspace:*
version: link:../../packages/typescript/ai-grok
- '@tanstack/ai-groq':
- specifier: workspace:*
- version: link:../../packages/typescript/ai-groq
'@tanstack/ai-ollama':
specifier: workspace:*
version: link:../../packages/typescript/ai-ollama
@@ -226,29 +226,29 @@ importers:
specifier: workspace:*
version: link:../../packages/typescript/ai-react-ui
'@tanstack/nitro-v2-vite-plugin':
- specifier: ^1.154.7
- version: 1.154.7(rolldown@1.0.0-beta.53)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+ specifier: ^1.141.0
+ version: 1.141.0(rolldown@1.0.0-beta.53)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
'@tanstack/react-devtools':
- specifier: ^0.9.10
- version: 0.9.10(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(csstype@3.2.3)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(solid-js@1.9.10)
+ specifier: ^0.8.2
+ version: 0.8.4(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(csstype@3.2.3)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(solid-js@1.9.10)
'@tanstack/react-router':
- specifier: ^1.158.4
- version: 1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
+ specifier: ^1.141.1
+ version: 1.141.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
'@tanstack/react-router-devtools':
- specifier: ^1.158.4
- version: 1.159.5(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(@tanstack/router-core@1.159.4)(csstype@3.2.3)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
+ specifier: ^1.139.7
+ version: 1.141.1(@tanstack/react-router@1.141.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(@tanstack/router-core@1.141.1)(csstype@3.2.3)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(solid-js@1.9.10)
'@tanstack/react-router-ssr-query':
- specifier: ^1.158.4
- version: 1.159.5(@tanstack/query-core@5.90.12)(@tanstack/react-query@5.90.12(react@19.2.3))(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(@tanstack/router-core@1.159.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
+ specifier: ^1.139.7
+ version: 1.141.1(@tanstack/query-core@5.90.12)(@tanstack/react-query@5.90.12(react@19.2.3))(@tanstack/react-router@1.141.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(@tanstack/router-core@1.141.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
'@tanstack/react-start':
- specifier: ^1.159.0
- version: 1.159.5(crossws@0.4.4(srvx@0.11.2))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+ specifier: ^1.141.1
+ version: 1.141.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
'@tanstack/react-store':
specifier: ^0.8.0
version: 0.8.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
'@tanstack/router-plugin':
- specifier: ^1.158.4
- version: 1.159.5(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+ specifier: ^1.139.7
+ version: 1.141.1(@tanstack/react-router@1.141.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
'@tanstack/store':
specifier: ^0.8.0
version: 0.8.0
@@ -290,8 +290,8 @@ importers:
version: 4.2.1
devDependencies:
'@tanstack/devtools-vite':
- specifier: ^0.5.3
- version: 0.5.3(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+ specifier: ^0.3.11
+ version: 0.3.12(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
'@tanstack/react-ai-devtools':
specifier: workspace:*
version: link:../../packages/typescript/react-ai-devtools
@@ -329,67 +329,6 @@ importers:
specifier: ^5.1.0
version: 5.1.0
- examples/ts-react-media:
- dependencies:
- '@tailwindcss/vite':
- specifier: ^4.1.18
- version: 4.1.18(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
- '@tanstack/ai':
- specifier: workspace:*
- version: link:../../packages/typescript/ai
- '@tanstack/ai-fal':
- specifier: workspace:*
- version: link:../../packages/typescript/ai-fal
- '@tanstack/ai-gemini':
- specifier: workspace:*
- version: link:../../packages/typescript/ai-gemini
- '@tanstack/react-router':
- specifier: ^1.158.4
- version: 1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
- '@tanstack/react-start':
- specifier: ^1.159.0
- version: 1.159.5(crossws@0.4.4(srvx@0.10.1))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
- '@tanstack/router-plugin':
- specifier: ^1.158.4
- version: 1.159.5(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
- lucide-react:
- specifier: ^0.561.0
- version: 0.561.0(react@19.2.3)
- nitro:
- specifier: 3.0.1-alpha.2
- version: 3.0.1-alpha.2(chokidar@5.0.0)(ioredis@5.9.2)(lru-cache@11.2.4)(rolldown@1.0.0-beta.53)(rollup@4.57.1)(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
- react:
- specifier: ^19.2.3
- version: 19.2.3
- react-dom:
- specifier: ^19.2.3
- version: 19.2.3(react@19.2.3)
- tailwindcss:
- specifier: ^4.1.18
- version: 4.1.18
- vite-tsconfig-paths:
- specifier: ^5.1.4
- version: 5.1.4(typescript@5.9.3)(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
- devDependencies:
- '@types/node':
- specifier: ^24.10.1
- version: 24.10.3
- '@types/react':
- specifier: ^19.2.7
- version: 19.2.7
- '@types/react-dom':
- specifier: ^19.2.3
- version: 19.2.3(@types/react@19.2.7)
- '@vitejs/plugin-react':
- specifier: ^5.1.2
- version: 5.1.2(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
- typescript:
- specifier: 5.9.3
- version: 5.9.3
- vite:
- specifier: ^7.2.7
- version: 7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
-
examples/ts-solid-chat:
dependencies:
'@tailwindcss/vite':
@@ -423,11 +362,11 @@ importers:
specifier: workspace:*
version: link:../../packages/typescript/ai-solid-ui
'@tanstack/nitro-v2-vite-plugin':
- specifier: ^1.154.7
- version: 1.154.7(rolldown@1.0.0-beta.53)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+ specifier: ^1.141.0
+ version: 1.141.0(rolldown@1.0.0-beta.53)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
'@tanstack/router-plugin':
- specifier: ^1.158.4
- version: 1.159.5(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+ specifier: ^1.139.7
+ version: 1.141.1(@tanstack/react-router@1.141.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
'@tanstack/solid-ai-devtools':
specifier: workspace:*
version: link:../../packages/typescript/solid-ai-devtools
@@ -439,13 +378,13 @@ importers:
version: 1.141.1(solid-js@1.9.10)
'@tanstack/solid-router-devtools':
specifier: ^1.139.10
- version: 1.141.1(@tanstack/router-core@1.159.4)(@tanstack/solid-router@1.141.1(solid-js@1.9.10))(csstype@3.2.3)(solid-js@1.9.10)
+ version: 1.141.1(@tanstack/router-core@1.141.1)(@tanstack/solid-router@1.141.1(solid-js@1.9.10))(csstype@3.2.3)(solid-js@1.9.10)
'@tanstack/solid-router-ssr-query':
specifier: ^1.139.10
- version: 1.141.1(@tanstack/query-core@5.90.12)(@tanstack/router-core@1.159.4)(@tanstack/solid-query@5.90.15(solid-js@1.9.10))(@tanstack/solid-router@1.141.1(solid-js@1.9.10))(eslint@9.39.2(jiti@2.6.1))(solid-js@1.9.10)(typescript@5.9.3)
+ version: 1.141.1(@tanstack/query-core@5.90.12)(@tanstack/router-core@1.141.1)(@tanstack/solid-query@5.90.15(solid-js@1.9.10))(@tanstack/solid-router@1.141.1(solid-js@1.9.10))(eslint@9.39.2(jiti@2.6.1))(solid-js@1.9.10)(typescript@5.9.3)
'@tanstack/solid-start':
specifier: ^1.139.10
- version: 1.141.1(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(crossws@0.4.4(srvx@0.11.2))(solid-js@1.9.10)(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+ version: 1.141.1(@tanstack/react-router@1.141.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(solid-js@1.9.10)(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
'@tanstack/solid-store':
specifier: ^0.8.0
version: 0.8.0(solid-js@1.9.10)
@@ -481,8 +420,8 @@ importers:
specifier: ^0.4.0
version: 0.4.0
'@tanstack/devtools-vite':
- specifier: ^0.5.3
- version: 0.5.3(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+ specifier: ^0.3.11
+ version: 0.3.12(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
'@testing-library/dom':
specifier: ^10.4.1
version: 10.4.1
@@ -681,7 +620,7 @@ importers:
version: 1.1.0
'@vitest/coverage-v8':
specifier: 4.0.14
- version: 4.0.14(vitest@4.0.18(@types/node@25.0.1)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+ version: 4.0.14(vitest@4.0.17(@types/node@25.0.1)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
zod:
specifier: ^4.2.0
version: 4.2.1
@@ -689,7 +628,7 @@ importers:
packages/typescript/ai-anthropic:
dependencies:
'@anthropic-ai/sdk':
- specifier: ^0.71.2
+ specifier: ^0.71.0
version: 0.71.2(zod@4.2.1)
devDependencies:
'@tanstack/ai':
@@ -697,7 +636,7 @@ importers:
version: link:../ai
'@vitest/coverage-v8':
specifier: 4.0.14
- version: 4.0.14(vitest@4.0.18(@types/node@25.0.1)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+ version: 4.0.14(vitest@4.0.17(@types/node@25.0.1)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
zod:
specifier: ^4.2.0
version: 4.2.1
@@ -710,7 +649,7 @@ importers:
devDependencies:
'@vitest/coverage-v8':
specifier: 4.0.14
- version: 4.0.14(vitest@4.0.18(@types/node@25.0.1)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+ version: 4.0.14(vitest@4.0.17(@types/node@25.0.1)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
vite:
specifier: ^7.2.7
version: 7.2.7(@types/node@25.0.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
@@ -724,11 +663,11 @@ importers:
specifier: workspace:*
version: link:../ai
'@tanstack/devtools-ui':
- specifier: ^0.5.0
- version: 0.5.0(csstype@3.2.3)(solid-js@1.9.10)
+ specifier: ^0.4.4
+ version: 0.4.4(csstype@3.2.3)(solid-js@1.9.10)
'@tanstack/devtools-utils':
- specifier: 0.3.2
- version: 0.3.2(@types/react@19.2.7)(csstype@3.2.3)(preact@10.28.2)(react@19.2.3)(solid-js@1.9.10)(vue@3.5.25(typescript@5.9.3))
+ specifier: ^0.3.0
+ version: 0.3.0(@types/react@19.2.7)(csstype@3.2.3)(preact@10.28.2)(react@19.2.3)(solid-js@1.9.10)(vue@3.5.25(typescript@5.9.3))
goober:
specifier: ^2.1.18
version: 2.1.18(csstype@3.2.3)
@@ -738,16 +677,10 @@ importers:
devDependencies:
'@vitest/coverage-v8':
specifier: 4.0.14
- version: 4.0.14(vitest@4.0.18(@types/node@25.0.1)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+ version: 4.0.14(vitest@4.0.17(@types/node@25.0.1)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
jsdom:
specifier: ^27.2.0
version: 27.3.0(postcss@8.5.6)
- tsup:
- specifier: ^8.5.1
- version: 8.5.1(@microsoft/api-extractor@7.47.7(@types/node@25.0.1))(jiti@2.6.1)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.2)
- tsup-preset-solid:
- specifier: ^2.2.0
- version: 2.2.0(esbuild@0.27.3)(solid-js@1.9.10)(tsup@8.5.1(@microsoft/api-extractor@7.47.7(@types/node@25.0.1))(jiti@2.6.1)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.2))
vite:
specifier: ^7.2.7
version: 7.2.7(@types/node@25.0.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
@@ -755,34 +688,34 @@ importers:
specifier: ^2.11.10
version: 2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@25.0.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
- packages/typescript/ai-fal:
+ packages/typescript/ai-elevenlabs:
dependencies:
- '@fal-ai/client':
- specifier: ^1.9.1
- version: 1.9.1
+ '@11labs/client':
+ specifier: ^0.2.0
+ version: 0.2.0(@types/dom-mediacapture-record@1.0.22)
devDependencies:
'@tanstack/ai':
specifier: workspace:*
version: link:../ai
+ '@tanstack/ai-client':
+ specifier: workspace:*
+ version: link:../ai-client
'@vitest/coverage-v8':
specifier: 4.0.14
- version: 4.0.14(vitest@4.0.18(@types/node@25.0.1)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
- vite:
- specifier: ^7.2.7
- version: 7.3.1(@types/node@25.0.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
+ version: 4.0.14(vitest@4.0.17(@types/node@25.0.1)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
packages/typescript/ai-gemini:
dependencies:
'@google/genai':
- specifier: ^1.43.0
- version: 1.43.0
+ specifier: ^1.30.0
+ version: 1.33.0
devDependencies:
'@tanstack/ai':
specifier: workspace:*
version: link:../ai
'@vitest/coverage-v8':
specifier: 4.0.14
- version: 4.0.14(vitest@4.0.18(@types/node@25.0.1)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+ version: 4.0.14(vitest@4.0.17(@types/node@25.0.1)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
vite:
specifier: ^7.2.7
version: 7.2.7(@types/node@25.0.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
@@ -801,30 +734,11 @@ importers:
devDependencies:
'@vitest/coverage-v8':
specifier: 4.0.14
- version: 4.0.14(vitest@4.0.18(@types/node@25.0.1)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+ version: 4.0.14(vitest@4.0.17(@types/node@25.0.1)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
vite:
specifier: ^7.2.7
version: 7.2.7(@types/node@25.0.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
- packages/typescript/ai-groq:
- dependencies:
- '@tanstack/ai':
- specifier: workspace:^
- version: link:../ai
- groq-sdk:
- specifier: ^0.37.0
- version: 0.37.0
- zod:
- specifier: ^4.0.0
- version: 4.3.6
- devDependencies:
- '@vitest/coverage-v8':
- specifier: 4.0.14
- version: 4.0.14(vitest@4.0.18(@types/node@25.0.1)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
- vite:
- specifier: ^7.2.7
- version: 7.3.1(@types/node@25.0.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
-
packages/typescript/ai-ollama:
dependencies:
ollama:
@@ -836,7 +750,7 @@ importers:
version: link:../ai
'@vitest/coverage-v8':
specifier: 4.0.14
- version: 4.0.14(vitest@4.0.18(@types/node@25.0.1)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+ version: 4.0.14(vitest@4.0.17(@types/node@25.0.1)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
vite:
specifier: ^7.2.7
version: 7.2.7(@types/node@25.0.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
@@ -850,9 +764,12 @@ importers:
'@tanstack/ai':
specifier: workspace:*
version: link:../ai
+ '@tanstack/ai-client':
+ specifier: workspace:*
+ version: link:../ai-client
'@vitest/coverage-v8':
specifier: 4.0.14
- version: 4.0.14(vitest@4.0.18(@types/node@25.0.1)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+ version: 4.0.14(vitest@4.0.17(@types/node@25.0.1)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
vite:
specifier: ^7.2.7
version: 7.2.7(@types/node@25.0.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
@@ -871,7 +788,7 @@ importers:
devDependencies:
'@vitest/coverage-v8':
specifier: 4.0.14
- version: 4.0.14(vitest@4.0.18(@types/node@25.0.1)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+ version: 4.0.14(vitest@4.0.17(@types/node@25.0.1)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
vite:
specifier: ^7.2.7
version: 7.2.7(@types/node@25.0.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
@@ -890,7 +807,7 @@ importers:
version: 3.2.4(preact@10.28.2)
'@vitest/coverage-v8':
specifier: 4.0.14
- version: 4.0.14(vitest@4.0.18(@types/node@25.0.1)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+ version: 4.0.14(vitest@4.0.17(@types/node@25.0.1)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
jsdom:
specifier: ^27.2.0
version: 27.3.0(postcss@8.5.6)
@@ -918,7 +835,7 @@ importers:
version: 19.2.7
'@vitest/coverage-v8':
specifier: 4.0.14
- version: 4.0.14(vitest@4.0.18(@types/node@25.0.1)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+ version: 4.0.14(vitest@4.0.17(@types/node@25.0.1)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
jsdom:
specifier: ^27.2.0
version: 27.3.0(postcss@8.5.6)
@@ -958,7 +875,7 @@ importers:
version: 19.2.7
'@vitest/coverage-v8':
specifier: 4.0.14
- version: 4.0.14(vitest@4.0.18(@types/node@25.0.1)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+ version: 4.0.14(vitest@4.0.17(@types/node@25.0.1)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
react:
specifier: ^19.2.3
version: 19.2.3
@@ -1029,7 +946,7 @@ importers:
version: link:../ai-solid
'@vitest/coverage-v8':
specifier: 4.0.14
- version: 4.0.14(vitest@4.0.18(@types/node@25.0.1)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+ version: 4.0.14(vitest@4.0.17(@types/node@25.0.1)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
solid-js:
specifier: ^1.9.10
version: 1.9.10
@@ -1057,7 +974,7 @@ importers:
version: 24.10.3
'@vitest/coverage-v8':
specifier: 4.0.14
- version: 4.0.14(vitest@4.0.18(@types/node@24.10.3)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+ version: 4.0.14(vitest@4.0.17(@types/node@24.10.3)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
jsdom:
specifier: ^27.2.0
version: 27.3.0(postcss@8.5.6)
@@ -1134,7 +1051,7 @@ importers:
version: 6.0.3(vite@7.2.7(@types/node@25.0.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(vue@3.5.25(typescript@5.9.3))
'@vitest/coverage-v8':
specifier: 4.0.14
- version: 4.0.14(vitest@4.0.18(@types/node@25.0.1)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+ version: 4.0.14(vitest@4.0.17(@types/node@25.0.1)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
vite:
specifier: ^7.2.7
version: 7.2.7(@types/node@25.0.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
@@ -1151,15 +1068,15 @@ importers:
specifier: workspace:*
version: link:../ai-devtools
'@tanstack/devtools-utils':
- specifier: 0.3.2
- version: 0.3.2(@types/react@19.2.7)(preact@10.28.1)(react@19.2.3)(solid-js@1.9.10)(vue@3.5.25(typescript@5.9.3))
+ specifier: ^0.3.0
+ version: 0.3.0(@types/react@19.2.7)(preact@10.28.1)(react@19.2.3)(solid-js@1.9.10)(vue@3.5.25(typescript@5.9.3))
preact:
specifier: ^10.0.0
version: 10.28.1
devDependencies:
'@vitest/coverage-v8':
specifier: 4.0.14
- version: 4.0.14(vitest@4.0.18(@types/node@25.0.1)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+ version: 4.0.14(vitest@4.0.17(@types/node@25.0.1)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
vite:
specifier: ^7.2.7
version: 7.2.7(@types/node@25.0.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
@@ -1170,15 +1087,15 @@ importers:
specifier: workspace:*
version: link:../ai-devtools
'@tanstack/devtools-utils':
- specifier: 0.3.2
- version: 0.3.2(@types/react@19.2.7)(csstype@3.2.3)(preact@10.28.2)(react@19.2.3)(solid-js@1.9.10)(vue@3.5.25(typescript@5.9.3))
+ specifier: ^0.3.0
+ version: 0.3.0(@types/react@19.2.7)(csstype@3.2.3)(preact@10.28.2)(react@19.2.3)(solid-js@1.9.10)(vue@3.5.25(typescript@5.9.3))
devDependencies:
'@types/react':
specifier: ^19.2.7
version: 19.2.7
'@vitest/coverage-v8':
specifier: 4.0.14
- version: 4.0.14(vitest@4.0.18(@types/node@25.0.1)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+ version: 4.0.14(vitest@4.0.17(@types/node@25.0.1)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
react:
specifier: ^19.2.3
version: 19.2.3
@@ -1230,9 +1147,6 @@ importers:
typescript:
specifier: 5.9.3
version: 5.9.3
- vitest:
- specifier: ^4.0.14
- version: 4.0.18(@types/node@24.10.3)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
zod:
specifier: ^4.2.0
version: 4.2.1
@@ -1255,20 +1169,17 @@ importers:
specifier: workspace:*
version: link:../../ai-react
'@tanstack/nitro-v2-vite-plugin':
- specifier: ^1.154.7
- version: 1.154.7(rolldown@1.0.0-beta.53)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+ specifier: ^1.141.0
+ version: 1.141.0(rolldown@1.0.0-beta.53)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
'@tanstack/react-router':
- specifier: ^1.158.4
- version: 1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
+ specifier: ^1.141.1
+ version: 1.141.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
'@tanstack/react-start':
- specifier: ^1.159.0
- version: 1.159.5(crossws@0.4.4(srvx@0.11.2))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+ specifier: ^1.141.1
+ version: 1.141.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
'@tanstack/router-plugin':
- specifier: ^1.158.4
- version: 1.159.5(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
- '@tanstack/tests-adapters':
- specifier: workspace:*
- version: link:../adapters
+ specifier: ^1.139.7
+ version: 1.141.1(@tanstack/react-router@1.141.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
react:
specifier: ^19.2.3
version: 19.2.3
@@ -1278,9 +1189,9 @@ importers:
tailwindcss:
specifier: ^4.1.18
version: 4.1.18
- zod:
- specifier: ^4.2.0
- version: 4.2.1
+ vite-tsconfig-paths:
+ specifier: ^5.1.4
+ version: 5.1.4(typescript@5.9.3)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
devDependencies:
'@playwright/test':
specifier: ^1.57.0
@@ -1303,9 +1214,6 @@ importers:
vite:
specifier: ^7.2.7
version: 7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
- vite-tsconfig-paths:
- specifier: ^5.1.4
- version: 5.1.4(typescript@5.9.3)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
packages/typescript/solid-ai-devtools:
dependencies:
@@ -1313,12 +1221,12 @@ importers:
specifier: workspace:*
version: link:../ai-devtools
'@tanstack/devtools-utils':
- specifier: 0.3.2
- version: 0.3.2(@types/react@19.2.7)(csstype@3.2.3)(preact@10.28.2)(react@19.2.3)(solid-js@1.9.10)(vue@3.5.25(typescript@5.9.3))
+ specifier: ^0.3.0
+ version: 0.3.0(@types/react@19.2.7)(csstype@3.2.3)(preact@10.28.2)(react@19.2.3)(solid-js@1.9.10)(vue@3.5.25(typescript@5.9.3))
devDependencies:
'@vitest/coverage-v8':
specifier: 4.0.14
- version: 4.0.14(vitest@4.0.18(@types/node@25.0.1)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+ version: 4.0.14(vitest@4.0.17(@types/node@25.0.1)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
solid-js:
specifier: ^1.9.10
version: 1.9.10
@@ -1355,9 +1263,6 @@ importers:
'@tanstack/ai-openai':
specifier: workspace:*
version: link:../../packages/typescript/ai-openai
- '@tanstack/ai-openrouter':
- specifier: workspace:*
- version: link:../../packages/typescript/ai-openrouter
'@tanstack/ai-react':
specifier: workspace:*
version: link:../../packages/typescript/ai-react
@@ -1365,17 +1270,17 @@ importers:
specifier: workspace:*
version: link:../../packages/typescript/ai-react-ui
'@tanstack/nitro-v2-vite-plugin':
- specifier: ^1.154.7
- version: 1.154.7(rolldown@1.0.0-beta.53)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+ specifier: ^1.141.0
+ version: 1.141.0(rolldown@1.0.0-beta.53)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
'@tanstack/react-router':
- specifier: ^1.158.4
- version: 1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
+ specifier: ^1.141.1
+ version: 1.141.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
'@tanstack/react-start':
- specifier: ^1.159.0
- version: 1.159.5(crossws@0.4.4(srvx@0.11.2))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+ specifier: ^1.141.1
+ version: 1.141.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
'@tanstack/start':
specifier: ^1.120.20
- version: 1.120.20(@types/node@24.10.3)(crossws@0.4.4(srvx@0.11.2))(db0@0.3.4)(ioredis@5.8.2)(jiti@2.6.1)(lightningcss@1.30.2)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(rolldown@1.0.0-beta.53)(terser@5.44.1)(tsx@4.21.0)(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(yaml@2.8.2)
+ version: 1.120.20(@types/node@24.10.3)(db0@0.3.4)(ioredis@5.8.2)(jiti@2.6.1)(lightningcss@1.30.2)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(rolldown@1.0.0-beta.53)(terser@5.44.1)(tsx@4.21.0)(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(yaml@2.8.2)
highlight.js:
specifier: ^11.11.1
version: 11.11.1
@@ -1413,9 +1318,6 @@ importers:
specifier: ^4.2.0
version: 4.2.1
devDependencies:
- '@playwright/test':
- specifier: ^1.57.0
- version: 1.57.0
'@types/node':
specifier: ^24.10.1
version: 24.10.3
@@ -1428,9 +1330,6 @@ importers:
'@vitejs/plugin-react':
specifier: ^5.1.2
version: 5.1.2(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
- dotenv:
- specifier: ^17.2.3
- version: 17.2.3
typescript:
specifier: 5.9.3
version: 5.9.3
@@ -1440,6 +1339,10 @@ importers:
packages:
+ '@11labs/client@0.2.0':
+ resolution: {integrity: sha512-GBplAV4WDbcoThsIzdSDPN3xbcitK0ZZ4iJfJZKfltqvgvS6Uw8GZxHwVgiPwnQoA3uosYyY3L9TuPwmel18xQ==}
+ deprecated: This package is no longer maintained. Please use @elevenlabs/client for the latest version
+
'@acemir/cssom@0.9.29':
resolution: {integrity: sha512-G90x0VW+9nW4dFajtjCoT+NM0scAfH9Mb08IcjgFHYbfiL/lU04dTF9JuVOi3/OH+DJCQdcIseSXkdCB9Ky6JA==}
@@ -1561,11 +1464,6 @@ packages:
engines: {node: '>=6.0.0'}
hasBin: true
- '@babel/parser@7.29.0':
- resolution: {integrity: sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==}
- engines: {node: '>=6.0.0'}
- hasBin: true
-
'@babel/plugin-syntax-jsx@7.27.1':
resolution: {integrity: sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w==}
engines: {node: '>=6.9.0'}
@@ -1624,14 +1522,13 @@ packages:
resolution: {integrity: sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==}
engines: {node: '>=6.9.0'}
- '@babel/types@7.29.0':
- resolution: {integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==}
- engines: {node: '>=6.9.0'}
-
'@bcoe/v8-coverage@1.0.2':
resolution: {integrity: sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==}
engines: {node: '>=18'}
+ '@bufbuild/protobuf@1.10.1':
+ resolution: {integrity: sha512-wJ8ReQbHxsAfXhrf9ixl0aYbZorRuOWpBNzm8pL8ftmSxQx/wnJD5Eg861NwJU/czy2VXFIebCeZnZrI9rktIQ==}
+
'@changesets/apply-release-plan@7.0.14':
resolution: {integrity: sha512-ddBvf9PHdy2YY0OUiEl3TV78mH9sckndJR14QAt87KLEbIov81XO0q0QAmvooBxXlqRRP8I9B7XOzZwQG7JkWA==}
@@ -1694,10 +1591,6 @@ packages:
resolution: {integrity: sha512-Nu8ahitGFFJztxUml9oD/DLb7Z28C8cd8F46IVQ7y5Btz575pvMY8AqZsXkX7Gds29eCKdMgIHjIvzskHgPSFg==}
engines: {node: '>=18.0.0'}
- '@cloudflare/kv-asset-handler@0.4.2':
- resolution: {integrity: sha512-SIOD2DxrRRwQ+jgzlXCqoEFiKOFqaPjhnNTGKXSRLvp1HiOvapLaFG2kEr9dYQTYe8rKrd9uvDUzmAITeNyaHQ==}
- engines: {node: '>=18.0.0'}
-
'@crazydos/vue-markdown@1.1.4':
resolution: {integrity: sha512-0I1QMP59LJ3aEjE7bolgvPU4JAFt+pykdDo5674CbsCwFo7OVFos50+MPhGdWflCz1mac5t152lB1qvV/tR/rw==}
engines: {node: '>=20.0.0'}
@@ -1765,14 +1658,14 @@ packages:
cpu: [ppc64]
os: [aix]
- '@esbuild/aix-ppc64@0.27.2':
- resolution: {integrity: sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw==}
+ '@esbuild/aix-ppc64@0.27.1':
+ resolution: {integrity: sha512-HHB50pdsBX6k47S4u5g/CaLjqS3qwaOVE5ILsq64jyzgMhLuCuZ8rGzM9yhsAjfjkbgUPMzZEPa7DAp7yz6vuA==}
engines: {node: '>=18'}
cpu: [ppc64]
os: [aix]
- '@esbuild/aix-ppc64@0.27.3':
- resolution: {integrity: sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==}
+ '@esbuild/aix-ppc64@0.27.2':
+ resolution: {integrity: sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw==}
engines: {node: '>=18'}
cpu: [ppc64]
os: [aix]
@@ -1789,14 +1682,14 @@ packages:
cpu: [arm64]
os: [android]
- '@esbuild/android-arm64@0.27.2':
- resolution: {integrity: sha512-pvz8ZZ7ot/RBphf8fv60ljmaoydPU12VuXHImtAs0XhLLw+EXBi2BLe3OYSBslR4rryHvweW5gmkKFwTiFy6KA==}
+ '@esbuild/android-arm64@0.27.1':
+ resolution: {integrity: sha512-45fuKmAJpxnQWixOGCrS+ro4Uvb4Re9+UTieUY2f8AEc+t7d4AaZ6eUJ3Hva7dtrxAAWHtlEFsXFMAgNnGU9uQ==}
engines: {node: '>=18'}
cpu: [arm64]
os: [android]
- '@esbuild/android-arm64@0.27.3':
- resolution: {integrity: sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==}
+ '@esbuild/android-arm64@0.27.2':
+ resolution: {integrity: sha512-pvz8ZZ7ot/RBphf8fv60ljmaoydPU12VuXHImtAs0XhLLw+EXBi2BLe3OYSBslR4rryHvweW5gmkKFwTiFy6KA==}
engines: {node: '>=18'}
cpu: [arm64]
os: [android]
@@ -1813,14 +1706,14 @@ packages:
cpu: [arm]
os: [android]
- '@esbuild/android-arm@0.27.2':
- resolution: {integrity: sha512-DVNI8jlPa7Ujbr1yjU2PfUSRtAUZPG9I1RwW4F4xFB1Imiu2on0ADiI/c3td+KmDtVKNbi+nffGDQMfcIMkwIA==}
+ '@esbuild/android-arm@0.27.1':
+ resolution: {integrity: sha512-kFqa6/UcaTbGm/NncN9kzVOODjhZW8e+FRdSeypWe6j33gzclHtwlANs26JrupOntlcWmB0u8+8HZo8s7thHvg==}
engines: {node: '>=18'}
cpu: [arm]
os: [android]
- '@esbuild/android-arm@0.27.3':
- resolution: {integrity: sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==}
+ '@esbuild/android-arm@0.27.2':
+ resolution: {integrity: sha512-DVNI8jlPa7Ujbr1yjU2PfUSRtAUZPG9I1RwW4F4xFB1Imiu2on0ADiI/c3td+KmDtVKNbi+nffGDQMfcIMkwIA==}
engines: {node: '>=18'}
cpu: [arm]
os: [android]
@@ -1837,14 +1730,14 @@ packages:
cpu: [x64]
os: [android]
- '@esbuild/android-x64@0.27.2':
- resolution: {integrity: sha512-z8Ank4Byh4TJJOh4wpz8g2vDy75zFL0TlZlkUkEwYXuPSgX8yzep596n6mT7905kA9uHZsf/o2OJZubl2l3M7A==}
+ '@esbuild/android-x64@0.27.1':
+ resolution: {integrity: sha512-LBEpOz0BsgMEeHgenf5aqmn/lLNTFXVfoWMUox8CtWWYK9X4jmQzWjoGoNb8lmAYml/tQ/Ysvm8q7szu7BoxRQ==}
engines: {node: '>=18'}
cpu: [x64]
os: [android]
- '@esbuild/android-x64@0.27.3':
- resolution: {integrity: sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==}
+ '@esbuild/android-x64@0.27.2':
+ resolution: {integrity: sha512-z8Ank4Byh4TJJOh4wpz8g2vDy75zFL0TlZlkUkEwYXuPSgX8yzep596n6mT7905kA9uHZsf/o2OJZubl2l3M7A==}
engines: {node: '>=18'}
cpu: [x64]
os: [android]
@@ -1861,14 +1754,14 @@ packages:
cpu: [arm64]
os: [darwin]
- '@esbuild/darwin-arm64@0.27.2':
- resolution: {integrity: sha512-davCD2Zc80nzDVRwXTcQP/28fiJbcOwvdolL0sOiOsbwBa72kegmVU0Wrh1MYrbuCL98Omp5dVhQFWRKR2ZAlg==}
+ '@esbuild/darwin-arm64@0.27.1':
+ resolution: {integrity: sha512-veg7fL8eMSCVKL7IW4pxb54QERtedFDfY/ASrumK/SbFsXnRazxY4YykN/THYqFnFwJ0aVjiUrVG2PwcdAEqQQ==}
engines: {node: '>=18'}
cpu: [arm64]
os: [darwin]
- '@esbuild/darwin-arm64@0.27.3':
- resolution: {integrity: sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==}
+ '@esbuild/darwin-arm64@0.27.2':
+ resolution: {integrity: sha512-davCD2Zc80nzDVRwXTcQP/28fiJbcOwvdolL0sOiOsbwBa72kegmVU0Wrh1MYrbuCL98Omp5dVhQFWRKR2ZAlg==}
engines: {node: '>=18'}
cpu: [arm64]
os: [darwin]
@@ -1885,14 +1778,14 @@ packages:
cpu: [x64]
os: [darwin]
- '@esbuild/darwin-x64@0.27.2':
- resolution: {integrity: sha512-ZxtijOmlQCBWGwbVmwOF/UCzuGIbUkqB1faQRf5akQmxRJ1ujusWsb3CVfk/9iZKr2L5SMU5wPBi1UWbvL+VQA==}
+ '@esbuild/darwin-x64@0.27.1':
+ resolution: {integrity: sha512-+3ELd+nTzhfWb07Vol7EZ+5PTbJ/u74nC6iv4/lwIU99Ip5uuY6QoIf0Hn4m2HoV0qcnRivN3KSqc+FyCHjoVQ==}
engines: {node: '>=18'}
cpu: [x64]
os: [darwin]
- '@esbuild/darwin-x64@0.27.3':
- resolution: {integrity: sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==}
+ '@esbuild/darwin-x64@0.27.2':
+ resolution: {integrity: sha512-ZxtijOmlQCBWGwbVmwOF/UCzuGIbUkqB1faQRf5akQmxRJ1ujusWsb3CVfk/9iZKr2L5SMU5wPBi1UWbvL+VQA==}
engines: {node: '>=18'}
cpu: [x64]
os: [darwin]
@@ -1909,14 +1802,14 @@ packages:
cpu: [arm64]
os: [freebsd]
- '@esbuild/freebsd-arm64@0.27.2':
- resolution: {integrity: sha512-lS/9CN+rgqQ9czogxlMcBMGd+l8Q3Nj1MFQwBZJyoEKI50XGxwuzznYdwcav6lpOGv5BqaZXqvBSiB/kJ5op+g==}
+ '@esbuild/freebsd-arm64@0.27.1':
+ resolution: {integrity: sha512-/8Rfgns4XD9XOSXlzUDepG8PX+AVWHliYlUkFI3K3GB6tqbdjYqdhcb4BKRd7C0BhZSoaCxhv8kTcBrcZWP+xg==}
engines: {node: '>=18'}
cpu: [arm64]
os: [freebsd]
- '@esbuild/freebsd-arm64@0.27.3':
- resolution: {integrity: sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==}
+ '@esbuild/freebsd-arm64@0.27.2':
+ resolution: {integrity: sha512-lS/9CN+rgqQ9czogxlMcBMGd+l8Q3Nj1MFQwBZJyoEKI50XGxwuzznYdwcav6lpOGv5BqaZXqvBSiB/kJ5op+g==}
engines: {node: '>=18'}
cpu: [arm64]
os: [freebsd]
@@ -1933,14 +1826,14 @@ packages:
cpu: [x64]
os: [freebsd]
- '@esbuild/freebsd-x64@0.27.2':
- resolution: {integrity: sha512-tAfqtNYb4YgPnJlEFu4c212HYjQWSO/w/h/lQaBK7RbwGIkBOuNKQI9tqWzx7Wtp7bTPaGC6MJvWI608P3wXYA==}
+ '@esbuild/freebsd-x64@0.27.1':
+ resolution: {integrity: sha512-GITpD8dK9C+r+5yRT/UKVT36h/DQLOHdwGVwwoHidlnA168oD3uxA878XloXebK4Ul3gDBBIvEdL7go9gCUFzQ==}
engines: {node: '>=18'}
cpu: [x64]
os: [freebsd]
- '@esbuild/freebsd-x64@0.27.3':
- resolution: {integrity: sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==}
+ '@esbuild/freebsd-x64@0.27.2':
+ resolution: {integrity: sha512-tAfqtNYb4YgPnJlEFu4c212HYjQWSO/w/h/lQaBK7RbwGIkBOuNKQI9tqWzx7Wtp7bTPaGC6MJvWI608P3wXYA==}
engines: {node: '>=18'}
cpu: [x64]
os: [freebsd]
@@ -1957,14 +1850,14 @@ packages:
cpu: [arm64]
os: [linux]
- '@esbuild/linux-arm64@0.27.2':
- resolution: {integrity: sha512-hYxN8pr66NsCCiRFkHUAsxylNOcAQaxSSkHMMjcpx0si13t1LHFphxJZUiGwojB1a/Hd5OiPIqDdXONia6bhTw==}
+ '@esbuild/linux-arm64@0.27.1':
+ resolution: {integrity: sha512-W9//kCrh/6in9rWIBdKaMtuTTzNj6jSeG/haWBADqLLa9P8O5YSRDzgD5y9QBok4AYlzS6ARHifAb75V6G670Q==}
engines: {node: '>=18'}
cpu: [arm64]
os: [linux]
- '@esbuild/linux-arm64@0.27.3':
- resolution: {integrity: sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==}
+ '@esbuild/linux-arm64@0.27.2':
+ resolution: {integrity: sha512-hYxN8pr66NsCCiRFkHUAsxylNOcAQaxSSkHMMjcpx0si13t1LHFphxJZUiGwojB1a/Hd5OiPIqDdXONia6bhTw==}
engines: {node: '>=18'}
cpu: [arm64]
os: [linux]
@@ -1981,14 +1874,14 @@ packages:
cpu: [arm]
os: [linux]
- '@esbuild/linux-arm@0.27.2':
- resolution: {integrity: sha512-vWfq4GaIMP9AIe4yj1ZUW18RDhx6EPQKjwe7n8BbIecFtCQG4CfHGaHuh7fdfq+y3LIA2vGS/o9ZBGVxIDi9hw==}
+ '@esbuild/linux-arm@0.27.1':
+ resolution: {integrity: sha512-ieMID0JRZY/ZeCrsFQ3Y3NlHNCqIhTprJfDgSB3/lv5jJZ8FX3hqPyXWhe+gvS5ARMBJ242PM+VNz/ctNj//eA==}
engines: {node: '>=18'}
cpu: [arm]
os: [linux]
- '@esbuild/linux-arm@0.27.3':
- resolution: {integrity: sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==}
+ '@esbuild/linux-arm@0.27.2':
+ resolution: {integrity: sha512-vWfq4GaIMP9AIe4yj1ZUW18RDhx6EPQKjwe7n8BbIecFtCQG4CfHGaHuh7fdfq+y3LIA2vGS/o9ZBGVxIDi9hw==}
engines: {node: '>=18'}
cpu: [arm]
os: [linux]
@@ -2005,14 +1898,14 @@ packages:
cpu: [ia32]
os: [linux]
- '@esbuild/linux-ia32@0.27.2':
- resolution: {integrity: sha512-MJt5BRRSScPDwG2hLelYhAAKh9imjHK5+NE/tvnRLbIqUWa+0E9N4WNMjmp/kXXPHZGqPLxggwVhz7QP8CTR8w==}
+ '@esbuild/linux-ia32@0.27.1':
+ resolution: {integrity: sha512-VIUV4z8GD8rtSVMfAj1aXFahsi/+tcoXXNYmXgzISL+KB381vbSTNdeZHHHIYqFyXcoEhu9n5cT+05tRv13rlw==}
engines: {node: '>=18'}
cpu: [ia32]
os: [linux]
- '@esbuild/linux-ia32@0.27.3':
- resolution: {integrity: sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==}
+ '@esbuild/linux-ia32@0.27.2':
+ resolution: {integrity: sha512-MJt5BRRSScPDwG2hLelYhAAKh9imjHK5+NE/tvnRLbIqUWa+0E9N4WNMjmp/kXXPHZGqPLxggwVhz7QP8CTR8w==}
engines: {node: '>=18'}
cpu: [ia32]
os: [linux]
@@ -2029,14 +1922,14 @@ packages:
cpu: [loong64]
os: [linux]
- '@esbuild/linux-loong64@0.27.2':
- resolution: {integrity: sha512-lugyF1atnAT463aO6KPshVCJK5NgRnU4yb3FUumyVz+cGvZbontBgzeGFO1nF+dPueHD367a2ZXe1NtUkAjOtg==}
+ '@esbuild/linux-loong64@0.27.1':
+ resolution: {integrity: sha512-l4rfiiJRN7sTNI//ff65zJ9z8U+k6zcCg0LALU5iEWzY+a1mVZ8iWC1k5EsNKThZ7XCQ6YWtsZ8EWYm7r1UEsg==}
engines: {node: '>=18'}
cpu: [loong64]
os: [linux]
- '@esbuild/linux-loong64@0.27.3':
- resolution: {integrity: sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==}
+ '@esbuild/linux-loong64@0.27.2':
+ resolution: {integrity: sha512-lugyF1atnAT463aO6KPshVCJK5NgRnU4yb3FUumyVz+cGvZbontBgzeGFO1nF+dPueHD367a2ZXe1NtUkAjOtg==}
engines: {node: '>=18'}
cpu: [loong64]
os: [linux]
@@ -2053,14 +1946,14 @@ packages:
cpu: [mips64el]
os: [linux]
- '@esbuild/linux-mips64el@0.27.2':
- resolution: {integrity: sha512-nlP2I6ArEBewvJ2gjrrkESEZkB5mIoaTswuqNFRv/WYd+ATtUpe9Y09RnJvgvdag7he0OWgEZWhviS1OTOKixw==}
+ '@esbuild/linux-mips64el@0.27.1':
+ resolution: {integrity: sha512-U0bEuAOLvO/DWFdygTHWY8C067FXz+UbzKgxYhXC0fDieFa0kDIra1FAhsAARRJbvEyso8aAqvPdNxzWuStBnA==}
engines: {node: '>=18'}
cpu: [mips64el]
os: [linux]
- '@esbuild/linux-mips64el@0.27.3':
- resolution: {integrity: sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==}
+ '@esbuild/linux-mips64el@0.27.2':
+ resolution: {integrity: sha512-nlP2I6ArEBewvJ2gjrrkESEZkB5mIoaTswuqNFRv/WYd+ATtUpe9Y09RnJvgvdag7he0OWgEZWhviS1OTOKixw==}
engines: {node: '>=18'}
cpu: [mips64el]
os: [linux]
@@ -2077,14 +1970,14 @@ packages:
cpu: [ppc64]
os: [linux]
- '@esbuild/linux-ppc64@0.27.2':
- resolution: {integrity: sha512-C92gnpey7tUQONqg1n6dKVbx3vphKtTHJaNG2Ok9lGwbZil6DrfyecMsp9CrmXGQJmZ7iiVXvvZH6Ml5hL6XdQ==}
+ '@esbuild/linux-ppc64@0.27.1':
+ resolution: {integrity: sha512-NzdQ/Xwu6vPSf/GkdmRNsOfIeSGnh7muundsWItmBsVpMoNPVpM61qNzAVY3pZ1glzzAxLR40UyYM23eaDDbYQ==}
engines: {node: '>=18'}
cpu: [ppc64]
os: [linux]
- '@esbuild/linux-ppc64@0.27.3':
- resolution: {integrity: sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==}
+ '@esbuild/linux-ppc64@0.27.2':
+ resolution: {integrity: sha512-C92gnpey7tUQONqg1n6dKVbx3vphKtTHJaNG2Ok9lGwbZil6DrfyecMsp9CrmXGQJmZ7iiVXvvZH6Ml5hL6XdQ==}
engines: {node: '>=18'}
cpu: [ppc64]
os: [linux]
@@ -2101,14 +1994,14 @@ packages:
cpu: [riscv64]
os: [linux]
- '@esbuild/linux-riscv64@0.27.2':
- resolution: {integrity: sha512-B5BOmojNtUyN8AXlK0QJyvjEZkWwy/FKvakkTDCziX95AowLZKR6aCDhG7LeF7uMCXEJqwa8Bejz5LTPYm8AvA==}
+ '@esbuild/linux-riscv64@0.27.1':
+ resolution: {integrity: sha512-7zlw8p3IApcsN7mFw0O1Z1PyEk6PlKMu18roImfl3iQHTnr/yAfYv6s4hXPidbDoI2Q0pW+5xeoM4eTCC0UdrQ==}
engines: {node: '>=18'}
cpu: [riscv64]
os: [linux]
- '@esbuild/linux-riscv64@0.27.3':
- resolution: {integrity: sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==}
+ '@esbuild/linux-riscv64@0.27.2':
+ resolution: {integrity: sha512-B5BOmojNtUyN8AXlK0QJyvjEZkWwy/FKvakkTDCziX95AowLZKR6aCDhG7LeF7uMCXEJqwa8Bejz5LTPYm8AvA==}
engines: {node: '>=18'}
cpu: [riscv64]
os: [linux]
@@ -2125,14 +2018,14 @@ packages:
cpu: [s390x]
os: [linux]
- '@esbuild/linux-s390x@0.27.2':
- resolution: {integrity: sha512-p4bm9+wsPwup5Z8f4EpfN63qNagQ47Ua2znaqGH6bqLlmJ4bx97Y9JdqxgGZ6Y8xVTixUnEkoKSHcpRlDnNr5w==}
+ '@esbuild/linux-s390x@0.27.1':
+ resolution: {integrity: sha512-cGj5wli+G+nkVQdZo3+7FDKC25Uh4ZVwOAK6A06Hsvgr8WqBBuOy/1s+PUEd/6Je+vjfm6stX0kmib5b/O2Ykw==}
engines: {node: '>=18'}
cpu: [s390x]
os: [linux]
- '@esbuild/linux-s390x@0.27.3':
- resolution: {integrity: sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==}
+ '@esbuild/linux-s390x@0.27.2':
+ resolution: {integrity: sha512-p4bm9+wsPwup5Z8f4EpfN63qNagQ47Ua2znaqGH6bqLlmJ4bx97Y9JdqxgGZ6Y8xVTixUnEkoKSHcpRlDnNr5w==}
engines: {node: '>=18'}
cpu: [s390x]
os: [linux]
@@ -2149,14 +2042,14 @@ packages:
cpu: [x64]
os: [linux]
- '@esbuild/linux-x64@0.27.2':
- resolution: {integrity: sha512-uwp2Tip5aPmH+NRUwTcfLb+W32WXjpFejTIOWZFw/v7/KnpCDKG66u4DLcurQpiYTiYwQ9B7KOeMJvLCu/OvbA==}
+ '@esbuild/linux-x64@0.27.1':
+ resolution: {integrity: sha512-z3H/HYI9MM0HTv3hQZ81f+AKb+yEoCRlUby1F80vbQ5XdzEMyY/9iNlAmhqiBKw4MJXwfgsh7ERGEOhrM1niMA==}
engines: {node: '>=18'}
cpu: [x64]
os: [linux]
- '@esbuild/linux-x64@0.27.3':
- resolution: {integrity: sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==}
+ '@esbuild/linux-x64@0.27.2':
+ resolution: {integrity: sha512-uwp2Tip5aPmH+NRUwTcfLb+W32WXjpFejTIOWZFw/v7/KnpCDKG66u4DLcurQpiYTiYwQ9B7KOeMJvLCu/OvbA==}
engines: {node: '>=18'}
cpu: [x64]
os: [linux]
@@ -2167,14 +2060,14 @@ packages:
cpu: [arm64]
os: [netbsd]
- '@esbuild/netbsd-arm64@0.27.2':
- resolution: {integrity: sha512-Kj6DiBlwXrPsCRDeRvGAUb/LNrBASrfqAIok+xB0LxK8CHqxZ037viF13ugfsIpePH93mX7xfJp97cyDuTZ3cw==}
+ '@esbuild/netbsd-arm64@0.27.1':
+ resolution: {integrity: sha512-wzC24DxAvk8Em01YmVXyjl96Mr+ecTPyOuADAvjGg+fyBpGmxmcr2E5ttf7Im8D0sXZihpxzO1isus8MdjMCXQ==}
engines: {node: '>=18'}
cpu: [arm64]
os: [netbsd]
- '@esbuild/netbsd-arm64@0.27.3':
- resolution: {integrity: sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==}
+ '@esbuild/netbsd-arm64@0.27.2':
+ resolution: {integrity: sha512-Kj6DiBlwXrPsCRDeRvGAUb/LNrBASrfqAIok+xB0LxK8CHqxZ037viF13ugfsIpePH93mX7xfJp97cyDuTZ3cw==}
engines: {node: '>=18'}
cpu: [arm64]
os: [netbsd]
@@ -2191,14 +2084,14 @@ packages:
cpu: [x64]
os: [netbsd]
- '@esbuild/netbsd-x64@0.27.2':
- resolution: {integrity: sha512-HwGDZ0VLVBY3Y+Nw0JexZy9o/nUAWq9MlV7cahpaXKW6TOzfVno3y3/M8Ga8u8Yr7GldLOov27xiCnqRZf0tCA==}
+ '@esbuild/netbsd-x64@0.27.1':
+ resolution: {integrity: sha512-1YQ8ybGi2yIXswu6eNzJsrYIGFpnlzEWRl6iR5gMgmsrR0FcNoV1m9k9sc3PuP5rUBLshOZylc9nqSgymI+TYg==}
engines: {node: '>=18'}
cpu: [x64]
os: [netbsd]
- '@esbuild/netbsd-x64@0.27.3':
- resolution: {integrity: sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==}
+ '@esbuild/netbsd-x64@0.27.2':
+ resolution: {integrity: sha512-HwGDZ0VLVBY3Y+Nw0JexZy9o/nUAWq9MlV7cahpaXKW6TOzfVno3y3/M8Ga8u8Yr7GldLOov27xiCnqRZf0tCA==}
engines: {node: '>=18'}
cpu: [x64]
os: [netbsd]
@@ -2209,14 +2102,14 @@ packages:
cpu: [arm64]
os: [openbsd]
- '@esbuild/openbsd-arm64@0.27.2':
- resolution: {integrity: sha512-DNIHH2BPQ5551A7oSHD0CKbwIA/Ox7+78/AWkbS5QoRzaqlev2uFayfSxq68EkonB+IKjiuxBFoV8ESJy8bOHA==}
+ '@esbuild/openbsd-arm64@0.27.1':
+ resolution: {integrity: sha512-5Z+DzLCrq5wmU7RDaMDe2DVXMRm2tTDvX2KU14JJVBN2CT/qov7XVix85QoJqHltpvAOZUAc3ndU56HSMWrv8g==}
engines: {node: '>=18'}
cpu: [arm64]
os: [openbsd]
- '@esbuild/openbsd-arm64@0.27.3':
- resolution: {integrity: sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==}
+ '@esbuild/openbsd-arm64@0.27.2':
+ resolution: {integrity: sha512-DNIHH2BPQ5551A7oSHD0CKbwIA/Ox7+78/AWkbS5QoRzaqlev2uFayfSxq68EkonB+IKjiuxBFoV8ESJy8bOHA==}
engines: {node: '>=18'}
cpu: [arm64]
os: [openbsd]
@@ -2233,14 +2126,14 @@ packages:
cpu: [x64]
os: [openbsd]
- '@esbuild/openbsd-x64@0.27.2':
- resolution: {integrity: sha512-/it7w9Nb7+0KFIzjalNJVR5bOzA9Vay+yIPLVHfIQYG/j+j9VTH84aNB8ExGKPU4AzfaEvN9/V4HV+F+vo8OEg==}
+ '@esbuild/openbsd-x64@0.27.1':
+ resolution: {integrity: sha512-Q73ENzIdPF5jap4wqLtsfh8YbYSZ8Q0wnxplOlZUOyZy7B4ZKW8DXGWgTCZmF8VWD7Tciwv5F4NsRf6vYlZtqg==}
engines: {node: '>=18'}
cpu: [x64]
os: [openbsd]
- '@esbuild/openbsd-x64@0.27.3':
- resolution: {integrity: sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==}
+ '@esbuild/openbsd-x64@0.27.2':
+ resolution: {integrity: sha512-/it7w9Nb7+0KFIzjalNJVR5bOzA9Vay+yIPLVHfIQYG/j+j9VTH84aNB8ExGKPU4AzfaEvN9/V4HV+F+vo8OEg==}
engines: {node: '>=18'}
cpu: [x64]
os: [openbsd]
@@ -2251,14 +2144,14 @@ packages:
cpu: [arm64]
os: [openharmony]
- '@esbuild/openharmony-arm64@0.27.2':
- resolution: {integrity: sha512-LRBbCmiU51IXfeXk59csuX/aSaToeG7w48nMwA6049Y4J4+VbWALAuXcs+qcD04rHDuSCSRKdmY63sruDS5qag==}
+ '@esbuild/openharmony-arm64@0.27.1':
+ resolution: {integrity: sha512-ajbHrGM/XiK+sXM0JzEbJAen+0E+JMQZ2l4RR4VFwvV9JEERx+oxtgkpoKv1SevhjavK2z2ReHk32pjzktWbGg==}
engines: {node: '>=18'}
cpu: [arm64]
os: [openharmony]
- '@esbuild/openharmony-arm64@0.27.3':
- resolution: {integrity: sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==}
+ '@esbuild/openharmony-arm64@0.27.2':
+ resolution: {integrity: sha512-LRBbCmiU51IXfeXk59csuX/aSaToeG7w48nMwA6049Y4J4+VbWALAuXcs+qcD04rHDuSCSRKdmY63sruDS5qag==}
engines: {node: '>=18'}
cpu: [arm64]
os: [openharmony]
@@ -2275,14 +2168,14 @@ packages:
cpu: [x64]
os: [sunos]
- '@esbuild/sunos-x64@0.27.2':
- resolution: {integrity: sha512-kMtx1yqJHTmqaqHPAzKCAkDaKsffmXkPHThSfRwZGyuqyIeBvf08KSsYXl+abf5HDAPMJIPnbBfXvP2ZC2TfHg==}
+ '@esbuild/sunos-x64@0.27.1':
+ resolution: {integrity: sha512-IPUW+y4VIjuDVn+OMzHc5FV4GubIwPnsz6ubkvN8cuhEqH81NovB53IUlrlBkPMEPxvNnf79MGBoz8rZ2iW8HA==}
engines: {node: '>=18'}
cpu: [x64]
os: [sunos]
- '@esbuild/sunos-x64@0.27.3':
- resolution: {integrity: sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==}
+ '@esbuild/sunos-x64@0.27.2':
+ resolution: {integrity: sha512-kMtx1yqJHTmqaqHPAzKCAkDaKsffmXkPHThSfRwZGyuqyIeBvf08KSsYXl+abf5HDAPMJIPnbBfXvP2ZC2TfHg==}
engines: {node: '>=18'}
cpu: [x64]
os: [sunos]
@@ -2299,14 +2192,14 @@ packages:
cpu: [arm64]
os: [win32]
- '@esbuild/win32-arm64@0.27.2':
- resolution: {integrity: sha512-Yaf78O/B3Kkh+nKABUF++bvJv5Ijoy9AN1ww904rOXZFLWVc5OLOfL56W+C8F9xn5JQZa3UX6m+IktJnIb1Jjg==}
+ '@esbuild/win32-arm64@0.27.1':
+ resolution: {integrity: sha512-RIVRWiljWA6CdVu8zkWcRmGP7iRRIIwvhDKem8UMBjPql2TXM5PkDVvvrzMtj1V+WFPB4K7zkIGM7VzRtFkjdg==}
engines: {node: '>=18'}
cpu: [arm64]
os: [win32]
- '@esbuild/win32-arm64@0.27.3':
- resolution: {integrity: sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==}
+ '@esbuild/win32-arm64@0.27.2':
+ resolution: {integrity: sha512-Yaf78O/B3Kkh+nKABUF++bvJv5Ijoy9AN1ww904rOXZFLWVc5OLOfL56W+C8F9xn5JQZa3UX6m+IktJnIb1Jjg==}
engines: {node: '>=18'}
cpu: [arm64]
os: [win32]
@@ -2323,14 +2216,14 @@ packages:
cpu: [ia32]
os: [win32]
- '@esbuild/win32-ia32@0.27.2':
- resolution: {integrity: sha512-Iuws0kxo4yusk7sw70Xa2E2imZU5HoixzxfGCdxwBdhiDgt9vX9VUCBhqcwY7/uh//78A1hMkkROMJq9l27oLQ==}
+ '@esbuild/win32-ia32@0.27.1':
+ resolution: {integrity: sha512-2BR5M8CPbptC1AK5JbJT1fWrHLvejwZidKx3UMSF0ecHMa+smhi16drIrCEggkgviBwLYd5nwrFLSl5Kho96RQ==}
engines: {node: '>=18'}
cpu: [ia32]
os: [win32]
- '@esbuild/win32-ia32@0.27.3':
- resolution: {integrity: sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==}
+ '@esbuild/win32-ia32@0.27.2':
+ resolution: {integrity: sha512-Iuws0kxo4yusk7sw70Xa2E2imZU5HoixzxfGCdxwBdhiDgt9vX9VUCBhqcwY7/uh//78A1hMkkROMJq9l27oLQ==}
engines: {node: '>=18'}
cpu: [ia32]
os: [win32]
@@ -2347,14 +2240,14 @@ packages:
cpu: [x64]
os: [win32]
- '@esbuild/win32-x64@0.27.2':
- resolution: {integrity: sha512-sRdU18mcKf7F+YgheI/zGf5alZatMUTKj/jNS6l744f9u3WFu4v7twcUI9vu4mknF4Y9aDlblIie0IM+5xxaqQ==}
+ '@esbuild/win32-x64@0.27.1':
+ resolution: {integrity: sha512-d5X6RMYv6taIymSk8JBP+nxv8DQAMY6A51GPgusqLdK9wBz5wWIXy1KjTck6HnjE9hqJzJRdk+1p/t5soSbCtw==}
engines: {node: '>=18'}
cpu: [x64]
os: [win32]
- '@esbuild/win32-x64@0.27.3':
- resolution: {integrity: sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==}
+ '@esbuild/win32-x64@0.27.2':
+ resolution: {integrity: sha512-sRdU18mcKf7F+YgheI/zGf5alZatMUTKj/jNS6l744f9u3WFu4v7twcUI9vu4mknF4Y9aDlblIie0IM+5xxaqQ==}
engines: {node: '>=18'}
cpu: [x64]
os: [win32]
@@ -2411,18 +2304,14 @@ packages:
resolution: {integrity: sha512-C3mrr3b5dRVlKPJdfrAXS8+dq+rq8Qm5SNRazca0JKgw1HQERFmrVb0towvMmw5uu8hHKNiQasMaR/tydf3Zsg==}
engines: {node: ^20.19.0 || ^22.13.0 || ^23.5.0 || >=24.0.0, npm: '>=10'}
- '@fal-ai/client@1.9.1':
- resolution: {integrity: sha512-Z6+n9/2sKlDam1wWDfRWmMkLS09e2WhTU9w+2eWL7PuoGmHK43IhwKirk4b3kPC/QPp1g+ymfvhrSiS1SpDr6g==}
- engines: {node: '>=18.0.0'}
-
'@gerrit0/mini-shiki@3.19.0':
resolution: {integrity: sha512-ZSlWfLvr8Nl0T4iA3FF/8VH8HivYF82xQts2DY0tJxZd4wtXJ8AA0nmdW9lmO4hlrh3f9xNwEPtOgqETPqKwDA==}
- '@google/genai@1.43.0':
- resolution: {integrity: sha512-hklCsJNdMlDM1IwcCVcGQFBg2izY0+t5BIGbRsxi2UnKi6AGKL7pqJqmBDNRbw0bYCs4y3NA7TB+fkKfP/Nrdw==}
+ '@google/genai@1.33.0':
+ resolution: {integrity: sha512-ThUjFZ1N0DU88peFjnQkb8K198EWaW2RmmnDShFQ+O+xkIH9itjpRe358x3L/b4X/A7dimkvq63oz49Vbh7Cog==}
engines: {node: '>=20.0.0'}
peerDependencies:
- '@modelcontextprotocol/sdk': ^1.25.2
+ '@modelcontextprotocol/sdk': ^1.24.0
peerDependenciesMeta:
'@modelcontextprotocol/sdk':
optional: true
@@ -2455,9 +2344,6 @@ packages:
'@ioredis/commands@1.4.0':
resolution: {integrity: sha512-aFT2yemJJo+TZCmieA7qnYGQooOS7QfNmYrzGtsYd3g9j5iDP8AimYYAesf79ohjbLG12XxC4nG5DyEnC88AsQ==}
- '@ioredis/commands@1.5.0':
- resolution: {integrity: sha512-eUgLqrMf8nJkZxT24JvVRrQya1vZkQh8BBeYNwGDqa5I0VUi8ACx7uFvAaLxintokpTenkK6DASvo/bvNbBGow==}
-
'@isaacs/balanced-match@4.0.1':
resolution: {integrity: sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==}
engines: {node: 20 || >=22}
@@ -2505,6 +2391,12 @@ packages:
'@jridgewell/trace-mapping@0.3.31':
resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==}
+ '@livekit/mutex@1.1.1':
+ resolution: {integrity: sha512-EsshAucklmpuUAfkABPxJNhzj9v2sG7JuzFDL4ML1oJQSV14sqrpTYnsaOudMAw9yOaW53NU3QQTlUQoRs4czw==}
+
+ '@livekit/protocol@1.42.2':
+ resolution: {integrity: sha512-0jeCwoMJKcwsZICg5S6RZM4xhJoF78qMvQELjACJQn6/VB+jmiySQKOSELTXvPBVafHfEbMlqxUw2UR1jTXs2g==}
+
'@manypkg/find-root@1.1.0':
resolution: {integrity: sha512-mki5uBvhHzO8kYYix/WRy2WX8S3B5wdVSc9D6KcU5lQNglP2yt58/VfLuAK49glRXChosY8ap2oJ1qgma3GUVA==}
@@ -2529,10 +2421,6 @@ packages:
'@microsoft/tsdoc@0.15.1':
resolution: {integrity: sha512-4aErSrCR/On/e5G2hDP0wjooqDdauzEbIq8hIkIe5pXV0rtWJZvdCEKL0ykZxex+IxIwBp0eGeV48hQN07dXtw==}
- '@msgpack/msgpack@3.1.3':
- resolution: {integrity: sha512-47XIizs9XZXvuJgoaJUIE2lFoID8ugvc0jzSHP+Ptfk8nTbnR8g788wv48N03Kx0UkAv559HWRQ3yzOgzlRNUA==}
- engines: {node: '>= 18'}
-
'@napi-rs/wasm-runtime@0.2.12':
resolution: {integrity: sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==}
@@ -2542,9 +2430,6 @@ packages:
'@napi-rs/wasm-runtime@1.1.0':
resolution: {integrity: sha512-Fq6DJW+Bb5jaWE69/qOE0D1TUN9+6uWhCeZpdnSBk14pjLcCWR7Q8n49PTSPHazM37JqrsdpEthXy2xn6jWWiA==}
- '@napi-rs/wasm-runtime@1.1.1':
- resolution: {integrity: sha512-p64ah1M1ld8xjWv3qbvFwHiFVWrq1yFvV4f7w+mzaqiR4IlSgkqhcRdHwsGgomwzBH51sRY4NEowLxnaBjcW/A==}
-
'@nodelib/fs.scandir@2.1.5':
resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
engines: {node: '>= 8'}
@@ -2648,195 +2533,76 @@ packages:
'@openrouter/sdk@0.3.15':
resolution: {integrity: sha512-tmiMQGu6L1fHD9NpIABN9LALEZitqM27CFebSVyJTQDcxCcR3m1F6v1O1MnOlLmedCFU+/BojniRGFAXo1F3Bw==}
- '@oxc-minify/binding-android-arm-eabi@0.110.0':
- resolution: {integrity: sha512-43fMTO8/5bMlqfOiNSZNKUzIqeLIYuB9Hr1Ohyf58B1wU11S2dPGibTXOGNaWsfgHy99eeZ1bSgeIHy/fEYqbw==}
- engines: {node: ^20.19.0 || >=22.12.0}
+ '@oxc-project/types@0.101.0':
+ resolution: {integrity: sha512-nuFhqlUzJX+gVIPPfuE6xurd4lST3mdcWOhyK/rZO0B9XWMKm79SuszIQEnSMmmDhq1DC8WWVYGVd+6F93o1gQ==}
+
+ '@oxc-resolver/binding-android-arm-eabi@11.15.0':
+ resolution: {integrity: sha512-Q+lWuFfq7whNelNJIP1dhXaVz4zO9Tu77GcQHyxDWh3MaCoO2Bisphgzmsh4ZoUe2zIchQh6OvQL99GlWHg9Tw==}
cpu: [arm]
os: [android]
- '@oxc-minify/binding-android-arm64@0.110.0':
- resolution: {integrity: sha512-5oQrnn9eK/ccOp80PTrNj0Vq893NPNNRryjGpOIVsYNgWFuoGCfpnKg68oEFcN8bArizYAqw4nvgHljEnar69w==}
- engines: {node: ^20.19.0 || >=22.12.0}
+ '@oxc-resolver/binding-android-arm64@11.15.0':
+ resolution: {integrity: sha512-vbdBttesHR0W1oJaxgWVTboyMUuu+VnPsHXJ6jrXf4czELzB6GIg5DrmlyhAmFBhjwov+yJH/DfTnHS+2sDgOw==}
cpu: [arm64]
os: [android]
- '@oxc-minify/binding-darwin-arm64@0.110.0':
- resolution: {integrity: sha512-dqBDgTG9tF2z2lrZp9E8wU+Godz1i8gCGSei2eFKS2hRploBOD5dmOLp1j4IMornkPvSQmbwB3uSjPq7fjx4EA==}
- engines: {node: ^20.19.0 || >=22.12.0}
+ '@oxc-resolver/binding-darwin-arm64@11.15.0':
+ resolution: {integrity: sha512-R67lsOe1UzNjqVBCwCZX1rlItTsj/cVtBw4Uy19CvTicqEWvwaTn8t34zLD75LQwDDPCY3C8n7NbD+LIdw+ZoA==}
cpu: [arm64]
os: [darwin]
- '@oxc-minify/binding-darwin-x64@0.110.0':
- resolution: {integrity: sha512-U0AqabqaooDOpYmeeOye8wClv8PSScELXgOfYqyqgrwH9J9KrpCE1jL8Rlqgz68QbL4mPw3V6sKiiHssI4CLeQ==}
- engines: {node: ^20.19.0 || >=22.12.0}
+ '@oxc-resolver/binding-darwin-x64@11.15.0':
+ resolution: {integrity: sha512-77mya5F8WV0EtCxI0MlVZcqkYlaQpfNwl/tZlfg4jRsoLpFbaTeWv75hFm6TE84WULVlJtSgvf7DhoWBxp9+ZQ==}
cpu: [x64]
os: [darwin]
- '@oxc-minify/binding-freebsd-x64@0.110.0':
- resolution: {integrity: sha512-H0w8o/Wo1072WSdLfhwwrpFpwZnPpjQODlHuRYkTfsSSSJbTxQtjJd4uxk7YJsRv5RQp69y0I7zvdH6f8Xueyw==}
- engines: {node: ^20.19.0 || >=22.12.0}
+ '@oxc-resolver/binding-freebsd-x64@11.15.0':
+ resolution: {integrity: sha512-X1Sz7m5PC+6D3KWIDXMUtux+0Imj6HfHGdBStSvgdI60OravzI1t83eyn6eN0LPTrynuPrUgjk7tOnOsBzSWHw==}
cpu: [x64]
os: [freebsd]
- '@oxc-minify/binding-linux-arm-gnueabihf@0.110.0':
- resolution: {integrity: sha512-qd6sW0AvEVYZhbVVMGtmKZw3b1zDYGIW+54Uh42moWRAj6i4Jhk/LGr6r9YNZpOINeuvZfkFuEeDD/jbu7xPUA==}
- engines: {node: ^20.19.0 || >=22.12.0}
+ '@oxc-resolver/binding-linux-arm-gnueabihf@11.15.0':
+ resolution: {integrity: sha512-L1x/wCaIRre+18I4cH/lTqSAymlV0k4HqfSYNNuI9oeL28Ks86lI6O5VfYL6sxxWYgjuWB98gNGo7tq7d4GarQ==}
cpu: [arm]
os: [linux]
- '@oxc-minify/binding-linux-arm-musleabihf@0.110.0':
- resolution: {integrity: sha512-7WXP0aXMrWSn0ScppUBi3jf68ebfBG0eri8kxLmBOVSBj6jw1repzkHMITJMBeLr5d0tT/51qFEptiAk2EP2iA==}
- engines: {node: ^20.19.0 || >=22.12.0}
+ '@oxc-resolver/binding-linux-arm-musleabihf@11.15.0':
+ resolution: {integrity: sha512-abGXd/zMGa0tH8nKlAXdOnRy4G7jZmkU0J85kMKWns161bxIgGn/j7zxqh3DKEW98wAzzU9GofZMJ0P5YCVPVw==}
cpu: [arm]
os: [linux]
- '@oxc-minify/binding-linux-arm64-gnu@0.110.0':
- resolution: {integrity: sha512-LYfADrq5x1W5gs+u9OIbMbDQNYkAECTXX0ufnAuf3oGmO51rF98kGFR5qJqC/6/csokDyT3wwTpxhE0TkcF/Og==}
- engines: {node: ^20.19.0 || >=22.12.0}
+ '@oxc-resolver/binding-linux-arm64-gnu@11.15.0':
+ resolution: {integrity: sha512-SVjjjtMW66Mza76PBGJLqB0KKyFTBnxmtDXLJPbL6ZPGSctcXVmujz7/WAc0rb9m2oV0cHQTtVjnq6orQnI/jg==}
cpu: [arm64]
os: [linux]
- '@oxc-minify/binding-linux-arm64-musl@0.110.0':
- resolution: {integrity: sha512-53GjCVY8kvymk9P6qNDh6zyblcehF5QHstq9QgCjv13ONGRnSHjeds0PxIwiihD7h295bxsWs84DN39syLPH4Q==}
- engines: {node: ^20.19.0 || >=22.12.0}
+ '@oxc-resolver/binding-linux-arm64-musl@11.15.0':
+ resolution: {integrity: sha512-JDv2/AycPF2qgzEiDeMJCcSzKNDm3KxNg0KKWipoKEMDFqfM7LxNwwSVyAOGmrYlE4l3dg290hOMsr9xG7jv9g==}
cpu: [arm64]
os: [linux]
- '@oxc-minify/binding-linux-ppc64-gnu@0.110.0':
- resolution: {integrity: sha512-li8XcN81dxbJDMBESnTgGhoiAQ+CNIdM0QGscZ4duVPjCry1RpX+5FJySFbGqG3pk4s9ZzlL/vtQtbRzZIZOzg==}
- engines: {node: ^20.19.0 || >=22.12.0}
+ '@oxc-resolver/binding-linux-ppc64-gnu@11.15.0':
+ resolution: {integrity: sha512-zbu9FhvBLW4KJxo7ElFvZWbSt4vP685Qc/Gyk/Ns3g2gR9qh2qWXouH8PWySy+Ko/qJ42+HJCLg+ZNcxikERfg==}
cpu: [ppc64]
os: [linux]
- '@oxc-minify/binding-linux-riscv64-gnu@0.110.0':
- resolution: {integrity: sha512-SweKfsnLKShu6UFV8mwuj1d1wmlNoL/FlAxPUzwjEBgwiT2HQkY24KnjBH+TIA+//1O83kzmWKvvs4OuEhdIEQ==}
- engines: {node: ^20.19.0 || >=22.12.0}
+ '@oxc-resolver/binding-linux-riscv64-gnu@11.15.0':
+ resolution: {integrity: sha512-Kfleehe6B09C2qCnyIU01xLFqFXCHI4ylzkicfX/89j+gNHh9xyNdpEvit88Kq6i5tTGdavVnM6DQfOE2qNtlg==}
cpu: [riscv64]
os: [linux]
- '@oxc-minify/binding-linux-riscv64-musl@0.110.0':
- resolution: {integrity: sha512-oH8G4aFMP8XyTsEpdANC5PQyHgSeGlopHZuW1rpyYcaErg5YaK0vXjQ4EM5HVvPm+feBV24JjxgakTnZoF3aOQ==}
- engines: {node: ^20.19.0 || >=22.12.0}
+ '@oxc-resolver/binding-linux-riscv64-musl@11.15.0':
+ resolution: {integrity: sha512-J7LPiEt27Tpm8P+qURDwNc8q45+n+mWgyys4/V6r5A8v5gDentHRGUx3iVk5NxdKhgoGulrzQocPTZVosq25Eg==}
cpu: [riscv64]
os: [linux]
- '@oxc-minify/binding-linux-s390x-gnu@0.110.0':
- resolution: {integrity: sha512-W9na+Vza7XVUlpf8wMt4QBfH35KeTENEmnpPUq3NSlbQHz8lSlSvhAafvo43NcKvHAXV3ckD/mUf2VkqSdbklg==}
- engines: {node: ^20.19.0 || >=22.12.0}
+ '@oxc-resolver/binding-linux-s390x-gnu@11.15.0':
+ resolution: {integrity: sha512-+8/d2tAScPjVJNyqa7GPGnqleTB/XW9dZJQ2D/oIM3wpH3TG+DaFEXBbk4QFJ9K9AUGBhvQvWU2mQyhK/yYn3Q==}
cpu: [s390x]
os: [linux]
- '@oxc-minify/binding-linux-x64-gnu@0.110.0':
- resolution: {integrity: sha512-XJdA4mmmXOjJxSRgNJXsDP7Xe8h3gQhmb56hUcCrvq5d+h5UcEi2pR8rxsdIrS8QmkLuBA3eHkGK8E27D7DTgQ==}
- engines: {node: ^20.19.0 || >=22.12.0}
- cpu: [x64]
- os: [linux]
-
- '@oxc-minify/binding-linux-x64-musl@0.110.0':
- resolution: {integrity: sha512-QqzvALuOTtSckI8x467R4GNArzYDb/yEh6aNzLoeaY1O7vfT7SPDwlOEcchaTznutpeS9Dy8gUS/AfqtUHaufw==}
- engines: {node: ^20.19.0 || >=22.12.0}
- cpu: [x64]
- os: [linux]
-
- '@oxc-minify/binding-openharmony-arm64@0.110.0':
- resolution: {integrity: sha512-gAMssLs2Q3+uhLZxanh1DF+27Kaug3cf4PXb9AB7XK81DR+LVcKySXaoGYoOs20Co0fFSphd6rRzKge2qDK3dA==}
- engines: {node: ^20.19.0 || >=22.12.0}
- cpu: [arm64]
- os: [openharmony]
-
- '@oxc-minify/binding-wasm32-wasi@0.110.0':
- resolution: {integrity: sha512-7Wqi5Zjl022bs2zXq+ICdalDPeDuCH/Nhbi8q2isLihAonMVIT0YH2hqqnNEylRNGYck+FJ6gRZwMpGCgrNxPg==}
- engines: {node: '>=14.0.0'}
- cpu: [wasm32]
-
- '@oxc-minify/binding-win32-arm64-msvc@0.110.0':
- resolution: {integrity: sha512-ZPx+0Tj4dqn41ecyoGotlvekQKy6JxJCixn9Rw7h/dafZ3eDuBcEVh3c2ZoldXXsyMIt5ywI8IWzFZsjNedd5Q==}
- engines: {node: ^20.19.0 || >=22.12.0}
- cpu: [arm64]
- os: [win32]
-
- '@oxc-minify/binding-win32-ia32-msvc@0.110.0':
- resolution: {integrity: sha512-H0Oyd3RWBfpEyvJIrFK94RYiY7KKSQl11Ym7LMDwLEagelIAfRCkt1amHZhFa/S3ZRoaOJFXzEw4YKeSsjVFsg==}
- engines: {node: ^20.19.0 || >=22.12.0}
- cpu: [ia32]
- os: [win32]
-
- '@oxc-minify/binding-win32-x64-msvc@0.110.0':
- resolution: {integrity: sha512-Hr3nK90+qXKJ2kepXwFIcNfQQIOBecB4FFCyaMMypthoEEhVP08heRynj4eSXZ8NL9hLjs3fQzH8PJXfpznRnQ==}
- engines: {node: ^20.19.0 || >=22.12.0}
- cpu: [x64]
- os: [win32]
-
- '@oxc-project/types@0.101.0':
- resolution: {integrity: sha512-nuFhqlUzJX+gVIPPfuE6xurd4lST3mdcWOhyK/rZO0B9XWMKm79SuszIQEnSMmmDhq1DC8WWVYGVd+6F93o1gQ==}
-
- '@oxc-resolver/binding-android-arm-eabi@11.15.0':
- resolution: {integrity: sha512-Q+lWuFfq7whNelNJIP1dhXaVz4zO9Tu77GcQHyxDWh3MaCoO2Bisphgzmsh4ZoUe2zIchQh6OvQL99GlWHg9Tw==}
- cpu: [arm]
- os: [android]
-
- '@oxc-resolver/binding-android-arm64@11.15.0':
- resolution: {integrity: sha512-vbdBttesHR0W1oJaxgWVTboyMUuu+VnPsHXJ6jrXf4czELzB6GIg5DrmlyhAmFBhjwov+yJH/DfTnHS+2sDgOw==}
- cpu: [arm64]
- os: [android]
-
- '@oxc-resolver/binding-darwin-arm64@11.15.0':
- resolution: {integrity: sha512-R67lsOe1UzNjqVBCwCZX1rlItTsj/cVtBw4Uy19CvTicqEWvwaTn8t34zLD75LQwDDPCY3C8n7NbD+LIdw+ZoA==}
- cpu: [arm64]
- os: [darwin]
-
- '@oxc-resolver/binding-darwin-x64@11.15.0':
- resolution: {integrity: sha512-77mya5F8WV0EtCxI0MlVZcqkYlaQpfNwl/tZlfg4jRsoLpFbaTeWv75hFm6TE84WULVlJtSgvf7DhoWBxp9+ZQ==}
- cpu: [x64]
- os: [darwin]
-
- '@oxc-resolver/binding-freebsd-x64@11.15.0':
- resolution: {integrity: sha512-X1Sz7m5PC+6D3KWIDXMUtux+0Imj6HfHGdBStSvgdI60OravzI1t83eyn6eN0LPTrynuPrUgjk7tOnOsBzSWHw==}
- cpu: [x64]
- os: [freebsd]
-
- '@oxc-resolver/binding-linux-arm-gnueabihf@11.15.0':
- resolution: {integrity: sha512-L1x/wCaIRre+18I4cH/lTqSAymlV0k4HqfSYNNuI9oeL28Ks86lI6O5VfYL6sxxWYgjuWB98gNGo7tq7d4GarQ==}
- cpu: [arm]
- os: [linux]
-
- '@oxc-resolver/binding-linux-arm-musleabihf@11.15.0':
- resolution: {integrity: sha512-abGXd/zMGa0tH8nKlAXdOnRy4G7jZmkU0J85kMKWns161bxIgGn/j7zxqh3DKEW98wAzzU9GofZMJ0P5YCVPVw==}
- cpu: [arm]
- os: [linux]
-
- '@oxc-resolver/binding-linux-arm64-gnu@11.15.0':
- resolution: {integrity: sha512-SVjjjtMW66Mza76PBGJLqB0KKyFTBnxmtDXLJPbL6ZPGSctcXVmujz7/WAc0rb9m2oV0cHQTtVjnq6orQnI/jg==}
- cpu: [arm64]
- os: [linux]
-
- '@oxc-resolver/binding-linux-arm64-musl@11.15.0':
- resolution: {integrity: sha512-JDv2/AycPF2qgzEiDeMJCcSzKNDm3KxNg0KKWipoKEMDFqfM7LxNwwSVyAOGmrYlE4l3dg290hOMsr9xG7jv9g==}
- cpu: [arm64]
- os: [linux]
-
- '@oxc-resolver/binding-linux-ppc64-gnu@11.15.0':
- resolution: {integrity: sha512-zbu9FhvBLW4KJxo7ElFvZWbSt4vP685Qc/Gyk/Ns3g2gR9qh2qWXouH8PWySy+Ko/qJ42+HJCLg+ZNcxikERfg==}
- cpu: [ppc64]
- os: [linux]
-
- '@oxc-resolver/binding-linux-riscv64-gnu@11.15.0':
- resolution: {integrity: sha512-Kfleehe6B09C2qCnyIU01xLFqFXCHI4ylzkicfX/89j+gNHh9xyNdpEvit88Kq6i5tTGdavVnM6DQfOE2qNtlg==}
- cpu: [riscv64]
- os: [linux]
-
- '@oxc-resolver/binding-linux-riscv64-musl@11.15.0':
- resolution: {integrity: sha512-J7LPiEt27Tpm8P+qURDwNc8q45+n+mWgyys4/V6r5A8v5gDentHRGUx3iVk5NxdKhgoGulrzQocPTZVosq25Eg==}
- cpu: [riscv64]
- os: [linux]
-
- '@oxc-resolver/binding-linux-s390x-gnu@11.15.0':
- resolution: {integrity: sha512-+8/d2tAScPjVJNyqa7GPGnqleTB/XW9dZJQ2D/oIM3wpH3TG+DaFEXBbk4QFJ9K9AUGBhvQvWU2mQyhK/yYn3Q==}
- cpu: [s390x]
- os: [linux]
-
- '@oxc-resolver/binding-linux-x64-gnu@11.15.0':
- resolution: {integrity: sha512-xtvSzH7Nr5MCZI2FKImmOdTl9kzuQ51RPyLh451tvD2qnkg3BaqI9Ox78bTk57YJhlXPuxWSOL5aZhKAc9J6qg==}
+ '@oxc-resolver/binding-linux-x64-gnu@11.15.0':
+ resolution: {integrity: sha512-xtvSzH7Nr5MCZI2FKImmOdTl9kzuQ51RPyLh451tvD2qnkg3BaqI9Ox78bTk57YJhlXPuxWSOL5aZhKAc9J6qg==}
cpu: [x64]
os: [linux]
@@ -2870,125 +2636,6 @@ packages:
cpu: [x64]
os: [win32]
- '@oxc-transform/binding-android-arm-eabi@0.110.0':
- resolution: {integrity: sha512-sE9dxvqqAax1YYJ3t7j+h5ZSI9jl6dYuDfngl6ieZUrIy5P89/8JKVgAzgp8o3wQSo7ndpJvYsi1K4ZqrmbP7w==}
- engines: {node: ^20.19.0 || >=22.12.0}
- cpu: [arm]
- os: [android]
-
- '@oxc-transform/binding-android-arm64@0.110.0':
- resolution: {integrity: sha512-nqtbP4aMCtsCZ6qpHlHaQoWVHSBtlKzwaAgwEOvR+9DWqHjk31BHvpGiDXlMeed6CVNpl3lCbWgygb3RcSjcfw==}
- engines: {node: ^20.19.0 || >=22.12.0}
- cpu: [arm64]
- os: [android]
-
- '@oxc-transform/binding-darwin-arm64@0.110.0':
- resolution: {integrity: sha512-oeSeHnL4Z4cMXtc8V0/rwoVn0dgwlS9q0j6LcHn9dIhtFEdp3W0iSBF8YmMQA+E7sILeLDjsHmHE4Kp0sOScXw==}
- engines: {node: ^20.19.0 || >=22.12.0}
- cpu: [arm64]
- os: [darwin]
-
- '@oxc-transform/binding-darwin-x64@0.110.0':
- resolution: {integrity: sha512-nL9K5x7OuZydobAGPylsEW9d4APs2qEkIBLMgQPA+kY8dtVD3IR87QsTbs4l4DBQYyun/+ay6qVCDlxqxdX2Jg==}
- engines: {node: ^20.19.0 || >=22.12.0}
- cpu: [x64]
- os: [darwin]
-
- '@oxc-transform/binding-freebsd-x64@0.110.0':
- resolution: {integrity: sha512-GS29zXXirDQhZEUq8xKJ1azAWMuUy3Ih3W5Bc5ddk12LRthO5wRLFcKIyeHpAXCoXymQ+LmxbMtbPf84GPxouw==}
- engines: {node: ^20.19.0 || >=22.12.0}
- cpu: [x64]
- os: [freebsd]
-
- '@oxc-transform/binding-linux-arm-gnueabihf@0.110.0':
- resolution: {integrity: sha512-glzDHak8ISyZJemCUi7RCvzNSl+MQ1ly9RceT2qRufhUsvNZ4C/2QLJ1HJwd2N6E88bO4laYn+RofdRzNnGGEA==}
- engines: {node: ^20.19.0 || >=22.12.0}
- cpu: [arm]
- os: [linux]
-
- '@oxc-transform/binding-linux-arm-musleabihf@0.110.0':
- resolution: {integrity: sha512-8JThvgJ2FRoTVfbp7e4wqeZqCZbtudM06SfZmNzND9kPNu/LVYygIR+72RWs+xm4bWkuYHg/islo/boNPtMT5Q==}
- engines: {node: ^20.19.0 || >=22.12.0}
- cpu: [arm]
- os: [linux]
-
- '@oxc-transform/binding-linux-arm64-gnu@0.110.0':
- resolution: {integrity: sha512-IRh21Ub/g4bkHoErZ0AUWMlWfoZaS0A6EaOVtbcY70RSYIMlrsbjiFwJCzM+b/1DD1rXbH5tsGcH7GweTbfRqg==}
- engines: {node: ^20.19.0 || >=22.12.0}
- cpu: [arm64]
- os: [linux]
-
- '@oxc-transform/binding-linux-arm64-musl@0.110.0':
- resolution: {integrity: sha512-e5JN94/oy+wevk76q+LMr+2klTTcO60uXa+Wkq558Ms7mdF2TvkKFI++d/JeiuIwJLTi/BxQ4qdT5FWcsHM/ug==}
- engines: {node: ^20.19.0 || >=22.12.0}
- cpu: [arm64]
- os: [linux]
-
- '@oxc-transform/binding-linux-ppc64-gnu@0.110.0':
- resolution: {integrity: sha512-Y3/Tnnz1GvDpmv8FXBIKtdZPsdZklOEPdrL6NHrN5i2u54BOkybFaDSptgWF53wOrJlTrcmAVSE6fRKK9XCM2Q==}
- engines: {node: ^20.19.0 || >=22.12.0}
- cpu: [ppc64]
- os: [linux]
-
- '@oxc-transform/binding-linux-riscv64-gnu@0.110.0':
- resolution: {integrity: sha512-Y0E35iA9/v9jlkNcP6tMJ+ZFOS0rLsWDqG6rU9z+X2R3fBFJBO9UARIK6ngx8upxk81y1TFR2CmBFhupfYdH6Q==}
- engines: {node: ^20.19.0 || >=22.12.0}
- cpu: [riscv64]
- os: [linux]
-
- '@oxc-transform/binding-linux-riscv64-musl@0.110.0':
- resolution: {integrity: sha512-JOUSYFfHjBUs7xp2FHmZHb8eTYD/oEu0NklS6JgUauqnoXZHiTLPLVW2o2uVCqldnabYHcomuwI2iqVFYJNhTw==}
- engines: {node: ^20.19.0 || >=22.12.0}
- cpu: [riscv64]
- os: [linux]
-
- '@oxc-transform/binding-linux-s390x-gnu@0.110.0':
- resolution: {integrity: sha512-7blgoXF9D3Ngzb7eun23pNrHJpoV/TtE6LObwlZ3Nmb4oZ6Z+yMvBVaoW68NarbmvNGfZ95zrOjgm6cVETLYBA==}
- engines: {node: ^20.19.0 || >=22.12.0}
- cpu: [s390x]
- os: [linux]
-
- '@oxc-transform/binding-linux-x64-gnu@0.110.0':
- resolution: {integrity: sha512-YQ2joGWCVDZVEU2cD/r/w49hVjDm/Qu1BvC/7zs8LvprzdLS/HyMXGF2oA0puw0b+AqgYaz3bhwKB2xexHyITQ==}
- engines: {node: ^20.19.0 || >=22.12.0}
- cpu: [x64]
- os: [linux]
-
- '@oxc-transform/binding-linux-x64-musl@0.110.0':
- resolution: {integrity: sha512-fkjr5qE632ULmNgvFXWDR/8668WxERz3tU7TQFp6JebPBneColitjSkdx6VKNVXEoMmQnOvBIGeP5tUNT384oA==}
- engines: {node: ^20.19.0 || >=22.12.0}
- cpu: [x64]
- os: [linux]
-
- '@oxc-transform/binding-openharmony-arm64@0.110.0':
- resolution: {integrity: sha512-HWH9Zj+lMrdSTqFRCZsvDWMz7OnMjbdGsm3xURXWfRZpuaz0bVvyuZNDQXc4FyyhRDsemICaJbU1bgeIpUJDGw==}
- engines: {node: ^20.19.0 || >=22.12.0}
- cpu: [arm64]
- os: [openharmony]
-
- '@oxc-transform/binding-wasm32-wasi@0.110.0':
- resolution: {integrity: sha512-ejdxHmYfIcHDPhZUe3WklViLt9mDEJE5BzcW7+R1vc5i/5JFA8D0l7NUSsHBJ7FB8Bu9gF+5iMDm6cXGAgaghw==}
- engines: {node: '>=14.0.0'}
- cpu: [wasm32]
-
- '@oxc-transform/binding-win32-arm64-msvc@0.110.0':
- resolution: {integrity: sha512-9VTwpXCZs7xkV+mKhQ62dVk7KLnLXtEUxNS2T4nLz3iMl1IJbA4h5oltK0JoobtiUAnbkV53QmMVGW8+Nh3bDQ==}
- engines: {node: ^20.19.0 || >=22.12.0}
- cpu: [arm64]
- os: [win32]
-
- '@oxc-transform/binding-win32-ia32-msvc@0.110.0':
- resolution: {integrity: sha512-5y0fzuNON7/F2hh2P94vANFaRPJ/3DI1hVl5rseCT8VUVqOGIjWaza0YS/D1g6t1WwycW2LWDMi2raOKoWU5GQ==}
- engines: {node: ^20.19.0 || >=22.12.0}
- cpu: [ia32]
- os: [win32]
-
- '@oxc-transform/binding-win32-x64-msvc@0.110.0':
- resolution: {integrity: sha512-QROrowwlrApI1fEScMknGWKM6GTM/Z2xwMnDqvSaEmzNazBsDUlE08Jasw610hFEsYAVU2K5sp/YaCa9ORdP4A==}
- engines: {node: ^20.19.0 || >=22.12.0}
- cpu: [x64]
- os: [win32]
-
'@parcel/watcher-android-arm64@2.5.1':
resolution: {integrity: sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA==}
engines: {node: '>= 10.0.0'}
@@ -3104,36 +2751,6 @@ packages:
'@poppinss/exception@1.2.3':
resolution: {integrity: sha512-dCED+QRChTVatE9ibtoaxc+WkdzOSjYTKi/+uacHWIsfodVfpsueo3+DKpgU5Px8qXjgmXkSvhXvSCz3fnP9lw==}
- '@protobufjs/aspromise@1.1.2':
- resolution: {integrity: sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==}
-
- '@protobufjs/base64@1.1.2':
- resolution: {integrity: sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==}
-
- '@protobufjs/codegen@2.0.4':
- resolution: {integrity: sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==}
-
- '@protobufjs/eventemitter@1.1.0':
- resolution: {integrity: sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==}
-
- '@protobufjs/fetch@1.1.0':
- resolution: {integrity: sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==}
-
- '@protobufjs/float@1.0.2':
- resolution: {integrity: sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==}
-
- '@protobufjs/inquire@1.1.0':
- resolution: {integrity: sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==}
-
- '@protobufjs/path@1.1.2':
- resolution: {integrity: sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==}
-
- '@protobufjs/pool@1.1.0':
- resolution: {integrity: sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==}
-
- '@protobufjs/utf8@1.1.0':
- resolution: {integrity: sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==}
-
'@publint/pack@0.1.2':
resolution: {integrity: sha512-S+9ANAvUmjutrshV4jZjaiG8XQyuJIZ8a4utWmN/vW1sgQ9IfBnPndwkmQYw53QmouOIytT874u65HEmu6H5jw==}
engines: {node: '>=18'}
@@ -3236,15 +2853,6 @@ packages:
rollup:
optional: true
- '@rollup/plugin-alias@6.0.0':
- resolution: {integrity: sha512-tPCzJOtS7uuVZd+xPhoy5W4vThe6KWXNmsFCNktaAh5RTqcLiSfT4huPQIXkgJ6YCOjJHvecOAzQxLFhPxKr+g==}
- engines: {node: '>=20.19.0'}
- peerDependencies:
- rollup: '>=4.0.0'
- peerDependenciesMeta:
- rollup:
- optional: true
-
'@rollup/plugin-commonjs@28.0.9':
resolution: {integrity: sha512-PIR4/OHZ79romx0BVVll/PkwWpJ7e5lsqFa3gFfcrFPWwLXLV39JVUzQV9RKjWerE7B845Hqjj9VYlQeieZ2dA==}
engines: {node: '>=16.0.0 || 14 >= 14.17'}
@@ -3254,15 +2862,6 @@ packages:
rollup:
optional: true
- '@rollup/plugin-commonjs@29.0.0':
- resolution: {integrity: sha512-U2YHaxR2cU/yAiwKJtJRhnyLk7cifnQw0zUpISsocBDoHDJn+HTV74ABqnwr5bEgWUwFZC9oFL6wLe21lHu5eQ==}
- engines: {node: '>=16.0.0 || 14 >= 14.17'}
- peerDependencies:
- rollup: ^2.68.0||^3.0.0||^4.0.0
- peerDependenciesMeta:
- rollup:
- optional: true
-
'@rollup/plugin-inject@5.0.5':
resolution: {integrity: sha512-2+DEJbNBoPROPkgTDNe8/1YXWcqxbN5DTjASVIOx8HS+pITXushyNiBV56RB08zuptzz8gT3YfkqriTBVycepg==}
engines: {node: '>=14.0.0'}
@@ -3322,8 +2921,8 @@ packages:
cpu: [arm]
os: [android]
- '@rollup/rollup-android-arm-eabi@4.57.1':
- resolution: {integrity: sha512-A6ehUVSiSaaliTxai040ZpZ2zTevHYbvu/lDoeAteHI8QnaosIzm4qwtezfRg1jOYaUmnzLX1AOD6Z+UJjtifg==}
+ '@rollup/rollup-android-arm-eabi@4.55.1':
+ resolution: {integrity: sha512-9R0DM/ykwfGIlNu6+2U09ga0WXeZ9MRC2Ter8jnz8415VbuIykVuc6bhdrbORFZANDmTDvq26mJrEVTl8TdnDg==}
cpu: [arm]
os: [android]
@@ -3332,8 +2931,8 @@ packages:
cpu: [arm64]
os: [android]
- '@rollup/rollup-android-arm64@4.57.1':
- resolution: {integrity: sha512-dQaAddCY9YgkFHZcFNS/606Exo8vcLHwArFZ7vxXq4rigo2bb494/xKMMwRRQW6ug7Js6yXmBZhSBRuBvCCQ3w==}
+ '@rollup/rollup-android-arm64@4.55.1':
+ resolution: {integrity: sha512-eFZCb1YUqhTysgW3sj/55du5cG57S7UTNtdMjCW7LwVcj3dTTcowCsC8p7uBdzKsZYa8J7IDE8lhMI+HX1vQvg==}
cpu: [arm64]
os: [android]
@@ -3342,8 +2941,8 @@ packages:
cpu: [arm64]
os: [darwin]
- '@rollup/rollup-darwin-arm64@4.57.1':
- resolution: {integrity: sha512-crNPrwJOrRxagUYeMn/DZwqN88SDmwaJ8Cvi/TN1HnWBU7GwknckyosC2gd0IqYRsHDEnXf328o9/HC6OkPgOg==}
+ '@rollup/rollup-darwin-arm64@4.55.1':
+ resolution: {integrity: sha512-p3grE2PHcQm2e8PSGZdzIhCKbMCw/xi9XvMPErPhwO17vxtvCN5FEA2mSLgmKlCjHGMQTP6phuQTYWUnKewwGg==}
cpu: [arm64]
os: [darwin]
@@ -3352,8 +2951,8 @@ packages:
cpu: [x64]
os: [darwin]
- '@rollup/rollup-darwin-x64@4.57.1':
- resolution: {integrity: sha512-Ji8g8ChVbKrhFtig5QBV7iMaJrGtpHelkB3lsaKzadFBe58gmjfGXAOfI5FV0lYMH8wiqsxKQ1C9B0YTRXVy4w==}
+ '@rollup/rollup-darwin-x64@4.55.1':
+ resolution: {integrity: sha512-rDUjG25C9qoTm+e02Esi+aqTKSBYwVTaoS1wxcN47/Luqef57Vgp96xNANwt5npq9GDxsH7kXxNkJVEsWEOEaQ==}
cpu: [x64]
os: [darwin]
@@ -3362,8 +2961,8 @@ packages:
cpu: [arm64]
os: [freebsd]
- '@rollup/rollup-freebsd-arm64@4.57.1':
- resolution: {integrity: sha512-R+/WwhsjmwodAcz65guCGFRkMb4gKWTcIeLy60JJQbXrJ97BOXHxnkPFrP+YwFlaS0m+uWJTstrUA9o+UchFug==}
+ '@rollup/rollup-freebsd-arm64@4.55.1':
+ resolution: {integrity: sha512-+JiU7Jbp5cdxekIgdte0jfcu5oqw4GCKr6i3PJTlXTCU5H5Fvtkpbs4XJHRmWNXF+hKmn4v7ogI5OQPaupJgOg==}
cpu: [arm64]
os: [freebsd]
@@ -3372,8 +2971,8 @@ packages:
cpu: [x64]
os: [freebsd]
- '@rollup/rollup-freebsd-x64@4.57.1':
- resolution: {integrity: sha512-IEQTCHeiTOnAUC3IDQdzRAGj3jOAYNr9kBguI7MQAAZK3caezRrg0GxAb6Hchg4lxdZEI5Oq3iov/w/hnFWY9Q==}
+ '@rollup/rollup-freebsd-x64@4.55.1':
+ resolution: {integrity: sha512-V5xC1tOVWtLLmr3YUk2f6EJK4qksksOYiz/TCsFHu/R+woubcLWdC9nZQmwjOAbmExBIVKsm1/wKmEy4z4u4Bw==}
cpu: [x64]
os: [freebsd]
@@ -3382,8 +2981,8 @@ packages:
cpu: [arm]
os: [linux]
- '@rollup/rollup-linux-arm-gnueabihf@4.57.1':
- resolution: {integrity: sha512-F8sWbhZ7tyuEfsmOxwc2giKDQzN3+kuBLPwwZGyVkLlKGdV1nvnNwYD0fKQ8+XS6hp9nY7B+ZeK01EBUE7aHaw==}
+ '@rollup/rollup-linux-arm-gnueabihf@4.55.1':
+ resolution: {integrity: sha512-Rn3n+FUk2J5VWx+ywrG/HGPTD9jXNbicRtTM11e/uorplArnXZYsVifnPPqNNP5BsO3roI4n8332ukpY/zN7rQ==}
cpu: [arm]
os: [linux]
@@ -3392,8 +2991,8 @@ packages:
cpu: [arm]
os: [linux]
- '@rollup/rollup-linux-arm-musleabihf@4.57.1':
- resolution: {integrity: sha512-rGfNUfn0GIeXtBP1wL5MnzSj98+PZe/AXaGBCRmT0ts80lU5CATYGxXukeTX39XBKsxzFpEeK+Mrp9faXOlmrw==}
+ '@rollup/rollup-linux-arm-musleabihf@4.55.1':
+ resolution: {integrity: sha512-grPNWydeKtc1aEdrJDWk4opD7nFtQbMmV7769hiAaYyUKCT1faPRm2av8CX1YJsZ4TLAZcg9gTR1KvEzoLjXkg==}
cpu: [arm]
os: [linux]
@@ -3402,8 +3001,8 @@ packages:
cpu: [arm64]
os: [linux]
- '@rollup/rollup-linux-arm64-gnu@4.57.1':
- resolution: {integrity: sha512-MMtej3YHWeg/0klK2Qodf3yrNzz6CGjo2UntLvk2RSPlhzgLvYEB3frRvbEF2wRKh1Z2fDIg9KRPe1fawv7C+g==}
+ '@rollup/rollup-linux-arm64-gnu@4.55.1':
+ resolution: {integrity: sha512-a59mwd1k6x8tXKcUxSyISiquLwB5pX+fJW9TkWU46lCqD/GRDe9uDN31jrMmVP3feI3mhAdvcCClhV8V5MhJFQ==}
cpu: [arm64]
os: [linux]
@@ -3412,8 +3011,8 @@ packages:
cpu: [arm64]
os: [linux]
- '@rollup/rollup-linux-arm64-musl@4.57.1':
- resolution: {integrity: sha512-1a/qhaaOXhqXGpMFMET9VqwZakkljWHLmZOX48R0I/YLbhdxr1m4gtG1Hq7++VhVUmf+L3sTAf9op4JlhQ5u1Q==}
+ '@rollup/rollup-linux-arm64-musl@4.55.1':
+ resolution: {integrity: sha512-puS1MEgWX5GsHSoiAsF0TYrpomdvkaXm0CofIMG5uVkP6IBV+ZO9xhC5YEN49nsgYo1DuuMquF9+7EDBVYu4uA==}
cpu: [arm64]
os: [linux]
@@ -3422,13 +3021,13 @@ packages:
cpu: [loong64]
os: [linux]
- '@rollup/rollup-linux-loong64-gnu@4.57.1':
- resolution: {integrity: sha512-QWO6RQTZ/cqYtJMtxhkRkidoNGXc7ERPbZN7dVW5SdURuLeVU7lwKMpo18XdcmpWYd0qsP1bwKPf7DNSUinhvA==}
+ '@rollup/rollup-linux-loong64-gnu@4.55.1':
+ resolution: {integrity: sha512-r3Wv40in+lTsULSb6nnoudVbARdOwb2u5fpeoOAZjFLznp6tDU8kd+GTHmJoqZ9lt6/Sys33KdIHUaQihFcu7g==}
cpu: [loong64]
os: [linux]
- '@rollup/rollup-linux-loong64-musl@4.57.1':
- resolution: {integrity: sha512-xpObYIf+8gprgWaPP32xiN5RVTi/s5FCR+XMXSKmhfoJjrpRAjCuuqQXyxUa/eJTdAE6eJ+KDKaoEqjZQxh3Gw==}
+ '@rollup/rollup-linux-loong64-musl@4.55.1':
+ resolution: {integrity: sha512-MR8c0+UxAlB22Fq4R+aQSPBayvYa3+9DrwG/i1TKQXFYEaoW3B5b/rkSRIypcZDdWjWnpcvxbNaAJDcSbJU3Lw==}
cpu: [loong64]
os: [linux]
@@ -3437,13 +3036,13 @@ packages:
cpu: [ppc64]
os: [linux]
- '@rollup/rollup-linux-ppc64-gnu@4.57.1':
- resolution: {integrity: sha512-4BrCgrpZo4hvzMDKRqEaW1zeecScDCR+2nZ86ATLhAoJ5FQ+lbHVD3ttKe74/c7tNT9c6F2viwB3ufwp01Oh2w==}
+ '@rollup/rollup-linux-ppc64-gnu@4.55.1':
+ resolution: {integrity: sha512-3KhoECe1BRlSYpMTeVrD4sh2Pw2xgt4jzNSZIIPLFEsnQn9gAnZagW9+VqDqAHgm1Xc77LzJOo2LdigS5qZ+gw==}
cpu: [ppc64]
os: [linux]
- '@rollup/rollup-linux-ppc64-musl@4.57.1':
- resolution: {integrity: sha512-NOlUuzesGauESAyEYFSe3QTUguL+lvrN1HtwEEsU2rOwdUDeTMJdO5dUYl/2hKf9jWydJrO9OL/XSSf65R5+Xw==}
+ '@rollup/rollup-linux-ppc64-musl@4.55.1':
+ resolution: {integrity: sha512-ziR1OuZx0vdYZZ30vueNZTg73alF59DicYrPViG0NEgDVN8/Jl87zkAPu4u6VjZST2llgEUjaiNl9JM6HH1Vdw==}
cpu: [ppc64]
os: [linux]
@@ -3452,8 +3051,8 @@ packages:
cpu: [riscv64]
os: [linux]
- '@rollup/rollup-linux-riscv64-gnu@4.57.1':
- resolution: {integrity: sha512-ptA88htVp0AwUUqhVghwDIKlvJMD/fmL/wrQj99PRHFRAG6Z5nbWoWG4o81Nt9FT+IuqUQi+L31ZKAFeJ5Is+A==}
+ '@rollup/rollup-linux-riscv64-gnu@4.55.1':
+ resolution: {integrity: sha512-uW0Y12ih2XJRERZ4jAfKamTyIHVMPQnTZcQjme2HMVDAHY4amf5u414OqNYC+x+LzRdRcnIG1YodLrrtA8xsxw==}
cpu: [riscv64]
os: [linux]
@@ -3462,8 +3061,8 @@ packages:
cpu: [riscv64]
os: [linux]
- '@rollup/rollup-linux-riscv64-musl@4.57.1':
- resolution: {integrity: sha512-S51t7aMMTNdmAMPpBg7OOsTdn4tySRQvklmL3RpDRyknk87+Sp3xaumlatU+ppQ+5raY7sSTcC2beGgvhENfuw==}
+ '@rollup/rollup-linux-riscv64-musl@4.55.1':
+ resolution: {integrity: sha512-u9yZ0jUkOED1BFrqu3BwMQoixvGHGZ+JhJNkNKY/hyoEgOwlqKb62qu+7UjbPSHYjiVy8kKJHvXKv5coH4wDeg==}
cpu: [riscv64]
os: [linux]
@@ -3472,8 +3071,8 @@ packages:
cpu: [s390x]
os: [linux]
- '@rollup/rollup-linux-s390x-gnu@4.57.1':
- resolution: {integrity: sha512-Bl00OFnVFkL82FHbEqy3k5CUCKH6OEJL54KCyx2oqsmZnFTR8IoNqBF+mjQVcRCT5sB6yOvK8A37LNm/kPJiZg==}
+ '@rollup/rollup-linux-s390x-gnu@4.55.1':
+ resolution: {integrity: sha512-/0PenBCmqM4ZUd0190j7J0UsQ/1nsi735iPRakO8iPciE7BQ495Y6msPzaOmvx0/pn+eJVVlZrNrSh4WSYLxNg==}
cpu: [s390x]
os: [linux]
@@ -3482,8 +3081,8 @@ packages:
cpu: [x64]
os: [linux]
- '@rollup/rollup-linux-x64-gnu@4.57.1':
- resolution: {integrity: sha512-ABca4ceT4N+Tv/GtotnWAeXZUZuM/9AQyCyKYyKnpk4yoA7QIAuBt6Hkgpw8kActYlew2mvckXkvx0FfoInnLg==}
+ '@rollup/rollup-linux-x64-gnu@4.55.1':
+ resolution: {integrity: sha512-a8G4wiQxQG2BAvo+gU6XrReRRqj+pLS2NGXKm8io19goR+K8lw269eTrPkSdDTALwMmJp4th2Uh0D8J9bEV1vg==}
cpu: [x64]
os: [linux]
@@ -3492,13 +3091,13 @@ packages:
cpu: [x64]
os: [linux]
- '@rollup/rollup-linux-x64-musl@4.57.1':
- resolution: {integrity: sha512-HFps0JeGtuOR2convgRRkHCekD7j+gdAuXM+/i6kGzQtFhlCtQkpwtNzkNj6QhCDp7DRJ7+qC/1Vg2jt5iSOFw==}
+ '@rollup/rollup-linux-x64-musl@4.55.1':
+ resolution: {integrity: sha512-bD+zjpFrMpP/hqkfEcnjXWHMw5BIghGisOKPj+2NaNDuVT+8Ds4mPf3XcPHuat1tz89WRL+1wbcxKY3WSbiT7w==}
cpu: [x64]
os: [linux]
- '@rollup/rollup-openbsd-x64@4.57.1':
- resolution: {integrity: sha512-H+hXEv9gdVQuDTgnqD+SQffoWoc0Of59AStSzTEj/feWTBAnSfSD3+Dql1ZruJQxmykT/JVY0dE8Ka7z0DH1hw==}
+ '@rollup/rollup-openbsd-x64@4.55.1':
+ resolution: {integrity: sha512-eLXw0dOiqE4QmvikfQ6yjgkg/xDM+MdU9YJuP4ySTibXU0oAvnEWXt7UDJmD4UkYialMfOGFPJnIHSe/kdzPxg==}
cpu: [x64]
os: [openbsd]
@@ -3507,8 +3106,8 @@ packages:
cpu: [arm64]
os: [openharmony]
- '@rollup/rollup-openharmony-arm64@4.57.1':
- resolution: {integrity: sha512-4wYoDpNg6o/oPximyc/NG+mYUejZrCU2q+2w6YZqrAs2UcNUChIZXjtafAiiZSUc7On8v5NyNj34Kzj/Ltk6dQ==}
+ '@rollup/rollup-openharmony-arm64@4.55.1':
+ resolution: {integrity: sha512-xzm44KgEP11te3S2HCSyYf5zIzWmx3n8HDCc7EE59+lTcswEWNpvMLfd9uJvVX8LCg9QWG67Xt75AuHn4vgsXw==}
cpu: [arm64]
os: [openharmony]
@@ -3517,8 +3116,8 @@ packages:
cpu: [arm64]
os: [win32]
- '@rollup/rollup-win32-arm64-msvc@4.57.1':
- resolution: {integrity: sha512-O54mtsV/6LW3P8qdTcamQmuC990HDfR71lo44oZMZlXU4tzLrbvTii87Ni9opq60ds0YzuAlEr/GNwuNluZyMQ==}
+ '@rollup/rollup-win32-arm64-msvc@4.55.1':
+ resolution: {integrity: sha512-yR6Bl3tMC/gBok5cz/Qi0xYnVbIxGx5Fcf/ca0eB6/6JwOY+SRUcJfI0OpeTpPls7f194as62thCt/2BjxYN8g==}
cpu: [arm64]
os: [win32]
@@ -3527,8 +3126,8 @@ packages:
cpu: [ia32]
os: [win32]
- '@rollup/rollup-win32-ia32-msvc@4.57.1':
- resolution: {integrity: sha512-P3dLS+IerxCT/7D2q2FYcRdWRl22dNbrbBEtxdWhXrfIMPP9lQhb5h4Du04mdl5Woq05jVCDPCMF7Ub0NAjIew==}
+ '@rollup/rollup-win32-ia32-msvc@4.55.1':
+ resolution: {integrity: sha512-3fZBidchE0eY0oFZBnekYCfg+5wAB0mbpCBuofh5mZuzIU/4jIVkbESmd2dOsFNS78b53CYv3OAtwqkZZmU5nA==}
cpu: [ia32]
os: [win32]
@@ -3537,8 +3136,8 @@ packages:
cpu: [x64]
os: [win32]
- '@rollup/rollup-win32-x64-gnu@4.57.1':
- resolution: {integrity: sha512-VMBH2eOOaKGtIJYleXsi2B8CPVADrh+TyNxJ4mWPnKfLB/DBUmzW+5m1xUrcwWoMfSLagIRpjUFeW5CO5hyciQ==}
+ '@rollup/rollup-win32-x64-gnu@4.55.1':
+ resolution: {integrity: sha512-xGGY5pXj69IxKb4yv/POoocPy/qmEGhimy/FoTpTSVju3FYXUQQMFCaZZXJVidsmGxRioZAwpThl/4zX41gRKg==}
cpu: [x64]
os: [win32]
@@ -3547,8 +3146,8 @@ packages:
cpu: [x64]
os: [win32]
- '@rollup/rollup-win32-x64-msvc@4.57.1':
- resolution: {integrity: sha512-mxRFDdHIWRxg3UfIIAwCm6NzvxG0jDX/wBN6KsQFTvKFqqg9vTrWUE68qEjHt19A5wwx5X5aUi2zuZT7YR0jrA==}
+ '@rollup/rollup-win32-x64-msvc@4.55.1':
+ resolution: {integrity: sha512-SPEpaL6DX4rmcXtnhdrQYgzQ5W2uW3SCJch88lB2zImhJRhIIK44fkUrgIV/Q8yUNfw5oyZ5vkeQsZLhCb06lw==}
cpu: [x64]
os: [win32]
@@ -3843,40 +3442,22 @@ packages:
resolution: {integrity: sha512-hsNDE3iu4frt9cC2ppn1mNRnLKo2uc1/1hXAyY9z4UYb+o40M2clFAhiFoo4HngjfGJDV3x18KVVIq7W4Un+zA==}
engines: {node: '>=18'}
- '@tanstack/devtools-client@0.0.6':
- resolution: {integrity: sha512-f85ZJXJnDIFOoykG/BFIixuAevJovCvJF391LPs6YjBAPhGYC50NWlx1y4iF/UmK5/cCMx+/JqI5SBOz7FanQQ==}
- engines: {node: '>=18'}
-
'@tanstack/devtools-event-bus@0.3.3':
resolution: {integrity: sha512-lWl88uLAz7ZhwNdLH6A3tBOSEuBCrvnY9Fzr5JPdzJRFdM5ZFdyNWz1Bf5l/F3GU57VodrN0KCFi9OA26H5Kpg==}
engines: {node: '>=18'}
- '@tanstack/devtools-event-bus@0.4.1':
- resolution: {integrity: sha512-cNnJ89Q021Zf883rlbBTfsaxTfi2r73/qejGtyTa7ksErF3hyDyAq1aTbo5crK9dAL7zSHh9viKY1BtMls1QOA==}
- engines: {node: '>=18'}
-
'@tanstack/devtools-event-client@0.4.0':
resolution: {integrity: sha512-RPfGuk2bDZgcu9bAJodvO2lnZeHuz4/71HjZ0bGb/SPg8+lyTA+RLSKQvo7fSmPSi8/vcH3aKQ8EM9ywf1olaw==}
engines: {node: '>=18'}
- '@tanstack/devtools-event-client@0.4.1':
- resolution: {integrity: sha512-GRxmPw4OHZ2oZeIEUkEwt/NDvuEqzEYRAjzUVMs+I0pd4C7k1ySOiuJK2CqF+K/yEAR3YZNkW3ExrpDarh9Vwg==}
- engines: {node: '>=18'}
-
'@tanstack/devtools-ui@0.4.4':
resolution: {integrity: sha512-5xHXFyX3nom0UaNfiOM92o6ziaHjGo3mcSGe2HD5Xs8dWRZNpdZ0Smd0B9ddEhy0oB+gXyMzZgUJb9DmrZV0Mg==}
engines: {node: '>=18'}
peerDependencies:
solid-js: '>=1.9.7'
- '@tanstack/devtools-ui@0.5.0':
- resolution: {integrity: sha512-nNZ14054n31fWB61jtWhZYLRdQ3yceCE3G/RINoINUB0RqIGZAIm9DnEDwOTAOfqt4/a/D8vNk8pJu6RQUp74g==}
- engines: {node: '>=18'}
- peerDependencies:
- solid-js: '>=1.9.7'
-
- '@tanstack/devtools-utils@0.3.2':
- resolution: {integrity: sha512-fu9wmE2bHigiE1Lc5RFSchgdN35wX15TqfB4O4vJa6SqX9JH2ov57J60u18lheROaBiteloPzcCbkLNpx0aacw==}
+ '@tanstack/devtools-utils@0.3.0':
+ resolution: {integrity: sha512-JgApXVrgtgSLIPrm/QWHx0u6c9Ji0MNMDWhwujapj8eMzux5aOfi+2Ycwzj0A0qITXA12SEPYV3HC568mDtYmQ==}
engines: {node: '>=18'}
peerDependencies:
'@types/react': '>=17.0.0'
@@ -3896,18 +3477,12 @@ packages:
vue:
optional: true
- '@tanstack/devtools-vite@0.5.3':
- resolution: {integrity: sha512-S7VK2GthBrEkto0UVODx31IAvxTFUK0RGH6aZEZixsohYTytTdrwcLmPKEREwFrRN8Qc2mIqfBhENPbRG1RFXA==}
+ '@tanstack/devtools-vite@0.3.12':
+ resolution: {integrity: sha512-fGJgu4xUhKmGk+a+/aHD8l5HKVk6+ObA+6D3YC3xCXbai/YmaGhztqcZf1tKUqjZyYyQLHsjqmKzvJgVpQP1jw==}
engines: {node: '>=18'}
peerDependencies:
vite: ^6.0.0 || ^7.0.0
- '@tanstack/devtools@0.10.11':
- resolution: {integrity: sha512-Nk1rHsv6S/5Krzz+uL5jldW9gKb3s6rkkVl1L9oVYHNClKthbrk2hGef4Di6yj449QIOqVExTdDujjQ4roq1dg==}
- engines: {node: '>=18'}
- peerDependencies:
- solid-js: '>=1.9.7'
-
'@tanstack/devtools@0.9.1':
resolution: {integrity: sha512-fW/1ewT+g0LgJGraS/Irwle3uRgM1VDwfhi/NP3aGHhGyCDAWJI0+Id9FBzjChQ5BuEU5qD5fdegcFqTZShXHw==}
engines: {node: '>=18'}
@@ -3938,12 +3513,8 @@ packages:
resolution: {integrity: sha512-LS54XNyxyTs5m/pl1lkwlg7uZM3lvsv2FIIV1rsJgnfwVCnI+n4ZGZ2CcjNT13BPu/3hPP+iHmliBSscJxW5FQ==}
engines: {node: '>=12'}
- '@tanstack/history@1.154.14':
- resolution: {integrity: sha512-xyIfof8eHBuub1CkBnbKNKQXeRZC4dClhmzePHVOEel4G7lk/dW+TQ16da7CFdeNLv6u6Owf5VoBQxoo6DFTSA==}
- engines: {node: '>=12'}
-
- '@tanstack/nitro-v2-vite-plugin@1.154.7':
- resolution: {integrity: sha512-THhjYwW+cREhmQyW/iATonY46RwYV8tbMnxBzIu77ceQOIHxkA1kVhLecb/oG5VdTduQnHVe90BD9qohX0mDHg==}
+ '@tanstack/nitro-v2-vite-plugin@1.141.0':
+ resolution: {integrity: sha512-OW0U7ftm4unRKhL9AZoTtdYIT3UnKfY8UQ25QNzI2uUPeVOyE9/yINFEgPGzS6gn4jQmJ3N2QvFZNvEjrbD0iA==}
engines: {node: '>=22.12'}
peerDependencies:
vite: '>=7.0.0'
@@ -3951,8 +3522,8 @@ packages:
'@tanstack/query-core@5.90.12':
resolution: {integrity: sha512-T1/8t5DhV/SisWjDnaiU2drl6ySvsHj1bHBCWNXd+/T+Hh1cf6JodyEYMd5sgwm+b/mETT4EV3H+zCVczCU5hg==}
- '@tanstack/react-devtools@0.9.10':
- resolution: {integrity: sha512-WKFU8SXN7DLM7EyD2aUAhmk7JGNeONWhQozAH2qDCeOjyc3Yzxs4BxeoyKMYyEiX/eCp8ZkMTf/pJX6vm2LGeA==}
+ '@tanstack/react-devtools@0.8.4':
+ resolution: {integrity: sha512-fq7GrpHIRdIBa5HmNN+CmC7CopY3tfKE4AXoszNSLk4yHKjC8iEjx7rh4r4RO5iUxHnmoCKX+NPXDgfsIKtaog==}
engines: {node: '>=18'}
peerDependencies:
'@types/react': '>=16.8'
@@ -3965,20 +3536,20 @@ packages:
peerDependencies:
react: ^18 || ^19
- '@tanstack/react-router-devtools@1.159.5':
- resolution: {integrity: sha512-IIyomu+ypWTxyoYT32mxamVmdTs7ZCGcTbdj7HVvtD3xp1lvo/bwRXj9oERENmb+OAPOaWF2doRYC/pmKjK5vg==}
+ '@tanstack/react-router-devtools@1.141.1':
+ resolution: {integrity: sha512-+XCn9cXSe1fZAD9jRrezEYE0ojn9U+Y0lRTRFdR8n51wx0UzJ6xe/Pewtw0rp03h/zmBR0pX+HRNU9NJDneWGA==}
engines: {node: '>=12'}
peerDependencies:
- '@tanstack/react-router': ^1.159.5
- '@tanstack/router-core': ^1.159.4
+ '@tanstack/react-router': ^1.141.1
+ '@tanstack/router-core': ^1.141.1
react: '>=18.0.0 || >=19.0.0'
react-dom: '>=18.0.0 || >=19.0.0'
peerDependenciesMeta:
'@tanstack/router-core':
optional: true
- '@tanstack/react-router-ssr-query@1.159.5':
- resolution: {integrity: sha512-r/Um9DASjmaTdiyXA3cpooGLrSD1BlcXUNsRz4zAlvD38m0gIFvaykOM2Naztqm9H+2CJkocRZp2/kR69Xcmyg==}
+ '@tanstack/react-router-ssr-query@1.141.1':
+ resolution: {integrity: sha512-80KEKpHx9OZwXcdCOZDyftqxWMP8QHGU6LQgyIsuunPrf76Wf1riyBnZrPOAOJPcjM3PDhTHLNIfmRBnAtItUw==}
engines: {node: '>=12'}
peerDependencies:
'@tanstack/query-core': '>=5.90.0'
@@ -3994,13 +3565,6 @@ packages:
react: '>=18.0.0 || >=19.0.0'
react-dom: '>=18.0.0 || >=19.0.0'
- '@tanstack/react-router@1.159.5':
- resolution: {integrity: sha512-rVb0MtKzP5c0BkWIoFgWBiRAJHYSU3bhsEHbT0cRdRLmlJiw21Awb6VEjgYq3hJiEhowcKKm6J8AdRD/8oZ5dQ==}
- engines: {node: '>=12'}
- peerDependencies:
- react: '>=18.0.0 || >=19.0.0'
- react-dom: '>=18.0.0 || >=19.0.0'
-
'@tanstack/react-start-client@1.141.1':
resolution: {integrity: sha512-DkScmgoed8DbLxivWI/LbyGUsPcuOuWI0WGcNrPdFJLn2SqJjGSXhNcYZAAKlwY2TtCp7L+YnZoeOi/EDgrdSg==}
engines: {node: '>=22.12.0'}
@@ -4008,13 +3572,6 @@ packages:
react: '>=18.0.0 || >=19.0.0'
react-dom: '>=18.0.0 || >=19.0.0'
- '@tanstack/react-start-client@1.159.5':
- resolution: {integrity: sha512-Qynx7XWHI1rhVpSUx6P40zazcQVJRhl2fnAcSH0I6vaAxSuZm8lvI37YacXPRu8flvI/ZGlF095arxiyps+A0w==}
- engines: {node: '>=22.12.0'}
- peerDependencies:
- react: '>=18.0.0 || >=19.0.0'
- react-dom: '>=18.0.0 || >=19.0.0'
-
'@tanstack/react-start-plugin@1.131.50':
resolution: {integrity: sha512-ys+sGvnnE8BUNjGsngg+MGn3F5lV4okL5CWEKFzjBSjQsrTN7apGfmqvBP3O6PkRPHpXZ8X3Z5QsFvSc0CaDRQ==}
engines: {node: '>=12'}
@@ -4033,15 +3590,8 @@ packages:
react: '>=18.0.0 || >=19.0.0'
react-dom: '>=18.0.0 || >=19.0.0'
- '@tanstack/react-start-server@1.159.5':
- resolution: {integrity: sha512-X4/SunwDTEbGkYTfM0gR+79amfk6phAM+2+NlC2s7TX2cD51xE8bUz2a//RxfOh9xg8f0f2CRIO34xTEDHGTfQ==}
- engines: {node: '>=22.12.0'}
- peerDependencies:
- react: '>=18.0.0 || >=19.0.0'
- react-dom: '>=18.0.0 || >=19.0.0'
-
- '@tanstack/react-start@1.159.5':
- resolution: {integrity: sha512-vfnF7eYswAK54ru6Ay08nb0TXVzTBaVRsbbRW7hx2M0chgwtSx+YScYzoixqkccRARQBN8a/CeVq7vNFW8525w==}
+ '@tanstack/react-start@1.141.1':
+ resolution: {integrity: sha512-03iELlg9T9ZN9rKAM1BTCCIBptLbaoZYCZXe0xGf4ZLs3Md+EhmJZibtKluclVQcnjzeiE0T17j1A/YxvVwTZg==}
engines: {node: '>=22.12.0'}
peerDependencies:
react: '>=18.0.0 || >=19.0.0'
@@ -4062,14 +3612,6 @@ packages:
resolution: {integrity: sha512-fR1GGpp6v3dVKu4KIAjEh+Sd0qGLQd/wvCOVHeopSY6aFidXKCzwrS5cBOBqoPPWTKmn6CdW1a0CzFr5Furdog==}
engines: {node: '>=12'}
- '@tanstack/router-core@1.157.16':
- resolution: {integrity: sha512-eJuVgM7KZYTTr4uPorbUzUflmljMVcaX2g6VvhITLnHmg9SBx9RAgtQ1HmT+72mzyIbRSlQ1q0fY/m+of/fosA==}
- engines: {node: '>=12'}
-
- '@tanstack/router-core@1.159.4':
- resolution: {integrity: sha512-MFzPH39ijNO83qJN3pe7x4iAlhZyqgao3sJIzv3SJ4Pnk12xMnzuDzIAQT/1WV6JolPQEcw0Wr4L5agF8yxoeg==}
- engines: {node: '>=12'}
-
'@tanstack/router-devtools-core@1.141.1':
resolution: {integrity: sha512-wD9yRvOk6FI+thiNBplhkGutPIPBlXvWu9ttU/obdFY5oXQj9WYgNS+IO9BEe8Pz5rNEu8zE/oLn4RUGIVdtnw==}
engines: {node: '>=12'}
@@ -4081,16 +3623,6 @@ packages:
csstype:
optional: true
- '@tanstack/router-devtools-core@1.159.4':
- resolution: {integrity: sha512-qMUeIv+6n1mZOcO2raCIbdOeDeMpJEmgm6oMs/nWEG61lYrzJYaCcpBTviAX0nRhSiQSUCX9cHiosUEA0e2HAw==}
- engines: {node: '>=12'}
- peerDependencies:
- '@tanstack/router-core': ^1.159.4
- csstype: ^3.0.10
- peerDependenciesMeta:
- csstype:
- optional: true
-
'@tanstack/router-generator@1.131.50':
resolution: {integrity: sha512-zlMBw5l88GIg3v+378JsfDYq3ejEaJmD3P1R+m0yEPxh0N//Id1FjKNSS7yJbejlK2WGVm9DUG46iBdTDMQM+Q==}
engines: {node: '>=12'}
@@ -4099,10 +3631,6 @@ packages:
resolution: {integrity: sha512-21RbVAoIDn7s/n/PKMN6U60d5hCeVADrBH/uN6B/poMT4MVYtJXqISVzkc2RAboVRw6eRdYFeF+YlwA3nF6y3Q==}
engines: {node: '>=12'}
- '@tanstack/router-generator@1.159.4':
- resolution: {integrity: sha512-O8tICQoSuvK6vs3mvBdI3zVLFmYfj/AYDCX0a5msSADP/2S0GsgDDTB5ah731TqYCtjeNriaWz9iqst38cjF/Q==}
- engines: {node: '>=12'}
-
'@tanstack/router-plugin@1.131.50':
resolution: {integrity: sha512-gdEBPGzx7llQNRnaqfPJ1iaPS3oqB8SlvKRG5l7Fxp4q4yINgkeowFYSKEhPOc9bjoNhGrIHOlvPTPXEzAQXzQ==}
engines: {node: '>=12'}
@@ -4145,36 +3673,8 @@ packages:
webpack:
optional: true
- '@tanstack/router-plugin@1.159.5':
- resolution: {integrity: sha512-i2LR3WRaBOAZ1Uab5QBG9UxZIRJ3V56JVu890NysbuX15rgzRiL5yLAbfenOHdhaHy2+4joX35VICAHuVWy7Og==}
- engines: {node: '>=12'}
- peerDependencies:
- '@rsbuild/core': '>=1.0.2'
- '@tanstack/react-router': ^1.159.5
- vite: '>=5.0.0 || >=6.0.0 || >=7.0.0'
- vite-plugin-solid: ^2.11.10
- webpack: '>=5.92.0'
- peerDependenciesMeta:
- '@rsbuild/core':
- optional: true
- '@tanstack/react-router':
- optional: true
- vite:
- optional: true
- vite-plugin-solid:
- optional: true
- webpack:
- optional: true
-
- '@tanstack/router-ssr-query-core@1.141.1':
- resolution: {integrity: sha512-bkRXUhktifxBewnnphH59E0sGcsUI1NmNqxzCAmXIb93xYgafhjUGGYwfK6FqFBOmCB5isr32exGO3+UMHJr/A==}
- engines: {node: '>=12'}
- peerDependencies:
- '@tanstack/query-core': '>=5.90.0'
- '@tanstack/router-core': '>=1.127.0'
-
- '@tanstack/router-ssr-query-core@1.159.4':
- resolution: {integrity: sha512-zqgJaf8iTk2ugrJqvU+b8NnFf3MKcnFaurtlp5tP38lNHQGW4En9UaOBOou/6zYZMlKQBcvqxSGJiwaLIyTK2g==}
+ '@tanstack/router-ssr-query-core@1.141.1':
+ resolution: {integrity: sha512-bkRXUhktifxBewnnphH59E0sGcsUI1NmNqxzCAmXIb93xYgafhjUGGYwfK6FqFBOmCB5isr32exGO3+UMHJr/A==}
engines: {node: '>=12'}
peerDependencies:
'@tanstack/query-core': '>=5.90.0'
@@ -4188,10 +3688,6 @@ packages:
resolution: {integrity: sha512-/eFGKCiix1SvjxwgzrmH4pHjMiMxc+GA4nIbgEkG2RdAJqyxLcRhd7RPLG0/LZaJ7d0ad3jrtRqsHLv2152Vbw==}
engines: {node: '>=12'}
- '@tanstack/router-utils@1.158.0':
- resolution: {integrity: sha512-qZ76eaLKU6Ae9iI/mc5zizBX149DXXZkBVVO3/QRIll79uKLJZHQlMKR++2ba7JsciBWz1pgpIBcCJPE9S0LVg==}
- engines: {node: '>=12'}
-
'@tanstack/server-functions-plugin@1.131.2':
resolution: {integrity: sha512-hWsaSgEZAVyzHg8+IcJWCEtfI9ZSlNELErfLiGHG9XCHEXMegFWsrESsKHlASzJqef9RsuOLDl+1IMPIskwdDw==}
engines: {node: '>=12'}
@@ -4273,10 +3769,6 @@ packages:
resolution: {integrity: sha512-Rk/b0ekX7p0ZBKOg9WM5c632YPqu7GlvZSYnAjNi1GDp1/sET6g2Trp+GAjs1s8kakp2pMQ4sZUG/11grCMfJw==}
engines: {node: '>=22.12.0'}
- '@tanstack/start-client-core@1.159.4':
- resolution: {integrity: sha512-9j2i1PRTIGcYAD+509znve0ngK81ZUfbX4XCpoNFMaUUpRHoEPPK5I9+PzLFvL9sNOto67x+WULCUggzX+lEKQ==}
- engines: {node: '>=22.12.0'}
-
'@tanstack/start-config@1.120.20':
resolution: {integrity: sha512-oH/mfTSHV8Qbil74tWicPLW6+kKmT3esXCnDzvrkhi3+N8ZuVUDr01Qpil0Wxf9lLPfM5L6VX03nF4hSU8vljg==}
engines: {node: '>=12'}
@@ -4285,10 +3777,6 @@ packages:
react-dom: '>=18.0.0 || >=19.0.0'
vite: ^6.0.0
- '@tanstack/start-fn-stubs@1.154.7':
- resolution: {integrity: sha512-D69B78L6pcFN5X5PHaydv7CScQcKLzJeEYqs7jpuyyqGQHSUIZUjS955j+Sir8cHhuDIovCe2LmsYHeZfWf3dQ==}
- engines: {node: '>=22.12.0'}
-
'@tanstack/start-plugin-core@1.131.50':
resolution: {integrity: sha512-eFvMA0chqLtHbq+8ojp1fXN7AQjhmeoOpQaZaU1d51wb7ugetrn0k3OuHblxtE/O0L4HEC9s4X5zmFJt0vLh0w==}
engines: {node: '>=12'}
@@ -4301,12 +3789,6 @@ packages:
peerDependencies:
vite: '>=7.0.0'
- '@tanstack/start-plugin-core@1.159.5':
- resolution: {integrity: sha512-QGiBw+L3qu2sUY0Tg9KovxjDSi5kevoANEcq9RLX7iIhLkTjrILN6hnAlXZUzqk5Egaf0aN2yWhwI4HWucMprw==}
- engines: {node: '>=22.12.0'}
- peerDependencies:
- vite: '>=7.0.0'
-
'@tanstack/start-server-core@1.131.50':
resolution: {integrity: sha512-3SWwwhW2GKMhPSaqWRal6Jj1Y9ObfdWEXKFQid1LBuk5xk/Es4bmW68o++MbVgs/GxUxyeZ3TRVqb0c7RG1sog==}
engines: {node: '>=12'}
@@ -4315,10 +3797,6 @@ packages:
resolution: {integrity: sha512-Qk/lZ/+iGUyNYeAAuj89bLR6GXLD/9BIpAR2CUwlS+xXGL0kQmOFcb1UvccWZ2QwtW+csxJW4NeQOeMuqsfyhA==}
engines: {node: '>=22.12.0'}
- '@tanstack/start-server-core@1.159.4':
- resolution: {integrity: sha512-sGpr+iil+pcY3Gglvbnxaj7fCEPTQJv4oF7YA24SVv8YvayLXtBXpF26miJLA+KR9P31dQdPYe1gTjv5zRyvHg==}
- engines: {node: '>=22.12.0'}
-
'@tanstack/start-server-functions-client@1.131.50':
resolution: {integrity: sha512-4aM17fFdVAFH6uLPswKJxzrhhIjcCwKqzfTcgY3OnhUKnaZBTQwJA+nUHQCI6IWvEvrcrNVtFTtv13TkDk3YMw==}
engines: {node: '>=12'}
@@ -4347,10 +3825,6 @@ packages:
resolution: {integrity: sha512-UPOQd4qsytgmc+pHeeS3oIZQazhyGAmEaCS/IrZI42TzpuVh2ZbLVssKEoDziheNP1dH5KT2lsL1bU9asAw7tA==}
engines: {node: '>=22.12.0'}
- '@tanstack/start-storage-context@1.159.4':
- resolution: {integrity: sha512-iGkmuCIq3PLI4GKOGwgUNHQKZ13YV8LGq62o2hVnyXE64Jm2SP7c5z6D1ndydpk4JwdRzQKlcOFT/1agvS6Nsg==}
- engines: {node: '>=22.12.0'}
-
'@tanstack/start@1.120.20':
resolution: {integrity: sha512-fQO+O/5xJpli5KlV6pwDz6DtpbqO/0atdVSyVnkemzk0Mej9azm4HXtw+cKkIPtsSplWs4B1EbMtgGMb9ADhSA==}
engines: {node: '>=12'}
@@ -4373,10 +3847,6 @@ packages:
resolution: {integrity: sha512-CJrWtr6L9TVzEImm9S7dQINx+xJcYP/aDkIi6gnaWtIgbZs1pnzsE0yJc2noqXZ+yAOqLx3TBGpBEs9tS0P9/A==}
engines: {node: '>=12'}
- '@tanstack/virtual-file-routes@1.154.7':
- resolution: {integrity: sha512-cHHDnewHozgjpI+MIVp9tcib6lYEQK5MyUr0ChHpHFGBl8Xei55rohFK0I0ve/GKoHeioaK42Smd8OixPp6CTg==}
- engines: {node: '>=12'}
-
'@tanstack/vite-config@0.4.1':
resolution: {integrity: sha512-FOl8EF6SAcljanKSm5aBeJaflFcxQAytTbxtNW8HC6D4x+UBW68IC4tBcrlrsI0wXHBmC/Gz4Ovvv8qCtiXSgQ==}
engines: {node: '>=18'}
@@ -4452,6 +3922,9 @@ packages:
'@types/deep-eql@4.0.2':
resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==}
+ '@types/dom-mediacapture-record@1.0.22':
+ resolution: {integrity: sha512-mUMZLK3NvwRLcAAT9qmcK+9p7tpU2FHdDsntR3YI4+GY88XrgG4XiE7u1Q2LAN2/FZOz/tdMDC3GQCR4T8nFuw==}
+
'@types/estree-jsx@1.0.5':
resolution: {integrity: sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==}
@@ -4473,15 +3946,9 @@ packages:
'@types/ms@2.1.0':
resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==}
- '@types/node-fetch@2.6.13':
- resolution: {integrity: sha512-QGpRVpzSaUs30JBSGPjOg4Uveu384erbHBoT1zeONvyCfwQxIkUshLAOqN/k9EjGviPRmWTTe6aH2qySWKTVSw==}
-
'@types/node@12.20.55':
resolution: {integrity: sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==}
- '@types/node@18.19.130':
- resolution: {integrity: sha512-GRaXQx6jGfL8sKfaIDD6OupbIHBr9jv7Jnaml9tB7l4v068PAOXqfcujMMo5PhbIs6ggR1XODELqahT2R8v0fg==}
-
'@types/node@20.19.26':
resolution: {integrity: sha512-0l6cjgF0XnihUpndDhk+nyD3exio3iKaYROSgvh/qSevPXax3L8p5DBRFjbvalnwatGgHEQn2R88y2fA3g4irg==}
@@ -4502,9 +3969,6 @@ packages:
'@types/resolve@1.20.2':
resolution: {integrity: sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==}
- '@types/retry@0.12.0':
- resolution: {integrity: sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==}
-
'@types/unist@2.0.11':
resolution: {integrity: sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==}
@@ -4679,11 +4143,6 @@ packages:
engines: {node: '>=18'}
hasBin: true
- '@vercel/nft@1.3.0':
- resolution: {integrity: sha512-i4EYGkCsIjzu4vorDUbqglZc5eFtQI2syHb++9ZUDm6TU4edVywGpVnYDein35x9sevONOn9/UabfQXuNXtuzQ==}
- engines: {node: '>=20'}
- hasBin: true
-
'@vinxi/listhen@1.5.6':
resolution: {integrity: sha512-WSN1z931BtasZJlgPp704zJFnQFRg7yzSjkm3MzAWQYe4uXFXlFr1hc5Ac2zae5/HDOz5x1/zDM5Cb54vTCnWw==}
hasBin: true
@@ -4719,8 +4178,8 @@ packages:
'@vitest/expect@4.0.15':
resolution: {integrity: sha512-Gfyva9/GxPAWXIWjyGDli9O+waHDC0Q0jaLdFP1qPAUUfo1FEXPXUfUkp3eZA0sSq340vPycSyOlYUeM15Ft1w==}
- '@vitest/expect@4.0.18':
- resolution: {integrity: sha512-8sCWUyckXXYvx4opfzVY03EOiYVxyNrHS5QxX3DAIi5dpJAAkyJezHCP77VMX4HKA2LDT/Jpfo8i2r5BE3GnQQ==}
+ '@vitest/expect@4.0.17':
+ resolution: {integrity: sha512-mEoqP3RqhKlbmUmntNDDCJeTDavDR+fVYkSOw8qRwJFaW/0/5zA9zFeTrHqNtcmwh6j26yMmwx2PqUDPzt5ZAQ==}
'@vitest/mocker@4.0.15':
resolution: {integrity: sha512-CZ28GLfOEIFkvCFngN8Sfx5h+Se0zN+h4B7yOsPVCcgtiO7t5jt9xQh2E1UkFep+eb9fjyMfuC5gBypwb07fvQ==}
@@ -4733,8 +4192,8 @@ packages:
vite:
optional: true
- '@vitest/mocker@4.0.18':
- resolution: {integrity: sha512-HhVd0MDnzzsgevnOWCBj5Otnzobjy5wLBe4EdeeFGv8luMsGcYqDuFRMcttKWZA5vVO8RFjexVovXvAM4JoJDQ==}
+ '@vitest/mocker@4.0.17':
+ resolution: {integrity: sha512-+ZtQhLA3lDh1tI2wxe3yMsGzbp7uuJSWBM1iTIKCbppWTSBN09PUC+L+fyNlQApQoR+Ps8twt2pbSSXg2fQVEQ==}
peerDependencies:
msw: ^2.4.9
vite: ^6.0.0 || ^7.0.0-0
@@ -4750,26 +4209,26 @@ packages:
'@vitest/pretty-format@4.0.15':
resolution: {integrity: sha512-SWdqR8vEv83WtZcrfLNqlqeQXlQLh2iilO1Wk1gv4eiHKjEzvgHb2OVc3mIPyhZE6F+CtfYjNlDJwP5MN6Km7A==}
- '@vitest/pretty-format@4.0.18':
- resolution: {integrity: sha512-P24GK3GulZWC5tz87ux0m8OADrQIUVDPIjjj65vBXYG17ZeU3qD7r+MNZ1RNv4l8CGU2vtTRqixrOi9fYk/yKw==}
+ '@vitest/pretty-format@4.0.17':
+ resolution: {integrity: sha512-Ah3VAYmjcEdHg6+MwFE17qyLqBHZ+ni2ScKCiW2XrlSBV4H3Z7vYfPfz7CWQ33gyu76oc0Ai36+kgLU3rfF4nw==}
'@vitest/runner@4.0.15':
resolution: {integrity: sha512-+A+yMY8dGixUhHmNdPUxOh0la6uVzun86vAbuMT3hIDxMrAOmn5ILBHm8ajrqHE0t8R9T1dGnde1A5DTnmi3qw==}
- '@vitest/runner@4.0.18':
- resolution: {integrity: sha512-rpk9y12PGa22Jg6g5M3UVVnTS7+zycIGk9ZNGN+m6tZHKQb7jrP7/77WfZy13Y/EUDd52NDsLRQhYKtv7XfPQw==}
+ '@vitest/runner@4.0.17':
+ resolution: {integrity: sha512-JmuQyf8aMWoo/LmNFppdpkfRVHJcsgzkbCA+/Bk7VfNH7RE6Ut2qxegeyx2j3ojtJtKIbIGy3h+KxGfYfk28YQ==}
'@vitest/snapshot@4.0.15':
resolution: {integrity: sha512-A7Ob8EdFZJIBjLjeO0DZF4lqR6U7Ydi5/5LIZ0xcI+23lYlsYJAfGn8PrIWTYdZQRNnSRlzhg0zyGu37mVdy5g==}
- '@vitest/snapshot@4.0.18':
- resolution: {integrity: sha512-PCiV0rcl7jKQjbgYqjtakly6T1uwv/5BQ9SwBLekVg/EaYeQFPiXcgrC2Y7vDMA8dM1SUEAEV82kgSQIlXNMvA==}
+ '@vitest/snapshot@4.0.17':
+ resolution: {integrity: sha512-npPelD7oyL+YQM2gbIYvlavlMVWUfNNGZPcu0aEUQXt7FXTuqhmgiYupPnAanhKvyP6Srs2pIbWo30K0RbDtRQ==}
'@vitest/spy@4.0.15':
resolution: {integrity: sha512-+EIjOJmnY6mIfdXtE/bnozKEvTC4Uczg19yeZ2vtCz5Yyb0QQ31QWVQ8hswJ3Ysx/K2EqaNsVanjr//2+P3FHw==}
- '@vitest/spy@4.0.18':
- resolution: {integrity: sha512-cbQt3PTSD7P2OARdVW3qWER5EGq7PHlvE+QfzSC0lbwO+xnt7+XH06ZzFjFRgzUX//JmpxrCu92VdwvEPlWSNw==}
+ '@vitest/spy@4.0.17':
+ resolution: {integrity: sha512-I1bQo8QaP6tZlTomQNWKJE6ym4SHf3oLS7ceNjozxxgzavRAgZDc06T7kD8gb9bXKEgcLNt00Z+kZO6KaJ62Ew==}
'@vitest/utils@4.0.14':
resolution: {integrity: sha512-hLqXZKAWNg8pI+SQXyXxWCTOpA3MvsqcbVeNgSi8x/CSN2wi26dSzn1wrOhmCmFjEvN9p8/kLFRHa6PI8jHazw==}
@@ -4777,8 +4236,8 @@ packages:
'@vitest/utils@4.0.15':
resolution: {integrity: sha512-HXjPW2w5dxhTD0dLwtYHDnelK3j8sR8cWIaLxr22evTyY6q8pRCjZSmhRWVjBaOVXChQd6AwMzi9pucorXCPZA==}
- '@vitest/utils@4.0.18':
- resolution: {integrity: sha512-msMRKLMVLWygpK3u2Hybgi4MNjcYJvwTb0Ru09+fOyCXIgT5raYP041DRRdiJiI3k/2U6SEbAETB3YtBrUkCFA==}
+ '@vitest/utils@4.0.17':
+ resolution: {integrity: sha512-RG6iy+IzQpa9SB8HAFHJ9Y+pTzI+h8553MrciN9eC6TFBErqrQaTas4vG+MVj8S4uKk8uTT2p0vgZPnTdxd96w==}
'@volar/language-core@2.4.15':
resolution: {integrity: sha512-3VHw+QZU0ZG9IuQmzT68IyN4hZNd9GchGPhbD9+pa8CVv7rnoOZwo7T8weIbrRmihqy3ATpdfXFnqRrfPVK6CA==}
@@ -4894,10 +4353,6 @@ packages:
resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==}
engines: {node: '>= 14'}
- agentkeepalive@4.6.0:
- resolution: {integrity: sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ==}
- engines: {node: '>= 8.0.0'}
-
ajv-draft-04@1.0.0:
resolution: {integrity: sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw==}
peerDependencies:
@@ -4957,9 +4412,6 @@ packages:
resolution: {integrity: sha512-HqZ5rWlFjGiV0tDm3UxxgNRqsOTniqoKZu0pIAfh7TZQMGuZK+hH0drySty0si0QXj1ieop4+SkSfPZBPPkHig==}
engines: {node: '>=14'}
- any-promise@1.3.0:
- resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==}
-
anymatch@3.1.3:
resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==}
engines: {node: '>= 8'}
@@ -5008,8 +4460,8 @@ packages:
resolution: {integrity: sha512-6t10qk83GOG8p0vKmaCr8eiilZwO171AvbROMtvvNiwrTly62t+7XkA8RdIIVbpMhCASAsxgAzdRSwh6nw/5Dg==}
engines: {node: '>=4'}
- ast-v8-to-istanbul@0.3.11:
- resolution: {integrity: sha512-Qya9fkoofMjCBNVdWINMjB5KZvkYfaO9/anwkWnjxibpWUxo5iHl2sOdP7/uAqaRuUYuoo8rDwnbaaKVFxoUvw==}
+ ast-v8-to-istanbul@0.3.8:
+ resolution: {integrity: sha512-szgSZqUxI5T8mLKvS7WTjF9is+MVbOeLADU73IseOcrqhxr/VAvy6wfoVE39KnKzA7JRhjF5eUagNlHwvZPlKQ==}
async-sema@3.1.1:
resolution: {integrity: sha512-tLRNUXati5MFePdAk8dw7Qt7DpxPB60ofAgn8WRhW6a2rcimZnYBP9oxHiv0OHy+Wz7kPMG+t4LGdt31+4EmGg==}
@@ -5049,9 +4501,6 @@ packages:
babel-dead-code-elimination@1.0.10:
resolution: {integrity: sha512-DV5bdJZTzZ0zn0DC24v3jD7Mnidh6xhKa4GfKCbq3sfW8kaWhDdZjP3i81geA8T33tdYqWKw4D3fVv0CwEgKVA==}
- babel-dead-code-elimination@1.0.12:
- resolution: {integrity: sha512-GERT7L2TiYcYDtYk1IpD+ASAYXjKbLTDPhBtYj7X1NuRMDTMtAx9kyBenub1Ev41lo91OHCKdmP+egTDmfQ7Ig==}
-
babel-plugin-jsx-dom-expressions@0.40.3:
resolution: {integrity: sha512-5HOwwt0BYiv/zxl7j8Pf2bGL6rDXfV6nUhLs8ygBX+EFJXzBPHM/euj9j/6deMZ6wa52Wb2PBaAV5U/jKwIY1w==}
peerDependencies:
@@ -5152,12 +4601,6 @@ packages:
buffer@6.0.3:
resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==}
- bundle-require@5.1.0:
- resolution: {integrity: sha512-3WrrOuZiyaaZPWiEt4G3+IffISVC9HYlWueJEBWED4ZH4aIAC2PnkdnuRrR94M+w6yGWn4AglWtJtBI8YqvgoA==}
- engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
- peerDependencies:
- esbuild: '>=0.18'
-
bytes@3.1.2:
resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==}
engines: {node: '>= 0.8'}
@@ -5170,14 +4613,6 @@ packages:
magicast:
optional: true
- c12@3.3.3:
- resolution: {integrity: sha512-750hTRvgBy5kcMNPdh95Qo+XUBeGo8C7nsKSmedDmaQI+E0r82DwHeM6vBewDe4rGFbnxoa4V9pw+sPh5+Iz8Q==}
- peerDependencies:
- magicast: '*'
- peerDependenciesMeta:
- magicast:
- optional: true
-
cac@6.7.14:
resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==}
engines: {node: '>=8'}
@@ -5329,10 +4764,6 @@ packages:
commander@2.20.3:
resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==}
- commander@4.1.1:
- resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==}
- engines: {node: '>= 6'}
-
comment-parser@1.4.1:
resolution: {integrity: sha512-buhp5kePrmda3vhc5B9t7pUQXAb2Tnd0qgpkIhPhkHXxJpiPJ11H0ZEU0oBpJ2QztSbzG/ZxMj/CHsYJqRHmyg==}
engines: {node: '>= 12.0.0'}
@@ -5426,14 +4857,6 @@ packages:
crossws@0.3.5:
resolution: {integrity: sha512-ojKiDvcmByhwa8YYqbQI/hg7MEU0NC03+pSdEq4ZUnZR9xXpwk7E43SMNGkn+JxJGPFtNvQ48+vV2p+P1ml5PA==}
- crossws@0.4.4:
- resolution: {integrity: sha512-w6c4OdpRNnudVmcgr7brb/+/HmYjMQvYToO/oTrprTwxRUiom3LYWU1PMWuD006okbUWpII1Ea9/+kwpUfmyRg==}
- peerDependencies:
- srvx: '>=0.7.1'
- peerDependenciesMeta:
- srvx:
- optional: true
-
css-select@5.2.2:
resolution: {integrity: sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==}
@@ -5467,9 +4890,6 @@ packages:
resolution: {integrity: sha512-gpuGEkBQM+5y6p4cWaw9+ePy5TNon+fdwFVtTI8leU3UhwhsBfPewRxMXGuQNC+M2b/MDGMlfgpqynkcd0C3FQ==}
deprecated: This package has moved to simply be 'dax' instead of 'dax-sh'
- dayjs@1.11.19:
- resolution: {integrity: sha512-t5EcLVS6QPBNqM2z8fakk/NKel+Xzshgt8FFKAn+qwlD1pzZWxh0nVCrvFK7ZDb6XucZeF9z8C7CBWTRIVApAw==}
-
db0@0.3.4:
resolution: {integrity: sha512-RiXXi4WaNzPTHEOu8UPQKMooIbqOEyqA1t7Z6MsdxSCeb8iUC9ko3LcmsLmeUt2SM5bctfArZKkRQggKZz7JNw==}
peerDependencies:
@@ -5739,12 +5159,6 @@ packages:
resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==}
engines: {node: '>= 0.4'}
- esbuild-plugin-solid@0.5.0:
- resolution: {integrity: sha512-ITK6n+0ayGFeDVUZWNMxX+vLsasEN1ILrg4pISsNOQ+mq4ljlJJiuXotInd+HE0MzwTcA9wExT1yzDE2hsqPsg==}
- peerDependencies:
- esbuild: '>=0.12'
- solid-js: '>= 1.0'
-
esbuild@0.20.2:
resolution: {integrity: sha512-WdOOppmUNU+IbZ0PaDiTst80zjnrOkyJNHoKupIcVyU8Lvla3Ugx94VzkQ32Ijqd7UhHJy75gNWDMUekcrSJ6g==}
engines: {node: '>=12'}
@@ -5755,13 +5169,13 @@ packages:
engines: {node: '>=18'}
hasBin: true
- esbuild@0.27.2:
- resolution: {integrity: sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw==}
+ esbuild@0.27.1:
+ resolution: {integrity: sha512-yY35KZckJJuVVPXpvjgxiCuVEJT67F6zDeVTv4rizyPrfGBUpZQsvmxnN+C371c2esD/hNMjj4tpBhuueLN7aA==}
engines: {node: '>=18'}
hasBin: true
- esbuild@0.27.3:
- resolution: {integrity: sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==}
+ esbuild@0.27.2:
+ resolution: {integrity: sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw==}
engines: {node: '>=18'}
hasBin: true
@@ -5934,10 +5348,6 @@ packages:
resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==}
engines: {node: '>=0.8.x'}
- eventsource-parser@1.1.2:
- resolution: {integrity: sha512-v0eOBUbiaFojBu2s2NPBfYUoRR9GjcDNvCXVaqEf5vVfpIAh9f8RCo4vXTP8c63QRKCFwoLpMpTdPwwhEKVgzA==}
- engines: {node: '>=14.18'}
-
execa@8.0.1:
resolution: {integrity: sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==}
engines: {node: '>=16.17'}
@@ -6024,9 +5434,6 @@ packages:
resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==}
engines: {node: '>=10'}
- fix-dts-default-cjs-exports@1.0.1:
- resolution: {integrity: sha512-pVIECanWFC61Hzl2+oOCtoJ3F17kglZC/6N94eRWycFgBH35hHx0Li604ZIzhseh97mf2p0cv7vVrOZGoqhlEg==}
-
flat-cache@4.0.1:
resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==}
engines: {node: '>=16'}
@@ -6055,9 +5462,6 @@ packages:
resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==}
engines: {node: '>=14'}
- form-data-encoder@1.7.2:
- resolution: {integrity: sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A==}
-
form-data@4.0.5:
resolution: {integrity: sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==}
engines: {node: '>= 6'}
@@ -6067,10 +5471,6 @@ packages:
engines: {node: '>=18.3.0'}
hasBin: true
- formdata-node@4.4.1:
- resolution: {integrity: sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ==}
- engines: {node: '>= 12.20'}
-
formdata-polyfill@4.0.10:
resolution: {integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==}
engines: {node: '>=12.20.0'}
@@ -6168,13 +5568,8 @@ packages:
glob@10.5.0:
resolution: {integrity: sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==}
- deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me
hasBin: true
- glob@13.0.0:
- resolution: {integrity: sha512-tvZgpqk6fz4BaNZ66ZsRaZnbHvP/jG3uKJvAZOwEVUL4RTA5nJeeLYfyN9/VA8NX/V3IBG+hkeuGpKjvELkVhA==}
- engines: {node: 20 || >=22}
-
globals@14.0.0:
resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==}
engines: {node: '>=18'}
@@ -6195,10 +5590,6 @@ packages:
resolution: {integrity: sha512-oB4vkQGqlMl682wL1IlWd02tXCbquGWM4voPEI85QmNKCaw8zGTm1f1rubFgkg3Eli2PtKlFgrnmUqasbQWlkw==}
engines: {node: '>=20'}
- globby@16.1.0:
- resolution: {integrity: sha512-+A4Hq7m7Ze592k9gZRy4gJ27DrXRNnC1vPjxTt1qQxEY8RxagBkBxivkCwg7FxSTG0iLLEMaUx13oOr0R2/qcQ==}
- engines: {node: '>=20'}
-
globrex@0.1.2:
resolution: {integrity: sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==}
@@ -6222,9 +5613,6 @@ packages:
graceful-fs@4.2.11:
resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==}
- groq-sdk@0.37.0:
- resolution: {integrity: sha512-lT72pcT8b/X5XrzdKf+rWVzUGW1OQSKESmL8fFN5cTbsf02gq6oFam4SVeNtzELt9cYE2Pt3pdGgSImuTbHFDg==}
-
gtoken@8.0.0:
resolution: {integrity: sha512-+CqsMbHPiSTdtSO14O51eMNlrp9N79gmeqmXeouJOhfucAedHw9noVe/n5uJk3tbKE6a+6ZCQg3RPhVhHByAIw==}
engines: {node: '>=18'}
@@ -6236,8 +5624,8 @@ packages:
h3@1.13.0:
resolution: {integrity: sha512-vFEAu/yf8UMUcB4s43OaDaigcqpQd14yanmOsn+NcRX3/guSKncyE2rOYhq8RIchgJrPSs/QiIddnTTR1ddiAg==}
- h3@1.15.5:
- resolution: {integrity: sha512-xEyq3rSl+dhGX2Lm0+eFQIAzlDN6Fs0EcC4f7BNUmzaRX/PTzeuM+Tr2lHB8FoXggsQIeXLj8EDVgs5ywxyxmg==}
+ h3@1.15.4:
+ resolution: {integrity: sha512-z5cFQWDffyOe4vQ9xIqNfCZdV4p//vy6fBnr8Q1AWnVZ0teurKMG66rLj++TKwKPUP3u7iMUvrvKaEUiQw2QWQ==}
h3@2.0.0-beta.5:
resolution: {integrity: sha512-ApIkLH+nTxzCC0Nq/GN1v6jkvu2eOLfdTnTs6ghiuG1EYHWJBDLzhk5tn7SZMEUNsLUjG4qfmqzBx2LG9I7Q/w==}
@@ -6248,16 +5636,6 @@ packages:
crossws:
optional: true
- h3@2.0.1-rc.14:
- resolution: {integrity: sha512-163qbGmTr/9rqQRNuqMqtgXnOUAkE4KTdauiC9y0E5iG1I65kte9NyfWvZw5RTDMt6eY+DtyoNzrQ9wA2BfvGQ==}
- engines: {node: '>=20.11.1'}
- hasBin: true
- peerDependencies:
- crossws: ^0.4.1
- peerDependenciesMeta:
- crossws:
- optional: true
-
happy-dom@20.0.11:
resolution: {integrity: sha512-QsCdAUHAmiDeKeaNojb1OHOPF7NjcWPBR7obdu3NwH2a/oyQaLg5d0aaCy/9My6CdPChYF07dvz5chaXBGaD4g==}
engines: {node: '>=20.0.0'}
@@ -6387,9 +5765,6 @@ packages:
resolution: {integrity: sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==}
engines: {node: '>=16.17.0'}
- humanize-ms@1.2.1:
- resolution: {integrity: sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==}
-
iconv-lite@0.6.3:
resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==}
engines: {node: '>=0.10.0'}
@@ -6448,10 +5823,6 @@ packages:
resolution: {integrity: sha512-C6uC+kleiIMmjViJINWk80sOQw5lEzse1ZmvD+S/s8p8CWapftSaC+kocGTx6xrbrJ4WmYQGC08ffHLr6ToR6Q==}
engines: {node: '>=12.22.0'}
- ioredis@5.9.2:
- resolution: {integrity: sha512-tAAg/72/VxOUW7RQSX1pIxJVucYKcjFjfvj60L57jrZpYCHC3XN0WCQ3sNYL4Gmvv+7GPvTAjc+KSdeNuE8oWQ==}
- engines: {node: '>=12.22.0'}
-
ipaddr.js@1.9.1:
resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==}
engines: {node: '>= 0.10'}
@@ -6553,10 +5924,6 @@ packages:
resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==}
engines: {node: '>=0.12.0'}
- is-path-inside@4.0.0:
- resolution: {integrity: sha512-lJJV/5dYS+RcL8uQdBDW9c9uWFLLBNRyFhnAKXw5tVqLlKZ4RMGZKv+YQ/IA3OhD+RpbJa1LLFM1FQPGyIXvOA==}
- engines: {node: '>=12'}
-
is-plain-obj@4.1.0:
resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==}
engines: {node: '>=12'}
@@ -6688,9 +6055,8 @@ packages:
jju@1.4.0:
resolution: {integrity: sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA==}
- joycon@3.1.1:
- resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==}
- engines: {node: '>=10'}
+ jose@6.1.3:
+ resolution: {integrity: sha512-0TpaTfihd4QMNwrz/ob2Bp7X04yuxJkjRGi4aKmOqwhov54i6u79oCv7T+C7lo70MKH6BesI3vscD1yb/yzKXQ==}
js-beautify@1.15.4:
resolution: {integrity: sha512-9/KXeZUKKJwqCXUdBxFJ3vPh467OCckSBmYDwSK/EtV090K+iMJ7zx2S3HLVDIWFQdqMIsZWbnaGiba18aWhaA==}
@@ -6701,9 +6067,6 @@ packages:
resolution: {integrity: sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==}
engines: {node: '>=14'}
- js-tokens@10.0.0:
- resolution: {integrity: sha512-lM/UBzQmfJRo9ABXbPWemivdCW8V2G8FHaHdypQaIy523snUjog0W71ayWXTjiR+ixeMyVHN2XcpnTd/liPg/Q==}
-
js-tokens@4.0.0:
resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
@@ -6884,13 +6247,6 @@ packages:
resolution: {integrity: sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ==}
engines: {node: '>= 12.0.0'}
- lilconfig@3.1.3:
- resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==}
- engines: {node: '>=14'}
-
- lines-and-columns@1.2.4:
- resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==}
-
lines-and-columns@2.0.3:
resolution: {integrity: sha512-cNOjgCnLB+FnvWWtyRTzmB3POJ+cXxTA81LoW7u8JdmhfXzriropYwpjShnz1QLLWsQwY7nIxoDmcPTwphDK9w==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
@@ -6902,9 +6258,10 @@ packages:
resolution: {integrity: sha512-I8oW2+QL5KJo8zXNWX046M134WchxsXC7SawLPvRQpogCbkyQIaFxPE89A2HiwR7vAK2Dm2ERBAmyjTYGYEpBg==}
hasBin: true
- load-tsconfig@0.2.5:
- resolution: {integrity: sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg==}
- engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+ livekit-client@2.17.0:
+ resolution: {integrity: sha512-BD1QUS44ancVTBdnAher0aO7DV5holFYH2lYradYT/HgXtn6R8xPyvtDAH3UH40jGcesDo9fEopCFwEdOgrIhg==}
+ peerDependencies:
+ '@types/dom-mediacapture-record': ^1
local-pkg@0.5.1:
resolution: {integrity: sha512-9rrA30MRRP3gBD3HTGnC6cDFpaE1kVDWxWgqWJUN0RvDNAo+Nz/9GxB+nHOH0ifbVFy0hSA1V6vFDvnx54lTEQ==}
@@ -6944,8 +6301,9 @@ packages:
resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==}
engines: {node: '>=10'}
- long@5.3.2:
- resolution: {integrity: sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==}
+ loglevel@1.9.2:
+ resolution: {integrity: sha512-HgMmCqIJSAKqo68l0rS2AanEWfkxaZ5wNiEFb5ggm08lDs9Xl2KxBlX3PTcaD2chBM1gXAYf491/M2Rv8Jwayg==}
+ engines: {node: '>= 0.6.0'}
longest-streak@3.1.0:
resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==}
@@ -6992,8 +6350,8 @@ packages:
magic-string@0.30.21:
resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==}
- magicast@0.5.2:
- resolution: {integrity: sha512-E3ZJh4J3S9KfwdjZhe2afj6R9lGIN5Pher1pF39UGrXRqq/VDaGVIGN13BjHd2u8B61hArAGOnso7nBOouW3TQ==}
+ magicast@0.5.1:
+ resolution: {integrity: sha512-xrHS24IxaLrvuo613F719wvOIv9xPHFWQHuvGUBmPnCA/3MQxKI3b+r7n1jAoDHmsbC5bRhTZYR77invLAxVnw==}
make-dir@4.0.0:
resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==}
@@ -7282,9 +6640,6 @@ packages:
muggle-string@0.4.1:
resolution: {integrity: sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==}
- mz@2.7.0:
- resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==}
-
nanoid@3.3.11:
resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==}
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
@@ -7302,28 +6657,6 @@ packages:
resolution: {integrity: sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==}
engines: {node: '>= 0.6'}
- nf3@0.3.10:
- resolution: {integrity: sha512-UlqmHkZiHGgSkRj17yrOXEsSu5ECvtlJ3Xm1W5WsWrTKgu9m7OjrMZh9H/ME2LcWrTlMD0/vmmNVpyBG4yRdGg==}
-
- nitro@3.0.1-alpha.2:
- resolution: {integrity: sha512-YviDY5J/trS821qQ1fpJtpXWIdPYiOizC/meHavlm1Hfuhx//H+Egd1+4C5SegJRgtWMnRPW9n//6Woaw81cTQ==}
- engines: {node: ^20.19.0 || >=22.12.0}
- hasBin: true
- peerDependencies:
- rolldown: '>=1.0.0-beta.0'
- rollup: ^4
- vite: ^7 || ^8 || >=8.0.0-0
- xml2js: ^0.6.2
- peerDependenciesMeta:
- rolldown:
- optional: true
- rollup:
- optional: true
- vite:
- optional: true
- xml2js:
- optional: true
-
nitropack@2.12.9:
resolution: {integrity: sha512-t6qqNBn2UDGMWogQuORjbL2UPevB8PvIPsPHmqvWpeGOlPr4P8Oc5oA8t3wFwGmaolM2M/s2SwT23nx9yARmOg==}
engines: {node: ^20.19.0 || >=22.12.0}
@@ -7334,16 +6667,6 @@ packages:
xml2js:
optional: true
- nitropack@2.13.1:
- resolution: {integrity: sha512-2dDj89C4wC2uzG7guF3CnyG+zwkZosPEp7FFBGHB3AJo11AywOolWhyQJFHDzve8COvGxJaqscye9wW2IrUsNw==}
- engines: {node: ^20.19.0 || >=22.12.0}
- hasBin: true
- peerDependencies:
- xml2js: ^0.6.2
- peerDependenciesMeta:
- xml2js:
- optional: true
-
node-addon-api@7.1.1:
resolution: {integrity: sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==}
@@ -7431,10 +6754,6 @@ packages:
engines: {node: ^14.16.0 || >=16.10.0}
hasBin: true
- object-assign@4.1.1:
- resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
- engines: {node: '>=0.10.0'}
-
object-inspect@1.13.4:
resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==}
engines: {node: '>= 0.4'}
@@ -7457,9 +6776,6 @@ packages:
ofetch@1.5.1:
resolution: {integrity: sha512-2W4oUZlVaqAPAil6FUg/difl6YhqhUR7x2eZY4bQCko22UXg3hptq9KLQdqFClV+Wu85UX7hNtdGTngi/1BxcA==}
- ofetch@2.0.0-alpha.3:
- resolution: {integrity: sha512-zpYTCs2byOuft65vI3z43Dd6iSdFbOZZLb9/d21aCpx2rGastVU9dOCv0lu4ykc1Ur1anAYjDi3SUvR0vq50JA==}
-
ohash@1.1.6:
resolution: {integrity: sha512-TBu7PtV8YkAZn0tSxobKY2n2aAQva936lhRrj6957aDaCf9IEtqsKbgMzXE/F/sjqYOwmrukeORHNLe5glk7Cg==}
@@ -7511,17 +6827,9 @@ packages:
outdent@0.5.0:
resolution: {integrity: sha512-/jHxFIzoMXdqPzTaCpFzAAWhpkSjZPF4Vsn6jAfNpmbH/ymsmd7Qc6VE9BGn0L6YMj6uwpQLxCECpus4ukKS9Q==}
- oxc-minify@0.110.0:
- resolution: {integrity: sha512-KWGTzPo83QmGrXC4ml83PM9HDwUPtZFfasiclUvTV4i3/0j7xRRqINVkrL77CbQnoWura3CMxkRofjQKVDuhBw==}
- engines: {node: ^20.19.0 || >=22.12.0}
-
oxc-resolver@11.15.0:
resolution: {integrity: sha512-Hk2J8QMYwmIO9XTCUiOH00+Xk2/+aBxRUnhrSlANDyCnLYc32R1WSIq1sU2yEdlqd53FfMpPEpnBYIKQMzliJw==}
- oxc-transform@0.110.0:
- resolution: {integrity: sha512-/fymQNzzUoKZweH0nC5yvbI2eR0yWYusT9TEKDYVgOgYrf9Qmdez9lUFyvxKR9ycx+PTHi/reIOzqf3wkShQsw==}
- engines: {node: ^20.19.0 || >=22.12.0}
-
p-filter@2.1.0:
resolution: {integrity: sha512-ZBxxZ5sL2HghephhpGAQdoskxplTwr7ICaehZwLIlfL6acuVgZPm8yBNuRAFBGEqtD/hmUeq9eqLg2ys9Xr/yw==}
engines: {node: '>=8'}
@@ -7546,10 +6854,6 @@ packages:
resolution: {integrity: sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==}
engines: {node: '>=6'}
- p-retry@4.6.2:
- resolution: {integrity: sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==}
- engines: {node: '>=8'}
-
p-try@2.2.0:
resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==}
engines: {node: '>=6'}
@@ -7611,10 +6915,6 @@ packages:
resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==}
engines: {node: '>=16 || 14 >=14.18'}
- path-scurry@2.0.1:
- resolution: {integrity: sha512-oWyT4gICAu+kaA7QWk/jvCHWarMKNs6pXOGWKDTr7cw4IGcUbW+PeTfbaQiLGheFRpjo6O9J0PmyMfQPjH71oA==}
- engines: {node: 20 || >=22}
-
path-to-regexp@6.3.0:
resolution: {integrity: sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==}
@@ -7653,10 +6953,6 @@ packages:
resolution: {integrity: sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==}
engines: {node: '>=6'}
- pirates@4.0.7:
- resolution: {integrity: sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==}
- engines: {node: '>= 6'}
-
pkg-types@1.3.1:
resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==}
@@ -7677,24 +6973,6 @@ packages:
resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==}
engines: {node: '>= 0.4'}
- postcss-load-config@6.0.1:
- resolution: {integrity: sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==}
- engines: {node: '>= 18'}
- peerDependencies:
- jiti: '>=1.21.0'
- postcss: '>=8.0.9'
- tsx: ^4.8.1
- yaml: ^2.4.2
- peerDependenciesMeta:
- jiti:
- optional: true
- postcss:
- optional: true
- tsx:
- optional: true
- yaml:
- optional: true
-
postcss-value-parser@4.2.0:
resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==}
@@ -7761,10 +7039,6 @@ packages:
proto-list@1.2.4:
resolution: {integrity: sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==}
- protobufjs@7.5.4:
- resolution: {integrity: sha512-CvexbZtbov6jW2eXAvLukXjXUW1TzFaivC46BpWc/3BpcCysb5Vffu+B3XHMm8lVEuy2Mm4XGex8hBSg1yapPg==}
- engines: {node: '>=12.0.0'}
-
proxy-addr@2.0.7:
resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==}
engines: {node: '>= 0.10'}
@@ -7946,10 +7220,6 @@ packages:
resolution: {integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==}
engines: {node: '>=8'}
- retry@0.13.1:
- resolution: {integrity: sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==}
- engines: {node: '>= 4'}
-
reusify@1.1.0:
resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==}
engines: {iojs: '>=1.0.0', node: '>=0.10.0'}
@@ -7958,9 +7228,6 @@ packages:
resolution: {integrity: sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ==}
hasBin: true
- robot3@0.4.1:
- resolution: {integrity: sha512-hzjy826lrxzx8eRgv80idkf8ua1JAepRc9Efdtj03N3KNJuznQCPlyCJ7gnUmDFwZCLQjxy567mQVKmdv2BsXQ==}
-
rolldown-plugin-dts@0.18.3:
resolution: {integrity: sha512-rd1LZ0Awwfyn89UndUF/HoFF4oH9a5j+2ZeuKSJYM80vmeN/p0gslYMnHTQHBEXPhUlvAlqGA3tVgXB/1qFNDg==}
engines: {node: '>=20.19.0'}
@@ -8008,8 +7275,8 @@ packages:
engines: {node: '>=18.0.0', npm: '>=8.0.0'}
hasBin: true
- rollup@4.57.1:
- resolution: {integrity: sha512-oQL6lgK3e2QZeQ7gcgIkS2YZPg5slw37hYufJ3edKlfQSGGm8ICoxswK15ntSzF/a8+h7ekRy7k7oWc3BQ7y8A==}
+ rollup@4.55.1:
+ resolution: {integrity: sha512-wDv/Ht1BNHB4upNbK74s9usvl7hObDnvVzknxqY/E/O3X6rW1U1rV1aENEfJ54eFZDTNo7zv1f5N4edCluH7+A==}
engines: {node: '>=18.0.0', npm: '>=8.0.0'}
hasBin: true
@@ -8053,6 +7320,13 @@ packages:
scule@1.3.0:
resolution: {integrity: sha512-6FtHJEvt+pVMIB9IBY+IcCJ6Z5f1iQnytgyfKMhDKgmzYG+TeH/wx1y3l27rshSbLiSanrR9ffZDrEsmjlQF2g==}
+ sdp-transform@2.15.0:
+ resolution: {integrity: sha512-KrOH82c/W+GYQ0LHqtr3caRpM3ITglq3ljGUIb8LTki7ByacJZ9z+piSGiwZDsRyhQbYBOBJgr2k6X4BZXi3Kw==}
+ hasBin: true
+
+ sdp@3.2.1:
+ resolution: {integrity: sha512-lwsAIzOPlH8/7IIjjz3K0zYBk7aBVVcvjMwt3M4fLxpjMYyy7i3I97SLHebgn4YBjirkzfp3RvRDWSKsh/+WFw==}
+
semver@6.3.1:
resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==}
hasBin: true
@@ -8067,11 +7341,6 @@ packages:
engines: {node: '>=10'}
hasBin: true
- semver@7.7.4:
- resolution: {integrity: sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==}
- engines: {node: '>=10'}
- hasBin: true
-
send@0.19.0:
resolution: {integrity: sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==}
engines: {node: '>= 0.8.0'}
@@ -8095,12 +7364,6 @@ packages:
peerDependencies:
seroval: ^1.0
- seroval-plugins@1.5.0:
- resolution: {integrity: sha512-EAHqADIQondwRZIdeW2I636zgsODzoBDwb3PT/+7TLDWyw1Dy/Xv7iGUIEXXav7usHDE9HVhOU61irI3EnyyHA==}
- engines: {node: '>=10'}
- peerDependencies:
- seroval: ^1.0
-
seroval@1.3.2:
resolution: {integrity: sha512-RbcPH1n5cfwKrru7v7+zrZvjLurgHhGyso3HTyGtRivGWgYjbOmGuivCQaORNELjNONoK35nj28EoWul9sb1zQ==}
engines: {node: '>=10'}
@@ -8109,10 +7372,6 @@ packages:
resolution: {integrity: sha512-BdrNXdzlofomLTiRnwJTSEAaGKyHHZkbMXIywOh7zlzp4uZnXErEwl9XZ+N1hJSNpeTtNxWvVwN0wUzAIQ4Hpg==}
engines: {node: '>=10'}
- seroval@1.5.0:
- resolution: {integrity: sha512-OE4cvmJ1uSPrKorFIH9/w/Qwuvi/IMcGbv5RKgcJ/zjA/IohDLU6SVaxFN9FwajbP7nsX0dQqMDes1whk3y+yw==}
- engines: {node: '>=10'}
-
serve-placeholder@2.0.2:
resolution: {integrity: sha512-/TMG8SboeiQbZJWRlfTCqMs2DD3SZgWp0kDQePz9yUuCnDfDh/92gf7/PxGhzXTKBIPASIHxFcZndoNbp6QOLQ==}
@@ -8124,10 +7383,6 @@ packages:
resolution: {integrity: sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==}
engines: {node: '>= 18'}
- serve-static@2.2.1:
- resolution: {integrity: sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==}
- engines: {node: '>= 18'}
-
set-cookie-parser@2.7.2:
resolution: {integrity: sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==}
@@ -8281,16 +7536,6 @@ packages:
sprintf-js@1.0.3:
resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==}
- srvx@0.10.1:
- resolution: {integrity: sha512-A//xtfak4eESMWWydSRFUVvCTQbSwivnGCEf8YGPe2eHU0+Z6znfUTCPF0a7oV3sObSOcrXHlL6Bs9vVctfXdg==}
- engines: {node: '>=20.16.0'}
- hasBin: true
-
- srvx@0.11.2:
- resolution: {integrity: sha512-u6NbjE84IJwm1XUnJ53WqylLTQ3BdWRw03lcjBNNeMBD+EFjkl0Cnw1RVaGSqRAo38pOHOPXJH30M6cuTINUxw==}
- engines: {node: '>=20.16.0'}
- hasBin: true
-
srvx@0.8.16:
resolution: {integrity: sha512-hmcGW4CgroeSmzgF1Ihwgl+Ths0JqAJ7HwjP2X7e3JzY7u4IydLMcdnlqGQiQGUswz+PO9oh/KtCpOISIvs9QQ==}
engines: {node: '>=20.16.0'}
@@ -8381,11 +7626,6 @@ packages:
style-to-object@1.0.14:
resolution: {integrity: sha512-LIN7rULI0jBscWQYaSswptyderlarFkjQ+t79nzty8tcIAceVomEVlLzH5VP4Cmsv6MtKhs7qaAiwlcp+Mgaxw==}
- sucrase@3.35.1:
- resolution: {integrity: sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==}
- engines: {node: '>=16 || 14 >=14.17'}
- hasBin: true
-
supports-color@10.2.2:
resolution: {integrity: sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g==}
engines: {node: '>=18'}
@@ -8448,7 +7688,6 @@ packages:
tar@7.5.2:
resolution: {integrity: sha512-7NyxrTE4Anh8km8iEy7o0QYPs+0JKBTj5ZaqHg6B39erLg0qYXN3BijtShwbsNSvQ+LN75+KV+C4QR/f6Gwnpg==}
engines: {node: '>=18'}
- deprecated: Old versions of tar are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me
term-size@2.2.1:
resolution: {integrity: sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==}
@@ -8462,13 +7701,6 @@ packages:
text-decoder@1.2.3:
resolution: {integrity: sha512-3/o9z3X0X0fTupwsYvR03pJ/DjWuqqrfwBgTQzdWDiQSm9KitAyz/9WqsT2JQW7KV2m+bC2ol/zqpW37NHxLaA==}
- thenify-all@1.6.0:
- resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==}
- engines: {node: '>=0.8'}
-
- thenify@3.3.1:
- resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==}
-
tiny-invariant@1.3.3:
resolution: {integrity: sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==}
@@ -8478,9 +7710,6 @@ packages:
tinybench@2.9.0:
resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==}
- tinyexec@0.3.2:
- resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==}
-
tinyexec@1.0.2:
resolution: {integrity: sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==}
engines: {node: '>=18'}
@@ -8546,14 +7775,14 @@ packages:
peerDependencies:
typescript: '>=4.8.4'
+ ts-debounce@4.0.0:
+ resolution: {integrity: sha512-+1iDGY6NmOGidq7i7xZGA4cm8DAa6fqdYcvO5Z6yBevH++Bdo9Qt/mN0TzHUgcCcKv1gmh9+W5dHqz8pMWbCbg==}
+
ts-declaration-location@1.0.7:
resolution: {integrity: sha512-EDyGAwH1gO0Ausm9gV6T2nUvBgXT5kGoCMJPllOaooZ+4VvJiKBdZE7wK18N1deEowhcUptS+5GXZK8U/fvpwA==}
peerDependencies:
typescript: '>=4.0.0'
- ts-interface-checker@0.1.13:
- resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==}
-
tsconfck@3.1.6:
resolution: {integrity: sha512-ks6Vjr/jEw0P1gmOVwutM3B7fWxoWBL2KRDb1JfqGVawBmO5UsvmWOQFGHBPl5yxYz4eERr19E6L7NMv+Fej4w==}
engines: {node: ^18 || >=20}
@@ -8597,30 +7826,6 @@ packages:
tslib@2.8.1:
resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==}
- tsup-preset-solid@2.2.0:
- resolution: {integrity: sha512-sPAzeArmYkVAZNRN+m4tkiojdd0GzW/lCwd4+TQDKMENe8wr2uAuro1s0Z59ASmdBbkXoxLgCiNcuQMyiidMZg==}
- peerDependencies:
- tsup: ^8.0.0
-
- tsup@8.5.1:
- resolution: {integrity: sha512-xtgkqwdhpKWr3tKPmCkvYmS9xnQK3m3XgxZHwSUjvfTjp7YfXe5tT3GgWi0F2N+ZSMsOeWeZFh7ZZFg5iPhing==}
- engines: {node: '>=18'}
- hasBin: true
- peerDependencies:
- '@microsoft/api-extractor': ^7.36.0
- '@swc/core': ^1
- postcss: ^8.4.12
- typescript: '>=4.5.0'
- peerDependenciesMeta:
- '@microsoft/api-extractor':
- optional: true
- '@swc/core':
- optional: true
- postcss:
- optional: true
- typescript:
- optional: true
-
tsx@4.21.0:
resolution: {integrity: sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==}
engines: {node: '>=18.0.0'}
@@ -8642,6 +7847,9 @@ packages:
resolution: {integrity: sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==}
engines: {node: '>= 0.6'}
+ typed-emitter@2.1.0:
+ resolution: {integrity: sha512-g/KzbYKbH5C2vPkaXGu8DJlHrGKHLsM25Zg9WuC9pMGfuvT+X25tZQWo5fK1BjBm8+UrVE9LDCvaY0CQk+fXDA==}
+
typedoc-plugin-frontmatter@1.3.0:
resolution: {integrity: sha512-xYQFMAecMlsRUjmf9oM/Sq2FVz4zlgcbIeVFNLdO118CHTN06gIKJNSlyExh9+Xl8sK0YhIvoQwViUURxritWA==}
peerDependencies:
@@ -8683,9 +7891,6 @@ packages:
ufo@1.6.1:
resolution: {integrity: sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA==}
- ufo@1.6.3:
- resolution: {integrity: sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q==}
-
ultrahtml@1.6.0:
resolution: {integrity: sha512-R9fBn90VTJrqqLDwyMph+HGne8eqY1iPfYhPzZrvKpIfwkWZbcYlfpsb8B9dTvBfpy1/hqAD7Wi8EKfP9e8zdw==}
@@ -8698,12 +7903,6 @@ packages:
unctx@2.4.1:
resolution: {integrity: sha512-AbaYw0Nm4mK4qjhns67C+kgxR2YWiwlDBPzxrN8h8C6VtAdCgditAY5Dezu3IJy4XVqAnbrXt9oQJvsn3fyozg==}
- unctx@2.5.0:
- resolution: {integrity: sha512-p+Rz9x0R7X+CYDkT+Xg8/GhpcShTlU8n+cf9OtOEf7zEQsNcCZO1dPKNRDqvUTaq+P32PMMkxWHwfrxkqfqAYg==}
-
- undici-types@5.26.5:
- resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==}
-
undici-types@5.28.4:
resolution: {integrity: sha512-3OeMF5Lyowe8VW0skf5qaIE7Or3yS9LS7fvMUI0gg4YxpIBVg0L8BxCmROw2CcYhSkpR68Epz7CGc8MPj94Uww==}
@@ -8717,10 +7916,6 @@ packages:
resolution: {integrity: sha512-QEg3HPMll0o3t2ourKwOeUAZ159Kn9mx5pnzHRQO8+Wixmh88YdZRiIwat0iNzNNXn0yoEtXJqFpyW7eM8BV7g==}
engines: {node: '>=20.18.1'}
- undici@7.21.0:
- resolution: {integrity: sha512-Hn2tCQpoDt1wv23a68Ctc8Cr/BHpUSfaPYrkajTXOS9IKpxVRx/X5m1K2YkbK2ipgZgxXSgsUinl3x+2YdSSfg==}
- engines: {node: '>=20.18.1'}
-
unenv@1.10.0:
resolution: {integrity: sha512-wY5bskBQFL9n3Eca5XnhH6KbUo/tfvkwm9OpcdCvLaeA7piBNbavbOKJySEwQ1V0RH6HvNlSAFRTpvTqgKRQXQ==}
@@ -8731,10 +7926,6 @@ packages:
resolution: {integrity: sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==}
engines: {node: '>=18'}
- unicorn-magic@0.4.0:
- resolution: {integrity: sha512-wH590V9VNgYH9g3lH9wWjTrUoKsjLF6sGLjhR4sH1LWpLmCOH0Zf7PukhDA8BiS7KHe4oPNkcTHqYkj7SOGUOw==}
- engines: {node: '>=20'}
-
unified@11.0.5:
resolution: {integrity: sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==}
@@ -8742,10 +7933,6 @@ packages:
resolution: {integrity: sha512-/JpWMG9s1nBSlXJAQ8EREFTFy3oy6USFd8T6AoBaw1q2GGcF4R9yp3ofg32UODZlYEO5VD0EWE1RpI9XDWyPYg==}
engines: {node: '>=18.12.0'}
- unimport@5.6.0:
- resolution: {integrity: sha512-8rqAmtJV8o60x46kBAJKtHpJDJWkA2xcBqWKPI14MgUb05o1pnpnCnXSxedUXyeq7p8fR5g3pTo2BaswZ9lD9A==}
- engines: {node: '>=18.12.0'}
-
unist-util-find-after@5.0.0:
resolution: {integrity: sha512-amQa0Ep2m6hE2g72AugUItjbuM8X8cGQnFoHk0pGfrFeT9GZhzN5SW8nRsiGKK7Aif4CrACPENkA6P/Lw6fHGQ==}
@@ -8802,8 +7989,8 @@ packages:
synckit:
optional: true
- unstorage@1.17.4:
- resolution: {integrity: sha512-fHK0yNg38tBiJKp/Vgsq4j0JEsCmgqH58HAn707S7zGkArbZsVr/CwINoi+nh3h98BRCwKvx1K3Xg9u3VV83sw==}
+ unstorage@1.17.3:
+ resolution: {integrity: sha512-i+JYyy0DoKmQ3FximTHbGadmIYb8JEpq7lxUjnjeB702bCPum0vzo6oy5Mfu0lpqISw7hCyMW2yj4nWC8bqJ3Q==}
peerDependencies:
'@azure/app-configuration': ^1.8.0
'@azure/cosmos': ^4.2.0
@@ -8811,14 +7998,14 @@ packages:
'@azure/identity': ^4.6.0
'@azure/keyvault-secrets': ^4.9.0
'@azure/storage-blob': ^12.26.0
- '@capacitor/preferences': ^6 || ^7 || ^8
+ '@capacitor/preferences': ^6.0.3 || ^7.0.0
'@deno/kv': '>=0.9.0'
'@netlify/blobs': ^6.5.0 || ^7.0.0 || ^8.1.0 || ^9.0.0 || ^10.0.0
'@planetscale/database': ^1.19.0
'@upstash/redis': ^1.34.3
'@vercel/blob': '>=0.27.1'
'@vercel/functions': ^2.2.12 || ^3.0.0
- '@vercel/kv': ^1 || ^2 || ^3
+ '@vercel/kv': ^1.0.1
aws4fetch: ^1.0.20
db0: '>=0.2.1'
idb-keyval: ^6.2.1
@@ -8864,80 +8051,6 @@ packages:
uploadthing:
optional: true
- unstorage@2.0.0-alpha.5:
- resolution: {integrity: sha512-Sj8btci21Twnd6M+N+MHhjg3fVn6lAPElPmvFTe0Y/wR0WImErUdA1PzlAaUavHylJ7uDiFwlZDQKm0elG4b7g==}
- peerDependencies:
- '@azure/app-configuration': ^1.9.0
- '@azure/cosmos': ^4.7.0
- '@azure/data-tables': ^13.3.1
- '@azure/identity': ^4.13.0
- '@azure/keyvault-secrets': ^4.10.0
- '@azure/storage-blob': ^12.29.1
- '@capacitor/preferences': ^6.0.3 || ^7.0.0
- '@deno/kv': '>=0.12.0'
- '@netlify/blobs': ^6.5.0 || ^7.0.0 || ^8.1.0 || ^9.0.0 || ^10.0.0
- '@planetscale/database': ^1.19.0
- '@upstash/redis': ^1.35.6
- '@vercel/blob': '>=0.27.3'
- '@vercel/functions': ^2.2.12 || ^3.0.0
- '@vercel/kv': ^1.0.1
- aws4fetch: ^1.0.20
- chokidar: ^4 || ^5
- db0: '>=0.3.4'
- idb-keyval: ^6.2.2
- ioredis: ^5.8.2
- lru-cache: ^11.2.2
- mongodb: ^6 || ^7
- ofetch: '*'
- uploadthing: ^7.7.4
- peerDependenciesMeta:
- '@azure/app-configuration':
- optional: true
- '@azure/cosmos':
- optional: true
- '@azure/data-tables':
- optional: true
- '@azure/identity':
- optional: true
- '@azure/keyvault-secrets':
- optional: true
- '@azure/storage-blob':
- optional: true
- '@capacitor/preferences':
- optional: true
- '@deno/kv':
- optional: true
- '@netlify/blobs':
- optional: true
- '@planetscale/database':
- optional: true
- '@upstash/redis':
- optional: true
- '@vercel/blob':
- optional: true
- '@vercel/functions':
- optional: true
- '@vercel/kv':
- optional: true
- aws4fetch:
- optional: true
- chokidar:
- optional: true
- db0:
- optional: true
- idb-keyval:
- optional: true
- ioredis:
- optional: true
- lru-cache:
- optional: true
- mongodb:
- optional: true
- ofetch:
- optional: true
- uploadthing:
- optional: true
-
untun@0.1.3:
resolution: {integrity: sha512-4luGP9LMYszMRZwsvyUd9MrxgEGZdZuZgpVQHEEX0lCYFESasVRvZd0EYpCkOIbJKHMuv0LskpXc/8Un+MJzEQ==}
hasBin: true
@@ -8949,9 +8062,6 @@ packages:
unwasm@0.3.11:
resolution: {integrity: sha512-Vhp5gb1tusSQw5of/g3Q697srYgMXvwMgXMjcG4ZNga02fDX9coxJ9fAb0Ci38hM2Hv/U1FXRPGgjP2BYqhNoQ==}
- unwasm@0.5.3:
- resolution: {integrity: sha512-keBgTSfp3r6+s9ZcSma+0chwxQdmLbB5+dAD9vjtB21UTMYuKAxHXCU1K2CbCtnP09EaWeRvACnXk0EJtUx+hw==}
-
update-browserslist-db@1.2.2:
resolution: {integrity: sha512-E85pfNzMQ9jpKkA7+TJAi4TJN+tBCuWh5rUcS/sv6cFi+1q9LYDwDI5dpUL0u/73EElyQ8d3TEaeW4sPedBqYA==}
hasBin: true
@@ -9184,18 +8294,18 @@ packages:
jsdom:
optional: true
- vitest@4.0.18:
- resolution: {integrity: sha512-hOQuK7h0FGKgBAas7v0mSAsnvrIgAvWmRFjmzpJ7SwFHH3g1k2u37JtYwOwmEKhK6ZO3v9ggDBBm0La1LCK4uQ==}
+ vitest@4.0.17:
+ resolution: {integrity: sha512-FQMeF0DJdWY0iOnbv466n/0BudNdKj1l5jYgl5JVTwjSsZSlqyXFt/9+1sEyhR6CLowbZpV7O1sCHrzBhucKKg==}
engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0}
hasBin: true
peerDependencies:
'@edge-runtime/vm': '*'
'@opentelemetry/api': ^1.9.0
'@types/node': ^20.0.0 || ^22.0.0 || >=24.0.0
- '@vitest/browser-playwright': 4.0.18
- '@vitest/browser-preview': 4.0.18
- '@vitest/browser-webdriverio': 4.0.18
- '@vitest/ui': 4.0.18
+ '@vitest/browser-playwright': 4.0.17
+ '@vitest/browser-preview': 4.0.17
+ '@vitest/browser-webdriverio': 4.0.17
+ '@vitest/ui': 4.0.17
happy-dom: '*'
jsdom: '*'
peerDependenciesMeta:
@@ -9267,10 +8377,6 @@ packages:
resolution: {integrity: sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==}
engines: {node: '>= 8'}
- web-streams-polyfill@4.0.0-beta.3:
- resolution: {integrity: sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==}
- engines: {node: '>= 14'}
-
web-vitals@5.1.0:
resolution: {integrity: sha512-ArI3kx5jI0atlTtmV0fWU3fjpLmq/nD3Zr1iFFlJLaqa5wLBkUSzINwBPySCX/8jRyjlmy1Volw1kz1g9XE4Jg==}
@@ -9284,10 +8390,13 @@ packages:
webpack-virtual-modules@0.6.2:
resolution: {integrity: sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==}
+ webrtc-adapter@9.0.3:
+ resolution: {integrity: sha512-5fALBcroIl31OeXAdd1YUntxiZl1eHlZZWzNg3U4Fn+J9/cGL3eT80YlrsWGvj2ojuz1rZr2OXkgCzIxAZ7vRQ==}
+ engines: {node: '>=6.0.0', npm: '>=3.10.0'}
+
whatwg-encoding@3.1.1:
resolution: {integrity: sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==}
engines: {node: '>=18'}
- deprecated: Use @exodus/bytes instead for a more spec-conformant and faster implementation
whatwg-fetch@3.6.20:
resolution: {integrity: sha512-EqhiFU6daOA8kpjOWTL0olhVOF3i7OrFzSYiGsEMB8GcXS+RrzauAERX65xMeNWVqxA6HXH2m69Z9LaKKdisfg==}
@@ -9430,14 +8539,17 @@ packages:
zod@4.2.1:
resolution: {integrity: sha512-0wZ1IRqGGhMP76gLqz8EyfBXKk0J2qo2+H3fi4mcUP/KtTocoX08nmIAHl1Z2kJIZbZee8KOpBCSNPRgauucjw==}
- zod@4.3.6:
- resolution: {integrity: sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==}
-
zwitch@2.0.4:
resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==}
snapshots:
+ '@11labs/client@0.2.0(@types/dom-mediacapture-record@1.0.22)':
+ dependencies:
+ livekit-client: 2.17.0(@types/dom-mediacapture-record@1.0.22)
+ transitivePeerDependencies:
+ - '@types/dom-mediacapture-record'
+
'@acemir/cssom@0.9.29': {}
'@alcyone-labs/zod-to-json-schema@4.0.10(zod@4.2.1)':
@@ -9504,15 +8616,15 @@ snapshots:
'@babel/generator@7.28.5':
dependencies:
- '@babel/parser': 7.29.0
- '@babel/types': 7.29.0
+ '@babel/parser': 7.28.5
+ '@babel/types': 7.28.5
'@jridgewell/gen-mapping': 0.3.13
'@jridgewell/trace-mapping': 0.3.31
jsesc: 3.1.0
'@babel/helper-annotate-as-pure@7.27.3':
dependencies:
- '@babel/types': 7.29.0
+ '@babel/types': 7.28.5
'@babel/helper-compilation-targets@7.27.2':
dependencies:
@@ -9540,18 +8652,18 @@ snapshots:
'@babel/helper-member-expression-to-functions@7.28.5':
dependencies:
'@babel/traverse': 7.28.5
- '@babel/types': 7.29.0
+ '@babel/types': 7.28.5
transitivePeerDependencies:
- supports-color
'@babel/helper-module-imports@7.18.6':
dependencies:
- '@babel/types': 7.29.0
+ '@babel/types': 7.28.5
'@babel/helper-module-imports@7.27.1':
dependencies:
'@babel/traverse': 7.28.5
- '@babel/types': 7.29.0
+ '@babel/types': 7.28.5
transitivePeerDependencies:
- supports-color
@@ -9566,7 +8678,7 @@ snapshots:
'@babel/helper-optimise-call-expression@7.27.1':
dependencies:
- '@babel/types': 7.29.0
+ '@babel/types': 7.28.5
'@babel/helper-plugin-utils@7.27.1': {}
@@ -9582,7 +8694,7 @@ snapshots:
'@babel/helper-skip-transparent-expression-wrappers@7.27.1':
dependencies:
'@babel/traverse': 7.28.5
- '@babel/types': 7.29.0
+ '@babel/types': 7.28.5
transitivePeerDependencies:
- supports-color
@@ -9595,15 +8707,11 @@ snapshots:
'@babel/helpers@7.28.4':
dependencies:
'@babel/template': 7.27.2
- '@babel/types': 7.29.0
+ '@babel/types': 7.28.5
'@babel/parser@7.28.5':
dependencies:
- '@babel/types': 7.29.0
-
- '@babel/parser@7.29.0':
- dependencies:
- '@babel/types': 7.29.0
+ '@babel/types': 7.28.5
'@babel/plugin-syntax-jsx@7.27.1(@babel/core@7.28.5)':
dependencies:
@@ -9680,13 +8788,10 @@ snapshots:
'@babel/helper-string-parser': 7.27.1
'@babel/helper-validator-identifier': 7.28.5
- '@babel/types@7.29.0':
- dependencies:
- '@babel/helper-string-parser': 7.27.1
- '@babel/helper-validator-identifier': 7.28.5
-
'@bcoe/v8-coverage@1.0.2': {}
+ '@bufbuild/protobuf@1.10.1': {}
+
'@changesets/apply-release-plan@7.0.14':
dependencies:
'@changesets/config': 3.1.2
@@ -9842,8 +8947,6 @@ snapshots:
dependencies:
mime: 3.0.0
- '@cloudflare/kv-asset-handler@0.4.2': {}
-
'@crazydos/vue-markdown@1.1.4(vue@3.5.25(typescript@5.9.3))':
dependencies:
deepmerge: 4.3.1
@@ -9906,10 +9009,10 @@ snapshots:
'@esbuild/aix-ppc64@0.25.12':
optional: true
- '@esbuild/aix-ppc64@0.27.2':
+ '@esbuild/aix-ppc64@0.27.1':
optional: true
- '@esbuild/aix-ppc64@0.27.3':
+ '@esbuild/aix-ppc64@0.27.2':
optional: true
'@esbuild/android-arm64@0.20.2':
@@ -9918,10 +9021,10 @@ snapshots:
'@esbuild/android-arm64@0.25.12':
optional: true
- '@esbuild/android-arm64@0.27.2':
+ '@esbuild/android-arm64@0.27.1':
optional: true
- '@esbuild/android-arm64@0.27.3':
+ '@esbuild/android-arm64@0.27.2':
optional: true
'@esbuild/android-arm@0.20.2':
@@ -9930,10 +9033,10 @@ snapshots:
'@esbuild/android-arm@0.25.12':
optional: true
- '@esbuild/android-arm@0.27.2':
+ '@esbuild/android-arm@0.27.1':
optional: true
- '@esbuild/android-arm@0.27.3':
+ '@esbuild/android-arm@0.27.2':
optional: true
'@esbuild/android-x64@0.20.2':
@@ -9942,10 +9045,10 @@ snapshots:
'@esbuild/android-x64@0.25.12':
optional: true
- '@esbuild/android-x64@0.27.2':
+ '@esbuild/android-x64@0.27.1':
optional: true
- '@esbuild/android-x64@0.27.3':
+ '@esbuild/android-x64@0.27.2':
optional: true
'@esbuild/darwin-arm64@0.20.2':
@@ -9954,10 +9057,10 @@ snapshots:
'@esbuild/darwin-arm64@0.25.12':
optional: true
- '@esbuild/darwin-arm64@0.27.2':
+ '@esbuild/darwin-arm64@0.27.1':
optional: true
- '@esbuild/darwin-arm64@0.27.3':
+ '@esbuild/darwin-arm64@0.27.2':
optional: true
'@esbuild/darwin-x64@0.20.2':
@@ -9966,10 +9069,10 @@ snapshots:
'@esbuild/darwin-x64@0.25.12':
optional: true
- '@esbuild/darwin-x64@0.27.2':
+ '@esbuild/darwin-x64@0.27.1':
optional: true
- '@esbuild/darwin-x64@0.27.3':
+ '@esbuild/darwin-x64@0.27.2':
optional: true
'@esbuild/freebsd-arm64@0.20.2':
@@ -9978,10 +9081,10 @@ snapshots:
'@esbuild/freebsd-arm64@0.25.12':
optional: true
- '@esbuild/freebsd-arm64@0.27.2':
+ '@esbuild/freebsd-arm64@0.27.1':
optional: true
- '@esbuild/freebsd-arm64@0.27.3':
+ '@esbuild/freebsd-arm64@0.27.2':
optional: true
'@esbuild/freebsd-x64@0.20.2':
@@ -9990,10 +9093,10 @@ snapshots:
'@esbuild/freebsd-x64@0.25.12':
optional: true
- '@esbuild/freebsd-x64@0.27.2':
+ '@esbuild/freebsd-x64@0.27.1':
optional: true
- '@esbuild/freebsd-x64@0.27.3':
+ '@esbuild/freebsd-x64@0.27.2':
optional: true
'@esbuild/linux-arm64@0.20.2':
@@ -10002,10 +9105,10 @@ snapshots:
'@esbuild/linux-arm64@0.25.12':
optional: true
- '@esbuild/linux-arm64@0.27.2':
+ '@esbuild/linux-arm64@0.27.1':
optional: true
- '@esbuild/linux-arm64@0.27.3':
+ '@esbuild/linux-arm64@0.27.2':
optional: true
'@esbuild/linux-arm@0.20.2':
@@ -10014,10 +9117,10 @@ snapshots:
'@esbuild/linux-arm@0.25.12':
optional: true
- '@esbuild/linux-arm@0.27.2':
+ '@esbuild/linux-arm@0.27.1':
optional: true
- '@esbuild/linux-arm@0.27.3':
+ '@esbuild/linux-arm@0.27.2':
optional: true
'@esbuild/linux-ia32@0.20.2':
@@ -10026,10 +9129,10 @@ snapshots:
'@esbuild/linux-ia32@0.25.12':
optional: true
- '@esbuild/linux-ia32@0.27.2':
+ '@esbuild/linux-ia32@0.27.1':
optional: true
- '@esbuild/linux-ia32@0.27.3':
+ '@esbuild/linux-ia32@0.27.2':
optional: true
'@esbuild/linux-loong64@0.20.2':
@@ -10038,10 +9141,10 @@ snapshots:
'@esbuild/linux-loong64@0.25.12':
optional: true
- '@esbuild/linux-loong64@0.27.2':
+ '@esbuild/linux-loong64@0.27.1':
optional: true
- '@esbuild/linux-loong64@0.27.3':
+ '@esbuild/linux-loong64@0.27.2':
optional: true
'@esbuild/linux-mips64el@0.20.2':
@@ -10050,10 +9153,10 @@ snapshots:
'@esbuild/linux-mips64el@0.25.12':
optional: true
- '@esbuild/linux-mips64el@0.27.2':
+ '@esbuild/linux-mips64el@0.27.1':
optional: true
- '@esbuild/linux-mips64el@0.27.3':
+ '@esbuild/linux-mips64el@0.27.2':
optional: true
'@esbuild/linux-ppc64@0.20.2':
@@ -10062,10 +9165,10 @@ snapshots:
'@esbuild/linux-ppc64@0.25.12':
optional: true
- '@esbuild/linux-ppc64@0.27.2':
+ '@esbuild/linux-ppc64@0.27.1':
optional: true
- '@esbuild/linux-ppc64@0.27.3':
+ '@esbuild/linux-ppc64@0.27.2':
optional: true
'@esbuild/linux-riscv64@0.20.2':
@@ -10074,10 +9177,10 @@ snapshots:
'@esbuild/linux-riscv64@0.25.12':
optional: true
- '@esbuild/linux-riscv64@0.27.2':
+ '@esbuild/linux-riscv64@0.27.1':
optional: true
- '@esbuild/linux-riscv64@0.27.3':
+ '@esbuild/linux-riscv64@0.27.2':
optional: true
'@esbuild/linux-s390x@0.20.2':
@@ -10086,10 +9189,10 @@ snapshots:
'@esbuild/linux-s390x@0.25.12':
optional: true
- '@esbuild/linux-s390x@0.27.2':
+ '@esbuild/linux-s390x@0.27.1':
optional: true
- '@esbuild/linux-s390x@0.27.3':
+ '@esbuild/linux-s390x@0.27.2':
optional: true
'@esbuild/linux-x64@0.20.2':
@@ -10098,19 +9201,19 @@ snapshots:
'@esbuild/linux-x64@0.25.12':
optional: true
- '@esbuild/linux-x64@0.27.2':
+ '@esbuild/linux-x64@0.27.1':
optional: true
- '@esbuild/linux-x64@0.27.3':
+ '@esbuild/linux-x64@0.27.2':
optional: true
'@esbuild/netbsd-arm64@0.25.12':
optional: true
- '@esbuild/netbsd-arm64@0.27.2':
+ '@esbuild/netbsd-arm64@0.27.1':
optional: true
- '@esbuild/netbsd-arm64@0.27.3':
+ '@esbuild/netbsd-arm64@0.27.2':
optional: true
'@esbuild/netbsd-x64@0.20.2':
@@ -10119,19 +9222,19 @@ snapshots:
'@esbuild/netbsd-x64@0.25.12':
optional: true
- '@esbuild/netbsd-x64@0.27.2':
+ '@esbuild/netbsd-x64@0.27.1':
optional: true
- '@esbuild/netbsd-x64@0.27.3':
+ '@esbuild/netbsd-x64@0.27.2':
optional: true
'@esbuild/openbsd-arm64@0.25.12':
optional: true
- '@esbuild/openbsd-arm64@0.27.2':
+ '@esbuild/openbsd-arm64@0.27.1':
optional: true
- '@esbuild/openbsd-arm64@0.27.3':
+ '@esbuild/openbsd-arm64@0.27.2':
optional: true
'@esbuild/openbsd-x64@0.20.2':
@@ -10140,19 +9243,19 @@ snapshots:
'@esbuild/openbsd-x64@0.25.12':
optional: true
- '@esbuild/openbsd-x64@0.27.2':
+ '@esbuild/openbsd-x64@0.27.1':
optional: true
- '@esbuild/openbsd-x64@0.27.3':
+ '@esbuild/openbsd-x64@0.27.2':
optional: true
'@esbuild/openharmony-arm64@0.25.12':
optional: true
- '@esbuild/openharmony-arm64@0.27.2':
+ '@esbuild/openharmony-arm64@0.27.1':
optional: true
- '@esbuild/openharmony-arm64@0.27.3':
+ '@esbuild/openharmony-arm64@0.27.2':
optional: true
'@esbuild/sunos-x64@0.20.2':
@@ -10161,10 +9264,10 @@ snapshots:
'@esbuild/sunos-x64@0.25.12':
optional: true
- '@esbuild/sunos-x64@0.27.2':
+ '@esbuild/sunos-x64@0.27.1':
optional: true
- '@esbuild/sunos-x64@0.27.3':
+ '@esbuild/sunos-x64@0.27.2':
optional: true
'@esbuild/win32-arm64@0.20.2':
@@ -10173,10 +9276,10 @@ snapshots:
'@esbuild/win32-arm64@0.25.12':
optional: true
- '@esbuild/win32-arm64@0.27.2':
+ '@esbuild/win32-arm64@0.27.1':
optional: true
- '@esbuild/win32-arm64@0.27.3':
+ '@esbuild/win32-arm64@0.27.2':
optional: true
'@esbuild/win32-ia32@0.20.2':
@@ -10185,10 +9288,10 @@ snapshots:
'@esbuild/win32-ia32@0.25.12':
optional: true
- '@esbuild/win32-ia32@0.27.2':
+ '@esbuild/win32-ia32@0.27.1':
optional: true
- '@esbuild/win32-ia32@0.27.3':
+ '@esbuild/win32-ia32@0.27.2':
optional: true
'@esbuild/win32-x64@0.20.2':
@@ -10197,10 +9300,10 @@ snapshots:
'@esbuild/win32-x64@0.25.12':
optional: true
- '@esbuild/win32-x64@0.27.2':
+ '@esbuild/win32-x64@0.27.1':
optional: true
- '@esbuild/win32-x64@0.27.3':
+ '@esbuild/win32-x64@0.27.2':
optional: true
'@eslint-community/eslint-utils@4.9.0(eslint@9.39.1(jiti@2.6.1))':
@@ -10263,12 +9366,6 @@ snapshots:
'@faker-js/faker@10.1.0': {}
- '@fal-ai/client@1.9.1':
- dependencies:
- '@msgpack/msgpack': 3.1.3
- eventsource-parser: 1.1.2
- robot3: 0.4.1
-
'@gerrit0/mini-shiki@3.19.0':
dependencies:
'@shikijs/engine-oniguruma': 3.20.0
@@ -10277,11 +9374,9 @@ snapshots:
'@shikijs/types': 3.20.0
'@shikijs/vscode-textmate': 10.0.2
- '@google/genai@1.43.0':
+ '@google/genai@1.33.0':
dependencies:
google-auth-library: 10.5.0
- p-retry: 4.6.2
- protobufjs: 7.5.4
ws: 8.18.3
transitivePeerDependencies:
- bufferutil
@@ -10308,8 +9403,6 @@ snapshots:
'@ioredis/commands@1.4.0': {}
- '@ioredis/commands@1.5.0': {}
-
'@isaacs/balanced-match@4.0.1': {}
'@isaacs/brace-expansion@5.0.0':
@@ -10361,6 +9454,12 @@ snapshots:
'@jridgewell/resolve-uri': 3.1.2
'@jridgewell/sourcemap-codec': 1.5.5
+ '@livekit/mutex@1.1.1': {}
+
+ '@livekit/protocol@1.42.2':
+ dependencies:
+ '@bufbuild/protobuf': 1.10.1
+
'@manypkg/find-root@1.1.0':
dependencies:
'@babel/runtime': 7.28.4
@@ -10384,7 +9483,7 @@ snapshots:
https-proxy-agent: 7.0.6
node-fetch: 2.7.0
nopt: 8.1.0
- semver: 7.7.4
+ semver: 7.7.3
tar: 7.5.2
transitivePeerDependencies:
- encoding
@@ -10398,15 +9497,6 @@ snapshots:
transitivePeerDependencies:
- '@types/node'
- '@microsoft/api-extractor-model@7.29.6(@types/node@25.0.1)':
- dependencies:
- '@microsoft/tsdoc': 0.15.1
- '@microsoft/tsdoc-config': 0.17.1
- '@rushstack/node-core-library': 5.7.0(@types/node@25.0.1)
- transitivePeerDependencies:
- - '@types/node'
- optional: true
-
'@microsoft/api-extractor@7.47.7(@types/node@24.10.3)':
dependencies:
'@microsoft/api-extractor-model': 7.29.6(@types/node@24.10.3)
@@ -10425,25 +9515,6 @@ snapshots:
transitivePeerDependencies:
- '@types/node'
- '@microsoft/api-extractor@7.47.7(@types/node@25.0.1)':
- dependencies:
- '@microsoft/api-extractor-model': 7.29.6(@types/node@25.0.1)
- '@microsoft/tsdoc': 0.15.1
- '@microsoft/tsdoc-config': 0.17.1
- '@rushstack/node-core-library': 5.7.0(@types/node@25.0.1)
- '@rushstack/rig-package': 0.5.3
- '@rushstack/terminal': 0.14.0(@types/node@25.0.1)
- '@rushstack/ts-command-line': 4.22.6(@types/node@25.0.1)
- lodash: 4.17.21
- minimatch: 3.0.8
- resolve: 1.22.11
- semver: 7.5.4
- source-map: 0.6.1
- typescript: 5.4.2
- transitivePeerDependencies:
- - '@types/node'
- optional: true
-
'@microsoft/tsdoc-config@0.17.1':
dependencies:
'@microsoft/tsdoc': 0.15.1
@@ -10453,8 +9524,6 @@ snapshots:
'@microsoft/tsdoc@0.15.1': {}
- '@msgpack/msgpack@3.1.3': {}
-
'@napi-rs/wasm-runtime@0.2.12':
dependencies:
'@emnapi/core': 1.7.1
@@ -10475,13 +9544,6 @@ snapshots:
'@tybys/wasm-util': 0.10.1
optional: true
- '@napi-rs/wasm-runtime@1.1.1':
- dependencies:
- '@emnapi/core': 1.7.1
- '@emnapi/runtime': 1.7.1
- '@tybys/wasm-util': 0.10.1
- optional: true
-
'@nodelib/fs.scandir@2.1.5':
dependencies:
'@nodelib/fs.stat': 2.0.5
@@ -10564,69 +9626,7 @@ snapshots:
'@openrouter/sdk@0.3.15':
dependencies:
- zod: 4.3.6
-
- '@oxc-minify/binding-android-arm-eabi@0.110.0':
- optional: true
-
- '@oxc-minify/binding-android-arm64@0.110.0':
- optional: true
-
- '@oxc-minify/binding-darwin-arm64@0.110.0':
- optional: true
-
- '@oxc-minify/binding-darwin-x64@0.110.0':
- optional: true
-
- '@oxc-minify/binding-freebsd-x64@0.110.0':
- optional: true
-
- '@oxc-minify/binding-linux-arm-gnueabihf@0.110.0':
- optional: true
-
- '@oxc-minify/binding-linux-arm-musleabihf@0.110.0':
- optional: true
-
- '@oxc-minify/binding-linux-arm64-gnu@0.110.0':
- optional: true
-
- '@oxc-minify/binding-linux-arm64-musl@0.110.0':
- optional: true
-
- '@oxc-minify/binding-linux-ppc64-gnu@0.110.0':
- optional: true
-
- '@oxc-minify/binding-linux-riscv64-gnu@0.110.0':
- optional: true
-
- '@oxc-minify/binding-linux-riscv64-musl@0.110.0':
- optional: true
-
- '@oxc-minify/binding-linux-s390x-gnu@0.110.0':
- optional: true
-
- '@oxc-minify/binding-linux-x64-gnu@0.110.0':
- optional: true
-
- '@oxc-minify/binding-linux-x64-musl@0.110.0':
- optional: true
-
- '@oxc-minify/binding-openharmony-arm64@0.110.0':
- optional: true
-
- '@oxc-minify/binding-wasm32-wasi@0.110.0':
- dependencies:
- '@napi-rs/wasm-runtime': 1.1.1
- optional: true
-
- '@oxc-minify/binding-win32-arm64-msvc@0.110.0':
- optional: true
-
- '@oxc-minify/binding-win32-ia32-msvc@0.110.0':
- optional: true
-
- '@oxc-minify/binding-win32-x64-msvc@0.110.0':
- optional: true
+ zod: 4.2.1
'@oxc-project/types@0.101.0': {}
@@ -10692,68 +9692,6 @@ snapshots:
'@oxc-resolver/binding-win32-x64-msvc@11.15.0':
optional: true
- '@oxc-transform/binding-android-arm-eabi@0.110.0':
- optional: true
-
- '@oxc-transform/binding-android-arm64@0.110.0':
- optional: true
-
- '@oxc-transform/binding-darwin-arm64@0.110.0':
- optional: true
-
- '@oxc-transform/binding-darwin-x64@0.110.0':
- optional: true
-
- '@oxc-transform/binding-freebsd-x64@0.110.0':
- optional: true
-
- '@oxc-transform/binding-linux-arm-gnueabihf@0.110.0':
- optional: true
-
- '@oxc-transform/binding-linux-arm-musleabihf@0.110.0':
- optional: true
-
- '@oxc-transform/binding-linux-arm64-gnu@0.110.0':
- optional: true
-
- '@oxc-transform/binding-linux-arm64-musl@0.110.0':
- optional: true
-
- '@oxc-transform/binding-linux-ppc64-gnu@0.110.0':
- optional: true
-
- '@oxc-transform/binding-linux-riscv64-gnu@0.110.0':
- optional: true
-
- '@oxc-transform/binding-linux-riscv64-musl@0.110.0':
- optional: true
-
- '@oxc-transform/binding-linux-s390x-gnu@0.110.0':
- optional: true
-
- '@oxc-transform/binding-linux-x64-gnu@0.110.0':
- optional: true
-
- '@oxc-transform/binding-linux-x64-musl@0.110.0':
- optional: true
-
- '@oxc-transform/binding-openharmony-arm64@0.110.0':
- optional: true
-
- '@oxc-transform/binding-wasm32-wasi@0.110.0':
- dependencies:
- '@napi-rs/wasm-runtime': 1.1.1
- optional: true
-
- '@oxc-transform/binding-win32-arm64-msvc@0.110.0':
- optional: true
-
- '@oxc-transform/binding-win32-ia32-msvc@0.110.0':
- optional: true
-
- '@oxc-transform/binding-win32-x64-msvc@0.110.0':
- optional: true
-
'@parcel/watcher-android-arm64@2.5.1':
optional: true
@@ -10845,29 +9783,6 @@ snapshots:
'@poppinss/exception@1.2.3': {}
- '@protobufjs/aspromise@1.1.2': {}
-
- '@protobufjs/base64@1.1.2': {}
-
- '@protobufjs/codegen@2.0.4': {}
-
- '@protobufjs/eventemitter@1.1.0': {}
-
- '@protobufjs/fetch@1.1.0':
- dependencies:
- '@protobufjs/aspromise': 1.1.2
- '@protobufjs/inquire': 1.1.0
-
- '@protobufjs/float@1.0.2': {}
-
- '@protobufjs/inquire@1.1.0': {}
-
- '@protobufjs/path@1.1.2': {}
-
- '@protobufjs/pool@1.1.0': {}
-
- '@protobufjs/utf8@1.1.0': {}
-
'@publint/pack@0.1.2': {}
'@quansync/fs@1.0.0':
@@ -10921,29 +9836,13 @@ snapshots:
'@rolldown/pluginutils@1.0.0-beta.53': {}
- '@rollup/plugin-alias@5.1.1(rollup@4.57.1)':
- optionalDependencies:
- rollup: 4.57.1
-
- '@rollup/plugin-alias@6.0.0(rollup@4.57.1)':
+ '@rollup/plugin-alias@5.1.1(rollup@4.53.3)':
optionalDependencies:
- rollup: 4.57.1
-
- '@rollup/plugin-commonjs@28.0.9(rollup@4.57.1)':
- dependencies:
- '@rollup/pluginutils': 5.3.0(rollup@4.57.1)
- commondir: 1.0.1
- estree-walker: 2.0.2
- fdir: 6.5.0(picomatch@4.0.3)
- is-reference: 1.2.1
- magic-string: 0.30.21
- picomatch: 4.0.3
- optionalDependencies:
- rollup: 4.57.1
+ rollup: 4.53.3
- '@rollup/plugin-commonjs@29.0.0(rollup@4.57.1)':
+ '@rollup/plugin-commonjs@28.0.9(rollup@4.53.3)':
dependencies:
- '@rollup/pluginutils': 5.3.0(rollup@4.57.1)
+ '@rollup/pluginutils': 5.3.0(rollup@4.53.3)
commondir: 1.0.1
estree-walker: 2.0.2
fdir: 6.5.0(picomatch@4.0.3)
@@ -10951,194 +9850,202 @@ snapshots:
magic-string: 0.30.21
picomatch: 4.0.3
optionalDependencies:
- rollup: 4.57.1
+ rollup: 4.53.3
- '@rollup/plugin-inject@5.0.5(rollup@4.57.1)':
+ '@rollup/plugin-inject@5.0.5(rollup@4.53.3)':
dependencies:
- '@rollup/pluginutils': 5.3.0(rollup@4.57.1)
+ '@rollup/pluginutils': 5.3.0(rollup@4.53.3)
estree-walker: 2.0.2
magic-string: 0.30.21
optionalDependencies:
- rollup: 4.57.1
+ rollup: 4.53.3
- '@rollup/plugin-json@6.1.0(rollup@4.57.1)':
+ '@rollup/plugin-json@6.1.0(rollup@4.53.3)':
dependencies:
- '@rollup/pluginutils': 5.3.0(rollup@4.57.1)
+ '@rollup/pluginutils': 5.3.0(rollup@4.53.3)
optionalDependencies:
- rollup: 4.57.1
+ rollup: 4.53.3
- '@rollup/plugin-node-resolve@16.0.3(rollup@4.57.1)':
+ '@rollup/plugin-node-resolve@16.0.3(rollup@4.53.3)':
dependencies:
- '@rollup/pluginutils': 5.3.0(rollup@4.57.1)
+ '@rollup/pluginutils': 5.3.0(rollup@4.53.3)
'@types/resolve': 1.20.2
deepmerge: 4.3.1
is-module: 1.0.0
resolve: 1.22.11
optionalDependencies:
- rollup: 4.57.1
+ rollup: 4.53.3
- '@rollup/plugin-replace@6.0.3(rollup@4.57.1)':
+ '@rollup/plugin-replace@6.0.3(rollup@4.53.3)':
dependencies:
- '@rollup/pluginutils': 5.3.0(rollup@4.57.1)
+ '@rollup/pluginutils': 5.3.0(rollup@4.53.3)
magic-string: 0.30.21
optionalDependencies:
- rollup: 4.57.1
+ rollup: 4.53.3
- '@rollup/plugin-terser@0.4.4(rollup@4.57.1)':
+ '@rollup/plugin-terser@0.4.4(rollup@4.53.3)':
dependencies:
serialize-javascript: 6.0.2
smob: 1.5.0
terser: 5.44.1
optionalDependencies:
- rollup: 4.57.1
+ rollup: 4.53.3
- '@rollup/pluginutils@5.3.0(rollup@4.57.1)':
+ '@rollup/pluginutils@5.3.0(rollup@4.53.3)':
dependencies:
'@types/estree': 1.0.8
estree-walker: 2.0.2
picomatch: 4.0.3
optionalDependencies:
- rollup: 4.57.1
+ rollup: 4.53.3
+
+ '@rollup/pluginutils@5.3.0(rollup@4.55.1)':
+ dependencies:
+ '@types/estree': 1.0.8
+ estree-walker: 2.0.2
+ picomatch: 4.0.3
+ optionalDependencies:
+ rollup: 4.55.1
'@rollup/rollup-android-arm-eabi@4.53.3':
optional: true
- '@rollup/rollup-android-arm-eabi@4.57.1':
+ '@rollup/rollup-android-arm-eabi@4.55.1':
optional: true
'@rollup/rollup-android-arm64@4.53.3':
optional: true
- '@rollup/rollup-android-arm64@4.57.1':
+ '@rollup/rollup-android-arm64@4.55.1':
optional: true
'@rollup/rollup-darwin-arm64@4.53.3':
optional: true
- '@rollup/rollup-darwin-arm64@4.57.1':
+ '@rollup/rollup-darwin-arm64@4.55.1':
optional: true
'@rollup/rollup-darwin-x64@4.53.3':
optional: true
- '@rollup/rollup-darwin-x64@4.57.1':
+ '@rollup/rollup-darwin-x64@4.55.1':
optional: true
'@rollup/rollup-freebsd-arm64@4.53.3':
optional: true
- '@rollup/rollup-freebsd-arm64@4.57.1':
+ '@rollup/rollup-freebsd-arm64@4.55.1':
optional: true
'@rollup/rollup-freebsd-x64@4.53.3':
optional: true
- '@rollup/rollup-freebsd-x64@4.57.1':
+ '@rollup/rollup-freebsd-x64@4.55.1':
optional: true
'@rollup/rollup-linux-arm-gnueabihf@4.53.3':
optional: true
- '@rollup/rollup-linux-arm-gnueabihf@4.57.1':
+ '@rollup/rollup-linux-arm-gnueabihf@4.55.1':
optional: true
'@rollup/rollup-linux-arm-musleabihf@4.53.3':
optional: true
- '@rollup/rollup-linux-arm-musleabihf@4.57.1':
+ '@rollup/rollup-linux-arm-musleabihf@4.55.1':
optional: true
'@rollup/rollup-linux-arm64-gnu@4.53.3':
optional: true
- '@rollup/rollup-linux-arm64-gnu@4.57.1':
+ '@rollup/rollup-linux-arm64-gnu@4.55.1':
optional: true
'@rollup/rollup-linux-arm64-musl@4.53.3':
optional: true
- '@rollup/rollup-linux-arm64-musl@4.57.1':
+ '@rollup/rollup-linux-arm64-musl@4.55.1':
optional: true
'@rollup/rollup-linux-loong64-gnu@4.53.3':
optional: true
- '@rollup/rollup-linux-loong64-gnu@4.57.1':
+ '@rollup/rollup-linux-loong64-gnu@4.55.1':
optional: true
- '@rollup/rollup-linux-loong64-musl@4.57.1':
+ '@rollup/rollup-linux-loong64-musl@4.55.1':
optional: true
'@rollup/rollup-linux-ppc64-gnu@4.53.3':
optional: true
- '@rollup/rollup-linux-ppc64-gnu@4.57.1':
+ '@rollup/rollup-linux-ppc64-gnu@4.55.1':
optional: true
- '@rollup/rollup-linux-ppc64-musl@4.57.1':
+ '@rollup/rollup-linux-ppc64-musl@4.55.1':
optional: true
'@rollup/rollup-linux-riscv64-gnu@4.53.3':
optional: true
- '@rollup/rollup-linux-riscv64-gnu@4.57.1':
+ '@rollup/rollup-linux-riscv64-gnu@4.55.1':
optional: true
'@rollup/rollup-linux-riscv64-musl@4.53.3':
optional: true
- '@rollup/rollup-linux-riscv64-musl@4.57.1':
+ '@rollup/rollup-linux-riscv64-musl@4.55.1':
optional: true
'@rollup/rollup-linux-s390x-gnu@4.53.3':
optional: true
- '@rollup/rollup-linux-s390x-gnu@4.57.1':
+ '@rollup/rollup-linux-s390x-gnu@4.55.1':
optional: true
'@rollup/rollup-linux-x64-gnu@4.53.3':
optional: true
- '@rollup/rollup-linux-x64-gnu@4.57.1':
+ '@rollup/rollup-linux-x64-gnu@4.55.1':
optional: true
'@rollup/rollup-linux-x64-musl@4.53.3':
optional: true
- '@rollup/rollup-linux-x64-musl@4.57.1':
+ '@rollup/rollup-linux-x64-musl@4.55.1':
optional: true
- '@rollup/rollup-openbsd-x64@4.57.1':
+ '@rollup/rollup-openbsd-x64@4.55.1':
optional: true
'@rollup/rollup-openharmony-arm64@4.53.3':
optional: true
- '@rollup/rollup-openharmony-arm64@4.57.1':
+ '@rollup/rollup-openharmony-arm64@4.55.1':
optional: true
'@rollup/rollup-win32-arm64-msvc@4.53.3':
optional: true
- '@rollup/rollup-win32-arm64-msvc@4.57.1':
+ '@rollup/rollup-win32-arm64-msvc@4.55.1':
optional: true
'@rollup/rollup-win32-ia32-msvc@4.53.3':
optional: true
- '@rollup/rollup-win32-ia32-msvc@4.57.1':
+ '@rollup/rollup-win32-ia32-msvc@4.55.1':
optional: true
'@rollup/rollup-win32-x64-gnu@4.53.3':
optional: true
- '@rollup/rollup-win32-x64-gnu@4.57.1':
+ '@rollup/rollup-win32-x64-gnu@4.55.1':
optional: true
'@rollup/rollup-win32-x64-msvc@4.53.3':
optional: true
- '@rollup/rollup-win32-x64-msvc@4.57.1':
+ '@rollup/rollup-win32-x64-msvc@4.55.1':
optional: true
'@rushstack/node-core-library@5.7.0(@types/node@24.10.3)':
@@ -11154,20 +10061,6 @@ snapshots:
optionalDependencies:
'@types/node': 24.10.3
- '@rushstack/node-core-library@5.7.0(@types/node@25.0.1)':
- dependencies:
- ajv: 8.13.0
- ajv-draft-04: 1.0.0(ajv@8.13.0)
- ajv-formats: 3.0.1(ajv@8.13.0)
- fs-extra: 7.0.1
- import-lazy: 4.0.0
- jju: 1.4.0
- resolve: 1.22.11
- semver: 7.5.4
- optionalDependencies:
- '@types/node': 25.0.1
- optional: true
-
'@rushstack/rig-package@0.5.3':
dependencies:
resolve: 1.22.11
@@ -11180,14 +10073,6 @@ snapshots:
optionalDependencies:
'@types/node': 24.10.3
- '@rushstack/terminal@0.14.0(@types/node@25.0.1)':
- dependencies:
- '@rushstack/node-core-library': 5.7.0(@types/node@25.0.1)
- supports-color: 8.1.1
- optionalDependencies:
- '@types/node': 25.0.1
- optional: true
-
'@rushstack/ts-command-line@4.22.6(@types/node@24.10.3)':
dependencies:
'@rushstack/terminal': 0.14.0(@types/node@24.10.3)
@@ -11197,16 +10082,6 @@ snapshots:
transitivePeerDependencies:
- '@types/node'
- '@rushstack/ts-command-line@4.22.6(@types/node@25.0.1)':
- dependencies:
- '@rushstack/terminal': 0.14.0(@types/node@25.0.1)
- '@types/argparse': 1.0.38
- argparse: 1.0.10
- string-argv: 0.3.2
- transitivePeerDependencies:
- - '@types/node'
- optional: true
-
'@shikijs/engine-oniguruma@3.20.0':
dependencies:
'@shikijs/types': 3.20.0
@@ -11493,21 +10368,10 @@ snapshots:
tailwindcss: 4.1.18
vite: 7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
- '@tailwindcss/vite@4.1.18(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
- dependencies:
- '@tailwindcss/node': 4.1.18
- '@tailwindcss/oxide': 4.1.18
- tailwindcss: 4.1.18
- vite: 7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
-
'@tanstack/devtools-client@0.0.5':
dependencies:
'@tanstack/devtools-event-client': 0.4.0
- '@tanstack/devtools-client@0.0.6':
- dependencies:
- '@tanstack/devtools-event-client': 0.4.1
-
'@tanstack/devtools-event-bus@0.3.3':
dependencies:
ws: 8.18.3
@@ -11515,17 +10379,8 @@ snapshots:
- bufferutil
- utf-8-validate
- '@tanstack/devtools-event-bus@0.4.1':
- dependencies:
- ws: 8.18.3
- transitivePeerDependencies:
- - bufferutil
- - utf-8-validate
-
'@tanstack/devtools-event-client@0.4.0': {}
- '@tanstack/devtools-event-client@0.4.1': {}
-
'@tanstack/devtools-ui@0.4.4(csstype@3.2.3)(solid-js@1.9.10)':
dependencies:
clsx: 2.1.1
@@ -11534,18 +10389,9 @@ snapshots:
transitivePeerDependencies:
- csstype
- '@tanstack/devtools-ui@0.5.0(csstype@3.2.3)(solid-js@1.9.10)':
- dependencies:
- clsx: 2.1.1
- dayjs: 1.11.19
- goober: 2.1.18(csstype@3.2.3)
- solid-js: 1.9.10
- transitivePeerDependencies:
- - csstype
-
- '@tanstack/devtools-utils@0.3.2(@types/react@19.2.7)(csstype@3.2.3)(preact@10.28.2)(react@19.2.3)(solid-js@1.9.10)(vue@3.5.25(typescript@5.9.3))':
+ '@tanstack/devtools-utils@0.3.0(@types/react@19.2.7)(csstype@3.2.3)(preact@10.28.2)(react@19.2.3)(solid-js@1.9.10)(vue@3.5.25(typescript@5.9.3))':
dependencies:
- '@tanstack/devtools-ui': 0.5.0(csstype@3.2.3)(solid-js@1.9.10)
+ '@tanstack/devtools-ui': 0.4.4(csstype@3.2.3)(solid-js@1.9.10)
optionalDependencies:
'@types/react': 19.2.7
preact: 10.28.2
@@ -11555,9 +10401,9 @@ snapshots:
transitivePeerDependencies:
- csstype
- '@tanstack/devtools-utils@0.3.2(@types/react@19.2.7)(preact@10.28.1)(react@19.2.3)(solid-js@1.9.10)(vue@3.5.25(typescript@5.9.3))':
+ '@tanstack/devtools-utils@0.3.0(@types/react@19.2.7)(preact@10.28.1)(react@19.2.3)(solid-js@1.9.10)(vue@3.5.25(typescript@5.9.3))':
dependencies:
- '@tanstack/devtools-ui': 0.5.0(csstype@3.2.3)(solid-js@1.9.10)
+ '@tanstack/devtools-ui': 0.4.4(csstype@3.2.3)(solid-js@1.9.10)
optionalDependencies:
'@types/react': 19.2.7
preact: 10.28.1
@@ -11567,15 +10413,15 @@ snapshots:
transitivePeerDependencies:
- csstype
- '@tanstack/devtools-vite@0.5.3(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
+ '@tanstack/devtools-vite@0.3.12(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
dependencies:
'@babel/core': 7.28.5
'@babel/generator': 7.28.5
- '@babel/parser': 7.29.0
+ '@babel/parser': 7.28.5
'@babel/traverse': 7.28.5
- '@babel/types': 7.29.0
- '@tanstack/devtools-client': 0.0.6
- '@tanstack/devtools-event-bus': 0.4.1
+ '@babel/types': 7.28.5
+ '@tanstack/devtools-client': 0.0.5
+ '@tanstack/devtools-event-bus': 0.3.3
chalk: 5.6.2
launch-editor: 2.12.0
picomatch: 4.0.3
@@ -11585,22 +10431,6 @@ snapshots:
- supports-color
- utf-8-validate
- '@tanstack/devtools@0.10.11(csstype@3.2.3)(solid-js@1.9.10)':
- dependencies:
- '@solid-primitives/event-listener': 2.4.3(solid-js@1.9.10)
- '@solid-primitives/keyboard': 1.3.3(solid-js@1.9.10)
- '@solid-primitives/resize-observer': 2.1.3(solid-js@1.9.10)
- '@tanstack/devtools-client': 0.0.6
- '@tanstack/devtools-event-bus': 0.4.1
- '@tanstack/devtools-ui': 0.5.0(csstype@3.2.3)(solid-js@1.9.10)
- clsx: 2.1.1
- goober: 2.1.18(csstype@3.2.3)
- solid-js: 1.9.10
- transitivePeerDependencies:
- - bufferutil
- - csstype
- - utf-8-validate
-
'@tanstack/devtools@0.9.1(csstype@3.2.3)(solid-js@1.9.10)':
dependencies:
'@solid-primitives/event-listener': 2.4.3(solid-js@1.9.10)
@@ -11622,7 +10452,7 @@ snapshots:
'@babel/code-frame': 7.27.1
'@babel/core': 7.28.5
'@babel/traverse': 7.28.5
- '@babel/types': 7.29.0
+ '@babel/types': 7.28.5
'@tanstack/router-utils': 1.131.2
babel-dead-code-elimination: 1.0.10
tiny-invariant: 1.3.3
@@ -11635,7 +10465,7 @@ snapshots:
'@babel/code-frame': 7.27.1
'@babel/core': 7.28.5
'@babel/traverse': 7.28.5
- '@babel/types': 7.29.0
+ '@babel/types': 7.28.5
'@tanstack/router-utils': 1.141.0
babel-dead-code-elimination: 1.0.10
pathe: 2.0.3
@@ -11664,11 +10494,9 @@ snapshots:
'@tanstack/history@1.141.0': {}
- '@tanstack/history@1.154.14': {}
-
- '@tanstack/nitro-v2-vite-plugin@1.154.7(rolldown@1.0.0-beta.53)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
+ '@tanstack/nitro-v2-vite-plugin@1.141.0(rolldown@1.0.0-beta.53)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
dependencies:
- nitropack: 2.13.1(rolldown@1.0.0-beta.53)
+ nitropack: 2.12.9(rolldown@1.0.0-beta.53)
pathe: 2.0.3
vite: 7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
transitivePeerDependencies:
@@ -11704,9 +10532,9 @@ snapshots:
'@tanstack/query-core@5.90.12': {}
- '@tanstack/react-devtools@0.9.10(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(csstype@3.2.3)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(solid-js@1.9.10)':
+ '@tanstack/react-devtools@0.8.4(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(csstype@3.2.3)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(solid-js@1.9.10)':
dependencies:
- '@tanstack/devtools': 0.10.11(csstype@3.2.3)(solid-js@1.9.10)
+ '@tanstack/devtools': 0.9.1(csstype@3.2.3)(solid-js@1.9.10)
'@types/react': 19.2.7
'@types/react-dom': 19.2.3(@types/react@19.2.7)
react: 19.2.3
@@ -11722,23 +10550,24 @@ snapshots:
'@tanstack/query-core': 5.90.12
react: 19.2.3
- '@tanstack/react-router-devtools@1.159.5(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(@tanstack/router-core@1.159.4)(csstype@3.2.3)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)':
+ '@tanstack/react-router-devtools@1.141.1(@tanstack/react-router@1.141.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(@tanstack/router-core@1.141.1)(csstype@3.2.3)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(solid-js@1.9.10)':
dependencies:
- '@tanstack/react-router': 1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
- '@tanstack/router-devtools-core': 1.159.4(@tanstack/router-core@1.159.4)(csstype@3.2.3)
+ '@tanstack/react-router': 1.141.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
+ '@tanstack/router-devtools-core': 1.141.1(@tanstack/router-core@1.141.1)(csstype@3.2.3)(solid-js@1.9.10)
react: 19.2.3
react-dom: 19.2.3(react@19.2.3)
optionalDependencies:
- '@tanstack/router-core': 1.159.4
+ '@tanstack/router-core': 1.141.1
transitivePeerDependencies:
- csstype
+ - solid-js
- '@tanstack/react-router-ssr-query@1.159.5(@tanstack/query-core@5.90.12)(@tanstack/react-query@5.90.12(react@19.2.3))(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(@tanstack/router-core@1.159.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)':
+ '@tanstack/react-router-ssr-query@1.141.1(@tanstack/query-core@5.90.12)(@tanstack/react-query@5.90.12(react@19.2.3))(@tanstack/react-router@1.141.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(@tanstack/router-core@1.141.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)':
dependencies:
'@tanstack/query-core': 5.90.12
'@tanstack/react-query': 5.90.12(react@19.2.3)
- '@tanstack/react-router': 1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
- '@tanstack/router-ssr-query-core': 1.159.4(@tanstack/query-core@5.90.12)(@tanstack/router-core@1.159.4)
+ '@tanstack/react-router': 1.141.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
+ '@tanstack/router-ssr-query-core': 1.141.1(@tanstack/query-core@5.90.12)(@tanstack/router-core@1.141.1)
react: 19.2.3
react-dom: 19.2.3(react@19.2.3)
transitivePeerDependencies:
@@ -11755,17 +10584,6 @@ snapshots:
tiny-invariant: 1.3.3
tiny-warning: 1.0.3
- '@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3)':
- dependencies:
- '@tanstack/history': 1.154.14
- '@tanstack/react-store': 0.8.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
- '@tanstack/router-core': 1.159.4
- isbot: 5.1.32
- react: 19.2.3
- react-dom: 19.2.3(react@19.2.3)
- tiny-invariant: 1.3.3
- tiny-warning: 1.0.3
-
'@tanstack/react-start-client@1.141.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3)':
dependencies:
'@tanstack/react-router': 1.141.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
@@ -11776,19 +10594,9 @@ snapshots:
tiny-invariant: 1.3.3
tiny-warning: 1.0.3
- '@tanstack/react-start-client@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3)':
- dependencies:
- '@tanstack/react-router': 1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
- '@tanstack/router-core': 1.159.4
- '@tanstack/start-client-core': 1.159.4
- react: 19.2.3
- react-dom: 19.2.3(react@19.2.3)
- tiny-invariant: 1.3.3
- tiny-warning: 1.0.3
-
- '@tanstack/react-start-plugin@1.131.50(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(@vitejs/plugin-react@4.7.0(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(rolldown@1.0.0-beta.53)(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
+ '@tanstack/react-start-plugin@1.131.50(@tanstack/react-router@1.141.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(@vitejs/plugin-react@4.7.0(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(rolldown@1.0.0-beta.53)(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
dependencies:
- '@tanstack/start-plugin-core': 1.131.50(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(rolldown@1.0.0-beta.53)(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+ '@tanstack/start-plugin-core': 1.131.50(@tanstack/react-router@1.141.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(rolldown@1.0.0-beta.53)(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
'@vitejs/plugin-react': 4.7.0(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
pathe: 2.0.3
vite: 7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
@@ -11830,7 +10638,7 @@ snapshots:
'@tanstack/react-start-router-manifest@1.120.19(@types/node@24.10.3)(db0@0.3.4)(ioredis@5.8.2)(jiti@2.6.1)(lightningcss@1.30.2)(rolldown@1.0.0-beta.53)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)':
dependencies:
- '@tanstack/router-core': 1.157.16
+ '@tanstack/router-core': 1.141.1
tiny-invariant: 1.3.3
vinxi: 0.5.3(@types/node@24.10.3)(db0@0.3.4)(ioredis@5.8.2)(jiti@2.6.1)(lightningcss@1.30.2)(rolldown@1.0.0-beta.53)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
transitivePeerDependencies:
@@ -11878,71 +10686,27 @@ snapshots:
- xml2js
- yaml
- '@tanstack/react-start-server@1.141.1(crossws@0.4.4(srvx@0.11.2))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)':
+ '@tanstack/react-start-server@1.141.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3)':
dependencies:
'@tanstack/history': 1.141.0
'@tanstack/react-router': 1.141.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
'@tanstack/router-core': 1.141.1
'@tanstack/start-client-core': 1.141.1
- '@tanstack/start-server-core': 1.141.1(crossws@0.4.4(srvx@0.11.2))
- react: 19.2.3
- react-dom: 19.2.3(react@19.2.3)
- transitivePeerDependencies:
- - crossws
-
- '@tanstack/react-start-server@1.159.5(crossws@0.4.4(srvx@0.10.1))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)':
- dependencies:
- '@tanstack/history': 1.154.14
- '@tanstack/react-router': 1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
- '@tanstack/router-core': 1.159.4
- '@tanstack/start-client-core': 1.159.4
- '@tanstack/start-server-core': 1.159.4(crossws@0.4.4(srvx@0.10.1))
- react: 19.2.3
- react-dom: 19.2.3(react@19.2.3)
- transitivePeerDependencies:
- - crossws
-
- '@tanstack/react-start-server@1.159.5(crossws@0.4.4(srvx@0.11.2))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)':
- dependencies:
- '@tanstack/history': 1.154.14
- '@tanstack/react-router': 1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
- '@tanstack/router-core': 1.159.4
- '@tanstack/start-client-core': 1.159.4
- '@tanstack/start-server-core': 1.159.4(crossws@0.4.4(srvx@0.11.2))
+ '@tanstack/start-server-core': 1.141.1
react: 19.2.3
react-dom: 19.2.3(react@19.2.3)
transitivePeerDependencies:
- crossws
- '@tanstack/react-start@1.159.5(crossws@0.4.4(srvx@0.10.1))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
+ '@tanstack/react-start@1.141.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
dependencies:
- '@tanstack/react-router': 1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
- '@tanstack/react-start-client': 1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
- '@tanstack/react-start-server': 1.159.5(crossws@0.4.4(srvx@0.10.1))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
- '@tanstack/router-utils': 1.158.0
- '@tanstack/start-client-core': 1.159.4
- '@tanstack/start-plugin-core': 1.159.5(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(crossws@0.4.4(srvx@0.10.1))(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
- '@tanstack/start-server-core': 1.159.4(crossws@0.4.4(srvx@0.10.1))
- pathe: 2.0.3
- react: 19.2.3
- react-dom: 19.2.3(react@19.2.3)
- vite: 7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
- transitivePeerDependencies:
- - '@rsbuild/core'
- - crossws
- - supports-color
- - vite-plugin-solid
- - webpack
-
- '@tanstack/react-start@1.159.5(crossws@0.4.4(srvx@0.11.2))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
- dependencies:
- '@tanstack/react-router': 1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
- '@tanstack/react-start-client': 1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
- '@tanstack/react-start-server': 1.159.5(crossws@0.4.4(srvx@0.11.2))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
- '@tanstack/router-utils': 1.158.0
- '@tanstack/start-client-core': 1.159.4
- '@tanstack/start-plugin-core': 1.159.5(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(crossws@0.4.4(srvx@0.11.2))(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
- '@tanstack/start-server-core': 1.159.4(crossws@0.4.4(srvx@0.11.2))
+ '@tanstack/react-router': 1.141.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
+ '@tanstack/react-start-client': 1.141.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
+ '@tanstack/react-start-server': 1.141.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
+ '@tanstack/router-utils': 1.141.0
+ '@tanstack/start-client-core': 1.141.1
+ '@tanstack/start-plugin-core': 1.141.1(@tanstack/react-router@1.141.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+ '@tanstack/start-server-core': 1.141.1
pathe: 2.0.3
react: 19.2.3
react-dom: 19.2.3(react@19.2.3)
@@ -11981,29 +10745,9 @@ snapshots:
tiny-invariant: 1.3.3
tiny-warning: 1.0.3
- '@tanstack/router-core@1.157.16':
+ '@tanstack/router-devtools-core@1.141.1(@tanstack/router-core@1.141.1)(csstype@3.2.3)(solid-js@1.9.10)':
dependencies:
- '@tanstack/history': 1.154.14
- '@tanstack/store': 0.8.0
- cookie-es: 2.0.0
- seroval: 1.5.0
- seroval-plugins: 1.5.0(seroval@1.5.0)
- tiny-invariant: 1.3.3
- tiny-warning: 1.0.3
-
- '@tanstack/router-core@1.159.4':
- dependencies:
- '@tanstack/history': 1.154.14
- '@tanstack/store': 0.8.0
- cookie-es: 2.0.0
- seroval: 1.5.0
- seroval-plugins: 1.5.0(seroval@1.5.0)
- tiny-invariant: 1.3.3
- tiny-warning: 1.0.3
-
- '@tanstack/router-devtools-core@1.141.1(@tanstack/router-core@1.159.4)(csstype@3.2.3)(solid-js@1.9.10)':
- dependencies:
- '@tanstack/router-core': 1.159.4
+ '@tanstack/router-core': 1.141.1
clsx: 2.1.1
goober: 2.1.18(csstype@3.2.3)
solid-js: 1.9.10
@@ -12011,15 +10755,6 @@ snapshots:
optionalDependencies:
csstype: 3.2.3
- '@tanstack/router-devtools-core@1.159.4(@tanstack/router-core@1.159.4)(csstype@3.2.3)':
- dependencies:
- '@tanstack/router-core': 1.159.4
- clsx: 2.1.1
- goober: 2.1.18(csstype@3.2.3)
- tiny-invariant: 1.3.3
- optionalDependencies:
- csstype: 3.2.3
-
'@tanstack/router-generator@1.131.50':
dependencies:
'@tanstack/router-core': 1.131.50
@@ -12046,27 +10781,14 @@ snapshots:
transitivePeerDependencies:
- supports-color
- '@tanstack/router-generator@1.159.4':
- dependencies:
- '@tanstack/router-core': 1.159.4
- '@tanstack/router-utils': 1.158.0
- '@tanstack/virtual-file-routes': 1.154.7
- prettier: 3.7.4
- recast: 0.23.11
- source-map: 0.7.6
- tsx: 4.21.0
- zod: 3.25.76
- transitivePeerDependencies:
- - supports-color
-
- '@tanstack/router-plugin@1.131.50(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
+ '@tanstack/router-plugin@1.131.50(@tanstack/react-router@1.141.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
dependencies:
'@babel/core': 7.28.5
'@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.28.5)
'@babel/plugin-syntax-typescript': 7.27.1(@babel/core@7.28.5)
'@babel/template': 7.27.2
'@babel/traverse': 7.28.5
- '@babel/types': 7.29.0
+ '@babel/types': 7.28.5
'@tanstack/router-core': 1.131.50
'@tanstack/router-generator': 1.131.50
'@tanstack/router-utils': 1.131.2
@@ -12076,20 +10798,20 @@ snapshots:
unplugin: 2.3.11
zod: 3.25.76
optionalDependencies:
- '@tanstack/react-router': 1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
+ '@tanstack/react-router': 1.141.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
vite: 7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
vite-plugin-solid: 2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
transitivePeerDependencies:
- supports-color
- '@tanstack/router-plugin@1.141.1(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
+ '@tanstack/router-plugin@1.141.1(@tanstack/react-router@1.141.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
dependencies:
'@babel/core': 7.28.5
'@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.28.5)
'@babel/plugin-syntax-typescript': 7.27.1(@babel/core@7.28.5)
'@babel/template': 7.27.2
'@babel/traverse': 7.28.5
- '@babel/types': 7.29.0
+ '@babel/types': 7.28.5
'@tanstack/router-core': 1.141.1
'@tanstack/router-generator': 1.141.1
'@tanstack/router-utils': 1.141.0
@@ -12099,71 +10821,22 @@ snapshots:
unplugin: 2.3.11
zod: 3.25.76
optionalDependencies:
- '@tanstack/react-router': 1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
- vite: 7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
- vite-plugin-solid: 2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
- transitivePeerDependencies:
- - supports-color
-
- '@tanstack/router-plugin@1.159.5(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
- dependencies:
- '@babel/core': 7.28.5
- '@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.28.5)
- '@babel/plugin-syntax-typescript': 7.27.1(@babel/core@7.28.5)
- '@babel/template': 7.27.2
- '@babel/traverse': 7.28.5
- '@babel/types': 7.29.0
- '@tanstack/router-core': 1.159.4
- '@tanstack/router-generator': 1.159.4
- '@tanstack/router-utils': 1.158.0
- '@tanstack/virtual-file-routes': 1.154.7
- chokidar: 3.6.0
- unplugin: 2.3.11
- zod: 3.25.76
- optionalDependencies:
- '@tanstack/react-router': 1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
+ '@tanstack/react-router': 1.141.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
vite: 7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
vite-plugin-solid: 2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
transitivePeerDependencies:
- supports-color
- '@tanstack/router-plugin@1.159.5(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
- dependencies:
- '@babel/core': 7.28.5
- '@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.28.5)
- '@babel/plugin-syntax-typescript': 7.27.1(@babel/core@7.28.5)
- '@babel/template': 7.27.2
- '@babel/traverse': 7.28.5
- '@babel/types': 7.29.0
- '@tanstack/router-core': 1.159.4
- '@tanstack/router-generator': 1.159.4
- '@tanstack/router-utils': 1.158.0
- '@tanstack/virtual-file-routes': 1.154.7
- chokidar: 3.6.0
- unplugin: 2.3.11
- zod: 3.25.76
- optionalDependencies:
- '@tanstack/react-router': 1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
- vite: 7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
- vite-plugin-solid: 2.11.10(solid-js@1.9.10)(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
- transitivePeerDependencies:
- - supports-color
-
- '@tanstack/router-ssr-query-core@1.141.1(@tanstack/query-core@5.90.12)(@tanstack/router-core@1.159.4)':
+ '@tanstack/router-ssr-query-core@1.141.1(@tanstack/query-core@5.90.12)(@tanstack/router-core@1.141.1)':
dependencies:
'@tanstack/query-core': 5.90.12
- '@tanstack/router-core': 1.159.4
-
- '@tanstack/router-ssr-query-core@1.159.4(@tanstack/query-core@5.90.12)(@tanstack/router-core@1.159.4)':
- dependencies:
- '@tanstack/query-core': 5.90.12
- '@tanstack/router-core': 1.159.4
+ '@tanstack/router-core': 1.141.1
'@tanstack/router-utils@1.131.2':
dependencies:
'@babel/core': 7.28.5
'@babel/generator': 7.28.5
- '@babel/parser': 7.29.0
+ '@babel/parser': 7.28.5
'@babel/preset-typescript': 7.28.5(@babel/core@7.28.5)
ansis: 4.2.0
diff: 8.0.2
@@ -12174,7 +10847,7 @@ snapshots:
dependencies:
'@babel/core': 7.28.5
'@babel/generator': 7.28.5
- '@babel/parser': 7.29.0
+ '@babel/parser': 7.28.5
'@babel/preset-typescript': 7.28.5(@babel/core@7.28.5)
ansis: 4.2.0
diff: 8.0.2
@@ -12183,20 +10856,6 @@ snapshots:
transitivePeerDependencies:
- supports-color
- '@tanstack/router-utils@1.158.0':
- dependencies:
- '@babel/core': 7.28.5
- '@babel/generator': 7.28.5
- '@babel/parser': 7.29.0
- '@babel/types': 7.29.0
- ansis: 4.2.0
- babel-dead-code-elimination: 1.0.12
- diff: 8.0.2
- pathe: 2.0.3
- tinyglobby: 0.2.15
- transitivePeerDependencies:
- - supports-color
-
'@tanstack/server-functions-plugin@1.131.2(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
dependencies:
'@babel/code-frame': 7.27.1
@@ -12205,7 +10864,7 @@ snapshots:
'@babel/plugin-syntax-typescript': 7.27.1(@babel/core@7.28.5)
'@babel/template': 7.27.2
'@babel/traverse': 7.28.5
- '@babel/types': 7.29.0
+ '@babel/types': 7.28.5
'@tanstack/directive-functions-plugin': 1.131.2(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
babel-dead-code-elimination: 1.0.10
tiny-invariant: 1.3.3
@@ -12221,7 +10880,7 @@ snapshots:
'@babel/plugin-syntax-typescript': 7.27.1(@babel/core@7.28.5)
'@babel/template': 7.27.2
'@babel/traverse': 7.28.5
- '@babel/types': 7.29.0
+ '@babel/types': 7.28.5
'@tanstack/directive-functions-plugin': 1.141.0(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
babel-dead-code-elimination: 1.0.10
tiny-invariant: 1.3.3
@@ -12243,20 +10902,20 @@ snapshots:
'@tanstack/query-core': 5.90.12
solid-js: 1.9.10
- '@tanstack/solid-router-devtools@1.141.1(@tanstack/router-core@1.159.4)(@tanstack/solid-router@1.141.1(solid-js@1.9.10))(csstype@3.2.3)(solid-js@1.9.10)':
+ '@tanstack/solid-router-devtools@1.141.1(@tanstack/router-core@1.141.1)(@tanstack/solid-router@1.141.1(solid-js@1.9.10))(csstype@3.2.3)(solid-js@1.9.10)':
dependencies:
- '@tanstack/router-devtools-core': 1.141.1(@tanstack/router-core@1.159.4)(csstype@3.2.3)(solid-js@1.9.10)
+ '@tanstack/router-devtools-core': 1.141.1(@tanstack/router-core@1.141.1)(csstype@3.2.3)(solid-js@1.9.10)
'@tanstack/solid-router': 1.141.1(solid-js@1.9.10)
solid-js: 1.9.10
optionalDependencies:
- '@tanstack/router-core': 1.159.4
+ '@tanstack/router-core': 1.141.1
transitivePeerDependencies:
- csstype
- '@tanstack/solid-router-ssr-query@1.141.1(@tanstack/query-core@5.90.12)(@tanstack/router-core@1.159.4)(@tanstack/solid-query@5.90.15(solid-js@1.9.10))(@tanstack/solid-router@1.141.1(solid-js@1.9.10))(eslint@9.39.2(jiti@2.6.1))(solid-js@1.9.10)(typescript@5.9.3)':
+ '@tanstack/solid-router-ssr-query@1.141.1(@tanstack/query-core@5.90.12)(@tanstack/router-core@1.141.1)(@tanstack/solid-query@5.90.15(solid-js@1.9.10))(@tanstack/solid-router@1.141.1(solid-js@1.9.10))(eslint@9.39.2(jiti@2.6.1))(solid-js@1.9.10)(typescript@5.9.3)':
dependencies:
'@tanstack/query-core': 5.90.12
- '@tanstack/router-ssr-query-core': 1.141.1(@tanstack/query-core@5.90.12)(@tanstack/router-core@1.159.4)
+ '@tanstack/router-ssr-query-core': 1.141.1(@tanstack/query-core@5.90.12)(@tanstack/router-core@1.141.1)
'@tanstack/solid-query': 5.90.15(solid-js@1.9.10)
'@tanstack/solid-router': 1.141.1(solid-js@1.9.10)
eslint-plugin-solid: 0.14.5(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)
@@ -12289,26 +10948,26 @@ snapshots:
tiny-invariant: 1.3.3
tiny-warning: 1.0.3
- '@tanstack/solid-start-server@1.141.1(crossws@0.4.4(srvx@0.11.2))(solid-js@1.9.10)':
+ '@tanstack/solid-start-server@1.141.1(solid-js@1.9.10)':
dependencies:
'@solidjs/meta': 0.29.4(solid-js@1.9.10)
'@tanstack/history': 1.141.0
'@tanstack/router-core': 1.141.1
'@tanstack/solid-router': 1.141.1(solid-js@1.9.10)
'@tanstack/start-client-core': 1.141.1
- '@tanstack/start-server-core': 1.141.1(crossws@0.4.4(srvx@0.11.2))
+ '@tanstack/start-server-core': 1.141.1
solid-js: 1.9.10
transitivePeerDependencies:
- crossws
- '@tanstack/solid-start@1.141.1(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(crossws@0.4.4(srvx@0.11.2))(solid-js@1.9.10)(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
+ '@tanstack/solid-start@1.141.1(@tanstack/react-router@1.141.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(solid-js@1.9.10)(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
dependencies:
'@tanstack/solid-router': 1.141.1(solid-js@1.9.10)
'@tanstack/solid-start-client': 1.141.1(solid-js@1.9.10)
- '@tanstack/solid-start-server': 1.141.1(crossws@0.4.4(srvx@0.11.2))(solid-js@1.9.10)
+ '@tanstack/solid-start-server': 1.141.1(solid-js@1.9.10)
'@tanstack/start-client-core': 1.141.1
- '@tanstack/start-plugin-core': 1.141.1(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(crossws@0.4.4(srvx@0.11.2))(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
- '@tanstack/start-server-core': 1.141.1(crossws@0.4.4(srvx@0.11.2))
+ '@tanstack/start-plugin-core': 1.141.1(@tanstack/react-router@1.141.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+ '@tanstack/start-server-core': 1.141.1
pathe: 2.0.3
solid-js: 1.9.10
vite: 7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
@@ -12325,10 +10984,10 @@ snapshots:
'@tanstack/store': 0.8.0
solid-js: 1.9.10
- '@tanstack/start-api-routes@1.120.19(@types/node@24.10.3)(crossws@0.4.4(srvx@0.11.2))(db0@0.3.4)(ioredis@5.8.2)(jiti@2.6.1)(lightningcss@1.30.2)(rolldown@1.0.0-beta.53)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)':
+ '@tanstack/start-api-routes@1.120.19(@types/node@24.10.3)(db0@0.3.4)(ioredis@5.8.2)(jiti@2.6.1)(lightningcss@1.30.2)(rolldown@1.0.0-beta.53)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)':
dependencies:
- '@tanstack/router-core': 1.157.16
- '@tanstack/start-server-core': 1.141.1(crossws@0.4.4(srvx@0.11.2))
+ '@tanstack/router-core': 1.141.1
+ '@tanstack/start-server-core': 1.141.1
vinxi: 0.5.3(@types/node@24.10.3)(db0@0.3.4)(ioredis@5.8.2)(jiti@2.6.1)(lightningcss@1.30.2)(rolldown@1.0.0-beta.53)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
transitivePeerDependencies:
- '@azure/app-configuration'
@@ -12392,23 +11051,14 @@ snapshots:
tiny-invariant: 1.3.3
tiny-warning: 1.0.3
- '@tanstack/start-client-core@1.159.4':
- dependencies:
- '@tanstack/router-core': 1.159.4
- '@tanstack/start-fn-stubs': 1.154.7
- '@tanstack/start-storage-context': 1.159.4
- seroval: 1.5.0
- tiny-invariant: 1.3.3
- tiny-warning: 1.0.3
-
- '@tanstack/start-config@1.120.20(@types/node@24.10.3)(crossws@0.4.4(srvx@0.11.2))(db0@0.3.4)(ioredis@5.8.2)(jiti@2.6.1)(lightningcss@1.30.2)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(rolldown@1.0.0-beta.53)(terser@5.44.1)(tsx@4.21.0)(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(yaml@2.8.2)':
+ '@tanstack/start-config@1.120.20(@types/node@24.10.3)(db0@0.3.4)(ioredis@5.8.2)(jiti@2.6.1)(lightningcss@1.30.2)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(rolldown@1.0.0-beta.53)(terser@5.44.1)(tsx@4.21.0)(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(yaml@2.8.2)':
dependencies:
- '@tanstack/react-router': 1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
- '@tanstack/react-start-plugin': 1.131.50(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(@vitejs/plugin-react@4.7.0(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(rolldown@1.0.0-beta.53)(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+ '@tanstack/react-router': 1.141.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
+ '@tanstack/react-start-plugin': 1.131.50(@tanstack/react-router@1.141.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(@vitejs/plugin-react@4.7.0(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(rolldown@1.0.0-beta.53)(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
'@tanstack/router-generator': 1.141.1
- '@tanstack/router-plugin': 1.159.5(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+ '@tanstack/router-plugin': 1.141.1(@tanstack/react-router@1.141.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
'@tanstack/server-functions-plugin': 1.141.0(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
- '@tanstack/start-server-functions-handler': 1.120.19(crossws@0.4.4(srvx@0.11.2))
+ '@tanstack/start-server-functions-handler': 1.120.19
'@vitejs/plugin-react': 4.7.0(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
import-meta-resolve: 4.2.0
nitropack: 2.12.9(rolldown@1.0.0-beta.53)
@@ -12467,16 +11117,14 @@ snapshots:
- xml2js
- yaml
- '@tanstack/start-fn-stubs@1.154.7': {}
-
- '@tanstack/start-plugin-core@1.131.50(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(rolldown@1.0.0-beta.53)(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
+ '@tanstack/start-plugin-core@1.131.50(@tanstack/react-router@1.141.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(rolldown@1.0.0-beta.53)(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
dependencies:
'@babel/code-frame': 7.26.2
'@babel/core': 7.28.5
- '@babel/types': 7.29.0
+ '@babel/types': 7.28.5
'@tanstack/router-core': 1.131.50
'@tanstack/router-generator': 1.131.50
- '@tanstack/router-plugin': 1.131.50(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+ '@tanstack/router-plugin': 1.131.50(@tanstack/react-router@1.141.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
'@tanstack/router-utils': 1.131.2
'@tanstack/server-functions-plugin': 1.131.2(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
'@tanstack/start-server-core': 1.131.50
@@ -12499,114 +11147,54 @@ snapshots:
- '@azure/identity'
- '@azure/keyvault-secrets'
- '@azure/storage-blob'
- - '@capacitor/preferences'
- - '@deno/kv'
- - '@electric-sql/pglite'
- - '@libsql/client'
- - '@netlify/blobs'
- - '@planetscale/database'
- - '@rsbuild/core'
- - '@tanstack/react-router'
- - '@upstash/redis'
- - '@vercel/blob'
- - '@vercel/functions'
- - '@vercel/kv'
- - aws4fetch
- - bare-abort-controller
- - better-sqlite3
- - drizzle-orm
- - encoding
- - idb-keyval
- - mysql2
- - react-native-b4a
- - rolldown
- - sqlite3
- - supports-color
- - uploadthing
- - vite-plugin-solid
- - webpack
- - xml2js
-
- '@tanstack/start-plugin-core@1.141.1(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(crossws@0.4.4(srvx@0.11.2))(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
- dependencies:
- '@babel/code-frame': 7.26.2
- '@babel/core': 7.28.5
- '@babel/types': 7.29.0
- '@rolldown/pluginutils': 1.0.0-beta.40
- '@tanstack/router-core': 1.141.1
- '@tanstack/router-generator': 1.141.1
- '@tanstack/router-plugin': 1.141.1(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
- '@tanstack/router-utils': 1.141.0
- '@tanstack/server-functions-plugin': 1.141.0(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
- '@tanstack/start-client-core': 1.141.1
- '@tanstack/start-server-core': 1.141.1(crossws@0.4.4(srvx@0.11.2))
- babel-dead-code-elimination: 1.0.10
- cheerio: 1.1.2
- exsolve: 1.0.8
- pathe: 2.0.3
- srvx: 0.8.16
- tinyglobby: 0.2.15
- ufo: 1.6.1
- vite: 7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
- vitefu: 1.1.1(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
- xmlbuilder2: 4.0.3
- zod: 3.25.76
- transitivePeerDependencies:
- - '@rsbuild/core'
- - '@tanstack/react-router'
- - crossws
- - supports-color
- - vite-plugin-solid
- - webpack
-
- '@tanstack/start-plugin-core@1.159.5(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(crossws@0.4.4(srvx@0.10.1))(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
- dependencies:
- '@babel/code-frame': 7.27.1
- '@babel/core': 7.28.5
- '@babel/types': 7.29.0
- '@rolldown/pluginutils': 1.0.0-beta.40
- '@tanstack/router-core': 1.159.4
- '@tanstack/router-generator': 1.159.4
- '@tanstack/router-plugin': 1.159.5(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
- '@tanstack/router-utils': 1.158.0
- '@tanstack/start-client-core': 1.159.4
- '@tanstack/start-server-core': 1.159.4(crossws@0.4.4(srvx@0.10.1))
- cheerio: 1.1.2
- exsolve: 1.0.8
- pathe: 2.0.3
- srvx: 0.11.2
- tinyglobby: 0.2.15
- ufo: 1.6.3
- vite: 7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
- vitefu: 1.1.1(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
- xmlbuilder2: 4.0.3
- zod: 3.25.76
- transitivePeerDependencies:
+ - '@capacitor/preferences'
+ - '@deno/kv'
+ - '@electric-sql/pglite'
+ - '@libsql/client'
+ - '@netlify/blobs'
+ - '@planetscale/database'
- '@rsbuild/core'
- '@tanstack/react-router'
- - crossws
+ - '@upstash/redis'
+ - '@vercel/blob'
+ - '@vercel/functions'
+ - '@vercel/kv'
+ - aws4fetch
+ - bare-abort-controller
+ - better-sqlite3
+ - drizzle-orm
+ - encoding
+ - idb-keyval
+ - mysql2
+ - react-native-b4a
+ - rolldown
+ - sqlite3
- supports-color
+ - uploadthing
- vite-plugin-solid
- webpack
+ - xml2js
- '@tanstack/start-plugin-core@1.159.5(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(crossws@0.4.4(srvx@0.11.2))(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
+ '@tanstack/start-plugin-core@1.141.1(@tanstack/react-router@1.141.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
dependencies:
- '@babel/code-frame': 7.27.1
+ '@babel/code-frame': 7.26.2
'@babel/core': 7.28.5
- '@babel/types': 7.29.0
+ '@babel/types': 7.28.5
'@rolldown/pluginutils': 1.0.0-beta.40
- '@tanstack/router-core': 1.159.4
- '@tanstack/router-generator': 1.159.4
- '@tanstack/router-plugin': 1.159.5(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
- '@tanstack/router-utils': 1.158.0
- '@tanstack/start-client-core': 1.159.4
- '@tanstack/start-server-core': 1.159.4(crossws@0.4.4(srvx@0.11.2))
+ '@tanstack/router-core': 1.141.1
+ '@tanstack/router-generator': 1.141.1
+ '@tanstack/router-plugin': 1.141.1(@tanstack/react-router@1.141.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+ '@tanstack/router-utils': 1.141.0
+ '@tanstack/server-functions-plugin': 1.141.0(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+ '@tanstack/start-client-core': 1.141.1
+ '@tanstack/start-server-core': 1.141.1
+ babel-dead-code-elimination: 1.0.10
cheerio: 1.1.2
exsolve: 1.0.8
pathe: 2.0.3
- srvx: 0.11.2
+ srvx: 0.8.16
tinyglobby: 0.2.15
- ufo: 1.6.3
+ ufo: 1.6.1
vite: 7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
vitefu: 1.1.1(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
xmlbuilder2: 4.0.3
@@ -12631,42 +11219,18 @@ snapshots:
tiny-warning: 1.0.3
unctx: 2.4.1
- '@tanstack/start-server-core@1.141.1(crossws@0.4.4(srvx@0.11.2))':
+ '@tanstack/start-server-core@1.141.1':
dependencies:
'@tanstack/history': 1.141.0
'@tanstack/router-core': 1.141.1
'@tanstack/start-client-core': 1.141.1
'@tanstack/start-storage-context': 1.141.1
- h3-v2: h3@2.0.0-beta.5(crossws@0.4.4(srvx@0.11.2))
+ h3-v2: h3@2.0.0-beta.5
seroval: 1.4.0
tiny-invariant: 1.3.3
transitivePeerDependencies:
- crossws
- '@tanstack/start-server-core@1.159.4(crossws@0.4.4(srvx@0.10.1))':
- dependencies:
- '@tanstack/history': 1.154.14
- '@tanstack/router-core': 1.159.4
- '@tanstack/start-client-core': 1.159.4
- '@tanstack/start-storage-context': 1.159.4
- h3-v2: h3@2.0.1-rc.14(crossws@0.4.4(srvx@0.10.1))
- seroval: 1.5.0
- tiny-invariant: 1.3.3
- transitivePeerDependencies:
- - crossws
-
- '@tanstack/start-server-core@1.159.4(crossws@0.4.4(srvx@0.11.2))':
- dependencies:
- '@tanstack/history': 1.154.14
- '@tanstack/router-core': 1.159.4
- '@tanstack/start-client-core': 1.159.4
- '@tanstack/start-storage-context': 1.159.4
- h3-v2: h3@2.0.1-rc.14(crossws@0.4.4(srvx@0.11.2))
- seroval: 1.5.0
- tiny-invariant: 1.3.3
- transitivePeerDependencies:
- - crossws
-
'@tanstack/start-server-functions-client@1.131.50(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
dependencies:
'@tanstack/server-functions-plugin': 1.131.2(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
@@ -12680,11 +11244,11 @@ snapshots:
'@tanstack/router-core': 1.131.50
'@tanstack/start-client-core': 1.131.50
- '@tanstack/start-server-functions-handler@1.120.19(crossws@0.4.4(srvx@0.11.2))':
+ '@tanstack/start-server-functions-handler@1.120.19':
dependencies:
- '@tanstack/router-core': 1.157.16
+ '@tanstack/router-core': 1.141.1
'@tanstack/start-client-core': 1.141.1
- '@tanstack/start-server-core': 1.141.1(crossws@0.4.4(srvx@0.11.2))
+ '@tanstack/start-server-core': 1.141.1
tiny-invariant: 1.3.3
transitivePeerDependencies:
- crossws
@@ -12697,11 +11261,11 @@ snapshots:
- supports-color
- vite
- '@tanstack/start-server-functions-ssr@1.120.19(crossws@0.4.4(srvx@0.11.2))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
+ '@tanstack/start-server-functions-ssr@1.120.19(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
dependencies:
'@tanstack/server-functions-plugin': 1.141.0(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
'@tanstack/start-client-core': 1.141.1
- '@tanstack/start-server-core': 1.141.1(crossws@0.4.4(srvx@0.11.2))
+ '@tanstack/start-server-core': 1.141.1
'@tanstack/start-server-functions-fetcher': 1.131.50
tiny-invariant: 1.3.3
transitivePeerDependencies:
@@ -12717,21 +11281,17 @@ snapshots:
dependencies:
'@tanstack/router-core': 1.141.1
- '@tanstack/start-storage-context@1.159.4':
- dependencies:
- '@tanstack/router-core': 1.159.4
-
- '@tanstack/start@1.120.20(@types/node@24.10.3)(crossws@0.4.4(srvx@0.11.2))(db0@0.3.4)(ioredis@5.8.2)(jiti@2.6.1)(lightningcss@1.30.2)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(rolldown@1.0.0-beta.53)(terser@5.44.1)(tsx@4.21.0)(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(yaml@2.8.2)':
+ '@tanstack/start@1.120.20(@types/node@24.10.3)(db0@0.3.4)(ioredis@5.8.2)(jiti@2.6.1)(lightningcss@1.30.2)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(rolldown@1.0.0-beta.53)(terser@5.44.1)(tsx@4.21.0)(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(yaml@2.8.2)':
dependencies:
'@tanstack/react-start-client': 1.141.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
'@tanstack/react-start-router-manifest': 1.120.19(@types/node@24.10.3)(db0@0.3.4)(ioredis@5.8.2)(jiti@2.6.1)(lightningcss@1.30.2)(rolldown@1.0.0-beta.53)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
- '@tanstack/react-start-server': 1.141.1(crossws@0.4.4(srvx@0.11.2))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
- '@tanstack/start-api-routes': 1.120.19(@types/node@24.10.3)(crossws@0.4.4(srvx@0.11.2))(db0@0.3.4)(ioredis@5.8.2)(jiti@2.6.1)(lightningcss@1.30.2)(rolldown@1.0.0-beta.53)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
- '@tanstack/start-config': 1.120.20(@types/node@24.10.3)(crossws@0.4.4(srvx@0.11.2))(db0@0.3.4)(ioredis@5.8.2)(jiti@2.6.1)(lightningcss@1.30.2)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(rolldown@1.0.0-beta.53)(terser@5.44.1)(tsx@4.21.0)(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(yaml@2.8.2)
+ '@tanstack/react-start-server': 1.141.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
+ '@tanstack/start-api-routes': 1.120.19(@types/node@24.10.3)(db0@0.3.4)(ioredis@5.8.2)(jiti@2.6.1)(lightningcss@1.30.2)(rolldown@1.0.0-beta.53)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
+ '@tanstack/start-config': 1.120.20(@types/node@24.10.3)(db0@0.3.4)(ioredis@5.8.2)(jiti@2.6.1)(lightningcss@1.30.2)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(rolldown@1.0.0-beta.53)(terser@5.44.1)(tsx@4.21.0)(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(yaml@2.8.2)
'@tanstack/start-server-functions-client': 1.131.50(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
- '@tanstack/start-server-functions-handler': 1.120.19(crossws@0.4.4(srvx@0.11.2))
+ '@tanstack/start-server-functions-handler': 1.120.19
'@tanstack/start-server-functions-server': 1.131.2(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
- '@tanstack/start-server-functions-ssr': 1.120.19(crossws@0.4.4(srvx@0.11.2))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+ '@tanstack/start-server-functions-ssr': 1.120.19(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
transitivePeerDependencies:
- '@azure/app-configuration'
- '@azure/cosmos'
@@ -12800,12 +11360,10 @@ snapshots:
'@tanstack/virtual-file-routes@1.141.0': {}
- '@tanstack/virtual-file-routes@1.154.7': {}
-
- '@tanstack/vite-config@0.4.1(@types/node@24.10.3)(rollup@4.57.1)(typescript@5.9.3)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
+ '@tanstack/vite-config@0.4.1(@types/node@24.10.3)(rollup@4.55.1)(typescript@5.9.3)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
dependencies:
- rollup-plugin-preserve-directives: 0.4.0(rollup@4.57.1)
- vite-plugin-dts: 4.2.3(@types/node@24.10.3)(rollup@4.57.1)(typescript@5.9.3)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+ rollup-plugin-preserve-directives: 0.4.0(rollup@4.55.1)
+ vite-plugin-dts: 4.2.3(@types/node@24.10.3)(rollup@4.55.1)(typescript@5.9.3)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
vite-plugin-externalize-deps: 0.10.0(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
vite-tsconfig-paths: 5.1.4(typescript@5.9.3)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
transitivePeerDependencies:
@@ -12877,16 +11435,16 @@ snapshots:
'@types/babel__generator@7.27.0':
dependencies:
- '@babel/types': 7.29.0
+ '@babel/types': 7.28.5
'@types/babel__template@7.4.4':
dependencies:
- '@babel/parser': 7.29.0
- '@babel/types': 7.29.0
+ '@babel/parser': 7.28.5
+ '@babel/types': 7.28.5
'@types/babel__traverse@7.28.0':
dependencies:
- '@babel/types': 7.29.0
+ '@babel/types': 7.28.5
'@types/braces@3.0.5': {}
@@ -12903,6 +11461,8 @@ snapshots:
'@types/deep-eql@4.0.2': {}
+ '@types/dom-mediacapture-record@1.0.22': {}
+
'@types/estree-jsx@1.0.5':
dependencies:
'@types/estree': 1.0.8
@@ -12925,17 +11485,8 @@ snapshots:
'@types/ms@2.1.0': {}
- '@types/node-fetch@2.6.13':
- dependencies:
- '@types/node': 24.10.3
- form-data: 4.0.5
-
'@types/node@12.20.55': {}
- '@types/node@18.19.130':
- dependencies:
- undici-types: 5.26.5
-
'@types/node@20.19.26':
dependencies:
undici-types: 6.21.0
@@ -12959,8 +11510,6 @@ snapshots:
'@types/resolve@1.20.2': {}
- '@types/retry@0.12.0': {}
-
'@types/unist@2.0.11': {}
'@types/unist@3.0.3': {}
@@ -13039,7 +11588,7 @@ snapshots:
'@typescript-eslint/visitor-keys': 8.49.0
debug: 4.4.3
minimatch: 9.0.5
- semver: 7.7.4
+ semver: 7.7.3
tinyglobby: 0.2.15
ts-api-utils: 2.1.0(typescript@5.9.3)
typescript: 5.9.3
@@ -13134,10 +11683,10 @@ snapshots:
'@unrs/resolver-binding-win32-x64-msvc@1.11.1':
optional: true
- '@vercel/nft@0.30.4(rollup@4.57.1)':
+ '@vercel/nft@0.30.4(rollup@4.53.3)':
dependencies:
'@mapbox/node-pre-gyp': 2.0.3
- '@rollup/pluginutils': 5.3.0(rollup@4.57.1)
+ '@rollup/pluginutils': 5.3.0(rollup@4.53.3)
acorn: 8.15.0
acorn-import-attributes: 1.9.5(acorn@8.15.0)
async-sema: 3.1.1
@@ -13153,25 +11702,6 @@ snapshots:
- rollup
- supports-color
- '@vercel/nft@1.3.0(rollup@4.57.1)':
- dependencies:
- '@mapbox/node-pre-gyp': 2.0.3
- '@rollup/pluginutils': 5.3.0(rollup@4.57.1)
- acorn: 8.15.0
- acorn-import-attributes: 1.9.5(acorn@8.15.0)
- async-sema: 3.1.1
- bindings: 1.5.0
- estree-walker: 2.0.2
- glob: 13.0.0
- graceful-fs: 4.2.11
- node-gyp-build: 4.8.4
- picomatch: 4.0.3
- resolve-from: 5.0.0
- transitivePeerDependencies:
- - encoding
- - rollup
- - supports-color
-
'@vinxi/listhen@1.5.6':
dependencies:
'@parcel/watcher': 2.5.1
@@ -13181,7 +11711,7 @@ snapshots:
consola: 3.4.2
defu: 6.1.4
get-port-please: 3.2.0
- h3: 1.15.5
+ h3: 1.13.0
http-shutdown: 1.2.2
jiti: 1.21.7
mlly: 1.8.0
@@ -13216,18 +11746,6 @@ snapshots:
transitivePeerDependencies:
- supports-color
- '@vitejs/plugin-react@5.1.2(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
- dependencies:
- '@babel/core': 7.28.5
- '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.28.5)
- '@babel/plugin-transform-react-jsx-source': 7.27.1(@babel/core@7.28.5)
- '@rolldown/pluginutils': 1.0.0-beta.53
- '@types/babel__core': 7.20.5
- react-refresh: 0.18.0
- vite: 7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
- transitivePeerDependencies:
- - supports-color
-
'@vitejs/plugin-vue@6.0.3(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(vue@3.5.25(typescript@5.9.3))':
dependencies:
'@rolldown/pluginutils': 1.0.0-beta.53
@@ -13244,12 +11762,12 @@ snapshots:
dependencies:
'@bcoe/v8-coverage': 1.0.2
'@vitest/utils': 4.0.14
- ast-v8-to-istanbul: 0.3.11
+ ast-v8-to-istanbul: 0.3.8
istanbul-lib-coverage: 3.2.2
istanbul-lib-report: 3.0.1
istanbul-lib-source-maps: 5.0.6
istanbul-reports: 3.2.0
- magicast: 0.5.2
+ magicast: 0.5.1
obug: 2.1.1
std-env: 3.10.0
tinyrainbow: 3.0.3
@@ -13257,37 +11775,37 @@ snapshots:
transitivePeerDependencies:
- supports-color
- '@vitest/coverage-v8@4.0.14(vitest@4.0.18(@types/node@24.10.3)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
+ '@vitest/coverage-v8@4.0.14(vitest@4.0.17(@types/node@24.10.3)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
dependencies:
'@bcoe/v8-coverage': 1.0.2
'@vitest/utils': 4.0.14
- ast-v8-to-istanbul: 0.3.11
+ ast-v8-to-istanbul: 0.3.8
istanbul-lib-coverage: 3.2.2
istanbul-lib-report: 3.0.1
istanbul-lib-source-maps: 5.0.6
istanbul-reports: 3.2.0
- magicast: 0.5.2
+ magicast: 0.5.1
obug: 2.1.1
std-env: 3.10.0
tinyrainbow: 3.0.3
- vitest: 4.0.18(@types/node@24.10.3)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
+ vitest: 4.0.17(@types/node@24.10.3)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
transitivePeerDependencies:
- supports-color
- '@vitest/coverage-v8@4.0.14(vitest@4.0.18(@types/node@25.0.1)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
+ '@vitest/coverage-v8@4.0.14(vitest@4.0.17(@types/node@25.0.1)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
dependencies:
'@bcoe/v8-coverage': 1.0.2
'@vitest/utils': 4.0.14
- ast-v8-to-istanbul: 0.3.11
+ ast-v8-to-istanbul: 0.3.8
istanbul-lib-coverage: 3.2.2
istanbul-lib-report: 3.0.1
istanbul-lib-source-maps: 5.0.6
istanbul-reports: 3.2.0
- magicast: 0.5.2
+ magicast: 0.5.1
obug: 2.1.1
std-env: 3.10.0
tinyrainbow: 3.0.3
- vitest: 4.0.18(@types/node@25.0.1)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
+ vitest: 4.0.17(@types/node@25.0.1)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
transitivePeerDependencies:
- supports-color
@@ -13300,34 +11818,34 @@ snapshots:
chai: 6.2.1
tinyrainbow: 3.0.3
- '@vitest/expect@4.0.18':
+ '@vitest/expect@4.0.17':
dependencies:
'@standard-schema/spec': 1.1.0
'@types/chai': 5.2.3
- '@vitest/spy': 4.0.18
- '@vitest/utils': 4.0.18
+ '@vitest/spy': 4.0.17
+ '@vitest/utils': 4.0.17
chai: 6.2.2
tinyrainbow: 3.0.3
- '@vitest/mocker@4.0.15(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
+ '@vitest/mocker@4.0.15(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
dependencies:
'@vitest/spy': 4.0.15
estree-walker: 3.0.3
magic-string: 0.30.21
optionalDependencies:
- vite: 7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
+ vite: 7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
- '@vitest/mocker@4.0.18(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
+ '@vitest/mocker@4.0.17(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
dependencies:
- '@vitest/spy': 4.0.18
+ '@vitest/spy': 4.0.17
estree-walker: 3.0.3
magic-string: 0.30.21
optionalDependencies:
vite: 7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
- '@vitest/mocker@4.0.18(vite@7.3.1(@types/node@25.0.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
+ '@vitest/mocker@4.0.17(vite@7.3.1(@types/node@25.0.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
dependencies:
- '@vitest/spy': 4.0.18
+ '@vitest/spy': 4.0.17
estree-walker: 3.0.3
magic-string: 0.30.21
optionalDependencies:
@@ -13341,7 +11859,7 @@ snapshots:
dependencies:
tinyrainbow: 3.0.3
- '@vitest/pretty-format@4.0.18':
+ '@vitest/pretty-format@4.0.17':
dependencies:
tinyrainbow: 3.0.3
@@ -13350,9 +11868,9 @@ snapshots:
'@vitest/utils': 4.0.15
pathe: 2.0.3
- '@vitest/runner@4.0.18':
+ '@vitest/runner@4.0.17':
dependencies:
- '@vitest/utils': 4.0.18
+ '@vitest/utils': 4.0.17
pathe: 2.0.3
'@vitest/snapshot@4.0.15':
@@ -13361,15 +11879,15 @@ snapshots:
magic-string: 0.30.21
pathe: 2.0.3
- '@vitest/snapshot@4.0.18':
+ '@vitest/snapshot@4.0.17':
dependencies:
- '@vitest/pretty-format': 4.0.18
+ '@vitest/pretty-format': 4.0.17
magic-string: 0.30.21
pathe: 2.0.3
'@vitest/spy@4.0.15': {}
- '@vitest/spy@4.0.18': {}
+ '@vitest/spy@4.0.17': {}
'@vitest/utils@4.0.14':
dependencies:
@@ -13381,9 +11899,9 @@ snapshots:
'@vitest/pretty-format': 4.0.15
tinyrainbow: 3.0.3
- '@vitest/utils@4.0.18':
+ '@vitest/utils@4.0.17':
dependencies:
- '@vitest/pretty-format': 4.0.18
+ '@vitest/pretty-format': 4.0.17
tinyrainbow: 3.0.3
'@volar/language-core@2.4.15':
@@ -13412,7 +11930,7 @@ snapshots:
'@vue/compiler-core@3.5.25':
dependencies:
- '@babel/parser': 7.29.0
+ '@babel/parser': 7.28.5
'@vue/shared': 3.5.25
entities: 4.5.0
estree-walker: 2.0.2
@@ -13425,7 +11943,7 @@ snapshots:
'@vue/compiler-sfc@3.5.25':
dependencies:
- '@babel/parser': 7.29.0
+ '@babel/parser': 7.28.5
'@vue/compiler-core': 3.5.25
'@vue/compiler-dom': 3.5.25
'@vue/compiler-ssr': 3.5.25
@@ -13536,10 +12054,6 @@ snapshots:
agent-base@7.1.4: {}
- agentkeepalive@4.6.0:
- dependencies:
- humanize-ms: 1.2.1
-
ajv-draft-04@1.0.0(ajv@8.13.0):
optionalDependencies:
ajv: 8.13.0
@@ -13591,8 +12105,6 @@ snapshots:
ansis@4.2.0: {}
- any-promise@1.3.0: {}
-
anymatch@3.1.3:
dependencies:
normalize-path: 3.0.0
@@ -13648,18 +12160,18 @@ snapshots:
ast-kit@2.2.0:
dependencies:
- '@babel/parser': 7.29.0
+ '@babel/parser': 7.28.5
pathe: 2.0.3
ast-types@0.16.1:
dependencies:
tslib: 2.8.1
- ast-v8-to-istanbul@0.3.11:
+ ast-v8-to-istanbul@0.3.8:
dependencies:
'@jridgewell/trace-mapping': 0.3.31
estree-walker: 3.0.3
- js-tokens: 10.0.0
+ js-tokens: 9.0.1
async-sema@3.1.1: {}
@@ -13696,18 +12208,9 @@ snapshots:
babel-dead-code-elimination@1.0.10:
dependencies:
'@babel/core': 7.28.5
- '@babel/parser': 7.29.0
- '@babel/traverse': 7.28.5
- '@babel/types': 7.29.0
- transitivePeerDependencies:
- - supports-color
-
- babel-dead-code-elimination@1.0.12:
- dependencies:
- '@babel/core': 7.28.5
- '@babel/parser': 7.29.0
+ '@babel/parser': 7.28.5
'@babel/traverse': 7.28.5
- '@babel/types': 7.29.0
+ '@babel/types': 7.28.5
transitivePeerDependencies:
- supports-color
@@ -13716,7 +12219,7 @@ snapshots:
'@babel/core': 7.28.5
'@babel/helper-module-imports': 7.18.6
'@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.28.5)
- '@babel/types': 7.29.0
+ '@babel/types': 7.28.5
html-entities: 2.3.3
parse5: 7.3.0
@@ -13825,14 +12328,9 @@ snapshots:
base64-js: 1.5.1
ieee754: 1.2.1
- bundle-require@5.1.0(esbuild@0.27.3):
- dependencies:
- esbuild: 0.27.3
- load-tsconfig: 0.2.5
-
bytes@3.1.2: {}
- c12@3.3.2(magicast@0.5.2):
+ c12@3.3.2(magicast@0.5.1):
dependencies:
chokidar: 4.0.3
confbox: 0.2.2
@@ -13847,24 +12345,7 @@ snapshots:
pkg-types: 2.3.0
rc9: 2.1.2
optionalDependencies:
- magicast: 0.5.2
-
- c12@3.3.3(magicast@0.5.2):
- dependencies:
- chokidar: 5.0.0
- confbox: 0.2.2
- defu: 6.1.4
- dotenv: 17.2.3
- exsolve: 1.0.8
- giget: 2.0.0
- jiti: 2.6.1
- ohash: 2.0.11
- pathe: 2.0.3
- perfect-debounce: 2.0.0
- pkg-types: 2.3.0
- rc9: 2.1.2
- optionalDependencies:
- magicast: 0.5.2
+ magicast: 0.5.1
cac@6.7.14: {}
@@ -14011,8 +12492,6 @@ snapshots:
commander@2.20.3: {}
- commander@4.1.1: {}
-
comment-parser@1.4.1: {}
commondir@1.0.1: {}
@@ -14090,15 +12569,6 @@ snapshots:
dependencies:
uncrypto: 0.1.3
- crossws@0.4.4(srvx@0.10.1):
- optionalDependencies:
- srvx: 0.10.1
-
- crossws@0.4.4(srvx@0.11.2):
- optionalDependencies:
- srvx: 0.11.2
- optional: true
-
css-select@5.2.2:
dependencies:
boolbase: 1.0.0
@@ -14138,8 +12608,6 @@ snapshots:
'@deno/shim-deno': 0.19.2
undici-types: 5.28.4
- dayjs@1.11.19: {}
-
db0@0.3.4: {}
de-indent@1.0.2: {}
@@ -14261,7 +12729,7 @@ snapshots:
dotenv-expand@11.0.7:
dependencies:
- dotenv: 16.6.1
+ dotenv: 16.4.7
dotenv@16.4.7: {}
@@ -14292,7 +12760,7 @@ snapshots:
'@one-ini/wasm': 0.1.1
commander: 10.0.1
minimatch: 9.0.1
- semver: 7.7.4
+ semver: 7.7.3
ee-first@1.1.1: {}
@@ -14366,16 +12834,6 @@ snapshots:
has-tostringtag: 1.0.2
hasown: 2.0.2
- esbuild-plugin-solid@0.5.0(esbuild@0.27.3)(solid-js@1.9.10):
- dependencies:
- '@babel/core': 7.28.5
- '@babel/preset-typescript': 7.28.5(@babel/core@7.28.5)
- babel-preset-solid: 1.9.10(@babel/core@7.28.5)(solid-js@1.9.10)
- esbuild: 0.27.3
- solid-js: 1.9.10
- transitivePeerDependencies:
- - supports-color
-
esbuild@0.20.2:
optionalDependencies:
'@esbuild/aix-ppc64': 0.20.2
@@ -14431,6 +12889,35 @@ snapshots:
'@esbuild/win32-ia32': 0.25.12
'@esbuild/win32-x64': 0.25.12
+ esbuild@0.27.1:
+ optionalDependencies:
+ '@esbuild/aix-ppc64': 0.27.1
+ '@esbuild/android-arm': 0.27.1
+ '@esbuild/android-arm64': 0.27.1
+ '@esbuild/android-x64': 0.27.1
+ '@esbuild/darwin-arm64': 0.27.1
+ '@esbuild/darwin-x64': 0.27.1
+ '@esbuild/freebsd-arm64': 0.27.1
+ '@esbuild/freebsd-x64': 0.27.1
+ '@esbuild/linux-arm': 0.27.1
+ '@esbuild/linux-arm64': 0.27.1
+ '@esbuild/linux-ia32': 0.27.1
+ '@esbuild/linux-loong64': 0.27.1
+ '@esbuild/linux-mips64el': 0.27.1
+ '@esbuild/linux-ppc64': 0.27.1
+ '@esbuild/linux-riscv64': 0.27.1
+ '@esbuild/linux-s390x': 0.27.1
+ '@esbuild/linux-x64': 0.27.1
+ '@esbuild/netbsd-arm64': 0.27.1
+ '@esbuild/netbsd-x64': 0.27.1
+ '@esbuild/openbsd-arm64': 0.27.1
+ '@esbuild/openbsd-x64': 0.27.1
+ '@esbuild/openharmony-arm64': 0.27.1
+ '@esbuild/sunos-x64': 0.27.1
+ '@esbuild/win32-arm64': 0.27.1
+ '@esbuild/win32-ia32': 0.27.1
+ '@esbuild/win32-x64': 0.27.1
+
esbuild@0.27.2:
optionalDependencies:
'@esbuild/aix-ppc64': 0.27.2
@@ -14460,35 +12947,6 @@ snapshots:
'@esbuild/win32-ia32': 0.27.2
'@esbuild/win32-x64': 0.27.2
- esbuild@0.27.3:
- optionalDependencies:
- '@esbuild/aix-ppc64': 0.27.3
- '@esbuild/android-arm': 0.27.3
- '@esbuild/android-arm64': 0.27.3
- '@esbuild/android-x64': 0.27.3
- '@esbuild/darwin-arm64': 0.27.3
- '@esbuild/darwin-x64': 0.27.3
- '@esbuild/freebsd-arm64': 0.27.3
- '@esbuild/freebsd-x64': 0.27.3
- '@esbuild/linux-arm': 0.27.3
- '@esbuild/linux-arm64': 0.27.3
- '@esbuild/linux-ia32': 0.27.3
- '@esbuild/linux-loong64': 0.27.3
- '@esbuild/linux-mips64el': 0.27.3
- '@esbuild/linux-ppc64': 0.27.3
- '@esbuild/linux-riscv64': 0.27.3
- '@esbuild/linux-s390x': 0.27.3
- '@esbuild/linux-x64': 0.27.3
- '@esbuild/netbsd-arm64': 0.27.3
- '@esbuild/netbsd-x64': 0.27.3
- '@esbuild/openbsd-arm64': 0.27.3
- '@esbuild/openbsd-x64': 0.27.3
- '@esbuild/openharmony-arm64': 0.27.3
- '@esbuild/sunos-x64': 0.27.3
- '@esbuild/win32-arm64': 0.27.3
- '@esbuild/win32-ia32': 0.27.3
- '@esbuild/win32-x64': 0.27.3
-
escalade@3.2.0: {}
escape-html@1.0.3: {}
@@ -14502,7 +12960,7 @@ snapshots:
eslint-compat-utils@0.5.1(eslint@9.39.1(jiti@2.6.1)):
dependencies:
eslint: 9.39.1(jiti@2.6.1)
- semver: 7.7.4
+ semver: 7.7.3
eslint-import-context@0.1.9(unrs-resolver@1.11.1):
dependencies:
@@ -14712,8 +13170,6 @@ snapshots:
events@3.3.0: {}
- eventsource-parser@1.1.2: {}
-
execa@8.0.1:
dependencies:
cross-spawn: 7.0.6
@@ -14837,12 +13293,6 @@ snapshots:
locate-path: 6.0.0
path-exists: 4.0.0
- fix-dts-default-cjs-exports@1.0.1:
- dependencies:
- magic-string: 0.30.21
- mlly: 1.8.0
- rollup: 4.57.1
-
flat-cache@4.0.1:
dependencies:
flatted: 3.3.3
@@ -14863,8 +13313,6 @@ snapshots:
cross-spawn: 7.0.6
signal-exit: 4.1.0
- form-data-encoder@1.7.2: {}
-
form-data@4.0.5:
dependencies:
asynckit: 0.4.0
@@ -14877,11 +13325,6 @@ snapshots:
dependencies:
fd-package-json: 2.0.0
- formdata-node@4.4.1:
- dependencies:
- node-domexception: 1.0.0
- web-streams-polyfill: 4.0.0-beta.3
-
formdata-polyfill@4.0.10:
dependencies:
fetch-blob: 3.2.0
@@ -14995,12 +13438,6 @@ snapshots:
package-json-from-dist: 1.0.1
path-scurry: 1.11.1
- glob@13.0.0:
- dependencies:
- minimatch: 10.1.1
- minipass: 7.1.2
- path-scurry: 2.0.1
-
globals@14.0.0: {}
globals@15.15.0: {}
@@ -15025,15 +13462,6 @@ snapshots:
slash: 5.1.0
unicorn-magic: 0.3.0
- globby@16.1.0:
- dependencies:
- '@sindresorhus/merge-streams': 4.0.0
- fast-glob: 3.3.3
- ignore: 7.0.5
- is-path-inside: 4.0.0
- slash: 5.1.0
- unicorn-magic: 0.4.0
-
globrex@0.1.2: {}
goober@2.1.18(csstype@3.2.3):
@@ -15058,18 +13486,6 @@ snapshots:
graceful-fs@4.2.11: {}
- groq-sdk@0.37.0:
- dependencies:
- '@types/node': 18.19.130
- '@types/node-fetch': 2.6.13
- abort-controller: 3.0.0
- agentkeepalive: 4.6.0
- form-data-encoder: 1.7.2
- formdata-node: 4.4.1
- node-fetch: 2.7.0
- transitivePeerDependencies:
- - encoding
-
gtoken@8.0.0:
dependencies:
gaxios: 7.1.3
@@ -15094,7 +13510,7 @@ snapshots:
uncrypto: 0.1.3
unenv: 1.10.0
- h3@1.15.5:
+ h3@1.15.4:
dependencies:
cookie-es: 1.2.2
crossws: 0.3.5
@@ -15103,31 +13519,15 @@ snapshots:
iron-webcrypto: 1.2.1
node-mock-http: 1.0.4
radix3: 1.1.2
- ufo: 1.6.3
+ ufo: 1.6.1
uncrypto: 0.1.3
- h3@2.0.0-beta.5(crossws@0.4.4(srvx@0.11.2)):
+ h3@2.0.0-beta.5:
dependencies:
cookie-es: 2.0.0
fetchdts: 0.1.7
rou3: 0.7.12
srvx: 0.8.16
- optionalDependencies:
- crossws: 0.4.4(srvx@0.11.2)
-
- h3@2.0.1-rc.14(crossws@0.4.4(srvx@0.10.1)):
- dependencies:
- rou3: 0.7.12
- srvx: 0.11.2
- optionalDependencies:
- crossws: 0.4.4(srvx@0.10.1)
-
- h3@2.0.1-rc.14(crossws@0.4.4(srvx@0.11.2)):
- dependencies:
- rou3: 0.7.12
- srvx: 0.11.2
- optionalDependencies:
- crossws: 0.4.4(srvx@0.11.2)
happy-dom@20.0.11:
dependencies:
@@ -15320,10 +13720,6 @@ snapshots:
human-signals@5.0.0: {}
- humanize-ms@1.2.1:
- dependencies:
- ms: 2.1.3
-
iconv-lite@0.6.3:
dependencies:
safer-buffer: 2.1.2
@@ -15379,20 +13775,6 @@ snapshots:
transitivePeerDependencies:
- supports-color
- ioredis@5.9.2:
- dependencies:
- '@ioredis/commands': 1.5.0
- cluster-key-slot: 1.1.2
- debug: 4.4.3
- denque: 2.1.0
- lodash.defaults: 4.2.0
- lodash.isarguments: 3.1.0
- redis-errors: 1.2.0
- redis-parser: 3.0.0
- standard-as-callback: 2.1.0
- transitivePeerDependencies:
- - supports-color
-
ipaddr.js@1.9.1: {}
iron-webcrypto@1.2.1: {}
@@ -15476,8 +13858,6 @@ snapshots:
is-number@7.0.0: {}
- is-path-inside@4.0.0: {}
-
is-plain-obj@4.1.0: {}
is-potential-custom-element-name@1.0.1: {}
@@ -15599,7 +13979,7 @@ snapshots:
jju@1.4.0: {}
- joycon@3.1.1: {}
+ jose@6.1.3: {}
js-beautify@1.15.4:
dependencies:
@@ -15611,8 +13991,6 @@ snapshots:
js-cookie@3.0.5: {}
- js-tokens@10.0.0: {}
-
js-tokens@4.0.0: {}
js-tokens@9.0.1: {}
@@ -15722,7 +14100,7 @@ snapshots:
smol-toml: 1.5.2
strip-json-comments: 5.0.3
typescript: 5.9.3
- zod: 4.3.6
+ zod: 4.2.1
knitwork@1.3.0: {}
@@ -15793,10 +14171,6 @@ snapshots:
lightningcss-win32-arm64-msvc: 1.30.2
lightningcss-win32-x64-msvc: 1.30.2
- lilconfig@3.1.3: {}
-
- lines-and-columns@1.2.4: {}
-
lines-and-columns@2.0.3: {}
linkify-it@5.0.0:
@@ -15813,7 +14187,7 @@ snapshots:
crossws: 0.3.5
defu: 6.1.4
get-port-please: 3.2.0
- h3: 1.15.5
+ h3: 1.15.4
http-shutdown: 1.2.2
jiti: 2.6.1
mlly: 1.8.0
@@ -15824,7 +14198,19 @@ snapshots:
untun: 0.1.3
uqr: 0.1.2
- load-tsconfig@0.2.5: {}
+ livekit-client@2.17.0(@types/dom-mediacapture-record@1.0.22):
+ dependencies:
+ '@livekit/mutex': 1.1.1
+ '@livekit/protocol': 1.42.2
+ '@types/dom-mediacapture-record': 1.0.22
+ events: 3.3.0
+ jose: 6.1.3
+ loglevel: 1.9.2
+ sdp-transform: 2.15.0
+ ts-debounce: 4.0.0
+ tslib: 2.8.1
+ typed-emitter: 2.1.0
+ webrtc-adapter: 9.0.3
local-pkg@0.5.1:
dependencies:
@@ -15862,7 +14248,7 @@ snapshots:
chalk: 4.1.2
is-unicode-supported: 0.1.0
- long@5.3.2: {}
+ loglevel@1.9.2: {}
longest-streak@3.1.0: {}
@@ -15904,15 +14290,15 @@ snapshots:
dependencies:
'@jridgewell/sourcemap-codec': 1.5.5
- magicast@0.5.2:
+ magicast@0.5.1:
dependencies:
- '@babel/parser': 7.29.0
- '@babel/types': 7.29.0
+ '@babel/parser': 7.28.5
+ '@babel/types': 7.28.5
source-map-js: 1.2.1
make-dir@4.0.0:
dependencies:
- semver: 7.7.4
+ semver: 7.7.3
markdown-it@14.1.0:
dependencies:
@@ -16380,84 +14766,27 @@ snapshots:
muggle-string@0.4.1: {}
- mz@2.7.0:
- dependencies:
- any-promise: 1.3.0
- object-assign: 4.1.1
- thenify-all: 1.6.0
-
- nanoid@3.3.11: {}
-
- napi-postinstall@0.3.4: {}
-
- natural-compare@1.4.0: {}
-
- negotiator@1.0.0: {}
-
- nf3@0.3.10: {}
-
- nitro@3.0.1-alpha.2(chokidar@5.0.0)(ioredis@5.9.2)(lru-cache@11.2.4)(rolldown@1.0.0-beta.53)(rollup@4.57.1)(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)):
- dependencies:
- consola: 3.4.2
- crossws: 0.4.4(srvx@0.10.1)
- db0: 0.3.4
- h3: 2.0.1-rc.14(crossws@0.4.4(srvx@0.10.1))
- jiti: 2.6.1
- nf3: 0.3.10
- ofetch: 2.0.0-alpha.3
- ohash: 2.0.11
- oxc-minify: 0.110.0
- oxc-transform: 0.110.0
- srvx: 0.10.1
- undici: 7.21.0
- unenv: 2.0.0-rc.24
- unstorage: 2.0.0-alpha.5(chokidar@5.0.0)(db0@0.3.4)(ioredis@5.9.2)(lru-cache@11.2.4)(ofetch@2.0.0-alpha.3)
- optionalDependencies:
- rolldown: 1.0.0-beta.53
- rollup: 4.57.1
- vite: 7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
- transitivePeerDependencies:
- - '@azure/app-configuration'
- - '@azure/cosmos'
- - '@azure/data-tables'
- - '@azure/identity'
- - '@azure/keyvault-secrets'
- - '@azure/storage-blob'
- - '@capacitor/preferences'
- - '@deno/kv'
- - '@electric-sql/pglite'
- - '@libsql/client'
- - '@netlify/blobs'
- - '@planetscale/database'
- - '@upstash/redis'
- - '@vercel/blob'
- - '@vercel/functions'
- - '@vercel/kv'
- - aws4fetch
- - better-sqlite3
- - chokidar
- - drizzle-orm
- - idb-keyval
- - ioredis
- - lru-cache
- - mongodb
- - mysql2
- - sqlite3
- - uploadthing
+ nanoid@3.3.11: {}
+
+ napi-postinstall@0.3.4: {}
+
+ natural-compare@1.4.0: {}
+
+ negotiator@1.0.0: {}
nitropack@2.12.9(rolldown@1.0.0-beta.53):
dependencies:
'@cloudflare/kv-asset-handler': 0.4.1
- '@rollup/plugin-alias': 5.1.1(rollup@4.57.1)
- '@rollup/plugin-commonjs': 28.0.9(rollup@4.57.1)
- '@rollup/plugin-inject': 5.0.5(rollup@4.57.1)
- '@rollup/plugin-json': 6.1.0(rollup@4.57.1)
- '@rollup/plugin-node-resolve': 16.0.3(rollup@4.57.1)
- '@rollup/plugin-replace': 6.0.3(rollup@4.57.1)
- '@rollup/plugin-terser': 0.4.4(rollup@4.57.1)
- '@vercel/nft': 0.30.4(rollup@4.57.1)
+ '@rollup/plugin-alias': 5.1.1(rollup@4.53.3)
+ '@rollup/plugin-commonjs': 28.0.9(rollup@4.53.3)
+ '@rollup/plugin-inject': 5.0.5(rollup@4.53.3)
+ '@rollup/plugin-json': 6.1.0(rollup@4.53.3)
+ '@rollup/plugin-node-resolve': 16.0.3(rollup@4.53.3)
+ '@rollup/plugin-replace': 6.0.3(rollup@4.53.3)
+ '@rollup/plugin-terser': 0.4.4(rollup@4.53.3)
+ '@vercel/nft': 0.30.4(rollup@4.53.3)
archiver: 7.0.1
- c12: 3.3.2(magicast@0.5.2)
+ c12: 3.3.2(magicast@0.5.1)
chokidar: 4.0.3
citty: 0.1.6
compatx: 0.2.0
@@ -16476,7 +14805,7 @@ snapshots:
exsolve: 1.0.8
globby: 15.0.0
gzip-size: 7.0.0
- h3: 1.15.5
+ h3: 1.15.4
hookable: 5.5.3
httpxy: 0.1.7
ioredis: 5.8.2
@@ -16485,7 +14814,7 @@ snapshots:
knitwork: 1.3.0
listhen: 1.9.0
magic-string: 0.30.21
- magicast: 0.5.2
+ magicast: 0.5.1
mime: 4.1.0
mlly: 1.8.0
node-fetch-native: 1.6.7
@@ -16497,10 +14826,10 @@ snapshots:
pkg-types: 2.3.0
pretty-bytes: 7.1.0
radix3: 1.1.2
- rollup: 4.57.1
- rollup-plugin-visualizer: 6.0.5(rolldown@1.0.0-beta.53)(rollup@4.57.1)
+ rollup: 4.53.3
+ rollup-plugin-visualizer: 6.0.5(rolldown@1.0.0-beta.53)(rollup@4.53.3)
scule: 1.3.0
- semver: 7.7.4
+ semver: 7.7.3
serve-placeholder: 2.0.2
serve-static: 2.2.0
source-map: 0.7.6
@@ -16512,7 +14841,7 @@ snapshots:
unenv: 2.0.0-rc.24
unimport: 5.5.0
unplugin-utils: 0.3.1
- unstorage: 1.17.4(db0@0.3.4)(ioredis@5.8.2)
+ unstorage: 1.17.3(db0@0.3.4)(ioredis@5.8.2)
untyped: 2.0.0
unwasm: 0.3.11
youch: 4.1.0-beta.13
@@ -16547,108 +14876,6 @@ snapshots:
- supports-color
- uploadthing
- nitropack@2.13.1(rolldown@1.0.0-beta.53):
- dependencies:
- '@cloudflare/kv-asset-handler': 0.4.2
- '@rollup/plugin-alias': 6.0.0(rollup@4.57.1)
- '@rollup/plugin-commonjs': 29.0.0(rollup@4.57.1)
- '@rollup/plugin-inject': 5.0.5(rollup@4.57.1)
- '@rollup/plugin-json': 6.1.0(rollup@4.57.1)
- '@rollup/plugin-node-resolve': 16.0.3(rollup@4.57.1)
- '@rollup/plugin-replace': 6.0.3(rollup@4.57.1)
- '@rollup/plugin-terser': 0.4.4(rollup@4.57.1)
- '@vercel/nft': 1.3.0(rollup@4.57.1)
- archiver: 7.0.1
- c12: 3.3.3(magicast@0.5.2)
- chokidar: 5.0.0
- citty: 0.1.6
- compatx: 0.2.0
- confbox: 0.2.2
- consola: 3.4.2
- cookie-es: 2.0.0
- croner: 9.1.0
- crossws: 0.3.5
- db0: 0.3.4
- defu: 6.1.4
- destr: 2.0.5
- dot-prop: 10.1.0
- esbuild: 0.27.3
- escape-string-regexp: 5.0.0
- etag: 1.8.1
- exsolve: 1.0.8
- globby: 16.1.0
- gzip-size: 7.0.0
- h3: 1.15.5
- hookable: 5.5.3
- httpxy: 0.1.7
- ioredis: 5.9.2
- jiti: 2.6.1
- klona: 2.0.6
- knitwork: 1.3.0
- listhen: 1.9.0
- magic-string: 0.30.21
- magicast: 0.5.2
- mime: 4.1.0
- mlly: 1.8.0
- node-fetch-native: 1.6.7
- node-mock-http: 1.0.4
- ofetch: 1.5.1
- ohash: 2.0.11
- pathe: 2.0.3
- perfect-debounce: 2.0.0
- pkg-types: 2.3.0
- pretty-bytes: 7.1.0
- radix3: 1.1.2
- rollup: 4.57.1
- rollup-plugin-visualizer: 6.0.5(rolldown@1.0.0-beta.53)(rollup@4.57.1)
- scule: 1.3.0
- semver: 7.7.4
- serve-placeholder: 2.0.2
- serve-static: 2.2.1
- source-map: 0.7.6
- std-env: 3.10.0
- ufo: 1.6.3
- ultrahtml: 1.6.0
- uncrypto: 0.1.3
- unctx: 2.5.0
- unenv: 2.0.0-rc.24
- unimport: 5.6.0
- unplugin-utils: 0.3.1
- unstorage: 1.17.4(db0@0.3.4)(ioredis@5.9.2)
- untyped: 2.0.0
- unwasm: 0.5.3
- youch: 4.1.0-beta.13
- youch-core: 0.3.3
- transitivePeerDependencies:
- - '@azure/app-configuration'
- - '@azure/cosmos'
- - '@azure/data-tables'
- - '@azure/identity'
- - '@azure/keyvault-secrets'
- - '@azure/storage-blob'
- - '@capacitor/preferences'
- - '@deno/kv'
- - '@electric-sql/pglite'
- - '@libsql/client'
- - '@netlify/blobs'
- - '@planetscale/database'
- - '@upstash/redis'
- - '@vercel/blob'
- - '@vercel/functions'
- - '@vercel/kv'
- - aws4fetch
- - bare-abort-controller
- - better-sqlite3
- - drizzle-orm
- - encoding
- - idb-keyval
- - mysql2
- - react-native-b4a
- - rolldown
- - sqlite3
- - supports-color
- - uploadthing
-
node-addon-api@7.1.1: {}
node-domexception@1.0.0: {}
@@ -16758,8 +14985,6 @@ snapshots:
pkg-types: 2.3.0
tinyexec: 1.0.2
- object-assign@4.1.1: {}
-
object-inspect@1.13.4: {}
object-is@1.1.6:
@@ -16786,8 +15011,6 @@ snapshots:
node-fetch-native: 1.6.7
ufo: 1.6.1
- ofetch@2.0.0-alpha.3: {}
-
ohash@1.1.6: {}
ohash@2.0.11: {}
@@ -16845,29 +15068,6 @@ snapshots:
outdent@0.5.0: {}
- oxc-minify@0.110.0:
- optionalDependencies:
- '@oxc-minify/binding-android-arm-eabi': 0.110.0
- '@oxc-minify/binding-android-arm64': 0.110.0
- '@oxc-minify/binding-darwin-arm64': 0.110.0
- '@oxc-minify/binding-darwin-x64': 0.110.0
- '@oxc-minify/binding-freebsd-x64': 0.110.0
- '@oxc-minify/binding-linux-arm-gnueabihf': 0.110.0
- '@oxc-minify/binding-linux-arm-musleabihf': 0.110.0
- '@oxc-minify/binding-linux-arm64-gnu': 0.110.0
- '@oxc-minify/binding-linux-arm64-musl': 0.110.0
- '@oxc-minify/binding-linux-ppc64-gnu': 0.110.0
- '@oxc-minify/binding-linux-riscv64-gnu': 0.110.0
- '@oxc-minify/binding-linux-riscv64-musl': 0.110.0
- '@oxc-minify/binding-linux-s390x-gnu': 0.110.0
- '@oxc-minify/binding-linux-x64-gnu': 0.110.0
- '@oxc-minify/binding-linux-x64-musl': 0.110.0
- '@oxc-minify/binding-openharmony-arm64': 0.110.0
- '@oxc-minify/binding-wasm32-wasi': 0.110.0
- '@oxc-minify/binding-win32-arm64-msvc': 0.110.0
- '@oxc-minify/binding-win32-ia32-msvc': 0.110.0
- '@oxc-minify/binding-win32-x64-msvc': 0.110.0
-
oxc-resolver@11.15.0:
optionalDependencies:
'@oxc-resolver/binding-android-arm-eabi': 11.15.0
@@ -16891,29 +15091,6 @@ snapshots:
'@oxc-resolver/binding-win32-ia32-msvc': 11.15.0
'@oxc-resolver/binding-win32-x64-msvc': 11.15.0
- oxc-transform@0.110.0:
- optionalDependencies:
- '@oxc-transform/binding-android-arm-eabi': 0.110.0
- '@oxc-transform/binding-android-arm64': 0.110.0
- '@oxc-transform/binding-darwin-arm64': 0.110.0
- '@oxc-transform/binding-darwin-x64': 0.110.0
- '@oxc-transform/binding-freebsd-x64': 0.110.0
- '@oxc-transform/binding-linux-arm-gnueabihf': 0.110.0
- '@oxc-transform/binding-linux-arm-musleabihf': 0.110.0
- '@oxc-transform/binding-linux-arm64-gnu': 0.110.0
- '@oxc-transform/binding-linux-arm64-musl': 0.110.0
- '@oxc-transform/binding-linux-ppc64-gnu': 0.110.0
- '@oxc-transform/binding-linux-riscv64-gnu': 0.110.0
- '@oxc-transform/binding-linux-riscv64-musl': 0.110.0
- '@oxc-transform/binding-linux-s390x-gnu': 0.110.0
- '@oxc-transform/binding-linux-x64-gnu': 0.110.0
- '@oxc-transform/binding-linux-x64-musl': 0.110.0
- '@oxc-transform/binding-openharmony-arm64': 0.110.0
- '@oxc-transform/binding-wasm32-wasi': 0.110.0
- '@oxc-transform/binding-win32-arm64-msvc': 0.110.0
- '@oxc-transform/binding-win32-ia32-msvc': 0.110.0
- '@oxc-transform/binding-win32-x64-msvc': 0.110.0
-
p-filter@2.1.0:
dependencies:
p-map: 2.1.0
@@ -16936,11 +15113,6 @@ snapshots:
p-map@2.1.0: {}
- p-retry@4.6.2:
- dependencies:
- '@types/retry': 0.12.0
- retry: 0.13.1
-
p-try@2.2.0: {}
package-json-from-dist@1.0.1: {}
@@ -17001,11 +15173,6 @@ snapshots:
lru-cache: 10.4.3
minipass: 7.1.2
- path-scurry@2.0.1:
- dependencies:
- lru-cache: 11.2.4
- minipass: 7.1.2
-
path-to-regexp@6.3.0: {}
path-to-regexp@8.3.0: {}
@@ -17028,8 +15195,6 @@ snapshots:
pify@4.0.1: {}
- pirates@4.0.7: {}
-
pkg-types@1.3.1:
dependencies:
confbox: 0.1.8
@@ -17052,15 +15217,6 @@ snapshots:
possible-typed-array-names@1.1.0: {}
- postcss-load-config@6.0.1(jiti@2.6.1)(postcss@8.5.6)(tsx@4.21.0)(yaml@2.8.2):
- dependencies:
- lilconfig: 3.1.3
- optionalDependencies:
- jiti: 2.6.1
- postcss: 8.5.6
- tsx: 4.21.0
- yaml: 2.8.2
-
postcss-value-parser@4.2.0: {}
postcss@8.5.6:
@@ -17110,21 +15266,6 @@ snapshots:
proto-list@1.2.4: {}
- protobufjs@7.5.4:
- dependencies:
- '@protobufjs/aspromise': 1.1.2
- '@protobufjs/base64': 1.1.2
- '@protobufjs/codegen': 2.0.4
- '@protobufjs/eventemitter': 1.1.0
- '@protobufjs/fetch': 1.1.0
- '@protobufjs/float': 1.0.2
- '@protobufjs/inquire': 1.1.0
- '@protobufjs/path': 1.1.2
- '@protobufjs/pool': 1.1.0
- '@protobufjs/utf8': 1.1.0
- '@types/node': 24.10.3
- long: 5.3.2
-
proxy-addr@2.0.7:
dependencies:
forwarded: 0.2.0
@@ -17350,21 +15491,17 @@ snapshots:
onetime: 5.1.2
signal-exit: 3.0.7
- retry@0.13.1: {}
-
reusify@1.1.0: {}
rimraf@5.0.10:
dependencies:
glob: 10.5.0
- robot3@0.4.1: {}
-
rolldown-plugin-dts@0.18.3(oxc-resolver@11.15.0)(rolldown@1.0.0-beta.53)(typescript@5.9.3):
dependencies:
'@babel/generator': 7.28.5
- '@babel/parser': 7.29.0
- '@babel/types': 7.29.0
+ '@babel/parser': 7.28.5
+ '@babel/types': 7.28.5
ast-kit: 2.2.0
birpc: 3.0.0
dts-resolver: 2.1.3(oxc-resolver@11.15.0)
@@ -17396,13 +15533,13 @@ snapshots:
'@rolldown/binding-win32-arm64-msvc': 1.0.0-beta.53
'@rolldown/binding-win32-x64-msvc': 1.0.0-beta.53
- rollup-plugin-preserve-directives@0.4.0(rollup@4.57.1):
+ rollup-plugin-preserve-directives@0.4.0(rollup@4.55.1):
dependencies:
- '@rollup/pluginutils': 5.3.0(rollup@4.57.1)
+ '@rollup/pluginutils': 5.3.0(rollup@4.55.1)
magic-string: 0.30.21
- rollup: 4.57.1
+ rollup: 4.55.1
- rollup-plugin-visualizer@6.0.5(rolldown@1.0.0-beta.53)(rollup@4.57.1):
+ rollup-plugin-visualizer@6.0.5(rolldown@1.0.0-beta.53)(rollup@4.53.3):
dependencies:
open: 8.4.2
picomatch: 4.0.3
@@ -17410,7 +15547,7 @@ snapshots:
yargs: 17.7.2
optionalDependencies:
rolldown: 1.0.0-beta.53
- rollup: 4.57.1
+ rollup: 4.53.3
rollup@4.53.3:
dependencies:
@@ -17440,35 +15577,35 @@ snapshots:
'@rollup/rollup-win32-x64-msvc': 4.53.3
fsevents: 2.3.3
- rollup@4.57.1:
+ rollup@4.55.1:
dependencies:
'@types/estree': 1.0.8
optionalDependencies:
- '@rollup/rollup-android-arm-eabi': 4.57.1
- '@rollup/rollup-android-arm64': 4.57.1
- '@rollup/rollup-darwin-arm64': 4.57.1
- '@rollup/rollup-darwin-x64': 4.57.1
- '@rollup/rollup-freebsd-arm64': 4.57.1
- '@rollup/rollup-freebsd-x64': 4.57.1
- '@rollup/rollup-linux-arm-gnueabihf': 4.57.1
- '@rollup/rollup-linux-arm-musleabihf': 4.57.1
- '@rollup/rollup-linux-arm64-gnu': 4.57.1
- '@rollup/rollup-linux-arm64-musl': 4.57.1
- '@rollup/rollup-linux-loong64-gnu': 4.57.1
- '@rollup/rollup-linux-loong64-musl': 4.57.1
- '@rollup/rollup-linux-ppc64-gnu': 4.57.1
- '@rollup/rollup-linux-ppc64-musl': 4.57.1
- '@rollup/rollup-linux-riscv64-gnu': 4.57.1
- '@rollup/rollup-linux-riscv64-musl': 4.57.1
- '@rollup/rollup-linux-s390x-gnu': 4.57.1
- '@rollup/rollup-linux-x64-gnu': 4.57.1
- '@rollup/rollup-linux-x64-musl': 4.57.1
- '@rollup/rollup-openbsd-x64': 4.57.1
- '@rollup/rollup-openharmony-arm64': 4.57.1
- '@rollup/rollup-win32-arm64-msvc': 4.57.1
- '@rollup/rollup-win32-ia32-msvc': 4.57.1
- '@rollup/rollup-win32-x64-gnu': 4.57.1
- '@rollup/rollup-win32-x64-msvc': 4.57.1
+ '@rollup/rollup-android-arm-eabi': 4.55.1
+ '@rollup/rollup-android-arm64': 4.55.1
+ '@rollup/rollup-darwin-arm64': 4.55.1
+ '@rollup/rollup-darwin-x64': 4.55.1
+ '@rollup/rollup-freebsd-arm64': 4.55.1
+ '@rollup/rollup-freebsd-x64': 4.55.1
+ '@rollup/rollup-linux-arm-gnueabihf': 4.55.1
+ '@rollup/rollup-linux-arm-musleabihf': 4.55.1
+ '@rollup/rollup-linux-arm64-gnu': 4.55.1
+ '@rollup/rollup-linux-arm64-musl': 4.55.1
+ '@rollup/rollup-linux-loong64-gnu': 4.55.1
+ '@rollup/rollup-linux-loong64-musl': 4.55.1
+ '@rollup/rollup-linux-ppc64-gnu': 4.55.1
+ '@rollup/rollup-linux-ppc64-musl': 4.55.1
+ '@rollup/rollup-linux-riscv64-gnu': 4.55.1
+ '@rollup/rollup-linux-riscv64-musl': 4.55.1
+ '@rollup/rollup-linux-s390x-gnu': 4.55.1
+ '@rollup/rollup-linux-x64-gnu': 4.55.1
+ '@rollup/rollup-linux-x64-musl': 4.55.1
+ '@rollup/rollup-openbsd-x64': 4.55.1
+ '@rollup/rollup-openharmony-arm64': 4.55.1
+ '@rollup/rollup-win32-arm64-msvc': 4.55.1
+ '@rollup/rollup-win32-ia32-msvc': 4.55.1
+ '@rollup/rollup-win32-x64-gnu': 4.55.1
+ '@rollup/rollup-win32-x64-msvc': 4.55.1
fsevents: 2.3.3
rou3@0.7.12: {}
@@ -17515,6 +15652,10 @@ snapshots:
scule@1.3.0: {}
+ sdp-transform@2.15.0: {}
+
+ sdp@3.2.1: {}
+
semver@6.3.1: {}
semver@7.5.4:
@@ -17523,8 +15664,6 @@ snapshots:
semver@7.7.3: {}
- semver@7.7.4: {}
-
send@0.19.0:
dependencies:
debug: 2.6.9
@@ -17571,16 +15710,10 @@ snapshots:
dependencies:
seroval: 1.4.0
- seroval-plugins@1.5.0(seroval@1.5.0):
- dependencies:
- seroval: 1.5.0
-
seroval@1.3.2: {}
seroval@1.4.0: {}
- seroval@1.5.0: {}
-
serve-placeholder@2.0.2:
dependencies:
defu: 6.1.4
@@ -17603,15 +15736,6 @@ snapshots:
transitivePeerDependencies:
- supports-color
- serve-static@2.2.1:
- dependencies:
- encodeurl: 2.0.0
- escape-html: 1.0.3
- parseurl: 1.3.3
- send: 1.2.0
- transitivePeerDependencies:
- - supports-color
-
set-cookie-parser@2.7.2: {}
set-function-length@1.2.2:
@@ -17748,7 +15872,7 @@ snapshots:
dependencies:
'@babel/generator': 7.28.5
'@babel/helper-module-imports': 7.27.1
- '@babel/types': 7.29.0
+ '@babel/types': 7.28.5
solid-js: 1.9.10
transitivePeerDependencies:
- supports-color
@@ -17773,10 +15897,6 @@ snapshots:
sprintf-js@1.0.3: {}
- srvx@0.10.1: {}
-
- srvx@0.11.2: {}
-
srvx@0.8.16: {}
stable-hash-x@0.2.0: {}
@@ -17864,16 +15984,6 @@ snapshots:
dependencies:
inline-style-parser: 0.2.7
- sucrase@3.35.1:
- dependencies:
- '@jridgewell/gen-mapping': 0.3.13
- commander: 4.1.1
- lines-and-columns: 1.2.4
- mz: 2.7.0
- pirates: 4.0.7
- tinyglobby: 0.2.15
- ts-interface-checker: 0.1.13
-
supports-color@10.2.2: {}
supports-color@7.2.0:
@@ -17973,22 +16083,12 @@ snapshots:
transitivePeerDependencies:
- react-native-b4a
- thenify-all@1.6.0:
- dependencies:
- thenify: 3.3.1
-
- thenify@3.3.1:
- dependencies:
- any-promise: 1.3.0
-
tiny-invariant@1.3.3: {}
tiny-warning@1.0.3: {}
tinybench@2.9.0: {}
- tinyexec@0.3.2: {}
-
tinyexec@1.0.2: {}
tinyglobby@0.2.15:
@@ -18036,13 +16136,13 @@ snapshots:
dependencies:
typescript: 5.9.3
+ ts-debounce@4.0.0: {}
+
ts-declaration-location@1.0.7(typescript@5.9.3):
dependencies:
picomatch: 4.0.3
typescript: 5.9.3
- ts-interface-checker@0.1.13: {}
-
tsconfck@3.1.6(typescript@5.9.3):
optionalDependencies:
typescript: 5.9.3
@@ -18082,47 +16182,9 @@ snapshots:
tslib@2.8.1: {}
- tsup-preset-solid@2.2.0(esbuild@0.27.3)(solid-js@1.9.10)(tsup@8.5.1(@microsoft/api-extractor@7.47.7(@types/node@25.0.1))(jiti@2.6.1)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.2)):
- dependencies:
- esbuild-plugin-solid: 0.5.0(esbuild@0.27.3)(solid-js@1.9.10)
- tsup: 8.5.1(@microsoft/api-extractor@7.47.7(@types/node@25.0.1))(jiti@2.6.1)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.2)
- transitivePeerDependencies:
- - esbuild
- - solid-js
- - supports-color
-
- tsup@8.5.1(@microsoft/api-extractor@7.47.7(@types/node@25.0.1))(jiti@2.6.1)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.2):
- dependencies:
- bundle-require: 5.1.0(esbuild@0.27.3)
- cac: 6.7.14
- chokidar: 4.0.3
- consola: 3.4.2
- debug: 4.4.3
- esbuild: 0.27.3
- fix-dts-default-cjs-exports: 1.0.1
- joycon: 3.1.1
- picocolors: 1.1.1
- postcss-load-config: 6.0.1(jiti@2.6.1)(postcss@8.5.6)(tsx@4.21.0)(yaml@2.8.2)
- resolve-from: 5.0.0
- rollup: 4.57.1
- source-map: 0.7.6
- sucrase: 3.35.1
- tinyexec: 0.3.2
- tinyglobby: 0.2.15
- tree-kill: 1.2.2
- optionalDependencies:
- '@microsoft/api-extractor': 7.47.7(@types/node@25.0.1)
- postcss: 8.5.6
- typescript: 5.9.3
- transitivePeerDependencies:
- - jiti
- - supports-color
- - tsx
- - yaml
-
tsx@4.21.0:
dependencies:
- esbuild: 0.27.2
+ esbuild: 0.27.1
get-tsconfig: 4.13.0
optionalDependencies:
fsevents: 2.3.3
@@ -18143,6 +16205,10 @@ snapshots:
media-typer: 1.1.0
mime-types: 3.0.2
+ typed-emitter@2.1.0:
+ optionalDependencies:
+ rxjs: 7.8.2
+
typedoc-plugin-frontmatter@1.3.0(typedoc-plugin-markdown@4.9.0(typedoc@0.28.14(typescript@5.9.3))):
dependencies:
typedoc-plugin-markdown: 4.9.0(typedoc@0.28.14(typescript@5.9.3))
@@ -18180,8 +16246,6 @@ snapshots:
ufo@1.6.1: {}
- ufo@1.6.3: {}
-
ultrahtml@1.6.0: {}
unconfig-core@7.4.2:
@@ -18198,15 +16262,6 @@ snapshots:
magic-string: 0.30.21
unplugin: 2.3.11
- unctx@2.5.0:
- dependencies:
- acorn: 8.15.0
- estree-walker: 3.0.3
- magic-string: 0.30.21
- unplugin: 2.3.11
-
- undici-types@5.26.5: {}
-
undici-types@5.28.4: {}
undici-types@6.21.0: {}
@@ -18215,8 +16270,6 @@ snapshots:
undici@7.16.0: {}
- undici@7.21.0: {}
-
unenv@1.10.0:
dependencies:
consola: 3.4.2
@@ -18231,8 +16284,6 @@ snapshots:
unicorn-magic@0.3.0: {}
- unicorn-magic@0.4.0: {}
-
unified@11.0.5:
dependencies:
'@types/unist': 3.0.3
@@ -18260,23 +16311,6 @@ snapshots:
unplugin: 2.3.11
unplugin-utils: 0.3.1
- unimport@5.6.0:
- dependencies:
- acorn: 8.15.0
- escape-string-regexp: 5.0.0
- estree-walker: 3.0.3
- local-pkg: 1.1.2
- magic-string: 0.30.21
- mlly: 1.8.0
- pathe: 2.0.3
- picomatch: 4.0.3
- pkg-types: 2.3.0
- scule: 1.3.0
- strip-literal: 3.1.0
- tinyglobby: 0.2.15
- unplugin: 2.3.11
- unplugin-utils: 0.3.1
-
unist-util-find-after@5.0.0:
dependencies:
'@types/unist': 3.0.3
@@ -18364,42 +16398,20 @@ snapshots:
dependencies:
rolldown: 1.0.0-beta.53
- unstorage@1.17.4(db0@0.3.4)(ioredis@5.8.2):
+ unstorage@1.17.3(db0@0.3.4)(ioredis@5.8.2):
dependencies:
anymatch: 3.1.3
- chokidar: 5.0.0
+ chokidar: 4.0.3
destr: 2.0.5
- h3: 1.15.5
- lru-cache: 11.2.4
+ h3: 1.15.4
+ lru-cache: 10.4.3
node-fetch-native: 1.6.7
ofetch: 1.5.1
- ufo: 1.6.3
+ ufo: 1.6.1
optionalDependencies:
db0: 0.3.4
ioredis: 5.8.2
- unstorage@1.17.4(db0@0.3.4)(ioredis@5.9.2):
- dependencies:
- anymatch: 3.1.3
- chokidar: 5.0.0
- destr: 2.0.5
- h3: 1.15.5
- lru-cache: 11.2.4
- node-fetch-native: 1.6.7
- ofetch: 1.5.1
- ufo: 1.6.3
- optionalDependencies:
- db0: 0.3.4
- ioredis: 5.9.2
-
- unstorage@2.0.0-alpha.5(chokidar@5.0.0)(db0@0.3.4)(ioredis@5.9.2)(lru-cache@11.2.4)(ofetch@2.0.0-alpha.3):
- optionalDependencies:
- chokidar: 5.0.0
- db0: 0.3.4
- ioredis: 5.9.2
- lru-cache: 11.2.4
- ofetch: 2.0.0-alpha.3
-
untun@0.1.3:
dependencies:
citty: 0.1.6
@@ -18423,15 +16435,6 @@ snapshots:
pkg-types: 2.3.0
unplugin: 2.3.11
- unwasm@0.5.3:
- dependencies:
- exsolve: 1.0.8
- knitwork: 1.3.0
- magic-string: 0.30.21
- mlly: 1.8.0
- pathe: 2.0.3
- pkg-types: 2.3.0
-
update-browserslist-db@1.2.2(browserslist@4.28.1):
dependencies:
browserslist: 4.28.1
@@ -18500,7 +16503,7 @@ snapshots:
ufo: 1.6.1
unctx: 2.4.1
unenv: 1.10.0
- unstorage: 1.17.4(db0@0.3.4)(ioredis@5.8.2)
+ unstorage: 1.17.3(db0@0.3.4)(ioredis@5.8.2)
vite: 6.4.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
zod: 3.25.76
transitivePeerDependencies:
@@ -18548,10 +16551,10 @@ snapshots:
- xml2js
- yaml
- vite-plugin-dts@4.2.3(@types/node@24.10.3)(rollup@4.57.1)(typescript@5.9.3)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)):
+ vite-plugin-dts@4.2.3(@types/node@24.10.3)(rollup@4.55.1)(typescript@5.9.3)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)):
dependencies:
'@microsoft/api-extractor': 7.47.7(@types/node@24.10.3)
- '@rollup/pluginutils': 5.3.0(rollup@4.57.1)
+ '@rollup/pluginutils': 5.3.0(rollup@4.55.1)
'@volar/typescript': 2.4.27
'@vue/language-core': 2.1.6(typescript@5.9.3)
compare-versions: 6.1.1
@@ -18597,20 +16600,6 @@ snapshots:
transitivePeerDependencies:
- supports-color
- vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)):
- dependencies:
- '@babel/core': 7.28.5
- '@types/babel__core': 7.20.5
- babel-preset-solid: 1.9.10(@babel/core@7.28.5)(solid-js@1.9.10)
- merge-anything: 5.1.7
- solid-js: 1.9.10
- solid-refresh: 0.6.3(solid-js@1.9.10)
- vite: 7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
- vitefu: 1.1.1(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
- transitivePeerDependencies:
- - supports-color
- optional: true
-
vite-tsconfig-paths@5.1.4(typescript@5.9.3)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)):
dependencies:
debug: 4.4.3
@@ -18622,24 +16611,13 @@ snapshots:
- supports-color
- typescript
- vite-tsconfig-paths@5.1.4(typescript@5.9.3)(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)):
- dependencies:
- debug: 4.4.3
- globrex: 0.1.2
- tsconfck: 3.1.6(typescript@5.9.3)
- optionalDependencies:
- vite: 7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
- transitivePeerDependencies:
- - supports-color
- - typescript
-
vite@6.4.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2):
dependencies:
esbuild: 0.25.12
fdir: 6.5.0(picomatch@4.0.3)
picomatch: 4.0.3
postcss: 8.5.6
- rollup: 4.57.1
+ rollup: 4.53.3
tinyglobby: 0.2.15
optionalDependencies:
'@types/node': 24.10.3
@@ -18686,11 +16664,11 @@ snapshots:
vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2):
dependencies:
- esbuild: 0.27.3
+ esbuild: 0.27.2
fdir: 6.5.0(picomatch@4.0.3)
picomatch: 4.0.3
postcss: 8.5.6
- rollup: 4.57.1
+ rollup: 4.55.1
tinyglobby: 0.2.15
optionalDependencies:
'@types/node': 24.10.3
@@ -18703,11 +16681,11 @@ snapshots:
vite@7.3.1(@types/node@25.0.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2):
dependencies:
- esbuild: 0.27.3
+ esbuild: 0.27.2
fdir: 6.5.0(picomatch@4.0.3)
picomatch: 4.0.3
postcss: 8.5.6
- rollup: 4.57.1
+ rollup: 4.55.1
tinyglobby: 0.2.15
optionalDependencies:
'@types/node': 25.0.1
@@ -18726,14 +16704,10 @@ snapshots:
optionalDependencies:
vite: 7.2.7(@types/node@25.0.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
- vitefu@1.1.1(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)):
- optionalDependencies:
- vite: 7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
-
vitest@4.0.15(@types/node@24.10.3)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2):
dependencies:
'@vitest/expect': 4.0.15
- '@vitest/mocker': 4.0.15(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+ '@vitest/mocker': 4.0.15(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
'@vitest/pretty-format': 4.0.15
'@vitest/runner': 4.0.15
'@vitest/snapshot': 4.0.15
@@ -18750,7 +16724,7 @@ snapshots:
tinyexec: 1.0.2
tinyglobby: 0.2.15
tinyrainbow: 3.0.3
- vite: 7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
+ vite: 7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
why-is-node-running: 2.3.0
optionalDependencies:
'@types/node': 24.10.3
@@ -18769,15 +16743,15 @@ snapshots:
- tsx
- yaml
- vitest@4.0.18(@types/node@24.10.3)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2):
+ vitest@4.0.17(@types/node@24.10.3)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2):
dependencies:
- '@vitest/expect': 4.0.18
- '@vitest/mocker': 4.0.18(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
- '@vitest/pretty-format': 4.0.18
- '@vitest/runner': 4.0.18
- '@vitest/snapshot': 4.0.18
- '@vitest/spy': 4.0.18
- '@vitest/utils': 4.0.18
+ '@vitest/expect': 4.0.17
+ '@vitest/mocker': 4.0.17(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+ '@vitest/pretty-format': 4.0.17
+ '@vitest/runner': 4.0.17
+ '@vitest/snapshot': 4.0.17
+ '@vitest/spy': 4.0.17
+ '@vitest/utils': 4.0.17
es-module-lexer: 1.7.0
expect-type: 1.3.0
magic-string: 0.30.21
@@ -18808,15 +16782,15 @@ snapshots:
- tsx
- yaml
- vitest@4.0.18(@types/node@25.0.1)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2):
+ vitest@4.0.17(@types/node@25.0.1)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2):
dependencies:
- '@vitest/expect': 4.0.18
- '@vitest/mocker': 4.0.18(vite@7.3.1(@types/node@25.0.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
- '@vitest/pretty-format': 4.0.18
- '@vitest/runner': 4.0.18
- '@vitest/snapshot': 4.0.18
- '@vitest/spy': 4.0.18
- '@vitest/utils': 4.0.18
+ '@vitest/expect': 4.0.17
+ '@vitest/mocker': 4.0.17(vite@7.3.1(@types/node@25.0.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+ '@vitest/pretty-format': 4.0.17
+ '@vitest/runner': 4.0.17
+ '@vitest/snapshot': 4.0.17
+ '@vitest/spy': 4.0.17
+ '@vitest/utils': 4.0.17
es-module-lexer: 1.7.0
expect-type: 1.3.0
magic-string: 0.30.21
@@ -18898,8 +16872,6 @@ snapshots:
web-streams-polyfill@3.3.3: {}
- web-streams-polyfill@4.0.0-beta.3: {}
-
web-vitals@5.1.0: {}
webidl-conversions@3.0.1: {}
@@ -18908,6 +16880,10 @@ snapshots:
webpack-virtual-modules@0.6.2: {}
+ webrtc-adapter@9.0.3:
+ dependencies:
+ sdp: 3.2.1
+
whatwg-encoding@3.1.1:
dependencies:
iconv-lite: 0.6.3
@@ -19055,6 +17031,4 @@ snapshots:
zod@4.2.1: {}
- zod@4.3.6: {}
-
zwitch@2.0.4: {}
From 929b4a892d560198cf7e577695738a4a05a8a106 Mon Sep 17 00:00:00 2001
From: Jack Herrington
Date: Tue, 20 Jan 2026 07:10:18 -0800
Subject: [PATCH 17/31] Realtime chat basically working
---
docs/architecture/realtime-chat.md | 313 +++++++++++++++++++++++++++++
1 file changed, 313 insertions(+)
create mode 100644 docs/architecture/realtime-chat.md
diff --git a/docs/architecture/realtime-chat.md b/docs/architecture/realtime-chat.md
new file mode 100644
index 0000000000..305029c3ec
--- /dev/null
+++ b/docs/architecture/realtime-chat.md
@@ -0,0 +1,313 @@
+---
+title: Realtime Voice Chat Architecture
+id: realtime-chat-architecture
+---
+
+# Realtime Voice Chat Architecture
+
+This document describes the architecture of TanStack AI's realtime voice-to-voice chat capability, which enables browser-based voice conversations with AI models.
+
+## Overview
+
+The realtime chat system provides a vendor-neutral, type-safe abstraction for voice-to-voice AI interactions. It currently supports:
+
+- **OpenAI Realtime API** - WebRTC-based connection with GPT-4o realtime models
+- **ElevenLabs Conversational AI** - SDK-based connection for voice conversations
+
+## Architecture Layers
+
+```
+┌─────────────────────────────────────────────────────────────────┐
+│ React Application │
+│ ┌─────────────────────────────────────────────────────────┐ │
+│ │ useRealtimeChat() │ │
+│ │ - Connection state (status, mode) │ │
+│ │ - Messages & transcripts │ │
+│ │ - Audio visualization (levels, waveforms) │ │
+│ │ - Control methods (connect, disconnect, interrupt) │ │
+│ └─────────────────────────────────────────────────────────┘ │
+└─────────────────────────────────────────────────────────────────┘
+ │
+ ▼
+┌─────────────────────────────────────────────────────────────────┐
+│ @tanstack/ai-client │
+│ ┌─────────────────────────────────────────────────────────┐ │
+│ │ RealtimeClient │ │
+│ │ - Connection lifecycle management │ │
+│ │ - Token refresh scheduling │ │
+│ │ - Event subscription & dispatch │ │
+│ │ - Tool execution coordination │ │
+│ └─────────────────────────────────────────────────────────┘ │
+└─────────────────────────────────────────────────────────────────┘
+ │
+ ▼
+┌─────────────────────────────────────────────────────────────────┐
+│ Provider Adapters │
+│ ┌──────────────────────┐ ┌──────────────────────┐ │
+│ │ openaiRealtime() │ │ elevenlabsRealtime() │ │
+│ │ - WebRTC connection │ │ - SDK wrapper │ │
+│ │ - Audio I/O │ │ - Signed URL auth │ │
+│ │ - Event mapping │ │ - Event mapping │ │
+│ └──────────────────────┘ └──────────────────────┘ │
+└─────────────────────────────────────────────────────────────────┘
+ │
+ ▼
+┌─────────────────────────────────────────────────────────────────┐
+│ Server-Side │
+│ ┌─────────────────────────────────────────────────────────┐ │
+│ │ Token Generation Endpoint │ │
+│ │ - openaiRealtimeToken() - ephemeral client secrets │ │
+│ │ - elevenlabsRealtimeToken() - signed URLs │ │
+│ └─────────────────────────────────────────────────────────┘ │
+└─────────────────────────────────────────────────────────────────┘
+```
+
+## Key Components
+
+### 1. Token Adapters (Server-Side)
+
+Token adapters generate short-lived credentials for client-side connections. This keeps API keys secure on the server.
+
+```typescript
+// Server-side token endpoint
+import { realtimeToken } from '@tanstack/ai'
+import { openaiRealtimeToken } from '@tanstack/ai-openai'
+
+const token = await realtimeToken({
+ adapter: openaiRealtimeToken({
+ model: 'gpt-4o-realtime-preview',
+ voice: 'alloy',
+ instructions: 'You are a helpful assistant.',
+ turnDetection: {
+ type: 'server_vad',
+ threshold: 0.5,
+ silence_duration_ms: 500,
+ },
+ }),
+})
+```
+
+**Token Structure:**
+```typescript
+interface RealtimeToken {
+ provider: string // 'openai' | 'elevenlabs'
+ token: string // Ephemeral token or signed URL
+ expiresAt: number // Expiration timestamp (ms)
+ config: RealtimeSessionConfig // Session configuration
+}
+```
+
+### 2. Client Adapters (Browser-Side)
+
+Client adapters handle the actual connection to provider APIs, managing:
+- WebRTC or WebSocket connections
+- Audio capture and playback
+- Event translation to common format
+- Audio visualization data
+
+```typescript
+// Client-side adapter usage
+import { openaiRealtime } from '@tanstack/ai-openai'
+
+const adapter = openaiRealtime({
+ connectionMode: 'webrtc', // default
+})
+```
+
+### 3. RealtimeClient
+
+The `RealtimeClient` class manages the connection lifecycle:
+
+- **Connection Management**: Connect, disconnect, reconnect
+- **Token Refresh**: Automatically refreshes tokens before expiry
+- **Event Handling**: Subscribes to adapter events and dispatches to callbacks
+- **State Management**: Tracks status, mode, messages, transcripts
+- **Tool Execution**: Coordinates client-side tool calls
+
+### 4. useRealtimeChat Hook
+
+The React hook provides a reactive interface:
+
+```typescript
+const {
+ // Connection state
+ status, // 'idle' | 'connecting' | 'connected' | 'reconnecting' | 'error'
+ error,
+ connect,
+ disconnect,
+
+ // Conversation state
+ mode, // 'idle' | 'listening' | 'thinking' | 'speaking'
+ messages,
+ pendingUserTranscript,
+ pendingAssistantTranscript,
+
+ // Voice control
+ startListening,
+ stopListening,
+ interrupt,
+
+ // Audio visualization
+ inputLevel,
+ outputLevel,
+ getInputTimeDomainData,
+ getOutputTimeDomainData,
+} = useRealtimeChat({
+ getToken: () => fetch('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/api/realtime-token').then(r => r.json()),
+ adapter: openaiRealtime(),
+})
+```
+
+## Connection Flow
+
+### OpenAI WebRTC Flow
+
+```mermaid
+sequenceDiagram
+ participant Browser
+ participant Server
+ participant OpenAI
+
+ Browser->>Server: POST /api/realtime-token
+ Server->>OpenAI: POST /v1/realtime/sessions
+ OpenAI-->>Server: { client_secret, expires_at }
+ Server-->>Browser: RealtimeToken
+
+ Browser->>Browser: getUserMedia() - request mic
+ Browser->>Browser: Create RTCPeerConnection
+ Browser->>Browser: Add audio track to PC
+ Browser->>Browser: createOffer()
+
+ Browser->>OpenAI: POST /v1/realtime?model=...
+ Note right of Browser: SDP offer + ephemeral token
+ OpenAI-->>Browser: SDP answer
+
+ Browser->>Browser: setRemoteDescription()
+ Note over Browser,OpenAI: WebRTC connection established
+
+ Browser->>OpenAI: Audio via WebRTC
+ OpenAI-->>Browser: Audio + events via WebRTC
+```
+
+### ElevenLabs Flow
+
+```mermaid
+sequenceDiagram
+ participant Browser
+ participant Server
+ participant ElevenLabs
+
+ Browser->>Server: POST /api/realtime-token
+ Server->>ElevenLabs: POST /v1/convai/conversation/get_signed_url
+ ElevenLabs-->>Server: { signed_url }
+ Server-->>Browser: RealtimeToken
+
+ Browser->>ElevenLabs: Conversation.startSession(signedUrl)
+ Note over Browser,ElevenLabs: SDK handles WebSocket/WebRTC
+
+ Browser->>ElevenLabs: Audio via SDK
+ ElevenLabs-->>Browser: Audio + events via SDK
+```
+
+## Audio Visualization
+
+The system provides real-time audio visualization through the `AudioVisualization` interface:
+
+```typescript
+interface AudioVisualization {
+ inputLevel: number // 0-1 normalized input volume (RMS)
+ outputLevel: number // 0-1 normalized output volume (RMS)
+ getInputFrequencyData(): Uint8Array // FFT frequency bins
+ getOutputFrequencyData(): Uint8Array
+ getInputTimeDomainData(): Uint8Array // Raw waveform samples
+ getOutputTimeDomainData(): Uint8Array
+ inputSampleRate: number
+ outputSampleRate: number
+}
+```
+
+The OpenAI adapter uses Web Audio API `AnalyserNode` for visualization:
+- `fftSize: 2048` for high-resolution analysis
+- RMS (Root Mean Square) calculation for accurate volume levels
+- Separate analysers for input (microphone) and output (AI voice)
+
+## Event System
+
+Adapters emit standardized events:
+
+| Event | Payload | Description |
+|-------|---------|-------------|
+| `status_change` | `{ status }` | Connection status changed |
+| `mode_change` | `{ mode }` | Conversation mode changed |
+| `transcript` | `{ role, transcript, isFinal }` | Speech-to-text update |
+| `message_complete` | `{ message }` | Full message received |
+| `tool_call` | `{ toolCallId, toolName, input }` | Tool invocation requested |
+| `interrupted` | `{ messageId? }` | Response was interrupted |
+| `error` | `{ error }` | Error occurred |
+
+## Current Status
+
+### Implemented Features
+
+- [x] OpenAI Realtime API integration (WebRTC)
+- [x] ElevenLabs Conversational AI integration
+- [x] Token generation and refresh
+- [x] Audio capture and playback
+- [x] Real-time transcription display
+- [x] Audio visualization (levels, waveforms)
+- [x] Interrupt capability
+- [x] React hook (`useRealtimeChat`)
+- [x] Demo application at `/realtime` route
+
+### Known Limitations
+
+- **Device Selection**: Currently uses system default audio devices. Custom device selection not yet implemented.
+- **ElevenLabs SDK**: Using `@11labs/client@0.2.0` which has limited TypeScript support.
+- **Push-to-Talk**: Manual VAD mode implemented but not exposed in demo UI.
+- **Tool Calling**: Framework supports tools but demo doesn't showcase them.
+
+### Demo Application
+
+The `examples/ts-react-chat` application includes a realtime voice chat demo at the `/realtime` route:
+
+**Features:**
+- Provider selection (OpenAI / ElevenLabs)
+- Connection status indicator
+- Conversation mode indicator (Listening/Thinking/Speaking)
+- Message history with transcripts
+- Audio level meters
+- Waveform visualization (debug mode)
+- Interrupt button during AI speech
+
+**Required Environment Variables:**
+```bash
+OPENAI_API_KEY=sk-...
+ELEVENLABS_API_KEY=xi-... # Optional, for ElevenLabs
+ELEVENLABS_AGENT_ID=... # Optional, for ElevenLabs
+```
+
+## Files Reference
+
+### Core Types
+- `packages/typescript/ai/src/realtime/types.ts` - Core type definitions
+- `packages/typescript/ai-client/src/realtime-types.ts` - Client-side types
+
+### Token Generation (Server)
+- `packages/typescript/ai/src/realtime/index.ts` - `realtimeToken()` function
+- `packages/typescript/ai-openai/src/realtime/token.ts` - OpenAI token adapter
+- `packages/typescript/ai-elevenlabs/src/realtime/token.ts` - ElevenLabs token adapter
+
+### Client Adapters
+- `packages/typescript/ai-openai/src/realtime/adapter.ts` - OpenAI WebRTC adapter
+- `packages/typescript/ai-elevenlabs/src/realtime/adapter.ts` - ElevenLabs SDK adapter
+
+### Client Library
+- `packages/typescript/ai-client/src/realtime-client.ts` - RealtimeClient class
+
+### React Integration
+- `packages/typescript/ai-react/src/use-realtime-chat.ts` - React hook
+- `packages/typescript/ai-react/src/realtime-types.ts` - Hook types
+
+### Demo Application
+- `examples/ts-react-chat/src/routes/realtime.tsx` - Demo UI component
+- `examples/ts-react-chat/src/routes/api.realtime-token.ts` - Token API endpoint
From 882c2be55dfbf69685576e238c551fd82553bec2 Mon Sep 17 00:00:00 2001
From: Jack Herrington
Date: Wed, 21 Jan 2026 16:15:17 -0800
Subject: [PATCH 18/31] more updates
---
.../ts-react-chat/src/lib/realtime-tools.ts | 141 ++++++++++++++++++
.../src/routes/api.realtime-token.ts | 50 ++++++-
.../ts-react-chat/src/routes/realtime.tsx | 95 ++++--------
.../ai-openai/src/realtime/adapter.ts | 29 ++--
4 files changed, 230 insertions(+), 85 deletions(-)
create mode 100644 examples/ts-react-chat/src/lib/realtime-tools.ts
diff --git a/examples/ts-react-chat/src/lib/realtime-tools.ts b/examples/ts-react-chat/src/lib/realtime-tools.ts
new file mode 100644
index 0000000000..2cf28d7bd3
--- /dev/null
+++ b/examples/ts-react-chat/src/lib/realtime-tools.ts
@@ -0,0 +1,141 @@
+import { toolDefinition } from '@tanstack/ai'
+import { z } from 'zod'
+
+// Tool to get current time - useful for voice assistants
+export const getCurrentTimeToolDef = toolDefinition({
+ name: 'getCurrentTime',
+ description: 'Get the current date and time. Use this when the user asks what time it is or the current date.',
+ inputSchema: z.object({
+ timezone: z.string().optional().describe('Optional timezone like "America/New_York" or "Europe/London"'),
+ }),
+ outputSchema: z.object({
+ time: z.string(),
+ date: z.string(),
+ timezone: z.string(),
+ }),
+})
+
+// Tool to get weather - common voice assistant use case
+export const getWeatherToolDef = toolDefinition({
+ name: 'getWeather',
+ description: 'Get the current weather for a location. Use this when the user asks about the weather.',
+ inputSchema: z.object({
+ location: z.string().describe('The city and state/country, e.g. "San Francisco, CA" or "London, UK"'),
+ }),
+ outputSchema: z.object({
+ location: z.string(),
+ temperature: z.number(),
+ unit: z.string(),
+ condition: z.string(),
+ humidity: z.number(),
+ }),
+})
+
+// Tool to set a reminder - demonstrates user interaction
+export const setReminderToolDef = toolDefinition({
+ name: 'setReminder',
+ description: 'Set a reminder for the user. Use this when the user asks to be reminded about something.',
+ inputSchema: z.object({
+ message: z.string().describe('What to remind the user about'),
+ inMinutes: z.number().describe('How many minutes from now to remind'),
+ }),
+ outputSchema: z.object({
+ success: z.boolean(),
+ message: z.string(),
+ remindAt: z.string(),
+ }),
+})
+
+// Tool to search knowledge base - useful for assistants with specific knowledge
+export const searchKnowledgeToolDef = toolDefinition({
+ name: 'searchKnowledge',
+ description: 'Search a knowledge base for information. Use this to find specific facts or documentation.',
+ inputSchema: z.object({
+ query: z.string().describe('The search query'),
+ }),
+ outputSchema: z.object({
+ results: z.array(z.object({
+ title: z.string(),
+ snippet: z.string(),
+ })),
+ }),
+})
+
+// Client-side implementation of getCurrentTime
+export const getCurrentTimeClient = getCurrentTimeToolDef.client(({ timezone }) => {
+ const now = new Date()
+ const tz = timezone || Intl.DateTimeFormat().resolvedOptions().timeZone
+
+ return {
+ time: now.toLocaleTimeString('en-US', { timeZone: tz }),
+ date: now.toLocaleDateString('en-US', {
+ weekday: 'long',
+ year: 'numeric',
+ month: 'long',
+ day: 'numeric',
+ timeZone: tz,
+ }),
+ timezone: tz,
+ }
+})
+
+// Client-side implementation of getWeather (mock data for demo)
+export const getWeatherClient = getWeatherToolDef.client(({ location }) => {
+ // Mock weather data for demo purposes
+ const conditions = ['Sunny', 'Partly Cloudy', 'Cloudy', 'Rainy', 'Snowy']
+ const randomCondition = conditions[Math.floor(Math.random() * conditions.length)]!
+ const randomTemp = Math.floor(Math.random() * 30) + 50 // 50-80°F
+ const randomHumidity = Math.floor(Math.random() * 50) + 30 // 30-80%
+
+ return {
+ location,
+ temperature: randomTemp,
+ unit: 'F',
+ condition: randomCondition,
+ humidity: randomHumidity,
+ }
+})
+
+// Client-side implementation of setReminder
+export const setReminderClient = setReminderToolDef.client(({ message, inMinutes }) => {
+ const remindAt = new Date(Date.now() + inMinutes * 60 * 1000)
+
+ // In a real app, you'd schedule a notification here
+ console.log(`[Reminder] Will remind about "${message}" at ${remindAt.toLocaleTimeString()}`)
+
+ // For demo purposes, show an alert after the specified time
+ setTimeout(() => {
+ alert(`Reminder: ${message}`)
+ }, inMinutes * 60 * 1000)
+
+ return {
+ success: true,
+ message: `Reminder set: "${message}"`,
+ remindAt: remindAt.toLocaleTimeString(),
+ }
+})
+
+// Client-side implementation of searchKnowledge (mock data for demo)
+export const searchKnowledgeClient = searchKnowledgeToolDef.client(({ query }) => {
+ // Mock search results for demo
+ const mockResults = [
+ {
+ title: `Result for: ${query}`,
+ snippet: `This is a mock search result for the query "${query}". In a real application, this would return actual search results from a knowledge base.`,
+ },
+ {
+ title: 'Additional Information',
+ snippet: 'More relevant information would appear here based on your search query.',
+ },
+ ]
+
+ return { results: mockResults }
+})
+
+// Export all client tools as an array for easy use
+export const realtimeClientTools = [
+ getCurrentTimeClient,
+ getWeatherClient,
+ setReminderClient,
+ searchKnowledgeClient,
+] as const
diff --git a/examples/ts-react-chat/src/routes/api.realtime-token.ts b/examples/ts-react-chat/src/routes/api.realtime-token.ts
index 0f7a46bdaa..c9367ad196 100644
--- a/examples/ts-react-chat/src/routes/api.realtime-token.ts
+++ b/examples/ts-react-chat/src/routes/api.realtime-token.ts
@@ -2,9 +2,36 @@ import { createFileRoute } from '@tanstack/react-router'
import { realtimeToken } from '@tanstack/ai'
import { openaiRealtimeToken } from '@tanstack/ai-openai'
import { elevenlabsRealtimeToken } from '@tanstack/ai-elevenlabs'
+import {
+ getCurrentTimeToolDef,
+ getWeatherToolDef,
+ setReminderToolDef,
+ searchKnowledgeToolDef,
+} from '@/lib/realtime-tools'
+import * as z from 'zod'
type Provider = 'openai' | 'elevenlabs'
+// Convert tool definitions to OpenAI's format using Zod's native toJSONSchema
+function toolDefToOpenAI(toolDef: { name: string; description: string; inputSchema?: unknown }) {
+ let parameters: Record = { type: 'object', properties: {} }
+
+ if (toolDef.inputSchema) {
+ // Use Zod's native toJSONSchema for Zod v4+
+ const jsonSchema = z.toJSONSchema(toolDef.inputSchema as z.ZodType)
+ // Remove $schema as OpenAI doesn't need it
+ const { $schema, ...rest } = jsonSchema as Record
+ parameters = rest
+ }
+
+ return {
+ type: 'function' as const,
+ name: toolDef.name,
+ description: toolDef.description,
+ parameters,
+ }
+}
+
export const Route = createFileRoute('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/api/realtime-token')({
server: {
handlers: {
@@ -16,14 +43,29 @@ export const Route = createFileRoute('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/api/realtime-token')({
let token
if (provider === 'openai') {
+ // Convert tool definitions to OpenAI format
+ const tools = [
+ toolDefToOpenAI(getCurrentTimeToolDef),
+ toolDefToOpenAI(getWeatherToolDef),
+ toolDefToOpenAI(setReminderToolDef),
+ toolDefToOpenAI(searchKnowledgeToolDef),
+ ]
+
token = await realtimeToken({
adapter: openaiRealtimeToken({
model: 'gpt-4o-realtime-preview',
voice: 'alloy',
- instructions: `You are a helpful, friendly assistant.
-
+ instructions: `You are a helpful, friendly voice assistant with access to several tools.
+
+You can:
+- Tell the user the current time and date (getCurrentTime)
+- Get weather information for any location (getWeather)
+- Set reminders for the user (setReminder)
+- Search a knowledge base for information (searchKnowledge)
+
Keep your responses concise and conversational since this is a voice interface.
-Be natural and engaging in your responses.`,
+When using tools, briefly explain what you're doing and then share the results naturally.
+Be friendly and engaging!`,
turnDetection: {
type: 'server_vad',
threshold: 0.5,
@@ -33,6 +75,8 @@ Be natural and engaging in your responses.`,
inputAudioTranscription: {
model: 'whisper-1',
},
+ tools,
+ toolChoice: 'auto',
}),
})
} else if (provider === 'elevenlabs') {
diff --git a/examples/ts-react-chat/src/routes/realtime.tsx b/examples/ts-react-chat/src/routes/realtime.tsx
index fcc954cb16..4be974a8fc 100644
--- a/examples/ts-react-chat/src/routes/realtime.tsx
+++ b/examples/ts-react-chat/src/routes/realtime.tsx
@@ -3,7 +3,8 @@ import { createFileRoute } from '@tanstack/react-router'
import { useRealtimeChat } from '@tanstack/ai-react'
import { openaiRealtime } from '@tanstack/ai-openai'
import { elevenlabsRealtime } from '@tanstack/ai-elevenlabs'
-import { Mic, MicOff, Phone, PhoneOff, Volume2 } from 'lucide-react'
+import { Mic, MicOff, Phone, PhoneOff, Volume2, Wrench } from 'lucide-react'
+import { realtimeClientTools } from '@/lib/realtime-tools'
type Provider = 'openai' | 'elevenlabs'
@@ -98,56 +99,9 @@ function AudioSparkline({
)
}
-// Debug component to show raw audio data stats
-function AudioDebug({
- getData,
- label
-}: {
- getData: () => Uint8Array
- label: string
-}) {
- const [stats, setStats] = useState({ length: 0, min: 0, max: 0, allSame: true, sample: '[]' })
-
- useEffect(() => {
- function update() {
- const data = getData()
- const min = Math.min(...data)
- const max = Math.max(...data)
- const allSame = data.every(v => v === data[0])
- // Get a few samples from different parts of the array
- const samples = data.length > 0 ? [
- data[0],
- data[Math.floor(data.length / 4)],
- data[Math.floor(data.length / 2)],
- data[Math.floor(data.length * 3 / 4)],
- data[data.length - 1]
- ] : []
- setStats({
- length: data.length,
- min,
- max,
- allSame,
- sample: `[${samples.join(', ')}]`
- })
- requestAnimationFrame(update)
- }
- const id = requestAnimationFrame(update)
- return () => cancelAnimationFrame(id)
- }, [getData])
-
- return (
-
- {label}: len={stats.length}, min={stats.min}, max={stats.max},
- {stats.allSame ? ALL SAME! : varying }
- {stats.sample}
-
- )
-}
-
function RealtimePage() {
const [provider, setProvider] = useState('openai')
const [agentId, setAgentId] = useState('')
- const [showDebug, setShowDebug] = useState(true)
const messagesEndRef = useRef(null)
// Get the appropriate adapter based on provider
@@ -165,7 +119,6 @@ function RealtimePage() {
interrupt,
inputLevel,
outputLevel,
- sendText,
getInputTimeDomainData,
getOutputTimeDomainData,
} = useRealtimeChat({
@@ -186,6 +139,8 @@ function RealtimePage() {
return response.json()
},
adapter,
+ // Pass the client tools - these execute locally when the AI calls them
+ tools: realtimeClientTools,
onError: (err) => {
console.error('Realtime error:', err)
},
@@ -302,15 +257,35 @@ function RealtimePage() {
+ {/* Tools indicator */}
+ {provider === 'openai' && (
+
+
+
+ Tools enabled:
+ getCurrentTime
+ •
+ getWeather
+ •
+ setReminder
+ •
+ searchKnowledge
+
+
+ )}
+
{/* Messages area */}
{messages.length === 0 && status === 'idle' && (
-
Voice Chat
+
Voice Chat with Tools
Click "Start Conversation" to begin talking with the AI
+
+ Try asking: "What time is it?" or "What's the weather in San Francisco?"
+
)}
@@ -437,26 +412,6 @@ function RealtimePage() {
label="Output"
/>
-
- {/* Debug info */}
- {showDebug && (
-
-
- Audio Debug
- setShowDebug(false)}
- className="text-xs text-gray-500 hover:text-gray-400"
- >
- Hide
-
-
-
-
-
- inputLevel: {inputLevel.toFixed(4)}, outputLevel: {outputLevel.toFixed(4)}
-
-
- )}
)}
diff --git a/packages/typescript/ai-openai/src/realtime/adapter.ts b/packages/typescript/ai-openai/src/realtime/adapter.ts
index 51745a26cd..645a5e7168 100644
--- a/packages/typescript/ai-openai/src/realtime/adapter.ts
+++ b/packages/typescript/ai-openai/src/realtime/adapter.ts
@@ -513,33 +513,38 @@ async function createWebRTCConnection(
// Log analyser state for debugging
console.log('[Realtime] getAudioVisualization called, inputAnalyser:', !!inputAnalyser, 'outputAnalyser:', !!outputAnalyser)
- // Helper to calculate RMS (Root Mean Square) from time domain data
- // This gives a better measure of perceived loudness than frequency data
- function calculateRMS(analyser: AnalyserNode): number {
+ // Helper to calculate audio level from time domain data
+ // Uses peak amplitude which is more responsive for voice audio meters
+ function calculateLevel(analyser: AnalyserNode): number {
const data = new Uint8Array(analyser.fftSize)
analyser.getByteTimeDomainData(data)
- // Calculate RMS - values are 0-255 with 128 being silence
- let sumSquares = 0
+ // Find peak deviation from center (128 is silence)
+ // This is more responsive than RMS for voice level meters
+ let maxDeviation = 0
for (const sample of data) {
- const normalized = (sample - 128) / 128 // Convert to -1 to 1 range
- sumSquares += normalized * normalized
+ const deviation = Math.abs(sample - 128)
+ if (deviation > maxDeviation) {
+ maxDeviation = deviation
+ }
}
- const rms = Math.sqrt(sumSquares / data.length)
- // Scale and clamp to 0-1 range (RMS of full-scale sine is ~0.707)
- return Math.min(1, rms * 1.5)
+ // Normalize to 0-1 range (max deviation is 128)
+ // Scale by 1.5x so that ~66% amplitude reads as full scale
+ // This provides good visual feedback without pegging too early
+ const normalized = maxDeviation / 128
+ return Math.min(1, normalized * 1.5)
}
return {
get inputLevel() {
if (!inputAnalyser) return 0
- return calculateRMS(inputAnalyser)
+ return calculateLevel(inputAnalyser)
},
get outputLevel() {
if (!outputAnalyser) return 0
- return calculateRMS(outputAnalyser)
+ return calculateLevel(outputAnalyser)
},
getInputFrequencyData() {
From 5298fa8d2061f6a79885d8e83e565516172b3ea4 Mon Sep 17 00:00:00 2001
From: Jack Herrington
Date: Thu, 19 Feb 2026 10:18:57 -0800
Subject: [PATCH 19/31] chore: update pnpm-lock.yaml and latest realtime chat
changes
Co-Authored-By: Warp
---
.changeset/realtime-chat.md | 11 +
examples/ts-react-chat/package.json | 2 +-
.../ai-client/src/realtime-client.ts | 2 +-
.../ai-client/src/realtime-types.ts | 28 +-
.../typescript/ai-elevenlabs/package.json | 2 +-
.../ai-elevenlabs/src/realtime/adapter.ts | 16 +-
.../ai-elevenlabs/src/realtime/token.ts | 2 +-
.../ai-elevenlabs/src/realtime/types.ts | 7 -
.../ai-openai/src/realtime/adapter.ts | 14 +-
.../ai-openai/src/realtime/token.ts | 4 +-
.../typescript/ai-react/src/realtime-types.ts | 2 +-
packages/typescript/ai/src/realtime/types.ts | 22 +-
pnpm-lock.yaml | 2904 +++++++++++++----
13 files changed, 2381 insertions(+), 635 deletions(-)
create mode 100644 .changeset/realtime-chat.md
diff --git a/.changeset/realtime-chat.md b/.changeset/realtime-chat.md
new file mode 100644
index 0000000000..11cc3cca14
--- /dev/null
+++ b/.changeset/realtime-chat.md
@@ -0,0 +1,11 @@
+---
+'@tanstack/ai': minor
+'@tanstack/ai-client': minor
+'@tanstack/ai-openai': minor
+'@tanstack/ai-elevenlabs': minor
+'@tanstack/ai-react': minor
+---
+
+feat: add realtime chat support with OpenAI and ElevenLabs adapters
+
+Adds realtime voice/text chat capabilities including a provider-agnostic realtime client, OpenAI Realtime API adapter, ElevenLabs conversational AI adapter, React `useRealtimeChat` hook, and shared realtime types across the core, client, and framework packages.
diff --git a/examples/ts-react-chat/package.json b/examples/ts-react-chat/package.json
index 746713f7de..3e1b9ca3b5 100644
--- a/examples/ts-react-chat/package.json
+++ b/examples/ts-react-chat/package.json
@@ -13,12 +13,12 @@
"@tanstack/ai": "workspace:*",
"@tanstack/ai-anthropic": "workspace:*",
"@tanstack/ai-client": "workspace:*",
+ "@tanstack/ai-elevenlabs": "workspace:*",
"@tanstack/ai-gemini": "workspace:*",
"@tanstack/ai-grok": "workspace:*",
"@tanstack/ai-groq": "workspace:*",
"@tanstack/ai-ollama": "workspace:*",
"@tanstack/ai-openai": "workspace:*",
- "@tanstack/ai-elevenlabs": "workspace:*",
"@tanstack/ai-openrouter": "workspace:*",
"@tanstack/ai-react": "workspace:*",
"@tanstack/ai-react-ui": "workspace:*",
diff --git a/packages/typescript/ai-client/src/realtime-client.ts b/packages/typescript/ai-client/src/realtime-client.ts
index 0672fe23eb..f49d4d25ea 100644
--- a/packages/typescript/ai-client/src/realtime-client.ts
+++ b/packages/typescript/ai-client/src/realtime-client.ts
@@ -1,11 +1,11 @@
import type {
+ AnyClientTool,
AudioVisualization,
RealtimeMessage,
RealtimeMode,
RealtimeStatus,
RealtimeToken,
} from '@tanstack/ai'
-import type { AnyClientTool } from '@tanstack/ai'
import type {
RealtimeClientOptions,
RealtimeClientState,
diff --git a/packages/typescript/ai-client/src/realtime-types.ts b/packages/typescript/ai-client/src/realtime-types.ts
index 3393ee92c6..4ff6bf9bd5 100644
--- a/packages/typescript/ai-client/src/realtime-types.ts
+++ b/packages/typescript/ai-client/src/realtime-types.ts
@@ -1,4 +1,5 @@
import type {
+ AnyClientTool,
AudioVisualization,
RealtimeEvent,
RealtimeEventHandler,
@@ -8,7 +9,6 @@ import type {
RealtimeStatus,
RealtimeToken,
} from '@tanstack/ai'
-import type { AnyClientTool } from '@tanstack/ai'
// ============================================================================
// Adapter Interface
@@ -27,7 +27,7 @@ export interface RealtimeAdapter {
* @param token - The ephemeral token from the server
* @returns A connection instance
*/
- connect(token: RealtimeToken): Promise
+ connect: (token: RealtimeToken) => Promise
}
/**
@@ -37,38 +37,38 @@ export interface RealtimeAdapter {
export interface RealtimeConnection {
// Lifecycle
/** Disconnect from the realtime session */
- disconnect(): Promise
+ disconnect: () => Promise
// Audio I/O
/** Start capturing audio from the microphone */
- startAudioCapture(): Promise
+ startAudioCapture: () => Promise
/** Stop capturing audio */
- stopAudioCapture(): void
+ stopAudioCapture: () => void
// Text input
/** Send a text message (fallback for when voice isn't available) */
- sendText(text: string): void
+ sendText: (text: string) => void
// Tool results
/** Send a tool execution result back to the provider */
- sendToolResult(callId: string, result: string): void
+ sendToolResult: (callId: string, result: string) => void
// Session management
/** Update session configuration */
- updateSession(config: Partial): void
+ updateSession: (config: Partial) => void
/** Interrupt the current response */
- interrupt(): void
+ interrupt: () => void
// Events
/** Subscribe to connection events */
- on(
- event: E,
- handler: RealtimeEventHandler,
- ): () => void
+ on: (
+ event: TEvent,
+ handler: RealtimeEventHandler,
+ ) => () => void
// Audio visualization
/** Get audio visualization data */
- getAudioVisualization(): AudioVisualization
+ getAudioVisualization: () => AudioVisualization
}
// ============================================================================
diff --git a/packages/typescript/ai-elevenlabs/package.json b/packages/typescript/ai-elevenlabs/package.json
index 0edafe92a4..4ff1754e8d 100644
--- a/packages/typescript/ai-elevenlabs/package.json
+++ b/packages/typescript/ai-elevenlabs/package.json
@@ -36,7 +36,7 @@
"lint:fix": "eslint ./src --fix",
"test:build": "publint --strict",
"test:eslint": "eslint ./src",
- "test:lib": "vitest",
+ "test:lib": "vitest --passWithNoTests",
"test:lib:dev": "pnpm test:lib --watch",
"test:types": "tsc"
},
diff --git a/packages/typescript/ai-elevenlabs/src/realtime/adapter.ts b/packages/typescript/ai-elevenlabs/src/realtime/adapter.ts
index cb193485ca..39ee355bdb 100644
--- a/packages/typescript/ai-elevenlabs/src/realtime/adapter.ts
+++ b/packages/typescript/ai-elevenlabs/src/realtime/adapter.ts
@@ -59,9 +59,9 @@ async function createElevenLabsConnection(
const emptyTimeDomainData = new Uint8Array(128).fill(128)
// Helper to emit events
- function emit(
- event: E,
- payload: Parameters>[0],
+ function emit(
+ event: TEvent,
+ payload: Parameters>[0],
) {
const handlers = eventHandlers.get(event)
if (handlers) {
@@ -145,7 +145,7 @@ async function createElevenLabsConnection(
emit('mode_change', { mode: 'idle' })
},
- sendText(text: string) {
+ sendText(_text: string) {
// ElevenLabs doesn't support direct text input in the same way
// The SDK is voice-first. Log a warning.
console.warn(
@@ -153,7 +153,7 @@ async function createElevenLabsConnection(
)
},
- sendToolResult(callId: string, result: string) {
+ sendToolResult(_callId: string, _result: string) {
// ElevenLabs handles client tools differently - they're registered at session start
console.warn(
'ElevenLabs tool results are handled via clientTools option during session creation.',
@@ -174,9 +174,9 @@ async function createElevenLabsConnection(
emit('interrupted', {})
},
- on(
- event: E,
- handler: RealtimeEventHandler,
+ on(
+ event: TEvent,
+ handler: RealtimeEventHandler,
): () => void {
if (!eventHandlers.has(event)) {
eventHandlers.set(event, new Set())
diff --git a/packages/typescript/ai-elevenlabs/src/realtime/token.ts b/packages/typescript/ai-elevenlabs/src/realtime/token.ts
index 99989b06b7..030d0c9a95 100644
--- a/packages/typescript/ai-elevenlabs/src/realtime/token.ts
+++ b/packages/typescript/ai-elevenlabs/src/realtime/token.ts
@@ -8,7 +8,7 @@ const ELEVENLABS_API_URL = 'https://api.elevenlabs.io/v1'
*/
function getElevenLabsApiKey(): string {
// Check process.env (Node.js)
- if (typeof process !== 'undefined' && process.env?.ELEVENLABS_API_KEY) {
+ if (typeof process !== 'undefined' && process.env.ELEVENLABS_API_KEY) {
return process.env.ELEVENLABS_API_KEY
}
diff --git a/packages/typescript/ai-elevenlabs/src/realtime/types.ts b/packages/typescript/ai-elevenlabs/src/realtime/types.ts
index ff2166f088..c3f5227f7f 100644
--- a/packages/typescript/ai-elevenlabs/src/realtime/types.ts
+++ b/packages/typescript/ai-elevenlabs/src/realtime/types.ts
@@ -53,10 +53,3 @@ export interface ElevenLabsClientTool {
/** Tool handler function */
handler: (params: TParams) => Promise | TResult
}
-
-/**
- * ElevenLabs signed URL response
- */
-export interface ElevenLabsSignedUrlResponse {
- signed_url: string
-}
diff --git a/packages/typescript/ai-openai/src/realtime/adapter.ts b/packages/typescript/ai-openai/src/realtime/adapter.ts
index 645a5e7168..6245a3c05c 100644
--- a/packages/typescript/ai-openai/src/realtime/adapter.ts
+++ b/packages/typescript/ai-openai/src/realtime/adapter.ts
@@ -88,9 +88,9 @@ async function createWebRTCConnection(
const emptyTimeDomainData = new Uint8Array(2048).fill(128) // 128 is silence
// Helper to emit events (defined early so it can be used during setup)
- function emit(
- event: E,
- payload: Parameters>[0],
+ function emit(
+ event: TEvent,
+ payload: Parameters>[0],
) {
const handlers = eventHandlers.get(event)
if (handlers) {
@@ -264,7 +264,7 @@ async function createWebRTCConnection(
// Emit message complete if we have a current message
if (currentMessageId) {
const response = event.response as Record
- const output = response.output as Array>
+ const output = response.output as Array> | undefined
const message: RealtimeMessage = {
id: currentMessageId,
@@ -495,9 +495,9 @@ async function createWebRTCConnection(
emit('interrupted', { messageId: currentMessageId ?? undefined })
},
- on(
- event: E,
- handler: RealtimeEventHandler,
+ on(
+ event: TEvent,
+ handler: RealtimeEventHandler,
): () => void {
if (!eventHandlers.has(event)) {
eventHandlers.set(event, new Set())
diff --git a/packages/typescript/ai-openai/src/realtime/token.ts b/packages/typescript/ai-openai/src/realtime/token.ts
index d226cacbba..e09d8c7668 100644
--- a/packages/typescript/ai-openai/src/realtime/token.ts
+++ b/packages/typescript/ai-openai/src/realtime/token.ts
@@ -1,5 +1,5 @@
+import { getOpenAIApiKeyFromEnv } from '../utils/client'
import type { RealtimeToken, RealtimeTokenAdapter, Tool } from '@tanstack/ai'
-import { getOpenAIApiKeyFromEnv } from '../utils'
import type {
OpenAIRealtimeModel,
OpenAIRealtimeSessionResponse,
@@ -111,7 +111,7 @@ export function openaiRealtimeToken(
const sessionData: OpenAIRealtimeSessionResponse = await response.json()
// Convert tools to our format
- const tools: Array = (sessionData.tools || []).map((t) => ({
+ const tools: Array = sessionData.tools.map((t) => ({
name: t.name,
description: t.description,
inputSchema: t.parameters,
diff --git a/packages/typescript/ai-react/src/realtime-types.ts b/packages/typescript/ai-react/src/realtime-types.ts
index f3a403464e..9b44269d9e 100644
--- a/packages/typescript/ai-react/src/realtime-types.ts
+++ b/packages/typescript/ai-react/src/realtime-types.ts
@@ -1,11 +1,11 @@
import type {
+ AnyClientTool,
RealtimeMessage,
RealtimeMode,
RealtimeStatus,
RealtimeToken,
} from '@tanstack/ai'
import type { RealtimeAdapter } from '@tanstack/ai-client'
-import type { AnyClientTool } from '@tanstack/ai'
/**
* Options for the useRealtimeChat hook.
diff --git a/packages/typescript/ai/src/realtime/types.ts b/packages/typescript/ai/src/realtime/types.ts
index e563a2ae75..8a4be3a98a 100644
--- a/packages/typescript/ai/src/realtime/types.ts
+++ b/packages/typescript/ai/src/realtime/types.ts
@@ -57,7 +57,7 @@ export interface RealtimeTokenAdapter {
/** Provider identifier */
provider: string
/** Generate an ephemeral token for client use */
- generateToken(): Promise
+ generateToken: () => Promise
}
/**
@@ -176,14 +176,14 @@ export interface AudioVisualization {
readonly outputLevel: number
/** Get frequency data for input audio visualization */
- getInputFrequencyData(): Uint8Array
+ getInputFrequencyData: () => Uint8Array
/** Get frequency data for output audio visualization */
- getOutputFrequencyData(): Uint8Array
+ getOutputFrequencyData: () => Uint8Array
/** Get time domain data for input waveform */
- getInputTimeDomainData(): Uint8Array
+ getInputTimeDomainData: () => Uint8Array
/** Get time domain data for output waveform */
- getOutputTimeDomainData(): Uint8Array
+ getOutputTimeDomainData: () => Uint8Array
/** Input sample rate */
readonly inputSampleRate: number
@@ -191,13 +191,13 @@ export interface AudioVisualization {
readonly outputSampleRate: number
/** Subscribe to raw input audio samples */
- onInputAudio?(
+ onInputAudio?: (
callback: (samples: Float32Array, sampleRate: number) => void,
- ): () => void
+ ) => () => void
/** Subscribe to raw output audio samples */
- onOutputAudio?(
+ onOutputAudio?: (
callback: (samples: Float32Array, sampleRate: number) => void,
- ): () => void
+ ) => () => void
}
// ============================================================================
@@ -238,8 +238,8 @@ export interface RealtimeEventPayloads {
/**
* Handler type for realtime events
*/
-export type RealtimeEventHandler = (
- payload: RealtimeEventPayloads[E],
+export type RealtimeEventHandler = (
+ payload: RealtimeEventPayloads[TEvent],
) => void
// ============================================================================
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index f53f865f57..cb260e5697 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -28,7 +28,7 @@ importers:
version: 0.3.1(typescript@5.9.3)
'@tanstack/vite-config':
specifier: 0.4.1
- version: 0.4.1(@types/node@24.10.3)(rollup@4.55.1)(typescript@5.9.3)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+ version: 0.4.1(@types/node@24.10.3)(rollup@4.57.1)(typescript@5.9.3)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
'@types/node':
specifier: ^24.10.1
version: 24.10.3
@@ -114,20 +114,20 @@ importers:
specifier: ^0.8.2
version: 0.8.4(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(csstype@3.2.3)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(solid-js@1.9.10)
'@tanstack/react-router':
- specifier: ^1.141.1
- version: 1.141.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
+ specifier: ^1.158.4
+ version: 1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
'@tanstack/react-router-devtools':
- specifier: ^1.139.7
- version: 1.141.1(@tanstack/react-router@1.141.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(@tanstack/router-core@1.141.1)(csstype@3.2.3)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(solid-js@1.9.10)
+ specifier: ^1.158.4
+ version: 1.159.5(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(@tanstack/router-core@1.159.4)(csstype@3.2.3)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
'@tanstack/react-router-ssr-query':
- specifier: ^1.139.7
- version: 1.141.1(@tanstack/query-core@5.90.12)(@tanstack/react-query@5.90.12(react@19.2.3))(@tanstack/react-router@1.141.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(@tanstack/router-core@1.141.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
+ specifier: ^1.158.4
+ version: 1.159.5(@tanstack/query-core@5.90.12)(@tanstack/react-query@5.90.12(react@19.2.3))(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(@tanstack/router-core@1.159.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
'@tanstack/react-start':
- specifier: ^1.141.1
- version: 1.141.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+ specifier: ^1.159.0
+ version: 1.159.5(crossws@0.4.4(srvx@0.11.2))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
'@tanstack/router-plugin':
- specifier: ^1.139.7
- version: 1.141.1(@tanstack/react-router@1.141.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+ specifier: ^1.158.4
+ version: 1.159.5(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
capnweb:
specifier: ^0.1.0
version: 0.1.0
@@ -226,29 +226,29 @@ importers:
specifier: workspace:*
version: link:../../packages/typescript/ai-react-ui
'@tanstack/nitro-v2-vite-plugin':
- specifier: ^1.141.0
- version: 1.141.0(rolldown@1.0.0-beta.53)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+ specifier: ^1.154.7
+ version: 1.154.7(rolldown@1.0.0-beta.53)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
'@tanstack/react-devtools':
specifier: ^0.8.2
version: 0.8.4(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(csstype@3.2.3)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(solid-js@1.9.10)
'@tanstack/react-router':
- specifier: ^1.141.1
- version: 1.141.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
+ specifier: ^1.158.4
+ version: 1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
'@tanstack/react-router-devtools':
- specifier: ^1.139.7
- version: 1.141.1(@tanstack/react-router@1.141.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(@tanstack/router-core@1.141.1)(csstype@3.2.3)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(solid-js@1.9.10)
+ specifier: ^1.158.4
+ version: 1.159.5(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(@tanstack/router-core@1.159.4)(csstype@3.2.3)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
'@tanstack/react-router-ssr-query':
- specifier: ^1.139.7
- version: 1.141.1(@tanstack/query-core@5.90.12)(@tanstack/react-query@5.90.12(react@19.2.3))(@tanstack/react-router@1.141.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(@tanstack/router-core@1.141.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
+ specifier: ^1.158.4
+ version: 1.159.5(@tanstack/query-core@5.90.12)(@tanstack/react-query@5.90.12(react@19.2.3))(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(@tanstack/router-core@1.159.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
'@tanstack/react-start':
- specifier: ^1.141.1
- version: 1.141.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+ specifier: ^1.159.0
+ version: 1.159.5(crossws@0.4.4(srvx@0.11.2))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
'@tanstack/react-store':
specifier: ^0.8.0
version: 0.8.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
'@tanstack/router-plugin':
- specifier: ^1.139.7
- version: 1.141.1(@tanstack/react-router@1.141.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+ specifier: ^1.158.4
+ version: 1.159.5(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
'@tanstack/store':
specifier: ^0.8.0
version: 0.8.0
@@ -329,6 +329,64 @@ importers:
specifier: ^5.1.0
version: 5.1.0
+ examples/ts-react-fal:
+ dependencies:
+ '@tailwindcss/vite':
+ specifier: ^4.1.18
+ version: 4.1.18(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+ '@tanstack/ai':
+ specifier: workspace:*
+ version: link:../../packages/typescript/ai
+ '@tanstack/ai-fal':
+ specifier: workspace:*
+ version: link:../../packages/typescript/ai-fal
+ '@tanstack/react-router':
+ specifier: ^1.158.4
+ version: 1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
+ '@tanstack/react-start':
+ specifier: ^1.159.0
+ version: 1.159.5(crossws@0.4.4(srvx@0.10.1))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+ '@tanstack/router-plugin':
+ specifier: ^1.158.4
+ version: 1.159.5(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+ lucide-react:
+ specifier: ^0.561.0
+ version: 0.561.0(react@19.2.3)
+ nitro:
+ specifier: 3.0.1-alpha.2
+ version: 3.0.1-alpha.2(chokidar@5.0.0)(ioredis@5.9.2)(lru-cache@11.2.4)(rolldown@1.0.0-beta.53)(rollup@4.57.1)(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+ react:
+ specifier: ^19.2.3
+ version: 19.2.3
+ react-dom:
+ specifier: ^19.2.3
+ version: 19.2.3(react@19.2.3)
+ tailwindcss:
+ specifier: ^4.1.18
+ version: 4.1.18
+ vite-tsconfig-paths:
+ specifier: ^5.1.4
+ version: 5.1.4(typescript@5.9.3)(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+ devDependencies:
+ '@types/node':
+ specifier: ^24.10.1
+ version: 24.10.3
+ '@types/react':
+ specifier: ^19.2.7
+ version: 19.2.7
+ '@types/react-dom':
+ specifier: ^19.2.3
+ version: 19.2.3(@types/react@19.2.7)
+ '@vitejs/plugin-react':
+ specifier: ^5.1.2
+ version: 5.1.2(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+ typescript:
+ specifier: 5.9.3
+ version: 5.9.3
+ vite:
+ specifier: ^7.2.7
+ version: 7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
+
examples/ts-solid-chat:
dependencies:
'@tailwindcss/vite':
@@ -362,11 +420,11 @@ importers:
specifier: workspace:*
version: link:../../packages/typescript/ai-solid-ui
'@tanstack/nitro-v2-vite-plugin':
- specifier: ^1.141.0
- version: 1.141.0(rolldown@1.0.0-beta.53)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+ specifier: ^1.154.7
+ version: 1.154.7(rolldown@1.0.0-beta.53)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
'@tanstack/router-plugin':
- specifier: ^1.139.7
- version: 1.141.1(@tanstack/react-router@1.141.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+ specifier: ^1.158.4
+ version: 1.159.5(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
'@tanstack/solid-ai-devtools':
specifier: workspace:*
version: link:../../packages/typescript/solid-ai-devtools
@@ -378,13 +436,13 @@ importers:
version: 1.141.1(solid-js@1.9.10)
'@tanstack/solid-router-devtools':
specifier: ^1.139.10
- version: 1.141.1(@tanstack/router-core@1.141.1)(@tanstack/solid-router@1.141.1(solid-js@1.9.10))(csstype@3.2.3)(solid-js@1.9.10)
+ version: 1.141.1(@tanstack/router-core@1.159.4)(@tanstack/solid-router@1.141.1(solid-js@1.9.10))(csstype@3.2.3)(solid-js@1.9.10)
'@tanstack/solid-router-ssr-query':
specifier: ^1.139.10
- version: 1.141.1(@tanstack/query-core@5.90.12)(@tanstack/router-core@1.141.1)(@tanstack/solid-query@5.90.15(solid-js@1.9.10))(@tanstack/solid-router@1.141.1(solid-js@1.9.10))(eslint@9.39.2(jiti@2.6.1))(solid-js@1.9.10)(typescript@5.9.3)
+ version: 1.141.1(@tanstack/query-core@5.90.12)(@tanstack/router-core@1.159.4)(@tanstack/solid-query@5.90.15(solid-js@1.9.10))(@tanstack/solid-router@1.141.1(solid-js@1.9.10))(eslint@9.39.2(jiti@2.6.1))(solid-js@1.9.10)(typescript@5.9.3)
'@tanstack/solid-start':
specifier: ^1.139.10
- version: 1.141.1(@tanstack/react-router@1.141.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(solid-js@1.9.10)(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+ version: 1.141.1(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(crossws@0.4.4(srvx@0.11.2))(solid-js@1.9.10)(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
'@tanstack/solid-store':
specifier: ^0.8.0
version: 0.8.0(solid-js@1.9.10)
@@ -620,7 +678,7 @@ importers:
version: 1.1.0
'@vitest/coverage-v8':
specifier: 4.0.14
- version: 4.0.14(vitest@4.0.17(@types/node@25.0.1)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+ version: 4.0.14(vitest@4.0.18(@types/node@25.0.1)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
zod:
specifier: ^4.2.0
version: 4.2.1
@@ -628,7 +686,7 @@ importers:
packages/typescript/ai-anthropic:
dependencies:
'@anthropic-ai/sdk':
- specifier: ^0.71.0
+ specifier: ^0.71.2
version: 0.71.2(zod@4.2.1)
devDependencies:
'@tanstack/ai':
@@ -636,7 +694,7 @@ importers:
version: link:../ai
'@vitest/coverage-v8':
specifier: 4.0.14
- version: 4.0.14(vitest@4.0.17(@types/node@25.0.1)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+ version: 4.0.14(vitest@4.0.18(@types/node@25.0.1)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
zod:
specifier: ^4.2.0
version: 4.2.1
@@ -649,7 +707,7 @@ importers:
devDependencies:
'@vitest/coverage-v8':
specifier: 4.0.14
- version: 4.0.14(vitest@4.0.17(@types/node@25.0.1)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+ version: 4.0.14(vitest@4.0.18(@types/node@25.0.1)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
vite:
specifier: ^7.2.7
version: 7.2.7(@types/node@25.0.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
@@ -677,7 +735,7 @@ importers:
devDependencies:
'@vitest/coverage-v8':
specifier: 4.0.14
- version: 4.0.14(vitest@4.0.17(@types/node@25.0.1)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+ version: 4.0.14(vitest@4.0.18(@types/node@25.0.1)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
jsdom:
specifier: ^27.2.0
version: 27.3.0(postcss@8.5.6)
@@ -702,7 +760,23 @@ importers:
version: link:../ai-client
'@vitest/coverage-v8':
specifier: 4.0.14
- version: 4.0.14(vitest@4.0.17(@types/node@25.0.1)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+ version: 4.0.14(vitest@4.0.18(@types/node@25.0.1)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+
+ packages/typescript/ai-fal:
+ dependencies:
+ '@fal-ai/client':
+ specifier: ^1.9.1
+ version: 1.9.1
+ devDependencies:
+ '@tanstack/ai':
+ specifier: workspace:*
+ version: link:../ai
+ '@vitest/coverage-v8':
+ specifier: 4.0.14
+ version: 4.0.14(vitest@4.0.18(@types/node@25.0.1)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+ vite:
+ specifier: ^7.2.7
+ version: 7.3.1(@types/node@25.0.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
packages/typescript/ai-gemini:
dependencies:
@@ -715,7 +789,7 @@ importers:
version: link:../ai
'@vitest/coverage-v8':
specifier: 4.0.14
- version: 4.0.14(vitest@4.0.17(@types/node@25.0.1)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+ version: 4.0.14(vitest@4.0.18(@types/node@25.0.1)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
vite:
specifier: ^7.2.7
version: 7.2.7(@types/node@25.0.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
@@ -734,7 +808,7 @@ importers:
devDependencies:
'@vitest/coverage-v8':
specifier: 4.0.14
- version: 4.0.14(vitest@4.0.17(@types/node@25.0.1)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+ version: 4.0.14(vitest@4.0.18(@types/node@25.0.1)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
vite:
specifier: ^7.2.7
version: 7.2.7(@types/node@25.0.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
@@ -750,7 +824,7 @@ importers:
version: link:../ai
'@vitest/coverage-v8':
specifier: 4.0.14
- version: 4.0.14(vitest@4.0.17(@types/node@25.0.1)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+ version: 4.0.14(vitest@4.0.18(@types/node@25.0.1)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
vite:
specifier: ^7.2.7
version: 7.2.7(@types/node@25.0.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
@@ -769,7 +843,7 @@ importers:
version: link:../ai-client
'@vitest/coverage-v8':
specifier: 4.0.14
- version: 4.0.14(vitest@4.0.17(@types/node@25.0.1)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+ version: 4.0.14(vitest@4.0.18(@types/node@25.0.1)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
vite:
specifier: ^7.2.7
version: 7.2.7(@types/node@25.0.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
@@ -788,7 +862,7 @@ importers:
devDependencies:
'@vitest/coverage-v8':
specifier: 4.0.14
- version: 4.0.14(vitest@4.0.17(@types/node@25.0.1)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+ version: 4.0.14(vitest@4.0.18(@types/node@25.0.1)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
vite:
specifier: ^7.2.7
version: 7.2.7(@types/node@25.0.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
@@ -807,7 +881,7 @@ importers:
version: 3.2.4(preact@10.28.2)
'@vitest/coverage-v8':
specifier: 4.0.14
- version: 4.0.14(vitest@4.0.17(@types/node@25.0.1)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+ version: 4.0.14(vitest@4.0.18(@types/node@25.0.1)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
jsdom:
specifier: ^27.2.0
version: 27.3.0(postcss@8.5.6)
@@ -835,7 +909,7 @@ importers:
version: 19.2.7
'@vitest/coverage-v8':
specifier: 4.0.14
- version: 4.0.14(vitest@4.0.17(@types/node@25.0.1)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+ version: 4.0.14(vitest@4.0.18(@types/node@25.0.1)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
jsdom:
specifier: ^27.2.0
version: 27.3.0(postcss@8.5.6)
@@ -875,7 +949,7 @@ importers:
version: 19.2.7
'@vitest/coverage-v8':
specifier: 4.0.14
- version: 4.0.14(vitest@4.0.17(@types/node@25.0.1)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+ version: 4.0.14(vitest@4.0.18(@types/node@25.0.1)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
react:
specifier: ^19.2.3
version: 19.2.3
@@ -946,7 +1020,7 @@ importers:
version: link:../ai-solid
'@vitest/coverage-v8':
specifier: 4.0.14
- version: 4.0.14(vitest@4.0.17(@types/node@25.0.1)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+ version: 4.0.14(vitest@4.0.18(@types/node@25.0.1)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
solid-js:
specifier: ^1.9.10
version: 1.9.10
@@ -974,7 +1048,7 @@ importers:
version: 24.10.3
'@vitest/coverage-v8':
specifier: 4.0.14
- version: 4.0.14(vitest@4.0.17(@types/node@24.10.3)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+ version: 4.0.14(vitest@4.0.18(@types/node@24.10.3)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
jsdom:
specifier: ^27.2.0
version: 27.3.0(postcss@8.5.6)
@@ -1051,7 +1125,7 @@ importers:
version: 6.0.3(vite@7.2.7(@types/node@25.0.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(vue@3.5.25(typescript@5.9.3))
'@vitest/coverage-v8':
specifier: 4.0.14
- version: 4.0.14(vitest@4.0.17(@types/node@25.0.1)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+ version: 4.0.14(vitest@4.0.18(@types/node@25.0.1)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
vite:
specifier: ^7.2.7
version: 7.2.7(@types/node@25.0.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
@@ -1076,7 +1150,7 @@ importers:
devDependencies:
'@vitest/coverage-v8':
specifier: 4.0.14
- version: 4.0.14(vitest@4.0.17(@types/node@25.0.1)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+ version: 4.0.14(vitest@4.0.18(@types/node@25.0.1)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
vite:
specifier: ^7.2.7
version: 7.2.7(@types/node@25.0.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
@@ -1095,7 +1169,7 @@ importers:
version: 19.2.7
'@vitest/coverage-v8':
specifier: 4.0.14
- version: 4.0.14(vitest@4.0.17(@types/node@25.0.1)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+ version: 4.0.14(vitest@4.0.18(@types/node@25.0.1)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
react:
specifier: ^19.2.3
version: 19.2.3
@@ -1147,6 +1221,9 @@ importers:
typescript:
specifier: 5.9.3
version: 5.9.3
+ vitest:
+ specifier: ^4.0.14
+ version: 4.0.18(@types/node@24.10.3)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
zod:
specifier: ^4.2.0
version: 4.2.1
@@ -1169,17 +1246,20 @@ importers:
specifier: workspace:*
version: link:../../ai-react
'@tanstack/nitro-v2-vite-plugin':
- specifier: ^1.141.0
- version: 1.141.0(rolldown@1.0.0-beta.53)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+ specifier: ^1.154.7
+ version: 1.154.7(rolldown@1.0.0-beta.53)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
'@tanstack/react-router':
- specifier: ^1.141.1
- version: 1.141.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
+ specifier: ^1.158.4
+ version: 1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
'@tanstack/react-start':
- specifier: ^1.141.1
- version: 1.141.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+ specifier: ^1.159.0
+ version: 1.159.5(crossws@0.4.4(srvx@0.11.2))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
'@tanstack/router-plugin':
- specifier: ^1.139.7
- version: 1.141.1(@tanstack/react-router@1.141.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+ specifier: ^1.158.4
+ version: 1.159.5(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+ '@tanstack/tests-adapters':
+ specifier: workspace:*
+ version: link:../adapters
react:
specifier: ^19.2.3
version: 19.2.3
@@ -1189,9 +1269,9 @@ importers:
tailwindcss:
specifier: ^4.1.18
version: 4.1.18
- vite-tsconfig-paths:
- specifier: ^5.1.4
- version: 5.1.4(typescript@5.9.3)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+ zod:
+ specifier: ^4.2.0
+ version: 4.2.1
devDependencies:
'@playwright/test':
specifier: ^1.57.0
@@ -1214,6 +1294,9 @@ importers:
vite:
specifier: ^7.2.7
version: 7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
+ vite-tsconfig-paths:
+ specifier: ^5.1.4
+ version: 5.1.4(typescript@5.9.3)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
packages/typescript/solid-ai-devtools:
dependencies:
@@ -1226,7 +1309,7 @@ importers:
devDependencies:
'@vitest/coverage-v8':
specifier: 4.0.14
- version: 4.0.14(vitest@4.0.17(@types/node@25.0.1)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+ version: 4.0.14(vitest@4.0.18(@types/node@25.0.1)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
solid-js:
specifier: ^1.9.10
version: 1.9.10
@@ -1263,6 +1346,9 @@ importers:
'@tanstack/ai-openai':
specifier: workspace:*
version: link:../../packages/typescript/ai-openai
+ '@tanstack/ai-openrouter':
+ specifier: workspace:*
+ version: link:../../packages/typescript/ai-openrouter
'@tanstack/ai-react':
specifier: workspace:*
version: link:../../packages/typescript/ai-react
@@ -1270,17 +1356,17 @@ importers:
specifier: workspace:*
version: link:../../packages/typescript/ai-react-ui
'@tanstack/nitro-v2-vite-plugin':
- specifier: ^1.141.0
- version: 1.141.0(rolldown@1.0.0-beta.53)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+ specifier: ^1.154.7
+ version: 1.154.7(rolldown@1.0.0-beta.53)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
'@tanstack/react-router':
- specifier: ^1.141.1
- version: 1.141.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
+ specifier: ^1.158.4
+ version: 1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
'@tanstack/react-start':
- specifier: ^1.141.1
- version: 1.141.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+ specifier: ^1.159.0
+ version: 1.159.5(crossws@0.4.4(srvx@0.11.2))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
'@tanstack/start':
specifier: ^1.120.20
- version: 1.120.20(@types/node@24.10.3)(db0@0.3.4)(ioredis@5.8.2)(jiti@2.6.1)(lightningcss@1.30.2)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(rolldown@1.0.0-beta.53)(terser@5.44.1)(tsx@4.21.0)(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(yaml@2.8.2)
+ version: 1.120.20(@types/node@24.10.3)(crossws@0.4.4(srvx@0.11.2))(db0@0.3.4)(ioredis@5.8.2)(jiti@2.6.1)(lightningcss@1.30.2)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(rolldown@1.0.0-beta.53)(terser@5.44.1)(tsx@4.21.0)(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(yaml@2.8.2)
highlight.js:
specifier: ^11.11.1
version: 11.11.1
@@ -1318,6 +1404,9 @@ importers:
specifier: ^4.2.0
version: 4.2.1
devDependencies:
+ '@playwright/test':
+ specifier: ^1.57.0
+ version: 1.57.0
'@types/node':
specifier: ^24.10.1
version: 24.10.3
@@ -1330,6 +1419,9 @@ importers:
'@vitejs/plugin-react':
specifier: ^5.1.2
version: 5.1.2(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+ dotenv:
+ specifier: ^17.2.3
+ version: 17.2.3
typescript:
specifier: 5.9.3
version: 5.9.3
@@ -1464,6 +1556,11 @@ packages:
engines: {node: '>=6.0.0'}
hasBin: true
+ '@babel/parser@7.29.0':
+ resolution: {integrity: sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==}
+ engines: {node: '>=6.0.0'}
+ hasBin: true
+
'@babel/plugin-syntax-jsx@7.27.1':
resolution: {integrity: sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w==}
engines: {node: '>=6.9.0'}
@@ -1522,6 +1619,10 @@ packages:
resolution: {integrity: sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==}
engines: {node: '>=6.9.0'}
+ '@babel/types@7.29.0':
+ resolution: {integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==}
+ engines: {node: '>=6.9.0'}
+
'@bcoe/v8-coverage@1.0.2':
resolution: {integrity: sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==}
engines: {node: '>=18'}
@@ -1591,6 +1692,10 @@ packages:
resolution: {integrity: sha512-Nu8ahitGFFJztxUml9oD/DLb7Z28C8cd8F46IVQ7y5Btz575pvMY8AqZsXkX7Gds29eCKdMgIHjIvzskHgPSFg==}
engines: {node: '>=18.0.0'}
+ '@cloudflare/kv-asset-handler@0.4.2':
+ resolution: {integrity: sha512-SIOD2DxrRRwQ+jgzlXCqoEFiKOFqaPjhnNTGKXSRLvp1HiOvapLaFG2kEr9dYQTYe8rKrd9uvDUzmAITeNyaHQ==}
+ engines: {node: '>=18.0.0'}
+
'@crazydos/vue-markdown@1.1.4':
resolution: {integrity: sha512-0I1QMP59LJ3aEjE7bolgvPU4JAFt+pykdDo5674CbsCwFo7OVFos50+MPhGdWflCz1mac5t152lB1qvV/tR/rw==}
engines: {node: '>=20.0.0'}
@@ -1658,14 +1763,14 @@ packages:
cpu: [ppc64]
os: [aix]
- '@esbuild/aix-ppc64@0.27.1':
- resolution: {integrity: sha512-HHB50pdsBX6k47S4u5g/CaLjqS3qwaOVE5ILsq64jyzgMhLuCuZ8rGzM9yhsAjfjkbgUPMzZEPa7DAp7yz6vuA==}
+ '@esbuild/aix-ppc64@0.27.2':
+ resolution: {integrity: sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw==}
engines: {node: '>=18'}
cpu: [ppc64]
os: [aix]
- '@esbuild/aix-ppc64@0.27.2':
- resolution: {integrity: sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw==}
+ '@esbuild/aix-ppc64@0.27.3':
+ resolution: {integrity: sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==}
engines: {node: '>=18'}
cpu: [ppc64]
os: [aix]
@@ -1682,14 +1787,14 @@ packages:
cpu: [arm64]
os: [android]
- '@esbuild/android-arm64@0.27.1':
- resolution: {integrity: sha512-45fuKmAJpxnQWixOGCrS+ro4Uvb4Re9+UTieUY2f8AEc+t7d4AaZ6eUJ3Hva7dtrxAAWHtlEFsXFMAgNnGU9uQ==}
+ '@esbuild/android-arm64@0.27.2':
+ resolution: {integrity: sha512-pvz8ZZ7ot/RBphf8fv60ljmaoydPU12VuXHImtAs0XhLLw+EXBi2BLe3OYSBslR4rryHvweW5gmkKFwTiFy6KA==}
engines: {node: '>=18'}
cpu: [arm64]
os: [android]
- '@esbuild/android-arm64@0.27.2':
- resolution: {integrity: sha512-pvz8ZZ7ot/RBphf8fv60ljmaoydPU12VuXHImtAs0XhLLw+EXBi2BLe3OYSBslR4rryHvweW5gmkKFwTiFy6KA==}
+ '@esbuild/android-arm64@0.27.3':
+ resolution: {integrity: sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==}
engines: {node: '>=18'}
cpu: [arm64]
os: [android]
@@ -1706,14 +1811,14 @@ packages:
cpu: [arm]
os: [android]
- '@esbuild/android-arm@0.27.1':
- resolution: {integrity: sha512-kFqa6/UcaTbGm/NncN9kzVOODjhZW8e+FRdSeypWe6j33gzclHtwlANs26JrupOntlcWmB0u8+8HZo8s7thHvg==}
+ '@esbuild/android-arm@0.27.2':
+ resolution: {integrity: sha512-DVNI8jlPa7Ujbr1yjU2PfUSRtAUZPG9I1RwW4F4xFB1Imiu2on0ADiI/c3td+KmDtVKNbi+nffGDQMfcIMkwIA==}
engines: {node: '>=18'}
cpu: [arm]
os: [android]
- '@esbuild/android-arm@0.27.2':
- resolution: {integrity: sha512-DVNI8jlPa7Ujbr1yjU2PfUSRtAUZPG9I1RwW4F4xFB1Imiu2on0ADiI/c3td+KmDtVKNbi+nffGDQMfcIMkwIA==}
+ '@esbuild/android-arm@0.27.3':
+ resolution: {integrity: sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==}
engines: {node: '>=18'}
cpu: [arm]
os: [android]
@@ -1730,14 +1835,14 @@ packages:
cpu: [x64]
os: [android]
- '@esbuild/android-x64@0.27.1':
- resolution: {integrity: sha512-LBEpOz0BsgMEeHgenf5aqmn/lLNTFXVfoWMUox8CtWWYK9X4jmQzWjoGoNb8lmAYml/tQ/Ysvm8q7szu7BoxRQ==}
+ '@esbuild/android-x64@0.27.2':
+ resolution: {integrity: sha512-z8Ank4Byh4TJJOh4wpz8g2vDy75zFL0TlZlkUkEwYXuPSgX8yzep596n6mT7905kA9uHZsf/o2OJZubl2l3M7A==}
engines: {node: '>=18'}
cpu: [x64]
os: [android]
- '@esbuild/android-x64@0.27.2':
- resolution: {integrity: sha512-z8Ank4Byh4TJJOh4wpz8g2vDy75zFL0TlZlkUkEwYXuPSgX8yzep596n6mT7905kA9uHZsf/o2OJZubl2l3M7A==}
+ '@esbuild/android-x64@0.27.3':
+ resolution: {integrity: sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==}
engines: {node: '>=18'}
cpu: [x64]
os: [android]
@@ -1754,14 +1859,14 @@ packages:
cpu: [arm64]
os: [darwin]
- '@esbuild/darwin-arm64@0.27.1':
- resolution: {integrity: sha512-veg7fL8eMSCVKL7IW4pxb54QERtedFDfY/ASrumK/SbFsXnRazxY4YykN/THYqFnFwJ0aVjiUrVG2PwcdAEqQQ==}
+ '@esbuild/darwin-arm64@0.27.2':
+ resolution: {integrity: sha512-davCD2Zc80nzDVRwXTcQP/28fiJbcOwvdolL0sOiOsbwBa72kegmVU0Wrh1MYrbuCL98Omp5dVhQFWRKR2ZAlg==}
engines: {node: '>=18'}
cpu: [arm64]
os: [darwin]
- '@esbuild/darwin-arm64@0.27.2':
- resolution: {integrity: sha512-davCD2Zc80nzDVRwXTcQP/28fiJbcOwvdolL0sOiOsbwBa72kegmVU0Wrh1MYrbuCL98Omp5dVhQFWRKR2ZAlg==}
+ '@esbuild/darwin-arm64@0.27.3':
+ resolution: {integrity: sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==}
engines: {node: '>=18'}
cpu: [arm64]
os: [darwin]
@@ -1778,14 +1883,14 @@ packages:
cpu: [x64]
os: [darwin]
- '@esbuild/darwin-x64@0.27.1':
- resolution: {integrity: sha512-+3ELd+nTzhfWb07Vol7EZ+5PTbJ/u74nC6iv4/lwIU99Ip5uuY6QoIf0Hn4m2HoV0qcnRivN3KSqc+FyCHjoVQ==}
+ '@esbuild/darwin-x64@0.27.2':
+ resolution: {integrity: sha512-ZxtijOmlQCBWGwbVmwOF/UCzuGIbUkqB1faQRf5akQmxRJ1ujusWsb3CVfk/9iZKr2L5SMU5wPBi1UWbvL+VQA==}
engines: {node: '>=18'}
cpu: [x64]
os: [darwin]
- '@esbuild/darwin-x64@0.27.2':
- resolution: {integrity: sha512-ZxtijOmlQCBWGwbVmwOF/UCzuGIbUkqB1faQRf5akQmxRJ1ujusWsb3CVfk/9iZKr2L5SMU5wPBi1UWbvL+VQA==}
+ '@esbuild/darwin-x64@0.27.3':
+ resolution: {integrity: sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==}
engines: {node: '>=18'}
cpu: [x64]
os: [darwin]
@@ -1802,14 +1907,14 @@ packages:
cpu: [arm64]
os: [freebsd]
- '@esbuild/freebsd-arm64@0.27.1':
- resolution: {integrity: sha512-/8Rfgns4XD9XOSXlzUDepG8PX+AVWHliYlUkFI3K3GB6tqbdjYqdhcb4BKRd7C0BhZSoaCxhv8kTcBrcZWP+xg==}
+ '@esbuild/freebsd-arm64@0.27.2':
+ resolution: {integrity: sha512-lS/9CN+rgqQ9czogxlMcBMGd+l8Q3Nj1MFQwBZJyoEKI50XGxwuzznYdwcav6lpOGv5BqaZXqvBSiB/kJ5op+g==}
engines: {node: '>=18'}
cpu: [arm64]
os: [freebsd]
- '@esbuild/freebsd-arm64@0.27.2':
- resolution: {integrity: sha512-lS/9CN+rgqQ9czogxlMcBMGd+l8Q3Nj1MFQwBZJyoEKI50XGxwuzznYdwcav6lpOGv5BqaZXqvBSiB/kJ5op+g==}
+ '@esbuild/freebsd-arm64@0.27.3':
+ resolution: {integrity: sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==}
engines: {node: '>=18'}
cpu: [arm64]
os: [freebsd]
@@ -1826,14 +1931,14 @@ packages:
cpu: [x64]
os: [freebsd]
- '@esbuild/freebsd-x64@0.27.1':
- resolution: {integrity: sha512-GITpD8dK9C+r+5yRT/UKVT36h/DQLOHdwGVwwoHidlnA168oD3uxA878XloXebK4Ul3gDBBIvEdL7go9gCUFzQ==}
+ '@esbuild/freebsd-x64@0.27.2':
+ resolution: {integrity: sha512-tAfqtNYb4YgPnJlEFu4c212HYjQWSO/w/h/lQaBK7RbwGIkBOuNKQI9tqWzx7Wtp7bTPaGC6MJvWI608P3wXYA==}
engines: {node: '>=18'}
cpu: [x64]
os: [freebsd]
- '@esbuild/freebsd-x64@0.27.2':
- resolution: {integrity: sha512-tAfqtNYb4YgPnJlEFu4c212HYjQWSO/w/h/lQaBK7RbwGIkBOuNKQI9tqWzx7Wtp7bTPaGC6MJvWI608P3wXYA==}
+ '@esbuild/freebsd-x64@0.27.3':
+ resolution: {integrity: sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==}
engines: {node: '>=18'}
cpu: [x64]
os: [freebsd]
@@ -1850,14 +1955,14 @@ packages:
cpu: [arm64]
os: [linux]
- '@esbuild/linux-arm64@0.27.1':
- resolution: {integrity: sha512-W9//kCrh/6in9rWIBdKaMtuTTzNj6jSeG/haWBADqLLa9P8O5YSRDzgD5y9QBok4AYlzS6ARHifAb75V6G670Q==}
+ '@esbuild/linux-arm64@0.27.2':
+ resolution: {integrity: sha512-hYxN8pr66NsCCiRFkHUAsxylNOcAQaxSSkHMMjcpx0si13t1LHFphxJZUiGwojB1a/Hd5OiPIqDdXONia6bhTw==}
engines: {node: '>=18'}
cpu: [arm64]
os: [linux]
- '@esbuild/linux-arm64@0.27.2':
- resolution: {integrity: sha512-hYxN8pr66NsCCiRFkHUAsxylNOcAQaxSSkHMMjcpx0si13t1LHFphxJZUiGwojB1a/Hd5OiPIqDdXONia6bhTw==}
+ '@esbuild/linux-arm64@0.27.3':
+ resolution: {integrity: sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==}
engines: {node: '>=18'}
cpu: [arm64]
os: [linux]
@@ -1874,14 +1979,14 @@ packages:
cpu: [arm]
os: [linux]
- '@esbuild/linux-arm@0.27.1':
- resolution: {integrity: sha512-ieMID0JRZY/ZeCrsFQ3Y3NlHNCqIhTprJfDgSB3/lv5jJZ8FX3hqPyXWhe+gvS5ARMBJ242PM+VNz/ctNj//eA==}
+ '@esbuild/linux-arm@0.27.2':
+ resolution: {integrity: sha512-vWfq4GaIMP9AIe4yj1ZUW18RDhx6EPQKjwe7n8BbIecFtCQG4CfHGaHuh7fdfq+y3LIA2vGS/o9ZBGVxIDi9hw==}
engines: {node: '>=18'}
cpu: [arm]
os: [linux]
- '@esbuild/linux-arm@0.27.2':
- resolution: {integrity: sha512-vWfq4GaIMP9AIe4yj1ZUW18RDhx6EPQKjwe7n8BbIecFtCQG4CfHGaHuh7fdfq+y3LIA2vGS/o9ZBGVxIDi9hw==}
+ '@esbuild/linux-arm@0.27.3':
+ resolution: {integrity: sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==}
engines: {node: '>=18'}
cpu: [arm]
os: [linux]
@@ -1898,14 +2003,14 @@ packages:
cpu: [ia32]
os: [linux]
- '@esbuild/linux-ia32@0.27.1':
- resolution: {integrity: sha512-VIUV4z8GD8rtSVMfAj1aXFahsi/+tcoXXNYmXgzISL+KB381vbSTNdeZHHHIYqFyXcoEhu9n5cT+05tRv13rlw==}
+ '@esbuild/linux-ia32@0.27.2':
+ resolution: {integrity: sha512-MJt5BRRSScPDwG2hLelYhAAKh9imjHK5+NE/tvnRLbIqUWa+0E9N4WNMjmp/kXXPHZGqPLxggwVhz7QP8CTR8w==}
engines: {node: '>=18'}
cpu: [ia32]
os: [linux]
- '@esbuild/linux-ia32@0.27.2':
- resolution: {integrity: sha512-MJt5BRRSScPDwG2hLelYhAAKh9imjHK5+NE/tvnRLbIqUWa+0E9N4WNMjmp/kXXPHZGqPLxggwVhz7QP8CTR8w==}
+ '@esbuild/linux-ia32@0.27.3':
+ resolution: {integrity: sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==}
engines: {node: '>=18'}
cpu: [ia32]
os: [linux]
@@ -1922,14 +2027,14 @@ packages:
cpu: [loong64]
os: [linux]
- '@esbuild/linux-loong64@0.27.1':
- resolution: {integrity: sha512-l4rfiiJRN7sTNI//ff65zJ9z8U+k6zcCg0LALU5iEWzY+a1mVZ8iWC1k5EsNKThZ7XCQ6YWtsZ8EWYm7r1UEsg==}
+ '@esbuild/linux-loong64@0.27.2':
+ resolution: {integrity: sha512-lugyF1atnAT463aO6KPshVCJK5NgRnU4yb3FUumyVz+cGvZbontBgzeGFO1nF+dPueHD367a2ZXe1NtUkAjOtg==}
engines: {node: '>=18'}
cpu: [loong64]
os: [linux]
- '@esbuild/linux-loong64@0.27.2':
- resolution: {integrity: sha512-lugyF1atnAT463aO6KPshVCJK5NgRnU4yb3FUumyVz+cGvZbontBgzeGFO1nF+dPueHD367a2ZXe1NtUkAjOtg==}
+ '@esbuild/linux-loong64@0.27.3':
+ resolution: {integrity: sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==}
engines: {node: '>=18'}
cpu: [loong64]
os: [linux]
@@ -1946,14 +2051,14 @@ packages:
cpu: [mips64el]
os: [linux]
- '@esbuild/linux-mips64el@0.27.1':
- resolution: {integrity: sha512-U0bEuAOLvO/DWFdygTHWY8C067FXz+UbzKgxYhXC0fDieFa0kDIra1FAhsAARRJbvEyso8aAqvPdNxzWuStBnA==}
+ '@esbuild/linux-mips64el@0.27.2':
+ resolution: {integrity: sha512-nlP2I6ArEBewvJ2gjrrkESEZkB5mIoaTswuqNFRv/WYd+ATtUpe9Y09RnJvgvdag7he0OWgEZWhviS1OTOKixw==}
engines: {node: '>=18'}
cpu: [mips64el]
os: [linux]
- '@esbuild/linux-mips64el@0.27.2':
- resolution: {integrity: sha512-nlP2I6ArEBewvJ2gjrrkESEZkB5mIoaTswuqNFRv/WYd+ATtUpe9Y09RnJvgvdag7he0OWgEZWhviS1OTOKixw==}
+ '@esbuild/linux-mips64el@0.27.3':
+ resolution: {integrity: sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==}
engines: {node: '>=18'}
cpu: [mips64el]
os: [linux]
@@ -1970,14 +2075,14 @@ packages:
cpu: [ppc64]
os: [linux]
- '@esbuild/linux-ppc64@0.27.1':
- resolution: {integrity: sha512-NzdQ/Xwu6vPSf/GkdmRNsOfIeSGnh7muundsWItmBsVpMoNPVpM61qNzAVY3pZ1glzzAxLR40UyYM23eaDDbYQ==}
+ '@esbuild/linux-ppc64@0.27.2':
+ resolution: {integrity: sha512-C92gnpey7tUQONqg1n6dKVbx3vphKtTHJaNG2Ok9lGwbZil6DrfyecMsp9CrmXGQJmZ7iiVXvvZH6Ml5hL6XdQ==}
engines: {node: '>=18'}
cpu: [ppc64]
os: [linux]
- '@esbuild/linux-ppc64@0.27.2':
- resolution: {integrity: sha512-C92gnpey7tUQONqg1n6dKVbx3vphKtTHJaNG2Ok9lGwbZil6DrfyecMsp9CrmXGQJmZ7iiVXvvZH6Ml5hL6XdQ==}
+ '@esbuild/linux-ppc64@0.27.3':
+ resolution: {integrity: sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==}
engines: {node: '>=18'}
cpu: [ppc64]
os: [linux]
@@ -1994,14 +2099,14 @@ packages:
cpu: [riscv64]
os: [linux]
- '@esbuild/linux-riscv64@0.27.1':
- resolution: {integrity: sha512-7zlw8p3IApcsN7mFw0O1Z1PyEk6PlKMu18roImfl3iQHTnr/yAfYv6s4hXPidbDoI2Q0pW+5xeoM4eTCC0UdrQ==}
+ '@esbuild/linux-riscv64@0.27.2':
+ resolution: {integrity: sha512-B5BOmojNtUyN8AXlK0QJyvjEZkWwy/FKvakkTDCziX95AowLZKR6aCDhG7LeF7uMCXEJqwa8Bejz5LTPYm8AvA==}
engines: {node: '>=18'}
cpu: [riscv64]
os: [linux]
- '@esbuild/linux-riscv64@0.27.2':
- resolution: {integrity: sha512-B5BOmojNtUyN8AXlK0QJyvjEZkWwy/FKvakkTDCziX95AowLZKR6aCDhG7LeF7uMCXEJqwa8Bejz5LTPYm8AvA==}
+ '@esbuild/linux-riscv64@0.27.3':
+ resolution: {integrity: sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==}
engines: {node: '>=18'}
cpu: [riscv64]
os: [linux]
@@ -2018,14 +2123,14 @@ packages:
cpu: [s390x]
os: [linux]
- '@esbuild/linux-s390x@0.27.1':
- resolution: {integrity: sha512-cGj5wli+G+nkVQdZo3+7FDKC25Uh4ZVwOAK6A06Hsvgr8WqBBuOy/1s+PUEd/6Je+vjfm6stX0kmib5b/O2Ykw==}
+ '@esbuild/linux-s390x@0.27.2':
+ resolution: {integrity: sha512-p4bm9+wsPwup5Z8f4EpfN63qNagQ47Ua2znaqGH6bqLlmJ4bx97Y9JdqxgGZ6Y8xVTixUnEkoKSHcpRlDnNr5w==}
engines: {node: '>=18'}
cpu: [s390x]
os: [linux]
- '@esbuild/linux-s390x@0.27.2':
- resolution: {integrity: sha512-p4bm9+wsPwup5Z8f4EpfN63qNagQ47Ua2znaqGH6bqLlmJ4bx97Y9JdqxgGZ6Y8xVTixUnEkoKSHcpRlDnNr5w==}
+ '@esbuild/linux-s390x@0.27.3':
+ resolution: {integrity: sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==}
engines: {node: '>=18'}
cpu: [s390x]
os: [linux]
@@ -2042,14 +2147,14 @@ packages:
cpu: [x64]
os: [linux]
- '@esbuild/linux-x64@0.27.1':
- resolution: {integrity: sha512-z3H/HYI9MM0HTv3hQZ81f+AKb+yEoCRlUby1F80vbQ5XdzEMyY/9iNlAmhqiBKw4MJXwfgsh7ERGEOhrM1niMA==}
+ '@esbuild/linux-x64@0.27.2':
+ resolution: {integrity: sha512-uwp2Tip5aPmH+NRUwTcfLb+W32WXjpFejTIOWZFw/v7/KnpCDKG66u4DLcurQpiYTiYwQ9B7KOeMJvLCu/OvbA==}
engines: {node: '>=18'}
cpu: [x64]
os: [linux]
- '@esbuild/linux-x64@0.27.2':
- resolution: {integrity: sha512-uwp2Tip5aPmH+NRUwTcfLb+W32WXjpFejTIOWZFw/v7/KnpCDKG66u4DLcurQpiYTiYwQ9B7KOeMJvLCu/OvbA==}
+ '@esbuild/linux-x64@0.27.3':
+ resolution: {integrity: sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==}
engines: {node: '>=18'}
cpu: [x64]
os: [linux]
@@ -2060,14 +2165,14 @@ packages:
cpu: [arm64]
os: [netbsd]
- '@esbuild/netbsd-arm64@0.27.1':
- resolution: {integrity: sha512-wzC24DxAvk8Em01YmVXyjl96Mr+ecTPyOuADAvjGg+fyBpGmxmcr2E5ttf7Im8D0sXZihpxzO1isus8MdjMCXQ==}
+ '@esbuild/netbsd-arm64@0.27.2':
+ resolution: {integrity: sha512-Kj6DiBlwXrPsCRDeRvGAUb/LNrBASrfqAIok+xB0LxK8CHqxZ037viF13ugfsIpePH93mX7xfJp97cyDuTZ3cw==}
engines: {node: '>=18'}
cpu: [arm64]
os: [netbsd]
- '@esbuild/netbsd-arm64@0.27.2':
- resolution: {integrity: sha512-Kj6DiBlwXrPsCRDeRvGAUb/LNrBASrfqAIok+xB0LxK8CHqxZ037viF13ugfsIpePH93mX7xfJp97cyDuTZ3cw==}
+ '@esbuild/netbsd-arm64@0.27.3':
+ resolution: {integrity: sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==}
engines: {node: '>=18'}
cpu: [arm64]
os: [netbsd]
@@ -2084,14 +2189,14 @@ packages:
cpu: [x64]
os: [netbsd]
- '@esbuild/netbsd-x64@0.27.1':
- resolution: {integrity: sha512-1YQ8ybGi2yIXswu6eNzJsrYIGFpnlzEWRl6iR5gMgmsrR0FcNoV1m9k9sc3PuP5rUBLshOZylc9nqSgymI+TYg==}
+ '@esbuild/netbsd-x64@0.27.2':
+ resolution: {integrity: sha512-HwGDZ0VLVBY3Y+Nw0JexZy9o/nUAWq9MlV7cahpaXKW6TOzfVno3y3/M8Ga8u8Yr7GldLOov27xiCnqRZf0tCA==}
engines: {node: '>=18'}
cpu: [x64]
os: [netbsd]
- '@esbuild/netbsd-x64@0.27.2':
- resolution: {integrity: sha512-HwGDZ0VLVBY3Y+Nw0JexZy9o/nUAWq9MlV7cahpaXKW6TOzfVno3y3/M8Ga8u8Yr7GldLOov27xiCnqRZf0tCA==}
+ '@esbuild/netbsd-x64@0.27.3':
+ resolution: {integrity: sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==}
engines: {node: '>=18'}
cpu: [x64]
os: [netbsd]
@@ -2102,14 +2207,14 @@ packages:
cpu: [arm64]
os: [openbsd]
- '@esbuild/openbsd-arm64@0.27.1':
- resolution: {integrity: sha512-5Z+DzLCrq5wmU7RDaMDe2DVXMRm2tTDvX2KU14JJVBN2CT/qov7XVix85QoJqHltpvAOZUAc3ndU56HSMWrv8g==}
+ '@esbuild/openbsd-arm64@0.27.2':
+ resolution: {integrity: sha512-DNIHH2BPQ5551A7oSHD0CKbwIA/Ox7+78/AWkbS5QoRzaqlev2uFayfSxq68EkonB+IKjiuxBFoV8ESJy8bOHA==}
engines: {node: '>=18'}
cpu: [arm64]
os: [openbsd]
- '@esbuild/openbsd-arm64@0.27.2':
- resolution: {integrity: sha512-DNIHH2BPQ5551A7oSHD0CKbwIA/Ox7+78/AWkbS5QoRzaqlev2uFayfSxq68EkonB+IKjiuxBFoV8ESJy8bOHA==}
+ '@esbuild/openbsd-arm64@0.27.3':
+ resolution: {integrity: sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==}
engines: {node: '>=18'}
cpu: [arm64]
os: [openbsd]
@@ -2126,14 +2231,14 @@ packages:
cpu: [x64]
os: [openbsd]
- '@esbuild/openbsd-x64@0.27.1':
- resolution: {integrity: sha512-Q73ENzIdPF5jap4wqLtsfh8YbYSZ8Q0wnxplOlZUOyZy7B4ZKW8DXGWgTCZmF8VWD7Tciwv5F4NsRf6vYlZtqg==}
+ '@esbuild/openbsd-x64@0.27.2':
+ resolution: {integrity: sha512-/it7w9Nb7+0KFIzjalNJVR5bOzA9Vay+yIPLVHfIQYG/j+j9VTH84aNB8ExGKPU4AzfaEvN9/V4HV+F+vo8OEg==}
engines: {node: '>=18'}
cpu: [x64]
os: [openbsd]
- '@esbuild/openbsd-x64@0.27.2':
- resolution: {integrity: sha512-/it7w9Nb7+0KFIzjalNJVR5bOzA9Vay+yIPLVHfIQYG/j+j9VTH84aNB8ExGKPU4AzfaEvN9/V4HV+F+vo8OEg==}
+ '@esbuild/openbsd-x64@0.27.3':
+ resolution: {integrity: sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==}
engines: {node: '>=18'}
cpu: [x64]
os: [openbsd]
@@ -2144,14 +2249,14 @@ packages:
cpu: [arm64]
os: [openharmony]
- '@esbuild/openharmony-arm64@0.27.1':
- resolution: {integrity: sha512-ajbHrGM/XiK+sXM0JzEbJAen+0E+JMQZ2l4RR4VFwvV9JEERx+oxtgkpoKv1SevhjavK2z2ReHk32pjzktWbGg==}
+ '@esbuild/openharmony-arm64@0.27.2':
+ resolution: {integrity: sha512-LRBbCmiU51IXfeXk59csuX/aSaToeG7w48nMwA6049Y4J4+VbWALAuXcs+qcD04rHDuSCSRKdmY63sruDS5qag==}
engines: {node: '>=18'}
cpu: [arm64]
os: [openharmony]
- '@esbuild/openharmony-arm64@0.27.2':
- resolution: {integrity: sha512-LRBbCmiU51IXfeXk59csuX/aSaToeG7w48nMwA6049Y4J4+VbWALAuXcs+qcD04rHDuSCSRKdmY63sruDS5qag==}
+ '@esbuild/openharmony-arm64@0.27.3':
+ resolution: {integrity: sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==}
engines: {node: '>=18'}
cpu: [arm64]
os: [openharmony]
@@ -2168,14 +2273,14 @@ packages:
cpu: [x64]
os: [sunos]
- '@esbuild/sunos-x64@0.27.1':
- resolution: {integrity: sha512-IPUW+y4VIjuDVn+OMzHc5FV4GubIwPnsz6ubkvN8cuhEqH81NovB53IUlrlBkPMEPxvNnf79MGBoz8rZ2iW8HA==}
+ '@esbuild/sunos-x64@0.27.2':
+ resolution: {integrity: sha512-kMtx1yqJHTmqaqHPAzKCAkDaKsffmXkPHThSfRwZGyuqyIeBvf08KSsYXl+abf5HDAPMJIPnbBfXvP2ZC2TfHg==}
engines: {node: '>=18'}
cpu: [x64]
os: [sunos]
- '@esbuild/sunos-x64@0.27.2':
- resolution: {integrity: sha512-kMtx1yqJHTmqaqHPAzKCAkDaKsffmXkPHThSfRwZGyuqyIeBvf08KSsYXl+abf5HDAPMJIPnbBfXvP2ZC2TfHg==}
+ '@esbuild/sunos-x64@0.27.3':
+ resolution: {integrity: sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==}
engines: {node: '>=18'}
cpu: [x64]
os: [sunos]
@@ -2192,14 +2297,14 @@ packages:
cpu: [arm64]
os: [win32]
- '@esbuild/win32-arm64@0.27.1':
- resolution: {integrity: sha512-RIVRWiljWA6CdVu8zkWcRmGP7iRRIIwvhDKem8UMBjPql2TXM5PkDVvvrzMtj1V+WFPB4K7zkIGM7VzRtFkjdg==}
+ '@esbuild/win32-arm64@0.27.2':
+ resolution: {integrity: sha512-Yaf78O/B3Kkh+nKABUF++bvJv5Ijoy9AN1ww904rOXZFLWVc5OLOfL56W+C8F9xn5JQZa3UX6m+IktJnIb1Jjg==}
engines: {node: '>=18'}
cpu: [arm64]
os: [win32]
- '@esbuild/win32-arm64@0.27.2':
- resolution: {integrity: sha512-Yaf78O/B3Kkh+nKABUF++bvJv5Ijoy9AN1ww904rOXZFLWVc5OLOfL56W+C8F9xn5JQZa3UX6m+IktJnIb1Jjg==}
+ '@esbuild/win32-arm64@0.27.3':
+ resolution: {integrity: sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==}
engines: {node: '>=18'}
cpu: [arm64]
os: [win32]
@@ -2216,14 +2321,14 @@ packages:
cpu: [ia32]
os: [win32]
- '@esbuild/win32-ia32@0.27.1':
- resolution: {integrity: sha512-2BR5M8CPbptC1AK5JbJT1fWrHLvejwZidKx3UMSF0ecHMa+smhi16drIrCEggkgviBwLYd5nwrFLSl5Kho96RQ==}
+ '@esbuild/win32-ia32@0.27.2':
+ resolution: {integrity: sha512-Iuws0kxo4yusk7sw70Xa2E2imZU5HoixzxfGCdxwBdhiDgt9vX9VUCBhqcwY7/uh//78A1hMkkROMJq9l27oLQ==}
engines: {node: '>=18'}
cpu: [ia32]
os: [win32]
- '@esbuild/win32-ia32@0.27.2':
- resolution: {integrity: sha512-Iuws0kxo4yusk7sw70Xa2E2imZU5HoixzxfGCdxwBdhiDgt9vX9VUCBhqcwY7/uh//78A1hMkkROMJq9l27oLQ==}
+ '@esbuild/win32-ia32@0.27.3':
+ resolution: {integrity: sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==}
engines: {node: '>=18'}
cpu: [ia32]
os: [win32]
@@ -2240,14 +2345,14 @@ packages:
cpu: [x64]
os: [win32]
- '@esbuild/win32-x64@0.27.1':
- resolution: {integrity: sha512-d5X6RMYv6taIymSk8JBP+nxv8DQAMY6A51GPgusqLdK9wBz5wWIXy1KjTck6HnjE9hqJzJRdk+1p/t5soSbCtw==}
+ '@esbuild/win32-x64@0.27.2':
+ resolution: {integrity: sha512-sRdU18mcKf7F+YgheI/zGf5alZatMUTKj/jNS6l744f9u3WFu4v7twcUI9vu4mknF4Y9aDlblIie0IM+5xxaqQ==}
engines: {node: '>=18'}
cpu: [x64]
os: [win32]
- '@esbuild/win32-x64@0.27.2':
- resolution: {integrity: sha512-sRdU18mcKf7F+YgheI/zGf5alZatMUTKj/jNS6l744f9u3WFu4v7twcUI9vu4mknF4Y9aDlblIie0IM+5xxaqQ==}
+ '@esbuild/win32-x64@0.27.3':
+ resolution: {integrity: sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==}
engines: {node: '>=18'}
cpu: [x64]
os: [win32]
@@ -2304,6 +2409,10 @@ packages:
resolution: {integrity: sha512-C3mrr3b5dRVlKPJdfrAXS8+dq+rq8Qm5SNRazca0JKgw1HQERFmrVb0towvMmw5uu8hHKNiQasMaR/tydf3Zsg==}
engines: {node: ^20.19.0 || ^22.13.0 || ^23.5.0 || >=24.0.0, npm: '>=10'}
+ '@fal-ai/client@1.9.1':
+ resolution: {integrity: sha512-Z6+n9/2sKlDam1wWDfRWmMkLS09e2WhTU9w+2eWL7PuoGmHK43IhwKirk4b3kPC/QPp1g+ymfvhrSiS1SpDr6g==}
+ engines: {node: '>=18.0.0'}
+
'@gerrit0/mini-shiki@3.19.0':
resolution: {integrity: sha512-ZSlWfLvr8Nl0T4iA3FF/8VH8HivYF82xQts2DY0tJxZd4wtXJ8AA0nmdW9lmO4hlrh3f9xNwEPtOgqETPqKwDA==}
@@ -2344,6 +2453,9 @@ packages:
'@ioredis/commands@1.4.0':
resolution: {integrity: sha512-aFT2yemJJo+TZCmieA7qnYGQooOS7QfNmYrzGtsYd3g9j5iDP8AimYYAesf79ohjbLG12XxC4nG5DyEnC88AsQ==}
+ '@ioredis/commands@1.5.0':
+ resolution: {integrity: sha512-eUgLqrMf8nJkZxT24JvVRrQya1vZkQh8BBeYNwGDqa5I0VUi8ACx7uFvAaLxintokpTenkK6DASvo/bvNbBGow==}
+
'@isaacs/balanced-match@4.0.1':
resolution: {integrity: sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==}
engines: {node: 20 || >=22}
@@ -2394,8 +2506,8 @@ packages:
'@livekit/mutex@1.1.1':
resolution: {integrity: sha512-EsshAucklmpuUAfkABPxJNhzj9v2sG7JuzFDL4ML1oJQSV14sqrpTYnsaOudMAw9yOaW53NU3QQTlUQoRs4czw==}
- '@livekit/protocol@1.42.2':
- resolution: {integrity: sha512-0jeCwoMJKcwsZICg5S6RZM4xhJoF78qMvQELjACJQn6/VB+jmiySQKOSELTXvPBVafHfEbMlqxUw2UR1jTXs2g==}
+ '@livekit/protocol@1.44.0':
+ resolution: {integrity: sha512-/vfhDUGcUKO8Q43r6i+5FrDhl5oZjm/X3U4x2Iciqvgn5C8qbj+57YPcWSJ1kyIZm5Cm6AV2nAPjMm3ETD/iyg==}
'@manypkg/find-root@1.1.0':
resolution: {integrity: sha512-mki5uBvhHzO8kYYix/WRy2WX8S3B5wdVSc9D6KcU5lQNglP2yt58/VfLuAK49glRXChosY8ap2oJ1qgma3GUVA==}
@@ -2421,6 +2533,10 @@ packages:
'@microsoft/tsdoc@0.15.1':
resolution: {integrity: sha512-4aErSrCR/On/e5G2hDP0wjooqDdauzEbIq8hIkIe5pXV0rtWJZvdCEKL0ykZxex+IxIwBp0eGeV48hQN07dXtw==}
+ '@msgpack/msgpack@3.1.3':
+ resolution: {integrity: sha512-47XIizs9XZXvuJgoaJUIE2lFoID8ugvc0jzSHP+Ptfk8nTbnR8g788wv48N03Kx0UkAv559HWRQ3yzOgzlRNUA==}
+ engines: {node: '>= 18'}
+
'@napi-rs/wasm-runtime@0.2.12':
resolution: {integrity: sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==}
@@ -2430,6 +2546,9 @@ packages:
'@napi-rs/wasm-runtime@1.1.0':
resolution: {integrity: sha512-Fq6DJW+Bb5jaWE69/qOE0D1TUN9+6uWhCeZpdnSBk14pjLcCWR7Q8n49PTSPHazM37JqrsdpEthXy2xn6jWWiA==}
+ '@napi-rs/wasm-runtime@1.1.1':
+ resolution: {integrity: sha512-p64ah1M1ld8xjWv3qbvFwHiFVWrq1yFvV4f7w+mzaqiR4IlSgkqhcRdHwsGgomwzBH51sRY4NEowLxnaBjcW/A==}
+
'@nodelib/fs.scandir@2.1.5':
resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
engines: {node: '>= 8'}
@@ -2533,6 +2652,125 @@ packages:
'@openrouter/sdk@0.3.15':
resolution: {integrity: sha512-tmiMQGu6L1fHD9NpIABN9LALEZitqM27CFebSVyJTQDcxCcR3m1F6v1O1MnOlLmedCFU+/BojniRGFAXo1F3Bw==}
+ '@oxc-minify/binding-android-arm-eabi@0.110.0':
+ resolution: {integrity: sha512-43fMTO8/5bMlqfOiNSZNKUzIqeLIYuB9Hr1Ohyf58B1wU11S2dPGibTXOGNaWsfgHy99eeZ1bSgeIHy/fEYqbw==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [arm]
+ os: [android]
+
+ '@oxc-minify/binding-android-arm64@0.110.0':
+ resolution: {integrity: sha512-5oQrnn9eK/ccOp80PTrNj0Vq893NPNNRryjGpOIVsYNgWFuoGCfpnKg68oEFcN8bArizYAqw4nvgHljEnar69w==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [arm64]
+ os: [android]
+
+ '@oxc-minify/binding-darwin-arm64@0.110.0':
+ resolution: {integrity: sha512-dqBDgTG9tF2z2lrZp9E8wU+Godz1i8gCGSei2eFKS2hRploBOD5dmOLp1j4IMornkPvSQmbwB3uSjPq7fjx4EA==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [arm64]
+ os: [darwin]
+
+ '@oxc-minify/binding-darwin-x64@0.110.0':
+ resolution: {integrity: sha512-U0AqabqaooDOpYmeeOye8wClv8PSScELXgOfYqyqgrwH9J9KrpCE1jL8Rlqgz68QbL4mPw3V6sKiiHssI4CLeQ==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [x64]
+ os: [darwin]
+
+ '@oxc-minify/binding-freebsd-x64@0.110.0':
+ resolution: {integrity: sha512-H0w8o/Wo1072WSdLfhwwrpFpwZnPpjQODlHuRYkTfsSSSJbTxQtjJd4uxk7YJsRv5RQp69y0I7zvdH6f8Xueyw==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [x64]
+ os: [freebsd]
+
+ '@oxc-minify/binding-linux-arm-gnueabihf@0.110.0':
+ resolution: {integrity: sha512-qd6sW0AvEVYZhbVVMGtmKZw3b1zDYGIW+54Uh42moWRAj6i4Jhk/LGr6r9YNZpOINeuvZfkFuEeDD/jbu7xPUA==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [arm]
+ os: [linux]
+
+ '@oxc-minify/binding-linux-arm-musleabihf@0.110.0':
+ resolution: {integrity: sha512-7WXP0aXMrWSn0ScppUBi3jf68ebfBG0eri8kxLmBOVSBj6jw1repzkHMITJMBeLr5d0tT/51qFEptiAk2EP2iA==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [arm]
+ os: [linux]
+
+ '@oxc-minify/binding-linux-arm64-gnu@0.110.0':
+ resolution: {integrity: sha512-LYfADrq5x1W5gs+u9OIbMbDQNYkAECTXX0ufnAuf3oGmO51rF98kGFR5qJqC/6/csokDyT3wwTpxhE0TkcF/Og==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [arm64]
+ os: [linux]
+
+ '@oxc-minify/binding-linux-arm64-musl@0.110.0':
+ resolution: {integrity: sha512-53GjCVY8kvymk9P6qNDh6zyblcehF5QHstq9QgCjv13ONGRnSHjeds0PxIwiihD7h295bxsWs84DN39syLPH4Q==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [arm64]
+ os: [linux]
+
+ '@oxc-minify/binding-linux-ppc64-gnu@0.110.0':
+ resolution: {integrity: sha512-li8XcN81dxbJDMBESnTgGhoiAQ+CNIdM0QGscZ4duVPjCry1RpX+5FJySFbGqG3pk4s9ZzlL/vtQtbRzZIZOzg==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [ppc64]
+ os: [linux]
+
+ '@oxc-minify/binding-linux-riscv64-gnu@0.110.0':
+ resolution: {integrity: sha512-SweKfsnLKShu6UFV8mwuj1d1wmlNoL/FlAxPUzwjEBgwiT2HQkY24KnjBH+TIA+//1O83kzmWKvvs4OuEhdIEQ==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [riscv64]
+ os: [linux]
+
+ '@oxc-minify/binding-linux-riscv64-musl@0.110.0':
+ resolution: {integrity: sha512-oH8G4aFMP8XyTsEpdANC5PQyHgSeGlopHZuW1rpyYcaErg5YaK0vXjQ4EM5HVvPm+feBV24JjxgakTnZoF3aOQ==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [riscv64]
+ os: [linux]
+
+ '@oxc-minify/binding-linux-s390x-gnu@0.110.0':
+ resolution: {integrity: sha512-W9na+Vza7XVUlpf8wMt4QBfH35KeTENEmnpPUq3NSlbQHz8lSlSvhAafvo43NcKvHAXV3ckD/mUf2VkqSdbklg==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [s390x]
+ os: [linux]
+
+ '@oxc-minify/binding-linux-x64-gnu@0.110.0':
+ resolution: {integrity: sha512-XJdA4mmmXOjJxSRgNJXsDP7Xe8h3gQhmb56hUcCrvq5d+h5UcEi2pR8rxsdIrS8QmkLuBA3eHkGK8E27D7DTgQ==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [x64]
+ os: [linux]
+
+ '@oxc-minify/binding-linux-x64-musl@0.110.0':
+ resolution: {integrity: sha512-QqzvALuOTtSckI8x467R4GNArzYDb/yEh6aNzLoeaY1O7vfT7SPDwlOEcchaTznutpeS9Dy8gUS/AfqtUHaufw==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [x64]
+ os: [linux]
+
+ '@oxc-minify/binding-openharmony-arm64@0.110.0':
+ resolution: {integrity: sha512-gAMssLs2Q3+uhLZxanh1DF+27Kaug3cf4PXb9AB7XK81DR+LVcKySXaoGYoOs20Co0fFSphd6rRzKge2qDK3dA==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [arm64]
+ os: [openharmony]
+
+ '@oxc-minify/binding-wasm32-wasi@0.110.0':
+ resolution: {integrity: sha512-7Wqi5Zjl022bs2zXq+ICdalDPeDuCH/Nhbi8q2isLihAonMVIT0YH2hqqnNEylRNGYck+FJ6gRZwMpGCgrNxPg==}
+ engines: {node: '>=14.0.0'}
+ cpu: [wasm32]
+
+ '@oxc-minify/binding-win32-arm64-msvc@0.110.0':
+ resolution: {integrity: sha512-ZPx+0Tj4dqn41ecyoGotlvekQKy6JxJCixn9Rw7h/dafZ3eDuBcEVh3c2ZoldXXsyMIt5ywI8IWzFZsjNedd5Q==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [arm64]
+ os: [win32]
+
+ '@oxc-minify/binding-win32-ia32-msvc@0.110.0':
+ resolution: {integrity: sha512-H0Oyd3RWBfpEyvJIrFK94RYiY7KKSQl11Ym7LMDwLEagelIAfRCkt1amHZhFa/S3ZRoaOJFXzEw4YKeSsjVFsg==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [ia32]
+ os: [win32]
+
+ '@oxc-minify/binding-win32-x64-msvc@0.110.0':
+ resolution: {integrity: sha512-Hr3nK90+qXKJ2kepXwFIcNfQQIOBecB4FFCyaMMypthoEEhVP08heRynj4eSXZ8NL9hLjs3fQzH8PJXfpznRnQ==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [x64]
+ os: [win32]
+
'@oxc-project/types@0.101.0':
resolution: {integrity: sha512-nuFhqlUzJX+gVIPPfuE6xurd4lST3mdcWOhyK/rZO0B9XWMKm79SuszIQEnSMmmDhq1DC8WWVYGVd+6F93o1gQ==}
@@ -2636,6 +2874,125 @@ packages:
cpu: [x64]
os: [win32]
+ '@oxc-transform/binding-android-arm-eabi@0.110.0':
+ resolution: {integrity: sha512-sE9dxvqqAax1YYJ3t7j+h5ZSI9jl6dYuDfngl6ieZUrIy5P89/8JKVgAzgp8o3wQSo7ndpJvYsi1K4ZqrmbP7w==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [arm]
+ os: [android]
+
+ '@oxc-transform/binding-android-arm64@0.110.0':
+ resolution: {integrity: sha512-nqtbP4aMCtsCZ6qpHlHaQoWVHSBtlKzwaAgwEOvR+9DWqHjk31BHvpGiDXlMeed6CVNpl3lCbWgygb3RcSjcfw==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [arm64]
+ os: [android]
+
+ '@oxc-transform/binding-darwin-arm64@0.110.0':
+ resolution: {integrity: sha512-oeSeHnL4Z4cMXtc8V0/rwoVn0dgwlS9q0j6LcHn9dIhtFEdp3W0iSBF8YmMQA+E7sILeLDjsHmHE4Kp0sOScXw==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [arm64]
+ os: [darwin]
+
+ '@oxc-transform/binding-darwin-x64@0.110.0':
+ resolution: {integrity: sha512-nL9K5x7OuZydobAGPylsEW9d4APs2qEkIBLMgQPA+kY8dtVD3IR87QsTbs4l4DBQYyun/+ay6qVCDlxqxdX2Jg==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [x64]
+ os: [darwin]
+
+ '@oxc-transform/binding-freebsd-x64@0.110.0':
+ resolution: {integrity: sha512-GS29zXXirDQhZEUq8xKJ1azAWMuUy3Ih3W5Bc5ddk12LRthO5wRLFcKIyeHpAXCoXymQ+LmxbMtbPf84GPxouw==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [x64]
+ os: [freebsd]
+
+ '@oxc-transform/binding-linux-arm-gnueabihf@0.110.0':
+ resolution: {integrity: sha512-glzDHak8ISyZJemCUi7RCvzNSl+MQ1ly9RceT2qRufhUsvNZ4C/2QLJ1HJwd2N6E88bO4laYn+RofdRzNnGGEA==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [arm]
+ os: [linux]
+
+ '@oxc-transform/binding-linux-arm-musleabihf@0.110.0':
+ resolution: {integrity: sha512-8JThvgJ2FRoTVfbp7e4wqeZqCZbtudM06SfZmNzND9kPNu/LVYygIR+72RWs+xm4bWkuYHg/islo/boNPtMT5Q==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [arm]
+ os: [linux]
+
+ '@oxc-transform/binding-linux-arm64-gnu@0.110.0':
+ resolution: {integrity: sha512-IRh21Ub/g4bkHoErZ0AUWMlWfoZaS0A6EaOVtbcY70RSYIMlrsbjiFwJCzM+b/1DD1rXbH5tsGcH7GweTbfRqg==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [arm64]
+ os: [linux]
+
+ '@oxc-transform/binding-linux-arm64-musl@0.110.0':
+ resolution: {integrity: sha512-e5JN94/oy+wevk76q+LMr+2klTTcO60uXa+Wkq558Ms7mdF2TvkKFI++d/JeiuIwJLTi/BxQ4qdT5FWcsHM/ug==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [arm64]
+ os: [linux]
+
+ '@oxc-transform/binding-linux-ppc64-gnu@0.110.0':
+ resolution: {integrity: sha512-Y3/Tnnz1GvDpmv8FXBIKtdZPsdZklOEPdrL6NHrN5i2u54BOkybFaDSptgWF53wOrJlTrcmAVSE6fRKK9XCM2Q==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [ppc64]
+ os: [linux]
+
+ '@oxc-transform/binding-linux-riscv64-gnu@0.110.0':
+ resolution: {integrity: sha512-Y0E35iA9/v9jlkNcP6tMJ+ZFOS0rLsWDqG6rU9z+X2R3fBFJBO9UARIK6ngx8upxk81y1TFR2CmBFhupfYdH6Q==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [riscv64]
+ os: [linux]
+
+ '@oxc-transform/binding-linux-riscv64-musl@0.110.0':
+ resolution: {integrity: sha512-JOUSYFfHjBUs7xp2FHmZHb8eTYD/oEu0NklS6JgUauqnoXZHiTLPLVW2o2uVCqldnabYHcomuwI2iqVFYJNhTw==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [riscv64]
+ os: [linux]
+
+ '@oxc-transform/binding-linux-s390x-gnu@0.110.0':
+ resolution: {integrity: sha512-7blgoXF9D3Ngzb7eun23pNrHJpoV/TtE6LObwlZ3Nmb4oZ6Z+yMvBVaoW68NarbmvNGfZ95zrOjgm6cVETLYBA==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [s390x]
+ os: [linux]
+
+ '@oxc-transform/binding-linux-x64-gnu@0.110.0':
+ resolution: {integrity: sha512-YQ2joGWCVDZVEU2cD/r/w49hVjDm/Qu1BvC/7zs8LvprzdLS/HyMXGF2oA0puw0b+AqgYaz3bhwKB2xexHyITQ==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [x64]
+ os: [linux]
+
+ '@oxc-transform/binding-linux-x64-musl@0.110.0':
+ resolution: {integrity: sha512-fkjr5qE632ULmNgvFXWDR/8668WxERz3tU7TQFp6JebPBneColitjSkdx6VKNVXEoMmQnOvBIGeP5tUNT384oA==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [x64]
+ os: [linux]
+
+ '@oxc-transform/binding-openharmony-arm64@0.110.0':
+ resolution: {integrity: sha512-HWH9Zj+lMrdSTqFRCZsvDWMz7OnMjbdGsm3xURXWfRZpuaz0bVvyuZNDQXc4FyyhRDsemICaJbU1bgeIpUJDGw==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [arm64]
+ os: [openharmony]
+
+ '@oxc-transform/binding-wasm32-wasi@0.110.0':
+ resolution: {integrity: sha512-ejdxHmYfIcHDPhZUe3WklViLt9mDEJE5BzcW7+R1vc5i/5JFA8D0l7NUSsHBJ7FB8Bu9gF+5iMDm6cXGAgaghw==}
+ engines: {node: '>=14.0.0'}
+ cpu: [wasm32]
+
+ '@oxc-transform/binding-win32-arm64-msvc@0.110.0':
+ resolution: {integrity: sha512-9VTwpXCZs7xkV+mKhQ62dVk7KLnLXtEUxNS2T4nLz3iMl1IJbA4h5oltK0JoobtiUAnbkV53QmMVGW8+Nh3bDQ==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [arm64]
+ os: [win32]
+
+ '@oxc-transform/binding-win32-ia32-msvc@0.110.0':
+ resolution: {integrity: sha512-5y0fzuNON7/F2hh2P94vANFaRPJ/3DI1hVl5rseCT8VUVqOGIjWaza0YS/D1g6t1WwycW2LWDMi2raOKoWU5GQ==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [ia32]
+ os: [win32]
+
+ '@oxc-transform/binding-win32-x64-msvc@0.110.0':
+ resolution: {integrity: sha512-QROrowwlrApI1fEScMknGWKM6GTM/Z2xwMnDqvSaEmzNazBsDUlE08Jasw610hFEsYAVU2K5sp/YaCa9ORdP4A==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [x64]
+ os: [win32]
+
'@parcel/watcher-android-arm64@2.5.1':
resolution: {integrity: sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA==}
engines: {node: '>= 10.0.0'}
@@ -2853,6 +3210,15 @@ packages:
rollup:
optional: true
+ '@rollup/plugin-alias@6.0.0':
+ resolution: {integrity: sha512-tPCzJOtS7uuVZd+xPhoy5W4vThe6KWXNmsFCNktaAh5RTqcLiSfT4huPQIXkgJ6YCOjJHvecOAzQxLFhPxKr+g==}
+ engines: {node: '>=20.19.0'}
+ peerDependencies:
+ rollup: '>=4.0.0'
+ peerDependenciesMeta:
+ rollup:
+ optional: true
+
'@rollup/plugin-commonjs@28.0.9':
resolution: {integrity: sha512-PIR4/OHZ79romx0BVVll/PkwWpJ7e5lsqFa3gFfcrFPWwLXLV39JVUzQV9RKjWerE7B845Hqjj9VYlQeieZ2dA==}
engines: {node: '>=16.0.0 || 14 >= 14.17'}
@@ -2862,6 +3228,15 @@ packages:
rollup:
optional: true
+ '@rollup/plugin-commonjs@29.0.0':
+ resolution: {integrity: sha512-U2YHaxR2cU/yAiwKJtJRhnyLk7cifnQw0zUpISsocBDoHDJn+HTV74ABqnwr5bEgWUwFZC9oFL6wLe21lHu5eQ==}
+ engines: {node: '>=16.0.0 || 14 >= 14.17'}
+ peerDependencies:
+ rollup: ^2.68.0||^3.0.0||^4.0.0
+ peerDependenciesMeta:
+ rollup:
+ optional: true
+
'@rollup/plugin-inject@5.0.5':
resolution: {integrity: sha512-2+DEJbNBoPROPkgTDNe8/1YXWcqxbN5DTjASVIOx8HS+pITXushyNiBV56RB08zuptzz8gT3YfkqriTBVycepg==}
engines: {node: '>=14.0.0'}
@@ -2921,8 +3296,8 @@ packages:
cpu: [arm]
os: [android]
- '@rollup/rollup-android-arm-eabi@4.55.1':
- resolution: {integrity: sha512-9R0DM/ykwfGIlNu6+2U09ga0WXeZ9MRC2Ter8jnz8415VbuIykVuc6bhdrbORFZANDmTDvq26mJrEVTl8TdnDg==}
+ '@rollup/rollup-android-arm-eabi@4.57.1':
+ resolution: {integrity: sha512-A6ehUVSiSaaliTxai040ZpZ2zTevHYbvu/lDoeAteHI8QnaosIzm4qwtezfRg1jOYaUmnzLX1AOD6Z+UJjtifg==}
cpu: [arm]
os: [android]
@@ -2931,8 +3306,8 @@ packages:
cpu: [arm64]
os: [android]
- '@rollup/rollup-android-arm64@4.55.1':
- resolution: {integrity: sha512-eFZCb1YUqhTysgW3sj/55du5cG57S7UTNtdMjCW7LwVcj3dTTcowCsC8p7uBdzKsZYa8J7IDE8lhMI+HX1vQvg==}
+ '@rollup/rollup-android-arm64@4.57.1':
+ resolution: {integrity: sha512-dQaAddCY9YgkFHZcFNS/606Exo8vcLHwArFZ7vxXq4rigo2bb494/xKMMwRRQW6ug7Js6yXmBZhSBRuBvCCQ3w==}
cpu: [arm64]
os: [android]
@@ -2941,8 +3316,8 @@ packages:
cpu: [arm64]
os: [darwin]
- '@rollup/rollup-darwin-arm64@4.55.1':
- resolution: {integrity: sha512-p3grE2PHcQm2e8PSGZdzIhCKbMCw/xi9XvMPErPhwO17vxtvCN5FEA2mSLgmKlCjHGMQTP6phuQTYWUnKewwGg==}
+ '@rollup/rollup-darwin-arm64@4.57.1':
+ resolution: {integrity: sha512-crNPrwJOrRxagUYeMn/DZwqN88SDmwaJ8Cvi/TN1HnWBU7GwknckyosC2gd0IqYRsHDEnXf328o9/HC6OkPgOg==}
cpu: [arm64]
os: [darwin]
@@ -2951,8 +3326,8 @@ packages:
cpu: [x64]
os: [darwin]
- '@rollup/rollup-darwin-x64@4.55.1':
- resolution: {integrity: sha512-rDUjG25C9qoTm+e02Esi+aqTKSBYwVTaoS1wxcN47/Luqef57Vgp96xNANwt5npq9GDxsH7kXxNkJVEsWEOEaQ==}
+ '@rollup/rollup-darwin-x64@4.57.1':
+ resolution: {integrity: sha512-Ji8g8ChVbKrhFtig5QBV7iMaJrGtpHelkB3lsaKzadFBe58gmjfGXAOfI5FV0lYMH8wiqsxKQ1C9B0YTRXVy4w==}
cpu: [x64]
os: [darwin]
@@ -2961,8 +3336,8 @@ packages:
cpu: [arm64]
os: [freebsd]
- '@rollup/rollup-freebsd-arm64@4.55.1':
- resolution: {integrity: sha512-+JiU7Jbp5cdxekIgdte0jfcu5oqw4GCKr6i3PJTlXTCU5H5Fvtkpbs4XJHRmWNXF+hKmn4v7ogI5OQPaupJgOg==}
+ '@rollup/rollup-freebsd-arm64@4.57.1':
+ resolution: {integrity: sha512-R+/WwhsjmwodAcz65guCGFRkMb4gKWTcIeLy60JJQbXrJ97BOXHxnkPFrP+YwFlaS0m+uWJTstrUA9o+UchFug==}
cpu: [arm64]
os: [freebsd]
@@ -2971,8 +3346,8 @@ packages:
cpu: [x64]
os: [freebsd]
- '@rollup/rollup-freebsd-x64@4.55.1':
- resolution: {integrity: sha512-V5xC1tOVWtLLmr3YUk2f6EJK4qksksOYiz/TCsFHu/R+woubcLWdC9nZQmwjOAbmExBIVKsm1/wKmEy4z4u4Bw==}
+ '@rollup/rollup-freebsd-x64@4.57.1':
+ resolution: {integrity: sha512-IEQTCHeiTOnAUC3IDQdzRAGj3jOAYNr9kBguI7MQAAZK3caezRrg0GxAb6Hchg4lxdZEI5Oq3iov/w/hnFWY9Q==}
cpu: [x64]
os: [freebsd]
@@ -2981,8 +3356,8 @@ packages:
cpu: [arm]
os: [linux]
- '@rollup/rollup-linux-arm-gnueabihf@4.55.1':
- resolution: {integrity: sha512-Rn3n+FUk2J5VWx+ywrG/HGPTD9jXNbicRtTM11e/uorplArnXZYsVifnPPqNNP5BsO3roI4n8332ukpY/zN7rQ==}
+ '@rollup/rollup-linux-arm-gnueabihf@4.57.1':
+ resolution: {integrity: sha512-F8sWbhZ7tyuEfsmOxwc2giKDQzN3+kuBLPwwZGyVkLlKGdV1nvnNwYD0fKQ8+XS6hp9nY7B+ZeK01EBUE7aHaw==}
cpu: [arm]
os: [linux]
@@ -2991,8 +3366,8 @@ packages:
cpu: [arm]
os: [linux]
- '@rollup/rollup-linux-arm-musleabihf@4.55.1':
- resolution: {integrity: sha512-grPNWydeKtc1aEdrJDWk4opD7nFtQbMmV7769hiAaYyUKCT1faPRm2av8CX1YJsZ4TLAZcg9gTR1KvEzoLjXkg==}
+ '@rollup/rollup-linux-arm-musleabihf@4.57.1':
+ resolution: {integrity: sha512-rGfNUfn0GIeXtBP1wL5MnzSj98+PZe/AXaGBCRmT0ts80lU5CATYGxXukeTX39XBKsxzFpEeK+Mrp9faXOlmrw==}
cpu: [arm]
os: [linux]
@@ -3001,8 +3376,8 @@ packages:
cpu: [arm64]
os: [linux]
- '@rollup/rollup-linux-arm64-gnu@4.55.1':
- resolution: {integrity: sha512-a59mwd1k6x8tXKcUxSyISiquLwB5pX+fJW9TkWU46lCqD/GRDe9uDN31jrMmVP3feI3mhAdvcCClhV8V5MhJFQ==}
+ '@rollup/rollup-linux-arm64-gnu@4.57.1':
+ resolution: {integrity: sha512-MMtej3YHWeg/0klK2Qodf3yrNzz6CGjo2UntLvk2RSPlhzgLvYEB3frRvbEF2wRKh1Z2fDIg9KRPe1fawv7C+g==}
cpu: [arm64]
os: [linux]
@@ -3011,8 +3386,8 @@ packages:
cpu: [arm64]
os: [linux]
- '@rollup/rollup-linux-arm64-musl@4.55.1':
- resolution: {integrity: sha512-puS1MEgWX5GsHSoiAsF0TYrpomdvkaXm0CofIMG5uVkP6IBV+ZO9xhC5YEN49nsgYo1DuuMquF9+7EDBVYu4uA==}
+ '@rollup/rollup-linux-arm64-musl@4.57.1':
+ resolution: {integrity: sha512-1a/qhaaOXhqXGpMFMET9VqwZakkljWHLmZOX48R0I/YLbhdxr1m4gtG1Hq7++VhVUmf+L3sTAf9op4JlhQ5u1Q==}
cpu: [arm64]
os: [linux]
@@ -3021,13 +3396,13 @@ packages:
cpu: [loong64]
os: [linux]
- '@rollup/rollup-linux-loong64-gnu@4.55.1':
- resolution: {integrity: sha512-r3Wv40in+lTsULSb6nnoudVbARdOwb2u5fpeoOAZjFLznp6tDU8kd+GTHmJoqZ9lt6/Sys33KdIHUaQihFcu7g==}
+ '@rollup/rollup-linux-loong64-gnu@4.57.1':
+ resolution: {integrity: sha512-QWO6RQTZ/cqYtJMtxhkRkidoNGXc7ERPbZN7dVW5SdURuLeVU7lwKMpo18XdcmpWYd0qsP1bwKPf7DNSUinhvA==}
cpu: [loong64]
os: [linux]
- '@rollup/rollup-linux-loong64-musl@4.55.1':
- resolution: {integrity: sha512-MR8c0+UxAlB22Fq4R+aQSPBayvYa3+9DrwG/i1TKQXFYEaoW3B5b/rkSRIypcZDdWjWnpcvxbNaAJDcSbJU3Lw==}
+ '@rollup/rollup-linux-loong64-musl@4.57.1':
+ resolution: {integrity: sha512-xpObYIf+8gprgWaPP32xiN5RVTi/s5FCR+XMXSKmhfoJjrpRAjCuuqQXyxUa/eJTdAE6eJ+KDKaoEqjZQxh3Gw==}
cpu: [loong64]
os: [linux]
@@ -3036,13 +3411,13 @@ packages:
cpu: [ppc64]
os: [linux]
- '@rollup/rollup-linux-ppc64-gnu@4.55.1':
- resolution: {integrity: sha512-3KhoECe1BRlSYpMTeVrD4sh2Pw2xgt4jzNSZIIPLFEsnQn9gAnZagW9+VqDqAHgm1Xc77LzJOo2LdigS5qZ+gw==}
+ '@rollup/rollup-linux-ppc64-gnu@4.57.1':
+ resolution: {integrity: sha512-4BrCgrpZo4hvzMDKRqEaW1zeecScDCR+2nZ86ATLhAoJ5FQ+lbHVD3ttKe74/c7tNT9c6F2viwB3ufwp01Oh2w==}
cpu: [ppc64]
os: [linux]
- '@rollup/rollup-linux-ppc64-musl@4.55.1':
- resolution: {integrity: sha512-ziR1OuZx0vdYZZ30vueNZTg73alF59DicYrPViG0NEgDVN8/Jl87zkAPu4u6VjZST2llgEUjaiNl9JM6HH1Vdw==}
+ '@rollup/rollup-linux-ppc64-musl@4.57.1':
+ resolution: {integrity: sha512-NOlUuzesGauESAyEYFSe3QTUguL+lvrN1HtwEEsU2rOwdUDeTMJdO5dUYl/2hKf9jWydJrO9OL/XSSf65R5+Xw==}
cpu: [ppc64]
os: [linux]
@@ -3051,8 +3426,8 @@ packages:
cpu: [riscv64]
os: [linux]
- '@rollup/rollup-linux-riscv64-gnu@4.55.1':
- resolution: {integrity: sha512-uW0Y12ih2XJRERZ4jAfKamTyIHVMPQnTZcQjme2HMVDAHY4amf5u414OqNYC+x+LzRdRcnIG1YodLrrtA8xsxw==}
+ '@rollup/rollup-linux-riscv64-gnu@4.57.1':
+ resolution: {integrity: sha512-ptA88htVp0AwUUqhVghwDIKlvJMD/fmL/wrQj99PRHFRAG6Z5nbWoWG4o81Nt9FT+IuqUQi+L31ZKAFeJ5Is+A==}
cpu: [riscv64]
os: [linux]
@@ -3061,8 +3436,8 @@ packages:
cpu: [riscv64]
os: [linux]
- '@rollup/rollup-linux-riscv64-musl@4.55.1':
- resolution: {integrity: sha512-u9yZ0jUkOED1BFrqu3BwMQoixvGHGZ+JhJNkNKY/hyoEgOwlqKb62qu+7UjbPSHYjiVy8kKJHvXKv5coH4wDeg==}
+ '@rollup/rollup-linux-riscv64-musl@4.57.1':
+ resolution: {integrity: sha512-S51t7aMMTNdmAMPpBg7OOsTdn4tySRQvklmL3RpDRyknk87+Sp3xaumlatU+ppQ+5raY7sSTcC2beGgvhENfuw==}
cpu: [riscv64]
os: [linux]
@@ -3071,8 +3446,8 @@ packages:
cpu: [s390x]
os: [linux]
- '@rollup/rollup-linux-s390x-gnu@4.55.1':
- resolution: {integrity: sha512-/0PenBCmqM4ZUd0190j7J0UsQ/1nsi735iPRakO8iPciE7BQ495Y6msPzaOmvx0/pn+eJVVlZrNrSh4WSYLxNg==}
+ '@rollup/rollup-linux-s390x-gnu@4.57.1':
+ resolution: {integrity: sha512-Bl00OFnVFkL82FHbEqy3k5CUCKH6OEJL54KCyx2oqsmZnFTR8IoNqBF+mjQVcRCT5sB6yOvK8A37LNm/kPJiZg==}
cpu: [s390x]
os: [linux]
@@ -3081,8 +3456,8 @@ packages:
cpu: [x64]
os: [linux]
- '@rollup/rollup-linux-x64-gnu@4.55.1':
- resolution: {integrity: sha512-a8G4wiQxQG2BAvo+gU6XrReRRqj+pLS2NGXKm8io19goR+K8lw269eTrPkSdDTALwMmJp4th2Uh0D8J9bEV1vg==}
+ '@rollup/rollup-linux-x64-gnu@4.57.1':
+ resolution: {integrity: sha512-ABca4ceT4N+Tv/GtotnWAeXZUZuM/9AQyCyKYyKnpk4yoA7QIAuBt6Hkgpw8kActYlew2mvckXkvx0FfoInnLg==}
cpu: [x64]
os: [linux]
@@ -3091,13 +3466,13 @@ packages:
cpu: [x64]
os: [linux]
- '@rollup/rollup-linux-x64-musl@4.55.1':
- resolution: {integrity: sha512-bD+zjpFrMpP/hqkfEcnjXWHMw5BIghGisOKPj+2NaNDuVT+8Ds4mPf3XcPHuat1tz89WRL+1wbcxKY3WSbiT7w==}
+ '@rollup/rollup-linux-x64-musl@4.57.1':
+ resolution: {integrity: sha512-HFps0JeGtuOR2convgRRkHCekD7j+gdAuXM+/i6kGzQtFhlCtQkpwtNzkNj6QhCDp7DRJ7+qC/1Vg2jt5iSOFw==}
cpu: [x64]
os: [linux]
- '@rollup/rollup-openbsd-x64@4.55.1':
- resolution: {integrity: sha512-eLXw0dOiqE4QmvikfQ6yjgkg/xDM+MdU9YJuP4ySTibXU0oAvnEWXt7UDJmD4UkYialMfOGFPJnIHSe/kdzPxg==}
+ '@rollup/rollup-openbsd-x64@4.57.1':
+ resolution: {integrity: sha512-H+hXEv9gdVQuDTgnqD+SQffoWoc0Of59AStSzTEj/feWTBAnSfSD3+Dql1ZruJQxmykT/JVY0dE8Ka7z0DH1hw==}
cpu: [x64]
os: [openbsd]
@@ -3106,8 +3481,8 @@ packages:
cpu: [arm64]
os: [openharmony]
- '@rollup/rollup-openharmony-arm64@4.55.1':
- resolution: {integrity: sha512-xzm44KgEP11te3S2HCSyYf5zIzWmx3n8HDCc7EE59+lTcswEWNpvMLfd9uJvVX8LCg9QWG67Xt75AuHn4vgsXw==}
+ '@rollup/rollup-openharmony-arm64@4.57.1':
+ resolution: {integrity: sha512-4wYoDpNg6o/oPximyc/NG+mYUejZrCU2q+2w6YZqrAs2UcNUChIZXjtafAiiZSUc7On8v5NyNj34Kzj/Ltk6dQ==}
cpu: [arm64]
os: [openharmony]
@@ -3116,8 +3491,8 @@ packages:
cpu: [arm64]
os: [win32]
- '@rollup/rollup-win32-arm64-msvc@4.55.1':
- resolution: {integrity: sha512-yR6Bl3tMC/gBok5cz/Qi0xYnVbIxGx5Fcf/ca0eB6/6JwOY+SRUcJfI0OpeTpPls7f194as62thCt/2BjxYN8g==}
+ '@rollup/rollup-win32-arm64-msvc@4.57.1':
+ resolution: {integrity: sha512-O54mtsV/6LW3P8qdTcamQmuC990HDfR71lo44oZMZlXU4tzLrbvTii87Ni9opq60ds0YzuAlEr/GNwuNluZyMQ==}
cpu: [arm64]
os: [win32]
@@ -3126,8 +3501,8 @@ packages:
cpu: [ia32]
os: [win32]
- '@rollup/rollup-win32-ia32-msvc@4.55.1':
- resolution: {integrity: sha512-3fZBidchE0eY0oFZBnekYCfg+5wAB0mbpCBuofh5mZuzIU/4jIVkbESmd2dOsFNS78b53CYv3OAtwqkZZmU5nA==}
+ '@rollup/rollup-win32-ia32-msvc@4.57.1':
+ resolution: {integrity: sha512-P3dLS+IerxCT/7D2q2FYcRdWRl22dNbrbBEtxdWhXrfIMPP9lQhb5h4Du04mdl5Woq05jVCDPCMF7Ub0NAjIew==}
cpu: [ia32]
os: [win32]
@@ -3136,8 +3511,8 @@ packages:
cpu: [x64]
os: [win32]
- '@rollup/rollup-win32-x64-gnu@4.55.1':
- resolution: {integrity: sha512-xGGY5pXj69IxKb4yv/POoocPy/qmEGhimy/FoTpTSVju3FYXUQQMFCaZZXJVidsmGxRioZAwpThl/4zX41gRKg==}
+ '@rollup/rollup-win32-x64-gnu@4.57.1':
+ resolution: {integrity: sha512-VMBH2eOOaKGtIJYleXsi2B8CPVADrh+TyNxJ4mWPnKfLB/DBUmzW+5m1xUrcwWoMfSLagIRpjUFeW5CO5hyciQ==}
cpu: [x64]
os: [win32]
@@ -3146,8 +3521,8 @@ packages:
cpu: [x64]
os: [win32]
- '@rollup/rollup-win32-x64-msvc@4.55.1':
- resolution: {integrity: sha512-SPEpaL6DX4rmcXtnhdrQYgzQ5W2uW3SCJch88lB2zImhJRhIIK44fkUrgIV/Q8yUNfw5oyZ5vkeQsZLhCb06lw==}
+ '@rollup/rollup-win32-x64-msvc@4.57.1':
+ resolution: {integrity: sha512-mxRFDdHIWRxg3UfIIAwCm6NzvxG0jDX/wBN6KsQFTvKFqqg9vTrWUE68qEjHt19A5wwx5X5aUi2zuZT7YR0jrA==}
cpu: [x64]
os: [win32]
@@ -3513,8 +3888,12 @@ packages:
resolution: {integrity: sha512-LS54XNyxyTs5m/pl1lkwlg7uZM3lvsv2FIIV1rsJgnfwVCnI+n4ZGZ2CcjNT13BPu/3hPP+iHmliBSscJxW5FQ==}
engines: {node: '>=12'}
- '@tanstack/nitro-v2-vite-plugin@1.141.0':
- resolution: {integrity: sha512-OW0U7ftm4unRKhL9AZoTtdYIT3UnKfY8UQ25QNzI2uUPeVOyE9/yINFEgPGzS6gn4jQmJ3N2QvFZNvEjrbD0iA==}
+ '@tanstack/history@1.154.14':
+ resolution: {integrity: sha512-xyIfof8eHBuub1CkBnbKNKQXeRZC4dClhmzePHVOEel4G7lk/dW+TQ16da7CFdeNLv6u6Owf5VoBQxoo6DFTSA==}
+ engines: {node: '>=12'}
+
+ '@tanstack/nitro-v2-vite-plugin@1.154.7':
+ resolution: {integrity: sha512-THhjYwW+cREhmQyW/iATonY46RwYV8tbMnxBzIu77ceQOIHxkA1kVhLecb/oG5VdTduQnHVe90BD9qohX0mDHg==}
engines: {node: '>=22.12'}
peerDependencies:
vite: '>=7.0.0'
@@ -3536,20 +3915,20 @@ packages:
peerDependencies:
react: ^18 || ^19
- '@tanstack/react-router-devtools@1.141.1':
- resolution: {integrity: sha512-+XCn9cXSe1fZAD9jRrezEYE0ojn9U+Y0lRTRFdR8n51wx0UzJ6xe/Pewtw0rp03h/zmBR0pX+HRNU9NJDneWGA==}
+ '@tanstack/react-router-devtools@1.159.5':
+ resolution: {integrity: sha512-IIyomu+ypWTxyoYT32mxamVmdTs7ZCGcTbdj7HVvtD3xp1lvo/bwRXj9oERENmb+OAPOaWF2doRYC/pmKjK5vg==}
engines: {node: '>=12'}
peerDependencies:
- '@tanstack/react-router': ^1.141.1
- '@tanstack/router-core': ^1.141.1
+ '@tanstack/react-router': ^1.159.5
+ '@tanstack/router-core': ^1.159.4
react: '>=18.0.0 || >=19.0.0'
react-dom: '>=18.0.0 || >=19.0.0'
peerDependenciesMeta:
'@tanstack/router-core':
optional: true
- '@tanstack/react-router-ssr-query@1.141.1':
- resolution: {integrity: sha512-80KEKpHx9OZwXcdCOZDyftqxWMP8QHGU6LQgyIsuunPrf76Wf1riyBnZrPOAOJPcjM3PDhTHLNIfmRBnAtItUw==}
+ '@tanstack/react-router-ssr-query@1.159.5':
+ resolution: {integrity: sha512-r/Um9DASjmaTdiyXA3cpooGLrSD1BlcXUNsRz4zAlvD38m0gIFvaykOM2Naztqm9H+2CJkocRZp2/kR69Xcmyg==}
engines: {node: '>=12'}
peerDependencies:
'@tanstack/query-core': '>=5.90.0'
@@ -3565,6 +3944,13 @@ packages:
react: '>=18.0.0 || >=19.0.0'
react-dom: '>=18.0.0 || >=19.0.0'
+ '@tanstack/react-router@1.159.5':
+ resolution: {integrity: sha512-rVb0MtKzP5c0BkWIoFgWBiRAJHYSU3bhsEHbT0cRdRLmlJiw21Awb6VEjgYq3hJiEhowcKKm6J8AdRD/8oZ5dQ==}
+ engines: {node: '>=12'}
+ peerDependencies:
+ react: '>=18.0.0 || >=19.0.0'
+ react-dom: '>=18.0.0 || >=19.0.0'
+
'@tanstack/react-start-client@1.141.1':
resolution: {integrity: sha512-DkScmgoed8DbLxivWI/LbyGUsPcuOuWI0WGcNrPdFJLn2SqJjGSXhNcYZAAKlwY2TtCp7L+YnZoeOi/EDgrdSg==}
engines: {node: '>=22.12.0'}
@@ -3572,6 +3958,13 @@ packages:
react: '>=18.0.0 || >=19.0.0'
react-dom: '>=18.0.0 || >=19.0.0'
+ '@tanstack/react-start-client@1.159.5':
+ resolution: {integrity: sha512-Qynx7XWHI1rhVpSUx6P40zazcQVJRhl2fnAcSH0I6vaAxSuZm8lvI37YacXPRu8flvI/ZGlF095arxiyps+A0w==}
+ engines: {node: '>=22.12.0'}
+ peerDependencies:
+ react: '>=18.0.0 || >=19.0.0'
+ react-dom: '>=18.0.0 || >=19.0.0'
+
'@tanstack/react-start-plugin@1.131.50':
resolution: {integrity: sha512-ys+sGvnnE8BUNjGsngg+MGn3F5lV4okL5CWEKFzjBSjQsrTN7apGfmqvBP3O6PkRPHpXZ8X3Z5QsFvSc0CaDRQ==}
engines: {node: '>=12'}
@@ -3590,8 +3983,15 @@ packages:
react: '>=18.0.0 || >=19.0.0'
react-dom: '>=18.0.0 || >=19.0.0'
- '@tanstack/react-start@1.141.1':
- resolution: {integrity: sha512-03iELlg9T9ZN9rKAM1BTCCIBptLbaoZYCZXe0xGf4ZLs3Md+EhmJZibtKluclVQcnjzeiE0T17j1A/YxvVwTZg==}
+ '@tanstack/react-start-server@1.159.5':
+ resolution: {integrity: sha512-X4/SunwDTEbGkYTfM0gR+79amfk6phAM+2+NlC2s7TX2cD51xE8bUz2a//RxfOh9xg8f0f2CRIO34xTEDHGTfQ==}
+ engines: {node: '>=22.12.0'}
+ peerDependencies:
+ react: '>=18.0.0 || >=19.0.0'
+ react-dom: '>=18.0.0 || >=19.0.0'
+
+ '@tanstack/react-start@1.159.5':
+ resolution: {integrity: sha512-vfnF7eYswAK54ru6Ay08nb0TXVzTBaVRsbbRW7hx2M0chgwtSx+YScYzoixqkccRARQBN8a/CeVq7vNFW8525w==}
engines: {node: '>=22.12.0'}
peerDependencies:
react: '>=18.0.0 || >=19.0.0'
@@ -3612,13 +4012,31 @@ packages:
resolution: {integrity: sha512-fR1GGpp6v3dVKu4KIAjEh+Sd0qGLQd/wvCOVHeopSY6aFidXKCzwrS5cBOBqoPPWTKmn6CdW1a0CzFr5Furdog==}
engines: {node: '>=12'}
- '@tanstack/router-devtools-core@1.141.1':
- resolution: {integrity: sha512-wD9yRvOk6FI+thiNBplhkGutPIPBlXvWu9ttU/obdFY5oXQj9WYgNS+IO9BEe8Pz5rNEu8zE/oLn4RUGIVdtnw==}
+ '@tanstack/router-core@1.157.16':
+ resolution: {integrity: sha512-eJuVgM7KZYTTr4uPorbUzUflmljMVcaX2g6VvhITLnHmg9SBx9RAgtQ1HmT+72mzyIbRSlQ1q0fY/m+of/fosA==}
+ engines: {node: '>=12'}
+
+ '@tanstack/router-core@1.159.4':
+ resolution: {integrity: sha512-MFzPH39ijNO83qJN3pe7x4iAlhZyqgao3sJIzv3SJ4Pnk12xMnzuDzIAQT/1WV6JolPQEcw0Wr4L5agF8yxoeg==}
+ engines: {node: '>=12'}
+
+ '@tanstack/router-devtools-core@1.141.1':
+ resolution: {integrity: sha512-wD9yRvOk6FI+thiNBplhkGutPIPBlXvWu9ttU/obdFY5oXQj9WYgNS+IO9BEe8Pz5rNEu8zE/oLn4RUGIVdtnw==}
+ engines: {node: '>=12'}
+ peerDependencies:
+ '@tanstack/router-core': ^1.141.1
+ csstype: ^3.0.10
+ solid-js: '>=1.9.5'
+ peerDependenciesMeta:
+ csstype:
+ optional: true
+
+ '@tanstack/router-devtools-core@1.159.4':
+ resolution: {integrity: sha512-qMUeIv+6n1mZOcO2raCIbdOeDeMpJEmgm6oMs/nWEG61lYrzJYaCcpBTviAX0nRhSiQSUCX9cHiosUEA0e2HAw==}
engines: {node: '>=12'}
peerDependencies:
- '@tanstack/router-core': ^1.141.1
+ '@tanstack/router-core': ^1.159.4
csstype: ^3.0.10
- solid-js: '>=1.9.5'
peerDependenciesMeta:
csstype:
optional: true
@@ -3631,6 +4049,10 @@ packages:
resolution: {integrity: sha512-21RbVAoIDn7s/n/PKMN6U60d5hCeVADrBH/uN6B/poMT4MVYtJXqISVzkc2RAboVRw6eRdYFeF+YlwA3nF6y3Q==}
engines: {node: '>=12'}
+ '@tanstack/router-generator@1.159.4':
+ resolution: {integrity: sha512-O8tICQoSuvK6vs3mvBdI3zVLFmYfj/AYDCX0a5msSADP/2S0GsgDDTB5ah731TqYCtjeNriaWz9iqst38cjF/Q==}
+ engines: {node: '>=12'}
+
'@tanstack/router-plugin@1.131.50':
resolution: {integrity: sha512-gdEBPGzx7llQNRnaqfPJ1iaPS3oqB8SlvKRG5l7Fxp4q4yINgkeowFYSKEhPOc9bjoNhGrIHOlvPTPXEzAQXzQ==}
engines: {node: '>=12'}
@@ -3673,6 +4095,27 @@ packages:
webpack:
optional: true
+ '@tanstack/router-plugin@1.159.5':
+ resolution: {integrity: sha512-i2LR3WRaBOAZ1Uab5QBG9UxZIRJ3V56JVu890NysbuX15rgzRiL5yLAbfenOHdhaHy2+4joX35VICAHuVWy7Og==}
+ engines: {node: '>=12'}
+ peerDependencies:
+ '@rsbuild/core': '>=1.0.2'
+ '@tanstack/react-router': ^1.159.5
+ vite: '>=5.0.0 || >=6.0.0 || >=7.0.0'
+ vite-plugin-solid: ^2.11.10
+ webpack: '>=5.92.0'
+ peerDependenciesMeta:
+ '@rsbuild/core':
+ optional: true
+ '@tanstack/react-router':
+ optional: true
+ vite:
+ optional: true
+ vite-plugin-solid:
+ optional: true
+ webpack:
+ optional: true
+
'@tanstack/router-ssr-query-core@1.141.1':
resolution: {integrity: sha512-bkRXUhktifxBewnnphH59E0sGcsUI1NmNqxzCAmXIb93xYgafhjUGGYwfK6FqFBOmCB5isr32exGO3+UMHJr/A==}
engines: {node: '>=12'}
@@ -3680,6 +4123,13 @@ packages:
'@tanstack/query-core': '>=5.90.0'
'@tanstack/router-core': '>=1.127.0'
+ '@tanstack/router-ssr-query-core@1.159.4':
+ resolution: {integrity: sha512-zqgJaf8iTk2ugrJqvU+b8NnFf3MKcnFaurtlp5tP38lNHQGW4En9UaOBOou/6zYZMlKQBcvqxSGJiwaLIyTK2g==}
+ engines: {node: '>=12'}
+ peerDependencies:
+ '@tanstack/query-core': '>=5.90.0'
+ '@tanstack/router-core': '>=1.127.0'
+
'@tanstack/router-utils@1.131.2':
resolution: {integrity: sha512-sr3x0d2sx9YIJoVth0QnfEcAcl+39sQYaNQxThtHmRpyeFYNyM2TTH+Ud3TNEnI3bbzmLYEUD+7YqB987GzhDA==}
engines: {node: '>=12'}
@@ -3688,6 +4138,10 @@ packages:
resolution: {integrity: sha512-/eFGKCiix1SvjxwgzrmH4pHjMiMxc+GA4nIbgEkG2RdAJqyxLcRhd7RPLG0/LZaJ7d0ad3jrtRqsHLv2152Vbw==}
engines: {node: '>=12'}
+ '@tanstack/router-utils@1.158.0':
+ resolution: {integrity: sha512-qZ76eaLKU6Ae9iI/mc5zizBX149DXXZkBVVO3/QRIll79uKLJZHQlMKR++2ba7JsciBWz1pgpIBcCJPE9S0LVg==}
+ engines: {node: '>=12'}
+
'@tanstack/server-functions-plugin@1.131.2':
resolution: {integrity: sha512-hWsaSgEZAVyzHg8+IcJWCEtfI9ZSlNELErfLiGHG9XCHEXMegFWsrESsKHlASzJqef9RsuOLDl+1IMPIskwdDw==}
engines: {node: '>=12'}
@@ -3769,6 +4223,10 @@ packages:
resolution: {integrity: sha512-Rk/b0ekX7p0ZBKOg9WM5c632YPqu7GlvZSYnAjNi1GDp1/sET6g2Trp+GAjs1s8kakp2pMQ4sZUG/11grCMfJw==}
engines: {node: '>=22.12.0'}
+ '@tanstack/start-client-core@1.159.4':
+ resolution: {integrity: sha512-9j2i1PRTIGcYAD+509znve0ngK81ZUfbX4XCpoNFMaUUpRHoEPPK5I9+PzLFvL9sNOto67x+WULCUggzX+lEKQ==}
+ engines: {node: '>=22.12.0'}
+
'@tanstack/start-config@1.120.20':
resolution: {integrity: sha512-oH/mfTSHV8Qbil74tWicPLW6+kKmT3esXCnDzvrkhi3+N8ZuVUDr01Qpil0Wxf9lLPfM5L6VX03nF4hSU8vljg==}
engines: {node: '>=12'}
@@ -3777,6 +4235,10 @@ packages:
react-dom: '>=18.0.0 || >=19.0.0'
vite: ^6.0.0
+ '@tanstack/start-fn-stubs@1.154.7':
+ resolution: {integrity: sha512-D69B78L6pcFN5X5PHaydv7CScQcKLzJeEYqs7jpuyyqGQHSUIZUjS955j+Sir8cHhuDIovCe2LmsYHeZfWf3dQ==}
+ engines: {node: '>=22.12.0'}
+
'@tanstack/start-plugin-core@1.131.50':
resolution: {integrity: sha512-eFvMA0chqLtHbq+8ojp1fXN7AQjhmeoOpQaZaU1d51wb7ugetrn0k3OuHblxtE/O0L4HEC9s4X5zmFJt0vLh0w==}
engines: {node: '>=12'}
@@ -3789,6 +4251,12 @@ packages:
peerDependencies:
vite: '>=7.0.0'
+ '@tanstack/start-plugin-core@1.159.5':
+ resolution: {integrity: sha512-QGiBw+L3qu2sUY0Tg9KovxjDSi5kevoANEcq9RLX7iIhLkTjrILN6hnAlXZUzqk5Egaf0aN2yWhwI4HWucMprw==}
+ engines: {node: '>=22.12.0'}
+ peerDependencies:
+ vite: '>=7.0.0'
+
'@tanstack/start-server-core@1.131.50':
resolution: {integrity: sha512-3SWwwhW2GKMhPSaqWRal6Jj1Y9ObfdWEXKFQid1LBuk5xk/Es4bmW68o++MbVgs/GxUxyeZ3TRVqb0c7RG1sog==}
engines: {node: '>=12'}
@@ -3797,6 +4265,10 @@ packages:
resolution: {integrity: sha512-Qk/lZ/+iGUyNYeAAuj89bLR6GXLD/9BIpAR2CUwlS+xXGL0kQmOFcb1UvccWZ2QwtW+csxJW4NeQOeMuqsfyhA==}
engines: {node: '>=22.12.0'}
+ '@tanstack/start-server-core@1.159.4':
+ resolution: {integrity: sha512-sGpr+iil+pcY3Gglvbnxaj7fCEPTQJv4oF7YA24SVv8YvayLXtBXpF26miJLA+KR9P31dQdPYe1gTjv5zRyvHg==}
+ engines: {node: '>=22.12.0'}
+
'@tanstack/start-server-functions-client@1.131.50':
resolution: {integrity: sha512-4aM17fFdVAFH6uLPswKJxzrhhIjcCwKqzfTcgY3OnhUKnaZBTQwJA+nUHQCI6IWvEvrcrNVtFTtv13TkDk3YMw==}
engines: {node: '>=12'}
@@ -3825,6 +4297,10 @@ packages:
resolution: {integrity: sha512-UPOQd4qsytgmc+pHeeS3oIZQazhyGAmEaCS/IrZI42TzpuVh2ZbLVssKEoDziheNP1dH5KT2lsL1bU9asAw7tA==}
engines: {node: '>=22.12.0'}
+ '@tanstack/start-storage-context@1.159.4':
+ resolution: {integrity: sha512-iGkmuCIq3PLI4GKOGwgUNHQKZ13YV8LGq62o2hVnyXE64Jm2SP7c5z6D1ndydpk4JwdRzQKlcOFT/1agvS6Nsg==}
+ engines: {node: '>=22.12.0'}
+
'@tanstack/start@1.120.20':
resolution: {integrity: sha512-fQO+O/5xJpli5KlV6pwDz6DtpbqO/0atdVSyVnkemzk0Mej9azm4HXtw+cKkIPtsSplWs4B1EbMtgGMb9ADhSA==}
engines: {node: '>=12'}
@@ -3847,6 +4323,10 @@ packages:
resolution: {integrity: sha512-CJrWtr6L9TVzEImm9S7dQINx+xJcYP/aDkIi6gnaWtIgbZs1pnzsE0yJc2noqXZ+yAOqLx3TBGpBEs9tS0P9/A==}
engines: {node: '>=12'}
+ '@tanstack/virtual-file-routes@1.154.7':
+ resolution: {integrity: sha512-cHHDnewHozgjpI+MIVp9tcib6lYEQK5MyUr0ChHpHFGBl8Xei55rohFK0I0ve/GKoHeioaK42Smd8OixPp6CTg==}
+ engines: {node: '>=12'}
+
'@tanstack/vite-config@0.4.1':
resolution: {integrity: sha512-FOl8EF6SAcljanKSm5aBeJaflFcxQAytTbxtNW8HC6D4x+UBW68IC4tBcrlrsI0wXHBmC/Gz4Ovvv8qCtiXSgQ==}
engines: {node: '>=18'}
@@ -4143,6 +4623,11 @@ packages:
engines: {node: '>=18'}
hasBin: true
+ '@vercel/nft@1.3.0':
+ resolution: {integrity: sha512-i4EYGkCsIjzu4vorDUbqglZc5eFtQI2syHb++9ZUDm6TU4edVywGpVnYDein35x9sevONOn9/UabfQXuNXtuzQ==}
+ engines: {node: '>=20'}
+ hasBin: true
+
'@vinxi/listhen@1.5.6':
resolution: {integrity: sha512-WSN1z931BtasZJlgPp704zJFnQFRg7yzSjkm3MzAWQYe4uXFXlFr1hc5Ac2zae5/HDOz5x1/zDM5Cb54vTCnWw==}
hasBin: true
@@ -4178,8 +4663,8 @@ packages:
'@vitest/expect@4.0.15':
resolution: {integrity: sha512-Gfyva9/GxPAWXIWjyGDli9O+waHDC0Q0jaLdFP1qPAUUfo1FEXPXUfUkp3eZA0sSq340vPycSyOlYUeM15Ft1w==}
- '@vitest/expect@4.0.17':
- resolution: {integrity: sha512-mEoqP3RqhKlbmUmntNDDCJeTDavDR+fVYkSOw8qRwJFaW/0/5zA9zFeTrHqNtcmwh6j26yMmwx2PqUDPzt5ZAQ==}
+ '@vitest/expect@4.0.18':
+ resolution: {integrity: sha512-8sCWUyckXXYvx4opfzVY03EOiYVxyNrHS5QxX3DAIi5dpJAAkyJezHCP77VMX4HKA2LDT/Jpfo8i2r5BE3GnQQ==}
'@vitest/mocker@4.0.15':
resolution: {integrity: sha512-CZ28GLfOEIFkvCFngN8Sfx5h+Se0zN+h4B7yOsPVCcgtiO7t5jt9xQh2E1UkFep+eb9fjyMfuC5gBypwb07fvQ==}
@@ -4192,8 +4677,8 @@ packages:
vite:
optional: true
- '@vitest/mocker@4.0.17':
- resolution: {integrity: sha512-+ZtQhLA3lDh1tI2wxe3yMsGzbp7uuJSWBM1iTIKCbppWTSBN09PUC+L+fyNlQApQoR+Ps8twt2pbSSXg2fQVEQ==}
+ '@vitest/mocker@4.0.18':
+ resolution: {integrity: sha512-HhVd0MDnzzsgevnOWCBj5Otnzobjy5wLBe4EdeeFGv8luMsGcYqDuFRMcttKWZA5vVO8RFjexVovXvAM4JoJDQ==}
peerDependencies:
msw: ^2.4.9
vite: ^6.0.0 || ^7.0.0-0
@@ -4209,26 +4694,26 @@ packages:
'@vitest/pretty-format@4.0.15':
resolution: {integrity: sha512-SWdqR8vEv83WtZcrfLNqlqeQXlQLh2iilO1Wk1gv4eiHKjEzvgHb2OVc3mIPyhZE6F+CtfYjNlDJwP5MN6Km7A==}
- '@vitest/pretty-format@4.0.17':
- resolution: {integrity: sha512-Ah3VAYmjcEdHg6+MwFE17qyLqBHZ+ni2ScKCiW2XrlSBV4H3Z7vYfPfz7CWQ33gyu76oc0Ai36+kgLU3rfF4nw==}
+ '@vitest/pretty-format@4.0.18':
+ resolution: {integrity: sha512-P24GK3GulZWC5tz87ux0m8OADrQIUVDPIjjj65vBXYG17ZeU3qD7r+MNZ1RNv4l8CGU2vtTRqixrOi9fYk/yKw==}
'@vitest/runner@4.0.15':
resolution: {integrity: sha512-+A+yMY8dGixUhHmNdPUxOh0la6uVzun86vAbuMT3hIDxMrAOmn5ILBHm8ajrqHE0t8R9T1dGnde1A5DTnmi3qw==}
- '@vitest/runner@4.0.17':
- resolution: {integrity: sha512-JmuQyf8aMWoo/LmNFppdpkfRVHJcsgzkbCA+/Bk7VfNH7RE6Ut2qxegeyx2j3ojtJtKIbIGy3h+KxGfYfk28YQ==}
+ '@vitest/runner@4.0.18':
+ resolution: {integrity: sha512-rpk9y12PGa22Jg6g5M3UVVnTS7+zycIGk9ZNGN+m6tZHKQb7jrP7/77WfZy13Y/EUDd52NDsLRQhYKtv7XfPQw==}
'@vitest/snapshot@4.0.15':
resolution: {integrity: sha512-A7Ob8EdFZJIBjLjeO0DZF4lqR6U7Ydi5/5LIZ0xcI+23lYlsYJAfGn8PrIWTYdZQRNnSRlzhg0zyGu37mVdy5g==}
- '@vitest/snapshot@4.0.17':
- resolution: {integrity: sha512-npPelD7oyL+YQM2gbIYvlavlMVWUfNNGZPcu0aEUQXt7FXTuqhmgiYupPnAanhKvyP6Srs2pIbWo30K0RbDtRQ==}
+ '@vitest/snapshot@4.0.18':
+ resolution: {integrity: sha512-PCiV0rcl7jKQjbgYqjtakly6T1uwv/5BQ9SwBLekVg/EaYeQFPiXcgrC2Y7vDMA8dM1SUEAEV82kgSQIlXNMvA==}
'@vitest/spy@4.0.15':
resolution: {integrity: sha512-+EIjOJmnY6mIfdXtE/bnozKEvTC4Uczg19yeZ2vtCz5Yyb0QQ31QWVQ8hswJ3Ysx/K2EqaNsVanjr//2+P3FHw==}
- '@vitest/spy@4.0.17':
- resolution: {integrity: sha512-I1bQo8QaP6tZlTomQNWKJE6ym4SHf3oLS7ceNjozxxgzavRAgZDc06T7kD8gb9bXKEgcLNt00Z+kZO6KaJ62Ew==}
+ '@vitest/spy@4.0.18':
+ resolution: {integrity: sha512-cbQt3PTSD7P2OARdVW3qWER5EGq7PHlvE+QfzSC0lbwO+xnt7+XH06ZzFjFRgzUX//JmpxrCu92VdwvEPlWSNw==}
'@vitest/utils@4.0.14':
resolution: {integrity: sha512-hLqXZKAWNg8pI+SQXyXxWCTOpA3MvsqcbVeNgSi8x/CSN2wi26dSzn1wrOhmCmFjEvN9p8/kLFRHa6PI8jHazw==}
@@ -4236,8 +4721,8 @@ packages:
'@vitest/utils@4.0.15':
resolution: {integrity: sha512-HXjPW2w5dxhTD0dLwtYHDnelK3j8sR8cWIaLxr22evTyY6q8pRCjZSmhRWVjBaOVXChQd6AwMzi9pucorXCPZA==}
- '@vitest/utils@4.0.17':
- resolution: {integrity: sha512-RG6iy+IzQpa9SB8HAFHJ9Y+pTzI+h8553MrciN9eC6TFBErqrQaTas4vG+MVj8S4uKk8uTT2p0vgZPnTdxd96w==}
+ '@vitest/utils@4.0.18':
+ resolution: {integrity: sha512-msMRKLMVLWygpK3u2Hybgi4MNjcYJvwTb0Ru09+fOyCXIgT5raYP041DRRdiJiI3k/2U6SEbAETB3YtBrUkCFA==}
'@volar/language-core@2.4.15':
resolution: {integrity: sha512-3VHw+QZU0ZG9IuQmzT68IyN4hZNd9GchGPhbD9+pa8CVv7rnoOZwo7T8weIbrRmihqy3ATpdfXFnqRrfPVK6CA==}
@@ -4460,8 +4945,8 @@ packages:
resolution: {integrity: sha512-6t10qk83GOG8p0vKmaCr8eiilZwO171AvbROMtvvNiwrTly62t+7XkA8RdIIVbpMhCASAsxgAzdRSwh6nw/5Dg==}
engines: {node: '>=4'}
- ast-v8-to-istanbul@0.3.8:
- resolution: {integrity: sha512-szgSZqUxI5T8mLKvS7WTjF9is+MVbOeLADU73IseOcrqhxr/VAvy6wfoVE39KnKzA7JRhjF5eUagNlHwvZPlKQ==}
+ ast-v8-to-istanbul@0.3.11:
+ resolution: {integrity: sha512-Qya9fkoofMjCBNVdWINMjB5KZvkYfaO9/anwkWnjxibpWUxo5iHl2sOdP7/uAqaRuUYuoo8rDwnbaaKVFxoUvw==}
async-sema@3.1.1:
resolution: {integrity: sha512-tLRNUXati5MFePdAk8dw7Qt7DpxPB60ofAgn8WRhW6a2rcimZnYBP9oxHiv0OHy+Wz7kPMG+t4LGdt31+4EmGg==}
@@ -4501,6 +4986,9 @@ packages:
babel-dead-code-elimination@1.0.10:
resolution: {integrity: sha512-DV5bdJZTzZ0zn0DC24v3jD7Mnidh6xhKa4GfKCbq3sfW8kaWhDdZjP3i81geA8T33tdYqWKw4D3fVv0CwEgKVA==}
+ babel-dead-code-elimination@1.0.12:
+ resolution: {integrity: sha512-GERT7L2TiYcYDtYk1IpD+ASAYXjKbLTDPhBtYj7X1NuRMDTMtAx9kyBenub1Ev41lo91OHCKdmP+egTDmfQ7Ig==}
+
babel-plugin-jsx-dom-expressions@0.40.3:
resolution: {integrity: sha512-5HOwwt0BYiv/zxl7j8Pf2bGL6rDXfV6nUhLs8ygBX+EFJXzBPHM/euj9j/6deMZ6wa52Wb2PBaAV5U/jKwIY1w==}
peerDependencies:
@@ -4613,6 +5101,14 @@ packages:
magicast:
optional: true
+ c12@3.3.3:
+ resolution: {integrity: sha512-750hTRvgBy5kcMNPdh95Qo+XUBeGo8C7nsKSmedDmaQI+E0r82DwHeM6vBewDe4rGFbnxoa4V9pw+sPh5+Iz8Q==}
+ peerDependencies:
+ magicast: '*'
+ peerDependenciesMeta:
+ magicast:
+ optional: true
+
cac@6.7.14:
resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==}
engines: {node: '>=8'}
@@ -4857,6 +5353,14 @@ packages:
crossws@0.3.5:
resolution: {integrity: sha512-ojKiDvcmByhwa8YYqbQI/hg7MEU0NC03+pSdEq4ZUnZR9xXpwk7E43SMNGkn+JxJGPFtNvQ48+vV2p+P1ml5PA==}
+ crossws@0.4.4:
+ resolution: {integrity: sha512-w6c4OdpRNnudVmcgr7brb/+/HmYjMQvYToO/oTrprTwxRUiom3LYWU1PMWuD006okbUWpII1Ea9/+kwpUfmyRg==}
+ peerDependencies:
+ srvx: '>=0.7.1'
+ peerDependenciesMeta:
+ srvx:
+ optional: true
+
css-select@5.2.2:
resolution: {integrity: sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==}
@@ -5169,13 +5673,13 @@ packages:
engines: {node: '>=18'}
hasBin: true
- esbuild@0.27.1:
- resolution: {integrity: sha512-yY35KZckJJuVVPXpvjgxiCuVEJT67F6zDeVTv4rizyPrfGBUpZQsvmxnN+C371c2esD/hNMjj4tpBhuueLN7aA==}
+ esbuild@0.27.2:
+ resolution: {integrity: sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw==}
engines: {node: '>=18'}
hasBin: true
- esbuild@0.27.2:
- resolution: {integrity: sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw==}
+ esbuild@0.27.3:
+ resolution: {integrity: sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==}
engines: {node: '>=18'}
hasBin: true
@@ -5348,6 +5852,10 @@ packages:
resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==}
engines: {node: '>=0.8.x'}
+ eventsource-parser@1.1.2:
+ resolution: {integrity: sha512-v0eOBUbiaFojBu2s2NPBfYUoRR9GjcDNvCXVaqEf5vVfpIAh9f8RCo4vXTP8c63QRKCFwoLpMpTdPwwhEKVgzA==}
+ engines: {node: '>=14.18'}
+
execa@8.0.1:
resolution: {integrity: sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==}
engines: {node: '>=16.17'}
@@ -5568,8 +6076,13 @@ packages:
glob@10.5.0:
resolution: {integrity: sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==}
+ deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me
hasBin: true
+ glob@13.0.0:
+ resolution: {integrity: sha512-tvZgpqk6fz4BaNZ66ZsRaZnbHvP/jG3uKJvAZOwEVUL4RTA5nJeeLYfyN9/VA8NX/V3IBG+hkeuGpKjvELkVhA==}
+ engines: {node: 20 || >=22}
+
globals@14.0.0:
resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==}
engines: {node: '>=18'}
@@ -5590,6 +6103,10 @@ packages:
resolution: {integrity: sha512-oB4vkQGqlMl682wL1IlWd02tXCbquGWM4voPEI85QmNKCaw8zGTm1f1rubFgkg3Eli2PtKlFgrnmUqasbQWlkw==}
engines: {node: '>=20'}
+ globby@16.1.0:
+ resolution: {integrity: sha512-+A4Hq7m7Ze592k9gZRy4gJ27DrXRNnC1vPjxTt1qQxEY8RxagBkBxivkCwg7FxSTG0iLLEMaUx13oOr0R2/qcQ==}
+ engines: {node: '>=20'}
+
globrex@0.1.2:
resolution: {integrity: sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==}
@@ -5627,6 +6144,9 @@ packages:
h3@1.15.4:
resolution: {integrity: sha512-z5cFQWDffyOe4vQ9xIqNfCZdV4p//vy6fBnr8Q1AWnVZ0teurKMG66rLj++TKwKPUP3u7iMUvrvKaEUiQw2QWQ==}
+ h3@1.15.5:
+ resolution: {integrity: sha512-xEyq3rSl+dhGX2Lm0+eFQIAzlDN6Fs0EcC4f7BNUmzaRX/PTzeuM+Tr2lHB8FoXggsQIeXLj8EDVgs5ywxyxmg==}
+
h3@2.0.0-beta.5:
resolution: {integrity: sha512-ApIkLH+nTxzCC0Nq/GN1v6jkvu2eOLfdTnTs6ghiuG1EYHWJBDLzhk5tn7SZMEUNsLUjG4qfmqzBx2LG9I7Q/w==}
engines: {node: '>=20.11.1'}
@@ -5636,6 +6156,16 @@ packages:
crossws:
optional: true
+ h3@2.0.1-rc.14:
+ resolution: {integrity: sha512-163qbGmTr/9rqQRNuqMqtgXnOUAkE4KTdauiC9y0E5iG1I65kte9NyfWvZw5RTDMt6eY+DtyoNzrQ9wA2BfvGQ==}
+ engines: {node: '>=20.11.1'}
+ hasBin: true
+ peerDependencies:
+ crossws: ^0.4.1
+ peerDependenciesMeta:
+ crossws:
+ optional: true
+
happy-dom@20.0.11:
resolution: {integrity: sha512-QsCdAUHAmiDeKeaNojb1OHOPF7NjcWPBR7obdu3NwH2a/oyQaLg5d0aaCy/9My6CdPChYF07dvz5chaXBGaD4g==}
engines: {node: '>=20.0.0'}
@@ -5823,6 +6353,10 @@ packages:
resolution: {integrity: sha512-C6uC+kleiIMmjViJINWk80sOQw5lEzse1ZmvD+S/s8p8CWapftSaC+kocGTx6xrbrJ4WmYQGC08ffHLr6ToR6Q==}
engines: {node: '>=12.22.0'}
+ ioredis@5.9.2:
+ resolution: {integrity: sha512-tAAg/72/VxOUW7RQSX1pIxJVucYKcjFjfvj60L57jrZpYCHC3XN0WCQ3sNYL4Gmvv+7GPvTAjc+KSdeNuE8oWQ==}
+ engines: {node: '>=12.22.0'}
+
ipaddr.js@1.9.1:
resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==}
engines: {node: '>= 0.10'}
@@ -5924,6 +6458,10 @@ packages:
resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==}
engines: {node: '>=0.12.0'}
+ is-path-inside@4.0.0:
+ resolution: {integrity: sha512-lJJV/5dYS+RcL8uQdBDW9c9uWFLLBNRyFhnAKXw5tVqLlKZ4RMGZKv+YQ/IA3OhD+RpbJa1LLFM1FQPGyIXvOA==}
+ engines: {node: '>=12'}
+
is-plain-obj@4.1.0:
resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==}
engines: {node: '>=12'}
@@ -6067,6 +6605,9 @@ packages:
resolution: {integrity: sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==}
engines: {node: '>=14'}
+ js-tokens@10.0.0:
+ resolution: {integrity: sha512-lM/UBzQmfJRo9ABXbPWemivdCW8V2G8FHaHdypQaIy523snUjog0W71ayWXTjiR+ixeMyVHN2XcpnTd/liPg/Q==}
+
js-tokens@4.0.0:
resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
@@ -6258,8 +6799,8 @@ packages:
resolution: {integrity: sha512-I8oW2+QL5KJo8zXNWX046M134WchxsXC7SawLPvRQpogCbkyQIaFxPE89A2HiwR7vAK2Dm2ERBAmyjTYGYEpBg==}
hasBin: true
- livekit-client@2.17.0:
- resolution: {integrity: sha512-BD1QUS44ancVTBdnAher0aO7DV5holFYH2lYradYT/HgXtn6R8xPyvtDAH3UH40jGcesDo9fEopCFwEdOgrIhg==}
+ livekit-client@2.17.2:
+ resolution: {integrity: sha512-+67y2EtAWZabARlY7kANl/VT1Uu1EJYR5a8qwpT2ub/uBCltsEgEDOxCIMwE9HFR5w+z41HR6GL9hyEvW/y6CQ==}
peerDependencies:
'@types/dom-mediacapture-record': ^1
@@ -6350,8 +6891,8 @@ packages:
magic-string@0.30.21:
resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==}
- magicast@0.5.1:
- resolution: {integrity: sha512-xrHS24IxaLrvuo613F719wvOIv9xPHFWQHuvGUBmPnCA/3MQxKI3b+r7n1jAoDHmsbC5bRhTZYR77invLAxVnw==}
+ magicast@0.5.2:
+ resolution: {integrity: sha512-E3ZJh4J3S9KfwdjZhe2afj6R9lGIN5Pher1pF39UGrXRqq/VDaGVIGN13BjHd2u8B61hArAGOnso7nBOouW3TQ==}
make-dir@4.0.0:
resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==}
@@ -6657,6 +7198,28 @@ packages:
resolution: {integrity: sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==}
engines: {node: '>= 0.6'}
+ nf3@0.3.10:
+ resolution: {integrity: sha512-UlqmHkZiHGgSkRj17yrOXEsSu5ECvtlJ3Xm1W5WsWrTKgu9m7OjrMZh9H/ME2LcWrTlMD0/vmmNVpyBG4yRdGg==}
+
+ nitro@3.0.1-alpha.2:
+ resolution: {integrity: sha512-YviDY5J/trS821qQ1fpJtpXWIdPYiOizC/meHavlm1Hfuhx//H+Egd1+4C5SegJRgtWMnRPW9n//6Woaw81cTQ==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ hasBin: true
+ peerDependencies:
+ rolldown: '>=1.0.0-beta.0'
+ rollup: ^4
+ vite: ^7 || ^8 || >=8.0.0-0
+ xml2js: ^0.6.2
+ peerDependenciesMeta:
+ rolldown:
+ optional: true
+ rollup:
+ optional: true
+ vite:
+ optional: true
+ xml2js:
+ optional: true
+
nitropack@2.12.9:
resolution: {integrity: sha512-t6qqNBn2UDGMWogQuORjbL2UPevB8PvIPsPHmqvWpeGOlPr4P8Oc5oA8t3wFwGmaolM2M/s2SwT23nx9yARmOg==}
engines: {node: ^20.19.0 || >=22.12.0}
@@ -6667,6 +7230,16 @@ packages:
xml2js:
optional: true
+ nitropack@2.13.1:
+ resolution: {integrity: sha512-2dDj89C4wC2uzG7guF3CnyG+zwkZosPEp7FFBGHB3AJo11AywOolWhyQJFHDzve8COvGxJaqscye9wW2IrUsNw==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ hasBin: true
+ peerDependencies:
+ xml2js: ^0.6.2
+ peerDependenciesMeta:
+ xml2js:
+ optional: true
+
node-addon-api@7.1.1:
resolution: {integrity: sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==}
@@ -6776,6 +7349,9 @@ packages:
ofetch@1.5.1:
resolution: {integrity: sha512-2W4oUZlVaqAPAil6FUg/difl6YhqhUR7x2eZY4bQCko22UXg3hptq9KLQdqFClV+Wu85UX7hNtdGTngi/1BxcA==}
+ ofetch@2.0.0-alpha.3:
+ resolution: {integrity: sha512-zpYTCs2byOuft65vI3z43Dd6iSdFbOZZLb9/d21aCpx2rGastVU9dOCv0lu4ykc1Ur1anAYjDi3SUvR0vq50JA==}
+
ohash@1.1.6:
resolution: {integrity: sha512-TBu7PtV8YkAZn0tSxobKY2n2aAQva936lhRrj6957aDaCf9IEtqsKbgMzXE/F/sjqYOwmrukeORHNLe5glk7Cg==}
@@ -6827,9 +7403,17 @@ packages:
outdent@0.5.0:
resolution: {integrity: sha512-/jHxFIzoMXdqPzTaCpFzAAWhpkSjZPF4Vsn6jAfNpmbH/ymsmd7Qc6VE9BGn0L6YMj6uwpQLxCECpus4ukKS9Q==}
+ oxc-minify@0.110.0:
+ resolution: {integrity: sha512-KWGTzPo83QmGrXC4ml83PM9HDwUPtZFfasiclUvTV4i3/0j7xRRqINVkrL77CbQnoWura3CMxkRofjQKVDuhBw==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+
oxc-resolver@11.15.0:
resolution: {integrity: sha512-Hk2J8QMYwmIO9XTCUiOH00+Xk2/+aBxRUnhrSlANDyCnLYc32R1WSIq1sU2yEdlqd53FfMpPEpnBYIKQMzliJw==}
+ oxc-transform@0.110.0:
+ resolution: {integrity: sha512-/fymQNzzUoKZweH0nC5yvbI2eR0yWYusT9TEKDYVgOgYrf9Qmdez9lUFyvxKR9ycx+PTHi/reIOzqf3wkShQsw==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+
p-filter@2.1.0:
resolution: {integrity: sha512-ZBxxZ5sL2HghephhpGAQdoskxplTwr7ICaehZwLIlfL6acuVgZPm8yBNuRAFBGEqtD/hmUeq9eqLg2ys9Xr/yw==}
engines: {node: '>=8'}
@@ -6915,6 +7499,10 @@ packages:
resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==}
engines: {node: '>=16 || 14 >=14.18'}
+ path-scurry@2.0.1:
+ resolution: {integrity: sha512-oWyT4gICAu+kaA7QWk/jvCHWarMKNs6pXOGWKDTr7cw4IGcUbW+PeTfbaQiLGheFRpjo6O9J0PmyMfQPjH71oA==}
+ engines: {node: 20 || >=22}
+
path-to-regexp@6.3.0:
resolution: {integrity: sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==}
@@ -7228,6 +7816,9 @@ packages:
resolution: {integrity: sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ==}
hasBin: true
+ robot3@0.4.1:
+ resolution: {integrity: sha512-hzjy826lrxzx8eRgv80idkf8ua1JAepRc9Efdtj03N3KNJuznQCPlyCJ7gnUmDFwZCLQjxy567mQVKmdv2BsXQ==}
+
rolldown-plugin-dts@0.18.3:
resolution: {integrity: sha512-rd1LZ0Awwfyn89UndUF/HoFF4oH9a5j+2ZeuKSJYM80vmeN/p0gslYMnHTQHBEXPhUlvAlqGA3tVgXB/1qFNDg==}
engines: {node: '>=20.19.0'}
@@ -7275,8 +7866,8 @@ packages:
engines: {node: '>=18.0.0', npm: '>=8.0.0'}
hasBin: true
- rollup@4.55.1:
- resolution: {integrity: sha512-wDv/Ht1BNHB4upNbK74s9usvl7hObDnvVzknxqY/E/O3X6rW1U1rV1aENEfJ54eFZDTNo7zv1f5N4edCluH7+A==}
+ rollup@4.57.1:
+ resolution: {integrity: sha512-oQL6lgK3e2QZeQ7gcgIkS2YZPg5slw37hYufJ3edKlfQSGGm8ICoxswK15ntSzF/a8+h7ekRy7k7oWc3BQ7y8A==}
engines: {node: '>=18.0.0', npm: '>=8.0.0'}
hasBin: true
@@ -7341,6 +7932,11 @@ packages:
engines: {node: '>=10'}
hasBin: true
+ semver@7.7.4:
+ resolution: {integrity: sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==}
+ engines: {node: '>=10'}
+ hasBin: true
+
send@0.19.0:
resolution: {integrity: sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==}
engines: {node: '>= 0.8.0'}
@@ -7364,6 +7960,12 @@ packages:
peerDependencies:
seroval: ^1.0
+ seroval-plugins@1.5.0:
+ resolution: {integrity: sha512-EAHqADIQondwRZIdeW2I636zgsODzoBDwb3PT/+7TLDWyw1Dy/Xv7iGUIEXXav7usHDE9HVhOU61irI3EnyyHA==}
+ engines: {node: '>=10'}
+ peerDependencies:
+ seroval: ^1.0
+
seroval@1.3.2:
resolution: {integrity: sha512-RbcPH1n5cfwKrru7v7+zrZvjLurgHhGyso3HTyGtRivGWgYjbOmGuivCQaORNELjNONoK35nj28EoWul9sb1zQ==}
engines: {node: '>=10'}
@@ -7372,6 +7974,10 @@ packages:
resolution: {integrity: sha512-BdrNXdzlofomLTiRnwJTSEAaGKyHHZkbMXIywOh7zlzp4uZnXErEwl9XZ+N1hJSNpeTtNxWvVwN0wUzAIQ4Hpg==}
engines: {node: '>=10'}
+ seroval@1.5.0:
+ resolution: {integrity: sha512-OE4cvmJ1uSPrKorFIH9/w/Qwuvi/IMcGbv5RKgcJ/zjA/IohDLU6SVaxFN9FwajbP7nsX0dQqMDes1whk3y+yw==}
+ engines: {node: '>=10'}
+
serve-placeholder@2.0.2:
resolution: {integrity: sha512-/TMG8SboeiQbZJWRlfTCqMs2DD3SZgWp0kDQePz9yUuCnDfDh/92gf7/PxGhzXTKBIPASIHxFcZndoNbp6QOLQ==}
@@ -7383,6 +7989,10 @@ packages:
resolution: {integrity: sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==}
engines: {node: '>= 18'}
+ serve-static@2.2.1:
+ resolution: {integrity: sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==}
+ engines: {node: '>= 18'}
+
set-cookie-parser@2.7.2:
resolution: {integrity: sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==}
@@ -7536,6 +8146,16 @@ packages:
sprintf-js@1.0.3:
resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==}
+ srvx@0.10.1:
+ resolution: {integrity: sha512-A//xtfak4eESMWWydSRFUVvCTQbSwivnGCEf8YGPe2eHU0+Z6znfUTCPF0a7oV3sObSOcrXHlL6Bs9vVctfXdg==}
+ engines: {node: '>=20.16.0'}
+ hasBin: true
+
+ srvx@0.11.2:
+ resolution: {integrity: sha512-u6NbjE84IJwm1XUnJ53WqylLTQ3BdWRw03lcjBNNeMBD+EFjkl0Cnw1RVaGSqRAo38pOHOPXJH30M6cuTINUxw==}
+ engines: {node: '>=20.16.0'}
+ hasBin: true
+
srvx@0.8.16:
resolution: {integrity: sha512-hmcGW4CgroeSmzgF1Ihwgl+Ths0JqAJ7HwjP2X7e3JzY7u4IydLMcdnlqGQiQGUswz+PO9oh/KtCpOISIvs9QQ==}
engines: {node: '>=20.16.0'}
@@ -7688,6 +8308,7 @@ packages:
tar@7.5.2:
resolution: {integrity: sha512-7NyxrTE4Anh8km8iEy7o0QYPs+0JKBTj5ZaqHg6B39erLg0qYXN3BijtShwbsNSvQ+LN75+KV+C4QR/f6Gwnpg==}
engines: {node: '>=18'}
+ deprecated: Old versions of tar are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me
term-size@2.2.1:
resolution: {integrity: sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==}
@@ -7891,6 +8512,9 @@ packages:
ufo@1.6.1:
resolution: {integrity: sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA==}
+ ufo@1.6.3:
+ resolution: {integrity: sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q==}
+
ultrahtml@1.6.0:
resolution: {integrity: sha512-R9fBn90VTJrqqLDwyMph+HGne8eqY1iPfYhPzZrvKpIfwkWZbcYlfpsb8B9dTvBfpy1/hqAD7Wi8EKfP9e8zdw==}
@@ -7903,6 +8527,9 @@ packages:
unctx@2.4.1:
resolution: {integrity: sha512-AbaYw0Nm4mK4qjhns67C+kgxR2YWiwlDBPzxrN8h8C6VtAdCgditAY5Dezu3IJy4XVqAnbrXt9oQJvsn3fyozg==}
+ unctx@2.5.0:
+ resolution: {integrity: sha512-p+Rz9x0R7X+CYDkT+Xg8/GhpcShTlU8n+cf9OtOEf7zEQsNcCZO1dPKNRDqvUTaq+P32PMMkxWHwfrxkqfqAYg==}
+
undici-types@5.28.4:
resolution: {integrity: sha512-3OeMF5Lyowe8VW0skf5qaIE7Or3yS9LS7fvMUI0gg4YxpIBVg0L8BxCmROw2CcYhSkpR68Epz7CGc8MPj94Uww==}
@@ -7916,6 +8543,10 @@ packages:
resolution: {integrity: sha512-QEg3HPMll0o3t2ourKwOeUAZ159Kn9mx5pnzHRQO8+Wixmh88YdZRiIwat0iNzNNXn0yoEtXJqFpyW7eM8BV7g==}
engines: {node: '>=20.18.1'}
+ undici@7.21.0:
+ resolution: {integrity: sha512-Hn2tCQpoDt1wv23a68Ctc8Cr/BHpUSfaPYrkajTXOS9IKpxVRx/X5m1K2YkbK2ipgZgxXSgsUinl3x+2YdSSfg==}
+ engines: {node: '>=20.18.1'}
+
unenv@1.10.0:
resolution: {integrity: sha512-wY5bskBQFL9n3Eca5XnhH6KbUo/tfvkwm9OpcdCvLaeA7piBNbavbOKJySEwQ1V0RH6HvNlSAFRTpvTqgKRQXQ==}
@@ -7926,6 +8557,10 @@ packages:
resolution: {integrity: sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==}
engines: {node: '>=18'}
+ unicorn-magic@0.4.0:
+ resolution: {integrity: sha512-wH590V9VNgYH9g3lH9wWjTrUoKsjLF6sGLjhR4sH1LWpLmCOH0Zf7PukhDA8BiS7KHe4oPNkcTHqYkj7SOGUOw==}
+ engines: {node: '>=20'}
+
unified@11.0.5:
resolution: {integrity: sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==}
@@ -7933,6 +8568,10 @@ packages:
resolution: {integrity: sha512-/JpWMG9s1nBSlXJAQ8EREFTFy3oy6USFd8T6AoBaw1q2GGcF4R9yp3ofg32UODZlYEO5VD0EWE1RpI9XDWyPYg==}
engines: {node: '>=18.12.0'}
+ unimport@5.6.0:
+ resolution: {integrity: sha512-8rqAmtJV8o60x46kBAJKtHpJDJWkA2xcBqWKPI14MgUb05o1pnpnCnXSxedUXyeq7p8fR5g3pTo2BaswZ9lD9A==}
+ engines: {node: '>=18.12.0'}
+
unist-util-find-after@5.0.0:
resolution: {integrity: sha512-amQa0Ep2m6hE2g72AugUItjbuM8X8cGQnFoHk0pGfrFeT9GZhzN5SW8nRsiGKK7Aif4CrACPENkA6P/Lw6fHGQ==}
@@ -7992,25 +8631,153 @@ packages:
unstorage@1.17.3:
resolution: {integrity: sha512-i+JYyy0DoKmQ3FximTHbGadmIYb8JEpq7lxUjnjeB702bCPum0vzo6oy5Mfu0lpqISw7hCyMW2yj4nWC8bqJ3Q==}
peerDependencies:
- '@azure/app-configuration': ^1.8.0
- '@azure/cosmos': ^4.2.0
- '@azure/data-tables': ^13.3.0
- '@azure/identity': ^4.6.0
- '@azure/keyvault-secrets': ^4.9.0
- '@azure/storage-blob': ^12.26.0
+ '@azure/app-configuration': ^1.8.0
+ '@azure/cosmos': ^4.2.0
+ '@azure/data-tables': ^13.3.0
+ '@azure/identity': ^4.6.0
+ '@azure/keyvault-secrets': ^4.9.0
+ '@azure/storage-blob': ^12.26.0
+ '@capacitor/preferences': ^6.0.3 || ^7.0.0
+ '@deno/kv': '>=0.9.0'
+ '@netlify/blobs': ^6.5.0 || ^7.0.0 || ^8.1.0 || ^9.0.0 || ^10.0.0
+ '@planetscale/database': ^1.19.0
+ '@upstash/redis': ^1.34.3
+ '@vercel/blob': '>=0.27.1'
+ '@vercel/functions': ^2.2.12 || ^3.0.0
+ '@vercel/kv': ^1.0.1
+ aws4fetch: ^1.0.20
+ db0: '>=0.2.1'
+ idb-keyval: ^6.2.1
+ ioredis: ^5.4.2
+ uploadthing: ^7.4.4
+ peerDependenciesMeta:
+ '@azure/app-configuration':
+ optional: true
+ '@azure/cosmos':
+ optional: true
+ '@azure/data-tables':
+ optional: true
+ '@azure/identity':
+ optional: true
+ '@azure/keyvault-secrets':
+ optional: true
+ '@azure/storage-blob':
+ optional: true
+ '@capacitor/preferences':
+ optional: true
+ '@deno/kv':
+ optional: true
+ '@netlify/blobs':
+ optional: true
+ '@planetscale/database':
+ optional: true
+ '@upstash/redis':
+ optional: true
+ '@vercel/blob':
+ optional: true
+ '@vercel/functions':
+ optional: true
+ '@vercel/kv':
+ optional: true
+ aws4fetch:
+ optional: true
+ db0:
+ optional: true
+ idb-keyval:
+ optional: true
+ ioredis:
+ optional: true
+ uploadthing:
+ optional: true
+
+ unstorage@1.17.4:
+ resolution: {integrity: sha512-fHK0yNg38tBiJKp/Vgsq4j0JEsCmgqH58HAn707S7zGkArbZsVr/CwINoi+nh3h98BRCwKvx1K3Xg9u3VV83sw==}
+ peerDependencies:
+ '@azure/app-configuration': ^1.8.0
+ '@azure/cosmos': ^4.2.0
+ '@azure/data-tables': ^13.3.0
+ '@azure/identity': ^4.6.0
+ '@azure/keyvault-secrets': ^4.9.0
+ '@azure/storage-blob': ^12.26.0
+ '@capacitor/preferences': ^6 || ^7 || ^8
+ '@deno/kv': '>=0.9.0'
+ '@netlify/blobs': ^6.5.0 || ^7.0.0 || ^8.1.0 || ^9.0.0 || ^10.0.0
+ '@planetscale/database': ^1.19.0
+ '@upstash/redis': ^1.34.3
+ '@vercel/blob': '>=0.27.1'
+ '@vercel/functions': ^2.2.12 || ^3.0.0
+ '@vercel/kv': ^1 || ^2 || ^3
+ aws4fetch: ^1.0.20
+ db0: '>=0.2.1'
+ idb-keyval: ^6.2.1
+ ioredis: ^5.4.2
+ uploadthing: ^7.4.4
+ peerDependenciesMeta:
+ '@azure/app-configuration':
+ optional: true
+ '@azure/cosmos':
+ optional: true
+ '@azure/data-tables':
+ optional: true
+ '@azure/identity':
+ optional: true
+ '@azure/keyvault-secrets':
+ optional: true
+ '@azure/storage-blob':
+ optional: true
+ '@capacitor/preferences':
+ optional: true
+ '@deno/kv':
+ optional: true
+ '@netlify/blobs':
+ optional: true
+ '@planetscale/database':
+ optional: true
+ '@upstash/redis':
+ optional: true
+ '@vercel/blob':
+ optional: true
+ '@vercel/functions':
+ optional: true
+ '@vercel/kv':
+ optional: true
+ aws4fetch:
+ optional: true
+ db0:
+ optional: true
+ idb-keyval:
+ optional: true
+ ioredis:
+ optional: true
+ uploadthing:
+ optional: true
+
+ unstorage@2.0.0-alpha.5:
+ resolution: {integrity: sha512-Sj8btci21Twnd6M+N+MHhjg3fVn6lAPElPmvFTe0Y/wR0WImErUdA1PzlAaUavHylJ7uDiFwlZDQKm0elG4b7g==}
+ peerDependencies:
+ '@azure/app-configuration': ^1.9.0
+ '@azure/cosmos': ^4.7.0
+ '@azure/data-tables': ^13.3.1
+ '@azure/identity': ^4.13.0
+ '@azure/keyvault-secrets': ^4.10.0
+ '@azure/storage-blob': ^12.29.1
'@capacitor/preferences': ^6.0.3 || ^7.0.0
- '@deno/kv': '>=0.9.0'
+ '@deno/kv': '>=0.12.0'
'@netlify/blobs': ^6.5.0 || ^7.0.0 || ^8.1.0 || ^9.0.0 || ^10.0.0
'@planetscale/database': ^1.19.0
- '@upstash/redis': ^1.34.3
- '@vercel/blob': '>=0.27.1'
+ '@upstash/redis': ^1.35.6
+ '@vercel/blob': '>=0.27.3'
'@vercel/functions': ^2.2.12 || ^3.0.0
'@vercel/kv': ^1.0.1
aws4fetch: ^1.0.20
- db0: '>=0.2.1'
- idb-keyval: ^6.2.1
- ioredis: ^5.4.2
- uploadthing: ^7.4.4
+ chokidar: ^4 || ^5
+ db0: '>=0.3.4'
+ idb-keyval: ^6.2.2
+ ioredis: ^5.8.2
+ lru-cache: ^11.2.2
+ mongodb: ^6 || ^7
+ ofetch: '*'
+ uploadthing: ^7.7.4
peerDependenciesMeta:
'@azure/app-configuration':
optional: true
@@ -8042,12 +8809,20 @@ packages:
optional: true
aws4fetch:
optional: true
+ chokidar:
+ optional: true
db0:
optional: true
idb-keyval:
optional: true
ioredis:
optional: true
+ lru-cache:
+ optional: true
+ mongodb:
+ optional: true
+ ofetch:
+ optional: true
uploadthing:
optional: true
@@ -8062,6 +8837,9 @@ packages:
unwasm@0.3.11:
resolution: {integrity: sha512-Vhp5gb1tusSQw5of/g3Q697srYgMXvwMgXMjcG4ZNga02fDX9coxJ9fAb0Ci38hM2Hv/U1FXRPGgjP2BYqhNoQ==}
+ unwasm@0.5.3:
+ resolution: {integrity: sha512-keBgTSfp3r6+s9ZcSma+0chwxQdmLbB5+dAD9vjtB21UTMYuKAxHXCU1K2CbCtnP09EaWeRvACnXk0EJtUx+hw==}
+
update-browserslist-db@1.2.2:
resolution: {integrity: sha512-E85pfNzMQ9jpKkA7+TJAi4TJN+tBCuWh5rUcS/sv6cFi+1q9LYDwDI5dpUL0u/73EElyQ8d3TEaeW4sPedBqYA==}
hasBin: true
@@ -8294,18 +9072,18 @@ packages:
jsdom:
optional: true
- vitest@4.0.17:
- resolution: {integrity: sha512-FQMeF0DJdWY0iOnbv466n/0BudNdKj1l5jYgl5JVTwjSsZSlqyXFt/9+1sEyhR6CLowbZpV7O1sCHrzBhucKKg==}
+ vitest@4.0.18:
+ resolution: {integrity: sha512-hOQuK7h0FGKgBAas7v0mSAsnvrIgAvWmRFjmzpJ7SwFHH3g1k2u37JtYwOwmEKhK6ZO3v9ggDBBm0La1LCK4uQ==}
engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0}
hasBin: true
peerDependencies:
'@edge-runtime/vm': '*'
'@opentelemetry/api': ^1.9.0
'@types/node': ^20.0.0 || ^22.0.0 || >=24.0.0
- '@vitest/browser-playwright': 4.0.17
- '@vitest/browser-preview': 4.0.17
- '@vitest/browser-webdriverio': 4.0.17
- '@vitest/ui': 4.0.17
+ '@vitest/browser-playwright': 4.0.18
+ '@vitest/browser-preview': 4.0.18
+ '@vitest/browser-webdriverio': 4.0.18
+ '@vitest/ui': 4.0.18
happy-dom: '*'
jsdom: '*'
peerDependenciesMeta:
@@ -8397,6 +9175,7 @@ packages:
whatwg-encoding@3.1.1:
resolution: {integrity: sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==}
engines: {node: '>=18'}
+ deprecated: Use @exodus/bytes instead for a more spec-conformant and faster implementation
whatwg-fetch@3.6.20:
resolution: {integrity: sha512-EqhiFU6daOA8kpjOWTL0olhVOF3i7OrFzSYiGsEMB8GcXS+RrzauAERX65xMeNWVqxA6HXH2m69Z9LaKKdisfg==}
@@ -8539,6 +9318,9 @@ packages:
zod@4.2.1:
resolution: {integrity: sha512-0wZ1IRqGGhMP76gLqz8EyfBXKk0J2qo2+H3fi4mcUP/KtTocoX08nmIAHl1Z2kJIZbZee8KOpBCSNPRgauucjw==}
+ zod@4.3.6:
+ resolution: {integrity: sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==}
+
zwitch@2.0.4:
resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==}
@@ -8546,7 +9328,7 @@ snapshots:
'@11labs/client@0.2.0(@types/dom-mediacapture-record@1.0.22)':
dependencies:
- livekit-client: 2.17.0(@types/dom-mediacapture-record@1.0.22)
+ livekit-client: 2.17.2(@types/dom-mediacapture-record@1.0.22)
transitivePeerDependencies:
- '@types/dom-mediacapture-record'
@@ -8624,7 +9406,7 @@ snapshots:
'@babel/helper-annotate-as-pure@7.27.3':
dependencies:
- '@babel/types': 7.28.5
+ '@babel/types': 7.29.0
'@babel/helper-compilation-targets@7.27.2':
dependencies:
@@ -8652,7 +9434,7 @@ snapshots:
'@babel/helper-member-expression-to-functions@7.28.5':
dependencies:
'@babel/traverse': 7.28.5
- '@babel/types': 7.28.5
+ '@babel/types': 7.29.0
transitivePeerDependencies:
- supports-color
@@ -8678,7 +9460,7 @@ snapshots:
'@babel/helper-optimise-call-expression@7.27.1':
dependencies:
- '@babel/types': 7.28.5
+ '@babel/types': 7.29.0
'@babel/helper-plugin-utils@7.27.1': {}
@@ -8694,7 +9476,7 @@ snapshots:
'@babel/helper-skip-transparent-expression-wrappers@7.27.1':
dependencies:
'@babel/traverse': 7.28.5
- '@babel/types': 7.28.5
+ '@babel/types': 7.29.0
transitivePeerDependencies:
- supports-color
@@ -8713,6 +9495,10 @@ snapshots:
dependencies:
'@babel/types': 7.28.5
+ '@babel/parser@7.29.0':
+ dependencies:
+ '@babel/types': 7.29.0
+
'@babel/plugin-syntax-jsx@7.27.1(@babel/core@7.28.5)':
dependencies:
'@babel/core': 7.28.5
@@ -8788,6 +9574,11 @@ snapshots:
'@babel/helper-string-parser': 7.27.1
'@babel/helper-validator-identifier': 7.28.5
+ '@babel/types@7.29.0':
+ dependencies:
+ '@babel/helper-string-parser': 7.27.1
+ '@babel/helper-validator-identifier': 7.28.5
+
'@bcoe/v8-coverage@1.0.2': {}
'@bufbuild/protobuf@1.10.1': {}
@@ -8947,6 +9738,8 @@ snapshots:
dependencies:
mime: 3.0.0
+ '@cloudflare/kv-asset-handler@0.4.2': {}
+
'@crazydos/vue-markdown@1.1.4(vue@3.5.25(typescript@5.9.3))':
dependencies:
deepmerge: 4.3.1
@@ -9009,10 +9802,10 @@ snapshots:
'@esbuild/aix-ppc64@0.25.12':
optional: true
- '@esbuild/aix-ppc64@0.27.1':
+ '@esbuild/aix-ppc64@0.27.2':
optional: true
- '@esbuild/aix-ppc64@0.27.2':
+ '@esbuild/aix-ppc64@0.27.3':
optional: true
'@esbuild/android-arm64@0.20.2':
@@ -9021,10 +9814,10 @@ snapshots:
'@esbuild/android-arm64@0.25.12':
optional: true
- '@esbuild/android-arm64@0.27.1':
+ '@esbuild/android-arm64@0.27.2':
optional: true
- '@esbuild/android-arm64@0.27.2':
+ '@esbuild/android-arm64@0.27.3':
optional: true
'@esbuild/android-arm@0.20.2':
@@ -9033,10 +9826,10 @@ snapshots:
'@esbuild/android-arm@0.25.12':
optional: true
- '@esbuild/android-arm@0.27.1':
+ '@esbuild/android-arm@0.27.2':
optional: true
- '@esbuild/android-arm@0.27.2':
+ '@esbuild/android-arm@0.27.3':
optional: true
'@esbuild/android-x64@0.20.2':
@@ -9045,10 +9838,10 @@ snapshots:
'@esbuild/android-x64@0.25.12':
optional: true
- '@esbuild/android-x64@0.27.1':
+ '@esbuild/android-x64@0.27.2':
optional: true
- '@esbuild/android-x64@0.27.2':
+ '@esbuild/android-x64@0.27.3':
optional: true
'@esbuild/darwin-arm64@0.20.2':
@@ -9057,10 +9850,10 @@ snapshots:
'@esbuild/darwin-arm64@0.25.12':
optional: true
- '@esbuild/darwin-arm64@0.27.1':
+ '@esbuild/darwin-arm64@0.27.2':
optional: true
- '@esbuild/darwin-arm64@0.27.2':
+ '@esbuild/darwin-arm64@0.27.3':
optional: true
'@esbuild/darwin-x64@0.20.2':
@@ -9069,10 +9862,10 @@ snapshots:
'@esbuild/darwin-x64@0.25.12':
optional: true
- '@esbuild/darwin-x64@0.27.1':
+ '@esbuild/darwin-x64@0.27.2':
optional: true
- '@esbuild/darwin-x64@0.27.2':
+ '@esbuild/darwin-x64@0.27.3':
optional: true
'@esbuild/freebsd-arm64@0.20.2':
@@ -9081,10 +9874,10 @@ snapshots:
'@esbuild/freebsd-arm64@0.25.12':
optional: true
- '@esbuild/freebsd-arm64@0.27.1':
+ '@esbuild/freebsd-arm64@0.27.2':
optional: true
- '@esbuild/freebsd-arm64@0.27.2':
+ '@esbuild/freebsd-arm64@0.27.3':
optional: true
'@esbuild/freebsd-x64@0.20.2':
@@ -9093,10 +9886,10 @@ snapshots:
'@esbuild/freebsd-x64@0.25.12':
optional: true
- '@esbuild/freebsd-x64@0.27.1':
+ '@esbuild/freebsd-x64@0.27.2':
optional: true
- '@esbuild/freebsd-x64@0.27.2':
+ '@esbuild/freebsd-x64@0.27.3':
optional: true
'@esbuild/linux-arm64@0.20.2':
@@ -9105,10 +9898,10 @@ snapshots:
'@esbuild/linux-arm64@0.25.12':
optional: true
- '@esbuild/linux-arm64@0.27.1':
+ '@esbuild/linux-arm64@0.27.2':
optional: true
- '@esbuild/linux-arm64@0.27.2':
+ '@esbuild/linux-arm64@0.27.3':
optional: true
'@esbuild/linux-arm@0.20.2':
@@ -9117,10 +9910,10 @@ snapshots:
'@esbuild/linux-arm@0.25.12':
optional: true
- '@esbuild/linux-arm@0.27.1':
+ '@esbuild/linux-arm@0.27.2':
optional: true
- '@esbuild/linux-arm@0.27.2':
+ '@esbuild/linux-arm@0.27.3':
optional: true
'@esbuild/linux-ia32@0.20.2':
@@ -9129,10 +9922,10 @@ snapshots:
'@esbuild/linux-ia32@0.25.12':
optional: true
- '@esbuild/linux-ia32@0.27.1':
+ '@esbuild/linux-ia32@0.27.2':
optional: true
- '@esbuild/linux-ia32@0.27.2':
+ '@esbuild/linux-ia32@0.27.3':
optional: true
'@esbuild/linux-loong64@0.20.2':
@@ -9141,10 +9934,10 @@ snapshots:
'@esbuild/linux-loong64@0.25.12':
optional: true
- '@esbuild/linux-loong64@0.27.1':
+ '@esbuild/linux-loong64@0.27.2':
optional: true
- '@esbuild/linux-loong64@0.27.2':
+ '@esbuild/linux-loong64@0.27.3':
optional: true
'@esbuild/linux-mips64el@0.20.2':
@@ -9153,10 +9946,10 @@ snapshots:
'@esbuild/linux-mips64el@0.25.12':
optional: true
- '@esbuild/linux-mips64el@0.27.1':
+ '@esbuild/linux-mips64el@0.27.2':
optional: true
- '@esbuild/linux-mips64el@0.27.2':
+ '@esbuild/linux-mips64el@0.27.3':
optional: true
'@esbuild/linux-ppc64@0.20.2':
@@ -9165,10 +9958,10 @@ snapshots:
'@esbuild/linux-ppc64@0.25.12':
optional: true
- '@esbuild/linux-ppc64@0.27.1':
+ '@esbuild/linux-ppc64@0.27.2':
optional: true
- '@esbuild/linux-ppc64@0.27.2':
+ '@esbuild/linux-ppc64@0.27.3':
optional: true
'@esbuild/linux-riscv64@0.20.2':
@@ -9177,10 +9970,10 @@ snapshots:
'@esbuild/linux-riscv64@0.25.12':
optional: true
- '@esbuild/linux-riscv64@0.27.1':
+ '@esbuild/linux-riscv64@0.27.2':
optional: true
- '@esbuild/linux-riscv64@0.27.2':
+ '@esbuild/linux-riscv64@0.27.3':
optional: true
'@esbuild/linux-s390x@0.20.2':
@@ -9189,10 +9982,10 @@ snapshots:
'@esbuild/linux-s390x@0.25.12':
optional: true
- '@esbuild/linux-s390x@0.27.1':
+ '@esbuild/linux-s390x@0.27.2':
optional: true
- '@esbuild/linux-s390x@0.27.2':
+ '@esbuild/linux-s390x@0.27.3':
optional: true
'@esbuild/linux-x64@0.20.2':
@@ -9201,19 +9994,19 @@ snapshots:
'@esbuild/linux-x64@0.25.12':
optional: true
- '@esbuild/linux-x64@0.27.1':
+ '@esbuild/linux-x64@0.27.2':
optional: true
- '@esbuild/linux-x64@0.27.2':
+ '@esbuild/linux-x64@0.27.3':
optional: true
'@esbuild/netbsd-arm64@0.25.12':
optional: true
- '@esbuild/netbsd-arm64@0.27.1':
+ '@esbuild/netbsd-arm64@0.27.2':
optional: true
- '@esbuild/netbsd-arm64@0.27.2':
+ '@esbuild/netbsd-arm64@0.27.3':
optional: true
'@esbuild/netbsd-x64@0.20.2':
@@ -9222,19 +10015,19 @@ snapshots:
'@esbuild/netbsd-x64@0.25.12':
optional: true
- '@esbuild/netbsd-x64@0.27.1':
+ '@esbuild/netbsd-x64@0.27.2':
optional: true
- '@esbuild/netbsd-x64@0.27.2':
+ '@esbuild/netbsd-x64@0.27.3':
optional: true
'@esbuild/openbsd-arm64@0.25.12':
optional: true
- '@esbuild/openbsd-arm64@0.27.1':
+ '@esbuild/openbsd-arm64@0.27.2':
optional: true
- '@esbuild/openbsd-arm64@0.27.2':
+ '@esbuild/openbsd-arm64@0.27.3':
optional: true
'@esbuild/openbsd-x64@0.20.2':
@@ -9243,19 +10036,19 @@ snapshots:
'@esbuild/openbsd-x64@0.25.12':
optional: true
- '@esbuild/openbsd-x64@0.27.1':
+ '@esbuild/openbsd-x64@0.27.2':
optional: true
- '@esbuild/openbsd-x64@0.27.2':
+ '@esbuild/openbsd-x64@0.27.3':
optional: true
'@esbuild/openharmony-arm64@0.25.12':
optional: true
- '@esbuild/openharmony-arm64@0.27.1':
+ '@esbuild/openharmony-arm64@0.27.2':
optional: true
- '@esbuild/openharmony-arm64@0.27.2':
+ '@esbuild/openharmony-arm64@0.27.3':
optional: true
'@esbuild/sunos-x64@0.20.2':
@@ -9264,10 +10057,10 @@ snapshots:
'@esbuild/sunos-x64@0.25.12':
optional: true
- '@esbuild/sunos-x64@0.27.1':
+ '@esbuild/sunos-x64@0.27.2':
optional: true
- '@esbuild/sunos-x64@0.27.2':
+ '@esbuild/sunos-x64@0.27.3':
optional: true
'@esbuild/win32-arm64@0.20.2':
@@ -9276,10 +10069,10 @@ snapshots:
'@esbuild/win32-arm64@0.25.12':
optional: true
- '@esbuild/win32-arm64@0.27.1':
+ '@esbuild/win32-arm64@0.27.2':
optional: true
- '@esbuild/win32-arm64@0.27.2':
+ '@esbuild/win32-arm64@0.27.3':
optional: true
'@esbuild/win32-ia32@0.20.2':
@@ -9288,10 +10081,10 @@ snapshots:
'@esbuild/win32-ia32@0.25.12':
optional: true
- '@esbuild/win32-ia32@0.27.1':
+ '@esbuild/win32-ia32@0.27.2':
optional: true
- '@esbuild/win32-ia32@0.27.2':
+ '@esbuild/win32-ia32@0.27.3':
optional: true
'@esbuild/win32-x64@0.20.2':
@@ -9300,10 +10093,10 @@ snapshots:
'@esbuild/win32-x64@0.25.12':
optional: true
- '@esbuild/win32-x64@0.27.1':
+ '@esbuild/win32-x64@0.27.2':
optional: true
- '@esbuild/win32-x64@0.27.2':
+ '@esbuild/win32-x64@0.27.3':
optional: true
'@eslint-community/eslint-utils@4.9.0(eslint@9.39.1(jiti@2.6.1))':
@@ -9366,6 +10159,12 @@ snapshots:
'@faker-js/faker@10.1.0': {}
+ '@fal-ai/client@1.9.1':
+ dependencies:
+ '@msgpack/msgpack': 3.1.3
+ eventsource-parser: 1.1.2
+ robot3: 0.4.1
+
'@gerrit0/mini-shiki@3.19.0':
dependencies:
'@shikijs/engine-oniguruma': 3.20.0
@@ -9403,6 +10202,8 @@ snapshots:
'@ioredis/commands@1.4.0': {}
+ '@ioredis/commands@1.5.0': {}
+
'@isaacs/balanced-match@4.0.1': {}
'@isaacs/brace-expansion@5.0.0':
@@ -9456,7 +10257,7 @@ snapshots:
'@livekit/mutex@1.1.1': {}
- '@livekit/protocol@1.42.2':
+ '@livekit/protocol@1.44.0':
dependencies:
'@bufbuild/protobuf': 1.10.1
@@ -9524,6 +10325,8 @@ snapshots:
'@microsoft/tsdoc@0.15.1': {}
+ '@msgpack/msgpack@3.1.3': {}
+
'@napi-rs/wasm-runtime@0.2.12':
dependencies:
'@emnapi/core': 1.7.1
@@ -9544,6 +10347,13 @@ snapshots:
'@tybys/wasm-util': 0.10.1
optional: true
+ '@napi-rs/wasm-runtime@1.1.1':
+ dependencies:
+ '@emnapi/core': 1.7.1
+ '@emnapi/runtime': 1.7.1
+ '@tybys/wasm-util': 0.10.1
+ optional: true
+
'@nodelib/fs.scandir@2.1.5':
dependencies:
'@nodelib/fs.stat': 2.0.5
@@ -9626,7 +10436,69 @@ snapshots:
'@openrouter/sdk@0.3.15':
dependencies:
- zod: 4.2.1
+ zod: 4.3.6
+
+ '@oxc-minify/binding-android-arm-eabi@0.110.0':
+ optional: true
+
+ '@oxc-minify/binding-android-arm64@0.110.0':
+ optional: true
+
+ '@oxc-minify/binding-darwin-arm64@0.110.0':
+ optional: true
+
+ '@oxc-minify/binding-darwin-x64@0.110.0':
+ optional: true
+
+ '@oxc-minify/binding-freebsd-x64@0.110.0':
+ optional: true
+
+ '@oxc-minify/binding-linux-arm-gnueabihf@0.110.0':
+ optional: true
+
+ '@oxc-minify/binding-linux-arm-musleabihf@0.110.0':
+ optional: true
+
+ '@oxc-minify/binding-linux-arm64-gnu@0.110.0':
+ optional: true
+
+ '@oxc-minify/binding-linux-arm64-musl@0.110.0':
+ optional: true
+
+ '@oxc-minify/binding-linux-ppc64-gnu@0.110.0':
+ optional: true
+
+ '@oxc-minify/binding-linux-riscv64-gnu@0.110.0':
+ optional: true
+
+ '@oxc-minify/binding-linux-riscv64-musl@0.110.0':
+ optional: true
+
+ '@oxc-minify/binding-linux-s390x-gnu@0.110.0':
+ optional: true
+
+ '@oxc-minify/binding-linux-x64-gnu@0.110.0':
+ optional: true
+
+ '@oxc-minify/binding-linux-x64-musl@0.110.0':
+ optional: true
+
+ '@oxc-minify/binding-openharmony-arm64@0.110.0':
+ optional: true
+
+ '@oxc-minify/binding-wasm32-wasi@0.110.0':
+ dependencies:
+ '@napi-rs/wasm-runtime': 1.1.1
+ optional: true
+
+ '@oxc-minify/binding-win32-arm64-msvc@0.110.0':
+ optional: true
+
+ '@oxc-minify/binding-win32-ia32-msvc@0.110.0':
+ optional: true
+
+ '@oxc-minify/binding-win32-x64-msvc@0.110.0':
+ optional: true
'@oxc-project/types@0.101.0': {}
@@ -9692,6 +10564,68 @@ snapshots:
'@oxc-resolver/binding-win32-x64-msvc@11.15.0':
optional: true
+ '@oxc-transform/binding-android-arm-eabi@0.110.0':
+ optional: true
+
+ '@oxc-transform/binding-android-arm64@0.110.0':
+ optional: true
+
+ '@oxc-transform/binding-darwin-arm64@0.110.0':
+ optional: true
+
+ '@oxc-transform/binding-darwin-x64@0.110.0':
+ optional: true
+
+ '@oxc-transform/binding-freebsd-x64@0.110.0':
+ optional: true
+
+ '@oxc-transform/binding-linux-arm-gnueabihf@0.110.0':
+ optional: true
+
+ '@oxc-transform/binding-linux-arm-musleabihf@0.110.0':
+ optional: true
+
+ '@oxc-transform/binding-linux-arm64-gnu@0.110.0':
+ optional: true
+
+ '@oxc-transform/binding-linux-arm64-musl@0.110.0':
+ optional: true
+
+ '@oxc-transform/binding-linux-ppc64-gnu@0.110.0':
+ optional: true
+
+ '@oxc-transform/binding-linux-riscv64-gnu@0.110.0':
+ optional: true
+
+ '@oxc-transform/binding-linux-riscv64-musl@0.110.0':
+ optional: true
+
+ '@oxc-transform/binding-linux-s390x-gnu@0.110.0':
+ optional: true
+
+ '@oxc-transform/binding-linux-x64-gnu@0.110.0':
+ optional: true
+
+ '@oxc-transform/binding-linux-x64-musl@0.110.0':
+ optional: true
+
+ '@oxc-transform/binding-openharmony-arm64@0.110.0':
+ optional: true
+
+ '@oxc-transform/binding-wasm32-wasi@0.110.0':
+ dependencies:
+ '@napi-rs/wasm-runtime': 1.1.1
+ optional: true
+
+ '@oxc-transform/binding-win32-arm64-msvc@0.110.0':
+ optional: true
+
+ '@oxc-transform/binding-win32-ia32-msvc@0.110.0':
+ optional: true
+
+ '@oxc-transform/binding-win32-x64-msvc@0.110.0':
+ optional: true
+
'@parcel/watcher-android-arm64@2.5.1':
optional: true
@@ -9840,6 +10774,10 @@ snapshots:
optionalDependencies:
rollup: 4.53.3
+ '@rollup/plugin-alias@6.0.0(rollup@4.57.1)':
+ optionalDependencies:
+ rollup: 4.57.1
+
'@rollup/plugin-commonjs@28.0.9(rollup@4.53.3)':
dependencies:
'@rollup/pluginutils': 5.3.0(rollup@4.53.3)
@@ -9852,6 +10790,18 @@ snapshots:
optionalDependencies:
rollup: 4.53.3
+ '@rollup/plugin-commonjs@29.0.0(rollup@4.57.1)':
+ dependencies:
+ '@rollup/pluginutils': 5.3.0(rollup@4.57.1)
+ commondir: 1.0.1
+ estree-walker: 2.0.2
+ fdir: 6.5.0(picomatch@4.0.3)
+ is-reference: 1.2.1
+ magic-string: 0.30.21
+ picomatch: 4.0.3
+ optionalDependencies:
+ rollup: 4.57.1
+
'@rollup/plugin-inject@5.0.5(rollup@4.53.3)':
dependencies:
'@rollup/pluginutils': 5.3.0(rollup@4.53.3)
@@ -9860,12 +10810,26 @@ snapshots:
optionalDependencies:
rollup: 4.53.3
+ '@rollup/plugin-inject@5.0.5(rollup@4.57.1)':
+ dependencies:
+ '@rollup/pluginutils': 5.3.0(rollup@4.57.1)
+ estree-walker: 2.0.2
+ magic-string: 0.30.21
+ optionalDependencies:
+ rollup: 4.57.1
+
'@rollup/plugin-json@6.1.0(rollup@4.53.3)':
dependencies:
'@rollup/pluginutils': 5.3.0(rollup@4.53.3)
optionalDependencies:
rollup: 4.53.3
+ '@rollup/plugin-json@6.1.0(rollup@4.57.1)':
+ dependencies:
+ '@rollup/pluginutils': 5.3.0(rollup@4.57.1)
+ optionalDependencies:
+ rollup: 4.57.1
+
'@rollup/plugin-node-resolve@16.0.3(rollup@4.53.3)':
dependencies:
'@rollup/pluginutils': 5.3.0(rollup@4.53.3)
@@ -9876,6 +10840,16 @@ snapshots:
optionalDependencies:
rollup: 4.53.3
+ '@rollup/plugin-node-resolve@16.0.3(rollup@4.57.1)':
+ dependencies:
+ '@rollup/pluginutils': 5.3.0(rollup@4.57.1)
+ '@types/resolve': 1.20.2
+ deepmerge: 4.3.1
+ is-module: 1.0.0
+ resolve: 1.22.11
+ optionalDependencies:
+ rollup: 4.57.1
+
'@rollup/plugin-replace@6.0.3(rollup@4.53.3)':
dependencies:
'@rollup/pluginutils': 5.3.0(rollup@4.53.3)
@@ -9883,6 +10857,13 @@ snapshots:
optionalDependencies:
rollup: 4.53.3
+ '@rollup/plugin-replace@6.0.3(rollup@4.57.1)':
+ dependencies:
+ '@rollup/pluginutils': 5.3.0(rollup@4.57.1)
+ magic-string: 0.30.21
+ optionalDependencies:
+ rollup: 4.57.1
+
'@rollup/plugin-terser@0.4.4(rollup@4.53.3)':
dependencies:
serialize-javascript: 6.0.2
@@ -9891,6 +10872,14 @@ snapshots:
optionalDependencies:
rollup: 4.53.3
+ '@rollup/plugin-terser@0.4.4(rollup@4.57.1)':
+ dependencies:
+ serialize-javascript: 6.0.2
+ smob: 1.5.0
+ terser: 5.44.1
+ optionalDependencies:
+ rollup: 4.57.1
+
'@rollup/pluginutils@5.3.0(rollup@4.53.3)':
dependencies:
'@types/estree': 1.0.8
@@ -9899,153 +10888,153 @@ snapshots:
optionalDependencies:
rollup: 4.53.3
- '@rollup/pluginutils@5.3.0(rollup@4.55.1)':
+ '@rollup/pluginutils@5.3.0(rollup@4.57.1)':
dependencies:
'@types/estree': 1.0.8
estree-walker: 2.0.2
picomatch: 4.0.3
optionalDependencies:
- rollup: 4.55.1
+ rollup: 4.57.1
'@rollup/rollup-android-arm-eabi@4.53.3':
optional: true
- '@rollup/rollup-android-arm-eabi@4.55.1':
+ '@rollup/rollup-android-arm-eabi@4.57.1':
optional: true
'@rollup/rollup-android-arm64@4.53.3':
optional: true
- '@rollup/rollup-android-arm64@4.55.1':
+ '@rollup/rollup-android-arm64@4.57.1':
optional: true
'@rollup/rollup-darwin-arm64@4.53.3':
optional: true
- '@rollup/rollup-darwin-arm64@4.55.1':
+ '@rollup/rollup-darwin-arm64@4.57.1':
optional: true
'@rollup/rollup-darwin-x64@4.53.3':
optional: true
- '@rollup/rollup-darwin-x64@4.55.1':
+ '@rollup/rollup-darwin-x64@4.57.1':
optional: true
'@rollup/rollup-freebsd-arm64@4.53.3':
optional: true
- '@rollup/rollup-freebsd-arm64@4.55.1':
+ '@rollup/rollup-freebsd-arm64@4.57.1':
optional: true
'@rollup/rollup-freebsd-x64@4.53.3':
optional: true
- '@rollup/rollup-freebsd-x64@4.55.1':
+ '@rollup/rollup-freebsd-x64@4.57.1':
optional: true
'@rollup/rollup-linux-arm-gnueabihf@4.53.3':
optional: true
- '@rollup/rollup-linux-arm-gnueabihf@4.55.1':
+ '@rollup/rollup-linux-arm-gnueabihf@4.57.1':
optional: true
'@rollup/rollup-linux-arm-musleabihf@4.53.3':
optional: true
- '@rollup/rollup-linux-arm-musleabihf@4.55.1':
+ '@rollup/rollup-linux-arm-musleabihf@4.57.1':
optional: true
'@rollup/rollup-linux-arm64-gnu@4.53.3':
optional: true
- '@rollup/rollup-linux-arm64-gnu@4.55.1':
+ '@rollup/rollup-linux-arm64-gnu@4.57.1':
optional: true
'@rollup/rollup-linux-arm64-musl@4.53.3':
optional: true
- '@rollup/rollup-linux-arm64-musl@4.55.1':
+ '@rollup/rollup-linux-arm64-musl@4.57.1':
optional: true
'@rollup/rollup-linux-loong64-gnu@4.53.3':
optional: true
- '@rollup/rollup-linux-loong64-gnu@4.55.1':
+ '@rollup/rollup-linux-loong64-gnu@4.57.1':
optional: true
- '@rollup/rollup-linux-loong64-musl@4.55.1':
+ '@rollup/rollup-linux-loong64-musl@4.57.1':
optional: true
'@rollup/rollup-linux-ppc64-gnu@4.53.3':
optional: true
- '@rollup/rollup-linux-ppc64-gnu@4.55.1':
+ '@rollup/rollup-linux-ppc64-gnu@4.57.1':
optional: true
- '@rollup/rollup-linux-ppc64-musl@4.55.1':
+ '@rollup/rollup-linux-ppc64-musl@4.57.1':
optional: true
'@rollup/rollup-linux-riscv64-gnu@4.53.3':
optional: true
- '@rollup/rollup-linux-riscv64-gnu@4.55.1':
+ '@rollup/rollup-linux-riscv64-gnu@4.57.1':
optional: true
'@rollup/rollup-linux-riscv64-musl@4.53.3':
optional: true
- '@rollup/rollup-linux-riscv64-musl@4.55.1':
+ '@rollup/rollup-linux-riscv64-musl@4.57.1':
optional: true
'@rollup/rollup-linux-s390x-gnu@4.53.3':
optional: true
- '@rollup/rollup-linux-s390x-gnu@4.55.1':
+ '@rollup/rollup-linux-s390x-gnu@4.57.1':
optional: true
'@rollup/rollup-linux-x64-gnu@4.53.3':
optional: true
- '@rollup/rollup-linux-x64-gnu@4.55.1':
+ '@rollup/rollup-linux-x64-gnu@4.57.1':
optional: true
'@rollup/rollup-linux-x64-musl@4.53.3':
optional: true
- '@rollup/rollup-linux-x64-musl@4.55.1':
+ '@rollup/rollup-linux-x64-musl@4.57.1':
optional: true
- '@rollup/rollup-openbsd-x64@4.55.1':
+ '@rollup/rollup-openbsd-x64@4.57.1':
optional: true
'@rollup/rollup-openharmony-arm64@4.53.3':
optional: true
- '@rollup/rollup-openharmony-arm64@4.55.1':
+ '@rollup/rollup-openharmony-arm64@4.57.1':
optional: true
'@rollup/rollup-win32-arm64-msvc@4.53.3':
optional: true
- '@rollup/rollup-win32-arm64-msvc@4.55.1':
+ '@rollup/rollup-win32-arm64-msvc@4.57.1':
optional: true
'@rollup/rollup-win32-ia32-msvc@4.53.3':
optional: true
- '@rollup/rollup-win32-ia32-msvc@4.55.1':
+ '@rollup/rollup-win32-ia32-msvc@4.57.1':
optional: true
'@rollup/rollup-win32-x64-gnu@4.53.3':
optional: true
- '@rollup/rollup-win32-x64-gnu@4.55.1':
+ '@rollup/rollup-win32-x64-gnu@4.57.1':
optional: true
'@rollup/rollup-win32-x64-msvc@4.53.3':
optional: true
- '@rollup/rollup-win32-x64-msvc@4.55.1':
+ '@rollup/rollup-win32-x64-msvc@4.57.1':
optional: true
'@rushstack/node-core-library@5.7.0(@types/node@24.10.3)':
@@ -10368,6 +11357,13 @@ snapshots:
tailwindcss: 4.1.18
vite: 7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
+ '@tailwindcss/vite@4.1.18(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
+ dependencies:
+ '@tailwindcss/node': 4.1.18
+ '@tailwindcss/oxide': 4.1.18
+ tailwindcss: 4.1.18
+ vite: 7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
+
'@tanstack/devtools-client@0.0.5':
dependencies:
'@tanstack/devtools-event-client': 0.4.0
@@ -10452,7 +11448,7 @@ snapshots:
'@babel/code-frame': 7.27.1
'@babel/core': 7.28.5
'@babel/traverse': 7.28.5
- '@babel/types': 7.28.5
+ '@babel/types': 7.29.0
'@tanstack/router-utils': 1.131.2
babel-dead-code-elimination: 1.0.10
tiny-invariant: 1.3.3
@@ -10465,7 +11461,7 @@ snapshots:
'@babel/code-frame': 7.27.1
'@babel/core': 7.28.5
'@babel/traverse': 7.28.5
- '@babel/types': 7.28.5
+ '@babel/types': 7.29.0
'@tanstack/router-utils': 1.141.0
babel-dead-code-elimination: 1.0.10
pathe: 2.0.3
@@ -10494,9 +11490,11 @@ snapshots:
'@tanstack/history@1.141.0': {}
- '@tanstack/nitro-v2-vite-plugin@1.141.0(rolldown@1.0.0-beta.53)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
+ '@tanstack/history@1.154.14': {}
+
+ '@tanstack/nitro-v2-vite-plugin@1.154.7(rolldown@1.0.0-beta.53)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
dependencies:
- nitropack: 2.12.9(rolldown@1.0.0-beta.53)
+ nitropack: 2.13.1(rolldown@1.0.0-beta.53)
pathe: 2.0.3
vite: 7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
transitivePeerDependencies:
@@ -10550,24 +11548,23 @@ snapshots:
'@tanstack/query-core': 5.90.12
react: 19.2.3
- '@tanstack/react-router-devtools@1.141.1(@tanstack/react-router@1.141.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(@tanstack/router-core@1.141.1)(csstype@3.2.3)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(solid-js@1.9.10)':
+ '@tanstack/react-router-devtools@1.159.5(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(@tanstack/router-core@1.159.4)(csstype@3.2.3)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)':
dependencies:
- '@tanstack/react-router': 1.141.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
- '@tanstack/router-devtools-core': 1.141.1(@tanstack/router-core@1.141.1)(csstype@3.2.3)(solid-js@1.9.10)
+ '@tanstack/react-router': 1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
+ '@tanstack/router-devtools-core': 1.159.4(@tanstack/router-core@1.159.4)(csstype@3.2.3)
react: 19.2.3
react-dom: 19.2.3(react@19.2.3)
optionalDependencies:
- '@tanstack/router-core': 1.141.1
+ '@tanstack/router-core': 1.159.4
transitivePeerDependencies:
- csstype
- - solid-js
- '@tanstack/react-router-ssr-query@1.141.1(@tanstack/query-core@5.90.12)(@tanstack/react-query@5.90.12(react@19.2.3))(@tanstack/react-router@1.141.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(@tanstack/router-core@1.141.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)':
+ '@tanstack/react-router-ssr-query@1.159.5(@tanstack/query-core@5.90.12)(@tanstack/react-query@5.90.12(react@19.2.3))(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(@tanstack/router-core@1.159.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)':
dependencies:
'@tanstack/query-core': 5.90.12
'@tanstack/react-query': 5.90.12(react@19.2.3)
- '@tanstack/react-router': 1.141.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
- '@tanstack/router-ssr-query-core': 1.141.1(@tanstack/query-core@5.90.12)(@tanstack/router-core@1.141.1)
+ '@tanstack/react-router': 1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
+ '@tanstack/router-ssr-query-core': 1.159.4(@tanstack/query-core@5.90.12)(@tanstack/router-core@1.159.4)
react: 19.2.3
react-dom: 19.2.3(react@19.2.3)
transitivePeerDependencies:
@@ -10584,6 +11581,17 @@ snapshots:
tiny-invariant: 1.3.3
tiny-warning: 1.0.3
+ '@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3)':
+ dependencies:
+ '@tanstack/history': 1.154.14
+ '@tanstack/react-store': 0.8.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
+ '@tanstack/router-core': 1.159.4
+ isbot: 5.1.32
+ react: 19.2.3
+ react-dom: 19.2.3(react@19.2.3)
+ tiny-invariant: 1.3.3
+ tiny-warning: 1.0.3
+
'@tanstack/react-start-client@1.141.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3)':
dependencies:
'@tanstack/react-router': 1.141.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
@@ -10594,9 +11602,19 @@ snapshots:
tiny-invariant: 1.3.3
tiny-warning: 1.0.3
- '@tanstack/react-start-plugin@1.131.50(@tanstack/react-router@1.141.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(@vitejs/plugin-react@4.7.0(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(rolldown@1.0.0-beta.53)(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
+ '@tanstack/react-start-client@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3)':
+ dependencies:
+ '@tanstack/react-router': 1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
+ '@tanstack/router-core': 1.159.4
+ '@tanstack/start-client-core': 1.159.4
+ react: 19.2.3
+ react-dom: 19.2.3(react@19.2.3)
+ tiny-invariant: 1.3.3
+ tiny-warning: 1.0.3
+
+ '@tanstack/react-start-plugin@1.131.50(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(@vitejs/plugin-react@4.7.0(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(rolldown@1.0.0-beta.53)(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
dependencies:
- '@tanstack/start-plugin-core': 1.131.50(@tanstack/react-router@1.141.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(rolldown@1.0.0-beta.53)(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+ '@tanstack/start-plugin-core': 1.131.50(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(rolldown@1.0.0-beta.53)(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
'@vitejs/plugin-react': 4.7.0(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
pathe: 2.0.3
vite: 7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
@@ -10638,7 +11656,7 @@ snapshots:
'@tanstack/react-start-router-manifest@1.120.19(@types/node@24.10.3)(db0@0.3.4)(ioredis@5.8.2)(jiti@2.6.1)(lightningcss@1.30.2)(rolldown@1.0.0-beta.53)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)':
dependencies:
- '@tanstack/router-core': 1.141.1
+ '@tanstack/router-core': 1.157.16
tiny-invariant: 1.3.3
vinxi: 0.5.3(@types/node@24.10.3)(db0@0.3.4)(ioredis@5.8.2)(jiti@2.6.1)(lightningcss@1.30.2)(rolldown@1.0.0-beta.53)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
transitivePeerDependencies:
@@ -10686,27 +11704,71 @@ snapshots:
- xml2js
- yaml
- '@tanstack/react-start-server@1.141.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3)':
+ '@tanstack/react-start-server@1.141.1(crossws@0.4.4(srvx@0.11.2))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)':
+ dependencies:
+ '@tanstack/history': 1.141.0
+ '@tanstack/react-router': 1.141.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
+ '@tanstack/router-core': 1.141.1
+ '@tanstack/start-client-core': 1.141.1
+ '@tanstack/start-server-core': 1.141.1(crossws@0.4.4(srvx@0.11.2))
+ react: 19.2.3
+ react-dom: 19.2.3(react@19.2.3)
+ transitivePeerDependencies:
+ - crossws
+
+ '@tanstack/react-start-server@1.159.5(crossws@0.4.4(srvx@0.10.1))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)':
+ dependencies:
+ '@tanstack/history': 1.154.14
+ '@tanstack/react-router': 1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
+ '@tanstack/router-core': 1.159.4
+ '@tanstack/start-client-core': 1.159.4
+ '@tanstack/start-server-core': 1.159.4(crossws@0.4.4(srvx@0.10.1))
+ react: 19.2.3
+ react-dom: 19.2.3(react@19.2.3)
+ transitivePeerDependencies:
+ - crossws
+
+ '@tanstack/react-start-server@1.159.5(crossws@0.4.4(srvx@0.11.2))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)':
dependencies:
- '@tanstack/history': 1.141.0
- '@tanstack/react-router': 1.141.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
- '@tanstack/router-core': 1.141.1
- '@tanstack/start-client-core': 1.141.1
- '@tanstack/start-server-core': 1.141.1
+ '@tanstack/history': 1.154.14
+ '@tanstack/react-router': 1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
+ '@tanstack/router-core': 1.159.4
+ '@tanstack/start-client-core': 1.159.4
+ '@tanstack/start-server-core': 1.159.4(crossws@0.4.4(srvx@0.11.2))
react: 19.2.3
react-dom: 19.2.3(react@19.2.3)
transitivePeerDependencies:
- crossws
- '@tanstack/react-start@1.141.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
+ '@tanstack/react-start@1.159.5(crossws@0.4.4(srvx@0.10.1))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
dependencies:
- '@tanstack/react-router': 1.141.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
- '@tanstack/react-start-client': 1.141.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
- '@tanstack/react-start-server': 1.141.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
- '@tanstack/router-utils': 1.141.0
- '@tanstack/start-client-core': 1.141.1
- '@tanstack/start-plugin-core': 1.141.1(@tanstack/react-router@1.141.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
- '@tanstack/start-server-core': 1.141.1
+ '@tanstack/react-router': 1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
+ '@tanstack/react-start-client': 1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
+ '@tanstack/react-start-server': 1.159.5(crossws@0.4.4(srvx@0.10.1))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
+ '@tanstack/router-utils': 1.158.0
+ '@tanstack/start-client-core': 1.159.4
+ '@tanstack/start-plugin-core': 1.159.5(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(crossws@0.4.4(srvx@0.10.1))(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+ '@tanstack/start-server-core': 1.159.4(crossws@0.4.4(srvx@0.10.1))
+ pathe: 2.0.3
+ react: 19.2.3
+ react-dom: 19.2.3(react@19.2.3)
+ vite: 7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
+ transitivePeerDependencies:
+ - '@rsbuild/core'
+ - crossws
+ - supports-color
+ - vite-plugin-solid
+ - webpack
+
+ '@tanstack/react-start@1.159.5(crossws@0.4.4(srvx@0.11.2))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
+ dependencies:
+ '@tanstack/react-router': 1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
+ '@tanstack/react-start-client': 1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
+ '@tanstack/react-start-server': 1.159.5(crossws@0.4.4(srvx@0.11.2))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
+ '@tanstack/router-utils': 1.158.0
+ '@tanstack/start-client-core': 1.159.4
+ '@tanstack/start-plugin-core': 1.159.5(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(crossws@0.4.4(srvx@0.11.2))(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+ '@tanstack/start-server-core': 1.159.4(crossws@0.4.4(srvx@0.11.2))
pathe: 2.0.3
react: 19.2.3
react-dom: 19.2.3(react@19.2.3)
@@ -10745,9 +11807,29 @@ snapshots:
tiny-invariant: 1.3.3
tiny-warning: 1.0.3
- '@tanstack/router-devtools-core@1.141.1(@tanstack/router-core@1.141.1)(csstype@3.2.3)(solid-js@1.9.10)':
+ '@tanstack/router-core@1.157.16':
dependencies:
- '@tanstack/router-core': 1.141.1
+ '@tanstack/history': 1.154.14
+ '@tanstack/store': 0.8.0
+ cookie-es: 2.0.0
+ seroval: 1.5.0
+ seroval-plugins: 1.5.0(seroval@1.5.0)
+ tiny-invariant: 1.3.3
+ tiny-warning: 1.0.3
+
+ '@tanstack/router-core@1.159.4':
+ dependencies:
+ '@tanstack/history': 1.154.14
+ '@tanstack/store': 0.8.0
+ cookie-es: 2.0.0
+ seroval: 1.5.0
+ seroval-plugins: 1.5.0(seroval@1.5.0)
+ tiny-invariant: 1.3.3
+ tiny-warning: 1.0.3
+
+ '@tanstack/router-devtools-core@1.141.1(@tanstack/router-core@1.159.4)(csstype@3.2.3)(solid-js@1.9.10)':
+ dependencies:
+ '@tanstack/router-core': 1.159.4
clsx: 2.1.1
goober: 2.1.18(csstype@3.2.3)
solid-js: 1.9.10
@@ -10755,6 +11837,15 @@ snapshots:
optionalDependencies:
csstype: 3.2.3
+ '@tanstack/router-devtools-core@1.159.4(@tanstack/router-core@1.159.4)(csstype@3.2.3)':
+ dependencies:
+ '@tanstack/router-core': 1.159.4
+ clsx: 2.1.1
+ goober: 2.1.18(csstype@3.2.3)
+ tiny-invariant: 1.3.3
+ optionalDependencies:
+ csstype: 3.2.3
+
'@tanstack/router-generator@1.131.50':
dependencies:
'@tanstack/router-core': 1.131.50
@@ -10781,14 +11872,27 @@ snapshots:
transitivePeerDependencies:
- supports-color
- '@tanstack/router-plugin@1.131.50(@tanstack/react-router@1.141.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
+ '@tanstack/router-generator@1.159.4':
+ dependencies:
+ '@tanstack/router-core': 1.159.4
+ '@tanstack/router-utils': 1.158.0
+ '@tanstack/virtual-file-routes': 1.154.7
+ prettier: 3.7.4
+ recast: 0.23.11
+ source-map: 0.7.6
+ tsx: 4.21.0
+ zod: 3.25.76
+ transitivePeerDependencies:
+ - supports-color
+
+ '@tanstack/router-plugin@1.131.50(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
dependencies:
'@babel/core': 7.28.5
'@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.28.5)
'@babel/plugin-syntax-typescript': 7.27.1(@babel/core@7.28.5)
'@babel/template': 7.27.2
'@babel/traverse': 7.28.5
- '@babel/types': 7.28.5
+ '@babel/types': 7.29.0
'@tanstack/router-core': 1.131.50
'@tanstack/router-generator': 1.131.50
'@tanstack/router-utils': 1.131.2
@@ -10798,13 +11902,13 @@ snapshots:
unplugin: 2.3.11
zod: 3.25.76
optionalDependencies:
- '@tanstack/react-router': 1.141.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
+ '@tanstack/react-router': 1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
vite: 7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
vite-plugin-solid: 2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
transitivePeerDependencies:
- supports-color
- '@tanstack/router-plugin@1.141.1(@tanstack/react-router@1.141.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
+ '@tanstack/router-plugin@1.141.1(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
dependencies:
'@babel/core': 7.28.5
'@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.28.5)
@@ -10821,22 +11925,71 @@ snapshots:
unplugin: 2.3.11
zod: 3.25.76
optionalDependencies:
- '@tanstack/react-router': 1.141.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
+ '@tanstack/react-router': 1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
+ vite: 7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
+ vite-plugin-solid: 2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+ transitivePeerDependencies:
+ - supports-color
+
+ '@tanstack/router-plugin@1.159.5(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
+ dependencies:
+ '@babel/core': 7.28.5
+ '@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.28.5)
+ '@babel/plugin-syntax-typescript': 7.27.1(@babel/core@7.28.5)
+ '@babel/template': 7.27.2
+ '@babel/traverse': 7.28.5
+ '@babel/types': 7.29.0
+ '@tanstack/router-core': 1.159.4
+ '@tanstack/router-generator': 1.159.4
+ '@tanstack/router-utils': 1.158.0
+ '@tanstack/virtual-file-routes': 1.154.7
+ chokidar: 3.6.0
+ unplugin: 2.3.11
+ zod: 3.25.76
+ optionalDependencies:
+ '@tanstack/react-router': 1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
vite: 7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
vite-plugin-solid: 2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
transitivePeerDependencies:
- supports-color
- '@tanstack/router-ssr-query-core@1.141.1(@tanstack/query-core@5.90.12)(@tanstack/router-core@1.141.1)':
+ '@tanstack/router-plugin@1.159.5(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
+ dependencies:
+ '@babel/core': 7.28.5
+ '@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.28.5)
+ '@babel/plugin-syntax-typescript': 7.27.1(@babel/core@7.28.5)
+ '@babel/template': 7.27.2
+ '@babel/traverse': 7.28.5
+ '@babel/types': 7.29.0
+ '@tanstack/router-core': 1.159.4
+ '@tanstack/router-generator': 1.159.4
+ '@tanstack/router-utils': 1.158.0
+ '@tanstack/virtual-file-routes': 1.154.7
+ chokidar: 3.6.0
+ unplugin: 2.3.11
+ zod: 3.25.76
+ optionalDependencies:
+ '@tanstack/react-router': 1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
+ vite: 7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
+ vite-plugin-solid: 2.11.10(solid-js@1.9.10)(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+ transitivePeerDependencies:
+ - supports-color
+
+ '@tanstack/router-ssr-query-core@1.141.1(@tanstack/query-core@5.90.12)(@tanstack/router-core@1.159.4)':
dependencies:
'@tanstack/query-core': 5.90.12
- '@tanstack/router-core': 1.141.1
+ '@tanstack/router-core': 1.159.4
+
+ '@tanstack/router-ssr-query-core@1.159.4(@tanstack/query-core@5.90.12)(@tanstack/router-core@1.159.4)':
+ dependencies:
+ '@tanstack/query-core': 5.90.12
+ '@tanstack/router-core': 1.159.4
'@tanstack/router-utils@1.131.2':
dependencies:
'@babel/core': 7.28.5
'@babel/generator': 7.28.5
- '@babel/parser': 7.28.5
+ '@babel/parser': 7.29.0
'@babel/preset-typescript': 7.28.5(@babel/core@7.28.5)
ansis: 4.2.0
diff: 8.0.2
@@ -10856,6 +12009,20 @@ snapshots:
transitivePeerDependencies:
- supports-color
+ '@tanstack/router-utils@1.158.0':
+ dependencies:
+ '@babel/core': 7.28.5
+ '@babel/generator': 7.28.5
+ '@babel/parser': 7.29.0
+ '@babel/types': 7.29.0
+ ansis: 4.2.0
+ babel-dead-code-elimination: 1.0.12
+ diff: 8.0.2
+ pathe: 2.0.3
+ tinyglobby: 0.2.15
+ transitivePeerDependencies:
+ - supports-color
+
'@tanstack/server-functions-plugin@1.131.2(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
dependencies:
'@babel/code-frame': 7.27.1
@@ -10864,7 +12031,7 @@ snapshots:
'@babel/plugin-syntax-typescript': 7.27.1(@babel/core@7.28.5)
'@babel/template': 7.27.2
'@babel/traverse': 7.28.5
- '@babel/types': 7.28.5
+ '@babel/types': 7.29.0
'@tanstack/directive-functions-plugin': 1.131.2(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
babel-dead-code-elimination: 1.0.10
tiny-invariant: 1.3.3
@@ -10902,20 +12069,20 @@ snapshots:
'@tanstack/query-core': 5.90.12
solid-js: 1.9.10
- '@tanstack/solid-router-devtools@1.141.1(@tanstack/router-core@1.141.1)(@tanstack/solid-router@1.141.1(solid-js@1.9.10))(csstype@3.2.3)(solid-js@1.9.10)':
+ '@tanstack/solid-router-devtools@1.141.1(@tanstack/router-core@1.159.4)(@tanstack/solid-router@1.141.1(solid-js@1.9.10))(csstype@3.2.3)(solid-js@1.9.10)':
dependencies:
- '@tanstack/router-devtools-core': 1.141.1(@tanstack/router-core@1.141.1)(csstype@3.2.3)(solid-js@1.9.10)
+ '@tanstack/router-devtools-core': 1.141.1(@tanstack/router-core@1.159.4)(csstype@3.2.3)(solid-js@1.9.10)
'@tanstack/solid-router': 1.141.1(solid-js@1.9.10)
solid-js: 1.9.10
optionalDependencies:
- '@tanstack/router-core': 1.141.1
+ '@tanstack/router-core': 1.159.4
transitivePeerDependencies:
- csstype
- '@tanstack/solid-router-ssr-query@1.141.1(@tanstack/query-core@5.90.12)(@tanstack/router-core@1.141.1)(@tanstack/solid-query@5.90.15(solid-js@1.9.10))(@tanstack/solid-router@1.141.1(solid-js@1.9.10))(eslint@9.39.2(jiti@2.6.1))(solid-js@1.9.10)(typescript@5.9.3)':
+ '@tanstack/solid-router-ssr-query@1.141.1(@tanstack/query-core@5.90.12)(@tanstack/router-core@1.159.4)(@tanstack/solid-query@5.90.15(solid-js@1.9.10))(@tanstack/solid-router@1.141.1(solid-js@1.9.10))(eslint@9.39.2(jiti@2.6.1))(solid-js@1.9.10)(typescript@5.9.3)':
dependencies:
'@tanstack/query-core': 5.90.12
- '@tanstack/router-ssr-query-core': 1.141.1(@tanstack/query-core@5.90.12)(@tanstack/router-core@1.141.1)
+ '@tanstack/router-ssr-query-core': 1.141.1(@tanstack/query-core@5.90.12)(@tanstack/router-core@1.159.4)
'@tanstack/solid-query': 5.90.15(solid-js@1.9.10)
'@tanstack/solid-router': 1.141.1(solid-js@1.9.10)
eslint-plugin-solid: 0.14.5(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)
@@ -10948,26 +12115,26 @@ snapshots:
tiny-invariant: 1.3.3
tiny-warning: 1.0.3
- '@tanstack/solid-start-server@1.141.1(solid-js@1.9.10)':
+ '@tanstack/solid-start-server@1.141.1(crossws@0.4.4(srvx@0.11.2))(solid-js@1.9.10)':
dependencies:
'@solidjs/meta': 0.29.4(solid-js@1.9.10)
'@tanstack/history': 1.141.0
'@tanstack/router-core': 1.141.1
'@tanstack/solid-router': 1.141.1(solid-js@1.9.10)
'@tanstack/start-client-core': 1.141.1
- '@tanstack/start-server-core': 1.141.1
+ '@tanstack/start-server-core': 1.141.1(crossws@0.4.4(srvx@0.11.2))
solid-js: 1.9.10
transitivePeerDependencies:
- crossws
- '@tanstack/solid-start@1.141.1(@tanstack/react-router@1.141.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(solid-js@1.9.10)(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
+ '@tanstack/solid-start@1.141.1(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(crossws@0.4.4(srvx@0.11.2))(solid-js@1.9.10)(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
dependencies:
'@tanstack/solid-router': 1.141.1(solid-js@1.9.10)
'@tanstack/solid-start-client': 1.141.1(solid-js@1.9.10)
- '@tanstack/solid-start-server': 1.141.1(solid-js@1.9.10)
+ '@tanstack/solid-start-server': 1.141.1(crossws@0.4.4(srvx@0.11.2))(solid-js@1.9.10)
'@tanstack/start-client-core': 1.141.1
- '@tanstack/start-plugin-core': 1.141.1(@tanstack/react-router@1.141.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
- '@tanstack/start-server-core': 1.141.1
+ '@tanstack/start-plugin-core': 1.141.1(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(crossws@0.4.4(srvx@0.11.2))(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+ '@tanstack/start-server-core': 1.141.1(crossws@0.4.4(srvx@0.11.2))
pathe: 2.0.3
solid-js: 1.9.10
vite: 7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
@@ -10984,10 +12151,10 @@ snapshots:
'@tanstack/store': 0.8.0
solid-js: 1.9.10
- '@tanstack/start-api-routes@1.120.19(@types/node@24.10.3)(db0@0.3.4)(ioredis@5.8.2)(jiti@2.6.1)(lightningcss@1.30.2)(rolldown@1.0.0-beta.53)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)':
+ '@tanstack/start-api-routes@1.120.19(@types/node@24.10.3)(crossws@0.4.4(srvx@0.11.2))(db0@0.3.4)(ioredis@5.8.2)(jiti@2.6.1)(lightningcss@1.30.2)(rolldown@1.0.0-beta.53)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)':
dependencies:
- '@tanstack/router-core': 1.141.1
- '@tanstack/start-server-core': 1.141.1
+ '@tanstack/router-core': 1.157.16
+ '@tanstack/start-server-core': 1.141.1(crossws@0.4.4(srvx@0.11.2))
vinxi: 0.5.3(@types/node@24.10.3)(db0@0.3.4)(ioredis@5.8.2)(jiti@2.6.1)(lightningcss@1.30.2)(rolldown@1.0.0-beta.53)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
transitivePeerDependencies:
- '@azure/app-configuration'
@@ -11051,14 +12218,23 @@ snapshots:
tiny-invariant: 1.3.3
tiny-warning: 1.0.3
- '@tanstack/start-config@1.120.20(@types/node@24.10.3)(db0@0.3.4)(ioredis@5.8.2)(jiti@2.6.1)(lightningcss@1.30.2)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(rolldown@1.0.0-beta.53)(terser@5.44.1)(tsx@4.21.0)(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(yaml@2.8.2)':
+ '@tanstack/start-client-core@1.159.4':
dependencies:
- '@tanstack/react-router': 1.141.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
- '@tanstack/react-start-plugin': 1.131.50(@tanstack/react-router@1.141.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(@vitejs/plugin-react@4.7.0(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(rolldown@1.0.0-beta.53)(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+ '@tanstack/router-core': 1.159.4
+ '@tanstack/start-fn-stubs': 1.154.7
+ '@tanstack/start-storage-context': 1.159.4
+ seroval: 1.5.0
+ tiny-invariant: 1.3.3
+ tiny-warning: 1.0.3
+
+ '@tanstack/start-config@1.120.20(@types/node@24.10.3)(crossws@0.4.4(srvx@0.11.2))(db0@0.3.4)(ioredis@5.8.2)(jiti@2.6.1)(lightningcss@1.30.2)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(rolldown@1.0.0-beta.53)(terser@5.44.1)(tsx@4.21.0)(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(yaml@2.8.2)':
+ dependencies:
+ '@tanstack/react-router': 1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
+ '@tanstack/react-start-plugin': 1.131.50(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(@vitejs/plugin-react@4.7.0(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(rolldown@1.0.0-beta.53)(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
'@tanstack/router-generator': 1.141.1
- '@tanstack/router-plugin': 1.141.1(@tanstack/react-router@1.141.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+ '@tanstack/router-plugin': 1.159.5(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
'@tanstack/server-functions-plugin': 1.141.0(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
- '@tanstack/start-server-functions-handler': 1.120.19
+ '@tanstack/start-server-functions-handler': 1.120.19(crossws@0.4.4(srvx@0.11.2))
'@vitejs/plugin-react': 4.7.0(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
import-meta-resolve: 4.2.0
nitropack: 2.12.9(rolldown@1.0.0-beta.53)
@@ -11117,14 +12293,16 @@ snapshots:
- xml2js
- yaml
- '@tanstack/start-plugin-core@1.131.50(@tanstack/react-router@1.141.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(rolldown@1.0.0-beta.53)(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
+ '@tanstack/start-fn-stubs@1.154.7': {}
+
+ '@tanstack/start-plugin-core@1.131.50(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(rolldown@1.0.0-beta.53)(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
dependencies:
'@babel/code-frame': 7.26.2
'@babel/core': 7.28.5
- '@babel/types': 7.28.5
+ '@babel/types': 7.29.0
'@tanstack/router-core': 1.131.50
'@tanstack/router-generator': 1.131.50
- '@tanstack/router-plugin': 1.131.50(@tanstack/react-router@1.141.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+ '@tanstack/router-plugin': 1.131.50(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
'@tanstack/router-utils': 1.131.2
'@tanstack/server-functions-plugin': 1.131.2(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
'@tanstack/start-server-core': 1.131.50
@@ -11175,7 +12353,7 @@ snapshots:
- webpack
- xml2js
- '@tanstack/start-plugin-core@1.141.1(@tanstack/react-router@1.141.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
+ '@tanstack/start-plugin-core@1.141.1(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(crossws@0.4.4(srvx@0.11.2))(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
dependencies:
'@babel/code-frame': 7.26.2
'@babel/core': 7.28.5
@@ -11183,11 +12361,11 @@ snapshots:
'@rolldown/pluginutils': 1.0.0-beta.40
'@tanstack/router-core': 1.141.1
'@tanstack/router-generator': 1.141.1
- '@tanstack/router-plugin': 1.141.1(@tanstack/react-router@1.141.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+ '@tanstack/router-plugin': 1.141.1(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
'@tanstack/router-utils': 1.141.0
'@tanstack/server-functions-plugin': 1.141.0(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
'@tanstack/start-client-core': 1.141.1
- '@tanstack/start-server-core': 1.141.1
+ '@tanstack/start-server-core': 1.141.1(crossws@0.4.4(srvx@0.11.2))
babel-dead-code-elimination: 1.0.10
cheerio: 1.1.2
exsolve: 1.0.8
@@ -11207,6 +12385,66 @@ snapshots:
- vite-plugin-solid
- webpack
+ '@tanstack/start-plugin-core@1.159.5(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(crossws@0.4.4(srvx@0.10.1))(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
+ dependencies:
+ '@babel/code-frame': 7.27.1
+ '@babel/core': 7.28.5
+ '@babel/types': 7.29.0
+ '@rolldown/pluginutils': 1.0.0-beta.40
+ '@tanstack/router-core': 1.159.4
+ '@tanstack/router-generator': 1.159.4
+ '@tanstack/router-plugin': 1.159.5(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+ '@tanstack/router-utils': 1.158.0
+ '@tanstack/start-client-core': 1.159.4
+ '@tanstack/start-server-core': 1.159.4(crossws@0.4.4(srvx@0.10.1))
+ cheerio: 1.1.2
+ exsolve: 1.0.8
+ pathe: 2.0.3
+ srvx: 0.11.2
+ tinyglobby: 0.2.15
+ ufo: 1.6.3
+ vite: 7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
+ vitefu: 1.1.1(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+ xmlbuilder2: 4.0.3
+ zod: 3.25.76
+ transitivePeerDependencies:
+ - '@rsbuild/core'
+ - '@tanstack/react-router'
+ - crossws
+ - supports-color
+ - vite-plugin-solid
+ - webpack
+
+ '@tanstack/start-plugin-core@1.159.5(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(crossws@0.4.4(srvx@0.11.2))(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
+ dependencies:
+ '@babel/code-frame': 7.27.1
+ '@babel/core': 7.28.5
+ '@babel/types': 7.29.0
+ '@rolldown/pluginutils': 1.0.0-beta.40
+ '@tanstack/router-core': 1.159.4
+ '@tanstack/router-generator': 1.159.4
+ '@tanstack/router-plugin': 1.159.5(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+ '@tanstack/router-utils': 1.158.0
+ '@tanstack/start-client-core': 1.159.4
+ '@tanstack/start-server-core': 1.159.4(crossws@0.4.4(srvx@0.11.2))
+ cheerio: 1.1.2
+ exsolve: 1.0.8
+ pathe: 2.0.3
+ srvx: 0.11.2
+ tinyglobby: 0.2.15
+ ufo: 1.6.3
+ vite: 7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
+ vitefu: 1.1.1(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+ xmlbuilder2: 4.0.3
+ zod: 3.25.76
+ transitivePeerDependencies:
+ - '@rsbuild/core'
+ - '@tanstack/react-router'
+ - crossws
+ - supports-color
+ - vite-plugin-solid
+ - webpack
+
'@tanstack/start-server-core@1.131.50':
dependencies:
'@tanstack/history': 1.131.2
@@ -11219,18 +12457,42 @@ snapshots:
tiny-warning: 1.0.3
unctx: 2.4.1
- '@tanstack/start-server-core@1.141.1':
+ '@tanstack/start-server-core@1.141.1(crossws@0.4.4(srvx@0.11.2))':
dependencies:
'@tanstack/history': 1.141.0
'@tanstack/router-core': 1.141.1
'@tanstack/start-client-core': 1.141.1
'@tanstack/start-storage-context': 1.141.1
- h3-v2: h3@2.0.0-beta.5
+ h3-v2: h3@2.0.0-beta.5(crossws@0.4.4(srvx@0.11.2))
seroval: 1.4.0
tiny-invariant: 1.3.3
transitivePeerDependencies:
- crossws
+ '@tanstack/start-server-core@1.159.4(crossws@0.4.4(srvx@0.10.1))':
+ dependencies:
+ '@tanstack/history': 1.154.14
+ '@tanstack/router-core': 1.159.4
+ '@tanstack/start-client-core': 1.159.4
+ '@tanstack/start-storage-context': 1.159.4
+ h3-v2: h3@2.0.1-rc.14(crossws@0.4.4(srvx@0.10.1))
+ seroval: 1.5.0
+ tiny-invariant: 1.3.3
+ transitivePeerDependencies:
+ - crossws
+
+ '@tanstack/start-server-core@1.159.4(crossws@0.4.4(srvx@0.11.2))':
+ dependencies:
+ '@tanstack/history': 1.154.14
+ '@tanstack/router-core': 1.159.4
+ '@tanstack/start-client-core': 1.159.4
+ '@tanstack/start-storage-context': 1.159.4
+ h3-v2: h3@2.0.1-rc.14(crossws@0.4.4(srvx@0.11.2))
+ seroval: 1.5.0
+ tiny-invariant: 1.3.3
+ transitivePeerDependencies:
+ - crossws
+
'@tanstack/start-server-functions-client@1.131.50(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
dependencies:
'@tanstack/server-functions-plugin': 1.131.2(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
@@ -11244,11 +12506,11 @@ snapshots:
'@tanstack/router-core': 1.131.50
'@tanstack/start-client-core': 1.131.50
- '@tanstack/start-server-functions-handler@1.120.19':
+ '@tanstack/start-server-functions-handler@1.120.19(crossws@0.4.4(srvx@0.11.2))':
dependencies:
- '@tanstack/router-core': 1.141.1
+ '@tanstack/router-core': 1.157.16
'@tanstack/start-client-core': 1.141.1
- '@tanstack/start-server-core': 1.141.1
+ '@tanstack/start-server-core': 1.141.1(crossws@0.4.4(srvx@0.11.2))
tiny-invariant: 1.3.3
transitivePeerDependencies:
- crossws
@@ -11261,11 +12523,11 @@ snapshots:
- supports-color
- vite
- '@tanstack/start-server-functions-ssr@1.120.19(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
+ '@tanstack/start-server-functions-ssr@1.120.19(crossws@0.4.4(srvx@0.11.2))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
dependencies:
'@tanstack/server-functions-plugin': 1.141.0(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
'@tanstack/start-client-core': 1.141.1
- '@tanstack/start-server-core': 1.141.1
+ '@tanstack/start-server-core': 1.141.1(crossws@0.4.4(srvx@0.11.2))
'@tanstack/start-server-functions-fetcher': 1.131.50
tiny-invariant: 1.3.3
transitivePeerDependencies:
@@ -11281,17 +12543,21 @@ snapshots:
dependencies:
'@tanstack/router-core': 1.141.1
- '@tanstack/start@1.120.20(@types/node@24.10.3)(db0@0.3.4)(ioredis@5.8.2)(jiti@2.6.1)(lightningcss@1.30.2)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(rolldown@1.0.0-beta.53)(terser@5.44.1)(tsx@4.21.0)(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(yaml@2.8.2)':
+ '@tanstack/start-storage-context@1.159.4':
+ dependencies:
+ '@tanstack/router-core': 1.159.4
+
+ '@tanstack/start@1.120.20(@types/node@24.10.3)(crossws@0.4.4(srvx@0.11.2))(db0@0.3.4)(ioredis@5.8.2)(jiti@2.6.1)(lightningcss@1.30.2)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(rolldown@1.0.0-beta.53)(terser@5.44.1)(tsx@4.21.0)(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(yaml@2.8.2)':
dependencies:
'@tanstack/react-start-client': 1.141.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
'@tanstack/react-start-router-manifest': 1.120.19(@types/node@24.10.3)(db0@0.3.4)(ioredis@5.8.2)(jiti@2.6.1)(lightningcss@1.30.2)(rolldown@1.0.0-beta.53)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
- '@tanstack/react-start-server': 1.141.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
- '@tanstack/start-api-routes': 1.120.19(@types/node@24.10.3)(db0@0.3.4)(ioredis@5.8.2)(jiti@2.6.1)(lightningcss@1.30.2)(rolldown@1.0.0-beta.53)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
- '@tanstack/start-config': 1.120.20(@types/node@24.10.3)(db0@0.3.4)(ioredis@5.8.2)(jiti@2.6.1)(lightningcss@1.30.2)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(rolldown@1.0.0-beta.53)(terser@5.44.1)(tsx@4.21.0)(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(yaml@2.8.2)
+ '@tanstack/react-start-server': 1.141.1(crossws@0.4.4(srvx@0.11.2))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
+ '@tanstack/start-api-routes': 1.120.19(@types/node@24.10.3)(crossws@0.4.4(srvx@0.11.2))(db0@0.3.4)(ioredis@5.8.2)(jiti@2.6.1)(lightningcss@1.30.2)(rolldown@1.0.0-beta.53)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
+ '@tanstack/start-config': 1.120.20(@types/node@24.10.3)(crossws@0.4.4(srvx@0.11.2))(db0@0.3.4)(ioredis@5.8.2)(jiti@2.6.1)(lightningcss@1.30.2)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(rolldown@1.0.0-beta.53)(terser@5.44.1)(tsx@4.21.0)(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(yaml@2.8.2)
'@tanstack/start-server-functions-client': 1.131.50(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
- '@tanstack/start-server-functions-handler': 1.120.19
+ '@tanstack/start-server-functions-handler': 1.120.19(crossws@0.4.4(srvx@0.11.2))
'@tanstack/start-server-functions-server': 1.131.2(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
- '@tanstack/start-server-functions-ssr': 1.120.19(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+ '@tanstack/start-server-functions-ssr': 1.120.19(crossws@0.4.4(srvx@0.11.2))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
transitivePeerDependencies:
- '@azure/app-configuration'
- '@azure/cosmos'
@@ -11360,10 +12626,12 @@ snapshots:
'@tanstack/virtual-file-routes@1.141.0': {}
- '@tanstack/vite-config@0.4.1(@types/node@24.10.3)(rollup@4.55.1)(typescript@5.9.3)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
+ '@tanstack/virtual-file-routes@1.154.7': {}
+
+ '@tanstack/vite-config@0.4.1(@types/node@24.10.3)(rollup@4.57.1)(typescript@5.9.3)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
dependencies:
- rollup-plugin-preserve-directives: 0.4.0(rollup@4.55.1)
- vite-plugin-dts: 4.2.3(@types/node@24.10.3)(rollup@4.55.1)(typescript@5.9.3)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+ rollup-plugin-preserve-directives: 0.4.0(rollup@4.57.1)
+ vite-plugin-dts: 4.2.3(@types/node@24.10.3)(rollup@4.57.1)(typescript@5.9.3)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
vite-plugin-externalize-deps: 0.10.0(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
vite-tsconfig-paths: 5.1.4(typescript@5.9.3)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
transitivePeerDependencies:
@@ -11702,6 +12970,25 @@ snapshots:
- rollup
- supports-color
+ '@vercel/nft@1.3.0(rollup@4.57.1)':
+ dependencies:
+ '@mapbox/node-pre-gyp': 2.0.3
+ '@rollup/pluginutils': 5.3.0(rollup@4.57.1)
+ acorn: 8.15.0
+ acorn-import-attributes: 1.9.5(acorn@8.15.0)
+ async-sema: 3.1.1
+ bindings: 1.5.0
+ estree-walker: 2.0.2
+ glob: 13.0.0
+ graceful-fs: 4.2.11
+ node-gyp-build: 4.8.4
+ picomatch: 4.0.3
+ resolve-from: 5.0.0
+ transitivePeerDependencies:
+ - encoding
+ - rollup
+ - supports-color
+
'@vinxi/listhen@1.5.6':
dependencies:
'@parcel/watcher': 2.5.1
@@ -11711,7 +12998,7 @@ snapshots:
consola: 3.4.2
defu: 6.1.4
get-port-please: 3.2.0
- h3: 1.13.0
+ h3: 1.15.5
http-shutdown: 1.2.2
jiti: 1.21.7
mlly: 1.8.0
@@ -11746,6 +13033,18 @@ snapshots:
transitivePeerDependencies:
- supports-color
+ '@vitejs/plugin-react@5.1.2(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
+ dependencies:
+ '@babel/core': 7.28.5
+ '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.28.5)
+ '@babel/plugin-transform-react-jsx-source': 7.27.1(@babel/core@7.28.5)
+ '@rolldown/pluginutils': 1.0.0-beta.53
+ '@types/babel__core': 7.20.5
+ react-refresh: 0.18.0
+ vite: 7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
+ transitivePeerDependencies:
+ - supports-color
+
'@vitejs/plugin-vue@6.0.3(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(vue@3.5.25(typescript@5.9.3))':
dependencies:
'@rolldown/pluginutils': 1.0.0-beta.53
@@ -11762,12 +13061,12 @@ snapshots:
dependencies:
'@bcoe/v8-coverage': 1.0.2
'@vitest/utils': 4.0.14
- ast-v8-to-istanbul: 0.3.8
+ ast-v8-to-istanbul: 0.3.11
istanbul-lib-coverage: 3.2.2
istanbul-lib-report: 3.0.1
istanbul-lib-source-maps: 5.0.6
istanbul-reports: 3.2.0
- magicast: 0.5.1
+ magicast: 0.5.2
obug: 2.1.1
std-env: 3.10.0
tinyrainbow: 3.0.3
@@ -11775,37 +13074,37 @@ snapshots:
transitivePeerDependencies:
- supports-color
- '@vitest/coverage-v8@4.0.14(vitest@4.0.17(@types/node@24.10.3)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
+ '@vitest/coverage-v8@4.0.14(vitest@4.0.18(@types/node@24.10.3)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
dependencies:
'@bcoe/v8-coverage': 1.0.2
'@vitest/utils': 4.0.14
- ast-v8-to-istanbul: 0.3.8
+ ast-v8-to-istanbul: 0.3.11
istanbul-lib-coverage: 3.2.2
istanbul-lib-report: 3.0.1
istanbul-lib-source-maps: 5.0.6
istanbul-reports: 3.2.0
- magicast: 0.5.1
+ magicast: 0.5.2
obug: 2.1.1
std-env: 3.10.0
tinyrainbow: 3.0.3
- vitest: 4.0.17(@types/node@24.10.3)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
+ vitest: 4.0.18(@types/node@24.10.3)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
transitivePeerDependencies:
- supports-color
- '@vitest/coverage-v8@4.0.14(vitest@4.0.17(@types/node@25.0.1)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
+ '@vitest/coverage-v8@4.0.14(vitest@4.0.18(@types/node@25.0.1)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
dependencies:
'@bcoe/v8-coverage': 1.0.2
'@vitest/utils': 4.0.14
- ast-v8-to-istanbul: 0.3.8
+ ast-v8-to-istanbul: 0.3.11
istanbul-lib-coverage: 3.2.2
istanbul-lib-report: 3.0.1
istanbul-lib-source-maps: 5.0.6
istanbul-reports: 3.2.0
- magicast: 0.5.1
+ magicast: 0.5.2
obug: 2.1.1
std-env: 3.10.0
tinyrainbow: 3.0.3
- vitest: 4.0.17(@types/node@25.0.1)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
+ vitest: 4.0.18(@types/node@25.0.1)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
transitivePeerDependencies:
- supports-color
@@ -11818,34 +13117,34 @@ snapshots:
chai: 6.2.1
tinyrainbow: 3.0.3
- '@vitest/expect@4.0.17':
+ '@vitest/expect@4.0.18':
dependencies:
'@standard-schema/spec': 1.1.0
'@types/chai': 5.2.3
- '@vitest/spy': 4.0.17
- '@vitest/utils': 4.0.17
+ '@vitest/spy': 4.0.18
+ '@vitest/utils': 4.0.18
chai: 6.2.2
tinyrainbow: 3.0.3
- '@vitest/mocker@4.0.15(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
+ '@vitest/mocker@4.0.15(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
dependencies:
'@vitest/spy': 4.0.15
estree-walker: 3.0.3
magic-string: 0.30.21
optionalDependencies:
- vite: 7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
+ vite: 7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
- '@vitest/mocker@4.0.17(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
+ '@vitest/mocker@4.0.18(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
dependencies:
- '@vitest/spy': 4.0.17
+ '@vitest/spy': 4.0.18
estree-walker: 3.0.3
magic-string: 0.30.21
optionalDependencies:
vite: 7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
- '@vitest/mocker@4.0.17(vite@7.3.1(@types/node@25.0.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
+ '@vitest/mocker@4.0.18(vite@7.3.1(@types/node@25.0.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
dependencies:
- '@vitest/spy': 4.0.17
+ '@vitest/spy': 4.0.18
estree-walker: 3.0.3
magic-string: 0.30.21
optionalDependencies:
@@ -11859,7 +13158,7 @@ snapshots:
dependencies:
tinyrainbow: 3.0.3
- '@vitest/pretty-format@4.0.17':
+ '@vitest/pretty-format@4.0.18':
dependencies:
tinyrainbow: 3.0.3
@@ -11868,9 +13167,9 @@ snapshots:
'@vitest/utils': 4.0.15
pathe: 2.0.3
- '@vitest/runner@4.0.17':
+ '@vitest/runner@4.0.18':
dependencies:
- '@vitest/utils': 4.0.17
+ '@vitest/utils': 4.0.18
pathe: 2.0.3
'@vitest/snapshot@4.0.15':
@@ -11879,15 +13178,15 @@ snapshots:
magic-string: 0.30.21
pathe: 2.0.3
- '@vitest/snapshot@4.0.17':
+ '@vitest/snapshot@4.0.18':
dependencies:
- '@vitest/pretty-format': 4.0.17
+ '@vitest/pretty-format': 4.0.18
magic-string: 0.30.21
pathe: 2.0.3
'@vitest/spy@4.0.15': {}
- '@vitest/spy@4.0.17': {}
+ '@vitest/spy@4.0.18': {}
'@vitest/utils@4.0.14':
dependencies:
@@ -11899,9 +13198,9 @@ snapshots:
'@vitest/pretty-format': 4.0.15
tinyrainbow: 3.0.3
- '@vitest/utils@4.0.17':
+ '@vitest/utils@4.0.18':
dependencies:
- '@vitest/pretty-format': 4.0.17
+ '@vitest/pretty-format': 4.0.18
tinyrainbow: 3.0.3
'@volar/language-core@2.4.15':
@@ -11930,7 +13229,7 @@ snapshots:
'@vue/compiler-core@3.5.25':
dependencies:
- '@babel/parser': 7.28.5
+ '@babel/parser': 7.29.0
'@vue/shared': 3.5.25
entities: 4.5.0
estree-walker: 2.0.2
@@ -12167,11 +13466,11 @@ snapshots:
dependencies:
tslib: 2.8.1
- ast-v8-to-istanbul@0.3.8:
+ ast-v8-to-istanbul@0.3.11:
dependencies:
'@jridgewell/trace-mapping': 0.3.31
estree-walker: 3.0.3
- js-tokens: 9.0.1
+ js-tokens: 10.0.0
async-sema@3.1.1: {}
@@ -12214,6 +13513,15 @@ snapshots:
transitivePeerDependencies:
- supports-color
+ babel-dead-code-elimination@1.0.12:
+ dependencies:
+ '@babel/core': 7.28.5
+ '@babel/parser': 7.29.0
+ '@babel/traverse': 7.28.5
+ '@babel/types': 7.29.0
+ transitivePeerDependencies:
+ - supports-color
+
babel-plugin-jsx-dom-expressions@0.40.3(@babel/core@7.28.5):
dependencies:
'@babel/core': 7.28.5
@@ -12330,7 +13638,7 @@ snapshots:
bytes@3.1.2: {}
- c12@3.3.2(magicast@0.5.1):
+ c12@3.3.2(magicast@0.5.2):
dependencies:
chokidar: 4.0.3
confbox: 0.2.2
@@ -12345,7 +13653,24 @@ snapshots:
pkg-types: 2.3.0
rc9: 2.1.2
optionalDependencies:
- magicast: 0.5.1
+ magicast: 0.5.2
+
+ c12@3.3.3(magicast@0.5.2):
+ dependencies:
+ chokidar: 5.0.0
+ confbox: 0.2.2
+ defu: 6.1.4
+ dotenv: 17.2.3
+ exsolve: 1.0.8
+ giget: 2.0.0
+ jiti: 2.6.1
+ ohash: 2.0.11
+ pathe: 2.0.3
+ perfect-debounce: 2.0.0
+ pkg-types: 2.3.0
+ rc9: 2.1.2
+ optionalDependencies:
+ magicast: 0.5.2
cac@6.7.14: {}
@@ -12569,6 +13894,15 @@ snapshots:
dependencies:
uncrypto: 0.1.3
+ crossws@0.4.4(srvx@0.10.1):
+ optionalDependencies:
+ srvx: 0.10.1
+
+ crossws@0.4.4(srvx@0.11.2):
+ optionalDependencies:
+ srvx: 0.11.2
+ optional: true
+
css-select@5.2.2:
dependencies:
boolbase: 1.0.0
@@ -12729,7 +14063,7 @@ snapshots:
dotenv-expand@11.0.7:
dependencies:
- dotenv: 16.4.7
+ dotenv: 16.6.1
dotenv@16.4.7: {}
@@ -12889,35 +14223,6 @@ snapshots:
'@esbuild/win32-ia32': 0.25.12
'@esbuild/win32-x64': 0.25.12
- esbuild@0.27.1:
- optionalDependencies:
- '@esbuild/aix-ppc64': 0.27.1
- '@esbuild/android-arm': 0.27.1
- '@esbuild/android-arm64': 0.27.1
- '@esbuild/android-x64': 0.27.1
- '@esbuild/darwin-arm64': 0.27.1
- '@esbuild/darwin-x64': 0.27.1
- '@esbuild/freebsd-arm64': 0.27.1
- '@esbuild/freebsd-x64': 0.27.1
- '@esbuild/linux-arm': 0.27.1
- '@esbuild/linux-arm64': 0.27.1
- '@esbuild/linux-ia32': 0.27.1
- '@esbuild/linux-loong64': 0.27.1
- '@esbuild/linux-mips64el': 0.27.1
- '@esbuild/linux-ppc64': 0.27.1
- '@esbuild/linux-riscv64': 0.27.1
- '@esbuild/linux-s390x': 0.27.1
- '@esbuild/linux-x64': 0.27.1
- '@esbuild/netbsd-arm64': 0.27.1
- '@esbuild/netbsd-x64': 0.27.1
- '@esbuild/openbsd-arm64': 0.27.1
- '@esbuild/openbsd-x64': 0.27.1
- '@esbuild/openharmony-arm64': 0.27.1
- '@esbuild/sunos-x64': 0.27.1
- '@esbuild/win32-arm64': 0.27.1
- '@esbuild/win32-ia32': 0.27.1
- '@esbuild/win32-x64': 0.27.1
-
esbuild@0.27.2:
optionalDependencies:
'@esbuild/aix-ppc64': 0.27.2
@@ -12947,6 +14252,35 @@ snapshots:
'@esbuild/win32-ia32': 0.27.2
'@esbuild/win32-x64': 0.27.2
+ esbuild@0.27.3:
+ optionalDependencies:
+ '@esbuild/aix-ppc64': 0.27.3
+ '@esbuild/android-arm': 0.27.3
+ '@esbuild/android-arm64': 0.27.3
+ '@esbuild/android-x64': 0.27.3
+ '@esbuild/darwin-arm64': 0.27.3
+ '@esbuild/darwin-x64': 0.27.3
+ '@esbuild/freebsd-arm64': 0.27.3
+ '@esbuild/freebsd-x64': 0.27.3
+ '@esbuild/linux-arm': 0.27.3
+ '@esbuild/linux-arm64': 0.27.3
+ '@esbuild/linux-ia32': 0.27.3
+ '@esbuild/linux-loong64': 0.27.3
+ '@esbuild/linux-mips64el': 0.27.3
+ '@esbuild/linux-ppc64': 0.27.3
+ '@esbuild/linux-riscv64': 0.27.3
+ '@esbuild/linux-s390x': 0.27.3
+ '@esbuild/linux-x64': 0.27.3
+ '@esbuild/netbsd-arm64': 0.27.3
+ '@esbuild/netbsd-x64': 0.27.3
+ '@esbuild/openbsd-arm64': 0.27.3
+ '@esbuild/openbsd-x64': 0.27.3
+ '@esbuild/openharmony-arm64': 0.27.3
+ '@esbuild/sunos-x64': 0.27.3
+ '@esbuild/win32-arm64': 0.27.3
+ '@esbuild/win32-ia32': 0.27.3
+ '@esbuild/win32-x64': 0.27.3
+
escalade@3.2.0: {}
escape-html@1.0.3: {}
@@ -13170,6 +14504,8 @@ snapshots:
events@3.3.0: {}
+ eventsource-parser@1.1.2: {}
+
execa@8.0.1:
dependencies:
cross-spawn: 7.0.6
@@ -13438,6 +14774,12 @@ snapshots:
package-json-from-dist: 1.0.1
path-scurry: 1.11.1
+ glob@13.0.0:
+ dependencies:
+ minimatch: 10.1.1
+ minipass: 7.1.2
+ path-scurry: 2.0.1
+
globals@14.0.0: {}
globals@15.15.0: {}
@@ -13462,6 +14804,15 @@ snapshots:
slash: 5.1.0
unicorn-magic: 0.3.0
+ globby@16.1.0:
+ dependencies:
+ '@sindresorhus/merge-streams': 4.0.0
+ fast-glob: 3.3.3
+ ignore: 7.0.5
+ is-path-inside: 4.0.0
+ slash: 5.1.0
+ unicorn-magic: 0.4.0
+
globrex@0.1.2: {}
goober@2.1.18(csstype@3.2.3):
@@ -13522,12 +14873,40 @@ snapshots:
ufo: 1.6.1
uncrypto: 0.1.3
- h3@2.0.0-beta.5:
+ h3@1.15.5:
+ dependencies:
+ cookie-es: 1.2.2
+ crossws: 0.3.5
+ defu: 6.1.4
+ destr: 2.0.5
+ iron-webcrypto: 1.2.1
+ node-mock-http: 1.0.4
+ radix3: 1.1.2
+ ufo: 1.6.3
+ uncrypto: 0.1.3
+
+ h3@2.0.0-beta.5(crossws@0.4.4(srvx@0.11.2)):
dependencies:
cookie-es: 2.0.0
fetchdts: 0.1.7
rou3: 0.7.12
srvx: 0.8.16
+ optionalDependencies:
+ crossws: 0.4.4(srvx@0.11.2)
+
+ h3@2.0.1-rc.14(crossws@0.4.4(srvx@0.10.1)):
+ dependencies:
+ rou3: 0.7.12
+ srvx: 0.11.2
+ optionalDependencies:
+ crossws: 0.4.4(srvx@0.10.1)
+
+ h3@2.0.1-rc.14(crossws@0.4.4(srvx@0.11.2)):
+ dependencies:
+ rou3: 0.7.12
+ srvx: 0.11.2
+ optionalDependencies:
+ crossws: 0.4.4(srvx@0.11.2)
happy-dom@20.0.11:
dependencies:
@@ -13775,6 +15154,20 @@ snapshots:
transitivePeerDependencies:
- supports-color
+ ioredis@5.9.2:
+ dependencies:
+ '@ioredis/commands': 1.5.0
+ cluster-key-slot: 1.1.2
+ debug: 4.4.3
+ denque: 2.1.0
+ lodash.defaults: 4.2.0
+ lodash.isarguments: 3.1.0
+ redis-errors: 1.2.0
+ redis-parser: 3.0.0
+ standard-as-callback: 2.1.0
+ transitivePeerDependencies:
+ - supports-color
+
ipaddr.js@1.9.1: {}
iron-webcrypto@1.2.1: {}
@@ -13858,6 +15251,8 @@ snapshots:
is-number@7.0.0: {}
+ is-path-inside@4.0.0: {}
+
is-plain-obj@4.1.0: {}
is-potential-custom-element-name@1.0.1: {}
@@ -13991,6 +15386,8 @@ snapshots:
js-cookie@3.0.5: {}
+ js-tokens@10.0.0: {}
+
js-tokens@4.0.0: {}
js-tokens@9.0.1: {}
@@ -14100,7 +15497,7 @@ snapshots:
smol-toml: 1.5.2
strip-json-comments: 5.0.3
typescript: 5.9.3
- zod: 4.2.1
+ zod: 4.3.6
knitwork@1.3.0: {}
@@ -14187,7 +15584,7 @@ snapshots:
crossws: 0.3.5
defu: 6.1.4
get-port-please: 3.2.0
- h3: 1.15.4
+ h3: 1.15.5
http-shutdown: 1.2.2
jiti: 2.6.1
mlly: 1.8.0
@@ -14198,10 +15595,10 @@ snapshots:
untun: 0.1.3
uqr: 0.1.2
- livekit-client@2.17.0(@types/dom-mediacapture-record@1.0.22):
+ livekit-client@2.17.2(@types/dom-mediacapture-record@1.0.22):
dependencies:
'@livekit/mutex': 1.1.1
- '@livekit/protocol': 1.42.2
+ '@livekit/protocol': 1.44.0
'@types/dom-mediacapture-record': 1.0.22
events: 3.3.0
jose: 6.1.3
@@ -14290,15 +15687,15 @@ snapshots:
dependencies:
'@jridgewell/sourcemap-codec': 1.5.5
- magicast@0.5.1:
+ magicast@0.5.2:
dependencies:
- '@babel/parser': 7.28.5
- '@babel/types': 7.28.5
+ '@babel/parser': 7.29.0
+ '@babel/types': 7.29.0
source-map-js: 1.2.1
make-dir@4.0.0:
dependencies:
- semver: 7.7.3
+ semver: 7.7.4
markdown-it@14.1.0:
dependencies:
@@ -14774,6 +16171,57 @@ snapshots:
negotiator@1.0.0: {}
+ nf3@0.3.10: {}
+
+ nitro@3.0.1-alpha.2(chokidar@5.0.0)(ioredis@5.9.2)(lru-cache@11.2.4)(rolldown@1.0.0-beta.53)(rollup@4.57.1)(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)):
+ dependencies:
+ consola: 3.4.2
+ crossws: 0.4.4(srvx@0.10.1)
+ db0: 0.3.4
+ h3: 2.0.1-rc.14(crossws@0.4.4(srvx@0.10.1))
+ jiti: 2.6.1
+ nf3: 0.3.10
+ ofetch: 2.0.0-alpha.3
+ ohash: 2.0.11
+ oxc-minify: 0.110.0
+ oxc-transform: 0.110.0
+ srvx: 0.10.1
+ undici: 7.21.0
+ unenv: 2.0.0-rc.24
+ unstorage: 2.0.0-alpha.5(chokidar@5.0.0)(db0@0.3.4)(ioredis@5.9.2)(lru-cache@11.2.4)(ofetch@2.0.0-alpha.3)
+ optionalDependencies:
+ rolldown: 1.0.0-beta.53
+ rollup: 4.57.1
+ vite: 7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
+ transitivePeerDependencies:
+ - '@azure/app-configuration'
+ - '@azure/cosmos'
+ - '@azure/data-tables'
+ - '@azure/identity'
+ - '@azure/keyvault-secrets'
+ - '@azure/storage-blob'
+ - '@capacitor/preferences'
+ - '@deno/kv'
+ - '@electric-sql/pglite'
+ - '@libsql/client'
+ - '@netlify/blobs'
+ - '@planetscale/database'
+ - '@upstash/redis'
+ - '@vercel/blob'
+ - '@vercel/functions'
+ - '@vercel/kv'
+ - aws4fetch
+ - better-sqlite3
+ - chokidar
+ - drizzle-orm
+ - idb-keyval
+ - ioredis
+ - lru-cache
+ - mongodb
+ - mysql2
+ - sqlite3
+ - uploadthing
+
nitropack@2.12.9(rolldown@1.0.0-beta.53):
dependencies:
'@cloudflare/kv-asset-handler': 0.4.1
@@ -14786,7 +16234,7 @@ snapshots:
'@rollup/plugin-terser': 0.4.4(rollup@4.53.3)
'@vercel/nft': 0.30.4(rollup@4.53.3)
archiver: 7.0.1
- c12: 3.3.2(magicast@0.5.1)
+ c12: 3.3.2(magicast@0.5.2)
chokidar: 4.0.3
citty: 0.1.6
compatx: 0.2.0
@@ -14814,7 +16262,7 @@ snapshots:
knitwork: 1.3.0
listhen: 1.9.0
magic-string: 0.30.21
- magicast: 0.5.1
+ magicast: 0.5.2
mime: 4.1.0
mlly: 1.8.0
node-fetch-native: 1.6.7
@@ -14876,6 +16324,108 @@ snapshots:
- supports-color
- uploadthing
+ nitropack@2.13.1(rolldown@1.0.0-beta.53):
+ dependencies:
+ '@cloudflare/kv-asset-handler': 0.4.2
+ '@rollup/plugin-alias': 6.0.0(rollup@4.57.1)
+ '@rollup/plugin-commonjs': 29.0.0(rollup@4.57.1)
+ '@rollup/plugin-inject': 5.0.5(rollup@4.57.1)
+ '@rollup/plugin-json': 6.1.0(rollup@4.57.1)
+ '@rollup/plugin-node-resolve': 16.0.3(rollup@4.57.1)
+ '@rollup/plugin-replace': 6.0.3(rollup@4.57.1)
+ '@rollup/plugin-terser': 0.4.4(rollup@4.57.1)
+ '@vercel/nft': 1.3.0(rollup@4.57.1)
+ archiver: 7.0.1
+ c12: 3.3.3(magicast@0.5.2)
+ chokidar: 5.0.0
+ citty: 0.1.6
+ compatx: 0.2.0
+ confbox: 0.2.2
+ consola: 3.4.2
+ cookie-es: 2.0.0
+ croner: 9.1.0
+ crossws: 0.3.5
+ db0: 0.3.4
+ defu: 6.1.4
+ destr: 2.0.5
+ dot-prop: 10.1.0
+ esbuild: 0.27.3
+ escape-string-regexp: 5.0.0
+ etag: 1.8.1
+ exsolve: 1.0.8
+ globby: 16.1.0
+ gzip-size: 7.0.0
+ h3: 1.15.5
+ hookable: 5.5.3
+ httpxy: 0.1.7
+ ioredis: 5.9.2
+ jiti: 2.6.1
+ klona: 2.0.6
+ knitwork: 1.3.0
+ listhen: 1.9.0
+ magic-string: 0.30.21
+ magicast: 0.5.2
+ mime: 4.1.0
+ mlly: 1.8.0
+ node-fetch-native: 1.6.7
+ node-mock-http: 1.0.4
+ ofetch: 1.5.1
+ ohash: 2.0.11
+ pathe: 2.0.3
+ perfect-debounce: 2.0.0
+ pkg-types: 2.3.0
+ pretty-bytes: 7.1.0
+ radix3: 1.1.2
+ rollup: 4.57.1
+ rollup-plugin-visualizer: 6.0.5(rolldown@1.0.0-beta.53)(rollup@4.57.1)
+ scule: 1.3.0
+ semver: 7.7.4
+ serve-placeholder: 2.0.2
+ serve-static: 2.2.1
+ source-map: 0.7.6
+ std-env: 3.10.0
+ ufo: 1.6.3
+ ultrahtml: 1.6.0
+ uncrypto: 0.1.3
+ unctx: 2.5.0
+ unenv: 2.0.0-rc.24
+ unimport: 5.6.0
+ unplugin-utils: 0.3.1
+ unstorage: 1.17.4(db0@0.3.4)(ioredis@5.9.2)
+ untyped: 2.0.0
+ unwasm: 0.5.3
+ youch: 4.1.0-beta.13
+ youch-core: 0.3.3
+ transitivePeerDependencies:
+ - '@azure/app-configuration'
+ - '@azure/cosmos'
+ - '@azure/data-tables'
+ - '@azure/identity'
+ - '@azure/keyvault-secrets'
+ - '@azure/storage-blob'
+ - '@capacitor/preferences'
+ - '@deno/kv'
+ - '@electric-sql/pglite'
+ - '@libsql/client'
+ - '@netlify/blobs'
+ - '@planetscale/database'
+ - '@upstash/redis'
+ - '@vercel/blob'
+ - '@vercel/functions'
+ - '@vercel/kv'
+ - aws4fetch
+ - bare-abort-controller
+ - better-sqlite3
+ - drizzle-orm
+ - encoding
+ - idb-keyval
+ - mysql2
+ - react-native-b4a
+ - rolldown
+ - sqlite3
+ - supports-color
+ - uploadthing
+
node-addon-api@7.1.1: {}
node-domexception@1.0.0: {}
@@ -15011,6 +16561,8 @@ snapshots:
node-fetch-native: 1.6.7
ufo: 1.6.1
+ ofetch@2.0.0-alpha.3: {}
+
ohash@1.1.6: {}
ohash@2.0.11: {}
@@ -15068,6 +16620,29 @@ snapshots:
outdent@0.5.0: {}
+ oxc-minify@0.110.0:
+ optionalDependencies:
+ '@oxc-minify/binding-android-arm-eabi': 0.110.0
+ '@oxc-minify/binding-android-arm64': 0.110.0
+ '@oxc-minify/binding-darwin-arm64': 0.110.0
+ '@oxc-minify/binding-darwin-x64': 0.110.0
+ '@oxc-minify/binding-freebsd-x64': 0.110.0
+ '@oxc-minify/binding-linux-arm-gnueabihf': 0.110.0
+ '@oxc-minify/binding-linux-arm-musleabihf': 0.110.0
+ '@oxc-minify/binding-linux-arm64-gnu': 0.110.0
+ '@oxc-minify/binding-linux-arm64-musl': 0.110.0
+ '@oxc-minify/binding-linux-ppc64-gnu': 0.110.0
+ '@oxc-minify/binding-linux-riscv64-gnu': 0.110.0
+ '@oxc-minify/binding-linux-riscv64-musl': 0.110.0
+ '@oxc-minify/binding-linux-s390x-gnu': 0.110.0
+ '@oxc-minify/binding-linux-x64-gnu': 0.110.0
+ '@oxc-minify/binding-linux-x64-musl': 0.110.0
+ '@oxc-minify/binding-openharmony-arm64': 0.110.0
+ '@oxc-minify/binding-wasm32-wasi': 0.110.0
+ '@oxc-minify/binding-win32-arm64-msvc': 0.110.0
+ '@oxc-minify/binding-win32-ia32-msvc': 0.110.0
+ '@oxc-minify/binding-win32-x64-msvc': 0.110.0
+
oxc-resolver@11.15.0:
optionalDependencies:
'@oxc-resolver/binding-android-arm-eabi': 11.15.0
@@ -15091,6 +16666,29 @@ snapshots:
'@oxc-resolver/binding-win32-ia32-msvc': 11.15.0
'@oxc-resolver/binding-win32-x64-msvc': 11.15.0
+ oxc-transform@0.110.0:
+ optionalDependencies:
+ '@oxc-transform/binding-android-arm-eabi': 0.110.0
+ '@oxc-transform/binding-android-arm64': 0.110.0
+ '@oxc-transform/binding-darwin-arm64': 0.110.0
+ '@oxc-transform/binding-darwin-x64': 0.110.0
+ '@oxc-transform/binding-freebsd-x64': 0.110.0
+ '@oxc-transform/binding-linux-arm-gnueabihf': 0.110.0
+ '@oxc-transform/binding-linux-arm-musleabihf': 0.110.0
+ '@oxc-transform/binding-linux-arm64-gnu': 0.110.0
+ '@oxc-transform/binding-linux-arm64-musl': 0.110.0
+ '@oxc-transform/binding-linux-ppc64-gnu': 0.110.0
+ '@oxc-transform/binding-linux-riscv64-gnu': 0.110.0
+ '@oxc-transform/binding-linux-riscv64-musl': 0.110.0
+ '@oxc-transform/binding-linux-s390x-gnu': 0.110.0
+ '@oxc-transform/binding-linux-x64-gnu': 0.110.0
+ '@oxc-transform/binding-linux-x64-musl': 0.110.0
+ '@oxc-transform/binding-openharmony-arm64': 0.110.0
+ '@oxc-transform/binding-wasm32-wasi': 0.110.0
+ '@oxc-transform/binding-win32-arm64-msvc': 0.110.0
+ '@oxc-transform/binding-win32-ia32-msvc': 0.110.0
+ '@oxc-transform/binding-win32-x64-msvc': 0.110.0
+
p-filter@2.1.0:
dependencies:
p-map: 2.1.0
@@ -15173,6 +16771,11 @@ snapshots:
lru-cache: 10.4.3
minipass: 7.1.2
+ path-scurry@2.0.1:
+ dependencies:
+ lru-cache: 11.2.4
+ minipass: 7.1.2
+
path-to-regexp@6.3.0: {}
path-to-regexp@8.3.0: {}
@@ -15497,6 +17100,8 @@ snapshots:
dependencies:
glob: 10.5.0
+ robot3@0.4.1: {}
+
rolldown-plugin-dts@0.18.3(oxc-resolver@11.15.0)(rolldown@1.0.0-beta.53)(typescript@5.9.3):
dependencies:
'@babel/generator': 7.28.5
@@ -15533,11 +17138,11 @@ snapshots:
'@rolldown/binding-win32-arm64-msvc': 1.0.0-beta.53
'@rolldown/binding-win32-x64-msvc': 1.0.0-beta.53
- rollup-plugin-preserve-directives@0.4.0(rollup@4.55.1):
+ rollup-plugin-preserve-directives@0.4.0(rollup@4.57.1):
dependencies:
- '@rollup/pluginutils': 5.3.0(rollup@4.55.1)
+ '@rollup/pluginutils': 5.3.0(rollup@4.57.1)
magic-string: 0.30.21
- rollup: 4.55.1
+ rollup: 4.57.1
rollup-plugin-visualizer@6.0.5(rolldown@1.0.0-beta.53)(rollup@4.53.3):
dependencies:
@@ -15549,6 +17154,16 @@ snapshots:
rolldown: 1.0.0-beta.53
rollup: 4.53.3
+ rollup-plugin-visualizer@6.0.5(rolldown@1.0.0-beta.53)(rollup@4.57.1):
+ dependencies:
+ open: 8.4.2
+ picomatch: 4.0.3
+ source-map: 0.7.6
+ yargs: 17.7.2
+ optionalDependencies:
+ rolldown: 1.0.0-beta.53
+ rollup: 4.57.1
+
rollup@4.53.3:
dependencies:
'@types/estree': 1.0.8
@@ -15577,35 +17192,35 @@ snapshots:
'@rollup/rollup-win32-x64-msvc': 4.53.3
fsevents: 2.3.3
- rollup@4.55.1:
+ rollup@4.57.1:
dependencies:
'@types/estree': 1.0.8
optionalDependencies:
- '@rollup/rollup-android-arm-eabi': 4.55.1
- '@rollup/rollup-android-arm64': 4.55.1
- '@rollup/rollup-darwin-arm64': 4.55.1
- '@rollup/rollup-darwin-x64': 4.55.1
- '@rollup/rollup-freebsd-arm64': 4.55.1
- '@rollup/rollup-freebsd-x64': 4.55.1
- '@rollup/rollup-linux-arm-gnueabihf': 4.55.1
- '@rollup/rollup-linux-arm-musleabihf': 4.55.1
- '@rollup/rollup-linux-arm64-gnu': 4.55.1
- '@rollup/rollup-linux-arm64-musl': 4.55.1
- '@rollup/rollup-linux-loong64-gnu': 4.55.1
- '@rollup/rollup-linux-loong64-musl': 4.55.1
- '@rollup/rollup-linux-ppc64-gnu': 4.55.1
- '@rollup/rollup-linux-ppc64-musl': 4.55.1
- '@rollup/rollup-linux-riscv64-gnu': 4.55.1
- '@rollup/rollup-linux-riscv64-musl': 4.55.1
- '@rollup/rollup-linux-s390x-gnu': 4.55.1
- '@rollup/rollup-linux-x64-gnu': 4.55.1
- '@rollup/rollup-linux-x64-musl': 4.55.1
- '@rollup/rollup-openbsd-x64': 4.55.1
- '@rollup/rollup-openharmony-arm64': 4.55.1
- '@rollup/rollup-win32-arm64-msvc': 4.55.1
- '@rollup/rollup-win32-ia32-msvc': 4.55.1
- '@rollup/rollup-win32-x64-gnu': 4.55.1
- '@rollup/rollup-win32-x64-msvc': 4.55.1
+ '@rollup/rollup-android-arm-eabi': 4.57.1
+ '@rollup/rollup-android-arm64': 4.57.1
+ '@rollup/rollup-darwin-arm64': 4.57.1
+ '@rollup/rollup-darwin-x64': 4.57.1
+ '@rollup/rollup-freebsd-arm64': 4.57.1
+ '@rollup/rollup-freebsd-x64': 4.57.1
+ '@rollup/rollup-linux-arm-gnueabihf': 4.57.1
+ '@rollup/rollup-linux-arm-musleabihf': 4.57.1
+ '@rollup/rollup-linux-arm64-gnu': 4.57.1
+ '@rollup/rollup-linux-arm64-musl': 4.57.1
+ '@rollup/rollup-linux-loong64-gnu': 4.57.1
+ '@rollup/rollup-linux-loong64-musl': 4.57.1
+ '@rollup/rollup-linux-ppc64-gnu': 4.57.1
+ '@rollup/rollup-linux-ppc64-musl': 4.57.1
+ '@rollup/rollup-linux-riscv64-gnu': 4.57.1
+ '@rollup/rollup-linux-riscv64-musl': 4.57.1
+ '@rollup/rollup-linux-s390x-gnu': 4.57.1
+ '@rollup/rollup-linux-x64-gnu': 4.57.1
+ '@rollup/rollup-linux-x64-musl': 4.57.1
+ '@rollup/rollup-openbsd-x64': 4.57.1
+ '@rollup/rollup-openharmony-arm64': 4.57.1
+ '@rollup/rollup-win32-arm64-msvc': 4.57.1
+ '@rollup/rollup-win32-ia32-msvc': 4.57.1
+ '@rollup/rollup-win32-x64-gnu': 4.57.1
+ '@rollup/rollup-win32-x64-msvc': 4.57.1
fsevents: 2.3.3
rou3@0.7.12: {}
@@ -15664,6 +17279,8 @@ snapshots:
semver@7.7.3: {}
+ semver@7.7.4: {}
+
send@0.19.0:
dependencies:
debug: 2.6.9
@@ -15710,10 +17327,16 @@ snapshots:
dependencies:
seroval: 1.4.0
+ seroval-plugins@1.5.0(seroval@1.5.0):
+ dependencies:
+ seroval: 1.5.0
+
seroval@1.3.2: {}
seroval@1.4.0: {}
+ seroval@1.5.0: {}
+
serve-placeholder@2.0.2:
dependencies:
defu: 6.1.4
@@ -15736,6 +17359,15 @@ snapshots:
transitivePeerDependencies:
- supports-color
+ serve-static@2.2.1:
+ dependencies:
+ encodeurl: 2.0.0
+ escape-html: 1.0.3
+ parseurl: 1.3.3
+ send: 1.2.0
+ transitivePeerDependencies:
+ - supports-color
+
set-cookie-parser@2.7.2: {}
set-function-length@1.2.2:
@@ -15897,6 +17529,10 @@ snapshots:
sprintf-js@1.0.3: {}
+ srvx@0.10.1: {}
+
+ srvx@0.11.2: {}
+
srvx@0.8.16: {}
stable-hash-x@0.2.0: {}
@@ -16184,7 +17820,7 @@ snapshots:
tsx@4.21.0:
dependencies:
- esbuild: 0.27.1
+ esbuild: 0.27.2
get-tsconfig: 4.13.0
optionalDependencies:
fsevents: 2.3.3
@@ -16246,6 +17882,8 @@ snapshots:
ufo@1.6.1: {}
+ ufo@1.6.3: {}
+
ultrahtml@1.6.0: {}
unconfig-core@7.4.2:
@@ -16262,6 +17900,13 @@ snapshots:
magic-string: 0.30.21
unplugin: 2.3.11
+ unctx@2.5.0:
+ dependencies:
+ acorn: 8.15.0
+ estree-walker: 3.0.3
+ magic-string: 0.30.21
+ unplugin: 2.3.11
+
undici-types@5.28.4: {}
undici-types@6.21.0: {}
@@ -16270,6 +17915,8 @@ snapshots:
undici@7.16.0: {}
+ undici@7.21.0: {}
+
unenv@1.10.0:
dependencies:
consola: 3.4.2
@@ -16284,6 +17931,8 @@ snapshots:
unicorn-magic@0.3.0: {}
+ unicorn-magic@0.4.0: {}
+
unified@11.0.5:
dependencies:
'@types/unist': 3.0.3
@@ -16311,6 +17960,23 @@ snapshots:
unplugin: 2.3.11
unplugin-utils: 0.3.1
+ unimport@5.6.0:
+ dependencies:
+ acorn: 8.15.0
+ escape-string-regexp: 5.0.0
+ estree-walker: 3.0.3
+ local-pkg: 1.1.2
+ magic-string: 0.30.21
+ mlly: 1.8.0
+ pathe: 2.0.3
+ picomatch: 4.0.3
+ pkg-types: 2.3.0
+ scule: 1.3.0
+ strip-literal: 3.1.0
+ tinyglobby: 0.2.15
+ unplugin: 2.3.11
+ unplugin-utils: 0.3.1
+
unist-util-find-after@5.0.0:
dependencies:
'@types/unist': 3.0.3
@@ -16403,7 +18069,7 @@ snapshots:
anymatch: 3.1.3
chokidar: 4.0.3
destr: 2.0.5
- h3: 1.15.4
+ h3: 1.15.5
lru-cache: 10.4.3
node-fetch-native: 1.6.7
ofetch: 1.5.1
@@ -16412,6 +18078,42 @@ snapshots:
db0: 0.3.4
ioredis: 5.8.2
+ unstorage@1.17.4(db0@0.3.4)(ioredis@5.8.2):
+ dependencies:
+ anymatch: 3.1.3
+ chokidar: 5.0.0
+ destr: 2.0.5
+ h3: 1.15.5
+ lru-cache: 11.2.4
+ node-fetch-native: 1.6.7
+ ofetch: 1.5.1
+ ufo: 1.6.3
+ optionalDependencies:
+ db0: 0.3.4
+ ioredis: 5.8.2
+
+ unstorage@1.17.4(db0@0.3.4)(ioredis@5.9.2):
+ dependencies:
+ anymatch: 3.1.3
+ chokidar: 5.0.0
+ destr: 2.0.5
+ h3: 1.15.5
+ lru-cache: 11.2.4
+ node-fetch-native: 1.6.7
+ ofetch: 1.5.1
+ ufo: 1.6.3
+ optionalDependencies:
+ db0: 0.3.4
+ ioredis: 5.9.2
+
+ unstorage@2.0.0-alpha.5(chokidar@5.0.0)(db0@0.3.4)(ioredis@5.9.2)(lru-cache@11.2.4)(ofetch@2.0.0-alpha.3):
+ optionalDependencies:
+ chokidar: 5.0.0
+ db0: 0.3.4
+ ioredis: 5.9.2
+ lru-cache: 11.2.4
+ ofetch: 2.0.0-alpha.3
+
untun@0.1.3:
dependencies:
citty: 0.1.6
@@ -16435,6 +18137,15 @@ snapshots:
pkg-types: 2.3.0
unplugin: 2.3.11
+ unwasm@0.5.3:
+ dependencies:
+ exsolve: 1.0.8
+ knitwork: 1.3.0
+ magic-string: 0.30.21
+ mlly: 1.8.0
+ pathe: 2.0.3
+ pkg-types: 2.3.0
+
update-browserslist-db@1.2.2(browserslist@4.28.1):
dependencies:
browserslist: 4.28.1
@@ -16503,7 +18214,7 @@ snapshots:
ufo: 1.6.1
unctx: 2.4.1
unenv: 1.10.0
- unstorage: 1.17.3(db0@0.3.4)(ioredis@5.8.2)
+ unstorage: 1.17.4(db0@0.3.4)(ioredis@5.8.2)
vite: 6.4.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
zod: 3.25.76
transitivePeerDependencies:
@@ -16551,10 +18262,10 @@ snapshots:
- xml2js
- yaml
- vite-plugin-dts@4.2.3(@types/node@24.10.3)(rollup@4.55.1)(typescript@5.9.3)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)):
+ vite-plugin-dts@4.2.3(@types/node@24.10.3)(rollup@4.57.1)(typescript@5.9.3)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)):
dependencies:
'@microsoft/api-extractor': 7.47.7(@types/node@24.10.3)
- '@rollup/pluginutils': 5.3.0(rollup@4.55.1)
+ '@rollup/pluginutils': 5.3.0(rollup@4.57.1)
'@volar/typescript': 2.4.27
'@vue/language-core': 2.1.6(typescript@5.9.3)
compare-versions: 6.1.1
@@ -16600,6 +18311,20 @@ snapshots:
transitivePeerDependencies:
- supports-color
+ vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)):
+ dependencies:
+ '@babel/core': 7.28.5
+ '@types/babel__core': 7.20.5
+ babel-preset-solid: 1.9.10(@babel/core@7.28.5)(solid-js@1.9.10)
+ merge-anything: 5.1.7
+ solid-js: 1.9.10
+ solid-refresh: 0.6.3(solid-js@1.9.10)
+ vite: 7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
+ vitefu: 1.1.1(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+ transitivePeerDependencies:
+ - supports-color
+ optional: true
+
vite-tsconfig-paths@5.1.4(typescript@5.9.3)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)):
dependencies:
debug: 4.4.3
@@ -16611,13 +18336,24 @@ snapshots:
- supports-color
- typescript
+ vite-tsconfig-paths@5.1.4(typescript@5.9.3)(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)):
+ dependencies:
+ debug: 4.4.3
+ globrex: 0.1.2
+ tsconfck: 3.1.6(typescript@5.9.3)
+ optionalDependencies:
+ vite: 7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
+ transitivePeerDependencies:
+ - supports-color
+ - typescript
+
vite@6.4.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2):
dependencies:
esbuild: 0.25.12
fdir: 6.5.0(picomatch@4.0.3)
picomatch: 4.0.3
postcss: 8.5.6
- rollup: 4.53.3
+ rollup: 4.57.1
tinyglobby: 0.2.15
optionalDependencies:
'@types/node': 24.10.3
@@ -16664,11 +18400,11 @@ snapshots:
vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2):
dependencies:
- esbuild: 0.27.2
+ esbuild: 0.27.3
fdir: 6.5.0(picomatch@4.0.3)
picomatch: 4.0.3
postcss: 8.5.6
- rollup: 4.55.1
+ rollup: 4.57.1
tinyglobby: 0.2.15
optionalDependencies:
'@types/node': 24.10.3
@@ -16681,11 +18417,11 @@ snapshots:
vite@7.3.1(@types/node@25.0.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2):
dependencies:
- esbuild: 0.27.2
+ esbuild: 0.27.3
fdir: 6.5.0(picomatch@4.0.3)
picomatch: 4.0.3
postcss: 8.5.6
- rollup: 4.55.1
+ rollup: 4.57.1
tinyglobby: 0.2.15
optionalDependencies:
'@types/node': 25.0.1
@@ -16704,10 +18440,14 @@ snapshots:
optionalDependencies:
vite: 7.2.7(@types/node@25.0.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
+ vitefu@1.1.1(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)):
+ optionalDependencies:
+ vite: 7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
+
vitest@4.0.15(@types/node@24.10.3)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2):
dependencies:
'@vitest/expect': 4.0.15
- '@vitest/mocker': 4.0.15(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+ '@vitest/mocker': 4.0.15(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
'@vitest/pretty-format': 4.0.15
'@vitest/runner': 4.0.15
'@vitest/snapshot': 4.0.15
@@ -16724,7 +18464,7 @@ snapshots:
tinyexec: 1.0.2
tinyglobby: 0.2.15
tinyrainbow: 3.0.3
- vite: 7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
+ vite: 7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
why-is-node-running: 2.3.0
optionalDependencies:
'@types/node': 24.10.3
@@ -16743,15 +18483,15 @@ snapshots:
- tsx
- yaml
- vitest@4.0.17(@types/node@24.10.3)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2):
+ vitest@4.0.18(@types/node@24.10.3)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2):
dependencies:
- '@vitest/expect': 4.0.17
- '@vitest/mocker': 4.0.17(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
- '@vitest/pretty-format': 4.0.17
- '@vitest/runner': 4.0.17
- '@vitest/snapshot': 4.0.17
- '@vitest/spy': 4.0.17
- '@vitest/utils': 4.0.17
+ '@vitest/expect': 4.0.18
+ '@vitest/mocker': 4.0.18(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+ '@vitest/pretty-format': 4.0.18
+ '@vitest/runner': 4.0.18
+ '@vitest/snapshot': 4.0.18
+ '@vitest/spy': 4.0.18
+ '@vitest/utils': 4.0.18
es-module-lexer: 1.7.0
expect-type: 1.3.0
magic-string: 0.30.21
@@ -16782,15 +18522,15 @@ snapshots:
- tsx
- yaml
- vitest@4.0.17(@types/node@25.0.1)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2):
+ vitest@4.0.18(@types/node@25.0.1)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2):
dependencies:
- '@vitest/expect': 4.0.17
- '@vitest/mocker': 4.0.17(vite@7.3.1(@types/node@25.0.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
- '@vitest/pretty-format': 4.0.17
- '@vitest/runner': 4.0.17
- '@vitest/snapshot': 4.0.17
- '@vitest/spy': 4.0.17
- '@vitest/utils': 4.0.17
+ '@vitest/expect': 4.0.18
+ '@vitest/mocker': 4.0.18(vite@7.3.1(@types/node@25.0.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+ '@vitest/pretty-format': 4.0.18
+ '@vitest/runner': 4.0.18
+ '@vitest/snapshot': 4.0.18
+ '@vitest/spy': 4.0.18
+ '@vitest/utils': 4.0.18
es-module-lexer: 1.7.0
expect-type: 1.3.0
magic-string: 0.30.21
@@ -17031,4 +18771,6 @@ snapshots:
zod@4.2.1: {}
+ zod@4.3.6: {}
+
zwitch@2.0.4: {}
From dbb9cab24fdaf3da8929e8a35303c34c13a2c77c Mon Sep 17 00:00:00 2001
From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com>
Date: Thu, 19 Feb 2026 18:21:02 +0000
Subject: [PATCH 20/31] ci: apply automated fixes
---
.../ts-react-chat/src/lib/realtime-tools.ts | 146 +++++++++++-------
.../src/routes/api.realtime-token.ts | 13 +-
.../ts-react-chat/src/routes/realtime.tsx | 40 ++---
.../ai-client/src/realtime-client.ts | 51 +++---
packages/typescript/ai-elevenlabs/README.md | 2 +-
.../typescript/ai-elevenlabs/src/index.ts | 5 +-
.../ai-elevenlabs/src/realtime/adapter.ts | 4 +-
packages/typescript/ai-openai/src/index.ts | 5 +-
.../ai-openai/src/realtime/adapter.ts | 35 +++--
.../ai-openai/src/realtime/token.ts | 11 +-
.../ai-react/src/use-realtime-chat.ts | 35 ++++-
11 files changed, 208 insertions(+), 139 deletions(-)
diff --git a/examples/ts-react-chat/src/lib/realtime-tools.ts b/examples/ts-react-chat/src/lib/realtime-tools.ts
index 2cf28d7bd3..e19c52226e 100644
--- a/examples/ts-react-chat/src/lib/realtime-tools.ts
+++ b/examples/ts-react-chat/src/lib/realtime-tools.ts
@@ -4,9 +4,13 @@ import { z } from 'zod'
// Tool to get current time - useful for voice assistants
export const getCurrentTimeToolDef = toolDefinition({
name: 'getCurrentTime',
- description: 'Get the current date and time. Use this when the user asks what time it is or the current date.',
+ description:
+ 'Get the current date and time. Use this when the user asks what time it is or the current date.',
inputSchema: z.object({
- timezone: z.string().optional().describe('Optional timezone like "America/New_York" or "Europe/London"'),
+ timezone: z
+ .string()
+ .optional()
+ .describe('Optional timezone like "America/New_York" or "Europe/London"'),
}),
outputSchema: z.object({
time: z.string(),
@@ -18,9 +22,14 @@ export const getCurrentTimeToolDef = toolDefinition({
// Tool to get weather - common voice assistant use case
export const getWeatherToolDef = toolDefinition({
name: 'getWeather',
- description: 'Get the current weather for a location. Use this when the user asks about the weather.',
+ description:
+ 'Get the current weather for a location. Use this when the user asks about the weather.',
inputSchema: z.object({
- location: z.string().describe('The city and state/country, e.g. "San Francisco, CA" or "London, UK"'),
+ location: z
+ .string()
+ .describe(
+ 'The city and state/country, e.g. "San Francisco, CA" or "London, UK"',
+ ),
}),
outputSchema: z.object({
location: z.string(),
@@ -34,7 +43,8 @@ export const getWeatherToolDef = toolDefinition({
// Tool to set a reminder - demonstrates user interaction
export const setReminderToolDef = toolDefinition({
name: 'setReminder',
- description: 'Set a reminder for the user. Use this when the user asks to be reminded about something.',
+ description:
+ 'Set a reminder for the user. Use this when the user asks to be reminded about something.',
inputSchema: z.object({
message: z.string().describe('What to remind the user about'),
inMinutes: z.number().describe('How many minutes from now to remind'),
@@ -49,44 +59,50 @@ export const setReminderToolDef = toolDefinition({
// Tool to search knowledge base - useful for assistants with specific knowledge
export const searchKnowledgeToolDef = toolDefinition({
name: 'searchKnowledge',
- description: 'Search a knowledge base for information. Use this to find specific facts or documentation.',
+ description:
+ 'Search a knowledge base for information. Use this to find specific facts or documentation.',
inputSchema: z.object({
query: z.string().describe('The search query'),
}),
outputSchema: z.object({
- results: z.array(z.object({
- title: z.string(),
- snippet: z.string(),
- })),
+ results: z.array(
+ z.object({
+ title: z.string(),
+ snippet: z.string(),
+ }),
+ ),
}),
})
// Client-side implementation of getCurrentTime
-export const getCurrentTimeClient = getCurrentTimeToolDef.client(({ timezone }) => {
- const now = new Date()
- const tz = timezone || Intl.DateTimeFormat().resolvedOptions().timeZone
-
- return {
- time: now.toLocaleTimeString('en-US', { timeZone: tz }),
- date: now.toLocaleDateString('en-US', {
- weekday: 'long',
- year: 'numeric',
- month: 'long',
- day: 'numeric',
- timeZone: tz,
- }),
- timezone: tz,
- }
-})
+export const getCurrentTimeClient = getCurrentTimeToolDef.client(
+ ({ timezone }) => {
+ const now = new Date()
+ const tz = timezone || Intl.DateTimeFormat().resolvedOptions().timeZone
+
+ return {
+ time: now.toLocaleTimeString('en-US', { timeZone: tz }),
+ date: now.toLocaleDateString('en-US', {
+ weekday: 'long',
+ year: 'numeric',
+ month: 'long',
+ day: 'numeric',
+ timeZone: tz,
+ }),
+ timezone: tz,
+ }
+ },
+)
// Client-side implementation of getWeather (mock data for demo)
export const getWeatherClient = getWeatherToolDef.client(({ location }) => {
// Mock weather data for demo purposes
const conditions = ['Sunny', 'Partly Cloudy', 'Cloudy', 'Rainy', 'Snowy']
- const randomCondition = conditions[Math.floor(Math.random() * conditions.length)]!
+ const randomCondition =
+ conditions[Math.floor(Math.random() * conditions.length)]!
const randomTemp = Math.floor(Math.random() * 30) + 50 // 50-80°F
const randomHumidity = Math.floor(Math.random() * 50) + 30 // 30-80%
-
+
return {
location,
temperature: randomTemp,
@@ -97,40 +113,50 @@ export const getWeatherClient = getWeatherToolDef.client(({ location }) => {
})
// Client-side implementation of setReminder
-export const setReminderClient = setReminderToolDef.client(({ message, inMinutes }) => {
- const remindAt = new Date(Date.now() + inMinutes * 60 * 1000)
-
- // In a real app, you'd schedule a notification here
- console.log(`[Reminder] Will remind about "${message}" at ${remindAt.toLocaleTimeString()}`)
-
- // For demo purposes, show an alert after the specified time
- setTimeout(() => {
- alert(`Reminder: ${message}`)
- }, inMinutes * 60 * 1000)
-
- return {
- success: true,
- message: `Reminder set: "${message}"`,
- remindAt: remindAt.toLocaleTimeString(),
- }
-})
+export const setReminderClient = setReminderToolDef.client(
+ ({ message, inMinutes }) => {
+ const remindAt = new Date(Date.now() + inMinutes * 60 * 1000)
+
+ // In a real app, you'd schedule a notification here
+ console.log(
+ `[Reminder] Will remind about "${message}" at ${remindAt.toLocaleTimeString()}`,
+ )
+
+ // For demo purposes, show an alert after the specified time
+ setTimeout(
+ () => {
+ alert(`Reminder: ${message}`)
+ },
+ inMinutes * 60 * 1000,
+ )
+
+ return {
+ success: true,
+ message: `Reminder set: "${message}"`,
+ remindAt: remindAt.toLocaleTimeString(),
+ }
+ },
+)
// Client-side implementation of searchKnowledge (mock data for demo)
-export const searchKnowledgeClient = searchKnowledgeToolDef.client(({ query }) => {
- // Mock search results for demo
- const mockResults = [
- {
- title: `Result for: ${query}`,
- snippet: `This is a mock search result for the query "${query}". In a real application, this would return actual search results from a knowledge base.`,
- },
- {
- title: 'Additional Information',
- snippet: 'More relevant information would appear here based on your search query.',
- },
- ]
-
- return { results: mockResults }
-})
+export const searchKnowledgeClient = searchKnowledgeToolDef.client(
+ ({ query }) => {
+ // Mock search results for demo
+ const mockResults = [
+ {
+ title: `Result for: ${query}`,
+ snippet: `This is a mock search result for the query "${query}". In a real application, this would return actual search results from a knowledge base.`,
+ },
+ {
+ title: 'Additional Information',
+ snippet:
+ 'More relevant information would appear here based on your search query.',
+ },
+ ]
+
+ return { results: mockResults }
+ },
+)
// Export all client tools as an array for easy use
export const realtimeClientTools = [
diff --git a/examples/ts-react-chat/src/routes/api.realtime-token.ts b/examples/ts-react-chat/src/routes/api.realtime-token.ts
index c9367ad196..807623ecf5 100644
--- a/examples/ts-react-chat/src/routes/api.realtime-token.ts
+++ b/examples/ts-react-chat/src/routes/api.realtime-token.ts
@@ -13,9 +13,13 @@ import * as z from 'zod'
type Provider = 'openai' | 'elevenlabs'
// Convert tool definitions to OpenAI's format using Zod's native toJSONSchema
-function toolDefToOpenAI(toolDef: { name: string; description: string; inputSchema?: unknown }) {
+function toolDefToOpenAI(toolDef: {
+ name: string
+ description: string
+ inputSchema?: unknown
+}) {
let parameters: Record = { type: 'object', properties: {} }
-
+
if (toolDef.inputSchema) {
// Use Zod's native toJSONSchema for Zod v4+
const jsonSchema = z.toJSONSchema(toolDef.inputSchema as z.ZodType)
@@ -23,7 +27,7 @@ function toolDefToOpenAI(toolDef: { name: string; description: string; inputSche
const { $schema, ...rest } = jsonSchema as Record
parameters = rest
}
-
+
return {
type: 'function' as const,
name: toolDef.name,
@@ -85,7 +89,8 @@ Be friendly and engaging!`,
if (!agentId) {
return new Response(
JSON.stringify({
- error: 'ElevenLabs agent ID is required. Set ELEVENLABS_AGENT_ID or pass agentId in request body.',
+ error:
+ 'ElevenLabs agent ID is required. Set ELEVENLABS_AGENT_ID or pass agentId in request body.',
}),
{
status: 400,
diff --git a/examples/ts-react-chat/src/routes/realtime.tsx b/examples/ts-react-chat/src/routes/realtime.tsx
index 4be974a8fc..107b839e57 100644
--- a/examples/ts-react-chat/src/routes/realtime.tsx
+++ b/examples/ts-react-chat/src/routes/realtime.tsx
@@ -14,11 +14,11 @@ const PROVIDER_OPTIONS: Array<{ value: Provider; label: string }> = [
]
// Sparkline component to visualize audio waveform
-function AudioSparkline({
- getData,
+function AudioSparkline({
+ getData,
color,
label,
-}: {
+}: {
getData: () => Uint8Array
color: string
label: string
@@ -49,20 +49,20 @@ function AudioSparkline({
// Sample the data to fit the canvas width
const step = Math.max(1, Math.floor(data.length / width))
-
+
for (let i = 0; i < width; i++) {
const dataIndex = Math.min(i * step, data.length - 1)
const value = data[dataIndex] ?? 128
// Convert 0-255 to canvas height (128 is center/silence)
- const y = height - ((value / 255) * height)
-
+ const y = height - (value / 255) * height
+
if (i === 0) {
ctx!.moveTo(i, y)
} else {
ctx!.lineTo(i, y)
}
}
-
+
ctx!.stroke()
// Draw center line (silence level)
@@ -89,10 +89,10 @@ function AudioSparkline({
return (
{label}
-
@@ -105,7 +105,8 @@ function RealtimePage() {
const messagesEndRef = useRef(null)
// Get the appropriate adapter based on provider
- const adapter = provider === 'openai' ? openaiRealtime() : elevenlabsRealtime()
+ const adapter =
+ provider === 'openai' ? openaiRealtime() : elevenlabsRealtime()
const {
status,
@@ -284,7 +285,8 @@ function RealtimePage() {
Click "Start Conversation" to begin talking with the AI
- Try asking: "What time is it?" or "What's the weather in San Francisco?"
+ Try asking: "What time is it?" or "What's the weather in San
+ Francisco?"
)}
@@ -388,9 +390,9 @@ function RealtimePage() {
{Math.round(inputLevel * 100)}%
-
@@ -406,9 +408,9 @@ function RealtimePage() {
{Math.round(outputLevel * 100)}%
-
diff --git a/packages/typescript/ai-client/src/realtime-client.ts b/packages/typescript/ai-client/src/realtime-client.ts
index f49d4d25ea..170a4d5855 100644
--- a/packages/typescript/ai-client/src/realtime-client.ts
+++ b/packages/typescript/ai-client/src/realtime-client.ts
@@ -61,7 +61,7 @@ export class RealtimeClient {
constructor(options: RealtimeClientOptions) {
this.instanceId = ++clientIdCounter
console.log(`[RealtimeClient #${this.instanceId}] Created`)
-
+
this.options = {
autoPlayback: true,
autoCapture: true,
@@ -102,7 +102,10 @@ export class RealtimeClient {
// Connect via adapter
this.connection = await this.options.adapter.connect(this.token)
- console.log(`[RealtimeClient #${this.instanceId}] Connection established:`, !!this.connection)
+ console.log(
+ `[RealtimeClient #${this.instanceId}] Connection established:`,
+ !!this.connection,
+ )
// Subscribe to connection events
this.subscribeToConnectionEvents()
@@ -251,7 +254,10 @@ export class RealtimeClient {
/** Get audio visualization data */
get audio(): AudioVisualization | null {
- console.log(`[RealtimeClient #${this.instanceId}] audio getter, connection:`, !!this.connection)
+ console.log(
+ `[RealtimeClient #${this.instanceId}] audio getter, connection:`,
+ !!this.connection,
+ )
return this.connection?.getAudioVisualization() ?? null
}
@@ -381,25 +387,28 @@ export class RealtimeClient {
// Tool calls
this.unsubscribers.push(
- this.connection.on('tool_call', async ({ toolCallId, toolName, input }) => {
- const tool = this.clientTools.get(toolName)
- if (tool?.execute) {
- try {
- const output = await tool.execute(input)
- this.connection?.sendToolResult(
- toolCallId,
- typeof output === 'string' ? output : JSON.stringify(output),
- )
- } catch (error) {
- const errMsg =
- error instanceof Error ? error.message : String(error)
- this.connection?.sendToolResult(
- toolCallId,
- JSON.stringify({ error: errMsg }),
- )
+ this.connection.on(
+ 'tool_call',
+ async ({ toolCallId, toolName, input }) => {
+ const tool = this.clientTools.get(toolName)
+ if (tool?.execute) {
+ try {
+ const output = await tool.execute(input)
+ this.connection?.sendToolResult(
+ toolCallId,
+ typeof output === 'string' ? output : JSON.stringify(output),
+ )
+ } catch (error) {
+ const errMsg =
+ error instanceof Error ? error.message : String(error)
+ this.connection?.sendToolResult(
+ toolCallId,
+ JSON.stringify({ error: errMsg }),
+ )
+ }
}
- }
- }),
+ },
+ ),
)
// Message complete
diff --git a/packages/typescript/ai-elevenlabs/README.md b/packages/typescript/ai-elevenlabs/README.md
index 6f85bb8ede..71b0d979b5 100644
--- a/packages/typescript/ai-elevenlabs/README.md
+++ b/packages/typescript/ai-elevenlabs/README.md
@@ -31,7 +31,7 @@ import { RealtimeClient } from '@tanstack/ai-client'
import { elevenlabsRealtime } from '@tanstack/ai-elevenlabs'
const client = new RealtimeClient({
- getToken: () => fetch('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/api/realtime-token').then(r => r.json()),
+ getToken: () => fetch('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/api/realtime-token').then((r) => r.json()),
adapter: elevenlabsRealtime(),
})
diff --git a/packages/typescript/ai-elevenlabs/src/index.ts b/packages/typescript/ai-elevenlabs/src/index.ts
index 14702a1daa..8f3789e848 100644
--- a/packages/typescript/ai-elevenlabs/src/index.ts
+++ b/packages/typescript/ai-elevenlabs/src/index.ts
@@ -2,10 +2,7 @@
// ElevenLabs Realtime (Voice) Adapters
// ============================================================================
-export {
- elevenlabsRealtimeToken,
- elevenlabsRealtime,
-} from './realtime/index'
+export { elevenlabsRealtimeToken, elevenlabsRealtime } from './realtime/index'
export type {
ElevenLabsRealtimeTokenOptions,
diff --git a/packages/typescript/ai-elevenlabs/src/realtime/adapter.ts b/packages/typescript/ai-elevenlabs/src/realtime/adapter.ts
index 39ee355bdb..dfe33d3182 100644
--- a/packages/typescript/ai-elevenlabs/src/realtime/adapter.ts
+++ b/packages/typescript/ai-elevenlabs/src/realtime/adapter.ts
@@ -51,7 +51,9 @@ async function createElevenLabsConnection(
_options: ElevenLabsRealtimeOptions,
): Promise {
const eventHandlers = new Map>>()
- let conversation: Awaited> | null = null
+ let conversation: Awaited<
+ ReturnType
+ > | null = null
let messageIdCounter = 0
// Empty arrays for when visualization isn't available
diff --git a/packages/typescript/ai-openai/src/index.ts b/packages/typescript/ai-openai/src/index.ts
index 2b7916a37e..afadc4529c 100644
--- a/packages/typescript/ai-openai/src/index.ts
+++ b/packages/typescript/ai-openai/src/index.ts
@@ -105,10 +105,7 @@ export type { OpenAIClientConfig } from './utils/client'
// Realtime (Voice) Adapters
// ============================================================================
-export {
- openaiRealtimeToken,
- openaiRealtime,
-} from './realtime/index'
+export { openaiRealtimeToken, openaiRealtime } from './realtime/index'
export type {
OpenAIRealtimeVoice,
diff --git a/packages/typescript/ai-openai/src/realtime/adapter.ts b/packages/typescript/ai-openai/src/realtime/adapter.ts
index 6245a3c05c..e25a7dbd30 100644
--- a/packages/typescript/ai-openai/src/realtime/adapter.ts
+++ b/packages/typescript/ai-openai/src/realtime/adapter.ts
@@ -8,10 +8,7 @@ import type {
RealtimeStatus,
RealtimeToken,
} from '@tanstack/ai'
-import type {
- RealtimeAdapter,
- RealtimeConnection,
-} from '@tanstack/ai-client'
+import type { RealtimeAdapter, RealtimeConnection } from '@tanstack/ai-client'
import type { OpenAIRealtimeOptions } from './types'
const OPENAI_REALTIME_URL = 'https://api.openai.com/v1/realtime'
@@ -175,7 +172,10 @@ async function createWebRTCConnection(
await pc.setRemoteDescription({ type: 'answer', sdp: answerSdp })
// Set up input audio analysis now that we have the stream
- console.log('[Realtime] Setting up input audio analysis, localStream:', localStream)
+ console.log(
+ '[Realtime] Setting up input audio analysis, localStream:',
+ localStream,
+ )
setupInputAudioAnalysis(localStream)
console.log('[Realtime] Input analyser created:', inputAnalyser)
@@ -224,7 +224,11 @@ async function createWebRTCConnection(
case 'response.audio_transcript.delta': {
const delta = event.delta as string
- emit('transcript', { role: 'assistant', transcript: delta, isFinal: false })
+ emit('transcript', {
+ role: 'assistant',
+ transcript: delta,
+ isFinal: false,
+ })
break
}
@@ -264,8 +268,10 @@ async function createWebRTCConnection(
// Emit message complete if we have a current message
if (currentMessageId) {
const response = event.response as Record
- const output = response.output as Array> | undefined
-
+ const output = response.output as
+ | Array>
+ | undefined
+
const message: RealtimeMessage = {
id: currentMessageId,
role: 'assistant',
@@ -511,14 +517,19 @@ async function createWebRTCConnection(
getAudioVisualization(): AudioVisualization {
// Log analyser state for debugging
- console.log('[Realtime] getAudioVisualization called, inputAnalyser:', !!inputAnalyser, 'outputAnalyser:', !!outputAnalyser)
-
+ console.log(
+ '[Realtime] getAudioVisualization called, inputAnalyser:',
+ !!inputAnalyser,
+ 'outputAnalyser:',
+ !!outputAnalyser,
+ )
+
// Helper to calculate audio level from time domain data
// Uses peak amplitude which is more responsive for voice audio meters
function calculateLevel(analyser: AnalyserNode): number {
const data = new Uint8Array(analyser.fftSize)
analyser.getByteTimeDomainData(data)
-
+
// Find peak deviation from center (128 is silence)
// This is more responsive than RMS for voice level meters
let maxDeviation = 0
@@ -528,7 +539,7 @@ async function createWebRTCConnection(
maxDeviation = deviation
}
}
-
+
// Normalize to 0-1 range (max deviation is 128)
// Scale by 1.5x so that ~66% amplitude reads as full scale
// This provides good visual feedback without pegging too early
diff --git a/packages/typescript/ai-openai/src/realtime/token.ts b/packages/typescript/ai-openai/src/realtime/token.ts
index e09d8c7668..832adaa79c 100644
--- a/packages/typescript/ai-openai/src/realtime/token.ts
+++ b/packages/typescript/ai-openai/src/realtime/token.ts
@@ -126,11 +126,12 @@ export function openaiRealtimeToken(
voice: sessionData.voice,
instructions: sessionData.instructions,
tools,
- vadMode: sessionData.turn_detection?.type === 'semantic_vad'
- ? 'semantic'
- : sessionData.turn_detection?.type === 'server_vad'
- ? 'server'
- : 'manual',
+ vadMode:
+ sessionData.turn_detection?.type === 'semantic_vad'
+ ? 'semantic'
+ : sessionData.turn_detection?.type === 'server_vad'
+ ? 'server'
+ : 'manual',
vadConfig: sessionData.turn_detection
? {
threshold: sessionData.turn_detection.threshold,
diff --git a/packages/typescript/ai-react/src/use-realtime-chat.ts b/packages/typescript/ai-react/src/use-realtime-chat.ts
index 3434db607d..9d3f0af41c 100644
--- a/packages/typescript/ai-react/src/use-realtime-chat.ts
+++ b/packages/typescript/ai-react/src/use-realtime-chat.ts
@@ -1,7 +1,14 @@
import { useCallback, useEffect, useRef, useState } from 'react'
import { RealtimeClient } from '@tanstack/ai-client'
-import type { RealtimeMessage, RealtimeMode, RealtimeStatus } from '@tanstack/ai'
-import type { UseRealtimeChatOptions, UseRealtimeChatReturn } from './realtime-types'
+import type {
+ RealtimeMessage,
+ RealtimeMode,
+ RealtimeStatus,
+} from '@tanstack/ai'
+import type {
+ UseRealtimeChatOptions,
+ UseRealtimeChatReturn,
+} from './realtime-types'
// Empty frequency data for when client is not connected
const emptyFrequencyData = new Uint8Array(128)
@@ -54,8 +61,12 @@ export function useRealtimeChat(
const [status, setStatus] = useState('idle')
const [mode, setMode] = useState('idle')
const [messages, setMessages] = useState>([])
- const [pendingUserTranscript, setPendingUserTranscript] = useState(null)
- const [pendingAssistantTranscript, setPendingAssistantTranscript] = useState(null)
+ const [pendingUserTranscript, setPendingUserTranscript] = useState<
+ string | null
+ >(null)
+ const [pendingAssistantTranscript, setPendingAssistantTranscript] = useState<
+ string | null
+ >(null)
const [error, setError] = useState(null)
const [inputLevel, setInputLevel] = useState(0)
const [outputLevel, setOutputLevel] = useState(0)
@@ -181,19 +192,27 @@ export function useRealtimeChat(
// Audio visualization
const getInputFrequencyData = useCallback(() => {
- return clientRef.current?.audio?.getInputFrequencyData() ?? emptyFrequencyData
+ return (
+ clientRef.current?.audio?.getInputFrequencyData() ?? emptyFrequencyData
+ )
}, [])
const getOutputFrequencyData = useCallback(() => {
- return clientRef.current?.audio?.getOutputFrequencyData() ?? emptyFrequencyData
+ return (
+ clientRef.current?.audio?.getOutputFrequencyData() ?? emptyFrequencyData
+ )
}, [])
const getInputTimeDomainData = useCallback(() => {
- return clientRef.current?.audio?.getInputTimeDomainData() ?? emptyTimeDomainData
+ return (
+ clientRef.current?.audio?.getInputTimeDomainData() ?? emptyTimeDomainData
+ )
}, [])
const getOutputTimeDomainData = useCallback(() => {
- return clientRef.current?.audio?.getOutputTimeDomainData() ?? emptyTimeDomainData
+ return (
+ clientRef.current?.audio?.getOutputTimeDomainData() ?? emptyTimeDomainData
+ )
}, [])
// VAD mode control
From 8dbdddff746fb0a1c6af6294a79dd63af1f5fdd5 Mon Sep 17 00:00:00 2001
From: Jack Herrington
Date: Thu, 5 Mar 2026 17:55:12 -0800
Subject: [PATCH 21/31] API improved
---
docs/architecture/realtime-chat.md | 112 +++++++--
.../src/routes/api.realtime-token.ts | 62 -----
.../ts-react-chat/src/routes/realtime.tsx | 13 +-
.../ai-client/src/realtime-client.ts | 43 ++--
.../ai-client/src/realtime-types.ts | 10 +
.../ai-openai/src/realtime/adapter.ts | 70 ++++--
.../ai-openai/src/realtime/token.ts | 84 +------
.../ai-openai/src/realtime/types.ts | 27 ---
.../typescript/ai-react/src/realtime-types.ts | 10 +
.../ai-react/src/use-realtime-chat.ts | 2 +
pnpm-lock.yaml | 227 +++++++++---------
11 files changed, 330 insertions(+), 330 deletions(-)
diff --git a/docs/architecture/realtime-chat.md b/docs/architecture/realtime-chat.md
index 305029c3ec..fcf15a0f0e 100644
--- a/docs/architecture/realtime-chat.md
+++ b/docs/architecture/realtime-chat.md
@@ -25,6 +25,7 @@ The realtime chat system provides a vendor-neutral, type-safe abstraction for vo
│ │ - Messages & transcripts │ │
│ │ - Audio visualization (levels, waveforms) │ │
│ │ - Control methods (connect, disconnect, interrupt) │ │
+│ │ - Client-side tool configuration │ │
│ └─────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
│
@@ -35,6 +36,7 @@ The realtime chat system provides a vendor-neutral, type-safe abstraction for vo
│ │ RealtimeClient │ │
│ │ - Connection lifecycle management │ │
│ │ - Token refresh scheduling │ │
+│ │ - Client-side session configuration (tools, voice, etc) │ │
│ │ - Event subscription & dispatch │ │
│ │ - Tool execution coordination │ │
│ └─────────────────────────────────────────────────────────┘ │
@@ -48,6 +50,7 @@ The realtime chat system provides a vendor-neutral, type-safe abstraction for vo
│ │ - WebRTC connection │ │ - SDK wrapper │ │
│ │ - Audio I/O │ │ - Signed URL auth │ │
│ │ - Event mapping │ │ - Event mapping │ │
+│ │ - Session updates │ │ │ │
│ └──────────────────────┘ └──────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
│
@@ -58,6 +61,8 @@ The realtime chat system provides a vendor-neutral, type-safe abstraction for vo
│ │ Token Generation Endpoint │ │
│ │ - openaiRealtimeToken() - ephemeral client secrets │ │
│ │ - elevenlabsRealtimeToken() - signed URLs │ │
+│ │ (Minimal config: model only — session config is │ │
+│ │ applied client-side via session.update) │ │
│ └─────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
```
@@ -66,7 +71,7 @@ The realtime chat system provides a vendor-neutral, type-safe abstraction for vo
### 1. Token Adapters (Server-Side)
-Token adapters generate short-lived credentials for client-side connections. This keeps API keys secure on the server.
+Token adapters generate short-lived credentials for client-side connections. This keeps API keys secure on the server. The token endpoint sends **only the model** to the provider; all other session configuration (instructions, voice, tools, VAD) is applied client-side.
```typescript
// Server-side token endpoint
@@ -76,13 +81,6 @@ import { openaiRealtimeToken } from '@tanstack/ai-openai'
const token = await realtimeToken({
adapter: openaiRealtimeToken({
model: 'gpt-4o-realtime-preview',
- voice: 'alloy',
- instructions: 'You are a helpful assistant.',
- turnDetection: {
- type: 'server_vad',
- threshold: 0.5,
- silence_duration_ms: 500,
- },
}),
})
```
@@ -104,6 +102,7 @@ Client adapters handle the actual connection to provider APIs, managing:
- Audio capture and playback
- Event translation to common format
- Audio visualization data
+- Session configuration updates (tools, instructions, voice, VAD)
```typescript
// Client-side adapter usage
@@ -114,15 +113,18 @@ const adapter = openaiRealtime({
})
```
+**Data Channel Readiness:** The OpenAI adapter waits for the WebRTC data channel to be fully open before returning the connection. If `updateSession()` is called before the channel is ready, events are queued and flushed once the channel opens.
+
### 3. RealtimeClient
The `RealtimeClient` class manages the connection lifecycle:
- **Connection Management**: Connect, disconnect, reconnect
- **Token Refresh**: Automatically refreshes tokens before expiry
+- **Session Configuration**: Applies client-side config (instructions, voice, tools, VAD) via `session.update` after connecting
- **Event Handling**: Subscribes to adapter events and dispatches to callbacks
- **State Management**: Tracks status, mode, messages, transcripts
-- **Tool Execution**: Coordinates client-side tool calls
+- **Tool Execution**: Looks up client-side tools by name, executes them, and sends results back to the provider
### 4. useRealtimeChat Hook
@@ -155,6 +157,9 @@ const {
} = useRealtimeChat({
getToken: () => fetch('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/api/realtime-token').then(r => r.json()),
adapter: openaiRealtime(),
+ instructions: 'You are a helpful voice assistant.',
+ voice: 'alloy',
+ tools: myClientTools,
})
```
@@ -169,7 +174,7 @@ sequenceDiagram
participant OpenAI
Browser->>Server: POST /api/realtime-token
- Server->>OpenAI: POST /v1/realtime/sessions
+ Server->>OpenAI: POST /v1/realtime/sessions (model only)
OpenAI-->>Server: { client_secret, expires_at }
Server-->>Browser: RealtimeToken
@@ -183,8 +188,12 @@ sequenceDiagram
OpenAI-->>Browser: SDP answer
Browser->>Browser: setRemoteDescription()
+ Browser->>Browser: Wait for data channel open
Note over Browser,OpenAI: WebRTC connection established
+ Browser->>OpenAI: session.update (tools, instructions, voice, VAD)
+ OpenAI-->>Browser: session.updated (confirms config)
+
Browser->>OpenAI: Audio via WebRTC
OpenAI-->>Browser: Audio + events via WebRTC
```
@@ -209,14 +218,82 @@ sequenceDiagram
ElevenLabs-->>Browser: Audio + events via SDK
```
+## Client-Side Tool Calling
+
+Tools are defined once using `toolDefinition()` and instantiated for client-side execution with `.client()`. When the AI model invokes a tool, the `RealtimeClient` executes it locally in the browser and sends the result back to the provider.
+
+### Tool Definition
+
+```typescript
+import { toolDefinition } from '@tanstack/ai'
+import { z } from 'zod'
+
+const getWeatherToolDef = toolDefinition({
+ name: 'getWeather',
+ description: 'Get the current weather for a location.',
+ inputSchema: z.object({
+ location: z.string().describe('City and state/country'),
+ }),
+ outputSchema: z.object({
+ location: z.string(),
+ temperature: z.number(),
+ condition: z.string(),
+ }),
+})
+
+// Create client-side implementation
+const getWeatherClient = getWeatherToolDef.client(({ location }) => ({
+ location,
+ temperature: 72,
+ condition: 'Sunny',
+}))
+```
+
+### Tool Call Flow
+
+```mermaid
+sequenceDiagram
+ participant User
+ participant Browser as Browser (RealtimeClient)
+ participant OpenAI
+
+ User->>Browser: "What's the weather in London?"
+ Browser->>OpenAI: Audio via WebRTC
+
+ OpenAI->>Browser: response.function_call_arguments.done
+ Note right of OpenAI: { name: "getWeather", arguments: '{"location":"London"}' }
+
+ Browser->>Browser: Look up tool in clientTools Map
+ Browser->>Browser: Execute tool.execute(input)
+ Browser->>OpenAI: conversation.item.create (function_call_output)
+ Browser->>OpenAI: response.create
+
+ OpenAI->>Browser: response.audio_transcript.delta
+ Note right of OpenAI: "The weather in London is 72°F and sunny!"
+ OpenAI->>Browser: response.done
+ Browser->>User: Display message + play audio
+```
+
+### Session Configuration
+
+When connecting, the `RealtimeClient` calls `applySessionConfig()` which sends a `session.update` event to the provider with:
+
+- **instructions** — System prompt for the assistant
+- **voice** — Voice to use for audio output (e.g., `'alloy'`)
+- **tools** — Array of tool definitions with JSON Schema parameters, plus `tool_choice: 'auto'`
+- **turn_detection** — VAD configuration (server_vad, semantic_vad, or manual)
+- **input_audio_transcription** — Enables user speech transcription (e.g., Whisper)
+
+Tool schemas are converted from Zod (or any Standard JSON Schema compliant library) to JSON Schema using `convertSchemaToJsonSchema()` before being sent to the provider.
+
## Audio Visualization
The system provides real-time audio visualization through the `AudioVisualization` interface:
```typescript
interface AudioVisualization {
- inputLevel: number // 0-1 normalized input volume (RMS)
- outputLevel: number // 0-1 normalized output volume (RMS)
+ inputLevel: number // 0-1 normalized input volume
+ outputLevel: number // 0-1 normalized output volume
getInputFrequencyData(): Uint8Array // FFT frequency bins
getOutputFrequencyData(): Uint8Array
getInputTimeDomainData(): Uint8Array // Raw waveform samples
@@ -228,7 +305,7 @@ interface AudioVisualization {
The OpenAI adapter uses Web Audio API `AnalyserNode` for visualization:
- `fftSize: 2048` for high-resolution analysis
-- RMS (Root Mean Square) calculation for accurate volume levels
+- Peak amplitude detection for responsive volume meters
- Separate analysers for input (microphone) and output (AI voice)
## Event System
@@ -256,15 +333,16 @@ Adapters emit standardized events:
- [x] Real-time transcription display
- [x] Audio visualization (levels, waveforms)
- [x] Interrupt capability
+- [x] Client-side tool calling (define, execute, return results)
+- [x] Client-side session configuration (instructions, voice, tools, VAD)
- [x] React hook (`useRealtimeChat`)
-- [x] Demo application at `/realtime` route
+- [x] Demo application at `/realtime` route with tool examples
### Known Limitations
- **Device Selection**: Currently uses system default audio devices. Custom device selection not yet implemented.
- **ElevenLabs SDK**: Using `@11labs/client@0.2.0` which has limited TypeScript support.
- **Push-to-Talk**: Manual VAD mode implemented but not exposed in demo UI.
-- **Tool Calling**: Framework supports tools but demo doesn't showcase them.
### Demo Application
@@ -276,8 +354,9 @@ The `examples/ts-react-chat` application includes a realtime voice chat demo at
- Conversation mode indicator (Listening/Thinking/Speaking)
- Message history with transcripts
- Audio level meters
-- Waveform visualization (debug mode)
+- Waveform visualization
- Interrupt button during AI speech
+- Client-side tool execution (getCurrentTime, getWeather, setReminder, searchKnowledge)
**Required Environment Variables:**
```bash
@@ -311,3 +390,4 @@ ELEVENLABS_AGENT_ID=... # Optional, for ElevenLabs
### Demo Application
- `examples/ts-react-chat/src/routes/realtime.tsx` - Demo UI component
- `examples/ts-react-chat/src/routes/api.realtime-token.ts` - Token API endpoint
+- `examples/ts-react-chat/src/lib/realtime-tools.ts` - Client-side tool definitions
diff --git a/examples/ts-react-chat/src/routes/api.realtime-token.ts b/examples/ts-react-chat/src/routes/api.realtime-token.ts
index 807623ecf5..62fb08d8d2 100644
--- a/examples/ts-react-chat/src/routes/api.realtime-token.ts
+++ b/examples/ts-react-chat/src/routes/api.realtime-token.ts
@@ -2,40 +2,9 @@ import { createFileRoute } from '@tanstack/react-router'
import { realtimeToken } from '@tanstack/ai'
import { openaiRealtimeToken } from '@tanstack/ai-openai'
import { elevenlabsRealtimeToken } from '@tanstack/ai-elevenlabs'
-import {
- getCurrentTimeToolDef,
- getWeatherToolDef,
- setReminderToolDef,
- searchKnowledgeToolDef,
-} from '@/lib/realtime-tools'
-import * as z from 'zod'
type Provider = 'openai' | 'elevenlabs'
-// Convert tool definitions to OpenAI's format using Zod's native toJSONSchema
-function toolDefToOpenAI(toolDef: {
- name: string
- description: string
- inputSchema?: unknown
-}) {
- let parameters: Record = { type: 'object', properties: {} }
-
- if (toolDef.inputSchema) {
- // Use Zod's native toJSONSchema for Zod v4+
- const jsonSchema = z.toJSONSchema(toolDef.inputSchema as z.ZodType)
- // Remove $schema as OpenAI doesn't need it
- const { $schema, ...rest } = jsonSchema as Record
- parameters = rest
- }
-
- return {
- type: 'function' as const,
- name: toolDef.name,
- description: toolDef.description,
- parameters,
- }
-}
-
export const Route = createFileRoute('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/api/realtime-token')({
server: {
handlers: {
@@ -47,40 +16,9 @@ export const Route = createFileRoute('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/api/realtime-token')({
let token
if (provider === 'openai') {
- // Convert tool definitions to OpenAI format
- const tools = [
- toolDefToOpenAI(getCurrentTimeToolDef),
- toolDefToOpenAI(getWeatherToolDef),
- toolDefToOpenAI(setReminderToolDef),
- toolDefToOpenAI(searchKnowledgeToolDef),
- ]
-
token = await realtimeToken({
adapter: openaiRealtimeToken({
model: 'gpt-4o-realtime-preview',
- voice: 'alloy',
- instructions: `You are a helpful, friendly voice assistant with access to several tools.
-
-You can:
-- Tell the user the current time and date (getCurrentTime)
-- Get weather information for any location (getWeather)
-- Set reminders for the user (setReminder)
-- Search a knowledge base for information (searchKnowledge)
-
-Keep your responses concise and conversational since this is a voice interface.
-When using tools, briefly explain what you're doing and then share the results naturally.
-Be friendly and engaging!`,
- turnDetection: {
- type: 'server_vad',
- threshold: 0.5,
- prefix_padding_ms: 300,
- silence_duration_ms: 500,
- },
- inputAudioTranscription: {
- model: 'whisper-1',
- },
- tools,
- toolChoice: 'auto',
}),
})
} else if (provider === 'elevenlabs') {
diff --git a/examples/ts-react-chat/src/routes/realtime.tsx b/examples/ts-react-chat/src/routes/realtime.tsx
index 107b839e57..272243aa82 100644
--- a/examples/ts-react-chat/src/routes/realtime.tsx
+++ b/examples/ts-react-chat/src/routes/realtime.tsx
@@ -140,7 +140,18 @@ function RealtimePage() {
return response.json()
},
adapter,
- // Pass the client tools - these execute locally when the AI calls them
+ instructions: `You are a helpful, friendly voice assistant with access to several tools.
+
+You can:
+- Tell the user the current time and date (getCurrentTime)
+- Get weather information for any location (getWeather)
+- Set reminders for the user (setReminder)
+- Search a knowledge base for information (searchKnowledge)
+
+Keep your responses concise and conversational since this is a voice interface.
+When using tools, briefly explain what you're doing and then share the results naturally.
+Be friendly and engaging!`,
+ voice: 'alloy',
tools: realtimeClientTools,
onError: (err) => {
console.error('Realtime error:', err)
diff --git a/packages/typescript/ai-client/src/realtime-client.ts b/packages/typescript/ai-client/src/realtime-client.ts
index 170a4d5855..4ce1502147 100644
--- a/packages/typescript/ai-client/src/realtime-client.ts
+++ b/packages/typescript/ai-client/src/realtime-client.ts
@@ -1,3 +1,4 @@
+import { convertSchemaToJsonSchema } from '@tanstack/ai'
import type {
AnyClientTool,
AudioVisualization,
@@ -37,10 +38,7 @@ const TOKEN_REFRESH_BUFFER_MS = 60_000
* await client.connect()
* ```
*/
-let clientIdCounter = 0
-
export class RealtimeClient {
- private instanceId: number
private options: RealtimeClientOptions
private connection: RealtimeConnection | null = null
private token: RealtimeToken | null = null
@@ -59,9 +57,6 @@ export class RealtimeClient {
}
constructor(options: RealtimeClientOptions) {
- this.instanceId = ++clientIdCounter
- console.log(`[RealtimeClient #${this.instanceId}] Created`)
-
this.options = {
autoPlayback: true,
autoCapture: true,
@@ -102,14 +97,13 @@ export class RealtimeClient {
// Connect via adapter
this.connection = await this.options.adapter.connect(this.token)
- console.log(
- `[RealtimeClient #${this.instanceId}] Connection established:`,
- !!this.connection,
- )
// Subscribe to connection events
this.subscribeToConnectionEvents()
+ // Auto-configure session with client-provided settings
+ this.applySessionConfig()
+
// Start audio capture if configured
if (this.options.autoCapture) {
await this.connection.startAudioCapture()
@@ -254,10 +248,6 @@ export class RealtimeClient {
/** Get audio visualization data */
get audio(): AudioVisualization | null {
- console.log(
- `[RealtimeClient #${this.instanceId}] audio getter, connection:`,
- !!this.connection,
- )
return this.connection?.getAudioVisualization() ?? null
}
@@ -454,6 +444,31 @@ export class RealtimeClient {
)
}
+ private applySessionConfig(): void {
+ if (!this.connection) return
+
+ const { instructions, voice, vadMode, tools } = this.options
+ const hasConfig = instructions || voice || vadMode || (tools && tools.length > 0)
+ if (!hasConfig) return
+
+ const toolsConfig = tools
+ ? Array.from(this.clientTools.values()).map((t) => ({
+ name: t.name,
+ description: t.description,
+ inputSchema: t.inputSchema
+ ? convertSchemaToJsonSchema(t.inputSchema)
+ : undefined,
+ }))
+ : undefined
+
+ this.connection.updateSession({
+ instructions,
+ voice,
+ vadMode,
+ tools: toolsConfig,
+ })
+ }
+
private generateId(): string {
return `msg-${Date.now()}-${Math.random().toString(36).substring(7)}`
}
diff --git a/packages/typescript/ai-client/src/realtime-types.ts b/packages/typescript/ai-client/src/realtime-types.ts
index 4ff6bf9bd5..859d5dea60 100644
--- a/packages/typescript/ai-client/src/realtime-types.ts
+++ b/packages/typescript/ai-client/src/realtime-types.ts
@@ -105,6 +105,16 @@ export interface RealtimeClientOptions {
*/
autoCapture?: boolean
+ /**
+ * System instructions for the assistant
+ */
+ instructions?: string
+
+ /**
+ * Voice to use for audio output
+ */
+ voice?: string
+
/**
* Voice activity detection mode (default: 'server')
*/
diff --git a/packages/typescript/ai-openai/src/realtime/adapter.ts b/packages/typescript/ai-openai/src/realtime/adapter.ts
index e25a7dbd30..03bc7da7aa 100644
--- a/packages/typescript/ai-openai/src/realtime/adapter.ts
+++ b/packages/typescript/ai-openai/src/realtime/adapter.ts
@@ -100,9 +100,14 @@ async function createWebRTCConnection(
// Set up data channel for bidirectional communication
dataChannel = pc.createDataChannel('oai-events')
- dataChannel.onopen = () => {
- emit('status_change', { status: 'connected' as RealtimeStatus })
- }
+ // Promise that resolves when the data channel is open and ready
+ const dataChannelReady = new Promise((resolve) => {
+ dataChannel!.onopen = () => {
+ flushPendingEvents()
+ emit('status_change', { status: 'connected' as RealtimeStatus })
+ resolve()
+ }
+ })
dataChannel.onmessage = (event) => {
try {
@@ -119,10 +124,8 @@ async function createWebRTCConnection(
// Handle incoming audio track
pc.ontrack = (event) => {
- console.log('[Realtime] ontrack event:', event.track.kind, event.streams[0])
if (event.track.kind === 'audio' && event.streams[0]) {
setupOutputAudioAnalysis(event.streams[0])
- console.log('[Realtime] Output analyser created:', outputAnalyser)
}
}
@@ -172,12 +175,7 @@ async function createWebRTCConnection(
await pc.setRemoteDescription({ type: 'answer', sdp: answerSdp })
// Set up input audio analysis now that we have the stream
- console.log(
- '[Realtime] Setting up input audio analysis, localStream:',
- localStream,
- )
setupInputAudioAnalysis(localStream)
- console.log('[Realtime] Input analyser created:', inputAnalyser)
// Handle server events
function handleServerEvent(event: Record) {
@@ -262,16 +260,16 @@ async function createWebRTCConnection(
}
case 'response.done': {
+ const response = event.response as Record
+ const output = response.output as
+ | Array>
+ | undefined
+
currentMode = 'listening'
emit('mode_change', { mode: 'listening' })
// Emit message complete if we have a current message
if (currentMessageId) {
- const response = event.response as Record
- const output = response.output as
- | Array>
- | undefined
-
const message: RealtimeMessage = {
id: currentMessageId,
role: 'assistant',
@@ -372,11 +370,24 @@ async function createWebRTCConnection(
inputSource.connect(inputAnalyser)
}
- // Send event to server
+ // Queue for events sent before the data channel is open
+ const pendingEvents: Array> = []
+
+ // Send event to server (queues if data channel not yet open)
function sendEvent(event: Record) {
if (dataChannel?.readyState === 'open') {
dataChannel.send(JSON.stringify(event))
+ } else {
+ pendingEvents.push(event)
+ }
+ }
+
+ // Flush any queued events (called when data channel opens)
+ function flushPendingEvents() {
+ for (const event of pendingEvents) {
+ dataChannel!.send(JSON.stringify(event))
}
+ pendingEvents.length = 0
}
// Connection implementation
@@ -486,6 +497,21 @@ async function createWebRTCConnection(
}
}
+ if (config.tools !== undefined) {
+ sessionUpdate.tools = config.tools.map((t) => ({
+ type: 'function',
+ name: t.name,
+ description: t.description,
+ parameters: t.inputSchema
+ ? (t.inputSchema as Record)
+ : { type: 'object', properties: {} },
+ }))
+ sessionUpdate.tool_choice = 'auto'
+ }
+
+ // Always enable input audio transcription so user speech is transcribed
+ sessionUpdate.input_audio_transcription = { model: 'whisper-1' }
+
if (Object.keys(sessionUpdate).length > 0) {
sendEvent({
type: 'session.update',
@@ -516,14 +542,6 @@ async function createWebRTCConnection(
},
getAudioVisualization(): AudioVisualization {
- // Log analyser state for debugging
- console.log(
- '[Realtime] getAudioVisualization called, inputAnalyser:',
- !!inputAnalyser,
- 'outputAnalyser:',
- !!outputAnalyser,
- )
-
// Helper to calculate audio level from time domain data
// Uses peak amplitude which is more responsive for voice audio meters
function calculateLevel(analyser: AnalyserNode): number {
@@ -597,5 +615,9 @@ async function createWebRTCConnection(
},
}
+ // Wait for the data channel to be open before returning the connection.
+ // This ensures session.update (tools, instructions, etc.) can be sent immediately.
+ await dataChannelReady
+
return connection
}
diff --git a/packages/typescript/ai-openai/src/realtime/token.ts b/packages/typescript/ai-openai/src/realtime/token.ts
index 832adaa79c..6bff9c9c26 100644
--- a/packages/typescript/ai-openai/src/realtime/token.ts
+++ b/packages/typescript/ai-openai/src/realtime/token.ts
@@ -1,5 +1,5 @@
import { getOpenAIApiKeyFromEnv } from '../utils/client'
-import type { RealtimeToken, RealtimeTokenAdapter, Tool } from '@tanstack/ai'
+import type { RealtimeToken, RealtimeTokenAdapter } from '@tanstack/ai'
import type {
OpenAIRealtimeModel,
OpenAIRealtimeSessionResponse,
@@ -47,58 +47,17 @@ export function openaiRealtimeToken(
async generateToken(): Promise {
const model: OpenAIRealtimeModel =
options.model ?? 'gpt-4o-realtime-preview'
- const voice = options.voice ?? 'alloy'
- // Build request body
- const body: Record = {
- model,
- voice,
- }
-
- if (options.instructions) {
- body.instructions = options.instructions
- }
-
- if (options.turnDetection !== undefined) {
- body.turn_detection = options.turnDetection
- }
-
- if (options.inputAudioFormat) {
- body.input_audio_format = options.inputAudioFormat
- }
-
- if (options.outputAudioFormat) {
- body.output_audio_format = options.outputAudioFormat
- }
-
- if (options.inputAudioTranscription) {
- body.input_audio_transcription = options.inputAudioTranscription
- }
-
- if (options.tools) {
- body.tools = options.tools
- }
-
- if (options.toolChoice) {
- body.tool_choice = options.toolChoice
- }
-
- if (options.temperature !== undefined) {
- body.temperature = options.temperature
- }
-
- if (options.maxResponseOutputTokens !== undefined) {
- body.max_response_output_tokens = options.maxResponseOutputTokens
- }
-
- // Call OpenAI API to create session and get ephemeral token
+ // Call OpenAI API to create session and get ephemeral token.
+ // Only the model is sent server-side; all other session config
+ // (instructions, voice, tools, VAD) is applied client-side via session.update.
const response = await fetch(OPENAI_REALTIME_SESSIONS_URL, {
method: 'POST',
headers: {
Authorization: `Bearer ${apiKey}`,
'Content-Type': 'application/json',
},
- body: JSON.stringify(body),
+ body: JSON.stringify({ model }),
})
if (!response.ok) {
@@ -110,43 +69,12 @@ export function openaiRealtimeToken(
const sessionData: OpenAIRealtimeSessionResponse = await response.json()
- // Convert tools to our format
- const tools: Array = sessionData.tools.map((t) => ({
- name: t.name,
- description: t.description,
- inputSchema: t.parameters,
- }))
-
return {
provider: 'openai',
token: sessionData.client_secret.value,
- expiresAt: sessionData.client_secret.expires_at * 1000, // Convert to ms
+ expiresAt: sessionData.client_secret.expires_at * 1000,
config: {
model: sessionData.model,
- voice: sessionData.voice,
- instructions: sessionData.instructions,
- tools,
- vadMode:
- sessionData.turn_detection?.type === 'semantic_vad'
- ? 'semantic'
- : sessionData.turn_detection?.type === 'server_vad'
- ? 'server'
- : 'manual',
- vadConfig: sessionData.turn_detection
- ? {
- threshold: sessionData.turn_detection.threshold,
- prefixPaddingMs: sessionData.turn_detection.prefix_padding_ms,
- silenceDurationMs:
- sessionData.turn_detection.silence_duration_ms,
- }
- : undefined,
- providerOptions: {
- inputAudioFormat: sessionData.input_audio_format,
- outputAudioFormat: sessionData.output_audio_format,
- inputAudioTranscription: sessionData.input_audio_transcription,
- temperature: sessionData.temperature,
- maxResponseOutputTokens: sessionData.max_response_output_tokens,
- },
},
}
},
diff --git a/packages/typescript/ai-openai/src/realtime/types.ts b/packages/typescript/ai-openai/src/realtime/types.ts
index 713bd2b4cf..815099866d 100644
--- a/packages/typescript/ai-openai/src/realtime/types.ts
+++ b/packages/typescript/ai-openai/src/realtime/types.ts
@@ -52,33 +52,6 @@ export type OpenAITurnDetection =
export interface OpenAIRealtimeTokenOptions {
/** Model to use (default: 'gpt-4o-realtime-preview') */
model?: OpenAIRealtimeModel
- /** Voice to use (default: 'alloy') */
- voice?: OpenAIRealtimeVoice
- /** System instructions */
- instructions?: string
- /** Turn detection configuration */
- turnDetection?: OpenAITurnDetection
- /** Input audio format (default: 'pcm16') */
- inputAudioFormat?: 'pcm16' | 'g711_ulaw' | 'g711_alaw'
- /** Output audio format (default: 'pcm16') */
- outputAudioFormat?: 'pcm16' | 'g711_ulaw' | 'g711_alaw'
- /** Input audio transcription model */
- inputAudioTranscription?: {
- model: 'whisper-1'
- }
- /** Tools available in the session */
- tools?: Array<{
- type: 'function'
- name: string
- description: string
- parameters: Record
- }>
- /** Tool choice strategy */
- toolChoice?: 'auto' | 'none' | 'required' | { type: 'function'; name: string }
- /** Temperature for response generation */
- temperature?: number
- /** Maximum response output tokens */
- maxResponseOutputTokens?: number | 'inf'
}
/**
diff --git a/packages/typescript/ai-react/src/realtime-types.ts b/packages/typescript/ai-react/src/realtime-types.ts
index 9b44269d9e..7687bbc42a 100644
--- a/packages/typescript/ai-react/src/realtime-types.ts
+++ b/packages/typescript/ai-react/src/realtime-types.ts
@@ -37,6 +37,16 @@ export interface UseRealtimeChatOptions {
*/
autoCapture?: boolean
+ /**
+ * System instructions for the assistant
+ */
+ instructions?: string
+
+ /**
+ * Voice to use for audio output
+ */
+ voice?: string
+
/**
* Voice activity detection mode (default: 'server')
*/
diff --git a/packages/typescript/ai-react/src/use-realtime-chat.ts b/packages/typescript/ai-react/src/use-realtime-chat.ts
index 9d3f0af41c..c40d26e784 100644
--- a/packages/typescript/ai-react/src/use-realtime-chat.ts
+++ b/packages/typescript/ai-react/src/use-realtime-chat.ts
@@ -87,6 +87,8 @@ export function useRealtimeChat(
getToken: optionsRef.current.getToken,
adapter: optionsRef.current.adapter,
tools: optionsRef.current.tools,
+ instructions: optionsRef.current.instructions,
+ voice: optionsRef.current.voice,
autoPlayback: optionsRef.current.autoPlayback,
autoCapture: optionsRef.current.autoCapture,
vadMode: optionsRef.current.vadMode,
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index cb260e5697..5fae8867f0 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -329,7 +329,7 @@ importers:
specifier: ^5.1.0
version: 5.1.0
- examples/ts-react-fal:
+ examples/ts-react-media:
dependencies:
'@tailwindcss/vite':
specifier: ^4.1.18
@@ -340,6 +340,9 @@ importers:
'@tanstack/ai-fal':
specifier: workspace:*
version: link:../../packages/typescript/ai-fal
+ '@tanstack/ai-gemini':
+ specifier: workspace:*
+ version: link:../../packages/typescript/ai-gemini
'@tanstack/react-router':
specifier: ^1.158.4
version: 1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
@@ -781,8 +784,8 @@ importers:
packages/typescript/ai-gemini:
dependencies:
'@google/genai':
- specifier: ^1.30.0
- version: 1.33.0
+ specifier: ^1.43.0
+ version: 1.43.0
devDependencies:
'@tanstack/ai':
specifier: workspace:*
@@ -2416,11 +2419,11 @@ packages:
'@gerrit0/mini-shiki@3.19.0':
resolution: {integrity: sha512-ZSlWfLvr8Nl0T4iA3FF/8VH8HivYF82xQts2DY0tJxZd4wtXJ8AA0nmdW9lmO4hlrh3f9xNwEPtOgqETPqKwDA==}
- '@google/genai@1.33.0':
- resolution: {integrity: sha512-ThUjFZ1N0DU88peFjnQkb8K198EWaW2RmmnDShFQ+O+xkIH9itjpRe358x3L/b4X/A7dimkvq63oz49Vbh7Cog==}
+ '@google/genai@1.43.0':
+ resolution: {integrity: sha512-hklCsJNdMlDM1IwcCVcGQFBg2izY0+t5BIGbRsxi2UnKi6AGKL7pqJqmBDNRbw0bYCs4y3NA7TB+fkKfP/Nrdw==}
engines: {node: '>=20.0.0'}
peerDependencies:
- '@modelcontextprotocol/sdk': ^1.24.0
+ '@modelcontextprotocol/sdk': ^1.25.2
peerDependenciesMeta:
'@modelcontextprotocol/sdk':
optional: true
@@ -3108,6 +3111,36 @@ packages:
'@poppinss/exception@1.2.3':
resolution: {integrity: sha512-dCED+QRChTVatE9ibtoaxc+WkdzOSjYTKi/+uacHWIsfodVfpsueo3+DKpgU5Px8qXjgmXkSvhXvSCz3fnP9lw==}
+ '@protobufjs/aspromise@1.1.2':
+ resolution: {integrity: sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==}
+
+ '@protobufjs/base64@1.1.2':
+ resolution: {integrity: sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==}
+
+ '@protobufjs/codegen@2.0.4':
+ resolution: {integrity: sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==}
+
+ '@protobufjs/eventemitter@1.1.0':
+ resolution: {integrity: sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==}
+
+ '@protobufjs/fetch@1.1.0':
+ resolution: {integrity: sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==}
+
+ '@protobufjs/float@1.0.2':
+ resolution: {integrity: sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==}
+
+ '@protobufjs/inquire@1.1.0':
+ resolution: {integrity: sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==}
+
+ '@protobufjs/path@1.1.2':
+ resolution: {integrity: sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==}
+
+ '@protobufjs/pool@1.1.0':
+ resolution: {integrity: sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==}
+
+ '@protobufjs/utf8@1.1.0':
+ resolution: {integrity: sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==}
+
'@publint/pack@0.1.2':
resolution: {integrity: sha512-S+9ANAvUmjutrshV4jZjaiG8XQyuJIZ8a4utWmN/vW1sgQ9IfBnPndwkmQYw53QmouOIytT874u65HEmu6H5jw==}
engines: {node: '>=18'}
@@ -4449,6 +4482,9 @@ packages:
'@types/resolve@1.20.2':
resolution: {integrity: sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==}
+ '@types/retry@0.12.0':
+ resolution: {integrity: sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==}
+
'@types/unist@2.0.11':
resolution: {integrity: sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==}
@@ -6141,9 +6177,6 @@ packages:
h3@1.13.0:
resolution: {integrity: sha512-vFEAu/yf8UMUcB4s43OaDaigcqpQd14yanmOsn+NcRX3/guSKncyE2rOYhq8RIchgJrPSs/QiIddnTTR1ddiAg==}
- h3@1.15.4:
- resolution: {integrity: sha512-z5cFQWDffyOe4vQ9xIqNfCZdV4p//vy6fBnr8Q1AWnVZ0teurKMG66rLj++TKwKPUP3u7iMUvrvKaEUiQw2QWQ==}
-
h3@1.15.5:
resolution: {integrity: sha512-xEyq3rSl+dhGX2Lm0+eFQIAzlDN6Fs0EcC4f7BNUmzaRX/PTzeuM+Tr2lHB8FoXggsQIeXLj8EDVgs5ywxyxmg==}
@@ -6593,8 +6626,8 @@ packages:
jju@1.4.0:
resolution: {integrity: sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA==}
- jose@6.1.3:
- resolution: {integrity: sha512-0TpaTfihd4QMNwrz/ob2Bp7X04yuxJkjRGi4aKmOqwhov54i6u79oCv7T+C7lo70MKH6BesI3vscD1yb/yzKXQ==}
+ jose@6.2.0:
+ resolution: {integrity: sha512-xsfE1TcSCbUdo6U07tR0mvhg0flGxU8tPLbF03mirl2ukGQENhUg4ubGYQnhVH0b5stLlPM+WOqDkEl1R1y5sQ==}
js-beautify@1.15.4:
resolution: {integrity: sha512-9/KXeZUKKJwqCXUdBxFJ3vPh467OCckSBmYDwSK/EtV090K+iMJ7zx2S3HLVDIWFQdqMIsZWbnaGiba18aWhaA==}
@@ -6846,6 +6879,9 @@ packages:
resolution: {integrity: sha512-HgMmCqIJSAKqo68l0rS2AanEWfkxaZ5wNiEFb5ggm08lDs9Xl2KxBlX3PTcaD2chBM1gXAYf491/M2Rv8Jwayg==}
engines: {node: '>= 0.6.0'}
+ long@5.3.2:
+ resolution: {integrity: sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==}
+
longest-streak@3.1.0:
resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==}
@@ -7438,6 +7474,10 @@ packages:
resolution: {integrity: sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==}
engines: {node: '>=6'}
+ p-retry@4.6.2:
+ resolution: {integrity: sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==}
+ engines: {node: '>=8'}
+
p-try@2.2.0:
resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==}
engines: {node: '>=6'}
@@ -7627,6 +7667,10 @@ packages:
proto-list@1.2.4:
resolution: {integrity: sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==}
+ protobufjs@7.5.4:
+ resolution: {integrity: sha512-CvexbZtbov6jW2eXAvLukXjXUW1TzFaivC46BpWc/3BpcCysb5Vffu+B3XHMm8lVEuy2Mm4XGex8hBSg1yapPg==}
+ engines: {node: '>=12.0.0'}
+
proxy-addr@2.0.7:
resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==}
engines: {node: '>= 0.10'}
@@ -7808,6 +7852,10 @@ packages:
resolution: {integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==}
engines: {node: '>=8'}
+ retry@0.13.1:
+ resolution: {integrity: sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==}
+ engines: {node: '>= 4'}
+
reusify@1.1.0:
resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==}
engines: {iojs: '>=1.0.0', node: '>=0.10.0'}
@@ -8628,68 +8676,6 @@ packages:
synckit:
optional: true
- unstorage@1.17.3:
- resolution: {integrity: sha512-i+JYyy0DoKmQ3FximTHbGadmIYb8JEpq7lxUjnjeB702bCPum0vzo6oy5Mfu0lpqISw7hCyMW2yj4nWC8bqJ3Q==}
- peerDependencies:
- '@azure/app-configuration': ^1.8.0
- '@azure/cosmos': ^4.2.0
- '@azure/data-tables': ^13.3.0
- '@azure/identity': ^4.6.0
- '@azure/keyvault-secrets': ^4.9.0
- '@azure/storage-blob': ^12.26.0
- '@capacitor/preferences': ^6.0.3 || ^7.0.0
- '@deno/kv': '>=0.9.0'
- '@netlify/blobs': ^6.5.0 || ^7.0.0 || ^8.1.0 || ^9.0.0 || ^10.0.0
- '@planetscale/database': ^1.19.0
- '@upstash/redis': ^1.34.3
- '@vercel/blob': '>=0.27.1'
- '@vercel/functions': ^2.2.12 || ^3.0.0
- '@vercel/kv': ^1.0.1
- aws4fetch: ^1.0.20
- db0: '>=0.2.1'
- idb-keyval: ^6.2.1
- ioredis: ^5.4.2
- uploadthing: ^7.4.4
- peerDependenciesMeta:
- '@azure/app-configuration':
- optional: true
- '@azure/cosmos':
- optional: true
- '@azure/data-tables':
- optional: true
- '@azure/identity':
- optional: true
- '@azure/keyvault-secrets':
- optional: true
- '@azure/storage-blob':
- optional: true
- '@capacitor/preferences':
- optional: true
- '@deno/kv':
- optional: true
- '@netlify/blobs':
- optional: true
- '@planetscale/database':
- optional: true
- '@upstash/redis':
- optional: true
- '@vercel/blob':
- optional: true
- '@vercel/functions':
- optional: true
- '@vercel/kv':
- optional: true
- aws4fetch:
- optional: true
- db0:
- optional: true
- idb-keyval:
- optional: true
- ioredis:
- optional: true
- uploadthing:
- optional: true
-
unstorage@1.17.4:
resolution: {integrity: sha512-fHK0yNg38tBiJKp/Vgsq4j0JEsCmgqH58HAn707S7zGkArbZsVr/CwINoi+nh3h98BRCwKvx1K3Xg9u3VV83sw==}
peerDependencies:
@@ -9168,8 +9154,8 @@ packages:
webpack-virtual-modules@0.6.2:
resolution: {integrity: sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==}
- webrtc-adapter@9.0.3:
- resolution: {integrity: sha512-5fALBcroIl31OeXAdd1YUntxiZl1eHlZZWzNg3U4Fn+J9/cGL3eT80YlrsWGvj2ojuz1rZr2OXkgCzIxAZ7vRQ==}
+ webrtc-adapter@9.0.4:
+ resolution: {integrity: sha512-5ZZY1+lGq8LEKuDlg9M2RPJHlH3R7OVwyHqMcUsLKCgd9Wvf+QrFTCItkXXYPmrJn8H6gRLXbSgxLLdexiqHxw==}
engines: {node: '>=6.0.0', npm: '>=3.10.0'}
whatwg-encoding@3.1.1:
@@ -10173,9 +10159,11 @@ snapshots:
'@shikijs/types': 3.20.0
'@shikijs/vscode-textmate': 10.0.2
- '@google/genai@1.33.0':
+ '@google/genai@1.43.0':
dependencies:
google-auth-library: 10.5.0
+ p-retry: 4.6.2
+ protobufjs: 7.5.4
ws: 8.18.3
transitivePeerDependencies:
- bufferutil
@@ -10717,6 +10705,29 @@ snapshots:
'@poppinss/exception@1.2.3': {}
+ '@protobufjs/aspromise@1.1.2': {}
+
+ '@protobufjs/base64@1.1.2': {}
+
+ '@protobufjs/codegen@2.0.4': {}
+
+ '@protobufjs/eventemitter@1.1.0': {}
+
+ '@protobufjs/fetch@1.1.0':
+ dependencies:
+ '@protobufjs/aspromise': 1.1.2
+ '@protobufjs/inquire': 1.1.0
+
+ '@protobufjs/float@1.0.2': {}
+
+ '@protobufjs/inquire@1.1.0': {}
+
+ '@protobufjs/path@1.1.2': {}
+
+ '@protobufjs/pool@1.1.0': {}
+
+ '@protobufjs/utf8@1.1.0': {}
+
'@publint/pack@0.1.2': {}
'@quansync/fs@1.0.0':
@@ -12778,6 +12789,8 @@ snapshots:
'@types/resolve@1.20.2': {}
+ '@types/retry@0.12.0': {}
+
'@types/unist@2.0.11': {}
'@types/unist@3.0.3': {}
@@ -14861,18 +14874,6 @@ snapshots:
uncrypto: 0.1.3
unenv: 1.10.0
- h3@1.15.4:
- dependencies:
- cookie-es: 1.2.2
- crossws: 0.3.5
- defu: 6.1.4
- destr: 2.0.5
- iron-webcrypto: 1.2.1
- node-mock-http: 1.0.4
- radix3: 1.1.2
- ufo: 1.6.1
- uncrypto: 0.1.3
-
h3@1.15.5:
dependencies:
cookie-es: 1.2.2
@@ -15374,7 +15375,7 @@ snapshots:
jju@1.4.0: {}
- jose@6.1.3: {}
+ jose@6.2.0: {}
js-beautify@1.15.4:
dependencies:
@@ -15601,13 +15602,13 @@ snapshots:
'@livekit/protocol': 1.44.0
'@types/dom-mediacapture-record': 1.0.22
events: 3.3.0
- jose: 6.1.3
+ jose: 6.2.0
loglevel: 1.9.2
sdp-transform: 2.15.0
ts-debounce: 4.0.0
tslib: 2.8.1
typed-emitter: 2.1.0
- webrtc-adapter: 9.0.3
+ webrtc-adapter: 9.0.4
local-pkg@0.5.1:
dependencies:
@@ -15647,6 +15648,8 @@ snapshots:
loglevel@1.9.2: {}
+ long@5.3.2: {}
+
longest-streak@3.1.0: {}
lowlight@3.3.0:
@@ -16253,7 +16256,7 @@ snapshots:
exsolve: 1.0.8
globby: 15.0.0
gzip-size: 7.0.0
- h3: 1.15.4
+ h3: 1.15.5
hookable: 5.5.3
httpxy: 0.1.7
ioredis: 5.8.2
@@ -16289,7 +16292,7 @@ snapshots:
unenv: 2.0.0-rc.24
unimport: 5.5.0
unplugin-utils: 0.3.1
- unstorage: 1.17.3(db0@0.3.4)(ioredis@5.8.2)
+ unstorage: 1.17.4(db0@0.3.4)(ioredis@5.8.2)
untyped: 2.0.0
unwasm: 0.3.11
youch: 4.1.0-beta.13
@@ -16711,6 +16714,11 @@ snapshots:
p-map@2.1.0: {}
+ p-retry@4.6.2:
+ dependencies:
+ '@types/retry': 0.12.0
+ retry: 0.13.1
+
p-try@2.2.0: {}
package-json-from-dist@1.0.1: {}
@@ -16869,6 +16877,21 @@ snapshots:
proto-list@1.2.4: {}
+ protobufjs@7.5.4:
+ dependencies:
+ '@protobufjs/aspromise': 1.1.2
+ '@protobufjs/base64': 1.1.2
+ '@protobufjs/codegen': 2.0.4
+ '@protobufjs/eventemitter': 1.1.0
+ '@protobufjs/fetch': 1.1.0
+ '@protobufjs/float': 1.0.2
+ '@protobufjs/inquire': 1.1.0
+ '@protobufjs/path': 1.1.2
+ '@protobufjs/pool': 1.1.0
+ '@protobufjs/utf8': 1.1.0
+ '@types/node': 24.10.3
+ long: 5.3.2
+
proxy-addr@2.0.7:
dependencies:
forwarded: 0.2.0
@@ -17094,6 +17117,8 @@ snapshots:
onetime: 5.1.2
signal-exit: 3.0.7
+ retry@0.13.1: {}
+
reusify@1.1.0: {}
rimraf@5.0.10:
@@ -18064,20 +18089,6 @@ snapshots:
dependencies:
rolldown: 1.0.0-beta.53
- unstorage@1.17.3(db0@0.3.4)(ioredis@5.8.2):
- dependencies:
- anymatch: 3.1.3
- chokidar: 4.0.3
- destr: 2.0.5
- h3: 1.15.5
- lru-cache: 10.4.3
- node-fetch-native: 1.6.7
- ofetch: 1.5.1
- ufo: 1.6.1
- optionalDependencies:
- db0: 0.3.4
- ioredis: 5.8.2
-
unstorage@1.17.4(db0@0.3.4)(ioredis@5.8.2):
dependencies:
anymatch: 3.1.3
@@ -18620,7 +18631,7 @@ snapshots:
webpack-virtual-modules@0.6.2: {}
- webrtc-adapter@9.0.3:
+ webrtc-adapter@9.0.4:
dependencies:
sdp: 3.2.1
From 44d0740877c26a7cda9610de84ecfb2459859cdd Mon Sep 17 00:00:00 2001
From: Jack Herrington
Date: Thu, 5 Mar 2026 18:49:52 -0800
Subject: [PATCH 22/31] API further improved
---
.../src/components/AudioSparkline.tsx | 81 +++++++++++
.../ts-react-chat/src/lib/use-realtime.ts | 80 +++++++++++
.../src/routes/api.realtime-token.ts | 73 ----------
.../ts-react-chat/src/routes/realtime.tsx | 132 +-----------------
.../ai-openai/src/realtime/adapter.ts | 4 +-
packages/typescript/ai/src/realtime/types.ts | 16 ++-
6 files changed, 177 insertions(+), 209 deletions(-)
create mode 100644 examples/ts-react-chat/src/components/AudioSparkline.tsx
create mode 100644 examples/ts-react-chat/src/lib/use-realtime.ts
delete mode 100644 examples/ts-react-chat/src/routes/api.realtime-token.ts
diff --git a/examples/ts-react-chat/src/components/AudioSparkline.tsx b/examples/ts-react-chat/src/components/AudioSparkline.tsx
new file mode 100644
index 0000000000..edc51b4a62
--- /dev/null
+++ b/examples/ts-react-chat/src/components/AudioSparkline.tsx
@@ -0,0 +1,81 @@
+import { useEffect, useRef } from 'react'
+
+export function AudioSparkline({
+ getData,
+ color,
+ label,
+}: {
+ getData: () => Uint8Array
+ color: string
+ label: string
+}) {
+ const canvasRef = useRef(null)
+ const animationRef = useRef(null)
+
+ useEffect(() => {
+ const canvas = canvasRef.current
+ if (!canvas) return
+
+ const ctx = canvas.getContext('2d')
+ if (!ctx) return
+
+ function draw() {
+ const data = getData()
+ const width = canvas!.width
+ const height = canvas!.height
+
+ ctx!.fillStyle = '#1f2937'
+ ctx!.fillRect(0, 0, width, height)
+
+ ctx!.strokeStyle = color
+ ctx!.lineWidth = 1
+ ctx!.beginPath()
+
+ const step = Math.max(1, Math.floor(data.length / width))
+
+ for (let i = 0; i < width; i++) {
+ const dataIndex = Math.min(i * step, data.length - 1)
+ const value = data[dataIndex] ?? 128
+ const y = height - (value / 255) * height
+
+ if (i === 0) {
+ ctx!.moveTo(i, y)
+ } else {
+ ctx!.lineTo(i, y)
+ }
+ }
+
+ ctx!.stroke()
+
+ ctx!.strokeStyle = '#4b5563'
+ ctx!.setLineDash([2, 2])
+ ctx!.beginPath()
+ ctx!.moveTo(0, height / 2)
+ ctx!.lineTo(width, height / 2)
+ ctx!.stroke()
+ ctx!.setLineDash([])
+
+ animationRef.current = requestAnimationFrame(draw)
+ }
+
+ draw()
+
+ return () => {
+ if (animationRef.current) {
+ cancelAnimationFrame(animationRef.current)
+ }
+ }
+ }, [getData, color])
+
+ return (
+
+ {label}
+
+
+ )
+}
diff --git a/examples/ts-react-chat/src/lib/use-realtime.ts b/examples/ts-react-chat/src/lib/use-realtime.ts
new file mode 100644
index 0000000000..df450efa7f
--- /dev/null
+++ b/examples/ts-react-chat/src/lib/use-realtime.ts
@@ -0,0 +1,80 @@
+import { createServerFn } from '@tanstack/react-start'
+import { realtimeToken } from '@tanstack/ai'
+import { useRealtimeChat } from '@tanstack/ai-react'
+import { openaiRealtime, openaiRealtimeToken } from '@tanstack/ai-openai'
+import {
+ elevenlabsRealtime,
+ elevenlabsRealtimeToken,
+} from '@tanstack/ai-elevenlabs'
+import { realtimeClientTools } from '@/lib/realtime-tools'
+
+type Provider = 'openai' | 'elevenlabs'
+
+const getRealtimeTokenFn = createServerFn({ method: 'POST' })
+ .inputValidator(
+ (data: { provider: Provider; agentId?: string }) => {
+ if (!data.provider) throw new Error('Provider is required')
+ return data
+ },
+ )
+ .handler(async ({ data }) => {
+ if (data.provider === 'openai') {
+ return realtimeToken({
+ adapter: openaiRealtimeToken({
+ model: 'gpt-4o-realtime-preview',
+ }),
+ })
+ }
+
+ if (data.provider === 'elevenlabs') {
+ const agentId = data.agentId || process.env.ELEVENLABS_AGENT_ID
+ if (!agentId) {
+ throw new Error(
+ 'ElevenLabs agent ID is required. Set ELEVENLABS_AGENT_ID or pass agentId in request body.',
+ )
+ }
+ return realtimeToken({
+ adapter: elevenlabsRealtimeToken({ agentId }),
+ })
+ }
+
+ throw new Error(`Unknown provider: ${data.provider}`)
+ })
+
+export function useRealtime({
+ provider,
+ agentId,
+}: {
+ provider: Provider
+ agentId: string
+}) {
+ const adapter =
+ provider === 'openai' ? openaiRealtime() : elevenlabsRealtime()
+
+ return useRealtimeChat({
+ getToken: () =>
+ getRealtimeTokenFn({
+ data: {
+ provider,
+ ...(provider === 'elevenlabs' && agentId ? { agentId } : {}),
+ },
+ }),
+ adapter,
+ instructions: `You are a helpful, friendly voice assistant with access to several tools.
+
+You can:
+- Tell the user the current time and date (getCurrentTime)
+- Get weather information for any location (getWeather)
+- Set reminders for the user (setReminder)
+- Search a knowledge base for information (searchKnowledge)
+
+Keep your responses concise and conversational since this is a voice interface.
+When using tools, briefly explain what you're doing and then share the results naturally.
+Be friendly and engaging!`,
+ voice: 'alloy',
+ tools: realtimeClientTools,
+ onError: (err) => {
+ console.error('Realtime error:', err)
+ },
+ })
+}
diff --git a/examples/ts-react-chat/src/routes/api.realtime-token.ts b/examples/ts-react-chat/src/routes/api.realtime-token.ts
deleted file mode 100644
index 62fb08d8d2..0000000000
--- a/examples/ts-react-chat/src/routes/api.realtime-token.ts
+++ /dev/null
@@ -1,73 +0,0 @@
-import { createFileRoute } from '@tanstack/react-router'
-import { realtimeToken } from '@tanstack/ai'
-import { openaiRealtimeToken } from '@tanstack/ai-openai'
-import { elevenlabsRealtimeToken } from '@tanstack/ai-elevenlabs'
-
-type Provider = 'openai' | 'elevenlabs'
-
-export const Route = createFileRoute('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/api/realtime-token')({
- server: {
- handlers: {
- POST: async ({ request }) => {
- try {
- const body = await request.json()
- const provider: Provider = body.provider || 'openai'
-
- let token
-
- if (provider === 'openai') {
- token = await realtimeToken({
- adapter: openaiRealtimeToken({
- model: 'gpt-4o-realtime-preview',
- }),
- })
- } else if (provider === 'elevenlabs') {
- const agentId = body.agentId || process.env.ELEVENLABS_AGENT_ID
-
- if (!agentId) {
- return new Response(
- JSON.stringify({
- error:
- 'ElevenLabs agent ID is required. Set ELEVENLABS_AGENT_ID or pass agentId in request body.',
- }),
- {
- status: 400,
- headers: { 'Content-Type': 'application/json' },
- },
- )
- }
-
- token = await realtimeToken({
- adapter: elevenlabsRealtimeToken({
- agentId,
- }),
- })
- } else {
- return new Response(
- JSON.stringify({ error: `Unknown provider: ${provider}` }),
- {
- status: 400,
- headers: { 'Content-Type': 'application/json' },
- },
- )
- }
-
- return new Response(JSON.stringify(token), {
- headers: { 'Content-Type': 'application/json' },
- })
- } catch (error: any) {
- console.error('[Realtime Token API] Error:', error)
- return new Response(
- JSON.stringify({
- error: error.message || 'Failed to generate realtime token',
- }),
- {
- status: 500,
- headers: { 'Content-Type': 'application/json' },
- },
- )
- }
- },
- },
- },
-})
diff --git a/examples/ts-react-chat/src/routes/realtime.tsx b/examples/ts-react-chat/src/routes/realtime.tsx
index 272243aa82..13d4c3adfd 100644
--- a/examples/ts-react-chat/src/routes/realtime.tsx
+++ b/examples/ts-react-chat/src/routes/realtime.tsx
@@ -1,10 +1,8 @@
import { useEffect, useRef, useState } from 'react'
import { createFileRoute } from '@tanstack/react-router'
-import { useRealtimeChat } from '@tanstack/ai-react'
-import { openaiRealtime } from '@tanstack/ai-openai'
-import { elevenlabsRealtime } from '@tanstack/ai-elevenlabs'
import { Mic, MicOff, Phone, PhoneOff, Volume2, Wrench } from 'lucide-react'
-import { realtimeClientTools } from '@/lib/realtime-tools'
+import { AudioSparkline } from '@/components/AudioSparkline'
+import { useRealtime } from '@/lib/use-realtime'
type Provider = 'openai' | 'elevenlabs'
@@ -13,101 +11,11 @@ const PROVIDER_OPTIONS: Array<{ value: Provider; label: string }> = [
{ value: 'elevenlabs', label: 'ElevenLabs' },
]
-// Sparkline component to visualize audio waveform
-function AudioSparkline({
- getData,
- color,
- label,
-}: {
- getData: () => Uint8Array
- color: string
- label: string
-}) {
- const canvasRef = useRef(null)
- const animationRef = useRef(null)
-
- useEffect(() => {
- const canvas = canvasRef.current
- if (!canvas) return
-
- const ctx = canvas.getContext('2d')
- if (!ctx) return
-
- function draw() {
- const data = getData()
- const width = canvas!.width
- const height = canvas!.height
-
- // Clear canvas
- ctx!.fillStyle = '#1f2937' // gray-800
- ctx!.fillRect(0, 0, width, height)
-
- // Draw waveform
- ctx!.strokeStyle = color
- ctx!.lineWidth = 1
- ctx!.beginPath()
-
- // Sample the data to fit the canvas width
- const step = Math.max(1, Math.floor(data.length / width))
-
- for (let i = 0; i < width; i++) {
- const dataIndex = Math.min(i * step, data.length - 1)
- const value = data[dataIndex] ?? 128
- // Convert 0-255 to canvas height (128 is center/silence)
- const y = height - (value / 255) * height
-
- if (i === 0) {
- ctx!.moveTo(i, y)
- } else {
- ctx!.lineTo(i, y)
- }
- }
-
- ctx!.stroke()
-
- // Draw center line (silence level)
- ctx!.strokeStyle = '#4b5563' // gray-600
- ctx!.setLineDash([2, 2])
- ctx!.beginPath()
- ctx!.moveTo(0, height / 2)
- ctx!.lineTo(width, height / 2)
- ctx!.stroke()
- ctx!.setLineDash([])
-
- animationRef.current = requestAnimationFrame(draw)
- }
-
- draw()
-
- return () => {
- if (animationRef.current) {
- cancelAnimationFrame(animationRef.current)
- }
- }
- }, [getData, color])
-
- return (
-
- {label}
-
-
- )
-}
-
function RealtimePage() {
const [provider, setProvider] = useState('openai')
const [agentId, setAgentId] = useState('')
const messagesEndRef = useRef(null)
- // Get the appropriate adapter based on provider
- const adapter =
- provider === 'openai' ? openaiRealtime() : elevenlabsRealtime()
-
const {
status,
mode,
@@ -122,41 +30,7 @@ function RealtimePage() {
outputLevel,
getInputTimeDomainData,
getOutputTimeDomainData,
- } = useRealtimeChat({
- getToken: async () => {
- const body: Record = { provider }
- if (provider === 'elevenlabs' && agentId) {
- body.agentId = agentId
- }
- const response = await fetch('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/api/realtime-token', {
- method: 'POST',
- headers: { 'Content-Type': 'application/json' },
- body: JSON.stringify(body),
- })
- if (!response.ok) {
- const error = await response.json()
- throw new Error(error.error || 'Failed to get token')
- }
- return response.json()
- },
- adapter,
- instructions: `You are a helpful, friendly voice assistant with access to several tools.
-
-You can:
-- Tell the user the current time and date (getCurrentTime)
-- Get weather information for any location (getWeather)
-- Set reminders for the user (setReminder)
-- Search a knowledge base for information (searchKnowledge)
-
-Keep your responses concise and conversational since this is a voice interface.
-When using tools, briefly explain what you're doing and then share the results naturally.
-Be friendly and engaging!`,
- voice: 'alloy',
- tools: realtimeClientTools,
- onError: (err) => {
- console.error('Realtime error:', err)
- },
- })
+ } = useRealtime({ provider, agentId })
// Auto-scroll to bottom when messages change
useEffect(() => {
diff --git a/packages/typescript/ai-openai/src/realtime/adapter.ts b/packages/typescript/ai-openai/src/realtime/adapter.ts
index 03bc7da7aa..0f9fbcf133 100644
--- a/packages/typescript/ai-openai/src/realtime/adapter.ts
+++ b/packages/typescript/ai-openai/src/realtime/adapter.ts
@@ -502,9 +502,7 @@ async function createWebRTCConnection(
type: 'function',
name: t.name,
description: t.description,
- parameters: t.inputSchema
- ? (t.inputSchema as Record)
- : { type: 'object', properties: {} },
+ parameters: t.inputSchema ?? { type: 'object', properties: {} },
}))
sessionUpdate.tool_choice = 'auto'
}
diff --git a/packages/typescript/ai/src/realtime/types.ts b/packages/typescript/ai/src/realtime/types.ts
index 8a4be3a98a..94ae56b32c 100644
--- a/packages/typescript/ai/src/realtime/types.ts
+++ b/packages/typescript/ai/src/realtime/types.ts
@@ -1,5 +1,3 @@
-import type { Tool } from '../types'
-
// ============================================================================
// Token Types
// ============================================================================
@@ -16,6 +14,16 @@ export interface VADConfig {
silenceDurationMs?: number
}
+/**
+ * Serializable tool descriptor for realtime session configuration.
+ * Contains only the metadata needed by providers, not Zod schemas or execute functions.
+ */
+export interface RealtimeToolConfig {
+ name: string
+ description: string
+ inputSchema?: Record
+}
+
/**
* Configuration for a realtime session
*/
@@ -27,13 +35,13 @@ export interface RealtimeSessionConfig {
/** System instructions for the assistant */
instructions?: string
/** Tools available in the session */
- tools?: Array
+ tools?: Array
/** VAD mode */
vadMode?: 'server' | 'semantic' | 'manual'
/** VAD configuration */
vadConfig?: VADConfig
/** Provider-specific options */
- providerOptions?: Record
+ providerOptions?: Record
}
/**
From 0165d97aa79b39d7d3c1c3abaea9ed92bc706377 Mon Sep 17 00:00:00 2001
From: Jack Herrington
Date: Thu, 5 Mar 2026 19:11:21 -0800
Subject: [PATCH 23/31] API further improved
---
examples/ts-react-chat/src/routeTree.gen.ts | 21 ---------------------
1 file changed, 21 deletions(-)
diff --git a/examples/ts-react-chat/src/routeTree.gen.ts b/examples/ts-react-chat/src/routeTree.gen.ts
index 89221b1ded..7888fee4bb 100644
--- a/examples/ts-react-chat/src/routeTree.gen.ts
+++ b/examples/ts-react-chat/src/routeTree.gen.ts
@@ -12,7 +12,6 @@ import { Route as rootRouteImport } from './routes/__root'
import { Route as RealtimeRouteImport } from './routes/realtime'
import { Route as IndexRouteImport } from './routes/index'
import { Route as ApiTanchatRouteImport } from './routes/api.tanchat'
-import { Route as ApiRealtimeTokenRouteImport } from './routes/api.realtime-token'
import { Route as ExampleGuitarsIndexRouteImport } from './routes/example.guitars/index'
import { Route as ExampleGuitarsGuitarIdRouteImport } from './routes/example.guitars/$guitarId'
@@ -31,11 +30,6 @@ const ApiTanchatRoute = ApiTanchatRouteImport.update({
path: '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/api/tanchat',
getParentRoute: () => rootRouteImport,
} as any)
-const ApiRealtimeTokenRoute = ApiRealtimeTokenRouteImport.update({
- id: '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/api/realtime-token',
- path: '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/api/realtime-token',
- getParentRoute: () => rootRouteImport,
-} as any)
const ExampleGuitarsIndexRoute = ExampleGuitarsIndexRouteImport.update({
id: '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/example/guitars/',
path: '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/example/guitars/',
@@ -50,7 +44,6 @@ const ExampleGuitarsGuitarIdRoute = ExampleGuitarsGuitarIdRouteImport.update({
export interface FileRoutesByFullPath {
'/': typeof IndexRoute
'/realtime': typeof RealtimeRoute
- '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/api/realtime-token': typeof ApiRealtimeTokenRoute
'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/api/tanchat': typeof ApiTanchatRoute
'/example/guitars/$guitarId': typeof ExampleGuitarsGuitarIdRoute
'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/example/guitars/': typeof ExampleGuitarsIndexRoute
@@ -58,7 +51,6 @@ export interface FileRoutesByFullPath {
export interface FileRoutesByTo {
'/': typeof IndexRoute
'/realtime': typeof RealtimeRoute
- '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/api/realtime-token': typeof ApiRealtimeTokenRoute
'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/api/tanchat': typeof ApiTanchatRoute
'/example/guitars/$guitarId': typeof ExampleGuitarsGuitarIdRoute
'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/example/guitars': typeof ExampleGuitarsIndexRoute
@@ -67,7 +59,6 @@ export interface FileRoutesById {
__root__: typeof rootRouteImport
'/': typeof IndexRoute
'/realtime': typeof RealtimeRoute
- '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/api/realtime-token': typeof ApiRealtimeTokenRoute
'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/api/tanchat': typeof ApiTanchatRoute
'/example/guitars/$guitarId': typeof ExampleGuitarsGuitarIdRoute
'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/example/guitars/': typeof ExampleGuitarsIndexRoute
@@ -77,7 +68,6 @@ export interface FileRouteTypes {
fullPaths:
| '/'
| '/realtime'
- | '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/api/realtime-token'
| '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/api/tanchat'
| '/example/guitars/$guitarId'
| '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/example/guitars/'
@@ -85,7 +75,6 @@ export interface FileRouteTypes {
to:
| '/'
| '/realtime'
- | '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/api/realtime-token'
| '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/api/tanchat'
| '/example/guitars/$guitarId'
| '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/example/guitars'
@@ -93,7 +82,6 @@ export interface FileRouteTypes {
| '__root__'
| '/'
| '/realtime'
- | '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/api/realtime-token'
| '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/api/tanchat'
| '/example/guitars/$guitarId'
| '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/example/guitars/'
@@ -102,7 +90,6 @@ export interface FileRouteTypes {
export interface RootRouteChildren {
IndexRoute: typeof IndexRoute
RealtimeRoute: typeof RealtimeRoute
- ApiRealtimeTokenRoute: typeof ApiRealtimeTokenRoute
ApiTanchatRoute: typeof ApiTanchatRoute
ExampleGuitarsGuitarIdRoute: typeof ExampleGuitarsGuitarIdRoute
ExampleGuitarsIndexRoute: typeof ExampleGuitarsIndexRoute
@@ -131,13 +118,6 @@ declare module '@tanstack/react-router' {
preLoaderRoute: typeof ApiTanchatRouteImport
parentRoute: typeof rootRouteImport
}
- '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/api/realtime-token': {
- id: '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/api/realtime-token'
- path: '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/api/realtime-token'
- fullPath: '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/api/realtime-token'
- preLoaderRoute: typeof ApiRealtimeTokenRouteImport
- parentRoute: typeof rootRouteImport
- }
'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/example/guitars/': {
id: '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/example/guitars/'
path: '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/example/guitars'
@@ -158,7 +138,6 @@ declare module '@tanstack/react-router' {
const rootRouteChildren: RootRouteChildren = {
IndexRoute: IndexRoute,
RealtimeRoute: RealtimeRoute,
- ApiRealtimeTokenRoute: ApiRealtimeTokenRoute,
ApiTanchatRoute: ApiTanchatRoute,
ExampleGuitarsGuitarIdRoute: ExampleGuitarsGuitarIdRoute,
ExampleGuitarsIndexRoute: ExampleGuitarsIndexRoute,
From 1f5eaab2b0cb80a7bece3f1fc677c5a1bf66bf5c Mon Sep 17 00:00:00 2001
From: Jack Herrington
Date: Thu, 5 Mar 2026 19:25:52 -0800
Subject: [PATCH 24/31] Updating the docs
---
docs/architecture/realtime-chat.md | 29 +++++++++++++++++------------
1 file changed, 17 insertions(+), 12 deletions(-)
diff --git a/docs/architecture/realtime-chat.md b/docs/architecture/realtime-chat.md
index fcf15a0f0e..315482a51e 100644
--- a/docs/architecture/realtime-chat.md
+++ b/docs/architecture/realtime-chat.md
@@ -58,7 +58,7 @@ The realtime chat system provides a vendor-neutral, type-safe abstraction for vo
┌─────────────────────────────────────────────────────────────────┐
│ Server-Side │
│ ┌─────────────────────────────────────────────────────────┐ │
-│ │ Token Generation Endpoint │ │
+│ │ Token Generation (Server Function) │ │
│ │ - openaiRealtimeToken() - ephemeral client secrets │ │
│ │ - elevenlabsRealtimeToken() - signed URLs │ │
│ │ (Minimal config: model only — session config is │ │
@@ -74,15 +74,19 @@ The realtime chat system provides a vendor-neutral, type-safe abstraction for vo
Token adapters generate short-lived credentials for client-side connections. This keeps API keys secure on the server. The token endpoint sends **only the model** to the provider; all other session configuration (instructions, voice, tools, VAD) is applied client-side.
```typescript
-// Server-side token endpoint
+// Server function (TanStack Start)
+import { createServerFn } from '@tanstack/react-start'
import { realtimeToken } from '@tanstack/ai'
import { openaiRealtimeToken } from '@tanstack/ai-openai'
-const token = await realtimeToken({
- adapter: openaiRealtimeToken({
- model: 'gpt-4o-realtime-preview',
- }),
-})
+const getRealtimeTokenFn = createServerFn({ method: 'POST' })
+ .handler(async () => {
+ return realtimeToken({
+ adapter: openaiRealtimeToken({
+ model: 'gpt-4o-realtime-preview',
+ }),
+ })
+ })
```
**Token Structure:**
@@ -155,7 +159,7 @@ const {
getInputTimeDomainData,
getOutputTimeDomainData,
} = useRealtimeChat({
- getToken: () => fetch('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/api/realtime-token').then(r => r.json()),
+ getToken: () => getRealtimeTokenFn(),
adapter: openaiRealtime(),
instructions: 'You are a helpful voice assistant.',
voice: 'alloy',
@@ -173,7 +177,7 @@ sequenceDiagram
participant Server
participant OpenAI
- Browser->>Server: POST /api/realtime-token
+ Browser->>Server: getRealtimeTokenFn() (server function)
Server->>OpenAI: POST /v1/realtime/sessions (model only)
OpenAI-->>Server: { client_secret, expires_at }
Server-->>Browser: RealtimeToken
@@ -206,7 +210,7 @@ sequenceDiagram
participant Server
participant ElevenLabs
- Browser->>Server: POST /api/realtime-token
+ Browser->>Server: getRealtimeTokenFn() (server function)
Server->>ElevenLabs: POST /v1/convai/conversation/get_signed_url
ElevenLabs-->>Server: { signed_url }
Server-->>Browser: RealtimeToken
@@ -280,7 +284,7 @@ When connecting, the `RealtimeClient` calls `applySessionConfig()` which sends a
- **instructions** — System prompt for the assistant
- **voice** — Voice to use for audio output (e.g., `'alloy'`)
-- **tools** — Array of tool definitions with JSON Schema parameters, plus `tool_choice: 'auto'`
+- **tools** — Array of `RealtimeToolConfig` descriptors (name, description, JSON Schema parameters), plus `tool_choice: 'auto'`
- **turn_detection** — VAD configuration (server_vad, semantic_vad, or manual)
- **input_audio_transcription** — Enables user speech transcription (e.g., Whisper)
@@ -389,5 +393,6 @@ ELEVENLABS_AGENT_ID=... # Optional, for ElevenLabs
### Demo Application
- `examples/ts-react-chat/src/routes/realtime.tsx` - Demo UI component
-- `examples/ts-react-chat/src/routes/api.realtime-token.ts` - Token API endpoint
+- `examples/ts-react-chat/src/lib/use-realtime.ts` - Custom hook with server function for token generation
- `examples/ts-react-chat/src/lib/realtime-tools.ts` - Client-side tool definitions
+- `examples/ts-react-chat/src/components/AudioSparkline.tsx` - Audio waveform visualization component
From 98831f8fdc5789b2adc7fc3673e7de770d7a5db4 Mon Sep 17 00:00:00 2001
From: Jack Herrington
Date: Thu, 5 Mar 2026 20:22:03 -0800
Subject: [PATCH 25/31] text chat
---
.../ts-react-chat/src/routes/realtime.tsx | 43 ++++++++++++++++++-
.../ai-elevenlabs/src/realtime/adapter.ts | 9 ++--
.../ai-openai/src/realtime/adapter.ts | 21 ++++++++-
3 files changed, 65 insertions(+), 8 deletions(-)
diff --git a/examples/ts-react-chat/src/routes/realtime.tsx b/examples/ts-react-chat/src/routes/realtime.tsx
index 13d4c3adfd..df7c7d8871 100644
--- a/examples/ts-react-chat/src/routes/realtime.tsx
+++ b/examples/ts-react-chat/src/routes/realtime.tsx
@@ -1,6 +1,14 @@
import { useEffect, useRef, useState } from 'react'
import { createFileRoute } from '@tanstack/react-router'
-import { Mic, MicOff, Phone, PhoneOff, Volume2, Wrench } from 'lucide-react'
+import {
+ Mic,
+ MicOff,
+ Phone,
+ PhoneOff,
+ Send,
+ Volume2,
+ Wrench,
+} from 'lucide-react'
import { AudioSparkline } from '@/components/AudioSparkline'
import { useRealtime } from '@/lib/use-realtime'
@@ -14,6 +22,7 @@ const PROVIDER_OPTIONS: Array<{ value: Provider; label: string }> = [
function RealtimePage() {
const [provider, setProvider] = useState('openai')
const [agentId, setAgentId] = useState('')
+ const [textInput, setTextInput] = useState('')
const messagesEndRef = useRef(null)
const {
@@ -26,6 +35,7 @@ function RealtimePage() {
connect,
disconnect,
interrupt,
+ sendText,
inputLevel,
outputLevel,
getInputTimeDomainData,
@@ -258,6 +268,37 @@ function RealtimePage() {
)}
+ {/* Text input */}
+ {status === 'connected' && (
+
+
+
+ )}
+
{/* Audio visualization & controls */}
{/* Volume meters and waveforms */}
diff --git a/packages/typescript/ai-elevenlabs/src/realtime/adapter.ts b/packages/typescript/ai-elevenlabs/src/realtime/adapter.ts
index dfe33d3182..042e3ce733 100644
--- a/packages/typescript/ai-elevenlabs/src/realtime/adapter.ts
+++ b/packages/typescript/ai-elevenlabs/src/realtime/adapter.ts
@@ -147,12 +147,9 @@ async function createElevenLabsConnection(
emit('mode_change', { mode: 'idle' })
},
- sendText(_text: string) {
- // ElevenLabs doesn't support direct text input in the same way
- // The SDK is voice-first. Log a warning.
- console.warn(
- 'ElevenLabs realtime adapter does not support sendText. Use voice input.',
- )
+ sendText(text: string) {
+ if (!conversation) return
+ conversation.sendUserMessage(text)
},
sendToolResult(_callId: string, _result: string) {
diff --git a/packages/typescript/ai-openai/src/realtime/adapter.ts b/packages/typescript/ai-openai/src/realtime/adapter.ts
index 0f9fbcf133..043f60771c 100644
--- a/packages/typescript/ai-openai/src/realtime/adapter.ts
+++ b/packages/typescript/ai-openai/src/realtime/adapter.ts
@@ -236,6 +236,22 @@ async function createWebRTCConnection(
break
}
+ case 'response.output_text.delta': {
+ const delta = event.delta as string
+ emit('transcript', {
+ role: 'assistant',
+ transcript: delta,
+ isFinal: false,
+ })
+ break
+ }
+
+ case 'response.output_text.done': {
+ const text = event.text as string
+ emit('transcript', { role: 'assistant', transcript: text, isFinal: true })
+ break
+ }
+
case 'response.audio.delta':
if (currentMode !== 'speaking') {
currentMode = 'speaking'
@@ -453,7 +469,10 @@ async function createWebRTCConnection(
content: [{ type: 'input_text', text }],
},
})
- sendEvent({ type: 'response.create' })
+ sendEvent({
+ type: 'response.create',
+ response: { output_modalities: ['text'] },
+ })
},
sendToolResult(callId: string, result: string) {
From 88a308fc02d9d61bd3b0688427e6be1f31a987ca Mon Sep 17 00:00:00 2001
From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com>
Date: Fri, 6 Mar 2026 03:14:29 +0000
Subject: [PATCH 26/31] ci: apply automated fixes
---
examples/ts-react-chat/src/lib/use-realtime.ts | 10 ++++------
packages/typescript/ai-client/src/realtime-client.ts | 3 ++-
2 files changed, 6 insertions(+), 7 deletions(-)
diff --git a/examples/ts-react-chat/src/lib/use-realtime.ts b/examples/ts-react-chat/src/lib/use-realtime.ts
index df450efa7f..f54da4ef72 100644
--- a/examples/ts-react-chat/src/lib/use-realtime.ts
+++ b/examples/ts-react-chat/src/lib/use-realtime.ts
@@ -11,12 +11,10 @@ import { realtimeClientTools } from '@/lib/realtime-tools'
type Provider = 'openai' | 'elevenlabs'
const getRealtimeTokenFn = createServerFn({ method: 'POST' })
- .inputValidator(
- (data: { provider: Provider; agentId?: string }) => {
- if (!data.provider) throw new Error('Provider is required')
- return data
- },
- )
+ .inputValidator((data: { provider: Provider; agentId?: string }) => {
+ if (!data.provider) throw new Error('Provider is required')
+ return data
+ })
.handler(async ({ data }) => {
if (data.provider === 'openai') {
return realtimeToken({
diff --git a/packages/typescript/ai-client/src/realtime-client.ts b/packages/typescript/ai-client/src/realtime-client.ts
index 4ce1502147..1a4bd97106 100644
--- a/packages/typescript/ai-client/src/realtime-client.ts
+++ b/packages/typescript/ai-client/src/realtime-client.ts
@@ -448,7 +448,8 @@ export class RealtimeClient {
if (!this.connection) return
const { instructions, voice, vadMode, tools } = this.options
- const hasConfig = instructions || voice || vadMode || (tools && tools.length > 0)
+ const hasConfig =
+ instructions || voice || vadMode || (tools && tools.length > 0)
if (!hasConfig) return
const toolsConfig = tools
From bd8f4797bca2032e6608ac2915305812b221deb4 Mon Sep 17 00:00:00 2001
From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com>
Date: Fri, 6 Mar 2026 04:25:37 +0000
Subject: [PATCH 27/31] ci: apply automated fixes
---
packages/typescript/ai-openai/src/realtime/adapter.ts | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/packages/typescript/ai-openai/src/realtime/adapter.ts b/packages/typescript/ai-openai/src/realtime/adapter.ts
index 043f60771c..2ca879e7ae 100644
--- a/packages/typescript/ai-openai/src/realtime/adapter.ts
+++ b/packages/typescript/ai-openai/src/realtime/adapter.ts
@@ -248,7 +248,11 @@ async function createWebRTCConnection(
case 'response.output_text.done': {
const text = event.text as string
- emit('transcript', { role: 'assistant', transcript: text, isFinal: true })
+ emit('transcript', {
+ role: 'assistant',
+ transcript: text,
+ isFinal: true,
+ })
break
}
From 3580092d293ad653105e9b217eba713a43aa39e9 Mon Sep 17 00:00:00 2001
From: Jack Herrington
Date: Fri, 6 Mar 2026 14:08:22 -0800
Subject: [PATCH 28/31] Getting close to releasable
---
docs/architecture/realtime-chat.md | 398 ----------------
docs/config.json | 8 +
docs/guides/realtime-chat.md | 446 ++++++++++++++++++
docs/reference/classes/RealtimeClient.md | 276 +++++++++++
docs/reference/functions/realtimeToken.md | 75 +++
.../interfaces/AudioVisualization.md | 126 +++++
docs/reference/interfaces/RealtimeAdapter.md | 48 ++
.../interfaces/RealtimeClientOptions.md | 204 ++++++++
.../interfaces/RealtimeConnection.md | 210 +++++++++
docs/reference/interfaces/RealtimeMessage.md | 80 ++++
.../interfaces/RealtimeSessionConfig.md | 120 +++++
docs/reference/interfaces/RealtimeToken.md | 50 ++
.../interfaces/RealtimeTokenAdapter.md | 34 ++
.../interfaces/RealtimeTokenOptions.md | 23 +
docs/reference/type-aliases/RealtimeEvent.md | 33 ++
.../type-aliases/RealtimeMessagePart.md | 27 ++
docs/reference/type-aliases/RealtimeMode.md | 21 +
docs/reference/type-aliases/RealtimeStatus.md | 22 +
.../ts-react-chat/src/lib/use-realtime.ts | 13 +
.../ts-react-chat/src/routes/realtime.tsx | 164 ++++++-
.../ai-client/src/realtime-client.ts | 58 ++-
.../ai-client/src/realtime-types.ts | 30 +-
.../ai-elevenlabs/src/realtime/adapter.ts | 62 ++-
.../ai-openai/src/realtime/adapter.ts | 42 +-
.../ai-openai/src/realtime/types.ts | 4 +
.../typescript/ai-react/src/realtime-types.ts | 24 +
.../ai-react/src/use-realtime-chat.ts | 15 +
packages/typescript/ai/src/index.ts | 1 +
packages/typescript/ai/src/realtime/types.ts | 20 +
29 files changed, 2214 insertions(+), 420 deletions(-)
delete mode 100644 docs/architecture/realtime-chat.md
create mode 100644 docs/guides/realtime-chat.md
create mode 100644 docs/reference/classes/RealtimeClient.md
create mode 100644 docs/reference/functions/realtimeToken.md
create mode 100644 docs/reference/interfaces/AudioVisualization.md
create mode 100644 docs/reference/interfaces/RealtimeAdapter.md
create mode 100644 docs/reference/interfaces/RealtimeClientOptions.md
create mode 100644 docs/reference/interfaces/RealtimeConnection.md
create mode 100644 docs/reference/interfaces/RealtimeMessage.md
create mode 100644 docs/reference/interfaces/RealtimeSessionConfig.md
create mode 100644 docs/reference/interfaces/RealtimeToken.md
create mode 100644 docs/reference/interfaces/RealtimeTokenAdapter.md
create mode 100644 docs/reference/interfaces/RealtimeTokenOptions.md
create mode 100644 docs/reference/type-aliases/RealtimeEvent.md
create mode 100644 docs/reference/type-aliases/RealtimeMessagePart.md
create mode 100644 docs/reference/type-aliases/RealtimeMode.md
create mode 100644 docs/reference/type-aliases/RealtimeStatus.md
diff --git a/docs/architecture/realtime-chat.md b/docs/architecture/realtime-chat.md
deleted file mode 100644
index 315482a51e..0000000000
--- a/docs/architecture/realtime-chat.md
+++ /dev/null
@@ -1,398 +0,0 @@
----
-title: Realtime Voice Chat Architecture
-id: realtime-chat-architecture
----
-
-# Realtime Voice Chat Architecture
-
-This document describes the architecture of TanStack AI's realtime voice-to-voice chat capability, which enables browser-based voice conversations with AI models.
-
-## Overview
-
-The realtime chat system provides a vendor-neutral, type-safe abstraction for voice-to-voice AI interactions. It currently supports:
-
-- **OpenAI Realtime API** - WebRTC-based connection with GPT-4o realtime models
-- **ElevenLabs Conversational AI** - SDK-based connection for voice conversations
-
-## Architecture Layers
-
-```
-┌─────────────────────────────────────────────────────────────────┐
-│ React Application │
-│ ┌─────────────────────────────────────────────────────────┐ │
-│ │ useRealtimeChat() │ │
-│ │ - Connection state (status, mode) │ │
-│ │ - Messages & transcripts │ │
-│ │ - Audio visualization (levels, waveforms) │ │
-│ │ - Control methods (connect, disconnect, interrupt) │ │
-│ │ - Client-side tool configuration │ │
-│ └─────────────────────────────────────────────────────────┘ │
-└─────────────────────────────────────────────────────────────────┘
- │
- ▼
-┌─────────────────────────────────────────────────────────────────┐
-│ @tanstack/ai-client │
-│ ┌─────────────────────────────────────────────────────────┐ │
-│ │ RealtimeClient │ │
-│ │ - Connection lifecycle management │ │
-│ │ - Token refresh scheduling │ │
-│ │ - Client-side session configuration (tools, voice, etc) │ │
-│ │ - Event subscription & dispatch │ │
-│ │ - Tool execution coordination │ │
-│ └─────────────────────────────────────────────────────────┘ │
-└─────────────────────────────────────────────────────────────────┘
- │
- ▼
-┌─────────────────────────────────────────────────────────────────┐
-│ Provider Adapters │
-│ ┌──────────────────────┐ ┌──────────────────────┐ │
-│ │ openaiRealtime() │ │ elevenlabsRealtime() │ │
-│ │ - WebRTC connection │ │ - SDK wrapper │ │
-│ │ - Audio I/O │ │ - Signed URL auth │ │
-│ │ - Event mapping │ │ - Event mapping │ │
-│ │ - Session updates │ │ │ │
-│ └──────────────────────┘ └──────────────────────┘ │
-└─────────────────────────────────────────────────────────────────┘
- │
- ▼
-┌─────────────────────────────────────────────────────────────────┐
-│ Server-Side │
-│ ┌─────────────────────────────────────────────────────────┐ │
-│ │ Token Generation (Server Function) │ │
-│ │ - openaiRealtimeToken() - ephemeral client secrets │ │
-│ │ - elevenlabsRealtimeToken() - signed URLs │ │
-│ │ (Minimal config: model only — session config is │ │
-│ │ applied client-side via session.update) │ │
-│ └─────────────────────────────────────────────────────────┘ │
-└─────────────────────────────────────────────────────────────────┘
-```
-
-## Key Components
-
-### 1. Token Adapters (Server-Side)
-
-Token adapters generate short-lived credentials for client-side connections. This keeps API keys secure on the server. The token endpoint sends **only the model** to the provider; all other session configuration (instructions, voice, tools, VAD) is applied client-side.
-
-```typescript
-// Server function (TanStack Start)
-import { createServerFn } from '@tanstack/react-start'
-import { realtimeToken } from '@tanstack/ai'
-import { openaiRealtimeToken } from '@tanstack/ai-openai'
-
-const getRealtimeTokenFn = createServerFn({ method: 'POST' })
- .handler(async () => {
- return realtimeToken({
- adapter: openaiRealtimeToken({
- model: 'gpt-4o-realtime-preview',
- }),
- })
- })
-```
-
-**Token Structure:**
-```typescript
-interface RealtimeToken {
- provider: string // 'openai' | 'elevenlabs'
- token: string // Ephemeral token or signed URL
- expiresAt: number // Expiration timestamp (ms)
- config: RealtimeSessionConfig // Session configuration
-}
-```
-
-### 2. Client Adapters (Browser-Side)
-
-Client adapters handle the actual connection to provider APIs, managing:
-- WebRTC or WebSocket connections
-- Audio capture and playback
-- Event translation to common format
-- Audio visualization data
-- Session configuration updates (tools, instructions, voice, VAD)
-
-```typescript
-// Client-side adapter usage
-import { openaiRealtime } from '@tanstack/ai-openai'
-
-const adapter = openaiRealtime({
- connectionMode: 'webrtc', // default
-})
-```
-
-**Data Channel Readiness:** The OpenAI adapter waits for the WebRTC data channel to be fully open before returning the connection. If `updateSession()` is called before the channel is ready, events are queued and flushed once the channel opens.
-
-### 3. RealtimeClient
-
-The `RealtimeClient` class manages the connection lifecycle:
-
-- **Connection Management**: Connect, disconnect, reconnect
-- **Token Refresh**: Automatically refreshes tokens before expiry
-- **Session Configuration**: Applies client-side config (instructions, voice, tools, VAD) via `session.update` after connecting
-- **Event Handling**: Subscribes to adapter events and dispatches to callbacks
-- **State Management**: Tracks status, mode, messages, transcripts
-- **Tool Execution**: Looks up client-side tools by name, executes them, and sends results back to the provider
-
-### 4. useRealtimeChat Hook
-
-The React hook provides a reactive interface:
-
-```typescript
-const {
- // Connection state
- status, // 'idle' | 'connecting' | 'connected' | 'reconnecting' | 'error'
- error,
- connect,
- disconnect,
-
- // Conversation state
- mode, // 'idle' | 'listening' | 'thinking' | 'speaking'
- messages,
- pendingUserTranscript,
- pendingAssistantTranscript,
-
- // Voice control
- startListening,
- stopListening,
- interrupt,
-
- // Audio visualization
- inputLevel,
- outputLevel,
- getInputTimeDomainData,
- getOutputTimeDomainData,
-} = useRealtimeChat({
- getToken: () => getRealtimeTokenFn(),
- adapter: openaiRealtime(),
- instructions: 'You are a helpful voice assistant.',
- voice: 'alloy',
- tools: myClientTools,
-})
-```
-
-## Connection Flow
-
-### OpenAI WebRTC Flow
-
-```mermaid
-sequenceDiagram
- participant Browser
- participant Server
- participant OpenAI
-
- Browser->>Server: getRealtimeTokenFn() (server function)
- Server->>OpenAI: POST /v1/realtime/sessions (model only)
- OpenAI-->>Server: { client_secret, expires_at }
- Server-->>Browser: RealtimeToken
-
- Browser->>Browser: getUserMedia() - request mic
- Browser->>Browser: Create RTCPeerConnection
- Browser->>Browser: Add audio track to PC
- Browser->>Browser: createOffer()
-
- Browser->>OpenAI: POST /v1/realtime?model=...
- Note right of Browser: SDP offer + ephemeral token
- OpenAI-->>Browser: SDP answer
-
- Browser->>Browser: setRemoteDescription()
- Browser->>Browser: Wait for data channel open
- Note over Browser,OpenAI: WebRTC connection established
-
- Browser->>OpenAI: session.update (tools, instructions, voice, VAD)
- OpenAI-->>Browser: session.updated (confirms config)
-
- Browser->>OpenAI: Audio via WebRTC
- OpenAI-->>Browser: Audio + events via WebRTC
-```
-
-### ElevenLabs Flow
-
-```mermaid
-sequenceDiagram
- participant Browser
- participant Server
- participant ElevenLabs
-
- Browser->>Server: getRealtimeTokenFn() (server function)
- Server->>ElevenLabs: POST /v1/convai/conversation/get_signed_url
- ElevenLabs-->>Server: { signed_url }
- Server-->>Browser: RealtimeToken
-
- Browser->>ElevenLabs: Conversation.startSession(signedUrl)
- Note over Browser,ElevenLabs: SDK handles WebSocket/WebRTC
-
- Browser->>ElevenLabs: Audio via SDK
- ElevenLabs-->>Browser: Audio + events via SDK
-```
-
-## Client-Side Tool Calling
-
-Tools are defined once using `toolDefinition()` and instantiated for client-side execution with `.client()`. When the AI model invokes a tool, the `RealtimeClient` executes it locally in the browser and sends the result back to the provider.
-
-### Tool Definition
-
-```typescript
-import { toolDefinition } from '@tanstack/ai'
-import { z } from 'zod'
-
-const getWeatherToolDef = toolDefinition({
- name: 'getWeather',
- description: 'Get the current weather for a location.',
- inputSchema: z.object({
- location: z.string().describe('City and state/country'),
- }),
- outputSchema: z.object({
- location: z.string(),
- temperature: z.number(),
- condition: z.string(),
- }),
-})
-
-// Create client-side implementation
-const getWeatherClient = getWeatherToolDef.client(({ location }) => ({
- location,
- temperature: 72,
- condition: 'Sunny',
-}))
-```
-
-### Tool Call Flow
-
-```mermaid
-sequenceDiagram
- participant User
- participant Browser as Browser (RealtimeClient)
- participant OpenAI
-
- User->>Browser: "What's the weather in London?"
- Browser->>OpenAI: Audio via WebRTC
-
- OpenAI->>Browser: response.function_call_arguments.done
- Note right of OpenAI: { name: "getWeather", arguments: '{"location":"London"}' }
-
- Browser->>Browser: Look up tool in clientTools Map
- Browser->>Browser: Execute tool.execute(input)
- Browser->>OpenAI: conversation.item.create (function_call_output)
- Browser->>OpenAI: response.create
-
- OpenAI->>Browser: response.audio_transcript.delta
- Note right of OpenAI: "The weather in London is 72°F and sunny!"
- OpenAI->>Browser: response.done
- Browser->>User: Display message + play audio
-```
-
-### Session Configuration
-
-When connecting, the `RealtimeClient` calls `applySessionConfig()` which sends a `session.update` event to the provider with:
-
-- **instructions** — System prompt for the assistant
-- **voice** — Voice to use for audio output (e.g., `'alloy'`)
-- **tools** — Array of `RealtimeToolConfig` descriptors (name, description, JSON Schema parameters), plus `tool_choice: 'auto'`
-- **turn_detection** — VAD configuration (server_vad, semantic_vad, or manual)
-- **input_audio_transcription** — Enables user speech transcription (e.g., Whisper)
-
-Tool schemas are converted from Zod (or any Standard JSON Schema compliant library) to JSON Schema using `convertSchemaToJsonSchema()` before being sent to the provider.
-
-## Audio Visualization
-
-The system provides real-time audio visualization through the `AudioVisualization` interface:
-
-```typescript
-interface AudioVisualization {
- inputLevel: number // 0-1 normalized input volume
- outputLevel: number // 0-1 normalized output volume
- getInputFrequencyData(): Uint8Array // FFT frequency bins
- getOutputFrequencyData(): Uint8Array
- getInputTimeDomainData(): Uint8Array // Raw waveform samples
- getOutputTimeDomainData(): Uint8Array
- inputSampleRate: number
- outputSampleRate: number
-}
-```
-
-The OpenAI adapter uses Web Audio API `AnalyserNode` for visualization:
-- `fftSize: 2048` for high-resolution analysis
-- Peak amplitude detection for responsive volume meters
-- Separate analysers for input (microphone) and output (AI voice)
-
-## Event System
-
-Adapters emit standardized events:
-
-| Event | Payload | Description |
-|-------|---------|-------------|
-| `status_change` | `{ status }` | Connection status changed |
-| `mode_change` | `{ mode }` | Conversation mode changed |
-| `transcript` | `{ role, transcript, isFinal }` | Speech-to-text update |
-| `message_complete` | `{ message }` | Full message received |
-| `tool_call` | `{ toolCallId, toolName, input }` | Tool invocation requested |
-| `interrupted` | `{ messageId? }` | Response was interrupted |
-| `error` | `{ error }` | Error occurred |
-
-## Current Status
-
-### Implemented Features
-
-- [x] OpenAI Realtime API integration (WebRTC)
-- [x] ElevenLabs Conversational AI integration
-- [x] Token generation and refresh
-- [x] Audio capture and playback
-- [x] Real-time transcription display
-- [x] Audio visualization (levels, waveforms)
-- [x] Interrupt capability
-- [x] Client-side tool calling (define, execute, return results)
-- [x] Client-side session configuration (instructions, voice, tools, VAD)
-- [x] React hook (`useRealtimeChat`)
-- [x] Demo application at `/realtime` route with tool examples
-
-### Known Limitations
-
-- **Device Selection**: Currently uses system default audio devices. Custom device selection not yet implemented.
-- **ElevenLabs SDK**: Using `@11labs/client@0.2.0` which has limited TypeScript support.
-- **Push-to-Talk**: Manual VAD mode implemented but not exposed in demo UI.
-
-### Demo Application
-
-The `examples/ts-react-chat` application includes a realtime voice chat demo at the `/realtime` route:
-
-**Features:**
-- Provider selection (OpenAI / ElevenLabs)
-- Connection status indicator
-- Conversation mode indicator (Listening/Thinking/Speaking)
-- Message history with transcripts
-- Audio level meters
-- Waveform visualization
-- Interrupt button during AI speech
-- Client-side tool execution (getCurrentTime, getWeather, setReminder, searchKnowledge)
-
-**Required Environment Variables:**
-```bash
-OPENAI_API_KEY=sk-...
-ELEVENLABS_API_KEY=xi-... # Optional, for ElevenLabs
-ELEVENLABS_AGENT_ID=... # Optional, for ElevenLabs
-```
-
-## Files Reference
-
-### Core Types
-- `packages/typescript/ai/src/realtime/types.ts` - Core type definitions
-- `packages/typescript/ai-client/src/realtime-types.ts` - Client-side types
-
-### Token Generation (Server)
-- `packages/typescript/ai/src/realtime/index.ts` - `realtimeToken()` function
-- `packages/typescript/ai-openai/src/realtime/token.ts` - OpenAI token adapter
-- `packages/typescript/ai-elevenlabs/src/realtime/token.ts` - ElevenLabs token adapter
-
-### Client Adapters
-- `packages/typescript/ai-openai/src/realtime/adapter.ts` - OpenAI WebRTC adapter
-- `packages/typescript/ai-elevenlabs/src/realtime/adapter.ts` - ElevenLabs SDK adapter
-
-### Client Library
-- `packages/typescript/ai-client/src/realtime-client.ts` - RealtimeClient class
-
-### React Integration
-- `packages/typescript/ai-react/src/use-realtime-chat.ts` - React hook
-- `packages/typescript/ai-react/src/realtime-types.ts` - Hook types
-
-### Demo Application
-- `examples/ts-react-chat/src/routes/realtime.tsx` - Demo UI component
-- `examples/ts-react-chat/src/lib/use-realtime.ts` - Custom hook with server function for token generation
-- `examples/ts-react-chat/src/lib/realtime-tools.ts` - Client-side tool definitions
-- `examples/ts-react-chat/src/components/AudioSparkline.tsx` - Audio waveform visualization component
diff --git a/docs/config.json b/docs/config.json
index 1439169ae0..05d2f8932d 100644
--- a/docs/config.json
+++ b/docs/config.json
@@ -78,6 +78,10 @@
"label": "Runtime Adapter Switching",
"to": "guides/runtime-adapter-switching"
},
+ {
+ "label": "Realtime Voice Chat",
+ "to": "guides/realtime-chat"
+ },
{
"label": "Text-to-Speech",
"to": "guides/text-to-speech"
@@ -224,6 +228,10 @@
"label": "ToolCallManager",
"to": "reference/classes/ToolCallManager"
},
+ {
+ "label": "RealtimeClient",
+ "to": "reference/classes/RealtimeClient"
+ },
{
"label": "WordBoundaryStrategy",
"to": "reference/classes/WordBoundaryStrategy"
diff --git a/docs/guides/realtime-chat.md b/docs/guides/realtime-chat.md
new file mode 100644
index 0000000000..afe2943c62
--- /dev/null
+++ b/docs/guides/realtime-chat.md
@@ -0,0 +1,446 @@
+---
+title: Realtime Voice Chat
+id: realtime-chat
+order: 14
+---
+
+TanStack AI provides a complete realtime voice chat system for building voice-to-voice AI interactions. The realtime API supports multiple providers (OpenAI, ElevenLabs), automatic tool execution, audio visualization, and multimodal input including images.
+
+## Overview
+
+Realtime voice chat differs from text-based chat in several key ways:
+
+- **Bidirectional audio** - Users speak into a microphone, and the AI responds with synthesized voice
+- **Voice Activity Detection (VAD)** - Automatically detects when the user starts and stops speaking
+- **Interruptions** - Users can interrupt the AI mid-response
+- **Low latency** - Uses WebRTC or WebSocket connections for near-instant communication
+- **Multimodal** - Supports text input, image input, and tool calling alongside voice
+
+The realtime system follows the same adapter architecture as the rest of TanStack AI:
+
+1. **Server** generates ephemeral tokens using `realtimeToken()` with a provider-specific token adapter
+2. **Client** connects using `RealtimeClient` (or `useRealtimeChat` in React) with a provider-specific connection adapter
+3. **Provider adapters** handle the protocol differences between OpenAI WebRTC, ElevenLabs WebSocket, etc.
+
+## Quick Start
+
+### 1. Set Up the Server Token Endpoint
+
+The server generates short-lived tokens so your API keys never reach the client:
+
+```typescript
+import { realtimeToken } from '@tanstack/ai'
+import { openaiRealtimeToken } from '@tanstack/ai-openai'
+import { createServerFn } from '@tanstack/react-start'
+
+const getRealtimeToken = createServerFn({ method: 'POST' })
+ .handler(async () => {
+ return realtimeToken({
+ adapter: openaiRealtimeToken({
+ model: 'gpt-4o-realtime-preview',
+ }),
+ })
+ })
+```
+
+> **Note:** The `realtimeToken()` function works with any server framework. The example above uses TanStack Start, but you can use Express, Hono, Fastify, or any other framework that can handle HTTP requests.
+
+### 2. Connect from the Client (React)
+
+```typescript
+import { useRealtimeChat } from '@tanstack/ai-react'
+import { openaiRealtime } from '@tanstack/ai-openai'
+
+function VoiceChat() {
+ const {
+ status,
+ mode,
+ messages,
+ connect,
+ disconnect,
+ pendingUserTranscript,
+ pendingAssistantTranscript,
+ inputLevel,
+ outputLevel,
+ } = useRealtimeChat({
+ getToken: () => fetch('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/api/realtime-token', { method: 'POST' }).then(r => r.json()),
+ adapter: openaiRealtime(),
+ instructions: 'You are a helpful voice assistant.',
+ voice: 'alloy',
+ })
+
+ return (
+
+
Status: {status}
+
Mode: {mode}
+
+ {status === 'idle' ? 'Start Conversation' : 'End Conversation'}
+
+ {pendingUserTranscript &&
You: {pendingUserTranscript}...
}
+ {pendingAssistantTranscript &&
AI: {pendingAssistantTranscript}...
}
+ {messages.map((msg) => (
+
+