├── .gitignore ├── README.md ├── example ├── .env.example ├── .gitignore ├── README.md ├── next.config.mjs ├── package-lock.json ├── package.json ├── pnpm-lock.yaml ├── postcss.config.mjs ├── public │ ├── next.svg │ └── vercel.svg ├── src │ └── app │ │ ├── favicon.ico │ │ ├── globals.css │ │ ├── layout.tsx │ │ └── page.tsx ├── tailwind.config.ts └── tsconfig.json ├── lib ├── VapiComponent.d.ts ├── VapiComponent.js ├── global.d.js ├── index.d.ts └── index.js ├── package-lock.json ├── package.json ├── src ├── VapiComponent.tsx ├── global.d.ts └── index.tsx └── tsconfig.json /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # All-in-One Vapi Component 2 | 3 | ### Integrate Vapi Voice AI into your web applications effortlessly. 4 | 5 | Add `` in your React or Next.js app & simplify Voice AI integrations. VapiComponent has everything you need baked-in and wraps all functionality and types for easy development. `` is intentionally designed for you to seamlessly integrate Vapi Voice AI services into your web applications. This component is turnkey: developers can effortlessly start and manage voice calls, handle various events, support function-calling, display live transcripts, and customize the UI. 6 | 7 | [Demo](https://vapi-web-package.vercel.app) 8 | 9 | 10 | ## **Features** 11 | 12 | - Drop-in component and get started with Vapi Voice AI. 13 | - Manage voice calls with start, stop, and mute functionalities. 14 | - Event handling for various call & audio events. 15 | - Real-time transcription (display of conversation in text as it's happening). 16 | - Customizable styles and labels for all UI elements. 17 | - Advanced assistant configurations for function calling during a conversation 18 | 19 | ## **Blocks** 20 | ### Particle Orb 21 | ```tsx 22 | "use client"; 23 | import React, { useRef, useEffect, useState } from 'react'; 24 | import * as THREE from 'three'; 25 | import { EffectComposer } from 'three/examples/jsm/postprocessing/EffectComposer.js'; 26 | import { RenderPass } from 'three/examples/jsm/postprocessing/RenderPass.js'; 27 | import { UnrealBloomPass } from 'three/examples/jsm/postprocessing/UnrealBloomPass.js'; 28 | import { OutputPass } from 'three/examples/jsm/postprocessing/OutputPass.js'; 29 | 30 | interface AudiovisualizerProps { 31 | red?: number; 32 | green?: number; 33 | blue?: number; 34 | currentVolume: number; 35 | startCall: () => void; 36 | stopCall: () => void; 37 | isSessionActive: boolean; 38 | initialSize?: number; 39 | activeSize?: number; 40 | } 41 | 42 | const Audiovisualizer: React.FC = ({ 43 | red = 1.0, 44 | green = 1.0, 45 | blue = 1.0, 46 | currentVolume, 47 | startCall, 48 | stopCall, 49 | isSessionActive, 50 | initialSize = 0.75, 51 | activeSize = 2 52 | }) => { 53 | const mountRef = useRef(null); 54 | const [loading, setLoading] = useState(false); 55 | 56 | useEffect(() => { 57 | const renderer = new THREE.WebGLRenderer({ antialias: true }); 58 | renderer.setSize(window.innerWidth, window.innerHeight); 59 | renderer.outputColorSpace = THREE.SRGBColorSpace; 60 | mountRef.current?.appendChild(renderer.domElement); 61 | 62 | const scene = new THREE.Scene(); 63 | const camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000); 64 | camera.position.set(0, -2, 14); 65 | camera.lookAt(0, 0, 0); 66 | 67 | const params = { 68 | threshold: 0.5, 69 | strength: 0.5, 70 | radius: 0.8 71 | }; 72 | 73 | const renderScene = new RenderPass(scene, camera); 74 | const bloomPass = new UnrealBloomPass( 75 | new THREE.Vector2(window.innerWidth, window.innerHeight), 76 | params.strength, 77 | params.radius, 78 | params.threshold 79 | ); 80 | 81 | const bloomComposer = new EffectComposer(renderer); 82 | bloomComposer.addPass(renderScene); 83 | bloomComposer.addPass(bloomPass); 84 | 85 | const outputPass = new OutputPass(); 86 | bloomComposer.addPass(outputPass); 87 | 88 | const uniforms = { 89 | u_time: { type: 'f', value: 0.0 }, 90 | u_frequency: { type: 'f', value: currentVolume }, 91 | u_red: { type: 'f', value: red }, 92 | u_green: { type: 'f', value: green }, 93 | u_blue: { type: 'f', value: blue } 94 | }; 95 | 96 | const mat = new THREE.ShaderMaterial({ 97 | uniforms, 98 | vertexShader: ` 99 | uniform float u_time; 100 | uniform float u_frequency; 101 | 102 | vec3 mod289(vec3 x) { 103 | return x - floor(x * (1.0 / 289.0)) * 289.0; 104 | } 105 | 106 | vec4 mod289(vec4 x) { 107 | return x - floor(x * (1.0 / 289.0)) * 289.0; 108 | } 109 | 110 | vec4 permute(vec4 x) { 111 | return mod289(((x * 34.0) + 10.0) * x); 112 | } 113 | 114 | vec4 taylorInvSqrt(vec4 r) { 115 | return 1.79284291400159 - 0.85373472095314 * r; 116 | } 117 | 118 | vec3 fade(vec3 t) { 119 | return t * t * t * (t * (t * 6.0 - 15.0) + 10.0); 120 | } 121 | 122 | float pnoise(vec3 P, vec3 rep) { 123 | vec3 Pi0 = mod(floor(P), rep); // Integer part, modulo period 124 | vec3 Pi1 = mod(Pi0 + vec3(1.0), rep); // Integer part + 1, mod period 125 | Pi0 = mod289(Pi0); 126 | Pi1 = mod289(Pi1); 127 | vec3 Pf0 = fract(P); // Fractional part for interpolation 128 | vec3 Pf1 = Pf0 - vec3(1.0); // Fractional part - 1.0 129 | vec4 ix = vec4(Pi0.x, Pi1.x, Pi0.x, Pi1.x); 130 | vec4 iy = vec4(Pi0.yy, Pi1.yy); 131 | vec4 iz0 = Pi0.zzzz; 132 | vec4 iz1 = Pi1.zzzz; 133 | 134 | vec4 ixy = permute(permute(ix) + iy); 135 | vec4 ixy0 = permute(ixy + iz0); 136 | vec4 ixy1 = permute(ixy + iz1); 137 | 138 | vec4 gx0 = ixy0 * (1.0 / 7.0); 139 | vec4 gy0 = fract(floor(gx0) * (1.0 / 7.0)) - 0.5; 140 | gx0 = fract(gx0); 141 | vec4 gz0 = vec4(0.5) - abs(gx0) - abs(gy0); 142 | vec4 sz0 = step(gz0, vec4(0.0)); 143 | gx0 -= sz0 * (step(0.0, gx0) - 0.5); 144 | gy0 -= sz0 * (step(0.0, gy0) - 0.5); 145 | 146 | vec4 gx1 = ixy1 * (1.0 / 7.0); 147 | vec4 gy1 = fract(floor(gx1) * (1.0 / 7.0)) - 0.5; 148 | gx1 = fract(gx1); 149 | vec4 gz1 = vec4(0.5) - abs(gx1) - abs(gy1); 150 | vec4 sz1 = step(gz1, vec4(0.0)); 151 | gx1 -= sz1 * (step(0.0, gx1) - 0.5); 152 | gy1 -= sz1 * (step(0.0, gy1) - 0.5); 153 | 154 | vec3 g000 = vec3(gx0.x,gy0.x,gz0.x); 155 | vec3 g100 = vec3(gx0.y,gy0.y,gz0.y); 156 | vec3 g010 = vec3(gx0.z,gy0.z,gz0.z); 157 | vec3 g110 = vec3(gx0.w,gy0.w,gz0.w); 158 | vec3 g001 = vec3(gx1.x,gy1.x,gz1.x); 159 | vec3 g101 = vec3(gx1.y,gy1.y,gz1.y); 160 | vec3 g011 = vec3(gx1.z,gy1.z,gx1.z); 161 | vec3 g111 = vec3(gx1.w,gy1.w,gx1.w); 162 | 163 | vec4 norm0 = taylorInvSqrt(vec4(dot(g000, g000), dot(g010, g010), dot(g100, g100), dot(g110, g110))); 164 | g000 *= norm0.x; 165 | g010 *= norm0.y; 166 | g100 *= norm0.z; 167 | g110 *= norm0.w; 168 | vec4 norm1 = taylorInvSqrt(vec4(dot(g001, g001), dot(g011, g011), dot(g101, g101), dot(g111, g111))); 169 | g001 *= norm1.x; 170 | g011 *= norm1.y; 171 | g101 *= norm1.z; 172 | g111 *= norm1.w; 173 | 174 | float n000 = dot(g000, Pf0); 175 | float n100 = dot(g100, vec3(Pf1.x, Pf0.yz)); 176 | float n010 = dot(g010, vec3(Pf0.x, Pf1.y, Pf0.z)); 177 | float n110 = dot(g110, vec3(Pf1.xy, Pf0.z)); 178 | float n001 = dot(g001, vec3(Pf0.xy, Pf1.z)); 179 | float n101 = dot(g101, vec3(Pf1.x, Pf0.y, Pf1.z)); 180 | float n011 = dot(g011, vec3(Pf0.x, Pf1.yz)); 181 | float n111 = dot(g111, Pf1); 182 | 183 | vec3 fade_xyz = fade(Pf0); 184 | vec4 n_z = mix(vec4(n000, n100, n010, n110), vec4(n001, n101, n011, n111), fade_xyz.z); 185 | vec2 n_yz = mix(n_z.xy, n_z.zw, fade_xyz.y); 186 | float n_xyz = mix(n_yz.x, n_yz.y, fade_xyz.x); 187 | return 2.2 * n_xyz; 188 | } 189 | 190 | void main() { 191 | float noise = 3.0 * pnoise(position + u_time, vec3(10.0)); 192 | float baseDisplacement = 0.5; // Base displacement value 193 | float displacement = baseDisplacement + (u_frequency / 30.0) * (noise / 10.0); 194 | vec3 newPosition = position + normal * displacement; 195 | gl_Position = projectionMatrix * modelViewMatrix * vec4(newPosition, 1.0); 196 | }`, 197 | fragmentShader: ` 198 | uniform float u_red; 199 | uniform float u_blue; 200 | uniform float u_green; 201 | 202 | void main() { 203 | gl_FragColor = vec4(vec3(u_red, u_green, u_blue), 0.5); // Set alpha to 0.5 for transparency 204 | }`, 205 | wireframe: true 206 | }); 207 | 208 | const geo = new THREE.IcosahedronGeometry(isSessionActive ? activeSize : initialSize, isSessionActive ? 9 : 5); // Reduced detail level 209 | const mesh = new THREE.Mesh(geo, mat); 210 | scene.add(mesh); 211 | 212 | const clock = new THREE.Clock(); 213 | const animate = () => { 214 | // Smoothly update the volume 215 | uniforms.u_frequency.value = THREE.MathUtils.lerp(uniforms.u_frequency.value, currentVolume, 0.1); 216 | if (isSessionActive) { 217 | uniforms.u_frequency.value += 3.5; // Intensify morphing when the call is active 218 | } 219 | mesh.rotation.x += 0.025; 220 | mesh.rotation.y += 0.001; 221 | uniforms.u_time.value = clock.getElapsedTime(); 222 | bloomComposer.render(); 223 | requestAnimationFrame(animate); 224 | }; 225 | animate(); 226 | 227 | window.addEventListener('resize', () => { 228 | camera.aspect = window.innerWidth / window.innerHeight; 229 | camera.updateProjectionMatrix(); 230 | renderer.setSize(window.innerWidth, window.innerHeight); 231 | bloomComposer.setSize(window.innerWidth, window.innerHeight); 232 | }); 233 | 234 | const handleClick = () => { 235 | if (isSessionActive) { 236 | stopCall(); 237 | } else { 238 | startCall(); 239 | } 240 | setLoading(true); 241 | setTimeout(() => setLoading(false), 2000); // Simulating a delay for the loading state 242 | }; 243 | 244 | mountRef.current?.addEventListener('click', handleClick); 245 | 246 | return () => { 247 | mountRef.current?.removeChild(renderer.domElement); 248 | mountRef.current?.removeEventListener('click', handleClick); 249 | }; 250 | }, [red, green, blue, currentVolume, startCall, stopCall, isSessionActive, initialSize, activeSize]); 251 | 252 | return ( 253 | 254 | {!isSessionActive && !loading && Click to Demo} 255 | {loading && One moment...} 256 | 257 | ); 258 | }; 259 | 260 | export default Audiovisualizer; 261 | ``` 262 | 263 | ## **Installation** 264 | To install the package, run: 265 | 266 | 267 | 268 | ```bash 269 | 270 | npm install vapi-web 271 | 272 | ``` 273 | 274 | 275 | 276 | ## **Usage** 277 | To use the `VapiComponent`, import it into your application and configure it with the necessary props. 278 | 279 | ```jsx 280 | import { VapiComponent } from "vapi-web" 281 | 284 | ``` 285 | 286 | 287 | ### **Props** 288 | 289 | | Prop | Type | Description | Default | 290 | |------------------------|-------------|--------------------------------------------------------------------------|-------------------------| 291 | | `publicKey` | `string` | Your Vapi public key for authentication. | | 292 | | `assistantId` | `string` | The ID of the pre-configured assistant. | | 293 | | `assistantConfig` | `object` | Inline configuration if `assistantId` is not provided. | | 294 | | `assistantOverrides` | `object` | Configuration overrides for the assistant. | | 295 | | `onEvents` | `object` | Handlers for various Vapi events (e.g., call-start, message). | | 296 | | `startButtonLabel` | `string` | Label for the start call button. | `"Start Call"` | 297 | | `stopButtonLabel` | `string` | Label for the stop call button. | `"Stop Call"` | 298 | | `muteButtonLabel` | `string` | Label for the mute button. | `"Mute"` | 299 | | `unmuteButtonLabel` | `string` | Label for the unmute button. | `"Unmute"` | 300 | | `logActionButtonLabel` | `string` | Label for the log action button. | `"Log Action"` | 301 | | `logActionMessage` | `string` | Message that will be logged when log action button is pressed. | `"The user has pressed the button, say peanuts"` | 302 | | `showLogActionButton` | `boolean` | Whether to show the log action button or not. | `true` | 303 | | `callStatusLabel` | `string` | Label for the call status display. | `"Call Status"` | 304 | | `transcriptLabel` | `string` | Label for the transcript display. | `"Transcript"` | 305 | | `onStart` | `function` | Callback when the start button is clicked. | | 306 | | `onStop` | `function` | Callback when the stop button is clicked. | | 307 | | `onMuteToggle` | `function` | Callback when the mute button is toggled. | | 308 | | `onVolumeChange` | `function` | Callback for realtime volumne levels (0-1). | | 309 | | `onTranscriptUpdate` | `function` | Callback when transcript updates. | | 310 | | `showTranscript` | `boolean` | Show/hide transcript display. | `true` | 311 | | `autoStart` | `boolean` | Automatically start the assistant when component mounts. | `false` | 312 | | `onFunctionCall` | `function` | Callback for function calls received in messages. | | 313 | | `styles` | `object` | Custom styles for various elements. | 314 | 315 | 316 | 317 | ## Styles: *Styles Interface* detailing configurable styles. 318 | - *container*: `React.CSSProperties | Style for the container element`. 319 | - *buttonContainer*: `React.CSSProperties | Style for the button container`. 320 | - *startButton*: `React.CSSProperties | Style for the start button`. 321 | - *stopButton*: `React.CSSProperties | Style for the stop button`. 322 | - *muteButton*: `React.CSSProperties | Style for the mute button`. 323 | - *logActionButton*: `React.CSSProperties | (Style for the log action button)`. 324 | - *statusContainer*: `React.CSSProperties | Style for the status container`. 325 | - *transcriptContainer*: `React.CSSProperties | Style for the transcript container`. 326 | - *transcriptEntry*: `React.CSSProperties | (Style for each transcript entry)`. 327 | 328 | 329 | ## **Example** 330 | Here’s an advanced usage example that demonstrates complex setup, custom event handling, dynamic styling, and advanced assistant configuration. 331 | 332 | ```jsx 333 | // Example usage in a component or app/page.tsx 334 | import React from 'react'; 335 | import VapiComponent from 'vapi-web'; 336 | ... 337 | 338 | const App = () => { 339 | ... 340 | 341 | const handleEvents = { 342 | 'call-start': () => console.log('Call started'), 343 | 'call-end': () => console.log('Call ended'), 344 | 'speech-start': () => console.log('Speech started'), 345 | 'speech-end': () => console.log('Speech ended'), 346 | 'volume-level': (volume: number) => console.log(`Volume level: ${volume}`), 347 | 'message': (message: any) => console.log('Message received:', message), 348 | 'error': (error: Error) => console.error('Error:', error), 349 | }; 350 | 351 | const handleTranscriptUpdate = (transcripts: TranscriptEntry[]) => { 352 | console.log('Transcript updated:', transcripts); 353 | }; 354 | 355 | const handleFunctionCall = (functionName: string, functionArgs: any) => { 356 | console.log(`Function called: ${functionName} with arguments:`, functionArgs); 357 | if (functionName === 'exampleFunction') { 358 | // Handle the function call 359 | alert(`Function called with args: ${JSON.stringify(functionArgs)}`); 360 | } 361 | }; 362 | 363 | const customStyles = { 364 | container: { padding: '20px', border: '1px solid #ccc', borderRadius: '8px', maxWidth: '600px', margin: '0 auto' }, 365 | buttonContainer: { marginBottom: '10px', display: 'flex', gap: '10px' }, 366 | startButton: { backgroundColor: '#4CAF50', color: 'white', padding: '10px', border: 'none', borderRadius: '4px', cursor: 'pointer' }, 367 | stopButton: { backgroundColor: '#f44336', color: 'white', padding: '10px', border: 'none', borderRadius: '4px', cursor: 'pointer' }, 368 | muteButton: { backgroundColor: '#008CBA', color: 'white', padding: '10px', border: 'none', borderRadius: '4px', cursor: 'pointer' }, 369 | statusContainer: { marginTop: '10px' }, 370 | transcriptContainer: { marginTop: '10px', whiteSpace: 'pre-wrap', backgroundColor: '#f1f1f1', padding: '10px', borderRadius: '4px' }, 371 | }; 372 | 373 | return ( 374 | 375 | Advanced Vapi Voice Assistant 376 | console.log('Call started')} 388 | onStop={() => console.log('Call stopped')} 389 | onMuteToggle={(isMuted) => console.log(`Mute toggled: ${isMuted}`)} 390 | onTranscriptUpdate={handleTranscriptUpdate} 391 | onFunctionCall={handleFunctionCall} 392 | autoStart={true} // Automatically starts the call 393 | styles={customStyles} 394 | /> 395 | 396 | ); 397 | }; 398 | ``` 399 | 400 | ### Key Highlights: 401 | 402 | - **State Management**: `useState` is used for managing the transcript and call duration states. 403 | - **Event Handling**: The `handleEvents` object contains event handlers for various Vapi events, enabling features like tracking call status, updating transcript, etc. 404 | - **Custom Styles**: The `customStyles` object allows you to apply custom styles ensuring the component matches your design language. 405 | - **Advanced Assistant Configuration**: The `assistantConfig` object encompasses comprehensive settings, including transcriber, model, and voice configurations. 406 | 407 | 408 | ### Extending the Component 409 | 410 | The `VapiComponent` is extremely flexible and can be adapted for numerous use cases. Customize UI elements and add functionality using provided props to build comprehensive and responsive voice-interactive applications. 411 | 412 | By leveraging all the props, this example demonstrates creating a highly configurable and engaging Vapi Voice Assistant within a Next.js app. 413 | 414 | ## **License** 415 | 416 | This project is licensed under the MIT License. 417 | 418 | 419 | 420 | ## **Acknowledgements** 421 | Special thanks to the Vapi Team for their support and continuous development of the Vapi API. 422 | 423 | ## Next Steps 424 | Work with Aceternity UI team to design beautiful styles / templates for a beautiful drop-in Voice AI solution 425 | -------------------------------------------------------------------------------- /example/.env.example: -------------------------------------------------------------------------------- 1 | NEXT_PUBLIC_VAPI_PUBLIC_KEY= 2 | NEXT_PUBLIC_VAPI_ASSISTANT_ID= -------------------------------------------------------------------------------- /example/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | .env 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | .yarn/install-state.gz 8 | 9 | # testing 10 | /coverage 11 | 12 | # next.js 13 | /.next/ 14 | /out/ 15 | 16 | # production 17 | /build 18 | 19 | # misc 20 | .DS_Store 21 | *.pem 22 | 23 | # debug 24 | npm-debug.log* 25 | yarn-debug.log* 26 | yarn-error.log* 27 | 28 | # local env files 29 | .env*.local 30 | 31 | # vercel 32 | .vercel 33 | 34 | # typescript 35 | *.tsbuildinfo 36 | next-env.d.ts 37 | -------------------------------------------------------------------------------- /example/README.md: -------------------------------------------------------------------------------- 1 | This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app). 2 | 3 | ## Getting Started 4 | 5 | First, run the development server: 6 | 7 | ```bash 8 | npm run dev 9 | # or 10 | yarn dev 11 | # or 12 | pnpm dev 13 | # or 14 | bun dev 15 | ``` 16 | 17 | Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. 18 | 19 | You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file. 20 | 21 | This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font. 22 | 23 | ## Learn More 24 | 25 | To learn more about Next.js, take a look at the following resources: 26 | 27 | - [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. 28 | - [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. 29 | 30 | You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome! 31 | 32 | ## Deploy on Vercel 33 | 34 | The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. 35 | 36 | Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details. 37 | -------------------------------------------------------------------------------- /example/next.config.mjs: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = {}; 3 | 4 | export default nextConfig; 5 | -------------------------------------------------------------------------------- /example/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vapi-demo", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev", 7 | "build": "next build", 8 | "start": "next start", 9 | "lint": "next lint" 10 | }, 11 | "dependencies": { 12 | "lucide-react": "^0.379.0", 13 | "next": "14.2.3", 14 | "react": "^18", 15 | "react-dom": "^18", 16 | "vapi-web": "file:../" 17 | }, 18 | "devDependencies": { 19 | "@types/node": "^20", 20 | "@types/react": "^18", 21 | "@types/react-dom": "^18", 22 | "postcss": "^8", 23 | "tailwindcss": "^3.4.1", 24 | "typescript": "^5" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /example/pnpm-lock.yaml: -------------------------------------------------------------------------------- 1 | lockfileVersion: '6.0' 2 | 3 | settings: 4 | autoInstallPeers: true 5 | excludeLinksFromLockfile: false 6 | 7 | dependencies: 8 | lucide-react: 9 | specifier: ^0.379.0 10 | version: 0.379.0(react@18.3.1) 11 | next: 12 | specifier: 14.2.3 13 | version: 14.2.3(react-dom@18.3.1)(react@18.3.1) 14 | react: 15 | specifier: ^18 16 | version: 18.3.1 17 | react-dom: 18 | specifier: ^18 19 | version: 18.3.1(react@18.3.1) 20 | 21 | devDependencies: 22 | '@types/node': 23 | specifier: ^20 24 | version: 20.12.12 25 | '@types/react': 26 | specifier: ^18 27 | version: 18.3.2 28 | '@types/react-dom': 29 | specifier: ^18 30 | version: 18.3.0 31 | postcss: 32 | specifier: ^8 33 | version: 8.4.38 34 | tailwindcss: 35 | specifier: ^3.4.1 36 | version: 3.4.3 37 | typescript: 38 | specifier: ^5 39 | version: 5.4.5 40 | 41 | packages: 42 | 43 | /@alloc/quick-lru@5.2.0: 44 | resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} 45 | engines: {node: '>=10'} 46 | dev: true 47 | 48 | /@isaacs/cliui@8.0.2: 49 | resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} 50 | engines: {node: '>=12'} 51 | dependencies: 52 | string-width: 5.1.2 53 | string-width-cjs: /string-width@4.2.3 54 | strip-ansi: 7.1.0 55 | strip-ansi-cjs: /strip-ansi@6.0.1 56 | wrap-ansi: 8.1.0 57 | wrap-ansi-cjs: /wrap-ansi@7.0.0 58 | dev: true 59 | 60 | /@jridgewell/gen-mapping@0.3.5: 61 | resolution: {integrity: sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==} 62 | engines: {node: '>=6.0.0'} 63 | dependencies: 64 | '@jridgewell/set-array': 1.2.1 65 | '@jridgewell/sourcemap-codec': 1.4.15 66 | '@jridgewell/trace-mapping': 0.3.25 67 | dev: true 68 | 69 | /@jridgewell/resolve-uri@3.1.2: 70 | resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} 71 | engines: {node: '>=6.0.0'} 72 | dev: true 73 | 74 | /@jridgewell/set-array@1.2.1: 75 | resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==} 76 | engines: {node: '>=6.0.0'} 77 | dev: true 78 | 79 | /@jridgewell/sourcemap-codec@1.4.15: 80 | resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} 81 | dev: true 82 | 83 | /@jridgewell/trace-mapping@0.3.25: 84 | resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} 85 | dependencies: 86 | '@jridgewell/resolve-uri': 3.1.2 87 | '@jridgewell/sourcemap-codec': 1.4.15 88 | dev: true 89 | 90 | /@next/env@14.2.3: 91 | resolution: {integrity: sha512-W7fd7IbkfmeeY2gXrzJYDx8D2lWKbVoTIj1o1ScPHNzvp30s1AuoEFSdr39bC5sjxJaxTtq3OTCZboNp0lNWHA==} 92 | dev: false 93 | 94 | /@next/swc-darwin-arm64@14.2.3: 95 | resolution: {integrity: sha512-3pEYo/RaGqPP0YzwnlmPN2puaF2WMLM3apt5jLW2fFdXD9+pqcoTzRk+iZsf8ta7+quAe4Q6Ms0nR0SFGFdS1A==} 96 | engines: {node: '>= 10'} 97 | cpu: [arm64] 98 | os: [darwin] 99 | requiresBuild: true 100 | dev: false 101 | optional: true 102 | 103 | /@next/swc-darwin-x64@14.2.3: 104 | resolution: {integrity: sha512-6adp7waE6P1TYFSXpY366xwsOnEXM+y1kgRpjSRVI2CBDOcbRjsJ67Z6EgKIqWIue52d2q/Mx8g9MszARj8IEA==} 105 | engines: {node: '>= 10'} 106 | cpu: [x64] 107 | os: [darwin] 108 | requiresBuild: true 109 | dev: false 110 | optional: true 111 | 112 | /@next/swc-linux-arm64-gnu@14.2.3: 113 | resolution: {integrity: sha512-cuzCE/1G0ZSnTAHJPUT1rPgQx1w5tzSX7POXSLaS7w2nIUJUD+e25QoXD/hMfxbsT9rslEXugWypJMILBj/QsA==} 114 | engines: {node: '>= 10'} 115 | cpu: [arm64] 116 | os: [linux] 117 | requiresBuild: true 118 | dev: false 119 | optional: true 120 | 121 | /@next/swc-linux-arm64-musl@14.2.3: 122 | resolution: {integrity: sha512-0D4/oMM2Y9Ta3nGuCcQN8jjJjmDPYpHX9OJzqk42NZGJocU2MqhBq5tWkJrUQOQY9N+In9xOdymzapM09GeiZw==} 123 | engines: {node: '>= 10'} 124 | cpu: [arm64] 125 | os: [linux] 126 | requiresBuild: true 127 | dev: false 128 | optional: true 129 | 130 | /@next/swc-linux-x64-gnu@14.2.3: 131 | resolution: {integrity: sha512-ENPiNnBNDInBLyUU5ii8PMQh+4XLr4pG51tOp6aJ9xqFQ2iRI6IH0Ds2yJkAzNV1CfyagcyzPfROMViS2wOZ9w==} 132 | engines: {node: '>= 10'} 133 | cpu: [x64] 134 | os: [linux] 135 | requiresBuild: true 136 | dev: false 137 | optional: true 138 | 139 | /@next/swc-linux-x64-musl@14.2.3: 140 | resolution: {integrity: sha512-BTAbq0LnCbF5MtoM7I/9UeUu/8ZBY0i8SFjUMCbPDOLv+un67e2JgyN4pmgfXBwy/I+RHu8q+k+MCkDN6P9ViQ==} 141 | engines: {node: '>= 10'} 142 | cpu: [x64] 143 | os: [linux] 144 | requiresBuild: true 145 | dev: false 146 | optional: true 147 | 148 | /@next/swc-win32-arm64-msvc@14.2.3: 149 | resolution: {integrity: sha512-AEHIw/dhAMLNFJFJIJIyOFDzrzI5bAjI9J26gbO5xhAKHYTZ9Or04BesFPXiAYXDNdrwTP2dQceYA4dL1geu8A==} 150 | engines: {node: '>= 10'} 151 | cpu: [arm64] 152 | os: [win32] 153 | requiresBuild: true 154 | dev: false 155 | optional: true 156 | 157 | /@next/swc-win32-ia32-msvc@14.2.3: 158 | resolution: {integrity: sha512-vga40n1q6aYb0CLrM+eEmisfKCR45ixQYXuBXxOOmmoV8sYST9k7E3US32FsY+CkkF7NtzdcebiFT4CHuMSyZw==} 159 | engines: {node: '>= 10'} 160 | cpu: [ia32] 161 | os: [win32] 162 | requiresBuild: true 163 | dev: false 164 | optional: true 165 | 166 | /@next/swc-win32-x64-msvc@14.2.3: 167 | resolution: {integrity: sha512-Q1/zm43RWynxrO7lW4ehciQVj+5ePBhOK+/K2P7pLFX3JaJ/IZVC69SHidrmZSOkqz7ECIOhhy7XhAFG4JYyHA==} 168 | engines: {node: '>= 10'} 169 | cpu: [x64] 170 | os: [win32] 171 | requiresBuild: true 172 | dev: false 173 | optional: true 174 | 175 | /@nodelib/fs.scandir@2.1.5: 176 | resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} 177 | engines: {node: '>= 8'} 178 | dependencies: 179 | '@nodelib/fs.stat': 2.0.5 180 | run-parallel: 1.2.0 181 | dev: true 182 | 183 | /@nodelib/fs.stat@2.0.5: 184 | resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} 185 | engines: {node: '>= 8'} 186 | dev: true 187 | 188 | /@nodelib/fs.walk@1.2.8: 189 | resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} 190 | engines: {node: '>= 8'} 191 | dependencies: 192 | '@nodelib/fs.scandir': 2.1.5 193 | fastq: 1.17.1 194 | dev: true 195 | 196 | /@pkgjs/parseargs@0.11.0: 197 | resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} 198 | engines: {node: '>=14'} 199 | requiresBuild: true 200 | dev: true 201 | optional: true 202 | 203 | /@swc/counter@0.1.3: 204 | resolution: {integrity: sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==} 205 | dev: false 206 | 207 | /@swc/helpers@0.5.5: 208 | resolution: {integrity: sha512-KGYxvIOXcceOAbEk4bi/dVLEK9z8sZ0uBB3Il5b1rhfClSpcX0yfRO0KmTkqR2cnQDymwLB+25ZyMzICg/cm/A==} 209 | dependencies: 210 | '@swc/counter': 0.1.3 211 | tslib: 2.6.2 212 | dev: false 213 | 214 | /@types/node@20.12.12: 215 | resolution: {integrity: sha512-eWLDGF/FOSPtAvEqeRAQ4C8LSA7M1I7i0ky1I8U7kD1J5ITyW3AsRhQrKVoWf5pFKZ2kILsEGJhsI9r93PYnOw==} 216 | dependencies: 217 | undici-types: 5.26.5 218 | dev: true 219 | 220 | /@types/prop-types@15.7.12: 221 | resolution: {integrity: sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==} 222 | dev: true 223 | 224 | /@types/react-dom@18.3.0: 225 | resolution: {integrity: sha512-EhwApuTmMBmXuFOikhQLIBUn6uFg81SwLMOAUgodJF14SOBOCMdU04gDoYi0WOJJHD144TL32z4yDqCW3dnkQg==} 226 | dependencies: 227 | '@types/react': 18.3.2 228 | dev: true 229 | 230 | /@types/react@18.3.2: 231 | resolution: {integrity: sha512-Btgg89dAnqD4vV7R3hlwOxgqobUQKgx3MmrQRi0yYbs/P0ym8XozIAlkqVilPqHQwXs4e9Tf63rrCgl58BcO4w==} 232 | dependencies: 233 | '@types/prop-types': 15.7.12 234 | csstype: 3.1.3 235 | dev: true 236 | 237 | /ansi-regex@5.0.1: 238 | resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} 239 | engines: {node: '>=8'} 240 | dev: true 241 | 242 | /ansi-regex@6.0.1: 243 | resolution: {integrity: sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==} 244 | engines: {node: '>=12'} 245 | dev: true 246 | 247 | /ansi-styles@4.3.0: 248 | resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} 249 | engines: {node: '>=8'} 250 | dependencies: 251 | color-convert: 2.0.1 252 | dev: true 253 | 254 | /ansi-styles@6.2.1: 255 | resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} 256 | engines: {node: '>=12'} 257 | dev: true 258 | 259 | /any-promise@1.3.0: 260 | resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} 261 | dev: true 262 | 263 | /anymatch@3.1.3: 264 | resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} 265 | engines: {node: '>= 8'} 266 | dependencies: 267 | normalize-path: 3.0.0 268 | picomatch: 2.3.1 269 | dev: true 270 | 271 | /arg@5.0.2: 272 | resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==} 273 | dev: true 274 | 275 | /balanced-match@1.0.2: 276 | resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} 277 | dev: true 278 | 279 | /binary-extensions@2.3.0: 280 | resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} 281 | engines: {node: '>=8'} 282 | dev: true 283 | 284 | /brace-expansion@2.0.1: 285 | resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} 286 | dependencies: 287 | balanced-match: 1.0.2 288 | dev: true 289 | 290 | /braces@3.0.3: 291 | resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} 292 | engines: {node: '>=8'} 293 | dependencies: 294 | fill-range: 7.1.1 295 | dev: true 296 | 297 | /busboy@1.6.0: 298 | resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==} 299 | engines: {node: '>=10.16.0'} 300 | dependencies: 301 | streamsearch: 1.1.0 302 | dev: false 303 | 304 | /camelcase-css@2.0.1: 305 | resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==} 306 | engines: {node: '>= 6'} 307 | dev: true 308 | 309 | /caniuse-lite@1.0.30001621: 310 | resolution: {integrity: sha512-+NLXZiviFFKX0fk8Piwv3PfLPGtRqJeq2TiNoUff/qB5KJgwecJTvCXDpmlyP/eCI/GUEmp/h/y5j0yckiiZrA==} 311 | dev: false 312 | 313 | /chokidar@3.6.0: 314 | resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} 315 | engines: {node: '>= 8.10.0'} 316 | dependencies: 317 | anymatch: 3.1.3 318 | braces: 3.0.3 319 | glob-parent: 5.1.2 320 | is-binary-path: 2.1.0 321 | is-glob: 4.0.3 322 | normalize-path: 3.0.0 323 | readdirp: 3.6.0 324 | optionalDependencies: 325 | fsevents: 2.3.3 326 | dev: true 327 | 328 | /client-only@0.0.1: 329 | resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==} 330 | dev: false 331 | 332 | /color-convert@2.0.1: 333 | resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} 334 | engines: {node: '>=7.0.0'} 335 | dependencies: 336 | color-name: 1.1.4 337 | dev: true 338 | 339 | /color-name@1.1.4: 340 | resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} 341 | dev: true 342 | 343 | /commander@4.1.1: 344 | resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} 345 | engines: {node: '>= 6'} 346 | dev: true 347 | 348 | /cross-spawn@7.0.3: 349 | resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} 350 | engines: {node: '>= 8'} 351 | dependencies: 352 | path-key: 3.1.1 353 | shebang-command: 2.0.0 354 | which: 2.0.2 355 | dev: true 356 | 357 | /cssesc@3.0.0: 358 | resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} 359 | engines: {node: '>=4'} 360 | hasBin: true 361 | dev: true 362 | 363 | /csstype@3.1.3: 364 | resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} 365 | dev: true 366 | 367 | /didyoumean@1.2.2: 368 | resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==} 369 | dev: true 370 | 371 | /dlv@1.1.3: 372 | resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==} 373 | dev: true 374 | 375 | /eastasianwidth@0.2.0: 376 | resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} 377 | dev: true 378 | 379 | /emoji-regex@8.0.0: 380 | resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} 381 | dev: true 382 | 383 | /emoji-regex@9.2.2: 384 | resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} 385 | dev: true 386 | 387 | /fast-glob@3.3.2: 388 | resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==} 389 | engines: {node: '>=8.6.0'} 390 | dependencies: 391 | '@nodelib/fs.stat': 2.0.5 392 | '@nodelib/fs.walk': 1.2.8 393 | glob-parent: 5.1.2 394 | merge2: 1.4.1 395 | micromatch: 4.0.6 396 | dev: true 397 | 398 | /fastq@1.17.1: 399 | resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==} 400 | dependencies: 401 | reusify: 1.0.4 402 | dev: true 403 | 404 | /fill-range@7.1.1: 405 | resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} 406 | engines: {node: '>=8'} 407 | dependencies: 408 | to-regex-range: 5.0.1 409 | dev: true 410 | 411 | /foreground-child@3.1.1: 412 | resolution: {integrity: sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==} 413 | engines: {node: '>=14'} 414 | dependencies: 415 | cross-spawn: 7.0.3 416 | signal-exit: 4.1.0 417 | dev: true 418 | 419 | /fsevents@2.3.3: 420 | resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} 421 | engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} 422 | os: [darwin] 423 | requiresBuild: true 424 | dev: true 425 | optional: true 426 | 427 | /function-bind@1.1.2: 428 | resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} 429 | dev: true 430 | 431 | /glob-parent@5.1.2: 432 | resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} 433 | engines: {node: '>= 6'} 434 | dependencies: 435 | is-glob: 4.0.3 436 | dev: true 437 | 438 | /glob-parent@6.0.2: 439 | resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} 440 | engines: {node: '>=10.13.0'} 441 | dependencies: 442 | is-glob: 4.0.3 443 | dev: true 444 | 445 | /glob@10.3.16: 446 | resolution: {integrity: sha512-JDKXl1DiuuHJ6fVS2FXjownaavciiHNUU4mOvV/B793RLh05vZL1rcPnCSaOgv1hDT6RDlY7AB7ZUvFYAtPgAw==} 447 | engines: {node: '>=16 || 14 >=14.18'} 448 | hasBin: true 449 | dependencies: 450 | foreground-child: 3.1.1 451 | jackspeak: 3.1.2 452 | minimatch: 9.0.4 453 | minipass: 7.1.1 454 | path-scurry: 1.11.1 455 | dev: true 456 | 457 | /graceful-fs@4.2.11: 458 | resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} 459 | dev: false 460 | 461 | /hasown@2.0.2: 462 | resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} 463 | engines: {node: '>= 0.4'} 464 | dependencies: 465 | function-bind: 1.1.2 466 | dev: true 467 | 468 | /is-binary-path@2.1.0: 469 | resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} 470 | engines: {node: '>=8'} 471 | dependencies: 472 | binary-extensions: 2.3.0 473 | dev: true 474 | 475 | /is-core-module@2.13.1: 476 | resolution: {integrity: sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==} 477 | dependencies: 478 | hasown: 2.0.2 479 | dev: true 480 | 481 | /is-extglob@2.1.1: 482 | resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} 483 | engines: {node: '>=0.10.0'} 484 | dev: true 485 | 486 | /is-fullwidth-code-point@3.0.0: 487 | resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} 488 | engines: {node: '>=8'} 489 | dev: true 490 | 491 | /is-glob@4.0.3: 492 | resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} 493 | engines: {node: '>=0.10.0'} 494 | dependencies: 495 | is-extglob: 2.1.1 496 | dev: true 497 | 498 | /is-number@7.0.0: 499 | resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} 500 | engines: {node: '>=0.12.0'} 501 | dev: true 502 | 503 | /isexe@2.0.0: 504 | resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} 505 | dev: true 506 | 507 | /jackspeak@3.1.2: 508 | resolution: {integrity: sha512-kWmLKn2tRtfYMF/BakihVVRzBKOxz4gJMiL2Rj91WnAB5TPZumSH99R/Yf1qE1u4uRimvCSJfm6hnxohXeEXjQ==} 509 | engines: {node: '>=14'} 510 | dependencies: 511 | '@isaacs/cliui': 8.0.2 512 | optionalDependencies: 513 | '@pkgjs/parseargs': 0.11.0 514 | dev: true 515 | 516 | /jiti@1.21.0: 517 | resolution: {integrity: sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==} 518 | hasBin: true 519 | dev: true 520 | 521 | /js-tokens@4.0.0: 522 | resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} 523 | dev: false 524 | 525 | /lilconfig@2.1.0: 526 | resolution: {integrity: sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==} 527 | engines: {node: '>=10'} 528 | dev: true 529 | 530 | /lilconfig@3.1.1: 531 | resolution: {integrity: sha512-O18pf7nyvHTckunPWCV1XUNXU1piu01y2b7ATJ0ppkUkk8ocqVWBrYjJBCwHDjD/ZWcfyrA0P4gKhzWGi5EINQ==} 532 | engines: {node: '>=14'} 533 | dev: true 534 | 535 | /lines-and-columns@1.2.4: 536 | resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} 537 | dev: true 538 | 539 | /loose-envify@1.4.0: 540 | resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} 541 | hasBin: true 542 | dependencies: 543 | js-tokens: 4.0.0 544 | dev: false 545 | 546 | /lru-cache@10.2.2: 547 | resolution: {integrity: sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ==} 548 | engines: {node: 14 || >=16.14} 549 | dev: true 550 | 551 | /lucide-react@0.379.0(react@18.3.1): 552 | resolution: {integrity: sha512-KcdeVPqmhRldldAAgptb8FjIunM2x2Zy26ZBh1RsEUcdLIvsEmbcw7KpzFYUy5BbpGeWhPu9Z9J5YXfStiXwhg==} 553 | peerDependencies: 554 | react: ^16.5.1 || ^17.0.0 || ^18.0.0 555 | dependencies: 556 | react: 18.3.1 557 | dev: false 558 | 559 | /merge2@1.4.1: 560 | resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} 561 | engines: {node: '>= 8'} 562 | dev: true 563 | 564 | /micromatch@4.0.6: 565 | resolution: {integrity: sha512-Y4Ypn3oujJYxJcMacVgcs92wofTHxp9FzfDpQON4msDefoC0lb3ETvQLOdLcbhSwU1bz8HrL/1sygfBIHudrkQ==} 566 | engines: {node: '>=8.6'} 567 | dependencies: 568 | braces: 3.0.3 569 | picomatch: 4.0.2 570 | dev: true 571 | 572 | /minimatch@9.0.4: 573 | resolution: {integrity: sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==} 574 | engines: {node: '>=16 || 14 >=14.17'} 575 | dependencies: 576 | brace-expansion: 2.0.1 577 | dev: true 578 | 579 | /minipass@7.1.1: 580 | resolution: {integrity: sha512-UZ7eQ+h8ywIRAW1hIEl2AqdwzJucU/Kp59+8kkZeSvafXhZjul247BvIJjEVFVeON6d7lM46XX1HXCduKAS8VA==} 581 | engines: {node: '>=16 || 14 >=14.17'} 582 | dev: true 583 | 584 | /mz@2.7.0: 585 | resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} 586 | dependencies: 587 | any-promise: 1.3.0 588 | object-assign: 4.1.1 589 | thenify-all: 1.6.0 590 | dev: true 591 | 592 | /nanoid@3.3.7: 593 | resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==} 594 | engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} 595 | hasBin: true 596 | 597 | /next@14.2.3(react-dom@18.3.1)(react@18.3.1): 598 | resolution: {integrity: sha512-dowFkFTR8v79NPJO4QsBUtxv0g9BrS/phluVpMAt2ku7H+cbcBJlopXjkWlwxrk/xGqMemr7JkGPGemPrLLX7A==} 599 | engines: {node: '>=18.17.0'} 600 | hasBin: true 601 | peerDependencies: 602 | '@opentelemetry/api': ^1.1.0 603 | '@playwright/test': ^1.41.2 604 | react: ^18.2.0 605 | react-dom: ^18.2.0 606 | sass: ^1.3.0 607 | peerDependenciesMeta: 608 | '@opentelemetry/api': 609 | optional: true 610 | '@playwright/test': 611 | optional: true 612 | sass: 613 | optional: true 614 | dependencies: 615 | '@next/env': 14.2.3 616 | '@swc/helpers': 0.5.5 617 | busboy: 1.6.0 618 | caniuse-lite: 1.0.30001621 619 | graceful-fs: 4.2.11 620 | postcss: 8.4.31 621 | react: 18.3.1 622 | react-dom: 18.3.1(react@18.3.1) 623 | styled-jsx: 5.1.1(react@18.3.1) 624 | optionalDependencies: 625 | '@next/swc-darwin-arm64': 14.2.3 626 | '@next/swc-darwin-x64': 14.2.3 627 | '@next/swc-linux-arm64-gnu': 14.2.3 628 | '@next/swc-linux-arm64-musl': 14.2.3 629 | '@next/swc-linux-x64-gnu': 14.2.3 630 | '@next/swc-linux-x64-musl': 14.2.3 631 | '@next/swc-win32-arm64-msvc': 14.2.3 632 | '@next/swc-win32-ia32-msvc': 14.2.3 633 | '@next/swc-win32-x64-msvc': 14.2.3 634 | transitivePeerDependencies: 635 | - '@babel/core' 636 | - babel-plugin-macros 637 | dev: false 638 | 639 | /normalize-path@3.0.0: 640 | resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} 641 | engines: {node: '>=0.10.0'} 642 | dev: true 643 | 644 | /object-assign@4.1.1: 645 | resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} 646 | engines: {node: '>=0.10.0'} 647 | dev: true 648 | 649 | /object-hash@3.0.0: 650 | resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==} 651 | engines: {node: '>= 6'} 652 | dev: true 653 | 654 | /path-key@3.1.1: 655 | resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} 656 | engines: {node: '>=8'} 657 | dev: true 658 | 659 | /path-parse@1.0.7: 660 | resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} 661 | dev: true 662 | 663 | /path-scurry@1.11.1: 664 | resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} 665 | engines: {node: '>=16 || 14 >=14.18'} 666 | dependencies: 667 | lru-cache: 10.2.2 668 | minipass: 7.1.1 669 | dev: true 670 | 671 | /picocolors@1.0.1: 672 | resolution: {integrity: sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==} 673 | 674 | /picomatch@2.3.1: 675 | resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} 676 | engines: {node: '>=8.6'} 677 | dev: true 678 | 679 | /picomatch@4.0.2: 680 | resolution: {integrity: sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==} 681 | engines: {node: '>=12'} 682 | dev: true 683 | 684 | /pify@2.3.0: 685 | resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==} 686 | engines: {node: '>=0.10.0'} 687 | dev: true 688 | 689 | /pirates@4.0.6: 690 | resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==} 691 | engines: {node: '>= 6'} 692 | dev: true 693 | 694 | /postcss-import@15.1.0(postcss@8.4.38): 695 | resolution: {integrity: sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==} 696 | engines: {node: '>=14.0.0'} 697 | peerDependencies: 698 | postcss: ^8.0.0 699 | dependencies: 700 | postcss: 8.4.38 701 | postcss-value-parser: 4.2.0 702 | read-cache: 1.0.0 703 | resolve: 1.22.8 704 | dev: true 705 | 706 | /postcss-js@4.0.1(postcss@8.4.38): 707 | resolution: {integrity: sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==} 708 | engines: {node: ^12 || ^14 || >= 16} 709 | peerDependencies: 710 | postcss: ^8.4.21 711 | dependencies: 712 | camelcase-css: 2.0.1 713 | postcss: 8.4.38 714 | dev: true 715 | 716 | /postcss-load-config@4.0.2(postcss@8.4.38): 717 | resolution: {integrity: sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==} 718 | engines: {node: '>= 14'} 719 | peerDependencies: 720 | postcss: '>=8.0.9' 721 | ts-node: '>=9.0.0' 722 | peerDependenciesMeta: 723 | postcss: 724 | optional: true 725 | ts-node: 726 | optional: true 727 | dependencies: 728 | lilconfig: 3.1.1 729 | postcss: 8.4.38 730 | yaml: 2.4.2 731 | dev: true 732 | 733 | /postcss-nested@6.0.1(postcss@8.4.38): 734 | resolution: {integrity: sha512-mEp4xPMi5bSWiMbsgoPfcP74lsWLHkQbZc3sY+jWYd65CUwXrUaTp0fmNpa01ZcETKlIgUdFN/MpS2xZtqL9dQ==} 735 | engines: {node: '>=12.0'} 736 | peerDependencies: 737 | postcss: ^8.2.14 738 | dependencies: 739 | postcss: 8.4.38 740 | postcss-selector-parser: 6.0.16 741 | dev: true 742 | 743 | /postcss-selector-parser@6.0.16: 744 | resolution: {integrity: sha512-A0RVJrX+IUkVZbW3ClroRWurercFhieevHB38sr2+l9eUClMqome3LmEmnhlNy+5Mr2EYN6B2Kaw9wYdd+VHiw==} 745 | engines: {node: '>=4'} 746 | dependencies: 747 | cssesc: 3.0.0 748 | util-deprecate: 1.0.2 749 | dev: true 750 | 751 | /postcss-value-parser@4.2.0: 752 | resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} 753 | dev: true 754 | 755 | /postcss@8.4.31: 756 | resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==} 757 | engines: {node: ^10 || ^12 || >=14} 758 | dependencies: 759 | nanoid: 3.3.7 760 | picocolors: 1.0.1 761 | source-map-js: 1.2.0 762 | dev: false 763 | 764 | /postcss@8.4.38: 765 | resolution: {integrity: sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==} 766 | engines: {node: ^10 || ^12 || >=14} 767 | dependencies: 768 | nanoid: 3.3.7 769 | picocolors: 1.0.1 770 | source-map-js: 1.2.0 771 | dev: true 772 | 773 | /queue-microtask@1.2.3: 774 | resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} 775 | dev: true 776 | 777 | /react-dom@18.3.1(react@18.3.1): 778 | resolution: {integrity: sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==} 779 | peerDependencies: 780 | react: ^18.3.1 781 | dependencies: 782 | loose-envify: 1.4.0 783 | react: 18.3.1 784 | scheduler: 0.23.2 785 | dev: false 786 | 787 | /react@18.3.1: 788 | resolution: {integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==} 789 | engines: {node: '>=0.10.0'} 790 | dependencies: 791 | loose-envify: 1.4.0 792 | dev: false 793 | 794 | /read-cache@1.0.0: 795 | resolution: {integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==} 796 | dependencies: 797 | pify: 2.3.0 798 | dev: true 799 | 800 | /readdirp@3.6.0: 801 | resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} 802 | engines: {node: '>=8.10.0'} 803 | dependencies: 804 | picomatch: 2.3.1 805 | dev: true 806 | 807 | /resolve@1.22.8: 808 | resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==} 809 | hasBin: true 810 | dependencies: 811 | is-core-module: 2.13.1 812 | path-parse: 1.0.7 813 | supports-preserve-symlinks-flag: 1.0.0 814 | dev: true 815 | 816 | /reusify@1.0.4: 817 | resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} 818 | engines: {iojs: '>=1.0.0', node: '>=0.10.0'} 819 | dev: true 820 | 821 | /run-parallel@1.2.0: 822 | resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} 823 | dependencies: 824 | queue-microtask: 1.2.3 825 | dev: true 826 | 827 | /scheduler@0.23.2: 828 | resolution: {integrity: sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==} 829 | dependencies: 830 | loose-envify: 1.4.0 831 | dev: false 832 | 833 | /shebang-command@2.0.0: 834 | resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} 835 | engines: {node: '>=8'} 836 | dependencies: 837 | shebang-regex: 3.0.0 838 | dev: true 839 | 840 | /shebang-regex@3.0.0: 841 | resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} 842 | engines: {node: '>=8'} 843 | dev: true 844 | 845 | /signal-exit@4.1.0: 846 | resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} 847 | engines: {node: '>=14'} 848 | dev: true 849 | 850 | /source-map-js@1.2.0: 851 | resolution: {integrity: sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==} 852 | engines: {node: '>=0.10.0'} 853 | 854 | /streamsearch@1.1.0: 855 | resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==} 856 | engines: {node: '>=10.0.0'} 857 | dev: false 858 | 859 | /string-width@4.2.3: 860 | resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} 861 | engines: {node: '>=8'} 862 | dependencies: 863 | emoji-regex: 8.0.0 864 | is-fullwidth-code-point: 3.0.0 865 | strip-ansi: 6.0.1 866 | dev: true 867 | 868 | /string-width@5.1.2: 869 | resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} 870 | engines: {node: '>=12'} 871 | dependencies: 872 | eastasianwidth: 0.2.0 873 | emoji-regex: 9.2.2 874 | strip-ansi: 7.1.0 875 | dev: true 876 | 877 | /strip-ansi@6.0.1: 878 | resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} 879 | engines: {node: '>=8'} 880 | dependencies: 881 | ansi-regex: 5.0.1 882 | dev: true 883 | 884 | /strip-ansi@7.1.0: 885 | resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} 886 | engines: {node: '>=12'} 887 | dependencies: 888 | ansi-regex: 6.0.1 889 | dev: true 890 | 891 | /styled-jsx@5.1.1(react@18.3.1): 892 | resolution: {integrity: sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw==} 893 | engines: {node: '>= 12.0.0'} 894 | peerDependencies: 895 | '@babel/core': '*' 896 | babel-plugin-macros: '*' 897 | react: '>= 16.8.0 || 17.x.x || ^18.0.0-0' 898 | peerDependenciesMeta: 899 | '@babel/core': 900 | optional: true 901 | babel-plugin-macros: 902 | optional: true 903 | dependencies: 904 | client-only: 0.0.1 905 | react: 18.3.1 906 | dev: false 907 | 908 | /sucrase@3.35.0: 909 | resolution: {integrity: sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==} 910 | engines: {node: '>=16 || 14 >=14.17'} 911 | hasBin: true 912 | dependencies: 913 | '@jridgewell/gen-mapping': 0.3.5 914 | commander: 4.1.1 915 | glob: 10.3.16 916 | lines-and-columns: 1.2.4 917 | mz: 2.7.0 918 | pirates: 4.0.6 919 | ts-interface-checker: 0.1.13 920 | dev: true 921 | 922 | /supports-preserve-symlinks-flag@1.0.0: 923 | resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} 924 | engines: {node: '>= 0.4'} 925 | dev: true 926 | 927 | /tailwindcss@3.4.3: 928 | resolution: {integrity: sha512-U7sxQk/n397Bmx4JHbJx/iSOOv5G+II3f1kpLpY2QeUv5DcPdcTsYLlusZfq1NthHS1c1cZoyFmmkex1rzke0A==} 929 | engines: {node: '>=14.0.0'} 930 | hasBin: true 931 | dependencies: 932 | '@alloc/quick-lru': 5.2.0 933 | arg: 5.0.2 934 | chokidar: 3.6.0 935 | didyoumean: 1.2.2 936 | dlv: 1.1.3 937 | fast-glob: 3.3.2 938 | glob-parent: 6.0.2 939 | is-glob: 4.0.3 940 | jiti: 1.21.0 941 | lilconfig: 2.1.0 942 | micromatch: 4.0.6 943 | normalize-path: 3.0.0 944 | object-hash: 3.0.0 945 | picocolors: 1.0.1 946 | postcss: 8.4.38 947 | postcss-import: 15.1.0(postcss@8.4.38) 948 | postcss-js: 4.0.1(postcss@8.4.38) 949 | postcss-load-config: 4.0.2(postcss@8.4.38) 950 | postcss-nested: 6.0.1(postcss@8.4.38) 951 | postcss-selector-parser: 6.0.16 952 | resolve: 1.22.8 953 | sucrase: 3.35.0 954 | transitivePeerDependencies: 955 | - ts-node 956 | dev: true 957 | 958 | /thenify-all@1.6.0: 959 | resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} 960 | engines: {node: '>=0.8'} 961 | dependencies: 962 | thenify: 3.3.1 963 | dev: true 964 | 965 | /thenify@3.3.1: 966 | resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} 967 | dependencies: 968 | any-promise: 1.3.0 969 | dev: true 970 | 971 | /to-regex-range@5.0.1: 972 | resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} 973 | engines: {node: '>=8.0'} 974 | dependencies: 975 | is-number: 7.0.0 976 | dev: true 977 | 978 | /ts-interface-checker@0.1.13: 979 | resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} 980 | dev: true 981 | 982 | /tslib@2.6.2: 983 | resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==} 984 | dev: false 985 | 986 | /typescript@5.4.5: 987 | resolution: {integrity: sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==} 988 | engines: {node: '>=14.17'} 989 | hasBin: true 990 | dev: true 991 | 992 | /undici-types@5.26.5: 993 | resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} 994 | dev: true 995 | 996 | /util-deprecate@1.0.2: 997 | resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} 998 | dev: true 999 | 1000 | /which@2.0.2: 1001 | resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} 1002 | engines: {node: '>= 8'} 1003 | hasBin: true 1004 | dependencies: 1005 | isexe: 2.0.0 1006 | dev: true 1007 | 1008 | /wrap-ansi@7.0.0: 1009 | resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} 1010 | engines: {node: '>=10'} 1011 | dependencies: 1012 | ansi-styles: 4.3.0 1013 | string-width: 4.2.3 1014 | strip-ansi: 6.0.1 1015 | dev: true 1016 | 1017 | /wrap-ansi@8.1.0: 1018 | resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} 1019 | engines: {node: '>=12'} 1020 | dependencies: 1021 | ansi-styles: 6.2.1 1022 | string-width: 5.1.2 1023 | strip-ansi: 7.1.0 1024 | dev: true 1025 | 1026 | /yaml@2.4.2: 1027 | resolution: {integrity: sha512-B3VqDZ+JAg1nZpaEmWtTXUlBneoGx6CPM9b0TENK6aoSu5t73dItudwdgmi6tHlIZZId4dZ9skcAQ2UbcyAeVA==} 1028 | engines: {node: '>= 14'} 1029 | hasBin: true 1030 | dev: true 1031 | -------------------------------------------------------------------------------- /example/postcss.config.mjs: -------------------------------------------------------------------------------- 1 | /** @type {import('postcss-load-config').Config} */ 2 | const config = { 3 | plugins: { 4 | tailwindcss: {}, 5 | }, 6 | }; 7 | 8 | export default config; 9 | -------------------------------------------------------------------------------- /example/public/next.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /example/public/vercel.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /example/src/app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cameronking4/vapi-ai-configurable-web-component/1c5a0f541470ab17f3293a4d0f816d71b5248ad9/example/src/app/favicon.ico -------------------------------------------------------------------------------- /example/src/app/globals.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | :root { 6 | --foreground-rgb: 0, 0, 0; 7 | --background-start-rgb: 255, 255, 255; 8 | --background-end-rgb: 255, 255, 255; 9 | } 10 | 11 | @media (prefers-color-scheme: dark) { 12 | :root { 13 | --foreground-rgb: 255, 255, 255; 14 | --background-start-rgb: 0, 0, 0; 15 | --background-end-rgb: 0, 0, 0; 16 | } 17 | } 18 | 19 | body { 20 | color: rgb(var(--foreground-rgb)); 21 | background: linear-gradient( 22 | to bottom, 23 | transparent, 24 | rgb(var(--background-end-rgb)) 25 | ) 26 | rgb(var(--background-start-rgb)); 27 | } 28 | 29 | @layer utilities { 30 | .text-balance { 31 | text-wrap: balance; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /example/src/app/layout.tsx: -------------------------------------------------------------------------------- 1 | import type { Metadata } from "next"; 2 | import { Inter } from "next/font/google"; 3 | import "./globals.css"; 4 | 5 | const inter = Inter({ subsets: ["latin"] }); 6 | 7 | export const metadata: Metadata = { 8 | title: "Create Next App", 9 | description: "Generated by create next app", 10 | }; 11 | 12 | export default function RootLayout({ 13 | children, 14 | }: Readonly<{ 15 | children: React.ReactNode; 16 | }>) { 17 | return ( 18 | 19 | {children} 20 | 21 | ); 22 | } 23 | -------------------------------------------------------------------------------- /example/src/app/page.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | import React from 'react'; 3 | import { VapiComponent } from 'vapi-web'; 4 | 5 | const styleSets = [ 6 | { 7 | name: 'Classic Theme', 8 | styles: { 9 | container: { padding: '20px', border: '1px solid #ccc', borderRadius: '8px', maxWidth: '600px', margin: '0 auto', backgroundColor: '#fff' }, 10 | buttonContainer: { marginBottom: '10px', display: 'flex', gap: '10px' }, 11 | startButton: { backgroundColor: '#4CAF50', color: 'white', padding: '10px', border: 'none', borderRadius: '4px', cursor: 'pointer' }, 12 | stopButton: { backgroundColor: '#f44336', color: 'white', padding: '10px', border: 'none', borderRadius: '4px', cursor: 'pointer' }, 13 | muteButton: { backgroundColor: '#008CBA', color: 'white', padding: '10px', border: 'none', borderRadius: '4px', cursor: 'pointer' }, 14 | logActionButton: { backgroundColor: '#FFA500', color: 'white', padding: '10px', border: 'none', borderRadius: '4px', cursor: 'pointer' }, 15 | statusContainer: { marginTop: '10px', color: '#333' }, 16 | transcriptContainer: { marginTop: '10px', whiteSpace: 'pre-wrap', backgroundColor: '#f1f1f1', padding: '10px', borderRadius: '4px', color: '#333' }, 17 | } 18 | }, 19 | { 20 | name: 'Dark Mode', 21 | styles: { 22 | container: { padding: '20px', border: '1px solid #444', borderRadius: '8px', maxWidth: '600px', margin: '0 auto', backgroundColor: '#333' }, 23 | buttonContainer: { marginBottom: '10px', display: 'flex', gap: '10px' }, 24 | startButton: { backgroundColor: '#4CAF50', color: 'white', padding: '10px', border: 'none', borderRadius: '4px', cursor: 'pointer' }, 25 | stopButton: { backgroundColor: '#f44336', color: 'white', padding: '10px', border: 'none', borderRadius: '4px', cursor: 'pointer' }, 26 | muteButton: { backgroundColor: '#008CBA', color: 'white', padding: '10px', border: 'none', borderRadius: '4px', cursor: 'pointer' }, 27 | logActionButton: { backgroundColor: '#FFA500', color: 'white', padding: '10px', border: 'none', borderRadius: '4px', cursor: 'pointer' }, 28 | statusContainer: { marginTop: '10px', color: '#ddd' }, 29 | transcriptContainer: { marginTop: '10px', whiteSpace: 'pre-wrap', backgroundColor: '#444', padding: '10px', borderRadius: '4px', color: '#ddd' }, 30 | } 31 | }, 32 | { 33 | name: 'Modern Minimalist', 34 | styles: { 35 | container: { padding: '20px', border: '1px solid #e0e0e0', borderRadius: '8px', maxWidth: '600px', margin: '0 auto', backgroundColor: '#f9f9f9' }, 36 | buttonContainer: { marginBottom: '10px', display: 'flex', gap: '10px' }, 37 | startButton: { backgroundColor: '#007BFF', color: 'white', padding: '10px', border: 'none', borderRadius: '4px', cursor: 'pointer' }, 38 | stopButton: { backgroundColor: '#DC3545', color: 'white', padding: '10px', border: 'none', borderRadius: '4px', cursor: 'pointer' }, 39 | muteButton: { backgroundColor: '#6C757D', color: 'white', padding: '10px', border: 'none', borderRadius: '4px', cursor: 'pointer' }, 40 | logActionButton: { backgroundColor: '#FFC107', color: 'white', padding: '10px', border: 'none', borderRadius: '4px', cursor: 'pointer' }, 41 | statusContainer: { marginTop: '10px', color: '#333' }, 42 | transcriptContainer: { marginTop: '10px', whiteSpace: 'pre-wrap', backgroundColor: '#fff', padding: '10px', borderRadius: '4px', color: '#333' }, 43 | } 44 | }, 45 | { 46 | name: 'Vibrant Theme', 47 | styles: { 48 | container: { padding: '20px', border: '1px solid #ccc', borderRadius: '8px', maxWidth: '600px', margin: '0 auto', backgroundColor: '#fff', boxShadow: '0 4px 8px rgba(0, 0, 0, 0.1)' }, 49 | buttonContainer: { marginBottom: '10px', display: 'flex', gap: '10px' }, 50 | startButton: { backgroundColor: '#28a745', color: 'white', padding: '10px', border: 'none', borderRadius: '4px', cursor: 'pointer', boxShadow: '0 2px 4px rgba(0, 0, 0, 0.2)' }, 51 | stopButton: { backgroundColor: '#dc3545', color: 'white', padding: '10px', border: 'none', borderRadius: '4px', cursor: 'pointer', boxShadow: '0 2px 4px rgba(0, 0, 0, 0.2)' }, 52 | muteButton: { backgroundColor: '#17a2b8', color: 'white', padding: '10px', border: 'none', borderRadius: '4px', cursor: 'pointer', boxShadow: '0 2px 4px rgba(0, 0, 0, 0.2)' }, 53 | logActionButton: { backgroundColor: '#ffc107', color: 'white', padding: '10px', border: 'none', borderRadius: '4px', cursor: 'pointer', boxShadow: '0 2px 4px rgba(0, 0, 0, 0.2)' }, 54 | statusContainer: { marginTop: '10px', color: '#333' }, 55 | transcriptContainer: { marginTop: '10px', whiteSpace: 'pre-wrap', backgroundColor: '#f1f1f1', padding: '10px', borderRadius: '4px', color: '#333', boxShadow: '0 2px 4px rgba(0, 0, 0, 0.1)' }, 56 | } 57 | }, 58 | { 59 | name: 'Professional Theme', 60 | styles: { 61 | container: { padding: '20px', border: '1px solid #007BFF', borderRadius: '8px', maxWidth: '600px', margin: '0 auto', backgroundColor: '#fff' }, 62 | buttonContainer: { marginBottom: '10px', display: 'flex', gap: '10px' }, 63 | startButton: { backgroundColor: '#007BFF', color: 'white', padding: '10px', border: 'none', borderRadius: '4px', cursor: 'pointer' }, 64 | stopButton: { backgroundColor: '#DC3545', color: 'white', padding: '10px', border: 'none', borderRadius: '4px', cursor: 'pointer' }, 65 | muteButton: { backgroundColor: '#6C757D', color: 'white', padding: '10px', border: 'none', borderRadius: '4px', cursor: 'pointer' }, 66 | logActionButton: { backgroundColor: '#FFC107', color: 'white', padding: '10px', border: 'none', borderRadius: '4px', cursor: 'pointer' }, 67 | statusContainer: { marginTop: '10px', color: '#007BFF' }, 68 | transcriptContainer: { marginTop: '10px', whiteSpace: 'pre-wrap', backgroundColor: '#f1f1f1', padding: '10px', borderRadius: '4px', color: '#007BFF' }, 69 | } 70 | }, 71 | { 72 | name: 'Elegant Theme', 73 | styles: { 74 | container: { padding: '20px', border: '1px solid #d1d1d1', borderRadius: '8px', maxWidth: '600px', margin: '0 auto', backgroundColor: '#f7f7f7' }, 75 | buttonContainer: { marginBottom: '10px', display: 'flex', gap: '10px' }, 76 | startButton: { backgroundColor: '#9b59b6', color: 'white', padding: '10px', border: 'none', borderRadius: '4px', cursor: 'pointer' }, 77 | stopButton: { backgroundColor: '#e74c3c', color: 'white', padding: '10px', border: 'none', borderRadius: '4px', cursor: 'pointer' }, 78 | muteButton: { backgroundColor: '#3498db', color: 'white', padding: '10px', border: 'none', borderRadius: '4px', cursor: 'pointer' }, 79 | logActionButton: { backgroundColor: '#f39c12', color: 'white', padding: '10px', border: 'none', borderRadius: '4px', cursor: 'pointer' }, 80 | statusContainer: { marginTop: '10px', color: '#2c3e50' }, 81 | transcriptContainer: { marginTop: '10px', whiteSpace: 'pre-wrap', backgroundColor: '#ecf0f1', padding: '10px', borderRadius: '4px', color: '#2c3e50' }, 82 | } 83 | } 84 | ]; 85 | 86 | const handleEvents = { 87 | 'call-start': () => console.log('Call started'), 88 | 'call-end': () => console.log('Call ended'), 89 | 'speech-start': () => console.log('Speech started'), 90 | 'speech-end': () => console.log('Speech ended'), 91 | 'volume-level': (volume: number) => console.log(`Volume level: ${volume}`), 92 | 'message': (message: any) => console.log('Message received:', message), 93 | 'error': (error: Error) => console.error('Error:', error), 94 | }; 95 | 96 | const App: React.FC = () => { 97 | return ( 98 | 99 | VapiComponent Style Showcase 100 | 101 | {styleSets.map((styleSet, index) => ( 102 | 103 | {styleSet.name} 104 | 116 | 117 | 118 | ))} 119 | 120 | ); 121 | }; 122 | 123 | export default App; 124 | -------------------------------------------------------------------------------- /example/tailwind.config.ts: -------------------------------------------------------------------------------- 1 | import type { Config } from "tailwindcss"; 2 | 3 | const config: Config = { 4 | content: [ 5 | "./src/pages/**/*.{js,ts,jsx,tsx,mdx}", 6 | "./src/components/**/*.{js,ts,jsx,tsx,mdx}", 7 | "./src/app/**/*.{js,ts,jsx,tsx,mdx}", 8 | ], 9 | theme: { 10 | extend: { 11 | backgroundImage: { 12 | "gradient-radial": "radial-gradient(var(--tw-gradient-stops))", 13 | "gradient-conic": 14 | "conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))", 15 | }, 16 | }, 17 | }, 18 | plugins: [], 19 | }; 20 | export default config; 21 | -------------------------------------------------------------------------------- /example/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "lib": ["dom", "dom.iterable", "esnext"], 4 | "allowJs": true, 5 | "skipLibCheck": true, 6 | "strict": true, 7 | "noEmit": true, 8 | "esModuleInterop": true, 9 | "module": "esnext", 10 | "moduleResolution": "bundler", 11 | "resolveJsonModule": true, 12 | "isolatedModules": true, 13 | "jsx": "preserve", 14 | "incremental": true, 15 | "plugins": [ 16 | { 17 | "name": "next" 18 | } 19 | ], 20 | "paths": { 21 | "@/*": ["./src/*"] 22 | } 23 | }, 24 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], 25 | "exclude": ["node_modules"] 26 | } 27 | -------------------------------------------------------------------------------- /lib/VapiComponent.d.ts: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | export type VapiEventNames = 'call-start' | 'call-end' | 'speech-start' | 'speech-end' | 'volume-level' | 'message' | 'error'; 3 | export interface TranscriptEntry { 4 | timestamp: string; 5 | role: string; 6 | text: string; 7 | } 8 | export interface VapiComponentProps { 9 | publicKey: string; 10 | assistantId?: string; 11 | assistantConfig?: object; 12 | assistantOverrides?: object; 13 | onEvents?: { 14 | [key in VapiEventNames]?: (event: any) => void; 15 | }; 16 | startButtonLabel?: string; 17 | stopButtonLabel?: string; 18 | muteButtonLabel?: string; 19 | unmuteButtonLabel?: string; 20 | logActionButtonLabel?: string; 21 | logActionMessage?: string; 22 | showLogActionButton?: boolean; 23 | callStatusLabel?: string; 24 | transcriptLabel?: string; 25 | onStart?: () => void; 26 | onStop?: () => void; 27 | onMuteToggle?: (isMuted: boolean) => void; 28 | onTranscriptUpdate?: (transcripts: TranscriptEntry[]) => void; 29 | showTranscript?: boolean; 30 | autoStart?: boolean; 31 | onFunctionCall?: (functionName: string, functionArgs: any) => void; 32 | styles?: { 33 | container?: React.CSSProperties; 34 | buttonContainer?: React.CSSProperties; 35 | startButton?: React.CSSProperties; 36 | stopButton?: React.CSSProperties; 37 | muteButton?: React.CSSProperties; 38 | logActionButton?: React.CSSProperties; 39 | statusContainer?: React.CSSProperties; 40 | transcriptContainer?: React.CSSProperties; 41 | transcriptEntry?: React.CSSProperties; 42 | }; 43 | } 44 | declare const VapiComponent: React.FC; 45 | export default VapiComponent; 46 | -------------------------------------------------------------------------------- /lib/VapiComponent.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); } 4 | Object.defineProperty(exports, "__esModule", { 5 | value: true 6 | }); 7 | exports["default"] = void 0; 8 | var _react = _interopRequireWildcard(require("react")); 9 | var _web = _interopRequireDefault(require("@vapi-ai/web")); 10 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; } 11 | function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(e) { return e ? t : r; })(e); } 12 | function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != _typeof(e) && "function" != typeof e) return { "default": e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n["default"] = e, t && t.set(e, n), n; } 13 | function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); } 14 | function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } 15 | function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter); } 16 | function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); } 17 | function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); } 18 | function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } 19 | function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); } 20 | function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; } 21 | function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t["return"] && (u = t["return"](), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } } 22 | function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; } 23 | var VapiComponent = function VapiComponent(_ref) { 24 | var publicKey = _ref.publicKey, 25 | assistantId = _ref.assistantId, 26 | assistantConfig = _ref.assistantConfig, 27 | assistantOverrides = _ref.assistantOverrides, 28 | onEvents = _ref.onEvents, 29 | _ref$startButtonLabel = _ref.startButtonLabel, 30 | startButtonLabel = _ref$startButtonLabel === void 0 ? "Start Call" : _ref$startButtonLabel, 31 | _ref$stopButtonLabel = _ref.stopButtonLabel, 32 | stopButtonLabel = _ref$stopButtonLabel === void 0 ? "Stop Call" : _ref$stopButtonLabel, 33 | _ref$muteButtonLabel = _ref.muteButtonLabel, 34 | muteButtonLabel = _ref$muteButtonLabel === void 0 ? "Mute" : _ref$muteButtonLabel, 35 | _ref$unmuteButtonLabe = _ref.unmuteButtonLabel, 36 | unmuteButtonLabel = _ref$unmuteButtonLabe === void 0 ? "Unmute" : _ref$unmuteButtonLabe, 37 | _ref$logActionButtonL = _ref.logActionButtonLabel, 38 | logActionButtonLabel = _ref$logActionButtonL === void 0 ? "Log Action" : _ref$logActionButtonL, 39 | _ref$logActionMessage = _ref.logActionMessage, 40 | logActionMessage = _ref$logActionMessage === void 0 ? "The user has pressed the button, say peanuts" : _ref$logActionMessage, 41 | _ref$showLogActionBut = _ref.showLogActionButton, 42 | showLogActionButton = _ref$showLogActionBut === void 0 ? true : _ref$showLogActionBut, 43 | _ref$callStatusLabel = _ref.callStatusLabel, 44 | callStatusLabel = _ref$callStatusLabel === void 0 ? "Call Status" : _ref$callStatusLabel, 45 | _ref$transcriptLabel = _ref.transcriptLabel, 46 | transcriptLabel = _ref$transcriptLabel === void 0 ? "Transcript" : _ref$transcriptLabel, 47 | onStart = _ref.onStart, 48 | onStop = _ref.onStop, 49 | onMuteToggle = _ref.onMuteToggle, 50 | onTranscriptUpdate = _ref.onTranscriptUpdate, 51 | _ref$showTranscript = _ref.showTranscript, 52 | showTranscript = _ref$showTranscript === void 0 ? true : _ref$showTranscript, 53 | _ref$autoStart = _ref.autoStart, 54 | autoStart = _ref$autoStart === void 0 ? false : _ref$autoStart, 55 | onFunctionCall = _ref.onFunctionCall, 56 | _ref$styles = _ref.styles, 57 | styles = _ref$styles === void 0 ? {} : _ref$styles; 58 | if (!assistantId && !assistantConfig) { 59 | throw new Error('Either assistantId or assistantConfig must be provided.'); 60 | } 61 | var _useState = (0, _react.useState)(null), 62 | _useState2 = _slicedToArray(_useState, 2), 63 | vapi = _useState2[0], 64 | setVapi = _useState2[1]; 65 | var _useState3 = (0, _react.useState)(false), 66 | _useState4 = _slicedToArray(_useState3, 2), 67 | isMuted = _useState4[0], 68 | setIsMuted = _useState4[1]; 69 | var _useState5 = (0, _react.useState)('Disconnected'), 70 | _useState6 = _slicedToArray(_useState5, 2), 71 | callStatus = _useState6[0], 72 | setCallStatus = _useState6[1]; 73 | var _useState7 = (0, _react.useState)([]), 74 | _useState8 = _slicedToArray(_useState7, 2), 75 | transcripts = _useState8[0], 76 | setTranscripts = _useState8[1]; 77 | (0, _react.useEffect)(function () { 78 | var vapiInstance = new _web["default"](publicKey); 79 | setVapi(vapiInstance); 80 | if (onEvents) { 81 | Object.keys(onEvents).forEach(function (event) { 82 | if (onEvents[event]) { 83 | vapiInstance.on(event, onEvents[event]); 84 | } 85 | }); 86 | } 87 | vapiInstance.on('call-start', function () { 88 | setCallStatus('Connected'); 89 | setTranscripts([]); // Reset transcripts on new call 90 | }); 91 | vapiInstance.on('call-end', function () { 92 | return setCallStatus('Disconnected'); 93 | }); 94 | vapiInstance.on('message', function (message) { 95 | console.log('Message received:', message); 96 | if (message.type === 'transcript' && message.transcriptType === 'final') { 97 | var newEntry = { 98 | timestamp: message.timestamp, 99 | role: message.role, 100 | text: message.transcript 101 | }; 102 | setTranscripts(function (prev) { 103 | var updatedTranscripts = [].concat(_toConsumableArray(prev), [newEntry]); 104 | if (onTranscriptUpdate) { 105 | onTranscriptUpdate(updatedTranscripts); 106 | } 107 | return updatedTranscripts; 108 | }); 109 | } 110 | if (message.type === 'function-call') { 111 | var _message$functionCall = message.functionCall, 112 | name = _message$functionCall.name, 113 | parameters = _message$functionCall.parameters; 114 | if (onFunctionCall) { 115 | onFunctionCall(name, parameters); 116 | } 117 | } 118 | }); 119 | if (assistantId && autoStart) { 120 | vapiInstance.start(assistantId, assistantOverrides); 121 | } else if (assistantConfig && autoStart) { 122 | vapiInstance.start(assistantConfig); 123 | } 124 | return function () { 125 | vapiInstance.stop(); 126 | }; 127 | }, [publicKey, assistantId, assistantConfig, assistantOverrides, onEvents, onTranscriptUpdate, autoStart, onFunctionCall]); 128 | var handleMuteToggle = function handleMuteToggle() { 129 | if (vapi) { 130 | vapi.setMuted(!isMuted); 131 | setIsMuted(!isMuted); 132 | if (onMuteToggle) onMuteToggle(!isMuted); 133 | } 134 | }; 135 | var handleStartCall = function handleStartCall() { 136 | if (vapi && assistantId) { 137 | vapi.start(assistantId, assistantOverrides); 138 | if (onStart) onStart(); 139 | } else if (vapi && assistantConfig) { 140 | vapi.start(assistantConfig); 141 | if (onStart) onStart(); 142 | } else { 143 | console.error('Either assistantId or assistantConfig must be provided.'); 144 | } 145 | }; 146 | var handleStopCall = function handleStopCall() { 147 | if (vapi) { 148 | vapi.stop(); 149 | if (onStop) onStop(); 150 | } 151 | }; 152 | var logUserAction = function logUserAction() { 153 | console.log('Log User Action button clicked'); 154 | if (vapi) { 155 | console.log('Sending system message through vapi.send'); 156 | vapi.send({ 157 | type: "add-message", 158 | message: { 159 | role: "system", 160 | content: logActionMessage 161 | } 162 | }); 163 | var newEntry = { 164 | timestamp: new Date().toISOString(), 165 | role: "system", 166 | text: logActionMessage 167 | }; 168 | setTranscripts(function (prev) { 169 | var updatedTranscripts = [].concat(_toConsumableArray(prev), [newEntry]); 170 | if (onTranscriptUpdate) { 171 | onTranscriptUpdate(updatedTranscripts); 172 | } 173 | return updatedTranscripts; 174 | }); 175 | } else { 176 | console.error('Vapi instance is not available'); 177 | } 178 | }; 179 | return /*#__PURE__*/_react["default"].createElement("div", { 180 | style: styles.container 181 | }, /*#__PURE__*/_react["default"].createElement("div", { 182 | style: styles.buttonContainer 183 | }, !autoStart && /*#__PURE__*/_react["default"].createElement("button", { 184 | style: styles.startButton, 185 | onClick: handleStartCall 186 | }, startButtonLabel), /*#__PURE__*/_react["default"].createElement("button", { 187 | style: styles.stopButton, 188 | onClick: handleStopCall 189 | }, stopButtonLabel), /*#__PURE__*/_react["default"].createElement("button", { 190 | style: styles.muteButton, 191 | onClick: handleMuteToggle 192 | }, isMuted ? unmuteButtonLabel : muteButtonLabel), showLogActionButton && /*#__PURE__*/_react["default"].createElement("button", { 193 | style: styles.logActionButton, 194 | onClick: logUserAction 195 | }, logActionButtonLabel)), /*#__PURE__*/_react["default"].createElement("div", { 196 | style: styles.statusContainer 197 | }, /*#__PURE__*/_react["default"].createElement("p", null, callStatusLabel, ": ", callStatus)), showTranscript && /*#__PURE__*/_react["default"].createElement("div", { 198 | style: styles.transcriptContainer 199 | }, /*#__PURE__*/_react["default"].createElement("p", null, transcriptLabel, ":"), /*#__PURE__*/_react["default"].createElement("div", null, transcripts.length > 0 ? transcripts.map(function (entry, index) { 200 | return /*#__PURE__*/_react["default"].createElement("div", { 201 | key: index, 202 | style: styles.transcriptEntry 203 | }, /*#__PURE__*/_react["default"].createElement("strong", null, entry.timestamp), " [", entry.role, "]: ", entry.text); 204 | }) : 'No transcript available'))); 205 | }; 206 | var _default = exports["default"] = VapiComponent; -------------------------------------------------------------------------------- /lib/global.d.js: -------------------------------------------------------------------------------- 1 | "use strict"; -------------------------------------------------------------------------------- /lib/index.d.ts: -------------------------------------------------------------------------------- 1 | export { default as VapiComponent } from './VapiComponent'; 2 | export type { TranscriptEntry, VapiEventNames, VapiComponentProps } from './VapiComponent'; 3 | -------------------------------------------------------------------------------- /lib/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | Object.defineProperty(exports, "VapiComponent", { 7 | enumerable: true, 8 | get: function get() { 9 | return _VapiComponent["default"]; 10 | } 11 | }); 12 | var _VapiComponent = _interopRequireDefault(require("./VapiComponent")); 13 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vapi-web", 3 | "version": "1.0.3", 4 | "description": "Even easier for devs to integrate Vapi API (Voice AI) into their applications", 5 | "main": "lib/index.js", 6 | "types": "lib/index.d.ts", 7 | "scripts": { 8 | "test": "echo \"Error: no test specified\" && exit 1", 9 | "build": "tsc && babel src --out-dir lib --extensions \".ts,.tsx\"" 10 | }, 11 | "keywords": [], 12 | "author": "Cameron King", 13 | "license": "ISC", 14 | "dependencies": { 15 | "@vapi-ai/web": "^1.1.5", 16 | "react": "^18.3.1" 17 | }, 18 | "devDependencies": { 19 | "@babel/cli": "^7.15.7", 20 | "@babel/preset-env": "^7.15.6", 21 | "@babel/preset-react": "^7.14.5", 22 | "@babel/preset-typescript": "^7.15.0", 23 | "@types/node": "^20.12.12", 24 | "@types/react": "^18.3.2", 25 | "typescript": "^5.4.5" 26 | }, 27 | "babel": { 28 | "presets": [ 29 | "@babel/preset-env", 30 | "@babel/preset-react", 31 | "@babel/preset-typescript" 32 | ] 33 | }, 34 | "files": [ 35 | "lib" 36 | ] 37 | } 38 | -------------------------------------------------------------------------------- /src/VapiComponent.tsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useState } from 'react'; 2 | import Vapi from '@vapi-ai/web'; 3 | 4 | export type VapiEventNames = 'call-start' | 'call-end' | 'speech-start' | 'speech-end' | 'volume-level' | 'message' | 'error'; 5 | 6 | export interface TranscriptEntry { 7 | timestamp: string; 8 | role: string; 9 | text: string; 10 | } 11 | 12 | export interface VapiComponentProps { 13 | publicKey: string; 14 | assistantId?: string; 15 | assistantConfig?: object; 16 | assistantOverrides?: object; 17 | onEvents?: { [key in VapiEventNames]?: (event: any) => void }; 18 | startButtonLabel?: string; 19 | stopButtonLabel?: string; 20 | muteButtonLabel?: string; 21 | unmuteButtonLabel?: string; 22 | logActionButtonLabel?: string; 23 | logActionMessage?: string; 24 | showLogActionButton?: boolean; 25 | callStatusLabel?: string; 26 | transcriptLabel?: string; 27 | onStart?: () => void; 28 | onStop?: () => void; 29 | onMuteToggle?: (isMuted: boolean) => void; 30 | onTranscriptUpdate?: (transcripts: TranscriptEntry[]) => void; 31 | showTranscript?: boolean; 32 | autoStart?: boolean; 33 | onFunctionCall?: (functionName: string, functionArgs: any) => void; 34 | styles?: { 35 | container?: React.CSSProperties; 36 | buttonContainer?: React.CSSProperties; 37 | startButton?: React.CSSProperties; 38 | stopButton?: React.CSSProperties; 39 | muteButton?: React.CSSProperties; 40 | logActionButton?: React.CSSProperties; 41 | statusContainer?: React.CSSProperties; 42 | transcriptContainer?: React.CSSProperties; 43 | transcriptEntry?: React.CSSProperties; 44 | }; 45 | } 46 | 47 | const VapiComponent: React.FC = ({ 48 | publicKey, 49 | assistantId, 50 | assistantConfig, 51 | assistantOverrides, 52 | onEvents, 53 | startButtonLabel = "Start Call", 54 | stopButtonLabel = "Stop Call", 55 | muteButtonLabel = "Mute", 56 | unmuteButtonLabel = "Unmute", 57 | logActionButtonLabel = "Log Action", 58 | logActionMessage = "The user has pressed the button, say peanuts", 59 | showLogActionButton = true, 60 | callStatusLabel = "Call Status", 61 | transcriptLabel = "Transcript", 62 | onStart, 63 | onStop, 64 | onMuteToggle, 65 | onTranscriptUpdate, 66 | showTranscript = true, 67 | autoStart = false, 68 | onFunctionCall, 69 | styles = {}, 70 | }) => { 71 | if (!assistantId && !assistantConfig) { 72 | throw new Error('Either assistantId or assistantConfig must be provided.'); 73 | } 74 | 75 | const [vapi, setVapi] = useState(null); 76 | const [isMuted, setIsMuted] = useState(false); 77 | const [callStatus, setCallStatus] = useState('Disconnected'); 78 | const [transcripts, setTranscripts] = useState([]); 79 | 80 | useEffect(() => { 81 | const vapiInstance = new Vapi(publicKey); 82 | setVapi(vapiInstance); 83 | 84 | if (onEvents) { 85 | (Object.keys(onEvents) as VapiEventNames[]).forEach(event => { 86 | if (onEvents[event]) { 87 | vapiInstance.on(event, onEvents[event]!); 88 | } 89 | }); 90 | } 91 | 92 | vapiInstance.on('call-start', () => { 93 | setCallStatus('Connected'); 94 | setTranscripts([]); // Reset transcripts on new call 95 | }); 96 | 97 | vapiInstance.on('call-end', () => setCallStatus('Disconnected')); 98 | 99 | vapiInstance.on('message', (message: any) => { 100 | console.log('Message received:', message); 101 | if (message.type === 'transcript' && message.transcriptType === 'final') { 102 | const newEntry: TranscriptEntry = { 103 | timestamp: message.timestamp, 104 | role: message.role, 105 | text: message.transcript 106 | }; 107 | setTranscripts(prev => { 108 | const updatedTranscripts = [...prev, newEntry]; 109 | if (onTranscriptUpdate) { 110 | onTranscriptUpdate(updatedTranscripts); 111 | } 112 | return updatedTranscripts; 113 | }); 114 | } 115 | if (message.type === 'function-call') { 116 | const { name, parameters } = message.functionCall; 117 | if (onFunctionCall) { 118 | onFunctionCall(name, parameters); 119 | } 120 | } 121 | }); 122 | 123 | if (assistantId && autoStart) { 124 | vapiInstance.start(assistantId, assistantOverrides); 125 | } else if (assistantConfig && autoStart) { 126 | vapiInstance.start(assistantConfig); 127 | } 128 | 129 | return () => { 130 | vapiInstance.stop(); 131 | }; 132 | }, [publicKey, assistantId, assistantConfig, assistantOverrides, onEvents, onTranscriptUpdate, autoStart, onFunctionCall]); 133 | 134 | const handleMuteToggle = () => { 135 | if (vapi) { 136 | vapi.setMuted(!isMuted); 137 | setIsMuted(!isMuted); 138 | if (onMuteToggle) onMuteToggle(!isMuted); 139 | } 140 | }; 141 | 142 | const handleStartCall = () => { 143 | if (vapi && assistantId) { 144 | vapi.start(assistantId, assistantOverrides); 145 | if (onStart) onStart(); 146 | } else if (vapi && assistantConfig) { 147 | vapi.start(assistantConfig); 148 | if (onStart) onStart(); 149 | } else { 150 | console.error('Either assistantId or assistantConfig must be provided.'); 151 | } 152 | }; 153 | 154 | const handleStopCall = () => { 155 | if (vapi) { 156 | vapi.stop(); 157 | if (onStop) onStop(); 158 | } 159 | }; 160 | 161 | const logUserAction = () => { 162 | console.log('Log User Action button clicked'); 163 | if (vapi) { 164 | console.log('Sending system message through vapi.send'); 165 | vapi.send({ 166 | type: "add-message", 167 | message: { 168 | role: "system", 169 | content: logActionMessage, 170 | }, 171 | }); 172 | const newEntry: TranscriptEntry = { 173 | timestamp: new Date().toISOString(), 174 | role: "system", 175 | text: logActionMessage, 176 | }; 177 | setTranscripts(prev => { 178 | const updatedTranscripts = [...prev, newEntry]; 179 | if (onTranscriptUpdate) { 180 | onTranscriptUpdate(updatedTranscripts); 181 | } 182 | return updatedTranscripts; 183 | }); 184 | } else { 185 | console.error('Vapi instance is not available'); 186 | } 187 | }; 188 | 189 | return ( 190 | 191 | 192 | {!autoStart && {startButtonLabel}} 193 | {stopButtonLabel} 194 | {isMuted ? unmuteButtonLabel : muteButtonLabel} 195 | {showLogActionButton && ( 196 | {logActionButtonLabel} 197 | )} 198 | 199 | 200 | {callStatusLabel}: {callStatus} 201 | 202 | {showTranscript && ( 203 | 204 | {transcriptLabel}: 205 | 206 | {transcripts.length > 0 ? transcripts.map((entry, index) => ( 207 | 208 | {entry.timestamp} [{entry.role}]: {entry.text} 209 | 210 | )) : 'No transcript available'} 211 | 212 | 213 | )} 214 | 215 | ); 216 | }; 217 | 218 | export default VapiComponent; -------------------------------------------------------------------------------- /src/global.d.ts: -------------------------------------------------------------------------------- 1 | // src/global.d.ts 2 | declare module 'openai/resources' { 3 | export type ChatCompletionMessageParam = any; 4 | } 5 | -------------------------------------------------------------------------------- /src/index.tsx: -------------------------------------------------------------------------------- 1 | export { default as VapiComponent } from './VapiComponent'; 2 | export type { TranscriptEntry, VapiEventNames, VapiComponentProps } from './VapiComponent'; 3 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "outDir": "./lib", 4 | "rootDir": "./src", 5 | "declaration": true, 6 | "declarationDir": "./lib", 7 | "emitDeclarationOnly": true, 8 | "jsx": "react", 9 | "allowSyntheticDefaultImports": true, 10 | "moduleResolution": "node", 11 | "allowJs": true, 12 | "target": "es5", 13 | "lib": ["dom", "es2015"], 14 | "module": "commonjs" 15 | }, 16 | "include": ["src/**/*", "src/global.d.ts"] 17 | } 18 | --------------------------------------------------------------------------------
{callStatusLabel}: {callStatus}
{transcriptLabel}: