feat: Implement WebRTC messaging and audio handling in the WebRTC service

This commit is contained in:
Marco Beretta 2024-12-21 16:18:23 +01:00 committed by Danny Avila
parent d5bc8d3869
commit 7717d3a514
No known key found for this signature in database
GPG key ID: BF31EEB2C5CA0956
8 changed files with 771 additions and 139 deletions

View file

@ -82,6 +82,7 @@
"mongoose": "^8.9.5", "mongoose": "^8.9.5",
"multer": "^1.4.5-lts.1", "multer": "^1.4.5-lts.1",
"nanoid": "^3.3.7", "nanoid": "^3.3.7",
"node-pre-gyp": "^0.17.0",
"nodemailer": "^6.9.15", "nodemailer": "^6.9.15",
"ollama": "^0.5.0", "ollama": "^0.5.0",
"openai": "^4.47.1", "openai": "^4.47.1",
@ -102,6 +103,7 @@
"ua-parser-js": "^1.0.36", "ua-parser-js": "^1.0.36",
"winston": "^3.11.0", "winston": "^3.11.0",
"winston-daily-rotate-file": "^4.7.1", "winston-daily-rotate-file": "^4.7.1",
"wrtc": "^0.4.7",
"ws": "^8.18.0", "ws": "^8.18.0",
"youtube-transcript": "^1.2.1", "youtube-transcript": "^1.2.1",
"zod": "^3.22.4" "zod": "^3.22.4"

View file

@ -1,12 +1,15 @@
const { WebSocketServer } = require('ws'); const { WebSocketServer } = require('ws');
const fs = require('fs'); const { RTCPeerConnection } = require('wrtc');
const path = require('path');
module.exports.WebSocketService = class { module.exports.WebSocketService = class {
constructor(server) { constructor(server) {
this.wss = new WebSocketServer({ server, path: '/ws' }); this.wss = new WebSocketServer({ server, path: '/ws' });
this.log('Server initialized'); this.log('Server initialized');
this.clientAudioBuffers = new Map(); this.activeClients = new Map();
this.iceServers = [
{ urls: 'stun:stun.l.google.com:19302' },
{ urls: 'stun:stun1.l.google.com:19302' },
];
this.setupHandlers(); this.setupHandlers();
} }
@ -17,7 +20,13 @@ module.exports.WebSocketService = class {
setupHandlers() { setupHandlers() {
this.wss.on('connection', (ws) => { this.wss.on('connection', (ws) => {
const clientId = Date.now().toString(); const clientId = Date.now().toString();
this.clientAudioBuffers.set(clientId, []); this.activeClients.set(clientId, {
ws,
state: 'idle',
audioBuffer: [],
currentTranscription: '',
isProcessing: false,
});
this.log(`Client connected: ${clientId}`); this.log(`Client connected: ${clientId}`);
@ -29,42 +38,175 @@ module.exports.WebSocketService = class {
return; return;
} }
if (message.type === 'audio-chunk') { switch (message.type) {
if (!this.clientAudioBuffers.has(clientId)) { case 'call-start':
this.clientAudioBuffers.set(clientId, []); this.handleCallStart(clientId);
} break;
this.clientAudioBuffers.get(clientId).push(message.data);
}
if (message.type === 'request-response') { case 'audio-chunk':
const filePath = path.join(__dirname, './assets/response.mp3'); await this.handleAudioChunk(clientId, message.data);
const audioFile = fs.readFileSync(filePath); break;
ws.send(JSON.stringify({ type: 'audio-response', data: audioFile.toString('base64') }));
}
if (message.type === 'call-ended') { case 'processing-start':
const allChunks = this.clientAudioBuffers.get(clientId); await this.processAudioStream(clientId);
this.writeAudioFile(clientId, allChunks); break;
this.clientAudioBuffers.delete(clientId);
case 'audio-received':
this.confirmAudioReceived(clientId);
break;
case 'call-ended':
this.handleCallEnd(clientId);
break;
} }
}); });
ws.on('close', () => { ws.on('close', () => {
this.handleCallEnd(clientId);
this.activeClients.delete(clientId);
this.log(`Client disconnected: ${clientId}`); this.log(`Client disconnected: ${clientId}`);
this.clientAudioBuffers.delete(clientId); });
ws.on('error', (error) => {
this.log(`Error for client ${clientId}: ${error.message}`);
this.handleCallEnd(clientId);
}); });
}); });
} }
writeAudioFile(clientId, base64Chunks) { async handleCallStart(clientId) {
if (!base64Chunks || base64Chunks.length === 0) { const client = this.activeClients.get(clientId);
if (!client) {
return; return;
} }
const filePath = path.join(__dirname, `recorded_${clientId}.webm`);
const buffer = Buffer.concat( try {
base64Chunks.map((chunk) => Buffer.from(chunk.split(',')[1], 'base64')), client.state = 'active';
client.audioBuffer = [];
client.currentTranscription = '';
client.isProcessing = false;
const peerConnection = new RTCPeerConnection({
iceServers: this.iceServers,
sdpSemantics: 'unified-plan',
});
client.peerConnection = peerConnection;
client.dataChannel = peerConnection.createDataChannel('audio', {
ordered: true,
maxRetransmits: 3,
});
client.dataChannel.onopen = () => this.log(`Data channel opened for ${clientId}`);
client.dataChannel.onmessage = async (event) => {
await this.handleAudioChunk(clientId, event.data);
};
peerConnection.onicecandidate = (event) => {
if (event.candidate) {
client.ws.send(
JSON.stringify({
type: 'ice-candidate',
candidate: event.candidate,
}),
);
}
};
peerConnection.onnegotiationneeded = async () => {
try {
const offer = await peerConnection.createOffer();
await peerConnection.setLocalDescription(offer);
client.ws.send(
JSON.stringify({
type: 'webrtc-offer',
sdp: peerConnection.localDescription,
}),
);
} catch (error) {
this.log(`Negotiation failed for ${clientId}: ${error}`);
}
};
this.log(`Call started for client ${clientId}`);
} catch (error) {
this.log(`Error starting call for ${clientId}: ${error.message}`);
this.handleCallEnd(clientId);
}
}
async handleAudioChunk(clientId, data) {
const client = this.activeClients.get(clientId);
if (!client || client.state !== 'active') {
return;
}
client.audioBuffer.push(data);
client.ws.send(JSON.stringify({ type: 'audio-received' }));
}
async processAudioStream(clientId) {
const client = this.activeClients.get(clientId);
if (!client || client.state !== 'active' || client.isProcessing) {
return;
}
client.isProcessing = true;
try {
// Process transcription
client.ws.send(
JSON.stringify({
type: 'transcription',
data: 'Processing audio...',
}),
);
// Stream LLM response
client.ws.send(
JSON.stringify({
type: 'llm-response',
data: 'Processing response...',
}),
);
// Stream TTS chunks
client.ws.send(
JSON.stringify({
type: 'tts-chunk',
data: 'audio_data_here',
}),
);
} catch (error) {
this.log(`Processing error for client ${clientId}: ${error.message}`);
} finally {
client.isProcessing = false;
client.audioBuffer = [];
}
}
confirmAudioReceived(clientId) {
const client = this.activeClients.get(clientId);
if (!client) {
return;
}
client.ws.send(
JSON.stringify({
type: 'audio-received',
data: null,
}),
); );
fs.writeFileSync(filePath, buffer); }
this.log(`Saved audio to ${filePath}`);
handleCallEnd(clientId) {
const client = this.activeClients.get(clientId);
if (!client) {
return;
}
client.state = 'idle';
client.audioBuffer = [];
client.currentTranscription = '';
} }
}; };

