├── .gitignore
├── lib
├── global.d.js
├── index.d.ts
├── index.js
├── VapiComponent.d.ts
└── VapiComponent.js
├── example
├── .env.example
├── next.config.mjs
├── src
│ └── app
│ │ ├── favicon.ico
│ │ ├── layout.tsx
│ │ ├── globals.css
│ │ └── page.tsx
├── postcss.config.mjs
├── .gitignore
├── tailwind.config.ts
├── public
│ ├── vercel.svg
│ └── next.svg
├── package.json
├── tsconfig.json
├── README.md
└── pnpm-lock.yaml
├── src
├── global.d.ts
├── index.tsx
└── VapiComponent.tsx
├── tsconfig.json
├── package.json
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
--------------------------------------------------------------------------------
/lib/global.d.js:
--------------------------------------------------------------------------------
1 | "use strict";
--------------------------------------------------------------------------------
/example/.env.example:
--------------------------------------------------------------------------------
1 | NEXT_PUBLIC_VAPI_PUBLIC_KEY=
2 | NEXT_PUBLIC_VAPI_ASSISTANT_ID=
--------------------------------------------------------------------------------
/example/next.config.mjs:
--------------------------------------------------------------------------------
1 | /** @type {import('next').NextConfig} */
2 | const nextConfig = {};
3 |
4 | export default nextConfig;
5 |
--------------------------------------------------------------------------------
/example/src/app/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cameronking4/vapi-ai-configurable-web-component/HEAD/example/src/app/favicon.ico
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/lib/index.d.ts:
--------------------------------------------------------------------------------
1 | export { default as VapiComponent } from './VapiComponent';
2 | export type { TranscriptEntry, VapiEventNames, VapiComponentProps } from './VapiComponent';
3 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 }; }
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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/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/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/public/vercel.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/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/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/example/public/next.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 && }
193 |
194 |
195 | {showLogActionButton && (
196 |
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;
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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;
--------------------------------------------------------------------------------
/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/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 |
--------------------------------------------------------------------------------