View file

@ -48,6 +48,17 @@ export type AudioChunk = {
}; };
}; };
export interface RTCMessage {
type:
| 'audio-chunk'
| 'audio-received'
| 'transcription'
| 'llm-response'
| 'tts-chunk'
| 'call-ended';
data?: string | ArrayBuffer | null;
}
export type AssistantListItem = { export type AssistantListItem = {
id: string; id: string;
name: string; name: string;

View file

@ -1,67 +1,106 @@
import { useState, useRef, useCallback } from 'react'; import { useState, useRef, useCallback } from 'react';
import useWebSocket from './useWebSocket';
import { WebRTCService } from '../services/WebRTC/WebRTCService'; import { WebRTCService } from '../services/WebRTC/WebRTCService';
import type { RTCMessage } from '~/common';
import useWebSocket from './useWebSocket';
const SILENCE_THRESHOLD = -50; const SILENCE_THRESHOLD = -50;
const SILENCE_DURATION = 1000; const SILENCE_DURATION = 1000;
const useCall = () => { const useCall = () => {
const { sendMessage } = useWebSocket(); const { sendMessage: wsMessage } = useWebSocket();
const [isCalling, setIsCalling] = useState(false); const [isCalling, setIsCalling] = useState(false);
const [isProcessing, setIsProcessing] = useState(false);
const audioContextRef = useRef<AudioContext | null>(null); const audioContextRef = useRef<AudioContext | null>(null);
const analyserRef = useRef<AnalyserNode | null>(null); const analyserRef = useRef<AnalyserNode | null>(null);
const audioChunksRef = useRef<Blob[]>([]);
const silenceStartRef = useRef<number | null>(null); const silenceStartRef = useRef<number | null>(null);
const intervalRef = useRef<number | null>(null); const intervalRef = useRef<number | null>(null);
const webrtcServiceRef = useRef<WebRTCService | null>(null); const webrtcServiceRef = useRef<WebRTCService | null>(null);
const checkSilence = useCallback(() => { const sendAudioChunk = useCallback(() => {
if (!analyserRef.current || !isCalling) { if (audioChunksRef.current.length === 0) {
return; return;
} }
const data = new Float32Array(analyserRef.current.frequencyBinCount);
analyserRef.current.getFloatFrequencyData(data); const audioBlob = new Blob(audioChunksRef.current, { type: 'audio/webm' });
const avg = data.reduce((a, b) => a + b) / data.length; // Send audio through WebRTC data channel
if (avg < SILENCE_THRESHOLD) { webrtcServiceRef.current?.sendAudioChunk(audioBlob);
if (!silenceStartRef.current) { // Signal processing start via WebSocket
silenceStartRef.current = Date.now(); wsMessage({ type: 'processing-start' });
} else if (Date.now() - silenceStartRef.current > SILENCE_DURATION) {
sendMessage({ type: 'request-response' }); audioChunksRef.current = [];
silenceStartRef.current = null; setIsProcessing(true);
} }, [wsMessage]);
} else {
silenceStartRef.current = null; const handleRTCMessage = useCallback((message: RTCMessage) => {
if (message.type === 'audio-received') {
// Backend confirmed audio receipt
setIsProcessing(true);
} }
}, [isCalling, sendMessage]); }, []);
const startCall = useCallback(async () => { const startCall = useCallback(async () => {
webrtcServiceRef.current = new WebRTCService(sendMessage); // Initialize WebRTC with message handler
webrtcServiceRef.current = new WebRTCService(handleRTCMessage);
await webrtcServiceRef.current.initializeCall(); await webrtcServiceRef.current.initializeCall();
// Signal call start via WebSocket
wsMessage({ type: 'call-start' });
const stream = await navigator.mediaDevices.getUserMedia({ audio: true }); const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
audioContextRef.current = new AudioContext(); audioContextRef.current = new AudioContext();
const source = audioContextRef.current.createMediaStreamSource(stream); const source = audioContextRef.current.createMediaStreamSource(stream);
analyserRef.current = audioContextRef.current.createAnalyser(); analyserRef.current = audioContextRef.current.createAnalyser();
source.connect(analyserRef.current); source.connect(analyserRef.current);
intervalRef.current = window.setInterval(checkSilence, 100); // Start VAD monitoring
intervalRef.current = window.setInterval(() => {
if (!analyserRef.current || !isCalling) {
return;
}
const data = new Float32Array(analyserRef.current.frequencyBinCount);
analyserRef.current.getFloatFrequencyData(data);
const avg = data.reduce((a, b) => a + b) / data.length;
if (avg < SILENCE_THRESHOLD) {
if (silenceStartRef.current === null) {
silenceStartRef.current = Date.now();
} else if (Date.now() - silenceStartRef.current > SILENCE_DURATION) {
sendAudioChunk();
silenceStartRef.current = null;
}
} else {
silenceStartRef.current = null;
}
}, 100);
setIsCalling(true); setIsCalling(true);
}, [checkSilence, sendMessage]); }, [handleRTCMessage, wsMessage, sendAudioChunk]);
const hangUp = useCallback(async () => { const hangUp = useCallback(async () => {
if (intervalRef.current) { if (intervalRef.current) {
clearInterval(intervalRef.current); clearInterval(intervalRef.current);
} }
analyserRef.current = null; analyserRef.current = null;
audioContextRef.current?.close(); audioContextRef.current?.close();
audioContextRef.current = null; audioContextRef.current = null;
await webrtcServiceRef.current?.endCall(); await webrtcServiceRef.current?.endCall();
webrtcServiceRef.current = null; webrtcServiceRef.current = null;
setIsCalling(false);
sendMessage({ type: 'call-ended' });
}, [sendMessage]);
return { isCalling, startCall, hangUp }; setIsCalling(false);
setIsProcessing(false);
wsMessage({ type: 'call-ended' });
}, [wsMessage]);
return {
isCalling,
isProcessing,
startCall,
hangUp,
};
}; };
export default useCall; export default useCall;

View file

@ -1,75 +1,44 @@
import { useRef, useCallback } from 'react'; import { useRef, useCallback } from 'react';
import { WebRTCService } from '../services/WebRTC/WebRTCService';
import type { RTCMessage } from '~/common';
import useWebSocket from './useWebSocket'; import useWebSocket from './useWebSocket';
const SILENCE_THRESHOLD = -50;
const SILENCE_DURATION = 1000;
const useWebRTC = () => { const useWebRTC = () => {
const { sendMessage } = useWebSocket(); const { sendMessage } = useWebSocket();
const localStreamRef = useRef<MediaStream | null>(null); const webrtcServiceRef = useRef<WebRTCService | null>(null);
const audioContextRef = useRef<AudioContext | null>(null);
const analyserRef = useRef<AnalyserNode | null>(null);
const silenceStartTime = useRef<number | null>(null);
const isProcessingRef = useRef(false);
const log = (msg: string) => console.log(`[WebRTC ${new Date().toISOString()}] ${msg}`); const handleRTCMessage = useCallback(
(message: RTCMessage) => {
const processAudioLevel = () => { switch (message.type) {
if (!analyserRef.current || !isProcessingRef.current) { case 'audio-chunk':
return; sendMessage({ type: 'processing-start' });
} break;
case 'transcription':
const dataArray = new Float32Array(analyserRef.current.frequencyBinCount); case 'llm-response':
analyserRef.current.getFloatFrequencyData(dataArray); case 'tts-chunk':
const average = dataArray.reduce((a, b) => a + b) / dataArray.length; // TODO: Handle streaming responses
break;
if (average < SILENCE_THRESHOLD) {
if (!silenceStartTime.current) {
silenceStartTime.current = Date.now();
log(`Silence started: ${average}dB`);
} else if (Date.now() - silenceStartTime.current > SILENCE_DURATION) {
log('Silence threshold reached - requesting response');
sendMessage({ type: 'request-response' });
silenceStartTime.current = null;
} }
} else { },
silenceStartTime.current = null; [sendMessage],
} );
requestAnimationFrame(processAudioLevel);
};
const startLocalStream = async () => { const startLocalStream = async () => {
try { try {
log('Starting audio capture'); webrtcServiceRef.current = new WebRTCService(handleRTCMessage);
localStreamRef.current = await navigator.mediaDevices.getUserMedia({ audio: true }); await webrtcServiceRef.current.initializeCall();
sendMessage({ type: 'call-start' });
audioContextRef.current = new AudioContext();
const source = audioContextRef.current.createMediaStreamSource(localStreamRef.current);
analyserRef.current = audioContextRef.current.createAnalyser();
source.connect(analyserRef.current);
isProcessingRef.current = true;
processAudioLevel();
log('Audio capture started');
} catch (error) { } catch (error) {
log(`Error: ${error instanceof Error ? error.message : 'Unknown error'}`); console.error(error);
throw error; throw error;
} }
}; };
const stopLocalStream = useCallback(() => { const stopLocalStream = useCallback(() => {
log('Stopping audio capture'); webrtcServiceRef.current?.endCall();
isProcessingRef.current = false; webrtcServiceRef.current = null;
audioContextRef.current?.close(); sendMessage({ type: 'call-ended' });
localStreamRef.current?.getTracks().forEach((track) => track.stop()); }, [sendMessage]);
localStreamRef.current = null;
audioContextRef.current = null;
analyserRef.current = null;
silenceStartTime.current = null;
}, []);
return { startLocalStream, stopLocalStream }; return { startLocalStream, stopLocalStream };
}; };

View file

@ -1,39 +1,47 @@
import { useEffect, useRef, useState, useCallback } from 'react'; import { useEffect, useRef, useState, useCallback } from 'react';
import { useGetWebsocketUrlQuery } from 'librechat-data-provider/react-query'; import { useGetWebsocketUrlQuery } from 'librechat-data-provider/react-query';
import type { RTCMessage } from '~/common';
const useWebSocket = () => { const useWebSocket = () => {
const { data: url } = useGetWebsocketUrlQuery(); const { data: data } = useGetWebsocketUrlQuery();
const [isConnected, setIsConnected] = useState(false); const [isConnected, setIsConnected] = useState(false);
const wsRef = useRef<WebSocket | null>(null); const wsRef = useRef<WebSocket | null>(null);
console.log('wsConfig:', url?.url);
const connect = useCallback(() => { const connect = useCallback(() => {
if (!url?.url) { if (!data || !data.url) {
return; return;
} }
wsRef.current = new WebSocket(url?.url); wsRef.current = new WebSocket(data.url);
wsRef.current.onopen = () => setIsConnected(true); wsRef.current.onopen = () => setIsConnected(true);
wsRef.current.onclose = () => setIsConnected(false); wsRef.current.onclose = () => setIsConnected(false);
wsRef.current.onerror = (err) => console.error('WebSocket error:', err); wsRef.current.onerror = (err) => console.error('WebSocket error:', err);
wsRef.current.onmessage = (event) => { wsRef.current.onmessage = (event) => {
const msg = JSON.parse(event.data); const msg: RTCMessage = JSON.parse(event.data);
if (msg.type === 'audio-response') { switch (msg.type) {
const audioData = msg.data; case 'transcription':
const audio = new Audio(`data:audio/mp3;base64,${audioData}`); // TODO: Handle transcription update
audio.play().catch(console.error); break;
case 'llm-response':
// TODO: Handle LLM streaming response
break;
case 'tts-chunk':
if (typeof msg.data === 'string') {
const audio = new Audio(`data:audio/mp3;base64,${msg.data}`);
audio.play().catch(console.error);
}
break;
} }
}; };
}, [url?.url]); }, [data?.url]);
useEffect(() => { useEffect(() => {
connect(); connect();
return () => wsRef.current?.close(); return () => wsRef.current?.close();
}, [connect]); }, [connect]);
const sendMessage = useCallback((message: any) => { const sendMessage = useCallback((message: Record<string, unknown>) => {
if (wsRef.current?.readyState === WebSocket.OPEN) { if (wsRef.current?.readyState === WebSocket.OPEN) {
wsRef.current.send(JSON.stringify(message)); wsRef.current.send(JSON.stringify(message));
} }

View file

@ -1,36 +1,55 @@
import type { RTCMessage } from '~/common';
export class WebRTCService { export class WebRTCService {
private peerConnection: RTCPeerConnection | null = null; private peerConnection: RTCPeerConnection | null = null;
private dataChannel: RTCDataChannel | null = null;
private mediaRecorder: MediaRecorder | null = null; private mediaRecorder: MediaRecorder | null = null;
private sendMessage: (msg: any) => void; private onMessage: (msg: RTCMessage) => void;
constructor(sendMessage: (msg: any) => void) { constructor(onMessage: (msg: RTCMessage) => void) {
this.sendMessage = sendMessage; this.onMessage = onMessage;
} }
async initializeCall() { async initializeCall() {
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
this.peerConnection = new RTCPeerConnection(); this.peerConnection = new RTCPeerConnection();
stream.getTracks().forEach((track) => this.peerConnection?.addTrack(track, stream)); this.dataChannel = this.peerConnection.createDataChannel('audio');
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
this.mediaRecorder = new MediaRecorder(stream); this.mediaRecorder = new MediaRecorder(stream);
this.mediaRecorder.ondataavailable = (e) => { this.mediaRecorder.ondataavailable = (e) => {
if (e.data.size > 0) { if (e.data.size > 0 && this.dataChannel?.readyState === 'open') {
const reader = new FileReader(); e.data.arrayBuffer().then((buffer) => {
reader.onload = () => { this.dataChannel?.send(buffer);
this.sendMessage({ });
type: 'audio-chunk',
data: reader.result,
});
};
reader.readAsDataURL(e.data);
} }
}; };
this.mediaRecorder.start();
this.mediaRecorder.start(100);
this.setupDataChannel();
}
private setupDataChannel() {
if (!this.dataChannel) {
return;
}
this.dataChannel.onmessage = (event) => {
this.onMessage({
type: 'audio-chunk',
data: event.data,
});
};
}
public async sendAudioChunk(audioBlob: Blob) {
if (this.dataChannel && this.dataChannel.readyState === 'open') {
this.dataChannel.send(await audioBlob.arrayBuffer());
}
} }
async endCall() { async endCall() {
this.mediaRecorder?.stop(); this.mediaRecorder?.stop();
this.dataChannel?.close();
this.peerConnection?.close(); this.peerConnection?.close();
this.peerConnection = null;
} }
} }

450
package-lock.json generated
View file

@ -98,6 +98,7 @@
"mongoose": "^8.9.5", "mongoose": "^8.9.5",
"multer": "^1.4.5-lts.1", "multer": "^1.4.5-lts.1",
"nanoid": "^3.3.7", "nanoid": "^3.3.7",
"node-pre-gyp": "^0.17.0",
"nodemailer": "^6.9.15", "nodemailer": "^6.9.15",
"ollama": "^0.5.0", "ollama": "^0.5.0",
"openai": "^4.47.1", "openai": "^4.47.1",
@ -118,6 +119,7 @@
"ua-parser-js": "^1.0.36", "ua-parser-js": "^1.0.36",
"winston": "^3.11.0", "winston": "^3.11.0",
"winston-daily-rotate-file": "^4.7.1", "winston-daily-rotate-file": "^4.7.1",
"wrtc": "^0.4.7",
"ws": "^8.18.0", "ws": "^8.18.0",
"youtube-transcript": "^1.2.1", "youtube-transcript": "^1.2.1",
"zod": "^3.22.4" "zod": "^3.22.4"
@ -17171,8 +17173,7 @@
"node_modules/abbrev": { "node_modules/abbrev": {
"version": "1.1.1", "version": "1.1.1",
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
"integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q=="
"dev": true
}, },
"node_modules/abort-controller": { "node_modules/abort-controller": {
"version": "3.0.0", "version": "3.0.0",
@ -17379,6 +17380,21 @@
"resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz", "resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz",
"integrity": "sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw==" "integrity": "sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw=="
}, },
"node_modules/aproba": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz",
"integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw=="
},
"node_modules/are-we-there-yet": {
"version": "1.1.7",
"resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.7.tgz",
"integrity": "sha512-nxwy40TuMiUGqMyRHgCSWZ9FM4VAoRP4xUYSTv5ImRog+h9yISPbVH7H8fASCIzYn9wlEv4zvFL7uKDMCFQm3g==",
"deprecated": "This package is no longer supported.",
"dependencies": {
"delegates": "^1.0.0",
"readable-stream": "^2.0.6"
}
},
"node_modules/arg": { "node_modules/arg": {
"version": "5.0.2", "version": "5.0.2",
"resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz",
@ -18861,6 +18877,14 @@
"node": ">= 0.12.0" "node": ">= 0.12.0"
} }
}, },
"node_modules/code-point-at": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
"integrity": "sha512-RpAVKQA5T63xEj6/giIbUEtZwJ4UFIc3ZtvEkiaUERylqe8xb5IvqcgOurZLahv93CLKfxcw5YI+DZcUBRyLXA==",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/cohere-ai": { "node_modules/cohere-ai": {
"version": "7.9.1", "version": "7.9.1",
"resolved": "https://registry.npmjs.org/cohere-ai/-/cohere-ai-7.9.1.tgz", "resolved": "https://registry.npmjs.org/cohere-ai/-/cohere-ai-7.9.1.tgz",
@ -19110,6 +19134,11 @@
"integrity": "sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==", "integrity": "sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==",
"dev": true "dev": true
}, },
"node_modules/console-control-strings": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz",
"integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ=="
},
"node_modules/constants-browserify": { "node_modules/constants-browserify": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz",
@ -19827,6 +19856,11 @@
"node": ">=0.4.0" "node": ">=0.4.0"
} }
}, },
"node_modules/delegates": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz",
"integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ=="
},
"node_modules/denque": { "node_modules/denque": {
"version": "2.1.0", "version": "2.1.0",
"resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz", "resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz",
@ -22111,6 +22145,23 @@
"universalify": "^0.1.0" "universalify": "^0.1.0"
} }
}, },
"node_modules/fs-minipass": {
"version": "1.2.7",
"resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.7.tgz",
"integrity": "sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA==",
"dependencies": {
"minipass": "^2.6.0"
}
},
"node_modules/fs-minipass/node_modules/minipass": {
"version": "2.9.0",
"resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz",
"integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==",
"dependencies": {
"safe-buffer": "^5.1.2",
"yallist": "^3.0.0"
}
},
"node_modules/fs.realpath": { "node_modules/fs.realpath": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
@ -22167,6 +22218,65 @@
"url": "https://github.com/sponsors/ljharb" "url": "https://github.com/sponsors/ljharb"
} }
}, },
"node_modules/gauge": {
"version": "2.7.4",
"resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz",
"integrity": "sha512-14x4kjc6lkD3ltw589k0NrPD6cCNTD6CWoVUNpB85+DrtONoZn+Rug6xZU5RvSC4+TZPxA5AnBibQYAvZn41Hg==",
"deprecated": "This package is no longer supported.",
"dependencies": {
"aproba": "^1.0.3",
"console-control-strings": "^1.0.0",
"has-unicode": "^2.0.0",
"object-assign": "^4.1.0",
"signal-exit": "^3.0.0",
"string-width": "^1.0.1",
"strip-ansi": "^3.0.1",
"wide-align": "^1.1.0"
}
},
"node_modules/gauge/node_modules/ansi-regex": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
"integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/gauge/node_modules/is-fullwidth-code-point": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
"integrity": "sha512-1pqUqRjkhPJ9miNq9SwMfdvi6lBJcd6eFxvfaivQhaH3SgisfiuudvFntdKOmxuee/77l+FPjKrQjWvmPjWrRw==",
"dependencies": {
"number-is-nan": "^1.0.0"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/gauge/node_modules/string-width": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
"integrity": "sha512-0XsVpQLnVCXHJfyEs8tC0zpTVIr5PKKsQtkT29IwupnPTjtPmQ3xT/4yCREF9hYkV/3M3kzcUTSAZT6a6h81tw==",
"dependencies": {
"code-point-at": "^1.0.0",
"is-fullwidth-code-point": "^1.0.0",
"strip-ansi": "^3.0.0"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/gauge/node_modules/strip-ansi": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
"integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==",
"dependencies": {
"ansi-regex": "^2.0.0"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/gaxios": { "node_modules/gaxios": {
"version": "6.2.0", "version": "6.2.0",
"resolved": "https://registry.npmjs.org/gaxios/-/gaxios-6.2.0.tgz", "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-6.2.0.tgz",
@ -22833,6 +22943,11 @@
"url": "https://github.com/sponsors/ljharb" "url": "https://github.com/sponsors/ljharb"
} }
}, },
"node_modules/has-unicode": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz",
"integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ=="
},
"node_modules/hash-base": { "node_modules/hash-base": {
"version": "3.1.0", "version": "3.1.0",
"resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz", "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz",
@ -23485,6 +23600,14 @@
"integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==",
"dev": true "dev": true
}, },
"node_modules/ignore-walk": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.4.tgz",
"integrity": "sha512-PY6Ii8o1jMRA1z4F2hRkH/xN59ox43DavKvD3oDpfurRlOJyAHpifIwpbdv1n4jt4ov0jSpw3kQ4GhJnpBL6WQ==",
"dependencies": {
"minimatch": "^3.0.4"
}
},
"node_modules/import-fresh": { "node_modules/import-fresh": {
"version": "3.3.0", "version": "3.3.0",
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
@ -28118,6 +28241,23 @@
"node": ">=16 || 14 >=14.17" "node": ">=16 || 14 >=14.17"
} }
}, },
"node_modules/minizlib": {
"version": "1.3.3",
"resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.3.3.tgz",
"integrity": "sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q==",
"dependencies": {
"minipass": "^2.9.0"
}
},
"node_modules/minizlib/node_modules/minipass": {
"version": "2.9.0",
"resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz",
"integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==",
"dependencies": {
"safe-buffer": "^5.1.2",
"yallist": "^3.0.0"
}
},
"node_modules/mkdirp": { "node_modules/mkdirp": {
"version": "1.0.4", "version": "1.0.4",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
@ -28395,6 +28535,30 @@
"node": ">=18" "node": ">=18"
} }
}, },
"node_modules/needle": {
"version": "2.9.1",
"resolved": "https://registry.npmjs.org/needle/-/needle-2.9.1.tgz",
"integrity": "sha512-6R9fqJ5Zcmf+uYaFgdIHmLwNldn5HbK8L5ybn7Uz+ylX/rnOsSp1AHcvQSrCaFN+qNM1wpymHqD7mVasEOlHGQ==",
"dependencies": {
"debug": "^3.2.6",
"iconv-lite": "^0.4.4",
"sax": "^1.2.4"
},
"bin": {
"needle": "bin/needle"
},
"engines": {
"node": ">= 4.4.x"
}
},
"node_modules/needle/node_modules/debug": {
"version": "3.2.7",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
"integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
"dependencies": {
"ms": "^2.1.1"
}
},
"node_modules/negotiator": { "node_modules/negotiator": {
"version": "0.6.3", "version": "0.6.3",
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
@ -28511,6 +28675,101 @@
"integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==",
"dev": true "dev": true
}, },
"node_modules/node-pre-gyp": {
"version": "0.17.0",
"resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.17.0.tgz",
"integrity": "sha512-abzZt1hmOjkZez29ppg+5gGqdPLUuJeAEwVPtHYEJgx0qzttCbcKFpxrCQn2HYbwCv2c+7JwH4BgEzFkUGpn4A==",
"deprecated": "Please upgrade to @mapbox/node-pre-gyp: the non-scoped node-pre-gyp package is deprecated and only the @mapbox scoped package will recieve updates in the future",
"dependencies": {
"detect-libc": "^1.0.3",
"mkdirp": "^0.5.5",
"needle": "^2.5.2",
"nopt": "^4.0.3",
"npm-packlist": "^1.4.8",
"npmlog": "^4.1.2",
"rc": "^1.2.8",
"rimraf": "^2.7.1",
"semver": "^5.7.1",
"tar": "^4.4.13"
},
"bin": {
"node-pre-gyp": "bin/node-pre-gyp"
}
},
"node_modules/node-pre-gyp/node_modules/detect-libc": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz",
"integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==",
"bin": {
"detect-libc": "bin/detect-libc.js"
},
"engines": {
"node": ">=0.10"
}
},
"node_modules/node-pre-gyp/node_modules/glob": {
"version": "7.2.3",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
"integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
"deprecated": "Glob versions prior to v9 are no longer supported",
"dependencies": {
"fs.realpath": "^1.0.0",
"inflight": "^1.0.4",
"inherits": "2",
"minimatch": "^3.1.1",
"once": "^1.3.0",
"path-is-absolute": "^1.0.0"
},
"engines": {
"node": "*"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/node-pre-gyp/node_modules/mkdirp": {
"version": "0.5.6",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz",
"integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==",
"dependencies": {
"minimist": "^1.2.6"
},
"bin": {
"mkdirp": "bin/cmd.js"
}
},
"node_modules/node-pre-gyp/node_modules/nopt": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.3.tgz",
"integrity": "sha512-CvaGwVMztSMJLOeXPrez7fyfObdZqNUK1cPAEzLHrTybIua9pMdmmPR5YwtfNftIOMv3DPUhFaxsZMNTQO20Kg==",
"dependencies": {
"abbrev": "1",
"osenv": "^0.1.4"
},
"bin": {
"nopt": "bin/nopt.js"
}
},
"node_modules/node-pre-gyp/node_modules/rimraf": {
"version": "2.7.1",
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
"integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
"deprecated": "Rimraf versions prior to v4 are no longer supported",
"dependencies": {
"glob": "^7.1.3"
},
"bin": {
"rimraf": "bin.js"
}
},
"node_modules/node-pre-gyp/node_modules/semver": {
"version": "5.7.2",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz",
"integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==",
"bin": {
"semver": "bin/semver"
}
},
"node_modules/node-releases": { "node_modules/node-releases": {
"version": "2.0.18", "version": "2.0.18",
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz",
@ -28720,6 +28979,29 @@
"node": ">=0.10.0" "node": ">=0.10.0"
} }
}, },
"node_modules/npm-bundled": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.1.2.tgz",
"integrity": "sha512-x5DHup0SuyQcmL3s7Rx/YQ8sbw/Hzg0rj48eN0dV7hf5cmQq5PXIeioroH3raV1QC1yh3uTYuMThvEQF3iKgGQ==",
"dependencies": {
"npm-normalize-package-bin": "^1.0.1"
}
},
"node_modules/npm-normalize-package-bin": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz",
"integrity": "sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA=="
},
"node_modules/npm-packlist": {
"version": "1.4.8",
"resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.4.8.tgz",
"integrity": "sha512-5+AZgwru5IevF5ZdnFglB5wNlHG1AOOuw28WhUq8/8emhBmLv6jX5by4WJCh7lW0uSYZYS6DXqIsyZVIXRZU9A==",
"dependencies": {
"ignore-walk": "^3.0.1",
"npm-bundled": "^1.0.1",
"npm-normalize-package-bin": "^1.0.1"
}
},
"node_modules/npm-run-path": { "node_modules/npm-run-path": {
"version": "4.0.1", "version": "4.0.1",
"resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz",
@ -28732,6 +29014,18 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/npmlog": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz",
"integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==",
"deprecated": "This package is no longer supported.",
"dependencies": {
"are-we-there-yet": "~1.1.2",
"console-control-strings": "~1.1.0",
"gauge": "~2.7.3",
"set-blocking": "~2.0.0"
}
},
"node_modules/nth-check": { "node_modules/nth-check": {
"version": "2.1.1", "version": "2.1.1",
"resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz",
@ -28745,6 +29039,14 @@
"url": "https://github.com/fb55/nth-check?sponsor=1" "url": "https://github.com/fb55/nth-check?sponsor=1"
} }
}, },
"node_modules/number-is-nan": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
"integrity": "sha512-4jbtZXNAsfZbAHiiqjLPBiCl16dES1zI4Hpzzxw61Tk+loF+sBDBKx1ICKKKwIqQ7M0mFn1TmkN7euSncWgHiQ==",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/nwsapi": { "node_modules/nwsapi": {
"version": "2.2.7", "version": "2.2.7",
"resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.7.tgz", "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.7.tgz",
@ -29067,6 +29369,32 @@
"integrity": "sha512-gjcpUc3clBf9+210TRaDWbf+rZZZEshZ+DlXMRCeAjp0xhTrnQsKHypIy1J3d5hKdUzj69t708EHtU8P6bUn0A==", "integrity": "sha512-gjcpUc3clBf9+210TRaDWbf+rZZZEshZ+DlXMRCeAjp0xhTrnQsKHypIy1J3d5hKdUzj69t708EHtU8P6bUn0A==",
"dev": true "dev": true
}, },
"node_modules/os-homedir": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz",
"integrity": "sha512-B5JU3cabzk8c67mRRd3ECmROafjYMXbuzlwtqdM8IbS8ktlTix8aFGb2bAGKrSRIlnfKwovGUUr72JUPyOb6kQ==",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/os-tmpdir": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
"integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/osenv": {
"version": "0.1.5",
"resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz",
"integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==",
"deprecated": "This package is no longer supported.",
"dependencies": {
"os-homedir": "^1.0.0",
"os-tmpdir": "^1.0.0"
}
},
"node_modules/outvariant": { "node_modules/outvariant": {
"version": "1.4.0", "version": "1.4.0",
"resolved": "https://registry.npmjs.org/outvariant/-/outvariant-1.4.0.tgz", "resolved": "https://registry.npmjs.org/outvariant/-/outvariant-1.4.0.tgz",
@ -33220,6 +33548,11 @@
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
}, },
"node_modules/sax": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz",
"integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg=="
},
"node_modules/saxes": { "node_modules/saxes": {
"version": "6.0.0", "version": "6.0.0",
"resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz",
@ -33348,6 +33681,11 @@
"node": ">= 0.8.0" "node": ">= 0.8.0"
} }
}, },
"node_modules/set-blocking": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
"integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw=="
},
"node_modules/set-function-length": { "node_modules/set-function-length": {
"version": "1.2.2", "version": "1.2.2",
"resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",
@ -33540,8 +33878,7 @@
"node_modules/signal-exit": { "node_modules/signal-exit": {
"version": "3.0.7", "version": "3.0.7",
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
"integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ=="
"dev": true
}, },
"node_modules/simple-concat": { "node_modules/simple-concat": {
"version": "1.0.1", "version": "1.0.1",
@ -34496,6 +34833,23 @@
"node": ">=6" "node": ">=6"
} }
}, },
"node_modules/tar": {
"version": "4.4.19",
"resolved": "https://registry.npmjs.org/tar/-/tar-4.4.19.tgz",
"integrity": "sha512-a20gEsvHnWe0ygBY8JbxoM4w3SJdhc7ZAuxkLqh+nvNQN2IOt0B5lLgM490X5Hl8FF0dl0tOf2ewFYAlIFgzVA==",
"dependencies": {
"chownr": "^1.1.4",
"fs-minipass": "^1.2.7",
"minipass": "^2.9.0",
"minizlib": "^1.3.3",
"mkdirp": "^0.5.5",
"safe-buffer": "^5.2.1",
"yallist": "^3.1.1"
},
"engines": {
"node": ">=4.5"
}
},
"node_modules/tar-fs": { "node_modules/tar-fs": {
"version": "3.0.4", "version": "3.0.4",
"resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.0.4.tgz", "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.0.4.tgz",
@ -34516,6 +34870,26 @@
"streamx": "^2.15.0" "streamx": "^2.15.0"
} }
}, },
"node_modules/tar/node_modules/minipass": {
"version": "2.9.0",
"resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz",
"integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==",
"dependencies": {
"safe-buffer": "^5.1.2",
"yallist": "^3.0.0"
}
},
"node_modules/tar/node_modules/mkdirp": {
"version": "0.5.6",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz",
"integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==",
"dependencies": {
"minimist": "^1.2.6"
},
"bin": {
"mkdirp": "bin/cmd.js"
}
},
"node_modules/temp-dir": { "node_modules/temp-dir": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-2.0.0.tgz", "resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-2.0.0.tgz",
@ -36411,6 +36785,40 @@
"url": "https://github.com/sponsors/ljharb" "url": "https://github.com/sponsors/ljharb"
} }
}, },
"node_modules/wide-align": {
"version": "1.1.5",
"resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz",
"integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==",
"dependencies": {
"string-width": "^1.0.2 || 2 || 3 || 4"
}
},
"node_modules/wide-align/node_modules/emoji-regex": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
},
"node_modules/wide-align/node_modules/is-fullwidth-code-point": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
"engines": {
"node": ">=8"
}
},
"node_modules/wide-align/node_modules/string-width": {
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
"dependencies": {
"emoji-regex": "^8.0.0",
"is-fullwidth-code-point": "^3.0.0",
"strip-ansi": "^6.0.1"
},
"engines": {
"node": ">=8"
}
},
"node_modules/winston": { "node_modules/winston": {
"version": "3.11.0", "version": "3.11.0",
"resolved": "https://registry.npmjs.org/winston/-/winston-3.11.0.tgz", "resolved": "https://registry.npmjs.org/winston/-/winston-3.11.0.tgz",
@ -37092,6 +37500,40 @@
"node": ">=6" "node": ">=6"
} }
}, },
"node_modules/wrtc": {
"version": "0.4.7",
"resolved": "https://registry.npmjs.org/wrtc/-/wrtc-0.4.7.tgz",
"integrity": "sha512-P6Hn7VT4lfSH49HxLHcHhDq+aFf/jd9dPY7lDHeFhZ22N3858EKuwm2jmnlPzpsRGEPaoF6XwkcxY5SYnt4f/g==",
"bundleDependencies": [
"node-pre-gyp"
],
"hasInstallScript": true,
"dependencies": {
"node-pre-gyp": "^0.13.0"
},
"engines": {
"node": "^8.11.2 || >=10.0.0"
},
"optionalDependencies": {
"domexception": "^1.0.1"
}
},
"node_modules/wrtc/node_modules/domexception": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/domexception/-/domexception-1.0.1.tgz",
"integrity": "sha512-raigMkn7CJNNo6Ihro1fzG7wr3fHuYVytzquZKX5n0yizGsTcYgzdIUwj1X9pK0VvjeihV+XiclP+DjwbsSKug==",
"deprecated": "Use your platform's native DOMException instead",
"optional": true,
"dependencies": {
"webidl-conversions": "^4.0.2"
}
},
"node_modules/wrtc/node_modules/webidl-conversions": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz",
"integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==",
"optional": true
},
"node_modules/ws": { "node_modules/ws": {
"version": "8.18.0", "version": "8.18.0",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz",