diff --git a/Assets/PongStreamSender.cs b/Assets/PongStreamSender.cs index 2e75404..9cde143 100644 --- a/Assets/PongStreamSender.cs +++ b/Assets/PongStreamSender.cs @@ -1,119 +1,119 @@ -using System; -using Unity.RenderStreaming.Signaling; -using UnityEngine; -using Unity.WebRTC; - -namespace Unity.RenderStreaming.Samples -{ - /// - /// 心跳接收通道 - 继承 DataChannelBase(对应博客中的 ReceiveChannel) - /// 接收服务端发送的 Ping,回复 Pong - /// - class HeartbeatReceiveChannel : DataChannelBase - { - // 消息类型(必须与服务端保持一致) - private const int MSG_TYPE_PING = 1; - private const int MSG_TYPE_PONG = 2; - - // 统计信息 - public long LastRtt { get; private set; } - public float AverageRtt { get; private set; } - public int ReceivedPingCount { get; private set; } - - // 事件 - public event Action OnPingReceived; // 参数:RTT - public event Action OnTimeoutWarning; // 超时警告 - - private System.Collections.Generic.Queue _latencyHistory = new System.Collections.Generic.Queue(10); - - [Serializable] - private class HeartbeatMessage - { - public int type; // 1=ping, 2=pong - public long timestamp; // 服务端发送时间戳 - public int seq; // 序列号 - } - - - /// - /// 重写 OnMessage - 当收到数据时自动调用(对应博客中的 ReceiveChannel 实现) - /// - protected override void OnMessage(byte[] bytes) - { - try - { - string json = System.Text.Encoding.UTF8.GetString(bytes); - var msg = JsonUtility.FromJson(json); - - if (msg.type == MSG_TYPE_PING) - { - HandlePing(msg); - } - } - catch (Exception e) - { - Debug.LogError($"[心跳接收通道] 消息解析失败: {e.Message}"); - } - } - - /// - /// 处理 Ping 消息并回复 Pong - /// - private void HandlePing(HeartbeatMessage ping) - { - long now = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); - long latency = now - ping.timestamp; - - ReceivedPingCount++; - LastRtt = latency; - - // 更新平均延迟 - _latencyHistory.Enqueue(latency); - if (_latencyHistory.Count > 10) - _latencyHistory.Dequeue(); - - long sum = 0; - foreach (var lat in _latencyHistory) - sum += lat; - AverageRtt = sum / (float)_latencyHistory.Count; - - Debug.Log($"[心跳接收通道] 收到 Ping #{ping.seq}, 延迟: {latency}ms, 平均: {AverageRtt:F1}ms"); - - // 立即回复 Pong(关键:回传原始时间戳,方便服务端计算 RTT) - SendPong(ping.timestamp, ping.seq); - - // 触发事件 - OnPingReceived?.Invoke(latency); - } - - /// - /// 发送 Pong 响应 - /// - private void SendPong(long originalTimestamp, int seq) - { - if (Channel == null || Channel.ReadyState != RTCDataChannelState.Open) - { - Debug.LogWarning("[心跳接收通道] 通道未打开,无法发送 Pong"); - return; - } - - var pong = new HeartbeatMessage - { - type = MSG_TYPE_PONG, - timestamp = originalTimestamp, // 回传服务端的时间戳 - seq = seq - }; - - string json = JsonUtility.ToJson(pong); - byte[] bytes = System.Text.Encoding.UTF8.GetBytes(json); - - Channel.Send(bytes); - Debug.Log($"[心跳接收通道] 发送 Pong #{seq}"); - } - - /// - /// 获取当前连接状态 - /// - public bool IsConnected => Channel != null && Channel.ReadyState == RTCDataChannelState.Open; - } -} \ No newline at end of file +// using System; +// using Unity.RenderStreaming.Signaling; +// using UnityEngine; +// using Unity.WebRTC; +// +// namespace Unity.RenderStreaming.Samples +// { +// /// +// /// 心跳接收通道 - 继承 DataChannelBase(对应博客中的 ReceiveChannel) +// /// 接收服务端发送的 Ping,回复 Pong +// /// +// class HeartbeatReceiveChannel : DataChannelBase +// { +// // 消息类型(必须与服务端保持一致) +// private const int MSG_TYPE_PING = 1; +// private const int MSG_TYPE_PONG = 2; +// +// // 统计信息 +// public long LastRtt { get; private set; } +// public float AverageRtt { get; private set; } +// public int ReceivedPingCount { get; private set; } +// +// // 事件 +// public event Action OnPingReceived; // 参数:RTT +// public event Action OnTimeoutWarning; // 超时警告 +// +// private System.Collections.Generic.Queue _latencyHistory = new System.Collections.Generic.Queue(10); +// +// [Serializable] +// private class HeartbeatMessage +// { +// public int type; // 1=ping, 2=pong +// public long timestamp; // 服务端发送时间戳 +// public int seq; // 序列号 +// } +// +// +// /// +// /// 重写 OnMessage - 当收到数据时自动调用(对应博客中的 ReceiveChannel 实现) +// /// +// protected override void OnMessage(byte[] bytes) +// { +// try +// { +// string json = System.Text.Encoding.UTF8.GetString(bytes); +// var msg = JsonUtility.FromJson(json); +// +// if (msg.type == MSG_TYPE_PING) +// { +// HandlePing(msg); +// } +// } +// catch (Exception e) +// { +// Debug.LogError($"[心跳接收通道] 消息解析失败: {e.Message}"); +// } +// } +// +// /// +// /// 处理 Ping 消息并回复 Pong +// /// +// private void HandlePing(HeartbeatMessage ping) +// { +// long now = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); +// long latency = now - ping.timestamp; +// +// ReceivedPingCount++; +// LastRtt = latency; +// +// // 更新平均延迟 +// _latencyHistory.Enqueue(latency); +// if (_latencyHistory.Count > 10) +// _latencyHistory.Dequeue(); +// +// long sum = 0; +// foreach (var lat in _latencyHistory) +// sum += lat; +// AverageRtt = sum / (float)_latencyHistory.Count; +// +// Debug.Log($"[心跳接收通道] 收到 Ping #{ping.seq}, 延迟: {latency}ms, 平均: {AverageRtt:F1}ms"); +// +// // 立即回复 Pong(关键:回传原始时间戳,方便服务端计算 RTT) +// SendPong(ping.timestamp, ping.seq); +// +// // 触发事件 +// OnPingReceived?.Invoke(latency); +// } +// +// /// +// /// 发送 Pong 响应 +// /// +// private void SendPong(long originalTimestamp, int seq) +// { +// if (Channel == null || Channel.ReadyState != RTCDataChannelState.Open) +// { +// Debug.LogWarning("[心跳接收通道] 通道未打开,无法发送 Pong"); +// return; +// } +// +// var pong = new HeartbeatMessage +// { +// type = MSG_TYPE_PONG, +// timestamp = originalTimestamp, // 回传服务端的时间戳 +// seq = seq +// }; +// +// string json = JsonUtility.ToJson(pong); +// byte[] bytes = System.Text.Encoding.UTF8.GetBytes(json); +// +// Channel.Send(bytes); +// Debug.Log($"[心跳接收通道] 发送 Pong #{seq}"); +// } +// +// /// +// /// 获取当前连接状态 +// /// +// public bool IsConnected => Channel != null && Channel.ReadyState == RTCDataChannelState.Open; +// } +// } \ No newline at end of file diff --git a/Assets/Samples/Unity Render Streaming/3.1.0-exp.9/Example/Bidirectional/BidirectionalSample.cs b/Assets/Samples/Unity Render Streaming/3.1.0-exp.9/Example/Bidirectional/BidirectionalSample.cs index febe314..7804ec6 100644 --- a/Assets/Samples/Unity Render Streaming/3.1.0-exp.9/Example/Bidirectional/BidirectionalSample.cs +++ b/Assets/Samples/Unity Render Streaming/3.1.0-exp.9/Example/Bidirectional/BidirectionalSample.cs @@ -22,7 +22,7 @@ namespace Unity.RenderStreaming.Samples [SerializeField] private VideoStreamReceiver receiveVideoViewer; [SerializeField] private AudioStreamSender microphoneStreamer; [SerializeField] private AudioStreamReceiver receiveAudioViewer; - [SerializeField] private SingleConnection singleConnection; + [SerializeField] private HostConnection singleConnection; #pragma warning restore 0649 private string connectionId; diff --git a/Packages/com.unity.renderstreaming@3.1.0-exp.9/Runtime/Scripts/ExecuteSignalingEvents.cs b/Packages/com.unity.renderstreaming@3.1.0-exp.9/Runtime/Scripts/ExecuteSignalingEvents.cs index 13b3d40..bc95e5e 100644 --- a/Packages/com.unity.renderstreaming@3.1.0-exp.9/Runtime/Scripts/ExecuteSignalingEvents.cs +++ b/Packages/com.unity.renderstreaming@3.1.0-exp.9/Runtime/Scripts/ExecuteSignalingEvents.cs @@ -29,6 +29,14 @@ namespace Unity.RenderStreaming s_AddChannelHandler = Execute; private static readonly ExecuteEvents.EventFunction s_AddReceiverHandler = Execute; + private static readonly ExecuteEvents.EventFunction + s_ParticipantJoinedHandler = Execute; + private static readonly ExecuteEvents.EventFunction + s_ParticipantLeftHandler = Execute; + private static readonly ExecuteEvents.EventFunction + s_CallRequestHandler = Execute; + private static readonly ExecuteEvents.EventFunction + s_MessageHandler = Execute; private static void Execute(ICreatedConnectionHandler handler, BaseEventData eventData) { @@ -62,6 +70,22 @@ namespace Unity.RenderStreaming { handler.OnAddReceiver(ValidateEventData(eventData)); } + private static void Execute(IParticipantJoinedHandler handler, BaseEventData eventData) + { + handler.OnParticipantJoined(ValidateEventData(eventData)); + } + private static void Execute(IParticipantLeftHandler handler, BaseEventData eventData) + { + handler.OnParticipantLeft(ValidateEventData(eventData)); + } + private static void Execute(ICallRequestHandler handler, BaseEventData eventData) + { + handler.OnCallRequest(ValidateEventData(eventData)); + } + private static void Execute(IMessageHandler handler, BaseEventData eventData) + { + handler.OnMessage(ValidateEventData(eventData)); + } public static ExecuteEvents.EventFunction createdConnectionHandler { @@ -96,6 +120,22 @@ namespace Unity.RenderStreaming { get { return s_AddReceiverHandler; } } + public static ExecuteEvents.EventFunction participantJoinedHandler + { + get { return s_ParticipantJoinedHandler; } + } + public static ExecuteEvents.EventFunction participantLeftHandler + { + get { return s_ParticipantLeftHandler; } + } + public static ExecuteEvents.EventFunction callRequestHandler + { + get { return s_CallRequestHandler; } + } + public static ExecuteEvents.EventFunction messageHandler + { + get { return s_MessageHandler; } + } } diff --git a/Packages/com.unity.renderstreaming@3.1.0-exp.9/Runtime/Scripts/HostConnection.cs b/Packages/com.unity.renderstreaming@3.1.0-exp.9/Runtime/Scripts/HostConnection.cs new file mode 100644 index 0000000..4b7b763 --- /dev/null +++ b/Packages/com.unity.renderstreaming@3.1.0-exp.9/Runtime/Scripts/HostConnection.cs @@ -0,0 +1,243 @@ +using System.Collections.Generic; +using System.Linq; +using UnityEngine; + +namespace Unity.RenderStreaming +{ + /// + /// Host模式的连接处理器 + /// 适用于私有模式下Unity作为Host(第一个加入房间的客户端) + /// 支持多个Participant连接,每个Participant拥有独立的PeerConnection + /// + /// 工作原理: + /// - Host通过CreateConnection(connectionId)创建房间连接 + /// - 当Participant加入时,服务器发送participant-joined通知 + /// - WebSocketSignaling将participantId作为内部connectionId使用, + /// 因此每个Participant会自动创建独立的PeerConnection + /// - 当收到Participant的offer时,自动添加Stream并发送answer + /// - 当Participant离开时,自动清理对应的连接资源 + /// + [AddComponentMenu("Render Streaming/Host Connection")] + public class HostConnection : SignalingHandlerBase, + IOfferHandler, IAddChannelHandler, IDisconnectHandler, IDeletedConnectionHandler, + IAddReceiverHandler, IParticipantJoinedHandler, IParticipantLeftHandler, + ICallRequestHandler, IMessageHandler + { + [SerializeField] private List streams = new List(); + + /// + /// 当前连接的所有Participant的participantId列表 + /// + private List participantIds = new List(); + + /// + /// 房间的connectionId(Host创建连接时使用的ID) + /// + private string roomConnectionId; + + public override IEnumerable Streams => streams; + + public void AddComponent(Component component) + { + streams.Add(component); + } + + public void RemoveComponent(Component component) + { + streams.Remove(component); + } + + /// + /// 创建Host连接(即创建房间) + /// Unity作为第一个连接的客户端,服务器会分配host角色(polite=false) + /// + /// 房间ID + public override void CreateConnection(string connectionId) + { + roomConnectionId = connectionId; + base.CreateConnection(connectionId); + } + + /// + /// 删除Host连接(关闭房间) + /// Host离开时,服务器会自动断开所有Participant + /// + public override void DeleteConnection(string connectionId) + { + // 清理所有Participant连接 + foreach (var participantId in participantIds.ToList()) + { + DisconnectParticipant(participantId); + } + participantIds.Clear(); + + if (connectionId == roomConnectionId) + { + base.DeleteConnection(connectionId); + roomConnectionId = null; + } + else + { + base.DeleteConnection(connectionId); + } + } + + public void OnDeletedConnection(SignalingEventData eventData) + { + Disconnect(eventData.connectionId); + } + + public void OnDisconnect(SignalingEventData eventData) + { + Disconnect(eventData.connectionId); + } + + private void Disconnect(string connectionId) + { + if (!participantIds.Contains(connectionId) && connectionId != roomConnectionId) + return; + + participantIds.Remove(connectionId); + + foreach (var sender in streams.OfType()) + { + RemoveSender(connectionId, sender); + } + foreach (var receiver in streams.OfType()) + { + RemoveReceiver(connectionId, receiver); + } + foreach (var channel in streams.OfType().Where(c => c.ConnectionId == connectionId)) + { + RemoveChannel(connectionId, channel); + } + } + + /// + /// 断开指定Participant的连接资源 + /// + private void DisconnectParticipant(string participantId) + { + foreach (var sender in streams.OfType()) + { + RemoveSender(participantId, sender); + } + foreach (var receiver in streams.OfType()) + { + RemoveReceiver(participantId, receiver); + } + foreach (var channel in streams.OfType().Where(c => c.ConnectionId == participantId)) + { + RemoveChannel(participantId, channel); + } + } + + /// + /// 收到Participant的offer时触发 + /// WebSocketSignaling已经将participantId作为内部connectionId + /// 所以每个Participant的offer会自动创建独立的PeerConnection + /// + public void OnOffer(SignalingEventData data) + { + // 记录新的Participant连接 + if (!participantIds.Contains(data.connectionId)) + { + participantIds.Add(data.connectionId); + Debug.Log($"[HostConnection] Participant offer received: {data.connectionId}"); + } + + // 为该Participant添加所有Stream + foreach (var source in streams.OfType()) + { + AddSender(data.connectionId, source); + } + foreach (var channel in streams.OfType().Where(c => c.IsLocal)) + { + AddChannel(data.connectionId, channel); + } + + // 发送answer给该Participant + SendAnswer(data.connectionId); + } + + /// + /// 收到远程Track时触发 + /// + public void OnAddReceiver(SignalingEventData data) + { + var track = data.transceiver.Receiver.Track; + IStreamReceiver receiver = GetReceiver(track.Kind); + SetReceiver(data.connectionId, receiver, data.transceiver); + } + + /// + /// 收到远程DataChannel时触发 + /// + public void OnAddChannel(SignalingEventData data) + { + var channel = streams.OfType(). + FirstOrDefault(r => !r.IsConnected && !r.IsLocal); + channel?.SetChannel(data.connectionId, data.channel); + } + + /// + /// 新Participant加入房间通知 + /// 在私有模式下,服务器会通知Host有新的Participant加入 + /// 此时不做额外处理,等收到Participant的offer时再建立连接 + /// + public void OnParticipantJoined(SignalingEventData eventData) + { + Debug.Log($"[HostConnection] Participant joined: connectionId={eventData.connectionId}, participantId={eventData.participantId}"); + } + + /// + /// Participant离开房间通知 + /// 清理该Participant的连接资源 + /// + public void OnParticipantLeft(SignalingEventData eventData) + { + string participantId = eventData.participantId; + if (!string.IsNullOrEmpty(participantId)) + { + Debug.Log($"[HostConnection] Participant left: connectionId={eventData.connectionId}, participantId={participantId}"); + DisconnectParticipant(participantId); + participantIds.Remove(participantId); + } + } + + /// + /// 收到呼叫请求 + /// + public void OnCallRequest(SignalingEventData eventData) + { + Debug.Log($"[HostConnection] Call request from: {eventData.connectionId}, data: {eventData.message}"); + } + + /// + /// 收到自定义消息 + /// + public void OnMessage(SignalingEventData eventData) + { + Debug.Log($"[HostConnection] Message from: {eventData.connectionId}, participantId: {eventData.participantId}, message: {eventData.message}"); + } + + /// + /// 获取当前连接的Participant数量 + /// + public int ParticipantCount => participantIds.Count; + + /// + /// 获取所有Participant的ID列表 + /// + public IReadOnlyList ParticipantIds => participantIds.AsReadOnly(); + + IStreamReceiver GetReceiver(WebRTC.TrackKind kind) + { + if (kind == WebRTC.TrackKind.Audio) + return streams.OfType().FirstOrDefault(); + if (kind == WebRTC.TrackKind.Video) + return streams.OfType().FirstOrDefault(); + throw new System.ArgumentException(); + } + } +} diff --git a/Packages/com.unity.renderstreaming@3.1.0-exp.9/Runtime/Scripts/HostConnection.cs.meta b/Packages/com.unity.renderstreaming@3.1.0-exp.9/Runtime/Scripts/HostConnection.cs.meta new file mode 100644 index 0000000..ae59a34 --- /dev/null +++ b/Packages/com.unity.renderstreaming@3.1.0-exp.9/Runtime/Scripts/HostConnection.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b839bc3e2809ef543963ff961d28ce91 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.renderstreaming@3.1.0-exp.9/Runtime/Scripts/IRenderStreamingHandler.cs b/Packages/com.unity.renderstreaming@3.1.0-exp.9/Runtime/Scripts/IRenderStreamingHandler.cs index 9278001..06941b9 100644 --- a/Packages/com.unity.renderstreaming@3.1.0-exp.9/Runtime/Scripts/IRenderStreamingHandler.cs +++ b/Packages/com.unity.renderstreaming@3.1.0-exp.9/Runtime/Scripts/IRenderStreamingHandler.cs @@ -50,6 +50,26 @@ namespace Unity.RenderStreaming /// /// event Action onAddChannel; + + /// + /// 参与者加入事件 (connectionId, participantId) + /// + event Action onParticipantJoined; + + /// + /// 参与者离开事件 (connectionId, participantId) + /// + event Action onParticipantLeft; + + /// + /// 呼叫请求事件 (connectionId, data) + /// + event Action onCallRequest; + + /// + /// 自定义消息事件 (connectionId, participantId, message) + /// + event Action onMessage; } public interface IRenderStreamingHandler diff --git a/Packages/com.unity.renderstreaming@3.1.0-exp.9/Runtime/Scripts/ISignalingEventHandler.cs b/Packages/com.unity.renderstreaming@3.1.0-exp.9/Runtime/Scripts/ISignalingEventHandler.cs index ed7259b..7cb284e 100644 --- a/Packages/com.unity.renderstreaming@3.1.0-exp.9/Runtime/Scripts/ISignalingEventHandler.cs +++ b/Packages/com.unity.renderstreaming@3.1.0-exp.9/Runtime/Scripts/ISignalingEventHandler.cs @@ -41,4 +41,36 @@ namespace Unity.RenderStreaming { void OnAddReceiver(SignalingEventData eventData); } + + /// + /// 参与者加入事件处理器(仅Host收到) + /// + public interface IParticipantJoinedHandler : IEventSystemHandler + { + void OnParticipantJoined(SignalingEventData eventData); + } + + /// + /// 参与者离开事件处理器 + /// + public interface IParticipantLeftHandler : IEventSystemHandler + { + void OnParticipantLeft(SignalingEventData eventData); + } + + /// + /// 呼叫请求事件处理器 + /// + public interface ICallRequestHandler : IEventSystemHandler + { + void OnCallRequest(SignalingEventData eventData); + } + + /// + /// 自定义消息事件处理器 + /// + public interface IMessageHandler : IEventSystemHandler + { + void OnMessage(SignalingEventData eventData); + } } diff --git a/Packages/com.unity.renderstreaming@3.1.0-exp.9/Runtime/Scripts/Signaling/HttpSignaling.cs b/Packages/com.unity.renderstreaming@3.1.0-exp.9/Runtime/Scripts/Signaling/HttpSignaling.cs index 19d02e8..ee1b8fa 100644 --- a/Packages/com.unity.renderstreaming@3.1.0-exp.9/Runtime/Scripts/Signaling/HttpSignaling.cs +++ b/Packages/com.unity.renderstreaming@3.1.0-exp.9/Runtime/Scripts/Signaling/HttpSignaling.cs @@ -94,6 +94,12 @@ namespace Unity.RenderStreaming.Signaling public event OnOfferHandler OnOffer; public event OnAnswerHandler OnAnswer; public event OnIceCandidateHandler OnIceCandidate; +#pragma warning disable 0067 + public event OnParticipantJoinedHandler OnParticipantJoined; + public event OnParticipantLeftHandler OnParticipantLeft; + public event OnCallRequestHandler OnCallRequest; + public event OnMessageHandler OnMessage; +#pragma warning restore 0067 public void SendOffer(string connectionId, RTCSessionDescription offer) { diff --git a/Packages/com.unity.renderstreaming@3.1.0-exp.9/Runtime/Scripts/Signaling/ISignaling.cs b/Packages/com.unity.renderstreaming@3.1.0-exp.9/Runtime/Scripts/Signaling/ISignaling.cs index 5029c45..5cbfe3f 100644 --- a/Packages/com.unity.renderstreaming@3.1.0-exp.9/Runtime/Scripts/Signaling/ISignaling.cs +++ b/Packages/com.unity.renderstreaming@3.1.0-exp.9/Runtime/Scripts/Signaling/ISignaling.cs @@ -8,6 +8,10 @@ namespace Unity.RenderStreaming.Signaling public delegate void OnOfferHandler(ISignaling signaling, DescData e); public delegate void OnAnswerHandler(ISignaling signaling, DescData e); public delegate void OnIceCandidateHandler(ISignaling signaling, CandidateData e); + public delegate void OnParticipantJoinedHandler(ISignaling signaling, ParticipantEventData e); + public delegate void OnParticipantLeftHandler(ISignaling signaling, ParticipantEventData e); + public delegate void OnCallRequestHandler(ISignaling signaling, CallRequestData e); + public delegate void OnMessageHandler(ISignaling signaling, OnMessageData e); public interface ISignaling { @@ -20,6 +24,10 @@ namespace Unity.RenderStreaming.Signaling event OnOfferHandler OnOffer; event OnAnswerHandler OnAnswer; event OnIceCandidateHandler OnIceCandidate; + event OnParticipantJoinedHandler OnParticipantJoined; + event OnParticipantLeftHandler OnParticipantLeft; + event OnCallRequestHandler OnCallRequest; + event OnMessageHandler OnMessage; string Url { get; } diff --git a/Packages/com.unity.renderstreaming@3.1.0-exp.9/Runtime/Scripts/Signaling/SignalingMessage.cs b/Packages/com.unity.renderstreaming@3.1.0-exp.9/Runtime/Scripts/Signaling/SignalingMessage.cs index cca63a6..48c4a2d 100644 --- a/Packages/com.unity.renderstreaming@3.1.0-exp.9/Runtime/Scripts/Signaling/SignalingMessage.cs +++ b/Packages/com.unity.renderstreaming@3.1.0-exp.9/Runtime/Scripts/Signaling/SignalingMessage.cs @@ -10,6 +10,7 @@ namespace Unity.RenderStreaming public string sdp; public bool polite; public DateTime dateTime; + public string participantId; } [Serializable] @@ -36,6 +37,9 @@ namespace Unity.RenderStreaming public string candidate; public string sdpMid; public int sdpMLineIndex; + public string role; + public string reason; + public string data; } [Serializable] @@ -106,5 +110,36 @@ namespace Unity.RenderStreaming public string datetime; } + /// + /// 参与者加入/离开事件数据 + /// + [Serializable] + public class ParticipantEventData + { + public string connectionId; + public string participantId; + } + + /// + /// 呼叫请求数据 + /// + [Serializable] + public class CallRequestData + { + public string connectionId; + public string data; + } + + /// + /// 自定义消息数据 + /// + [Serializable] + public class OnMessageData + { + public string connectionId; + public string participantId; + public string message; + } + #pragma warning restore 0649 } diff --git a/Packages/com.unity.renderstreaming@3.1.0-exp.9/Runtime/Scripts/Signaling/WebSocketSignaling.cs b/Packages/com.unity.renderstreaming@3.1.0-exp.9/Runtime/Scripts/Signaling/WebSocketSignaling.cs index 77f0b63..109ae71 100644 --- a/Packages/com.unity.renderstreaming@3.1.0-exp.9/Runtime/Scripts/Signaling/WebSocketSignaling.cs +++ b/Packages/com.unity.renderstreaming@3.1.0-exp.9/Runtime/Scripts/Signaling/WebSocketSignaling.cs @@ -24,6 +24,23 @@ namespace Unity.RenderStreaming.Signaling public string participantId; public string Url { get { return m_url; } } + /// + /// 当前客户端是否为Host角色(由服务器在connect响应中分配) + /// + public bool isHost { get; private set; } + + /// + /// Host连接时使用的房间connectionId + /// + private string m_roomConnectionId; + + /// + /// 参与者连接ID到房间connectionId的映射 + /// Key: participantId, Value: roomConnectionId + /// 用于Host向特定Participant发送消息时,将内部connectionId还原为服务器格式 + /// + private Dictionary m_participantToRoom = new Dictionary(); + public WebSocketSignaling(SignalingSettings signalingSettings, SynchronizationContext mainThreadContext) { if (signalingSettings == null) @@ -89,46 +106,97 @@ namespace Unity.RenderStreaming.Signaling public event OnAnswerHandler OnAnswer; #pragma warning restore 0067 public event OnIceCandidateHandler OnIceCandidate; + public event OnParticipantJoinedHandler OnParticipantJoined; + public event OnParticipantLeftHandler OnParticipantLeft; + public event OnCallRequestHandler OnCallRequest; + public event OnMessageHandler OnMessage; + + /// + /// 判断一个connectionId是否为参与者连接ID(而非房间connectionId) + /// + private bool IsParticipantConnectionId(string connectionId) + { + return m_participantToRoom.ContainsKey(connectionId); + } + + /// + /// 获取参与者对应的房间connectionId + /// + private string GetRoomConnectionId(string participantConnectionId) + { + return m_participantToRoom.TryGetValue(participantConnectionId, out var roomId) ? roomId : participantConnectionId; + } public void SendOffer(string connectionId, RTCSessionDescription offer) { DescData data = new DescData(); - data.connectionId = connectionId; + // data.connectionId必须使用房间connectionId(服务器用此查找连接组进行路由) + // 而不是内部participantId(participantId仅通过routedMessage.participantId传递用于目标选择) + data.connectionId = IsParticipantConnectionId(connectionId) ? GetRoomConnectionId(connectionId) : connectionId; data.sdp = offer.sdp; data.dateTime = DateTime.Now; RoutedMessage routedMessage = new RoutedMessage(); - routedMessage.from = connectionId; + // 如果connectionId是参与者ID,使用房间connectionId作为from,并设置目标participantId + if (IsParticipantConnectionId(connectionId)) + { + routedMessage.from = GetRoomConnectionId(connectionId); + routedMessage.participantId = connectionId; + } + else + { + routedMessage.from = connectionId; + routedMessage.participantId = participantId; + } routedMessage.data = data; routedMessage.type = "offer"; - routedMessage.participantId =participantId; WSSend(routedMessage); } public void SendAnswer(string connectionId, RTCSessionDescription answer) { DescData data = new DescData(); - data.connectionId = connectionId; + // data.connectionId必须使用房间connectionId(服务器用此查找连接组进行路由) + data.connectionId = IsParticipantConnectionId(connectionId) ? GetRoomConnectionId(connectionId) : connectionId; data.sdp = answer.sdp; RoutedMessage routedMessage = new RoutedMessage(); - routedMessage.from = connectionId; + // 如果connectionId是参与者ID,使用房间connectionId作为from,并设置目标participantId + if (IsParticipantConnectionId(connectionId)) + { + routedMessage.from = GetRoomConnectionId(connectionId); + routedMessage.participantId = connectionId; + } + else + { + routedMessage.from = connectionId; + routedMessage.participantId = participantId; + } routedMessage.data = data; routedMessage.type = "answer"; - routedMessage.participantId =participantId; WSSend(routedMessage); } public void SendCandidate(string connectionId, RTCIceCandidate candidate) { CandidateData data = new CandidateData(); - data.connectionId = connectionId; + // data.connectionId必须使用房间connectionId(服务器用此查找连接组进行路由) + data.connectionId = IsParticipantConnectionId(connectionId) ? GetRoomConnectionId(connectionId) : connectionId; data.candidate = candidate.Candidate; data.sdpMLineIndex = candidate.SdpMLineIndex.GetValueOrDefault(0); data.sdpMid = candidate.SdpMid; RoutedMessage routedMessage = new RoutedMessage(); - routedMessage.from = connectionId; + // 如果connectionId是参与者ID,使用房间connectionId作为from,并设置目标participantId + if (IsParticipantConnectionId(connectionId)) + { + routedMessage.from = GetRoomConnectionId(connectionId); + routedMessage.participantId = connectionId; + } + else + { + routedMessage.from = connectionId; + } routedMessage.data = data; routedMessage.type = "candidate"; @@ -137,12 +205,16 @@ namespace Unity.RenderStreaming.Signaling public void OpenConnection(string connectionId) { + m_roomConnectionId = connectionId; this.WSSend($"{{\"type\":\"connect\", \"connectionId\":\"{connectionId}\"}}"); } public void CloseConnection(string connectionId) { - this.WSSend($"{{\"type\":\"disconnect\", \"connectionId\":\"{connectionId}\"}}"); + // 如果关闭的是参与者连接,使用房间connectionId发送disconnect + string actualConnectionId = IsParticipantConnectionId(connectionId) ? GetRoomConnectionId(connectionId) : connectionId; + m_participantToRoom.Remove(connectionId); + this.WSSend($"{{\"type\":\"disconnect\", \"connectionId\":\"{actualConnectionId}\"}}"); } private void WSManage() @@ -211,28 +283,51 @@ namespace Unity.RenderStreaming.Signaling if (routedMessage.type == "connect") { msg = JsonUtility.FromJson(content); + isHost = msg.role == "host"; + participantId = msg.participantId; m_mainThreadContext.Post(d => OnCreateConnection?.Invoke(this, msg.connectionId, msg.polite), null); - participantId=msg.participantId; } else if (routedMessage.type == "disconnect") { msg = JsonUtility.FromJson(content); - m_mainThreadContext.Post(d => OnDestroyConnection?.Invoke(this, msg.connectionId), null); + string disconnectConnectionId = msg.connectionId; + // 如果断开的是参与者连接,用participantId查找内部connectionId + if (!string.IsNullOrEmpty(routedMessage.participantId) && isHost) + { + disconnectConnectionId = routedMessage.participantId; + m_participantToRoom.Remove(routedMessage.participantId); + } + m_mainThreadContext.Post(d => OnDestroyConnection?.Invoke(this, disconnectConnectionId), null); } else if (routedMessage.type == "offer") { DescData offer = new DescData(); - offer.connectionId = routedMessage.from; + // Host收到带participantId的offer时,使用participantId作为内部connectionId + // 这样每个participant会创建独立的PeerConnection + if (!string.IsNullOrEmpty(routedMessage.participantId) && isHost) + { + offer.connectionId = routedMessage.participantId; + m_participantToRoom[routedMessage.participantId] = routedMessage.from ?? m_roomConnectionId; + } + else + { + offer.connectionId = routedMessage.from; + } offer.sdp = msg.sdp; offer.polite = msg.polite; + offer.participantId = routedMessage.participantId; m_mainThreadContext.Post(d => OnOffer?.Invoke(this, offer), null); } else if (routedMessage.type == "answer") { DescData answer = new DescData { - connectionId = routedMessage.from, - sdp = msg.sdp + // Host收到带participantId的answer时,使用participantId作为内部connectionId + connectionId = !string.IsNullOrEmpty(routedMessage.participantId) && isHost + ? routedMessage.participantId + : routedMessage.from, + sdp = msg.sdp, + participantId = routedMessage.participantId }; m_mainThreadContext.Post(d => OnAnswer?.Invoke(this, answer), null); } @@ -240,13 +335,68 @@ namespace Unity.RenderStreaming.Signaling { CandidateData candidate = new CandidateData { - connectionId = routedMessage.@from, + // Host收到带participantId的candidate时,使用participantId作为内部connectionId + connectionId = !string.IsNullOrEmpty(routedMessage.participantId) && isHost + ? routedMessage.participantId + : routedMessage.@from, candidate = msg.candidate, sdpMLineIndex = msg.sdpMLineIndex, - sdpMid = msg.sdpMid + sdpMid = msg.sdpMid, + participantId = routedMessage.participantId }; m_mainThreadContext.Post(d => OnIceCandidate?.Invoke(this, candidate), null); } + else if (routedMessage.type == "participant-joined") + { + // Host收到新参与者加入通知 + msg = JsonUtility.FromJson(content); + ParticipantEventData participantData = new ParticipantEventData + { + connectionId = msg.connectionId ?? routedMessage.from, + participantId = msg.participantId ?? routedMessage.participantId + }; + // 记录参与者映射 + if (!string.IsNullOrEmpty(participantData.participantId)) + { + m_participantToRoom[participantData.participantId] = participantData.connectionId; + } + RenderStreaming.Logger.Log($"Signaling: Participant joined - connectionId: {participantData.connectionId}, participantId: {participantData.participantId}"); + m_mainThreadContext.Post(d => OnParticipantJoined?.Invoke(this, participantData), null); + } + else if (routedMessage.type == "participant-left") + { + // Host/Participant收到参与者离开通知 + msg = JsonUtility.FromJson(content); + ParticipantEventData participantData = new ParticipantEventData + { + connectionId = msg.connectionId ?? routedMessage.from, + participantId = msg.participantId ?? routedMessage.participantId + }; + m_participantToRoom.Remove(participantData.participantId); + RenderStreaming.Logger.Log($"Signaling: Participant left - connectionId: {participantData.connectionId}, participantId: {participantData.participantId}"); + m_mainThreadContext.Post(d => OnParticipantLeft?.Invoke(this, participantData), null); + } + else if (routedMessage.type == "call-request") + { + msg = JsonUtility.FromJson(content); + CallRequestData callData = new CallRequestData + { + connectionId = routedMessage.from, + data = msg.data + }; + m_mainThreadContext.Post(d => OnCallRequest?.Invoke(this, callData), null); + } + else if (routedMessage.type == "on-message") + { + msg = JsonUtility.FromJson(content); + OnMessageData messageData = new OnMessageData + { + connectionId = routedMessage.from, + participantId = routedMessage.participantId, + message = msg.message + }; + m_mainThreadContext.Post(d => OnMessage?.Invoke(this, messageData), null); + } else if (routedMessage.type == "error") { msg = JsonUtility.FromJson(content); diff --git a/Packages/com.unity.renderstreaming@3.1.0-exp.9/Runtime/Scripts/SignalingEventData.cs b/Packages/com.unity.renderstreaming@3.1.0-exp.9/Runtime/Scripts/SignalingEventData.cs index 48a4e27..43e6cac 100644 --- a/Packages/com.unity.renderstreaming@3.1.0-exp.9/Runtime/Scripts/SignalingEventData.cs +++ b/Packages/com.unity.renderstreaming@3.1.0-exp.9/Runtime/Scripts/SignalingEventData.cs @@ -28,6 +28,21 @@ namespace Unity.RenderStreaming /// public string sdp { get; set; } + /// + /// 参与者ID + /// + public string participantId { get; set; } + + /// + /// 角色 (host/participant) + /// + public string role { get; set; } + + /// + /// 自定义消息内容 + /// + public string message { get; set; } + /// /// /// diff --git a/Packages/com.unity.renderstreaming@3.1.0-exp.9/Runtime/Scripts/SignalingEventProvider.cs b/Packages/com.unity.renderstreaming@3.1.0-exp.9/Runtime/Scripts/SignalingEventProvider.cs index 6c0b406..8e5ef80 100644 --- a/Packages/com.unity.renderstreaming@3.1.0-exp.9/Runtime/Scripts/SignalingEventProvider.cs +++ b/Packages/com.unity.renderstreaming@3.1.0-exp.9/Runtime/Scripts/SignalingEventProvider.cs @@ -20,6 +20,10 @@ namespace Unity.RenderStreaming handler.onGotAnswer += OnGotAnswer; handler.onAddChannel += OnAddChannel; handler.onAddTransceiver += OnAddReceiver; + handler.onParticipantJoined += OnParticipantJoined; + handler.onParticipantLeft += OnParticipantLeft; + handler.onCallRequest += OnCallRequest; + handler.onMessage += OnMessage; } public bool Subscribe(Component comp) @@ -137,5 +141,46 @@ namespace Unity.RenderStreaming }; ExecuteEventToAllTargets(data, ExecuteSignalingEvents.addReceiverHandler); } + + private void OnParticipantJoined(string connectionId, string participantId) + { + var data = new SignalingEventData(EventSystem.current) + { + connectionId = connectionId, + participantId = participantId + }; + ExecuteEventToAllTargets(data, ExecuteSignalingEvents.participantJoinedHandler); + } + + private void OnParticipantLeft(string connectionId, string participantId) + { + var data = new SignalingEventData(EventSystem.current) + { + connectionId = connectionId, + participantId = participantId + }; + ExecuteEventToAllTargets(data, ExecuteSignalingEvents.participantLeftHandler); + } + + private void OnCallRequest(string connectionId, string callData) + { + var data = new SignalingEventData(EventSystem.current) + { + connectionId = connectionId, + message = callData + }; + ExecuteEventToAllTargets(data, ExecuteSignalingEvents.callRequestHandler); + } + + private void OnMessage(string connectionId, string participantId, string message) + { + var data = new SignalingEventData(EventSystem.current) + { + connectionId = connectionId, + participantId = participantId, + message = message + }; + ExecuteEventToAllTargets(data, ExecuteSignalingEvents.messageHandler); + } } } diff --git a/Packages/com.unity.renderstreaming@3.1.0-exp.9/Runtime/Scripts/SignalingManagerInternal.cs b/Packages/com.unity.renderstreaming@3.1.0-exp.9/Runtime/Scripts/SignalingManagerInternal.cs index db0fae9..fab5062 100644 --- a/Packages/com.unity.renderstreaming@3.1.0-exp.9/Runtime/Scripts/SignalingManagerInternal.cs +++ b/Packages/com.unity.renderstreaming@3.1.0-exp.9/Runtime/Scripts/SignalingManagerInternal.cs @@ -90,6 +90,26 @@ namespace Unity.RenderStreaming /// public event Action onAddChannel; + /// + /// 参与者加入事件 (connectionId, participantId) + /// + public event Action onParticipantJoined; + + /// + /// 参与者离开事件 (connectionId, participantId) + /// + public event Action onParticipantLeft; + + /// + /// 呼叫请求事件 (connectionId, data) + /// + public event Action onCallRequest; + + /// + /// 自定义消息事件 (connectionId, participantId, message) + /// + public event Action onMessage; + private bool _disposed; private readonly ISignaling _signaling; private RTCConfiguration _config; @@ -122,6 +142,10 @@ namespace Unity.RenderStreaming _signaling.OnOffer += OnOffer; _signaling.OnAnswer += OnAnswer; _signaling.OnIceCandidate += OnIceCandidate; + _signaling.OnParticipantJoined += OnParticipantJoinedHandler; + _signaling.OnParticipantLeft += OnParticipantLeftHandler; + _signaling.OnCallRequest += OnCallRequestHandler; + _signaling.OnMessage += OnMessageHandler; _signaling.Start(); _startCoroutine(WebRTC.WebRTC.Update()); } @@ -153,6 +177,10 @@ namespace Unity.RenderStreaming _signaling.OnOffer -= OnOffer; _signaling.OnAnswer -= OnAnswer; _signaling.OnIceCandidate -= OnIceCandidate; + _signaling.OnParticipantJoined -= OnParticipantJoinedHandler; + _signaling.OnParticipantLeft -= OnParticipantLeftHandler; + _signaling.OnCallRequest -= OnCallRequestHandler; + _signaling.OnMessage -= OnMessageHandler; foreach (var pair in _mapConnectionIdAndPeer) pair.Value.Dispose(); @@ -428,5 +456,30 @@ namespace Unity.RenderStreaming RTCSessionDescription description = new RTCSessionDescription { type = RTCSdpType.Offer, sdp = e.sdp }; _startCoroutine(pc.OnGotDescription(description, () => onGotOffer?.Invoke(connectionId, e.sdp))); } + + void OnParticipantJoinedHandler(ISignaling signaling, ParticipantEventData e) + { + onParticipantJoined?.Invoke(e.connectionId, e.participantId); + } + + void OnParticipantLeftHandler(ISignaling signaling, ParticipantEventData e) + { + // 参与者离开时,销毁对应的PeerConnection + if (_mapConnectionIdAndPeer.ContainsKey(e.participantId)) + { + DestroyConnection(e.participantId); + } + onParticipantLeft?.Invoke(e.connectionId, e.participantId); + } + + void OnCallRequestHandler(ISignaling signaling, CallRequestData e) + { + onCallRequest?.Invoke(e.connectionId, e.data); + } + + void OnMessageHandler(ISignaling signaling, OnMessageData e) + { + onMessage?.Invoke(e.connectionId, e.participantId, e.message); + } } } diff --git a/Packages/com.unity.renderstreaming@3.1.0-exp.9/Tests/Runtime/MockLogger.cs b/Packages/com.unity.renderstreaming@3.1.0-exp.9/Tests/Runtime/MockLogger.cs index 20246aa..a78cc62 100644 --- a/Packages/com.unity.renderstreaming@3.1.0-exp.9/Tests/Runtime/MockLogger.cs +++ b/Packages/com.unity.renderstreaming@3.1.0-exp.9/Tests/Runtime/MockLogger.cs @@ -8,86 +8,71 @@ namespace Unity.RenderStreaming.RuntimeTest { public void LogFormat(LogType logType, Object context, string format, params object[] args) { - throw new NotImplementedException(); } public void LogException(Exception exception, Object context) { - throw new NotImplementedException(); } public bool IsLogTypeAllowed(LogType logType) { - throw new NotImplementedException(); + return false; } public void Log(LogType logType, object message) { - throw new NotImplementedException(); } public void Log(LogType logType, object message, Object context) { - throw new NotImplementedException(); } public void Log(LogType logType, string tag, object message) { - throw new NotImplementedException(); } public void Log(LogType logType, string tag, object message, Object context) { - throw new NotImplementedException(); } public void Log(object message) { - throw new NotImplementedException(); } public void Log(string tag, object message) { - throw new NotImplementedException(); } public void Log(string tag, object message, Object context) { - throw new NotImplementedException(); } public void LogWarning(string tag, object message) { - throw new NotImplementedException(); } public void LogWarning(string tag, object message, Object context) { - throw new NotImplementedException(); } public void LogError(string tag, object message) { - throw new NotImplementedException(); } public void LogError(string tag, object message, Object context) { - throw new NotImplementedException(); } public void LogFormat(LogType logType, string format, params object[] args) { - throw new NotImplementedException(); } public void LogException(Exception exception) { - throw new NotImplementedException(); } public ILogHandler logHandler { get; set; } - public bool logEnabled { get; set; } - public LogType filterLogType { get; set; } + public bool logEnabled { get; set; } = true; + public LogType filterLogType { get; set; } = LogType.Log; } } diff --git a/Packages/com.unity.renderstreaming@3.1.0-exp.9/Tests/Runtime/Signaling/MockSignaling.cs b/Packages/com.unity.renderstreaming@3.1.0-exp.9/Tests/Runtime/Signaling/MockSignaling.cs index f5355a5..9497578 100644 --- a/Packages/com.unity.renderstreaming@3.1.0-exp.9/Tests/Runtime/Signaling/MockSignaling.cs +++ b/Packages/com.unity.renderstreaming@3.1.0-exp.9/Tests/Runtime/Signaling/MockSignaling.cs @@ -258,8 +258,6 @@ namespace Unity.RenderStreaming.RuntimeTest.Signaling public string Url { get { return string.Empty; } } - public float Interval { get { return 0.1f; } } - static MockSignaling() { manager = new MockPublicSignalingManager(); @@ -285,6 +283,12 @@ namespace Unity.RenderStreaming.RuntimeTest.Signaling public event OnOfferHandler OnOffer; public event OnAnswerHandler OnAnswer; public event OnIceCandidateHandler OnIceCandidate; +#pragma warning disable 0067 + public event OnParticipantJoinedHandler OnParticipantJoined; + public event OnParticipantLeftHandler OnParticipantLeft; + public event OnCallRequestHandler OnCallRequest; + public event OnMessageHandler OnMessage; +#pragma warning restore 0067 public void OpenConnection(string connectionId) { diff --git a/Packages/com.unity.renderstreaming@3.1.0-exp.9/Tests/Runtime/SignalingEventProviderTest.cs b/Packages/com.unity.renderstreaming@3.1.0-exp.9/Tests/Runtime/SignalingEventProviderTest.cs index 6d6bebd..ae1e64b 100644 --- a/Packages/com.unity.renderstreaming@3.1.0-exp.9/Tests/Runtime/SignalingEventProviderTest.cs +++ b/Packages/com.unity.renderstreaming@3.1.0-exp.9/Tests/Runtime/SignalingEventProviderTest.cs @@ -119,6 +119,10 @@ namespace Unity.RenderStreaming.RuntimeTest public event Action onDisconnect; public event Action onAddTransceiver; public event Action onAddChannel; + public event Action onParticipantJoined; + public event Action onParticipantLeft; + public event Action onCallRequest; + public event Action onMessage; public void RaiseOnStart() { diff --git a/WebApp/.editorconfig b/WebApp/.editorconfig deleted file mode 100644 index a27bc33..0000000 --- a/WebApp/.editorconfig +++ /dev/null @@ -1,20 +0,0 @@ -# References -# https://github.com/MicrosoftDocs/visualstudio-docs/blob/master/docs/ide/editorconfig-code-style-settings-reference.md#example-editorconfig-file - -############################### -# Core EditorConfig Options # -############################### - -root = true - -# All files -[*] -indent_style = space - -# Code files -[*.{ts,js,json,html}] -end_of_line = lf -indent_size = 2 -insert_final_newline = true -charset = utf-8 -trim_trailing_whitespace = true \ No newline at end of file diff --git a/WebApp/.eslintrc.cjs b/WebApp/.eslintrc.cjs deleted file mode 100644 index 3c5e79b..0000000 --- a/WebApp/.eslintrc.cjs +++ /dev/null @@ -1,24 +0,0 @@ -module.exports = { - env: { - node: true, - jest: true, - }, - extends: [ - "eslint:recommended", - "plugin:@typescript-eslint/eslint-recommended", - "plugin:@typescript-eslint/recommended", - "plugin:jest/recommended" - ], - parser: "@typescript-eslint/parser", - parserOptions: { - sourceType: "module", - project: "./tsconfig.lint.json", - }, - plugins: ["@typescript-eslint", "jest"], - rules: { - "@typescript-eslint/no-var-requires": "off", - "@typescript-eslint/no-explicit-any": "off", - "@typescript-eslint/semi": ["error"], - "@typescript-eslint/no-extra-semi": ["error"], - } -}; diff --git a/WebApp/client/.eslintrc.json b/WebApp/client/.eslintrc.json deleted file mode 100644 index 6d31058..0000000 --- a/WebApp/client/.eslintrc.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "root": true, - "extends": [ - "eslint:recommended", - "plugin:jest/recommended" - ], - "plugins": [ - "jest" - ], - "parserOptions": { - "sourceType": "module", - "ecmaVersion": "latest" - }, - "env": { - "browser": true, - "es6": true , - "jest": true - }, - "rules": { - "semi": "error", - "no-extra-semi": "error" - } -} \ No newline at end of file diff --git a/WebApp/client/jest.config.js b/WebApp/client/jest.config.js deleted file mode 100644 index 7a52a86..0000000 --- a/WebApp/client/jest.config.js +++ /dev/null @@ -1,195 +0,0 @@ -/* - * For a detailed explanation regarding each configuration property, visit: - * https://jestjs.io/docs/configuration - */ -export default { - // All imported modules in your tests should be mocked automatically - // automock: false, - - // Stop running tests after `n` failures - // bail: 0, - - // The directory where Jest should store its cached dependency information - // cacheDirectory: "/private/var/folders/wt/swsbjj0x061bdb0y4dqc0g4c0000gn/T/jest_dx", - - // Automatically clear mock calls and instances between every test - // clearMocks: false, - - // Indicates whether the coverage information should be collected while executing the test - collectCoverage: true, - - // An array of glob patterns indicating a set of files for which coverage information should be collected - // collectCoverageFrom: undefined, - - // The directory where Jest should output its coverage files - coverageDirectory: "coverage", - - // An array of regexp pattern strings used to skip coverage collection - // coveragePathIgnorePatterns: [ - // "/node_modules/" - // ], - - // Indicates which provider should be used to instrument code for coverage - coverageProvider: "v8", - - // A list of reporter names that Jest uses when writing coverage reports - // coverageReporters: [ - // "json", - // "text", - // "lcov", - // "clover" - // ], - - // An object that configures minimum threshold enforcement for coverage results - // coverageThreshold: undefined, - - // A path to a custom dependency extractor - // dependencyExtractor: undefined, - - // Make calling deprecated APIs throw helpful error messages - // errorOnDeprecated: false, - - // Force coverage collection from ignored files using an array of glob patterns - // forceCoverageMatch: [], - - // A path to a module which exports an async function that is triggered once before all test suites - // globalSetup: undefined, - - // A path to a module which exports an async function that is triggered once after all test suites - // globalTeardown: undefined, - - // A set of global variables that need to be available in all test environments - // globals: {}, - - // The maximum amount of workers used to run your tests. Can be specified as % or a number. E.g. maxWorkers: 10% will use 10% of your CPU amount + 1 as the maximum worker number. maxWorkers: 2 will use a maximum of 2 workers. - // maxWorkers: "50%", - - // An array of directory names to be searched recursively up from the requiring module's location - // moduleDirectories: [ - // "node_modules" - // ], - - // An array of file extensions your modules use - moduleFileExtensions: [ - "js", - "jsx", - "ts", - "tsx", - "json", - "node" - ], - - // A map from regular expressions to module names or to arrays of module names that allow to stub out resources with a single module - // moduleNameMapper: {}, - - // An array of regexp pattern strings, matched against all module paths before considered 'visible' to the module loader - // modulePathIgnorePatterns: [], - - // Activates notifications for test results - // notify: false, - - // An enum that specifies notification mode. Requires { notify: true } - // notifyMode: "failure-change", - - // A preset that is used as a base for Jest's configuration - // preset: undefined, - - // Run tests from one or more projects - // projects: undefined, - - // Use this configuration option to add custom reporters to Jest - // reporters: undefined, - - // Automatically reset mock state between every test - // resetMocks: false, - - // Reset the module registry before running each individual test - // resetModules: false, - - // A path to a custom resolver - // resolver: undefined, - - // Automatically restore mock state between every test - // restoreMocks: false, - - // The root directory that Jest should scan for tests and modules within - // rootDir: undefined, - - // A list of paths to directories that Jest should use to search for files in - // roots: [ - // "" - // ], - - // Allows you to use a custom runner instead of Jest's default test runner - // runner: "jest-runner", - - // The paths to modules that run some code to configure or set up the testing environment before each test - // setupFiles: [], - - // A list of paths to modules that run some code to configure or set up the testing framework before each test - setupFilesAfterEnv: ['./jest.setup.js'], - - // The number of seconds after which a test is considered as slow and reported as such in the results. - // slowTestThreshold: 5, - - // A list of paths to snapshot serializer modules Jest should use for snapshot testing - // snapshotSerializers: [], - - // The test environment that will be used for testing - testEnvironment: "jest-environment-jsdom", - - // Options that will be passed to the testEnvironment - testEnvironmentOptions: { - url: "http://localhost:8081" - }, - - // Adds a location field to test results - // testLocationInResults: false, - - // The glob patterns Jest uses to detect test files - testMatch: [ - "**/__tests__/**/*.[jt]s?(x)", - "**/?(*.)+(spec|test).[tj]s?(x)" - ], - - // An array of regexp pattern strings that are matched against all test paths, matched tests are skipped - // testPathIgnorePatterns: [ - // "/node_modules/" - // ], - - // The regexp pattern or array of patterns that Jest uses to detect test files - // testRegex: [], - - // This option allows the use of a custom results processor - // testResultsProcessor: undefined, - - // This option allows use of a custom test runner - // testRunner: "jest-circus/runner", - - // This option set timeout each test - testTimeout: 5000, - - // Setting this value to "fake" allows the use of fake timers for functions such as "setTimeout" - // timers: "real", - - // A map from regular expressions to paths to transformers - // transform: undefined - - // An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation - // transformIgnorePatterns: [ - // "/node_modules/", - // "\\.pnp\\.[^\\/]+$" - // ], - - // An array of regexp pattern strings that are matched against all modules before the module loader will automatically return a mock for them - // unmockedModulePathPatterns: undefined, - - // Indicates whether each individual test should be reported during the run - // verbose: undefined, - - // An array of regexp patterns that are matched against all source file paths before re-running tests in watch mode - // watchPathIgnorePatterns: [], - - // Whether to use watchman for file crawling - // watchman: true, -}; diff --git a/WebApp/client/jest.setup.js b/WebApp/client/jest.setup.js deleted file mode 100644 index 8101fdb..0000000 --- a/WebApp/client/jest.setup.js +++ /dev/null @@ -1,35 +0,0 @@ -/* eslint-disable no-undef */ -import fetch from 'node-fetch'; -import { TextEncoder, TextDecoder } from 'util'; -import { PeerConnectionMock, SessionDescriptionMock, IceCandidateMock } from './test/peerconnectionmock'; -import ResizeObserverMock from './test/resizeobservermock'; - -// note: If set testEnvironment `jest-environment-jsdom`, below classes are not defined. - -if (!window.fetch) { - window.fetch = fetch; -} - -if (!window.TextEncoder) { - window.TextEncoder = TextEncoder; -} - -if (!window.TextDecoder) { - window.TextDecoder = TextDecoder; -} - -if (!window.RTCPeerConnection) { - window.RTCPeerConnection = PeerConnectionMock; -} - -if (!window.RTCSessionDescription) { - window.RTCSessionDescription = SessionDescriptionMock; -} - -if (!window.RTCIceCandidate) { - window.RTCIceCandidate = IceCandidateMock; -} - -if (!window.ResizeObserver) { - window.ResizeObserver = ResizeObserverMock; -} \ No newline at end of file diff --git a/WebApp/client/package-lock.json b/WebApp/client/package-lock.json deleted file mode 100644 index d9d9444..0000000 --- a/WebApp/client/package-lock.json +++ /dev/null @@ -1,9885 +0,0 @@ -{ - "name": "webclient", - "version": "3.1.0", - "lockfileVersion": 2, - "requires": true, - "packages": { - "": { - "name": "webclient", - "version": "3.1.0", - "devDependencies": { - "eslint": "^8.23.0", - "eslint-plugin-jest": "^27.0.1", - "jest": "^29.0.2", - "jest-dev-server": "^6.1.1", - "jest-environment-jsdom": "^29.0.2", - "node-fetch": "^3.2.10" - } - }, - "node_modules/@ampproject/remapping": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", - "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", - "dev": true, - "dependencies": { - "@jridgewell/gen-mapping": "^0.1.0", - "@jridgewell/trace-mapping": "^0.3.9" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/code-frame": { - "version": "7.22.13", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", - "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", - "dev": true, - "dependencies": { - "@babel/highlight": "^7.22.13", - "chalk": "^2.4.2" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/code-frame/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/code-frame/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/code-frame/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/@babel/code-frame/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, - "node_modules/@babel/code-frame/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/@babel/code-frame/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/code-frame/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/compat-data": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.19.0.tgz", - "integrity": "sha512-y5rqgTTPTmaF5e2nVhOxw+Ur9HDJLsWb6U/KpgUzRZEdPfE6VOubXBKLdbcUTijzRptednSBDQbYZBOSqJxpJw==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/core": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.19.0.tgz", - "integrity": "sha512-reM4+U7B9ss148rh2n1Qs9ASS+w94irYXga7c2jaQv9RVzpS7Mv1a9rnYYwuDa45G+DkORt9g6An2k/V4d9LbQ==", - "dev": true, - "dependencies": { - "@ampproject/remapping": "^2.1.0", - "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.19.0", - "@babel/helper-compilation-targets": "^7.19.0", - "@babel/helper-module-transforms": "^7.19.0", - "@babel/helpers": "^7.19.0", - "@babel/parser": "^7.19.0", - "@babel/template": "^7.18.10", - "@babel/traverse": "^7.19.0", - "@babel/types": "^7.19.0", - "convert-source-map": "^1.7.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.1", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" - } - }, - "node_modules/@babel/core/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@babel/generator": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz", - "integrity": "sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==", - "dev": true, - "dependencies": { - "@babel/types": "^7.23.0", - "@jridgewell/gen-mapping": "^0.3.2", - "@jridgewell/trace-mapping": "^0.3.17", - "jsesc": "^2.5.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/generator/node_modules/@jridgewell/gen-mapping": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", - "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", - "dev": true, - "dependencies": { - "@jridgewell/set-array": "^1.0.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/helper-compilation-targets": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.19.0.tgz", - "integrity": "sha512-Ai5bNWXIvwDvWM7njqsG3feMlL9hCVQsPYXodsZyLwshYkZVJt59Gftau4VrE8S9IT9asd2uSP1hG6wCNw+sXA==", - "dev": true, - "dependencies": { - "@babel/compat-data": "^7.19.0", - "@babel/helper-validator-option": "^7.18.6", - "browserslist": "^4.20.2", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-compilation-targets/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@babel/helper-environment-visitor": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", - "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-function-name": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", - "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", - "dev": true, - "dependencies": { - "@babel/template": "^7.22.15", - "@babel/types": "^7.23.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-hoist-variables": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", - "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", - "dev": true, - "dependencies": { - "@babel/types": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-imports": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz", - "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==", - "dev": true, - "dependencies": { - "@babel/types": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-transforms": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.19.0.tgz", - "integrity": "sha512-3HBZ377Fe14RbLIA+ac3sY4PTgpxHVkFrESaWhoI5PuyXPBBX8+C34qblV9G89ZtycGJCmCI/Ut+VUDK4bltNQ==", - "dev": true, - "dependencies": { - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-module-imports": "^7.18.6", - "@babel/helper-simple-access": "^7.18.6", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/helper-validator-identifier": "^7.18.6", - "@babel/template": "^7.18.10", - "@babel/traverse": "^7.19.0", - "@babel/types": "^7.19.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-plugin-utils": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.19.0.tgz", - "integrity": "sha512-40Ryx7I8mT+0gaNxm8JGTZFUITNqdLAgdg0hXzeVZxVD6nFsdhQvip6v8dqkRHzsz1VFpFAaOCHNn0vKBL7Czw==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-simple-access": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.18.6.tgz", - "integrity": "sha512-iNpIgTgyAvDQpDj76POqg+YEt8fPxx3yaNBg3S30dxNKm2SWfYhD0TGrK/Eu9wHpUW63VQU894TsTg+GLbUa1g==", - "dev": true, - "dependencies": { - "@babel/types": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-split-export-declaration": { - "version": "7.22.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", - "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", - "dev": true, - "dependencies": { - "@babel/types": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-string-parser": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz", - "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", - "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-option": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz", - "integrity": "sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helpers": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.19.0.tgz", - "integrity": "sha512-DRBCKGwIEdqY3+rPJgG/dKfQy9+08rHIAJx8q2p+HSWP87s2HCrQmaAMMyMll2kIXKCW0cO1RdQskx15Xakftg==", - "dev": true, - "dependencies": { - "@babel/template": "^7.18.10", - "@babel/traverse": "^7.19.0", - "@babel/types": "^7.19.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz", - "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==", - "dev": true, - "dependencies": { - "@babel/helper-validator-identifier": "^7.22.20", - "chalk": "^2.4.2", - "js-tokens": "^4.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/@babel/highlight/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, - "node_modules/@babel/highlight/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/@babel/highlight/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/parser": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz", - "integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==", - "dev": true, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/plugin-syntax-async-generators": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", - "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-bigint": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", - "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-class-properties": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", - "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.12.13" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-import-meta": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", - "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-json-strings": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", - "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-jsx": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.18.6.tgz", - "integrity": "sha512-6mmljtAedFGTWu2p/8WIORGwy+61PLgOMPOdazc7YoJ9ZCWUyFy3A6CpPkRKLKD1ToAesxX8KGEViAiLo9N+7Q==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-logical-assignment-operators": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", - "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", - "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-numeric-separator": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", - "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-object-rest-spread": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", - "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-optional-catch-binding": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", - "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-optional-chaining": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", - "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-top-level-await": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", - "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-typescript": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.18.6.tgz", - "integrity": "sha512-mAWAuq4rvOepWCBid55JuRNvpTNf2UGVgoz4JV0fXEKolsVZDzsa4NqCef758WZJj/GDu0gVGItjKFiClTAmZA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/template": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", - "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.22.13", - "@babel/parser": "^7.22.15", - "@babel/types": "^7.22.15" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse": { - "version": "7.23.2", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz", - "integrity": "sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.22.13", - "@babel/generator": "^7.23.0", - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-function-name": "^7.23.0", - "@babel/helper-hoist-variables": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/parser": "^7.23.0", - "@babel/types": "^7.23.0", - "debug": "^4.1.0", - "globals": "^11.1.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse/node_modules/globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/types": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz", - "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==", - "dev": true, - "dependencies": { - "@babel/helper-string-parser": "^7.22.5", - "@babel/helper-validator-identifier": "^7.22.20", - "to-fast-properties": "^2.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@bcoe/v8-coverage": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", - "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", - "dev": true - }, - "node_modules/@eslint/eslintrc": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.1.tgz", - "integrity": "sha512-OhSY22oQQdw3zgPOOwdoj01l/Dzl1Z+xyUP33tkSN+aqyEhymJCcPHyXt+ylW8FSe0TfRC2VG+ROQOapD0aZSQ==", - "dev": true, - "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.4.0", - "globals": "^13.15.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@hapi/hoek": { - "version": "9.3.0", - "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz", - "integrity": "sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==", - "dev": true - }, - "node_modules/@hapi/topo": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-5.1.0.tgz", - "integrity": "sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==", - "dev": true, - "dependencies": { - "@hapi/hoek": "^9.0.0" - } - }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.10.4", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.10.4.tgz", - "integrity": "sha512-mXAIHxZT3Vcpg83opl1wGlVZ9xydbfZO3r5YfRSH6Gpp2J/PfdBP0wbDa2sO6/qRbcalpoevVyW6A/fI6LfeMw==", - "dev": true, - "dependencies": { - "@humanwhocodes/object-schema": "^1.2.1", - "debug": "^4.1.1", - "minimatch": "^3.0.4" - }, - "engines": { - "node": ">=10.10.0" - } - }, - "node_modules/@humanwhocodes/gitignore-to-minimatch": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@humanwhocodes/gitignore-to-minimatch/-/gitignore-to-minimatch-1.0.2.tgz", - "integrity": "sha512-rSqmMJDdLFUsyxR6FMtD00nfQKKLFb1kv+qBbOVKqErvloEIJLo5bDTJTQNTYgeyp78JsA7u/NPi5jT1GR/MuA==", - "dev": true, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "dev": true, - "engines": { - "node": ">=12.22" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@humanwhocodes/object-schema": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", - "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", - "dev": true - }, - "node_modules/@istanbuljs/load-nyc-config": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", - "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", - "dev": true, - "dependencies": { - "camelcase": "^5.3.1", - "find-up": "^4.1.0", - "get-package-type": "^0.1.0", - "js-yaml": "^3.13.1", - "resolve-from": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "dependencies": { - "sprintf-js": "~1.0.2" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "dev": true, - "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/schema": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", - "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/console": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.0.2.tgz", - "integrity": "sha512-Fv02ijyhF4D/Wb3DvZO3iBJQz5DnzpJEIDBDbvje8Em099N889tNMUnBw7SalmSuOI+NflNG40RA1iK71kImPw==", - "dev": true, - "dependencies": { - "@jest/types": "^29.0.2", - "@types/node": "*", - "chalk": "^4.0.0", - "jest-message-util": "^29.0.2", - "jest-util": "^29.0.2", - "slash": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/core": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.0.2.tgz", - "integrity": "sha512-imP5M6cdpHEOkmcuFYZuM5cTG1DAF7ZlVNCq1+F7kbqme2Jcl+Kh4M78hihM76DJHNkurbv4UVOnejGxBKEmww==", - "dev": true, - "dependencies": { - "@jest/console": "^29.0.2", - "@jest/reporters": "^29.0.2", - "@jest/test-result": "^29.0.2", - "@jest/transform": "^29.0.2", - "@jest/types": "^29.0.2", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.9", - "jest-changed-files": "^29.0.0", - "jest-config": "^29.0.2", - "jest-haste-map": "^29.0.2", - "jest-message-util": "^29.0.2", - "jest-regex-util": "^29.0.0", - "jest-resolve": "^29.0.2", - "jest-resolve-dependencies": "^29.0.2", - "jest-runner": "^29.0.2", - "jest-runtime": "^29.0.2", - "jest-snapshot": "^29.0.2", - "jest-util": "^29.0.2", - "jest-validate": "^29.0.2", - "jest-watcher": "^29.0.2", - "micromatch": "^4.0.4", - "pretty-format": "^29.0.2", - "slash": "^3.0.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "node_modules/@jest/environment": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.0.2.tgz", - "integrity": "sha512-Yf+EYaLOrVCgts/aTS5nGznU4prZUPa5k9S63Yct8YSOKj2jkdS17hHSUKhk5jxDFMyCy1PXknypDw7vfgc/mA==", - "dev": true, - "dependencies": { - "@jest/fake-timers": "^29.0.2", - "@jest/types": "^29.0.2", - "@types/node": "*", - "jest-mock": "^29.0.2" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/expect": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.0.2.tgz", - "integrity": "sha512-y/3geZ92p2/zovBm/F+ZjXUJ3thvT9IRzD6igqaWskFE2aR0idD+N/p5Lj/ZautEox/9RwEc6nqergebeh72uQ==", - "dev": true, - "dependencies": { - "expect": "^29.0.2", - "jest-snapshot": "^29.0.2" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/expect-utils": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.0.2.tgz", - "integrity": "sha512-+wcQF9khXKvAEi8VwROnCWWmHfsJYCZAs5dmuMlJBKk57S6ZN2/FQMIlo01F29fJyT8kV/xblE7g3vkIdTLOjw==", - "dev": true, - "dependencies": { - "jest-get-type": "^29.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/fake-timers": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.0.2.tgz", - "integrity": "sha512-2JhQeWU28fvmM5r33lxg6BxxkTKaVXs6KMaJ6eXSM8ml/MaWkt2BvbIO8G9KWAJFMdBXWbn+2h9OK1/s5urKZA==", - "dev": true, - "dependencies": { - "@jest/types": "^29.0.2", - "@sinonjs/fake-timers": "^9.1.2", - "@types/node": "*", - "jest-message-util": "^29.0.2", - "jest-mock": "^29.0.2", - "jest-util": "^29.0.2" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/globals": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.0.2.tgz", - "integrity": "sha512-4hcooSNJCVXuTu07/VJwCWW6HTnjLtQdqlcGisK6JST7z2ixa8emw4SkYsOk7j36WRc2ZUEydlUePnOIOTCNXg==", - "dev": true, - "dependencies": { - "@jest/environment": "^29.0.2", - "@jest/expect": "^29.0.2", - "@jest/types": "^29.0.2", - "jest-mock": "^29.0.2" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/reporters": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.0.2.tgz", - "integrity": "sha512-Kr41qejRQHHkCgWHC9YwSe7D5xivqP4XML+PvgwsnRFaykKdNflDUb4+xLXySOU+O/bPkVdFpGzUpVNSJChCrw==", - "dev": true, - "dependencies": { - "@bcoe/v8-coverage": "^0.2.3", - "@jest/console": "^29.0.2", - "@jest/test-result": "^29.0.2", - "@jest/transform": "^29.0.2", - "@jest/types": "^29.0.2", - "@jridgewell/trace-mapping": "^0.3.15", - "@types/node": "*", - "chalk": "^4.0.0", - "collect-v8-coverage": "^1.0.0", - "exit": "^0.1.2", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "istanbul-lib-coverage": "^3.0.0", - "istanbul-lib-instrument": "^5.1.0", - "istanbul-lib-report": "^3.0.0", - "istanbul-lib-source-maps": "^4.0.0", - "istanbul-reports": "^3.1.3", - "jest-message-util": "^29.0.2", - "jest-util": "^29.0.2", - "jest-worker": "^29.0.2", - "slash": "^3.0.0", - "string-length": "^4.0.1", - "strip-ansi": "^6.0.0", - "terminal-link": "^2.0.0", - "v8-to-istanbul": "^9.0.1" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "node_modules/@jest/schemas": { - "version": "29.0.0", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.0.0.tgz", - "integrity": "sha512-3Ab5HgYIIAnS0HjqJHQYZS+zXc4tUmTmBH3z83ajI6afXp8X3ZtdLX+nXx+I7LNkJD7uN9LAVhgnjDgZa2z0kA==", - "dev": true, - "dependencies": { - "@sinclair/typebox": "^0.24.1" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/source-map": { - "version": "29.0.0", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.0.0.tgz", - "integrity": "sha512-nOr+0EM8GiHf34mq2GcJyz/gYFyLQ2INDhAylrZJ9mMWoW21mLBfZa0BUVPPMxVYrLjeiRe2Z7kWXOGnS0TFhQ==", - "dev": true, - "dependencies": { - "@jridgewell/trace-mapping": "^0.3.15", - "callsites": "^3.0.0", - "graceful-fs": "^4.2.9" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/test-result": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.0.2.tgz", - "integrity": "sha512-b5rDc0lLL6Kx73LyCx6370k9uZ8o5UKdCpMS6Za3ke7H9y8PtAU305y6TeghpBmf2In8p/qqi3GpftgzijSsNw==", - "dev": true, - "dependencies": { - "@jest/console": "^29.0.2", - "@jest/types": "^29.0.2", - "@types/istanbul-lib-coverage": "^2.0.0", - "collect-v8-coverage": "^1.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/test-sequencer": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.0.2.tgz", - "integrity": "sha512-fsyZqHBlXNMv5ZqjQwCuYa2pskXCO0DVxh5aaVCuAtwzHuYEGrhordyEncBLQNuCGQSYgElrEEmS+7wwFnnMKw==", - "dev": true, - "dependencies": { - "@jest/test-result": "^29.0.2", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.0.2", - "slash": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/transform": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.0.2.tgz", - "integrity": "sha512-lajVQx2AnsR+Pa17q2zR7eikz2PkPs1+g/qPbZkqQATeS/s6eT55H+yHcsLfuI/0YQ/4VSBepSu3bOX+44q0aA==", - "dev": true, - "dependencies": { - "@babel/core": "^7.11.6", - "@jest/types": "^29.0.2", - "@jridgewell/trace-mapping": "^0.3.15", - "babel-plugin-istanbul": "^6.1.1", - "chalk": "^4.0.0", - "convert-source-map": "^1.4.0", - "fast-json-stable-stringify": "^2.1.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.0.2", - "jest-regex-util": "^29.0.0", - "jest-util": "^29.0.2", - "micromatch": "^4.0.4", - "pirates": "^4.0.4", - "slash": "^3.0.0", - "write-file-atomic": "^4.0.1" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/types": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.0.2.tgz", - "integrity": "sha512-5WNMesBLmlkt1+fVkoCjHa0X3i3q8zc4QLTDkdHgCa2gyPZc7rdlZBWgVLqwS1860ZW5xJuCDwAzqbGaXIr/ew==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.0.0", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", - "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==", - "dev": true, - "dependencies": { - "@jridgewell/set-array": "^1.0.0", - "@jridgewell/sourcemap-codec": "^1.4.10" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", - "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", - "dev": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/set-array": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", - "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", - "dev": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.14", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", - "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", - "dev": true - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.20", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz", - "integrity": "sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==", - "dev": true, - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@sideway/address": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.4.tgz", - "integrity": "sha512-7vwq+rOHVWjyXxVlR76Agnvhy8I9rpzjosTESvmhNeXOXdZZB15Fl+TI9x1SiHZH5Jv2wTGduSxFDIaq0m3DUw==", - "dev": true, - "dependencies": { - "@hapi/hoek": "^9.0.0" - } - }, - "node_modules/@sideway/formula": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.1.tgz", - "integrity": "sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==", - "dev": true - }, - "node_modules/@sideway/pinpoint": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@sideway/pinpoint/-/pinpoint-2.0.0.tgz", - "integrity": "sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==", - "dev": true - }, - "node_modules/@sinclair/typebox": { - "version": "0.24.35", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.35.tgz", - "integrity": "sha512-iN6ehuDndiTiDz2F+Orv/+oHJR+PrGv+38oghCddpsW4YEZl5qyLsWxSwYUWrKEOfjpGtXDFW6scJtjpzSLeSw==", - "dev": true - }, - "node_modules/@sinonjs/commons": { - "version": "1.8.3", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz", - "integrity": "sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ==", - "dev": true, - "dependencies": { - "type-detect": "4.0.8" - } - }, - "node_modules/@sinonjs/fake-timers": { - "version": "9.1.2", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-9.1.2.tgz", - "integrity": "sha512-BPS4ynJW/o92PUR4wgriz2Ud5gpST5vz6GQfMixEDK0Z8ZCUv2M7SkBLykH56T++Xs+8ln9zTGbOvNGIe02/jw==", - "dev": true, - "dependencies": { - "@sinonjs/commons": "^1.7.0" - } - }, - "node_modules/@tootallnate/once": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", - "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", - "dev": true, - "engines": { - "node": ">= 10" - } - }, - "node_modules/@types/babel__core": { - "version": "7.1.19", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.19.tgz", - "integrity": "sha512-WEOTgRsbYkvA/KCsDwVEGkd7WAr1e3g31VHQ8zy5gul/V1qKullU/BU5I68X5v7V3GnB9eotmom4v5a5gjxorw==", - "dev": true, - "dependencies": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0", - "@types/babel__generator": "*", - "@types/babel__template": "*", - "@types/babel__traverse": "*" - } - }, - "node_modules/@types/babel__generator": { - "version": "7.6.4", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.4.tgz", - "integrity": "sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==", - "dev": true, - "dependencies": { - "@babel/types": "^7.0.0" - } - }, - "node_modules/@types/babel__template": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz", - "integrity": "sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==", - "dev": true, - "dependencies": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0" - } - }, - "node_modules/@types/babel__traverse": { - "version": "7.18.1", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.18.1.tgz", - "integrity": "sha512-FSdLaZh2UxaMuLp9lixWaHq/golWTRWOnRsAXzDTDSDOQLuZb1nsdCt6pJSPWSEQt2eFZ2YVk3oYhn+1kLMeMA==", - "dev": true, - "dependencies": { - "@babel/types": "^7.3.0" - } - }, - "node_modules/@types/graceful-fs": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz", - "integrity": "sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/istanbul-lib-coverage": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", - "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==", - "dev": true - }, - "node_modules/@types/istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-coverage": "*" - } - }, - "node_modules/@types/istanbul-reports": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", - "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-report": "*" - } - }, - "node_modules/@types/jsdom": { - "version": "20.0.0", - "resolved": "https://registry.npmjs.org/@types/jsdom/-/jsdom-20.0.0.tgz", - "integrity": "sha512-YfAchFs0yM1QPDrLm2VHe+WHGtqms3NXnXAMolrgrVP6fgBHHXy1ozAbo/dFtPNtZC/m66bPiCTWYmqp1F14gA==", - "dev": true, - "dependencies": { - "@types/node": "*", - "@types/tough-cookie": "*", - "parse5": "^7.0.0" - } - }, - "node_modules/@types/json-schema": { - "version": "7.0.11", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", - "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", - "dev": true - }, - "node_modules/@types/node": { - "version": "18.7.15", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.7.15.tgz", - "integrity": "sha512-XnjpaI8Bgc3eBag2Aw4t2Uj/49lLBSStHWfqKvIuXD7FIrZyMLWp8KuAFHAqxMZYTF9l08N1ctUn9YNybZJVmQ==", - "dev": true - }, - "node_modules/@types/prettier": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.0.tgz", - "integrity": "sha512-RI1L7N4JnW5gQw2spvL7Sllfuf1SaHdrZpCHiBlCXjIlufi1SMNnbu2teze3/QE67Fg2tBlH7W+mi4hVNk4p0A==", - "dev": true - }, - "node_modules/@types/stack-utils": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", - "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", - "dev": true - }, - "node_modules/@types/tough-cookie": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.2.tgz", - "integrity": "sha512-Q5vtl1W5ue16D+nIaW8JWebSSraJVlK+EthKn7e7UcD4KWsaSJ8BqGPXNaPghgtcn/fhvrN17Tv8ksUsQpiplw==", - "dev": true - }, - "node_modules/@types/yargs": { - "version": "17.0.12", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.12.tgz", - "integrity": "sha512-Nz4MPhecOFArtm81gFQvQqdV7XYCrWKx5uUt6GNHredFHn1i2mtWqXTON7EPXMtNi1qjtjEM/VCHDhcHsAMLXQ==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/@types/yargs-parser": { - "version": "21.0.0", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz", - "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==", - "dev": true - }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "5.27.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.27.1.tgz", - "integrity": "sha512-fQEOSa/QroWE6fAEg+bJxtRZJTH8NTskggybogHt4H9Da8zd4cJji76gA5SBlR0MgtwF7rebxTbDKB49YUCpAg==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "5.27.1", - "@typescript-eslint/visitor-keys": "5.27.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/types": { - "version": "5.27.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.27.1.tgz", - "integrity": "sha512-LgogNVkBhCTZU/m8XgEYIWICD6m4dmEDbKXESCbqOXfKZxRKeqpiJXQIErv66sdopRKZPo5l32ymNqibYEH/xg==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "5.27.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.27.1.tgz", - "integrity": "sha512-DnZvvq3TAJ5ke+hk0LklvxwYsnXpRdqUY5gaVS0D4raKtbznPz71UJGnPTHEFo0GDxqLOLdMkkmVZjSpET1hFw==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "5.27.1", - "@typescript-eslint/visitor-keys": "5.27.1", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "semver": "^7.3.7", - "tsutils": "^3.21.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/utils": { - "version": "5.27.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.27.1.tgz", - "integrity": "sha512-mZ9WEn1ZLDaVrhRaYgzbkXBkTPghPFsup8zDbbsYTxC5OmqrFE7skkKS/sraVsLP3TcT3Ki5CSyEFBRkLH/H/w==", - "dev": true, - "dependencies": { - "@types/json-schema": "^7.0.9", - "@typescript-eslint/scope-manager": "5.27.1", - "@typescript-eslint/types": "5.27.1", - "@typescript-eslint/typescript-estree": "5.27.1", - "eslint-scope": "^5.1.1", - "eslint-utils": "^3.0.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/@typescript-eslint/utils/node_modules/eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/@typescript-eslint/utils/node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "5.27.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.27.1.tgz", - "integrity": "sha512-xYs6ffo01nhdJgPieyk7HAOpjhTsx7r/oB9LWEhwAXgwn33tkr+W8DI2ChboqhZlC4q3TC6geDYPoiX8ROqyOQ==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "5.27.1", - "eslint-visitor-keys": "^3.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/abab": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", - "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==", - "dev": true - }, - "node_modules/acorn": { - "version": "8.8.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz", - "integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-globals": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-6.0.0.tgz", - "integrity": "sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg==", - "dev": true, - "dependencies": { - "acorn": "^7.1.1", - "acorn-walk": "^7.1.1" - } - }, - "node_modules/acorn-globals/node_modules/acorn": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/acorn-walk": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", - "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "dev": true, - "dependencies": { - "debug": "4" - }, - "engines": { - "node": ">= 6.0.0" - } - }, - "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ansi-escapes": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", - "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", - "dev": true, - "dependencies": { - "type-fest": "^0.21.3" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ansi-escapes/node_modules/type-fest": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/anymatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", - "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", - "dev": true, - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "node_modules/array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", - "dev": true - }, - "node_modules/axios": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.25.0.tgz", - "integrity": "sha512-cD8FOb0tRH3uuEe6+evtAbgJtfxr7ly3fQjYcMcuPlgkwVS9xboaVIpcDV+cYQe+yGykgwZCs1pzjntcGa6l5g==", - "dev": true, - "dependencies": { - "follow-redirects": "^1.14.7" - } - }, - "node_modules/babel-jest": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.0.2.tgz", - "integrity": "sha512-yTu4/WSi/HzarjQtrJSwV+/0maoNt+iP0DmpvFJdv9yY+5BuNle8TbheHzzcSWj5gIHfuhpbLYHWRDYhWKyeKQ==", - "dev": true, - "dependencies": { - "@jest/transform": "^29.0.2", - "@types/babel__core": "^7.1.14", - "babel-plugin-istanbul": "^6.1.1", - "babel-preset-jest": "^29.0.2", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "slash": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "@babel/core": "^7.8.0" - } - }, - "node_modules/babel-plugin-istanbul": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", - "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.0.0", - "@istanbuljs/load-nyc-config": "^1.0.0", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-instrument": "^5.0.4", - "test-exclude": "^6.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/babel-plugin-jest-hoist": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.0.2.tgz", - "integrity": "sha512-eBr2ynAEFjcebVvu8Ktx580BD1QKCrBG1XwEUTXJe285p9HA/4hOhfWCFRQhTKSyBV0VzjhG7H91Eifz9s29hg==", - "dev": true, - "dependencies": { - "@babel/template": "^7.3.3", - "@babel/types": "^7.3.3", - "@types/babel__core": "^7.1.14", - "@types/babel__traverse": "^7.0.6" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/babel-preset-current-node-syntax": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", - "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", - "dev": true, - "dependencies": { - "@babel/plugin-syntax-async-generators": "^7.8.4", - "@babel/plugin-syntax-bigint": "^7.8.3", - "@babel/plugin-syntax-class-properties": "^7.8.3", - "@babel/plugin-syntax-import-meta": "^7.8.3", - "@babel/plugin-syntax-json-strings": "^7.8.3", - "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.8.3", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", - "@babel/plugin-syntax-optional-chaining": "^7.8.3", - "@babel/plugin-syntax-top-level-await": "^7.8.3" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/babel-preset-jest": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.0.2.tgz", - "integrity": "sha512-BeVXp7rH5TK96ofyEnHjznjLMQ2nAeDJ+QzxKnHAAMs0RgrQsCywjAN8m4mOm5Di0pxU//3AoEeJJrerMH5UeA==", - "dev": true, - "dependencies": { - "babel-plugin-jest-hoist": "^29.0.2", - "babel-preset-current-node-syntax": "^1.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "dependencies": { - "fill-range": "^7.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/browser-process-hrtime": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz", - "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==", - "dev": true - }, - "node_modules/browserslist": { - "version": "4.21.3", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.3.tgz", - "integrity": "sha512-898rgRXLAyRkM1GryrrBHGkqA5hlpkV5MhtZwg9QXeiyLUYs2k00Un05aX5l2/yJIOObYKOpS2JNo8nJDE7fWQ==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - } - ], - "dependencies": { - "caniuse-lite": "^1.0.30001370", - "electron-to-chromium": "^1.4.202", - "node-releases": "^2.0.6", - "update-browserslist-db": "^1.0.5" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - } - }, - "node_modules/bser": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", - "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", - "dev": true, - "dependencies": { - "node-int64": "^0.4.0" - } - }, - "node_modules/buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true - }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/caniuse-lite": { - "version": "1.0.30001390", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001390.tgz", - "integrity": "sha512-sS4CaUM+/+vqQUlCvCJ2WtDlV81aWtHhqeEVkLokVJJa3ViN4zDxAGfq9R8i1m90uGHxo99cy10Od+lvn3hf0g==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - } - ] - }, - "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/char-regex": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", - "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/ci-info": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.3.2.tgz", - "integrity": "sha512-xmDt/QIAdeZ9+nfdPsaBCpMvHNLFiLdjj59qjqn+6iPe6YmHGQ35sBnQ8uslRBXFmXkiZQOJRjvQeoGppoTjjg==", - "dev": true - }, - "node_modules/cjs-module-lexer": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz", - "integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==", - "dev": true - }, - "node_modules/cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "dev": true, - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } - }, - "node_modules/co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", - "dev": true, - "engines": { - "iojs": ">= 1.0.0", - "node": ">= 0.12.0" - } - }, - "node_modules/collect-v8-coverage": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz", - "integrity": "sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==", - "dev": true - }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dev": true, - "dependencies": { - "delayed-stream": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/commander": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz", - "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==", - "dev": true, - "engines": { - "node": ">= 6" - } - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true - }, - "node_modules/convert-source-map": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", - "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", - "dev": true, - "dependencies": { - "safe-buffer": "~5.1.1" - } - }, - "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/cssom": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.5.0.tgz", - "integrity": "sha512-iKuQcq+NdHqlAcwUY0o/HL69XQrUaQdMjmStJ8JFmUaiiQErlhrmuigkg/CU4E2J0IyUKUrMAgl36TvN67MqTw==", - "dev": true - }, - "node_modules/cssstyle": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", - "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", - "dev": true, - "dependencies": { - "cssom": "~0.3.6" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cssstyle/node_modules/cssom": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", - "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", - "dev": true - }, - "node_modules/cwd": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/cwd/-/cwd-0.10.0.tgz", - "integrity": "sha512-YGZxdTTL9lmLkCUTpg4j0zQ7IhRB5ZmqNBbGCl3Tg6MP/d5/6sY7L5mmTjzbc6JKgVZYiqTQTNhPFsbXNGlRaA==", - "dev": true, - "dependencies": { - "find-pkg": "^0.1.2", - "fs-exists-sync": "^0.1.0" - }, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/data-uri-to-buffer": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.0.tgz", - "integrity": "sha512-Vr3mLBA8qWmcuschSLAOogKgQ/Jwxulv3RNE4FXnYWRGujzrRWQI4m12fQqRkwX06C0KanhLr4hK+GydchZsaA==", - "dev": true, - "engines": { - "node": ">= 12" - } - }, - "node_modules/data-urls": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-3.0.2.tgz", - "integrity": "sha512-Jy/tj3ldjZJo63sVAvg6LHt2mHvl4V6AgRAmNDtLdm7faqtsx+aJG42rsyCo9JCoRVKwPFzKlIPx3DIibwSIaQ==", - "dev": true, - "dependencies": { - "abab": "^2.0.6", - "whatwg-mimetype": "^3.0.0", - "whatwg-url": "^11.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/decimal.js": { - "version": "10.4.0", - "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.0.tgz", - "integrity": "sha512-Nv6ENEzyPQ6AItkGwLE2PGKinZZ9g59vSh2BeH6NqPu0OTKZ5ruJsVqh/orbAnqXc9pBbgXAIrc2EyaCj8NpGg==", - "dev": true - }, - "node_modules/dedent": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", - "integrity": "sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==", - "dev": true - }, - "node_modules/deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true - }, - "node_modules/deepmerge": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", - "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/detect-newline": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", - "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/diff-sequences": { - "version": "29.0.0", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.0.0.tgz", - "integrity": "sha512-7Qe/zd1wxSDL4D/X/FPjOMB+ZMDt71W94KYaq05I2l0oQqgXgs7s4ftYYmV38gBSrPz2vcygxfs1xn0FT+rKNA==", - "dev": true, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, - "dependencies": { - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/domexception": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/domexception/-/domexception-4.0.0.tgz", - "integrity": "sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw==", - "dev": true, - "dependencies": { - "webidl-conversions": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/electron-to-chromium": { - "version": "1.4.242", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.242.tgz", - "integrity": "sha512-nPdgMWtjjWGCtreW/2adkrB2jyHjClo9PtVhR6rW+oxa4E4Wom642Tn+5LslHP3XPL5MCpkn5/UEY60EXylNeQ==", - "dev": true - }, - "node_modules/emittery": { - "version": "0.10.2", - "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.10.2.tgz", - "integrity": "sha512-aITqOwnLanpHLNXZJENbOgjUBeHocD+xsSJmNrjovKBW5HbSpW3d1pEls7GFQPUWXiwG9+0P4GtHfEqC/4M0Iw==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sindresorhus/emittery?sponsor=1" - } - }, - "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==", - "dev": true - }, - "node_modules/entities": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-4.4.0.tgz", - "integrity": "sha512-oYp7156SP8LkeGD0GF85ad1X9Ai79WtRsZ2gxJqtBuzH+98YUV6jkHEKlZkMbcrjJjIVJNIDP/3WL9wQkoPbWA==", - "dev": true, - "engines": { - "node": ">=0.12" - }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, - "node_modules/error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, - "dependencies": { - "is-arrayish": "^0.2.1" - } - }, - "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/escodegen": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.0.0.tgz", - "integrity": "sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw==", - "dev": true, - "dependencies": { - "esprima": "^4.0.1", - "estraverse": "^5.2.0", - "esutils": "^2.0.2", - "optionator": "^0.8.1" - }, - "bin": { - "escodegen": "bin/escodegen.js", - "esgenerate": "bin/esgenerate.js" - }, - "engines": { - "node": ">=6.0" - }, - "optionalDependencies": { - "source-map": "~0.6.1" - } - }, - "node_modules/escodegen/node_modules/levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==", - "dev": true, - "dependencies": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/escodegen/node_modules/optionator": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", - "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", - "dev": true, - "dependencies": { - "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.6", - "levn": "~0.3.0", - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2", - "word-wrap": "~1.2.3" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/escodegen/node_modules/prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/escodegen/node_modules/type-check": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==", - "dev": true, - "dependencies": { - "prelude-ls": "~1.1.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/eslint": { - "version": "8.23.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.23.0.tgz", - "integrity": "sha512-pBG/XOn0MsJcKcTRLr27S5HpzQo4kLr+HjLQIyK4EiCsijDl/TB+h5uEuJU6bQ8Edvwz1XWOjpaP2qgnXGpTcA==", - "dev": true, - "dependencies": { - "@eslint/eslintrc": "^1.3.1", - "@humanwhocodes/config-array": "^0.10.4", - "@humanwhocodes/gitignore-to-minimatch": "^1.0.2", - "@humanwhocodes/module-importer": "^1.0.1", - "ajv": "^6.10.0", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.3.2", - "doctrine": "^3.0.0", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.1.1", - "eslint-utils": "^3.0.0", - "eslint-visitor-keys": "^3.3.0", - "espree": "^9.4.0", - "esquery": "^1.4.0", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "find-up": "^5.0.0", - "functional-red-black-tree": "^1.0.1", - "glob-parent": "^6.0.1", - "globals": "^13.15.0", - "globby": "^11.1.0", - "grapheme-splitter": "^1.0.4", - "ignore": "^5.2.0", - "import-fresh": "^3.0.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "js-yaml": "^4.1.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.1", - "regexpp": "^3.2.0", - "strip-ansi": "^6.0.1", - "strip-json-comments": "^3.1.0", - "text-table": "^0.2.0" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-plugin-jest": { - "version": "27.0.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-27.0.1.tgz", - "integrity": "sha512-LosUsrkwVSs/8Z/I8Hqn5vWgTEsHrfIquDEKOsV8/cl+gbFR4tiRCE1AimEotsHjSC0Rx1tYm6vPhw8C3ktmmg==", - "dev": true, - "dependencies": { - "@typescript-eslint/utils": "^5.10.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "@typescript-eslint/eslint-plugin": "^5.0.0", - "eslint": "^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "@typescript-eslint/eslint-plugin": { - "optional": true - }, - "jest": { - "optional": true - } - } - }, - "node_modules/eslint-scope": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", - "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", - "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/eslint-utils": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", - "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", - "dev": true, - "dependencies": { - "eslint-visitor-keys": "^2.0.0" - }, - "engines": { - "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - }, - "peerDependencies": { - "eslint": ">=5" - } - }, - "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", - "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/espree": { - "version": "9.4.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.0.tgz", - "integrity": "sha512-DQmnRpLj7f6TgN/NYb0MTzJXL+vJF9h3pHy4JhCIs3zwcgez8xmGg3sXHcEO97BrmO2OSvCwMdfdlyl+E9KjOw==", - "dev": true, - "dependencies": { - "acorn": "^8.8.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true, - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/esquery": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", - "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", - "dev": true, - "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } - }, - "node_modules/exit": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", - "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/expand-tilde": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-1.2.2.tgz", - "integrity": "sha512-rtmc+cjLZqnu9dSYosX9EWmSJhTwpACgJQTfj4hgg2JjOD/6SIQalZrt4a3aQeh++oNxkazcaxrhPUj6+g5G/Q==", - "dev": true, - "dependencies": { - "os-homedir": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/expect": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/expect/-/expect-29.0.2.tgz", - "integrity": "sha512-JeJlAiLKn4aApT4pzUXBVxl3NaZidWIOdg//smaIlP9ZMBDkHZGFd9ubphUZP9pUyDEo7bC6M0IIZR51o75qQw==", - "dev": true, - "dependencies": { - "@jest/expect-utils": "^29.0.2", - "jest-get-type": "^29.0.0", - "jest-matcher-utils": "^29.0.2", - "jest-message-util": "^29.0.2", - "jest-util": "^29.0.2" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true - }, - "node_modules/fast-glob": { - "version": "3.2.11", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", - "integrity": "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==", - "dev": true, - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - }, - "engines": { - "node": ">=8.6.0" - } - }, - "node_modules/fast-glob/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true - }, - "node_modules/fastq": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", - "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", - "dev": true, - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/fb-watchman": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.1.tgz", - "integrity": "sha512-DkPJKQeY6kKwmuMretBhr7G6Vodr7bFwDYTXIkfG1gjvNpaxBTQV3PbXg6bR1c1UP4jPOX0jHUbbHANL9vRjVg==", - "dev": true, - "dependencies": { - "bser": "2.1.1" - } - }, - "node_modules/fetch-blob": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.1.5.tgz", - "integrity": "sha512-N64ZpKqoLejlrwkIAnb9iLSA3Vx/kjgzpcDhygcqJ2KKjky8nCgUQ+dzXtbrLaWZGZNmNfQTsiQ0weZ1svglHg==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/jimmywarting" - }, - { - "type": "paypal", - "url": "https://paypal.me/jimmywarting" - } - ], - "dependencies": { - "node-domexception": "^1.0.0", - "web-streams-polyfill": "^3.0.3" - }, - "engines": { - "node": "^12.20 || >= 14.13" - } - }, - "node_modules/file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", - "dev": true, - "dependencies": { - "flat-cache": "^3.0.4" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/find-file-up": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/find-file-up/-/find-file-up-0.1.3.tgz", - "integrity": "sha512-mBxmNbVyjg1LQIIpgO8hN+ybWBgDQK8qjht+EbrTCGmmPV/sc7RF1i9stPTD6bpvXZywBdrwRYxhSdJv867L6A==", - "dev": true, - "dependencies": { - "fs-exists-sync": "^0.1.0", - "resolve-dir": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/find-pkg": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/find-pkg/-/find-pkg-0.1.2.tgz", - "integrity": "sha512-0rnQWcFwZr7eO0513HahrWafsc3CTFioEB7DRiEYCUM/70QXSY8f3mCST17HXLcPvEhzH/Ty/Bxd72ZZsr/yvw==", - "dev": true, - "dependencies": { - "find-file-up": "^0.1.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/find-process": { - "version": "1.4.7", - "resolved": "https://registry.npmjs.org/find-process/-/find-process-1.4.7.tgz", - "integrity": "sha512-/U4CYp1214Xrp3u3Fqr9yNynUrr5Le4y0SsJh2lMDDSbpwYSz3M2SMWQC+wqcx79cN8PQtHQIL8KnuY9M66fdg==", - "dev": true, - "dependencies": { - "chalk": "^4.0.0", - "commander": "^5.1.0", - "debug": "^4.1.1" - }, - "bin": { - "find-process": "bin/find-process.js" - } - }, - "node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/flat-cache": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", - "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", - "dev": true, - "dependencies": { - "flatted": "^3.1.0", - "rimraf": "^3.0.2" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/flatted": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.5.tgz", - "integrity": "sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg==", - "dev": true - }, - "node_modules/follow-redirects": { - "version": "1.15.1", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.1.tgz", - "integrity": "sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/RubenVerborgh" - } - ], - "engines": { - "node": ">=4.0" - }, - "peerDependenciesMeta": { - "debug": { - "optional": true - } - } - }, - "node_modules/form-data": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", - "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", - "dev": true, - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/formdata-polyfill": { - "version": "4.0.10", - "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", - "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", - "dev": true, - "dependencies": { - "fetch-blob": "^3.1.2" - }, - "engines": { - "node": ">=12.20.0" - } - }, - "node_modules/fs-exists-sync": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/fs-exists-sync/-/fs-exists-sync-0.1.0.tgz", - "integrity": "sha512-cR/vflFyPZtrN6b38ZyWxpWdhlXrzZEBawlpBQMq7033xVY7/kg0GDMBK5jg8lDYQckdJ5x/YC88lM3C7VMsLg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true - }, - "node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, - "node_modules/functional-red-black-tree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==", - "dev": true - }, - "node_modules/gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true, - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "node_modules/get-package-type": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", - "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", - "dev": true, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, - "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/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/global-modules": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-0.2.3.tgz", - "integrity": "sha512-JeXuCbvYzYXcwE6acL9V2bAOeSIGl4dD+iwLY9iUx2VBJJ80R18HCn+JCwHM9Oegdfya3lEkGCdaRkSyc10hDA==", - "dev": true, - "dependencies": { - "global-prefix": "^0.1.4", - "is-windows": "^0.2.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/global-prefix": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-0.1.5.tgz", - "integrity": "sha512-gOPiyxcD9dJGCEArAhF4Hd0BAqvAe/JzERP7tYumE4yIkmIedPUVXcJFWbV3/p/ovIIvKjkrTk+f1UVkq7vvbw==", - "dev": true, - "dependencies": { - "homedir-polyfill": "^1.0.0", - "ini": "^1.3.4", - "is-windows": "^0.2.0", - "which": "^1.2.12" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/global-prefix/node_modules/which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "which": "bin/which" - } - }, - "node_modules/globals": { - "version": "13.17.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.17.0.tgz", - "integrity": "sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw==", - "dev": true, - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "dev": true, - "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.10", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", - "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", - "dev": true - }, - "node_modules/grapheme-splitter": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", - "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", - "dev": true - }, - "node_modules/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1" - }, - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/homedir-polyfill": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", - "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==", - "dev": true, - "dependencies": { - "parse-passwd": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/html-encoding-sniffer": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz", - "integrity": "sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==", - "dev": true, - "dependencies": { - "whatwg-encoding": "^2.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/html-escaper": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", - "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", - "dev": true - }, - "node_modules/http-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", - "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", - "dev": true, - "dependencies": { - "@tootallnate/once": "2", - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/https-proxy-agent": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", - "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", - "dev": true, - "dependencies": { - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/human-signals": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", - "dev": true, - "engines": { - "node": ">=10.17.0" - } - }, - "node_modules/iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "dev": true, - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/ignore": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", - "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/import-local": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", - "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", - "dev": true, - "dependencies": { - "pkg-dir": "^4.2.0", - "resolve-cwd": "^3.0.0" - }, - "bin": { - "import-local-fixture": "fixtures/cli.js" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true, - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "dev": true, - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, - "node_modules/ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "dev": true - }, - "node_modules/is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "dev": true - }, - "node_modules/is-core-module": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.10.0.tgz", - "integrity": "sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg==", - "dev": true, - "dependencies": { - "has": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "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==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-generator-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", - "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/is-potential-custom-element-name": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", - "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", - "dev": true - }, - "node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-windows": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-0.2.0.tgz", - "integrity": "sha512-n67eJYmXbniZB7RF4I/FTjK1s6RPOCTxhYrVYLRaCt3lF0mpWZPKr3T2LSZAqyjQsxR2qMmGYXXzK0YWwcPM1Q==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true - }, - "node_modules/istanbul-lib-coverage": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", - "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-instrument": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.0.tgz", - "integrity": "sha512-6Lthe1hqXHBNsqvgDzGO6l03XNeu3CrG4RqQ1KM9+l5+jNGpEJfIELx1NS3SEHmJQA8np/u+E4EPRKRiu6m19A==", - "dev": true, - "dependencies": { - "@babel/core": "^7.12.3", - "@babel/parser": "^7.14.7", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.2.0", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-instrument/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", - "dev": true, - "dependencies": { - "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^3.0.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-source-maps": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", - "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", - "dev": true, - "dependencies": { - "debug": "^4.1.1", - "istanbul-lib-coverage": "^3.0.0", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/istanbul-reports": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz", - "integrity": "sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==", - "dev": true, - "dependencies": { - "html-escaper": "^2.0.0", - "istanbul-lib-report": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/jest/-/jest-29.0.2.tgz", - "integrity": "sha512-enziNbNUmXTcTaTP/Uq5rV91r0Yqy2UKzLUIabxMpGm9YHz8qpbJhiRnNVNvm6vzWfzt/0o97NEHH8/3udoClA==", - "dev": true, - "dependencies": { - "@jest/core": "^29.0.2", - "@jest/types": "^29.0.2", - "import-local": "^3.0.2", - "jest-cli": "^29.0.2" - }, - "bin": { - "jest": "bin/jest.js" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "node_modules/jest-changed-files": { - "version": "29.0.0", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.0.0.tgz", - "integrity": "sha512-28/iDMDrUpGoCitTURuDqUzWQoWmOmOKOFST1mi2lwh62X4BFf6khgH3uSuo1e49X/UDjuApAj3w0wLOex4VPQ==", - "dev": true, - "dependencies": { - "execa": "^5.0.0", - "p-limit": "^3.1.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-circus": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.0.2.tgz", - "integrity": "sha512-YTPEsoE1P1X0bcyDQi3QIkpt2Wl9om9k2DQRuLFdS5x8VvAKSdYAVJufgvudhnKgM8WHvvAzhBE+1DRQB8x1CQ==", - "dev": true, - "dependencies": { - "@jest/environment": "^29.0.2", - "@jest/expect": "^29.0.2", - "@jest/test-result": "^29.0.2", - "@jest/types": "^29.0.2", - "@types/node": "*", - "chalk": "^4.0.0", - "co": "^4.6.0", - "dedent": "^0.7.0", - "is-generator-fn": "^2.0.0", - "jest-each": "^29.0.2", - "jest-matcher-utils": "^29.0.2", - "jest-message-util": "^29.0.2", - "jest-runtime": "^29.0.2", - "jest-snapshot": "^29.0.2", - "jest-util": "^29.0.2", - "p-limit": "^3.1.0", - "pretty-format": "^29.0.2", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-cli": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.0.2.tgz", - "integrity": "sha512-tlf8b+4KcUbBGr25cywIi3+rbZ4+G+SiG8SvY552m9sRZbXPafdmQRyeVE/C/R8K+TiBAMrTIUmV2SlStRJ40g==", - "dev": true, - "dependencies": { - "@jest/core": "^29.0.2", - "@jest/test-result": "^29.0.2", - "@jest/types": "^29.0.2", - "chalk": "^4.0.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.9", - "import-local": "^3.0.2", - "jest-config": "^29.0.2", - "jest-util": "^29.0.2", - "jest-validate": "^29.0.2", - "prompts": "^2.0.1", - "yargs": "^17.3.1" - }, - "bin": { - "jest": "bin/jest.js" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "node_modules/jest-config": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.0.2.tgz", - "integrity": "sha512-RU4gzeUNZAFktYVzDGimDxeYoaiTnH100jkYYZgldqFamaZukF0IqmFx8+QrzVeEWccYg10EEJT3ox1Dq5b74w==", - "dev": true, - "dependencies": { - "@babel/core": "^7.11.6", - "@jest/test-sequencer": "^29.0.2", - "@jest/types": "^29.0.2", - "babel-jest": "^29.0.2", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "deepmerge": "^4.2.2", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "jest-circus": "^29.0.2", - "jest-environment-node": "^29.0.2", - "jest-get-type": "^29.0.0", - "jest-regex-util": "^29.0.0", - "jest-resolve": "^29.0.2", - "jest-runner": "^29.0.2", - "jest-util": "^29.0.2", - "jest-validate": "^29.0.2", - "micromatch": "^4.0.4", - "parse-json": "^5.2.0", - "pretty-format": "^29.0.2", - "slash": "^3.0.0", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "@types/node": "*", - "ts-node": ">=9.0.0" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - }, - "ts-node": { - "optional": true - } - } - }, - "node_modules/jest-dev-server": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/jest-dev-server/-/jest-dev-server-6.1.1.tgz", - "integrity": "sha512-z5LnaGDvlIkdMv/rppSO4+rq+GyQKf1xI9oiBxf9/2EBeN2hxRaWiMvaLNDnHPZj2PAhBXsycrKslDDoZO2Xtw==", - "dev": true, - "dependencies": { - "chalk": "^4.1.2", - "cwd": "^0.10.0", - "find-process": "^1.4.7", - "prompts": "^2.4.2", - "spawnd": "^6.0.2", - "tree-kill": "^1.2.2", - "wait-on": "^6.0.1" - } - }, - "node_modules/jest-diff": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.0.2.tgz", - "integrity": "sha512-b9l9970sa1rMXH1owp2Woprmy42qIwwll/htsw4Gf7+WuSp5bZxNhkKHDuCGKL+HoHn1KhcC+tNEeAPYBkD2Jg==", - "dev": true, - "dependencies": { - "chalk": "^4.0.0", - "diff-sequences": "^29.0.0", - "jest-get-type": "^29.0.0", - "pretty-format": "^29.0.2" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-docblock": { - "version": "29.0.0", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.0.0.tgz", - "integrity": "sha512-s5Kpra/kLzbqu9dEjov30kj1n4tfu3e7Pl8v+f8jOkeWNqM6Ds8jRaJfZow3ducoQUrf2Z4rs2N5S3zXnb83gw==", - "dev": true, - "dependencies": { - "detect-newline": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-each": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.0.2.tgz", - "integrity": "sha512-+sA9YjrJl35iCg0W0VCrgCVj+wGhDrrKQ+YAqJ/DHBC4gcDFAeePtRRhpJnX9gvOZ63G7gt52pwp2PesuSEx0Q==", - "dev": true, - "dependencies": { - "@jest/types": "^29.0.2", - "chalk": "^4.0.0", - "jest-get-type": "^29.0.0", - "jest-util": "^29.0.2", - "pretty-format": "^29.0.2" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-environment-jsdom": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-29.0.2.tgz", - "integrity": "sha512-hWqC9FQI5yT04lTd4VJnzT5QObxq0xrSrqpGkqsYfxPeJYjyhriI7W2oJC5HZ1UbhnvA+8GS1nzgPsstvRpdVw==", - "dev": true, - "dependencies": { - "@jest/environment": "^29.0.2", - "@jest/fake-timers": "^29.0.2", - "@jest/types": "^29.0.2", - "@types/jsdom": "^20.0.0", - "@types/node": "*", - "jest-mock": "^29.0.2", - "jest-util": "^29.0.2", - "jsdom": "^20.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-environment-node": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.0.2.tgz", - "integrity": "sha512-4Fv8GXVCToRlMzDO94gvA8iOzKxQ7rhAbs8L+j8GPyTxGuUiYkV+63LecGeVdVhsL2KXih1sKnoqmH6tp89J7Q==", - "dev": true, - "dependencies": { - "@jest/environment": "^29.0.2", - "@jest/fake-timers": "^29.0.2", - "@jest/types": "^29.0.2", - "@types/node": "*", - "jest-mock": "^29.0.2", - "jest-util": "^29.0.2" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-get-type": { - "version": "29.0.0", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.0.0.tgz", - "integrity": "sha512-83X19z/HuLKYXYHskZlBAShO7UfLFXu/vWajw9ZNJASN32li8yHMaVGAQqxFW1RCFOkB7cubaL6FaJVQqqJLSw==", - "dev": true, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-haste-map": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.0.2.tgz", - "integrity": "sha512-SOorh2ysQ0fe8gsF4gaUDhoMIWAvi2hXOkwThEO48qT3JqA8GLAUieQcIvdSEd6M0scRDe1PVmKc5tXR3Z0U0A==", - "dev": true, - "dependencies": { - "@jest/types": "^29.0.2", - "@types/graceful-fs": "^4.1.3", - "@types/node": "*", - "anymatch": "^3.0.3", - "fb-watchman": "^2.0.0", - "graceful-fs": "^4.2.9", - "jest-regex-util": "^29.0.0", - "jest-util": "^29.0.2", - "jest-worker": "^29.0.2", - "micromatch": "^4.0.4", - "walker": "^1.0.8" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "optionalDependencies": { - "fsevents": "^2.3.2" - } - }, - "node_modules/jest-leak-detector": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.0.2.tgz", - "integrity": "sha512-5f0493qDeAxjUldkBSQg5D1cLadRgZVyWpTQvfJeQwQUpHQInE21AyVHVv64M7P2Ue8Z5EZ4BAcoDS/dSPPgMw==", - "dev": true, - "dependencies": { - "jest-get-type": "^29.0.0", - "pretty-format": "^29.0.2" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-matcher-utils": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.0.2.tgz", - "integrity": "sha512-s62YkHFBfAx0JLA2QX1BlnCRFwHRobwAv2KP1+YhjzF6ZCbCVrf1sG8UJyn62ZUsDaQKpoo86XMTjkUyO5aWmQ==", - "dev": true, - "dependencies": { - "chalk": "^4.0.0", - "jest-diff": "^29.0.2", - "jest-get-type": "^29.0.0", - "pretty-format": "^29.0.2" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-message-util": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.0.2.tgz", - "integrity": "sha512-kcJAgms3ckJV0wUoLsAM40xAhY+pb9FVSZwicjFU9PFkaTNmqh9xd99/CzKse48wPM1ANUQKmp03/DpkY+lGrA==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.12.13", - "@jest/types": "^29.0.2", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "micromatch": "^4.0.4", - "pretty-format": "^29.0.2", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-mock": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.0.2.tgz", - "integrity": "sha512-giWXOIT23UCxHCN2VUfUJ0Q7SmiqQwfSFXlCaIhW5anITpNQ+3vuLPQdKt5wkuwM37GrbFyHIClce8AAK9ft9g==", - "dev": true, - "dependencies": { - "@jest/types": "^29.0.2", - "@types/node": "*" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-pnp-resolver": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz", - "integrity": "sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w==", - "dev": true, - "engines": { - "node": ">=6" - }, - "peerDependencies": { - "jest-resolve": "*" - }, - "peerDependenciesMeta": { - "jest-resolve": { - "optional": true - } - } - }, - "node_modules/jest-regex-util": { - "version": "29.0.0", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.0.0.tgz", - "integrity": "sha512-BV7VW7Sy0fInHWN93MMPtlClweYv2qrSCwfeFWmpribGZtQPWNvRSq9XOVgOEjU1iBGRKXUZil0o2AH7Iy9Lug==", - "dev": true, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-resolve": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.0.2.tgz", - "integrity": "sha512-V3uLjSA+EHxLtjIDKTBXnY71hyx+8lusCqPXvqzkFO1uCGvVpjBfuOyp+KOLBNSuY61kM2jhepiMwt4eiJS+Vw==", - "dev": true, - "dependencies": { - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.0.2", - "jest-pnp-resolver": "^1.2.2", - "jest-util": "^29.0.2", - "jest-validate": "^29.0.2", - "resolve": "^1.20.0", - "resolve.exports": "^1.1.0", - "slash": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-resolve-dependencies": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.0.2.tgz", - "integrity": "sha512-fSAu6eIG7wtGdnPJUkVVdILGzYAP9Dj/4+zvC8BrGe8msaUMJ9JeygU0Hf9+Uor6/icbuuzQn5See1uajLnAqg==", - "dev": true, - "dependencies": { - "jest-regex-util": "^29.0.0", - "jest-snapshot": "^29.0.2" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-runner": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.0.2.tgz", - "integrity": "sha512-+D82iPZejI8t+SfduOO1deahC/QgLFf8aJBO++Znz3l2ETtOMdM7K4ATsGWzCFnTGio5yHaRifg1Su5Ybza5Nw==", - "dev": true, - "dependencies": { - "@jest/console": "^29.0.2", - "@jest/environment": "^29.0.2", - "@jest/test-result": "^29.0.2", - "@jest/transform": "^29.0.2", - "@jest/types": "^29.0.2", - "@types/node": "*", - "chalk": "^4.0.0", - "emittery": "^0.10.2", - "graceful-fs": "^4.2.9", - "jest-docblock": "^29.0.0", - "jest-environment-node": "^29.0.2", - "jest-haste-map": "^29.0.2", - "jest-leak-detector": "^29.0.2", - "jest-message-util": "^29.0.2", - "jest-resolve": "^29.0.2", - "jest-runtime": "^29.0.2", - "jest-util": "^29.0.2", - "jest-watcher": "^29.0.2", - "jest-worker": "^29.0.2", - "p-limit": "^3.1.0", - "source-map-support": "0.5.13" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-runtime": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.0.2.tgz", - "integrity": "sha512-DO6F81LX4okOgjJLkLySv10E5YcV5NHUbY1ZqAUtofxdQE+q4hjH0P2gNsY8x3z3sqgw7O/+919SU4r18Fcuig==", - "dev": true, - "dependencies": { - "@jest/environment": "^29.0.2", - "@jest/fake-timers": "^29.0.2", - "@jest/globals": "^29.0.2", - "@jest/source-map": "^29.0.0", - "@jest/test-result": "^29.0.2", - "@jest/transform": "^29.0.2", - "@jest/types": "^29.0.2", - "@types/node": "*", - "chalk": "^4.0.0", - "cjs-module-lexer": "^1.0.0", - "collect-v8-coverage": "^1.0.0", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.0.2", - "jest-message-util": "^29.0.2", - "jest-mock": "^29.0.2", - "jest-regex-util": "^29.0.0", - "jest-resolve": "^29.0.2", - "jest-snapshot": "^29.0.2", - "jest-util": "^29.0.2", - "slash": "^3.0.0", - "strip-bom": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-snapshot": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.0.2.tgz", - "integrity": "sha512-26C4PzGKaX5gkoKg8UzYGVy2HPVcTaROSkf0gwnHu3lGeTB7bAIJBovvVPZoiJ20IximJELQs/r8WSDRCuGX2A==", - "dev": true, - "dependencies": { - "@babel/core": "^7.11.6", - "@babel/generator": "^7.7.2", - "@babel/plugin-syntax-jsx": "^7.7.2", - "@babel/plugin-syntax-typescript": "^7.7.2", - "@babel/traverse": "^7.7.2", - "@babel/types": "^7.3.3", - "@jest/expect-utils": "^29.0.2", - "@jest/transform": "^29.0.2", - "@jest/types": "^29.0.2", - "@types/babel__traverse": "^7.0.6", - "@types/prettier": "^2.1.5", - "babel-preset-current-node-syntax": "^1.0.0", - "chalk": "^4.0.0", - "expect": "^29.0.2", - "graceful-fs": "^4.2.9", - "jest-diff": "^29.0.2", - "jest-get-type": "^29.0.0", - "jest-haste-map": "^29.0.2", - "jest-matcher-utils": "^29.0.2", - "jest-message-util": "^29.0.2", - "jest-util": "^29.0.2", - "natural-compare": "^1.4.0", - "pretty-format": "^29.0.2", - "semver": "^7.3.5" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-util": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.0.2.tgz", - "integrity": "sha512-ozk8ruEEEACxqpz0hN9UOgtPZS0aN+NffwQduR5dVlhN+eN47vxurtvgZkYZYMpYrsmlAEx1XabkB3BnN0GfKQ==", - "dev": true, - "dependencies": { - "@jest/types": "^29.0.2", - "@types/node": "*", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "graceful-fs": "^4.2.9", - "picomatch": "^2.2.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-validate": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.0.2.tgz", - "integrity": "sha512-AeRKm7cEucSy7tr54r3LhiGIXYvOILUwBM1S7jQkKs6YelwAlWKsmZGVrQR7uwsd31rBTnR5NQkODi1Z+6TKIQ==", - "dev": true, - "dependencies": { - "@jest/types": "^29.0.2", - "camelcase": "^6.2.0", - "chalk": "^4.0.0", - "jest-get-type": "^29.0.0", - "leven": "^3.1.0", - "pretty-format": "^29.0.2" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-validate/node_modules/camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/jest-watcher": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.0.2.tgz", - "integrity": "sha512-ds2bV0oyUdYoyrUTv4Ga5uptz4cEvmmP/JzqDyzZZanvrIn8ipxg5l3SDOAIiyuAx1VdHd2FBzeXPFO5KPH8vQ==", - "dev": true, - "dependencies": { - "@jest/test-result": "^29.0.2", - "@jest/types": "^29.0.2", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "emittery": "^0.10.2", - "jest-util": "^29.0.2", - "string-length": "^4.0.1" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-worker": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.0.2.tgz", - "integrity": "sha512-EyvBlYcvd2pg28yg5A3OODQnqK9LI1kitnGUZUG5/NYIeaRgewtYBKB5wlr7oXj8zPCkzev7EmnTCsrXK7V+Xw==", - "dev": true, - "dependencies": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-worker/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "node_modules/joi": { - "version": "17.6.0", - "resolved": "https://registry.npmjs.org/joi/-/joi-17.6.0.tgz", - "integrity": "sha512-OX5dG6DTbcr/kbMFj0KGYxuew69HPcAE3K/sZpEV2nP6e/j/C0HV+HNiBPCASxdx5T7DMoa0s8UeHWMnb6n2zw==", - "dev": true, - "dependencies": { - "@hapi/hoek": "^9.0.0", - "@hapi/topo": "^5.0.0", - "@sideway/address": "^4.1.3", - "@sideway/formula": "^3.0.0", - "@sideway/pinpoint": "^2.0.0" - } - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, - "node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/jsdom": { - "version": "20.0.0", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-20.0.0.tgz", - "integrity": "sha512-x4a6CKCgx00uCmP+QakBDFXwjAJ69IkkIWHmtmjd3wvXPcdOS44hfX2vqkOQrVrq8l9DhNNADZRXaCEWvgXtVA==", - "dev": true, - "dependencies": { - "abab": "^2.0.6", - "acorn": "^8.7.1", - "acorn-globals": "^6.0.0", - "cssom": "^0.5.0", - "cssstyle": "^2.3.0", - "data-urls": "^3.0.2", - "decimal.js": "^10.3.1", - "domexception": "^4.0.0", - "escodegen": "^2.0.0", - "form-data": "^4.0.0", - "html-encoding-sniffer": "^3.0.0", - "http-proxy-agent": "^5.0.0", - "https-proxy-agent": "^5.0.1", - "is-potential-custom-element-name": "^1.0.1", - "nwsapi": "^2.2.0", - "parse5": "^7.0.0", - "saxes": "^6.0.0", - "symbol-tree": "^3.2.4", - "tough-cookie": "^4.0.0", - "w3c-hr-time": "^1.0.2", - "w3c-xmlserializer": "^3.0.0", - "webidl-conversions": "^7.0.0", - "whatwg-encoding": "^2.0.0", - "whatwg-mimetype": "^3.0.0", - "whatwg-url": "^11.0.0", - "ws": "^8.8.0", - "xml-name-validator": "^4.0.0" - }, - "engines": { - "node": ">=14" - }, - "peerDependencies": { - "canvas": "^2.5.0" - }, - "peerDependenciesMeta": { - "canvas": { - "optional": true - } - } - }, - "node_modules/jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "dev": true, - "bin": { - "jsesc": "bin/jsesc" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true - }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true - }, - "node_modules/json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "dev": true, - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/kleur": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", - "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/leven": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", - "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/lines-and-columns": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "dev": true - }, - "node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true - }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true - }, - "node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dev": true, - "dependencies": { - "semver": "^6.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/make-dir/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/makeerror": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", - "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", - "dev": true, - "dependencies": { - "tmpl": "1.0.5" - } - }, - "node_modules/merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true - }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", - "dev": true, - "dependencies": { - "braces": "^3.0.2", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dev": true, - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/minimist": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", - "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", - "dev": true - }, - "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node_modules/natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true - }, - "node_modules/node-domexception": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", - "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/jimmywarting" - }, - { - "type": "github", - "url": "https://paypal.me/jimmywarting" - } - ], - "engines": { - "node": ">=10.5.0" - } - }, - "node_modules/node-fetch": { - "version": "3.2.10", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.2.10.tgz", - "integrity": "sha512-MhuzNwdURnZ1Cp4XTazr69K0BTizsBroX7Zx3UgDSVcZYKF/6p0CBe4EUb/hLqmzVhl0UpYfgRljQ4yxE+iCxA==", - "dev": true, - "dependencies": { - "data-uri-to-buffer": "^4.0.0", - "fetch-blob": "^3.1.4", - "formdata-polyfill": "^4.0.10" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/node-fetch" - } - }, - "node_modules/node-int64": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", - "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", - "dev": true - }, - "node_modules/node-releases": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz", - "integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==", - "dev": true - }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "dev": true, - "dependencies": { - "path-key": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/nwsapi": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.2.tgz", - "integrity": "sha512-90yv+6538zuvUMnN+zCr8LuV6bPFdq50304114vJYJ8RDyK8D5O9Phpbd6SZWgI7PwzmmfN1upeOJlvybDSgCw==", - "dev": true - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dev": true, - "dependencies": { - "mimic-fn": "^2.1.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/optionator": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", - "dev": true, - "dependencies": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.3" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/os-homedir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", - "integrity": "sha512-B5JU3cabzk8c67mRRd3ECmROafjYMXbuzlwtqdM8IbS8ktlTix8aFGb2bAGKrSRIlnfKwovGUUr72JUPyOb6kQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/parse-passwd": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", - "integrity": "sha512-1Y1A//QUXEZK7YKz+rD9WydcE1+EuPr6ZBgKecAB8tmoW6UFv0NREVJe1p+jRxtThkcbbKkfwIbWJe/IeE6m2Q==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/parse5": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.1.tgz", - "integrity": "sha512-kwpuwzB+px5WUg9pyK0IcK/shltJN5/OVhQagxhCQNtT9Y9QRZqNY2e1cmbu/paRh5LMnz/oVTVLBpjFmMZhSg==", - "dev": true, - "dependencies": { - "entities": "^4.4.0" - }, - "funding": { - "url": "https://github.com/inikulin/parse5?sponsor=1" - } - }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true - }, - "node_modules/path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", - "dev": true - }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/pirates": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz", - "integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==", - "dev": true, - "engines": { - "node": ">= 6" - } - }, - "node_modules/pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "dev": true, - "dependencies": { - "find-up": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/pkg-dir/node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/pkg-dir/node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/pkg-dir/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/pkg-dir/node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/pretty-format": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.0.2.tgz", - "integrity": "sha512-wp3CdtUa3cSJVFn3Miu5a1+pxc1iPIQTenOAn+x5erXeN1+ryTcLesV5pbK/rlW5EKwp27x38MoYfNGaNXDDhg==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.0.0", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/pretty-format/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/prompts": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", - "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", - "dev": true, - "dependencies": { - "kleur": "^3.0.3", - "sisteransi": "^1.0.5" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/psl": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", - "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==", - "dev": true - }, - "node_modules/punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/querystringify": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", - "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", - "dev": true - }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/react-is": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", - "dev": true - }, - "node_modules/regexpp": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", - "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - } - }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/requires-port": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", - "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", - "dev": true - }, - "node_modules/resolve": { - "version": "1.22.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", - "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", - "dev": true, - "dependencies": { - "is-core-module": "^2.9.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/resolve-cwd": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", - "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", - "dev": true, - "dependencies": { - "resolve-from": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/resolve-cwd/node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/resolve-dir": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-0.1.1.tgz", - "integrity": "sha512-QxMPqI6le2u0dCLyiGzgy92kjkkL6zO0XyvHzjdTNH3zM6e5Hz3BwG6+aEyNgiQ5Xz6PwTwgQEj3U50dByPKIA==", - "dev": true, - "dependencies": { - "expand-tilde": "^1.2.2", - "global-modules": "^0.2.3" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/resolve.exports": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-1.1.0.tgz", - "integrity": "sha512-J1l+Zxxp4XK3LUDZ9m60LRJF/mAe4z6a4xyabPHk7pvK5t35dACV32iIjJDFeWZFfZlO29w6SZ67knR0tHzJtQ==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true, - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, - "node_modules/rxjs": { - "version": "7.5.5", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.5.5.tgz", - "integrity": "sha512-sy+H0pQofO95VDmFLzyaw9xNJU4KTRSwQIGM6+iG3SypAtCiLDzpeG8sJrNCWn2Up9km+KhkvTdbkrdy+yzZdw==", - "dev": true, - "dependencies": { - "tslib": "^2.1.0" - } - }, - "node_modules/rxjs/node_modules/tslib": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", - "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==", - "dev": true - }, - "node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true - }, - "node_modules/saxes": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", - "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", - "dev": true, - "dependencies": { - "xmlchars": "^2.2.0" - }, - "engines": { - "node": ">=v12.22.7" - } - }, - "node_modules/semver": { - "version": "7.3.7", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", - "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true - }, - "node_modules/sisteransi": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", - "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", - "dev": true - }, - "node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/source-map-support": { - "version": "0.5.13", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", - "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", - "dev": true, - "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "node_modules/spawnd": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/spawnd/-/spawnd-6.0.2.tgz", - "integrity": "sha512-+YJtx0dvy2wt304MrHD//tASc84zinBUYU1jacPBzrjhZUd7RsDo25krxr4HUHAQzEQFuMAs4/p+yLYU5ciZ1w==", - "dev": true, - "dependencies": { - "exit": "^0.1.2", - "signal-exit": "^3.0.6", - "tree-kill": "^1.2.2" - } - }, - "node_modules/sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", - "dev": true - }, - "node_modules/stack-utils": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.5.tgz", - "integrity": "sha512-xrQcmYhOsn/1kX+Vraq+7j4oE2j/6BFscZ0etmYg81xuM8Gq0022Pxb8+IqgOFUIaxHs0KaSb7T1+OegiNrNFA==", - "dev": true, - "dependencies": { - "escape-string-regexp": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/stack-utils/node_modules/escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/string-length": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", - "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", - "dev": true, - "dependencies": { - "char-regex": "^1.0.2", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "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==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-bom": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", - "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/supports-hyperlinks": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.3.0.tgz", - "integrity": "sha512-RpsAZlpWcDwOPQA22aCH4J0t7L8JmAvsCxfOSEwm7cQs3LshN36QaTkwd70DnBOXDWGssw2eUoc8CaRWT0XunA==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0", - "supports-color": "^7.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/symbol-tree": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", - "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", - "dev": true - }, - "node_modules/terminal-link": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-2.1.1.tgz", - "integrity": "sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==", - "dev": true, - "dependencies": { - "ansi-escapes": "^4.2.1", - "supports-hyperlinks": "^2.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/test-exclude": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", - "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", - "dev": true, - "dependencies": { - "@istanbuljs/schema": "^0.1.2", - "glob": "^7.1.4", - "minimatch": "^3.0.4" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true - }, - "node_modules/tmpl": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", - "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", - "dev": true - }, - "node_modules/to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/tough-cookie": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.3.tgz", - "integrity": "sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==", - "dev": true, - "dependencies": { - "psl": "^1.1.33", - "punycode": "^2.1.1", - "universalify": "^0.2.0", - "url-parse": "^1.5.3" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/tr46": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-3.0.0.tgz", - "integrity": "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==", - "dev": true, - "dependencies": { - "punycode": "^2.1.1" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/tree-kill": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", - "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", - "dev": true, - "bin": { - "tree-kill": "cli.js" - } - }, - "node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - }, - "node_modules/tsutils": { - "version": "3.21.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", - "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", - "dev": true, - "dependencies": { - "tslib": "^1.8.1" - }, - "engines": { - "node": ">= 6" - }, - "peerDependencies": { - "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" - } - }, - "node_modules/type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/type-detect": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/typescript": { - "version": "4.7.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.3.tgz", - "integrity": "sha512-WOkT3XYvrpXx4vMMqlD+8R8R37fZkjyLGlxavMc4iB8lrl8L0DeTcHbYgw/v0N/z9wAFsgBhcsF0ruoySS22mA==", - "dev": true, - "peer": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=4.2.0" - } - }, - "node_modules/universalify": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", - "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", - "dev": true, - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/update-browserslist-db": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.7.tgz", - "integrity": "sha512-iN/XYesmZ2RmmWAiI4Z5rq0YqSiv0brj9Ce9CfhNE4xIW2h+MFxcgkxIzZ+ShkFPUkjU3gQ+3oypadD3RAMtrg==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - } - ], - "dependencies": { - "escalade": "^3.1.1", - "picocolors": "^1.0.0" - }, - "bin": { - "browserslist-lint": "cli.js" - }, - "peerDependencies": { - "browserslist": ">= 4.21.0" - } - }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/url-parse": { - "version": "1.5.10", - "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", - "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", - "dev": true, - "dependencies": { - "querystringify": "^2.1.1", - "requires-port": "^1.0.0" - } - }, - "node_modules/v8-to-istanbul": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.0.1.tgz", - "integrity": "sha512-74Y4LqY74kLE6IFyIjPtkSTWzUZmj8tdHT9Ii/26dvQ6K9Dl2NbEfj0XgU2sHCtKgt5VupqhlO/5aWuqS+IY1w==", - "dev": true, - "dependencies": { - "@jridgewell/trace-mapping": "^0.3.12", - "@types/istanbul-lib-coverage": "^2.0.1", - "convert-source-map": "^1.6.0" - }, - "engines": { - "node": ">=10.12.0" - } - }, - "node_modules/w3c-hr-time": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", - "integrity": "sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==", - "dev": true, - "dependencies": { - "browser-process-hrtime": "^1.0.0" - } - }, - "node_modules/w3c-xmlserializer": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-3.0.0.tgz", - "integrity": "sha512-3WFqGEgSXIyGhOmAFtlicJNMjEps8b1MG31NCA0/vOF9+nKMUW1ckhi9cnNHmf88Rzw5V+dwIwsm2C7X8k9aQg==", - "dev": true, - "dependencies": { - "xml-name-validator": "^4.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/wait-on": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/wait-on/-/wait-on-6.0.1.tgz", - "integrity": "sha512-zht+KASY3usTY5u2LgaNqn/Cd8MukxLGjdcZxT2ns5QzDmTFc4XoWBgC+C/na+sMRZTuVygQoMYwdcVjHnYIVw==", - "dev": true, - "dependencies": { - "axios": "^0.25.0", - "joi": "^17.6.0", - "lodash": "^4.17.21", - "minimist": "^1.2.5", - "rxjs": "^7.5.4" - }, - "bin": { - "wait-on": "bin/wait-on" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/walker": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", - "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", - "dev": true, - "dependencies": { - "makeerror": "1.0.12" - } - }, - "node_modules/web-streams-polyfill": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz", - "integrity": "sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/webidl-conversions": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", - "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", - "dev": true, - "engines": { - "node": ">=12" - } - }, - "node_modules/whatwg-encoding": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz", - "integrity": "sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==", - "dev": true, - "dependencies": { - "iconv-lite": "0.6.3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/whatwg-mimetype": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-3.0.0.tgz", - "integrity": "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==", - "dev": true, - "engines": { - "node": ">=12" - } - }, - "node_modules/whatwg-url": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-11.0.0.tgz", - "integrity": "sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==", - "dev": true, - "dependencies": { - "tr46": "^3.0.0", - "webidl-conversions": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/word-wrap": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.4.tgz", - "integrity": "sha512-2V81OA4ugVo5pRo46hAoD2ivUJx8jXmWXfUkY4KFNw0hEptvN0QfH3K4nHiwzGeKl5rFKedV48QVoqYavy4YpA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true - }, - "node_modules/write-file-atomic": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", - "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", - "dev": true, - "dependencies": { - "imurmurhash": "^0.1.4", - "signal-exit": "^3.0.7" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/ws": { - "version": "8.8.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.8.1.tgz", - "integrity": "sha512-bGy2JzvzkPowEJV++hF07hAD6niYSr0JzBNo/J29WsB57A2r7Wlc1UFcTR9IzrPvuNVO4B8LGqF8qcpsVOhJCA==", - "dev": true, - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "node_modules/xml-name-validator": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-4.0.0.tgz", - "integrity": "sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==", - "dev": true, - "engines": { - "node": ">=12" - } - }, - "node_modules/xmlchars": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", - "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", - "dev": true - }, - "node_modules/y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/yargs": { - "version": "17.5.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.5.1.tgz", - "integrity": "sha512-t6YAJcxDkNX7NFYiVtKvWUz8l+PaKTLiL63mJYWR2GnHq2gjEWISzsLp9wg3aY36dY1j+gfIEL3pIF+XlJJfbA==", - "dev": true, - "dependencies": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "dev": true, - "engines": { - "node": ">=12" - } - }, - "node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - } - }, - "dependencies": { - "@ampproject/remapping": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", - "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", - "dev": true, - "requires": { - "@jridgewell/gen-mapping": "^0.1.0", - "@jridgewell/trace-mapping": "^0.3.9" - } - }, - "@babel/code-frame": { - "version": "7.22.13", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", - "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", - "dev": true, - "requires": { - "@babel/highlight": "^7.22.13", - "chalk": "^2.4.2" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "@babel/compat-data": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.19.0.tgz", - "integrity": "sha512-y5rqgTTPTmaF5e2nVhOxw+Ur9HDJLsWb6U/KpgUzRZEdPfE6VOubXBKLdbcUTijzRptednSBDQbYZBOSqJxpJw==", - "dev": true - }, - "@babel/core": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.19.0.tgz", - "integrity": "sha512-reM4+U7B9ss148rh2n1Qs9ASS+w94irYXga7c2jaQv9RVzpS7Mv1a9rnYYwuDa45G+DkORt9g6An2k/V4d9LbQ==", - "dev": true, - "requires": { - "@ampproject/remapping": "^2.1.0", - "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.19.0", - "@babel/helper-compilation-targets": "^7.19.0", - "@babel/helper-module-transforms": "^7.19.0", - "@babel/helpers": "^7.19.0", - "@babel/parser": "^7.19.0", - "@babel/template": "^7.18.10", - "@babel/traverse": "^7.19.0", - "@babel/types": "^7.19.0", - "convert-source-map": "^1.7.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.1", - "semver": "^6.3.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } - } - }, - "@babel/generator": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz", - "integrity": "sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==", - "dev": true, - "requires": { - "@babel/types": "^7.23.0", - "@jridgewell/gen-mapping": "^0.3.2", - "@jridgewell/trace-mapping": "^0.3.17", - "jsesc": "^2.5.1" - }, - "dependencies": { - "@jridgewell/gen-mapping": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", - "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", - "dev": true, - "requires": { - "@jridgewell/set-array": "^1.0.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" - } - } - } - }, - "@babel/helper-compilation-targets": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.19.0.tgz", - "integrity": "sha512-Ai5bNWXIvwDvWM7njqsG3feMlL9hCVQsPYXodsZyLwshYkZVJt59Gftau4VrE8S9IT9asd2uSP1hG6wCNw+sXA==", - "dev": true, - "requires": { - "@babel/compat-data": "^7.19.0", - "@babel/helper-validator-option": "^7.18.6", - "browserslist": "^4.20.2", - "semver": "^6.3.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } - } - }, - "@babel/helper-environment-visitor": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", - "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", - "dev": true - }, - "@babel/helper-function-name": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", - "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", - "dev": true, - "requires": { - "@babel/template": "^7.22.15", - "@babel/types": "^7.23.0" - } - }, - "@babel/helper-hoist-variables": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", - "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", - "dev": true, - "requires": { - "@babel/types": "^7.22.5" - } - }, - "@babel/helper-module-imports": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz", - "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==", - "dev": true, - "requires": { - "@babel/types": "^7.18.6" - } - }, - "@babel/helper-module-transforms": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.19.0.tgz", - "integrity": "sha512-3HBZ377Fe14RbLIA+ac3sY4PTgpxHVkFrESaWhoI5PuyXPBBX8+C34qblV9G89ZtycGJCmCI/Ut+VUDK4bltNQ==", - "dev": true, - "requires": { - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-module-imports": "^7.18.6", - "@babel/helper-simple-access": "^7.18.6", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/helper-validator-identifier": "^7.18.6", - "@babel/template": "^7.18.10", - "@babel/traverse": "^7.19.0", - "@babel/types": "^7.19.0" - } - }, - "@babel/helper-plugin-utils": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.19.0.tgz", - "integrity": "sha512-40Ryx7I8mT+0gaNxm8JGTZFUITNqdLAgdg0hXzeVZxVD6nFsdhQvip6v8dqkRHzsz1VFpFAaOCHNn0vKBL7Czw==", - "dev": true - }, - "@babel/helper-simple-access": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.18.6.tgz", - "integrity": "sha512-iNpIgTgyAvDQpDj76POqg+YEt8fPxx3yaNBg3S30dxNKm2SWfYhD0TGrK/Eu9wHpUW63VQU894TsTg+GLbUa1g==", - "dev": true, - "requires": { - "@babel/types": "^7.18.6" - } - }, - "@babel/helper-split-export-declaration": { - "version": "7.22.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", - "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", - "dev": true, - "requires": { - "@babel/types": "^7.22.5" - } - }, - "@babel/helper-string-parser": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz", - "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==", - "dev": true - }, - "@babel/helper-validator-identifier": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", - "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", - "dev": true - }, - "@babel/helper-validator-option": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz", - "integrity": "sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==", - "dev": true - }, - "@babel/helpers": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.19.0.tgz", - "integrity": "sha512-DRBCKGwIEdqY3+rPJgG/dKfQy9+08rHIAJx8q2p+HSWP87s2HCrQmaAMMyMll2kIXKCW0cO1RdQskx15Xakftg==", - "dev": true, - "requires": { - "@babel/template": "^7.18.10", - "@babel/traverse": "^7.19.0", - "@babel/types": "^7.19.0" - } - }, - "@babel/highlight": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz", - "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.22.20", - "chalk": "^2.4.2", - "js-tokens": "^4.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "@babel/parser": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz", - "integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==", - "dev": true - }, - "@babel/plugin-syntax-async-generators": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", - "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-bigint": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", - "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-class-properties": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", - "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.12.13" - } - }, - "@babel/plugin-syntax-import-meta": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", - "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-syntax-json-strings": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", - "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-jsx": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.18.6.tgz", - "integrity": "sha512-6mmljtAedFGTWu2p/8WIORGwy+61PLgOMPOdazc7YoJ9ZCWUyFy3A6CpPkRKLKD1ToAesxX8KGEViAiLo9N+7Q==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.18.6" - } - }, - "@babel/plugin-syntax-logical-assignment-operators": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", - "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-syntax-nullish-coalescing-operator": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", - "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-numeric-separator": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", - "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-syntax-object-rest-spread": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", - "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-optional-catch-binding": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", - "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-optional-chaining": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", - "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-top-level-await": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", - "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.14.5" - } - }, - "@babel/plugin-syntax-typescript": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.18.6.tgz", - "integrity": "sha512-mAWAuq4rvOepWCBid55JuRNvpTNf2UGVgoz4JV0fXEKolsVZDzsa4NqCef758WZJj/GDu0gVGItjKFiClTAmZA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.18.6" - } - }, - "@babel/template": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", - "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.22.13", - "@babel/parser": "^7.22.15", - "@babel/types": "^7.22.15" - } - }, - "@babel/traverse": { - "version": "7.23.2", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz", - "integrity": "sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.22.13", - "@babel/generator": "^7.23.0", - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-function-name": "^7.23.0", - "@babel/helper-hoist-variables": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/parser": "^7.23.0", - "@babel/types": "^7.23.0", - "debug": "^4.1.0", - "globals": "^11.1.0" - }, - "dependencies": { - "globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true - } - } - }, - "@babel/types": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz", - "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==", - "dev": true, - "requires": { - "@babel/helper-string-parser": "^7.22.5", - "@babel/helper-validator-identifier": "^7.22.20", - "to-fast-properties": "^2.0.0" - } - }, - "@bcoe/v8-coverage": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", - "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", - "dev": true - }, - "@eslint/eslintrc": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.1.tgz", - "integrity": "sha512-OhSY22oQQdw3zgPOOwdoj01l/Dzl1Z+xyUP33tkSN+aqyEhymJCcPHyXt+ylW8FSe0TfRC2VG+ROQOapD0aZSQ==", - "dev": true, - "requires": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.4.0", - "globals": "^13.15.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - } - }, - "@hapi/hoek": { - "version": "9.3.0", - "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz", - "integrity": "sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==", - "dev": true - }, - "@hapi/topo": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-5.1.0.tgz", - "integrity": "sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==", - "dev": true, - "requires": { - "@hapi/hoek": "^9.0.0" - } - }, - "@humanwhocodes/config-array": { - "version": "0.10.4", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.10.4.tgz", - "integrity": "sha512-mXAIHxZT3Vcpg83opl1wGlVZ9xydbfZO3r5YfRSH6Gpp2J/PfdBP0wbDa2sO6/qRbcalpoevVyW6A/fI6LfeMw==", - "dev": true, - "requires": { - "@humanwhocodes/object-schema": "^1.2.1", - "debug": "^4.1.1", - "minimatch": "^3.0.4" - } - }, - "@humanwhocodes/gitignore-to-minimatch": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@humanwhocodes/gitignore-to-minimatch/-/gitignore-to-minimatch-1.0.2.tgz", - "integrity": "sha512-rSqmMJDdLFUsyxR6FMtD00nfQKKLFb1kv+qBbOVKqErvloEIJLo5bDTJTQNTYgeyp78JsA7u/NPi5jT1GR/MuA==", - "dev": true - }, - "@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "dev": true - }, - "@humanwhocodes/object-schema": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", - "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", - "dev": true - }, - "@istanbuljs/load-nyc-config": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", - "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", - "dev": true, - "requires": { - "camelcase": "^5.3.1", - "find-up": "^4.1.0", - "get-package-type": "^0.1.0", - "js-yaml": "^3.13.1", - "resolve-from": "^5.0.0" - }, - "dependencies": { - "argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "requires": { - "sprintf-js": "~1.0.2" - } - }, - "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, - "js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "dev": true, - "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - } - }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "requires": { - "p-locate": "^4.1.0" - } - }, - "p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "requires": { - "p-limit": "^2.2.0" - } - }, - "resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true - } - } - }, - "@istanbuljs/schema": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", - "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", - "dev": true - }, - "@jest/console": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.0.2.tgz", - "integrity": "sha512-Fv02ijyhF4D/Wb3DvZO3iBJQz5DnzpJEIDBDbvje8Em099N889tNMUnBw7SalmSuOI+NflNG40RA1iK71kImPw==", - "dev": true, - "requires": { - "@jest/types": "^29.0.2", - "@types/node": "*", - "chalk": "^4.0.0", - "jest-message-util": "^29.0.2", - "jest-util": "^29.0.2", - "slash": "^3.0.0" - } - }, - "@jest/core": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.0.2.tgz", - "integrity": "sha512-imP5M6cdpHEOkmcuFYZuM5cTG1DAF7ZlVNCq1+F7kbqme2Jcl+Kh4M78hihM76DJHNkurbv4UVOnejGxBKEmww==", - "dev": true, - "requires": { - "@jest/console": "^29.0.2", - "@jest/reporters": "^29.0.2", - "@jest/test-result": "^29.0.2", - "@jest/transform": "^29.0.2", - "@jest/types": "^29.0.2", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.9", - "jest-changed-files": "^29.0.0", - "jest-config": "^29.0.2", - "jest-haste-map": "^29.0.2", - "jest-message-util": "^29.0.2", - "jest-regex-util": "^29.0.0", - "jest-resolve": "^29.0.2", - "jest-resolve-dependencies": "^29.0.2", - "jest-runner": "^29.0.2", - "jest-runtime": "^29.0.2", - "jest-snapshot": "^29.0.2", - "jest-util": "^29.0.2", - "jest-validate": "^29.0.2", - "jest-watcher": "^29.0.2", - "micromatch": "^4.0.4", - "pretty-format": "^29.0.2", - "slash": "^3.0.0", - "strip-ansi": "^6.0.0" - } - }, - "@jest/environment": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.0.2.tgz", - "integrity": "sha512-Yf+EYaLOrVCgts/aTS5nGznU4prZUPa5k9S63Yct8YSOKj2jkdS17hHSUKhk5jxDFMyCy1PXknypDw7vfgc/mA==", - "dev": true, - "requires": { - "@jest/fake-timers": "^29.0.2", - "@jest/types": "^29.0.2", - "@types/node": "*", - "jest-mock": "^29.0.2" - } - }, - "@jest/expect": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.0.2.tgz", - "integrity": "sha512-y/3geZ92p2/zovBm/F+ZjXUJ3thvT9IRzD6igqaWskFE2aR0idD+N/p5Lj/ZautEox/9RwEc6nqergebeh72uQ==", - "dev": true, - "requires": { - "expect": "^29.0.2", - "jest-snapshot": "^29.0.2" - } - }, - "@jest/expect-utils": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.0.2.tgz", - "integrity": "sha512-+wcQF9khXKvAEi8VwROnCWWmHfsJYCZAs5dmuMlJBKk57S6ZN2/FQMIlo01F29fJyT8kV/xblE7g3vkIdTLOjw==", - "dev": true, - "requires": { - "jest-get-type": "^29.0.0" - } - }, - "@jest/fake-timers": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.0.2.tgz", - "integrity": "sha512-2JhQeWU28fvmM5r33lxg6BxxkTKaVXs6KMaJ6eXSM8ml/MaWkt2BvbIO8G9KWAJFMdBXWbn+2h9OK1/s5urKZA==", - "dev": true, - "requires": { - "@jest/types": "^29.0.2", - "@sinonjs/fake-timers": "^9.1.2", - "@types/node": "*", - "jest-message-util": "^29.0.2", - "jest-mock": "^29.0.2", - "jest-util": "^29.0.2" - } - }, - "@jest/globals": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.0.2.tgz", - "integrity": "sha512-4hcooSNJCVXuTu07/VJwCWW6HTnjLtQdqlcGisK6JST7z2ixa8emw4SkYsOk7j36WRc2ZUEydlUePnOIOTCNXg==", - "dev": true, - "requires": { - "@jest/environment": "^29.0.2", - "@jest/expect": "^29.0.2", - "@jest/types": "^29.0.2", - "jest-mock": "^29.0.2" - } - }, - "@jest/reporters": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.0.2.tgz", - "integrity": "sha512-Kr41qejRQHHkCgWHC9YwSe7D5xivqP4XML+PvgwsnRFaykKdNflDUb4+xLXySOU+O/bPkVdFpGzUpVNSJChCrw==", - "dev": true, - "requires": { - "@bcoe/v8-coverage": "^0.2.3", - "@jest/console": "^29.0.2", - "@jest/test-result": "^29.0.2", - "@jest/transform": "^29.0.2", - "@jest/types": "^29.0.2", - "@jridgewell/trace-mapping": "^0.3.15", - "@types/node": "*", - "chalk": "^4.0.0", - "collect-v8-coverage": "^1.0.0", - "exit": "^0.1.2", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "istanbul-lib-coverage": "^3.0.0", - "istanbul-lib-instrument": "^5.1.0", - "istanbul-lib-report": "^3.0.0", - "istanbul-lib-source-maps": "^4.0.0", - "istanbul-reports": "^3.1.3", - "jest-message-util": "^29.0.2", - "jest-util": "^29.0.2", - "jest-worker": "^29.0.2", - "slash": "^3.0.0", - "string-length": "^4.0.1", - "strip-ansi": "^6.0.0", - "terminal-link": "^2.0.0", - "v8-to-istanbul": "^9.0.1" - } - }, - "@jest/schemas": { - "version": "29.0.0", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.0.0.tgz", - "integrity": "sha512-3Ab5HgYIIAnS0HjqJHQYZS+zXc4tUmTmBH3z83ajI6afXp8X3ZtdLX+nXx+I7LNkJD7uN9LAVhgnjDgZa2z0kA==", - "dev": true, - "requires": { - "@sinclair/typebox": "^0.24.1" - } - }, - "@jest/source-map": { - "version": "29.0.0", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.0.0.tgz", - "integrity": "sha512-nOr+0EM8GiHf34mq2GcJyz/gYFyLQ2INDhAylrZJ9mMWoW21mLBfZa0BUVPPMxVYrLjeiRe2Z7kWXOGnS0TFhQ==", - "dev": true, - "requires": { - "@jridgewell/trace-mapping": "^0.3.15", - "callsites": "^3.0.0", - "graceful-fs": "^4.2.9" - } - }, - "@jest/test-result": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.0.2.tgz", - "integrity": "sha512-b5rDc0lLL6Kx73LyCx6370k9uZ8o5UKdCpMS6Za3ke7H9y8PtAU305y6TeghpBmf2In8p/qqi3GpftgzijSsNw==", - "dev": true, - "requires": { - "@jest/console": "^29.0.2", - "@jest/types": "^29.0.2", - "@types/istanbul-lib-coverage": "^2.0.0", - "collect-v8-coverage": "^1.0.0" - } - }, - "@jest/test-sequencer": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.0.2.tgz", - "integrity": "sha512-fsyZqHBlXNMv5ZqjQwCuYa2pskXCO0DVxh5aaVCuAtwzHuYEGrhordyEncBLQNuCGQSYgElrEEmS+7wwFnnMKw==", - "dev": true, - "requires": { - "@jest/test-result": "^29.0.2", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.0.2", - "slash": "^3.0.0" - } - }, - "@jest/transform": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.0.2.tgz", - "integrity": "sha512-lajVQx2AnsR+Pa17q2zR7eikz2PkPs1+g/qPbZkqQATeS/s6eT55H+yHcsLfuI/0YQ/4VSBepSu3bOX+44q0aA==", - "dev": true, - "requires": { - "@babel/core": "^7.11.6", - "@jest/types": "^29.0.2", - "@jridgewell/trace-mapping": "^0.3.15", - "babel-plugin-istanbul": "^6.1.1", - "chalk": "^4.0.0", - "convert-source-map": "^1.4.0", - "fast-json-stable-stringify": "^2.1.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.0.2", - "jest-regex-util": "^29.0.0", - "jest-util": "^29.0.2", - "micromatch": "^4.0.4", - "pirates": "^4.0.4", - "slash": "^3.0.0", - "write-file-atomic": "^4.0.1" - } - }, - "@jest/types": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.0.2.tgz", - "integrity": "sha512-5WNMesBLmlkt1+fVkoCjHa0X3i3q8zc4QLTDkdHgCa2gyPZc7rdlZBWgVLqwS1860ZW5xJuCDwAzqbGaXIr/ew==", - "dev": true, - "requires": { - "@jest/schemas": "^29.0.0", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - } - }, - "@jridgewell/gen-mapping": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", - "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==", - "dev": true, - "requires": { - "@jridgewell/set-array": "^1.0.0", - "@jridgewell/sourcemap-codec": "^1.4.10" - } - }, - "@jridgewell/resolve-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", - "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", - "dev": true - }, - "@jridgewell/set-array": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", - "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", - "dev": true - }, - "@jridgewell/sourcemap-codec": { - "version": "1.4.14", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", - "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", - "dev": true - }, - "@jridgewell/trace-mapping": { - "version": "0.3.20", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz", - "integrity": "sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==", - "dev": true, - "requires": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, - "@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "requires": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - } - }, - "@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true - }, - "@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "requires": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - } - }, - "@sideway/address": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.4.tgz", - "integrity": "sha512-7vwq+rOHVWjyXxVlR76Agnvhy8I9rpzjosTESvmhNeXOXdZZB15Fl+TI9x1SiHZH5Jv2wTGduSxFDIaq0m3DUw==", - "dev": true, - "requires": { - "@hapi/hoek": "^9.0.0" - } - }, - "@sideway/formula": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.1.tgz", - "integrity": "sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==", - "dev": true - }, - "@sideway/pinpoint": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@sideway/pinpoint/-/pinpoint-2.0.0.tgz", - "integrity": "sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==", - "dev": true - }, - "@sinclair/typebox": { - "version": "0.24.35", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.35.tgz", - "integrity": "sha512-iN6ehuDndiTiDz2F+Orv/+oHJR+PrGv+38oghCddpsW4YEZl5qyLsWxSwYUWrKEOfjpGtXDFW6scJtjpzSLeSw==", - "dev": true - }, - "@sinonjs/commons": { - "version": "1.8.3", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz", - "integrity": "sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ==", - "dev": true, - "requires": { - "type-detect": "4.0.8" - } - }, - "@sinonjs/fake-timers": { - "version": "9.1.2", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-9.1.2.tgz", - "integrity": "sha512-BPS4ynJW/o92PUR4wgriz2Ud5gpST5vz6GQfMixEDK0Z8ZCUv2M7SkBLykH56T++Xs+8ln9zTGbOvNGIe02/jw==", - "dev": true, - "requires": { - "@sinonjs/commons": "^1.7.0" - } - }, - "@tootallnate/once": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", - "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", - "dev": true - }, - "@types/babel__core": { - "version": "7.1.19", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.19.tgz", - "integrity": "sha512-WEOTgRsbYkvA/KCsDwVEGkd7WAr1e3g31VHQ8zy5gul/V1qKullU/BU5I68X5v7V3GnB9eotmom4v5a5gjxorw==", - "dev": true, - "requires": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0", - "@types/babel__generator": "*", - "@types/babel__template": "*", - "@types/babel__traverse": "*" - } - }, - "@types/babel__generator": { - "version": "7.6.4", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.4.tgz", - "integrity": "sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==", - "dev": true, - "requires": { - "@babel/types": "^7.0.0" - } - }, - "@types/babel__template": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz", - "integrity": "sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==", - "dev": true, - "requires": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0" - } - }, - "@types/babel__traverse": { - "version": "7.18.1", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.18.1.tgz", - "integrity": "sha512-FSdLaZh2UxaMuLp9lixWaHq/golWTRWOnRsAXzDTDSDOQLuZb1nsdCt6pJSPWSEQt2eFZ2YVk3oYhn+1kLMeMA==", - "dev": true, - "requires": { - "@babel/types": "^7.3.0" - } - }, - "@types/graceful-fs": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz", - "integrity": "sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, - "@types/istanbul-lib-coverage": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", - "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==", - "dev": true - }, - "@types/istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "*" - } - }, - "@types/istanbul-reports": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", - "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", - "dev": true, - "requires": { - "@types/istanbul-lib-report": "*" - } - }, - "@types/jsdom": { - "version": "20.0.0", - "resolved": "https://registry.npmjs.org/@types/jsdom/-/jsdom-20.0.0.tgz", - "integrity": "sha512-YfAchFs0yM1QPDrLm2VHe+WHGtqms3NXnXAMolrgrVP6fgBHHXy1ozAbo/dFtPNtZC/m66bPiCTWYmqp1F14gA==", - "dev": true, - "requires": { - "@types/node": "*", - "@types/tough-cookie": "*", - "parse5": "^7.0.0" - } - }, - "@types/json-schema": { - "version": "7.0.11", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", - "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", - "dev": true - }, - "@types/node": { - "version": "18.7.15", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.7.15.tgz", - "integrity": "sha512-XnjpaI8Bgc3eBag2Aw4t2Uj/49lLBSStHWfqKvIuXD7FIrZyMLWp8KuAFHAqxMZYTF9l08N1ctUn9YNybZJVmQ==", - "dev": true - }, - "@types/prettier": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.0.tgz", - "integrity": "sha512-RI1L7N4JnW5gQw2spvL7Sllfuf1SaHdrZpCHiBlCXjIlufi1SMNnbu2teze3/QE67Fg2tBlH7W+mi4hVNk4p0A==", - "dev": true - }, - "@types/stack-utils": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", - "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", - "dev": true - }, - "@types/tough-cookie": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.2.tgz", - "integrity": "sha512-Q5vtl1W5ue16D+nIaW8JWebSSraJVlK+EthKn7e7UcD4KWsaSJ8BqGPXNaPghgtcn/fhvrN17Tv8ksUsQpiplw==", - "dev": true - }, - "@types/yargs": { - "version": "17.0.12", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.12.tgz", - "integrity": "sha512-Nz4MPhecOFArtm81gFQvQqdV7XYCrWKx5uUt6GNHredFHn1i2mtWqXTON7EPXMtNi1qjtjEM/VCHDhcHsAMLXQ==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - }, - "@types/yargs-parser": { - "version": "21.0.0", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz", - "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==", - "dev": true - }, - "@typescript-eslint/scope-manager": { - "version": "5.27.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.27.1.tgz", - "integrity": "sha512-fQEOSa/QroWE6fAEg+bJxtRZJTH8NTskggybogHt4H9Da8zd4cJji76gA5SBlR0MgtwF7rebxTbDKB49YUCpAg==", - "dev": true, - "requires": { - "@typescript-eslint/types": "5.27.1", - "@typescript-eslint/visitor-keys": "5.27.1" - } - }, - "@typescript-eslint/types": { - "version": "5.27.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.27.1.tgz", - "integrity": "sha512-LgogNVkBhCTZU/m8XgEYIWICD6m4dmEDbKXESCbqOXfKZxRKeqpiJXQIErv66sdopRKZPo5l32ymNqibYEH/xg==", - "dev": true - }, - "@typescript-eslint/typescript-estree": { - "version": "5.27.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.27.1.tgz", - "integrity": "sha512-DnZvvq3TAJ5ke+hk0LklvxwYsnXpRdqUY5gaVS0D4raKtbznPz71UJGnPTHEFo0GDxqLOLdMkkmVZjSpET1hFw==", - "dev": true, - "requires": { - "@typescript-eslint/types": "5.27.1", - "@typescript-eslint/visitor-keys": "5.27.1", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "semver": "^7.3.7", - "tsutils": "^3.21.0" - } - }, - "@typescript-eslint/utils": { - "version": "5.27.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.27.1.tgz", - "integrity": "sha512-mZ9WEn1ZLDaVrhRaYgzbkXBkTPghPFsup8zDbbsYTxC5OmqrFE7skkKS/sraVsLP3TcT3Ki5CSyEFBRkLH/H/w==", - "dev": true, - "requires": { - "@types/json-schema": "^7.0.9", - "@typescript-eslint/scope-manager": "5.27.1", - "@typescript-eslint/types": "5.27.1", - "@typescript-eslint/typescript-estree": "5.27.1", - "eslint-scope": "^5.1.1", - "eslint-utils": "^3.0.0" - }, - "dependencies": { - "eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dev": true, - "requires": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - } - }, - "estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true - } - } - }, - "@typescript-eslint/visitor-keys": { - "version": "5.27.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.27.1.tgz", - "integrity": "sha512-xYs6ffo01nhdJgPieyk7HAOpjhTsx7r/oB9LWEhwAXgwn33tkr+W8DI2ChboqhZlC4q3TC6geDYPoiX8ROqyOQ==", - "dev": true, - "requires": { - "@typescript-eslint/types": "5.27.1", - "eslint-visitor-keys": "^3.3.0" - } - }, - "abab": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", - "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==", - "dev": true - }, - "acorn": { - "version": "8.8.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz", - "integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==", - "dev": true - }, - "acorn-globals": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-6.0.0.tgz", - "integrity": "sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg==", - "dev": true, - "requires": { - "acorn": "^7.1.1", - "acorn-walk": "^7.1.1" - }, - "dependencies": { - "acorn": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", - "dev": true - } - } - }, - "acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "requires": {} - }, - "acorn-walk": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", - "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", - "dev": true - }, - "agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "dev": true, - "requires": { - "debug": "4" - } - }, - "ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, - "ansi-escapes": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", - "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", - "dev": true, - "requires": { - "type-fest": "^0.21.3" - }, - "dependencies": { - "type-fest": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", - "dev": true - } - } - }, - "ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true - }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "anymatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", - "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", - "dev": true, - "requires": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - } - }, - "argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true - }, - "asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", - "dev": true - }, - "axios": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.25.0.tgz", - "integrity": "sha512-cD8FOb0tRH3uuEe6+evtAbgJtfxr7ly3fQjYcMcuPlgkwVS9xboaVIpcDV+cYQe+yGykgwZCs1pzjntcGa6l5g==", - "dev": true, - "requires": { - "follow-redirects": "^1.14.7" - } - }, - "babel-jest": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.0.2.tgz", - "integrity": "sha512-yTu4/WSi/HzarjQtrJSwV+/0maoNt+iP0DmpvFJdv9yY+5BuNle8TbheHzzcSWj5gIHfuhpbLYHWRDYhWKyeKQ==", - "dev": true, - "requires": { - "@jest/transform": "^29.0.2", - "@types/babel__core": "^7.1.14", - "babel-plugin-istanbul": "^6.1.1", - "babel-preset-jest": "^29.0.2", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "slash": "^3.0.0" - } - }, - "babel-plugin-istanbul": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", - "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@istanbuljs/load-nyc-config": "^1.0.0", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-instrument": "^5.0.4", - "test-exclude": "^6.0.0" - } - }, - "babel-plugin-jest-hoist": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.0.2.tgz", - "integrity": "sha512-eBr2ynAEFjcebVvu8Ktx580BD1QKCrBG1XwEUTXJe285p9HA/4hOhfWCFRQhTKSyBV0VzjhG7H91Eifz9s29hg==", - "dev": true, - "requires": { - "@babel/template": "^7.3.3", - "@babel/types": "^7.3.3", - "@types/babel__core": "^7.1.14", - "@types/babel__traverse": "^7.0.6" - } - }, - "babel-preset-current-node-syntax": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", - "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", - "dev": true, - "requires": { - "@babel/plugin-syntax-async-generators": "^7.8.4", - "@babel/plugin-syntax-bigint": "^7.8.3", - "@babel/plugin-syntax-class-properties": "^7.8.3", - "@babel/plugin-syntax-import-meta": "^7.8.3", - "@babel/plugin-syntax-json-strings": "^7.8.3", - "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.8.3", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", - "@babel/plugin-syntax-optional-chaining": "^7.8.3", - "@babel/plugin-syntax-top-level-await": "^7.8.3" - } - }, - "babel-preset-jest": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.0.2.tgz", - "integrity": "sha512-BeVXp7rH5TK96ofyEnHjznjLMQ2nAeDJ+QzxKnHAAMs0RgrQsCywjAN8m4mOm5Di0pxU//3AoEeJJrerMH5UeA==", - "dev": true, - "requires": { - "babel-plugin-jest-hoist": "^29.0.2", - "babel-preset-current-node-syntax": "^1.0.0" - } - }, - "balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "requires": { - "fill-range": "^7.0.1" - } - }, - "browser-process-hrtime": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz", - "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==", - "dev": true - }, - "browserslist": { - "version": "4.21.3", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.3.tgz", - "integrity": "sha512-898rgRXLAyRkM1GryrrBHGkqA5hlpkV5MhtZwg9QXeiyLUYs2k00Un05aX5l2/yJIOObYKOpS2JNo8nJDE7fWQ==", - "dev": true, - "requires": { - "caniuse-lite": "^1.0.30001370", - "electron-to-chromium": "^1.4.202", - "node-releases": "^2.0.6", - "update-browserslist-db": "^1.0.5" - } - }, - "bser": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", - "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", - "dev": true, - "requires": { - "node-int64": "^0.4.0" - } - }, - "buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true - }, - "callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true - }, - "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true - }, - "caniuse-lite": { - "version": "1.0.30001390", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001390.tgz", - "integrity": "sha512-sS4CaUM+/+vqQUlCvCJ2WtDlV81aWtHhqeEVkLokVJJa3ViN4zDxAGfq9R8i1m90uGHxo99cy10Od+lvn3hf0g==", - "dev": true - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "char-regex": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", - "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", - "dev": true - }, - "ci-info": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.3.2.tgz", - "integrity": "sha512-xmDt/QIAdeZ9+nfdPsaBCpMvHNLFiLdjj59qjqn+6iPe6YmHGQ35sBnQ8uslRBXFmXkiZQOJRjvQeoGppoTjjg==", - "dev": true - }, - "cjs-module-lexer": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz", - "integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==", - "dev": true - }, - "cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "dev": true, - "requires": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } - }, - "co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", - "dev": true - }, - "collect-v8-coverage": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz", - "integrity": "sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==", - "dev": true - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dev": true, - "requires": { - "delayed-stream": "~1.0.0" - } - }, - "commander": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz", - "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==", - "dev": true - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true - }, - "convert-source-map": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", - "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.1" - } - }, - "cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "requires": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - } - }, - "cssom": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.5.0.tgz", - "integrity": "sha512-iKuQcq+NdHqlAcwUY0o/HL69XQrUaQdMjmStJ8JFmUaiiQErlhrmuigkg/CU4E2J0IyUKUrMAgl36TvN67MqTw==", - "dev": true - }, - "cssstyle": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", - "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", - "dev": true, - "requires": { - "cssom": "~0.3.6" - }, - "dependencies": { - "cssom": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", - "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", - "dev": true - } - } - }, - "cwd": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/cwd/-/cwd-0.10.0.tgz", - "integrity": "sha512-YGZxdTTL9lmLkCUTpg4j0zQ7IhRB5ZmqNBbGCl3Tg6MP/d5/6sY7L5mmTjzbc6JKgVZYiqTQTNhPFsbXNGlRaA==", - "dev": true, - "requires": { - "find-pkg": "^0.1.2", - "fs-exists-sync": "^0.1.0" - } - }, - "data-uri-to-buffer": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.0.tgz", - "integrity": "sha512-Vr3mLBA8qWmcuschSLAOogKgQ/Jwxulv3RNE4FXnYWRGujzrRWQI4m12fQqRkwX06C0KanhLr4hK+GydchZsaA==", - "dev": true - }, - "data-urls": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-3.0.2.tgz", - "integrity": "sha512-Jy/tj3ldjZJo63sVAvg6LHt2mHvl4V6AgRAmNDtLdm7faqtsx+aJG42rsyCo9JCoRVKwPFzKlIPx3DIibwSIaQ==", - "dev": true, - "requires": { - "abab": "^2.0.6", - "whatwg-mimetype": "^3.0.0", - "whatwg-url": "^11.0.0" - } - }, - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "decimal.js": { - "version": "10.4.0", - "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.0.tgz", - "integrity": "sha512-Nv6ENEzyPQ6AItkGwLE2PGKinZZ9g59vSh2BeH6NqPu0OTKZ5ruJsVqh/orbAnqXc9pBbgXAIrc2EyaCj8NpGg==", - "dev": true - }, - "dedent": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", - "integrity": "sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==", - "dev": true - }, - "deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true - }, - "deepmerge": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", - "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", - "dev": true - }, - "delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "dev": true - }, - "detect-newline": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", - "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", - "dev": true - }, - "diff-sequences": { - "version": "29.0.0", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.0.0.tgz", - "integrity": "sha512-7Qe/zd1wxSDL4D/X/FPjOMB+ZMDt71W94KYaq05I2l0oQqgXgs7s4ftYYmV38gBSrPz2vcygxfs1xn0FT+rKNA==", - "dev": true - }, - "dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, - "requires": { - "path-type": "^4.0.0" - } - }, - "doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "requires": { - "esutils": "^2.0.2" - } - }, - "domexception": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/domexception/-/domexception-4.0.0.tgz", - "integrity": "sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw==", - "dev": true, - "requires": { - "webidl-conversions": "^7.0.0" - } - }, - "electron-to-chromium": { - "version": "1.4.242", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.242.tgz", - "integrity": "sha512-nPdgMWtjjWGCtreW/2adkrB2jyHjClo9PtVhR6rW+oxa4E4Wom642Tn+5LslHP3XPL5MCpkn5/UEY60EXylNeQ==", - "dev": true - }, - "emittery": { - "version": "0.10.2", - "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.10.2.tgz", - "integrity": "sha512-aITqOwnLanpHLNXZJENbOgjUBeHocD+xsSJmNrjovKBW5HbSpW3d1pEls7GFQPUWXiwG9+0P4GtHfEqC/4M0Iw==", - "dev": true - }, - "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==", - "dev": true - }, - "entities": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-4.4.0.tgz", - "integrity": "sha512-oYp7156SP8LkeGD0GF85ad1X9Ai79WtRsZ2gxJqtBuzH+98YUV6jkHEKlZkMbcrjJjIVJNIDP/3WL9wQkoPbWA==", - "dev": true - }, - "error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, - "requires": { - "is-arrayish": "^0.2.1" - } - }, - "escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "dev": true - }, - "escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true - }, - "escodegen": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.0.0.tgz", - "integrity": "sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw==", - "dev": true, - "requires": { - "esprima": "^4.0.1", - "estraverse": "^5.2.0", - "esutils": "^2.0.2", - "optionator": "^0.8.1", - "source-map": "~0.6.1" - }, - "dependencies": { - "levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==", - "dev": true, - "requires": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" - } - }, - "optionator": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", - "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", - "dev": true, - "requires": { - "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.6", - "levn": "~0.3.0", - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2", - "word-wrap": "~1.2.3" - } - }, - "prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==", - "dev": true - }, - "type-check": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==", - "dev": true, - "requires": { - "prelude-ls": "~1.1.2" - } - } - } - }, - "eslint": { - "version": "8.23.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.23.0.tgz", - "integrity": "sha512-pBG/XOn0MsJcKcTRLr27S5HpzQo4kLr+HjLQIyK4EiCsijDl/TB+h5uEuJU6bQ8Edvwz1XWOjpaP2qgnXGpTcA==", - "dev": true, - "requires": { - "@eslint/eslintrc": "^1.3.1", - "@humanwhocodes/config-array": "^0.10.4", - "@humanwhocodes/gitignore-to-minimatch": "^1.0.2", - "@humanwhocodes/module-importer": "^1.0.1", - "ajv": "^6.10.0", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.3.2", - "doctrine": "^3.0.0", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.1.1", - "eslint-utils": "^3.0.0", - "eslint-visitor-keys": "^3.3.0", - "espree": "^9.4.0", - "esquery": "^1.4.0", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "find-up": "^5.0.0", - "functional-red-black-tree": "^1.0.1", - "glob-parent": "^6.0.1", - "globals": "^13.15.0", - "globby": "^11.1.0", - "grapheme-splitter": "^1.0.4", - "ignore": "^5.2.0", - "import-fresh": "^3.0.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "js-yaml": "^4.1.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.1", - "regexpp": "^3.2.0", - "strip-ansi": "^6.0.1", - "strip-json-comments": "^3.1.0", - "text-table": "^0.2.0" - } - }, - "eslint-plugin-jest": { - "version": "27.0.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-27.0.1.tgz", - "integrity": "sha512-LosUsrkwVSs/8Z/I8Hqn5vWgTEsHrfIquDEKOsV8/cl+gbFR4tiRCE1AimEotsHjSC0Rx1tYm6vPhw8C3ktmmg==", - "dev": true, - "requires": { - "@typescript-eslint/utils": "^5.10.0" - } - }, - "eslint-scope": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", - "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", - "dev": true, - "requires": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - } - }, - "eslint-utils": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", - "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", - "dev": true, - "requires": { - "eslint-visitor-keys": "^2.0.0" - }, - "dependencies": { - "eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", - "dev": true - } - } - }, - "eslint-visitor-keys": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", - "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", - "dev": true - }, - "espree": { - "version": "9.4.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.0.tgz", - "integrity": "sha512-DQmnRpLj7f6TgN/NYb0MTzJXL+vJF9h3pHy4JhCIs3zwcgez8xmGg3sXHcEO97BrmO2OSvCwMdfdlyl+E9KjOw==", - "dev": true, - "requires": { - "acorn": "^8.8.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.3.0" - } - }, - "esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true - }, - "esquery": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", - "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", - "dev": true, - "requires": { - "estraverse": "^5.1.0" - } - }, - "esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "requires": { - "estraverse": "^5.2.0" - } - }, - "estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true - }, - "esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true - }, - "execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", - "dev": true, - "requires": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" - } - }, - "exit": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", - "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", - "dev": true - }, - "expand-tilde": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-1.2.2.tgz", - "integrity": "sha512-rtmc+cjLZqnu9dSYosX9EWmSJhTwpACgJQTfj4hgg2JjOD/6SIQalZrt4a3aQeh++oNxkazcaxrhPUj6+g5G/Q==", - "dev": true, - "requires": { - "os-homedir": "^1.0.1" - } - }, - "expect": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/expect/-/expect-29.0.2.tgz", - "integrity": "sha512-JeJlAiLKn4aApT4pzUXBVxl3NaZidWIOdg//smaIlP9ZMBDkHZGFd9ubphUZP9pUyDEo7bC6M0IIZR51o75qQw==", - "dev": true, - "requires": { - "@jest/expect-utils": "^29.0.2", - "jest-get-type": "^29.0.0", - "jest-matcher-utils": "^29.0.2", - "jest-message-util": "^29.0.2", - "jest-util": "^29.0.2" - } - }, - "fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true - }, - "fast-glob": { - "version": "3.2.11", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", - "integrity": "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==", - "dev": true, - "requires": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - }, - "dependencies": { - "glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "requires": { - "is-glob": "^4.0.1" - } - } - } - }, - "fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true - }, - "fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true - }, - "fastq": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", - "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", - "dev": true, - "requires": { - "reusify": "^1.0.4" - } - }, - "fb-watchman": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.1.tgz", - "integrity": "sha512-DkPJKQeY6kKwmuMretBhr7G6Vodr7bFwDYTXIkfG1gjvNpaxBTQV3PbXg6bR1c1UP4jPOX0jHUbbHANL9vRjVg==", - "dev": true, - "requires": { - "bser": "2.1.1" - } - }, - "fetch-blob": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.1.5.tgz", - "integrity": "sha512-N64ZpKqoLejlrwkIAnb9iLSA3Vx/kjgzpcDhygcqJ2KKjky8nCgUQ+dzXtbrLaWZGZNmNfQTsiQ0weZ1svglHg==", - "dev": true, - "requires": { - "node-domexception": "^1.0.0", - "web-streams-polyfill": "^3.0.3" - } - }, - "file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", - "dev": true, - "requires": { - "flat-cache": "^3.0.4" - } - }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "requires": { - "to-regex-range": "^5.0.1" - } - }, - "find-file-up": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/find-file-up/-/find-file-up-0.1.3.tgz", - "integrity": "sha512-mBxmNbVyjg1LQIIpgO8hN+ybWBgDQK8qjht+EbrTCGmmPV/sc7RF1i9stPTD6bpvXZywBdrwRYxhSdJv867L6A==", - "dev": true, - "requires": { - "fs-exists-sync": "^0.1.0", - "resolve-dir": "^0.1.0" - } - }, - "find-pkg": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/find-pkg/-/find-pkg-0.1.2.tgz", - "integrity": "sha512-0rnQWcFwZr7eO0513HahrWafsc3CTFioEB7DRiEYCUM/70QXSY8f3mCST17HXLcPvEhzH/Ty/Bxd72ZZsr/yvw==", - "dev": true, - "requires": { - "find-file-up": "^0.1.2" - } - }, - "find-process": { - "version": "1.4.7", - "resolved": "https://registry.npmjs.org/find-process/-/find-process-1.4.7.tgz", - "integrity": "sha512-/U4CYp1214Xrp3u3Fqr9yNynUrr5Le4y0SsJh2lMDDSbpwYSz3M2SMWQC+wqcx79cN8PQtHQIL8KnuY9M66fdg==", - "dev": true, - "requires": { - "chalk": "^4.0.0", - "commander": "^5.1.0", - "debug": "^4.1.1" - } - }, - "find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "requires": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - } - }, - "flat-cache": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", - "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", - "dev": true, - "requires": { - "flatted": "^3.1.0", - "rimraf": "^3.0.2" - } - }, - "flatted": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.5.tgz", - "integrity": "sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg==", - "dev": true - }, - "follow-redirects": { - "version": "1.15.1", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.1.tgz", - "integrity": "sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA==", - "dev": true - }, - "form-data": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", - "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", - "dev": true, - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - } - }, - "formdata-polyfill": { - "version": "4.0.10", - "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", - "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", - "dev": true, - "requires": { - "fetch-blob": "^3.1.2" - } - }, - "fs-exists-sync": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/fs-exists-sync/-/fs-exists-sync-0.1.0.tgz", - "integrity": "sha512-cR/vflFyPZtrN6b38ZyWxpWdhlXrzZEBawlpBQMq7033xVY7/kg0GDMBK5jg8lDYQckdJ5x/YC88lM3C7VMsLg==", - "dev": true - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true - }, - "fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, - "optional": true - }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, - "functional-red-black-tree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==", - "dev": true - }, - "gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true - }, - "get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true - }, - "get-package-type": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", - "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", - "dev": true - }, - "get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "dev": true - }, - "glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, - "requires": { - "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" - } - }, - "glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "requires": { - "is-glob": "^4.0.3" - } - }, - "global-modules": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-0.2.3.tgz", - "integrity": "sha512-JeXuCbvYzYXcwE6acL9V2bAOeSIGl4dD+iwLY9iUx2VBJJ80R18HCn+JCwHM9Oegdfya3lEkGCdaRkSyc10hDA==", - "dev": true, - "requires": { - "global-prefix": "^0.1.4", - "is-windows": "^0.2.0" - } - }, - "global-prefix": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-0.1.5.tgz", - "integrity": "sha512-gOPiyxcD9dJGCEArAhF4Hd0BAqvAe/JzERP7tYumE4yIkmIedPUVXcJFWbV3/p/ovIIvKjkrTk+f1UVkq7vvbw==", - "dev": true, - "requires": { - "homedir-polyfill": "^1.0.0", - "ini": "^1.3.4", - "is-windows": "^0.2.0", - "which": "^1.2.12" - }, - "dependencies": { - "which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - } - } - }, - "globals": { - "version": "13.17.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.17.0.tgz", - "integrity": "sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw==", - "dev": true, - "requires": { - "type-fest": "^0.20.2" - } - }, - "globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "dev": true, - "requires": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - } - }, - "graceful-fs": { - "version": "4.2.10", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", - "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", - "dev": true - }, - "grapheme-splitter": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", - "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", - "dev": true - }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "requires": { - "function-bind": "^1.1.1" - } - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "homedir-polyfill": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", - "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==", - "dev": true, - "requires": { - "parse-passwd": "^1.0.0" - } - }, - "html-encoding-sniffer": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz", - "integrity": "sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==", - "dev": true, - "requires": { - "whatwg-encoding": "^2.0.0" - } - }, - "html-escaper": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", - "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", - "dev": true - }, - "http-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", - "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", - "dev": true, - "requires": { - "@tootallnate/once": "2", - "agent-base": "6", - "debug": "4" - } - }, - "https-proxy-agent": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", - "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", - "dev": true, - "requires": { - "agent-base": "6", - "debug": "4" - } - }, - "human-signals": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", - "dev": true - }, - "iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "dev": true, - "requires": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - } - }, - "ignore": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", - "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", - "dev": true - }, - "import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "requires": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - } - }, - "import-local": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", - "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", - "dev": true, - "requires": { - "pkg-dir": "^4.2.0", - "resolve-cwd": "^3.0.0" - } - }, - "imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "dev": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, - "ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "dev": true - }, - "is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "dev": true - }, - "is-core-module": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.10.0.tgz", - "integrity": "sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg==", - "dev": true, - "requires": { - "has": "^1.0.3" - } - }, - "is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true - }, - "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==", - "dev": true - }, - "is-generator-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", - "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", - "dev": true - }, - "is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "requires": { - "is-extglob": "^2.1.1" - } - }, - "is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true - }, - "is-potential-custom-element-name": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", - "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", - "dev": true - }, - "is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true - }, - "is-windows": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-0.2.0.tgz", - "integrity": "sha512-n67eJYmXbniZB7RF4I/FTjK1s6RPOCTxhYrVYLRaCt3lF0mpWZPKr3T2LSZAqyjQsxR2qMmGYXXzK0YWwcPM1Q==", - "dev": true - }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true - }, - "istanbul-lib-coverage": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", - "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", - "dev": true - }, - "istanbul-lib-instrument": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.0.tgz", - "integrity": "sha512-6Lthe1hqXHBNsqvgDzGO6l03XNeu3CrG4RqQ1KM9+l5+jNGpEJfIELx1NS3SEHmJQA8np/u+E4EPRKRiu6m19A==", - "dev": true, - "requires": { - "@babel/core": "^7.12.3", - "@babel/parser": "^7.14.7", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.2.0", - "semver": "^6.3.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } - } - }, - "istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", - "dev": true, - "requires": { - "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^3.0.0", - "supports-color": "^7.1.0" - } - }, - "istanbul-lib-source-maps": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", - "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", - "dev": true, - "requires": { - "debug": "^4.1.1", - "istanbul-lib-coverage": "^3.0.0", - "source-map": "^0.6.1" - } - }, - "istanbul-reports": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz", - "integrity": "sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==", - "dev": true, - "requires": { - "html-escaper": "^2.0.0", - "istanbul-lib-report": "^3.0.0" - } - }, - "jest": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/jest/-/jest-29.0.2.tgz", - "integrity": "sha512-enziNbNUmXTcTaTP/Uq5rV91r0Yqy2UKzLUIabxMpGm9YHz8qpbJhiRnNVNvm6vzWfzt/0o97NEHH8/3udoClA==", - "dev": true, - "requires": { - "@jest/core": "^29.0.2", - "@jest/types": "^29.0.2", - "import-local": "^3.0.2", - "jest-cli": "^29.0.2" - } - }, - "jest-changed-files": { - "version": "29.0.0", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.0.0.tgz", - "integrity": "sha512-28/iDMDrUpGoCitTURuDqUzWQoWmOmOKOFST1mi2lwh62X4BFf6khgH3uSuo1e49X/UDjuApAj3w0wLOex4VPQ==", - "dev": true, - "requires": { - "execa": "^5.0.0", - "p-limit": "^3.1.0" - } - }, - "jest-circus": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.0.2.tgz", - "integrity": "sha512-YTPEsoE1P1X0bcyDQi3QIkpt2Wl9om9k2DQRuLFdS5x8VvAKSdYAVJufgvudhnKgM8WHvvAzhBE+1DRQB8x1CQ==", - "dev": true, - "requires": { - "@jest/environment": "^29.0.2", - "@jest/expect": "^29.0.2", - "@jest/test-result": "^29.0.2", - "@jest/types": "^29.0.2", - "@types/node": "*", - "chalk": "^4.0.0", - "co": "^4.6.0", - "dedent": "^0.7.0", - "is-generator-fn": "^2.0.0", - "jest-each": "^29.0.2", - "jest-matcher-utils": "^29.0.2", - "jest-message-util": "^29.0.2", - "jest-runtime": "^29.0.2", - "jest-snapshot": "^29.0.2", - "jest-util": "^29.0.2", - "p-limit": "^3.1.0", - "pretty-format": "^29.0.2", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" - } - }, - "jest-cli": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.0.2.tgz", - "integrity": "sha512-tlf8b+4KcUbBGr25cywIi3+rbZ4+G+SiG8SvY552m9sRZbXPafdmQRyeVE/C/R8K+TiBAMrTIUmV2SlStRJ40g==", - "dev": true, - "requires": { - "@jest/core": "^29.0.2", - "@jest/test-result": "^29.0.2", - "@jest/types": "^29.0.2", - "chalk": "^4.0.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.9", - "import-local": "^3.0.2", - "jest-config": "^29.0.2", - "jest-util": "^29.0.2", - "jest-validate": "^29.0.2", - "prompts": "^2.0.1", - "yargs": "^17.3.1" - } - }, - "jest-config": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.0.2.tgz", - "integrity": "sha512-RU4gzeUNZAFktYVzDGimDxeYoaiTnH100jkYYZgldqFamaZukF0IqmFx8+QrzVeEWccYg10EEJT3ox1Dq5b74w==", - "dev": true, - "requires": { - "@babel/core": "^7.11.6", - "@jest/test-sequencer": "^29.0.2", - "@jest/types": "^29.0.2", - "babel-jest": "^29.0.2", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "deepmerge": "^4.2.2", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "jest-circus": "^29.0.2", - "jest-environment-node": "^29.0.2", - "jest-get-type": "^29.0.0", - "jest-regex-util": "^29.0.0", - "jest-resolve": "^29.0.2", - "jest-runner": "^29.0.2", - "jest-util": "^29.0.2", - "jest-validate": "^29.0.2", - "micromatch": "^4.0.4", - "parse-json": "^5.2.0", - "pretty-format": "^29.0.2", - "slash": "^3.0.0", - "strip-json-comments": "^3.1.1" - } - }, - "jest-dev-server": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/jest-dev-server/-/jest-dev-server-6.1.1.tgz", - "integrity": "sha512-z5LnaGDvlIkdMv/rppSO4+rq+GyQKf1xI9oiBxf9/2EBeN2hxRaWiMvaLNDnHPZj2PAhBXsycrKslDDoZO2Xtw==", - "dev": true, - "requires": { - "chalk": "^4.1.2", - "cwd": "^0.10.0", - "find-process": "^1.4.7", - "prompts": "^2.4.2", - "spawnd": "^6.0.2", - "tree-kill": "^1.2.2", - "wait-on": "^6.0.1" - } - }, - "jest-diff": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.0.2.tgz", - "integrity": "sha512-b9l9970sa1rMXH1owp2Woprmy42qIwwll/htsw4Gf7+WuSp5bZxNhkKHDuCGKL+HoHn1KhcC+tNEeAPYBkD2Jg==", - "dev": true, - "requires": { - "chalk": "^4.0.0", - "diff-sequences": "^29.0.0", - "jest-get-type": "^29.0.0", - "pretty-format": "^29.0.2" - } - }, - "jest-docblock": { - "version": "29.0.0", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.0.0.tgz", - "integrity": "sha512-s5Kpra/kLzbqu9dEjov30kj1n4tfu3e7Pl8v+f8jOkeWNqM6Ds8jRaJfZow3ducoQUrf2Z4rs2N5S3zXnb83gw==", - "dev": true, - "requires": { - "detect-newline": "^3.0.0" - } - }, - "jest-each": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.0.2.tgz", - "integrity": "sha512-+sA9YjrJl35iCg0W0VCrgCVj+wGhDrrKQ+YAqJ/DHBC4gcDFAeePtRRhpJnX9gvOZ63G7gt52pwp2PesuSEx0Q==", - "dev": true, - "requires": { - "@jest/types": "^29.0.2", - "chalk": "^4.0.0", - "jest-get-type": "^29.0.0", - "jest-util": "^29.0.2", - "pretty-format": "^29.0.2" - } - }, - "jest-environment-jsdom": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-29.0.2.tgz", - "integrity": "sha512-hWqC9FQI5yT04lTd4VJnzT5QObxq0xrSrqpGkqsYfxPeJYjyhriI7W2oJC5HZ1UbhnvA+8GS1nzgPsstvRpdVw==", - "dev": true, - "requires": { - "@jest/environment": "^29.0.2", - "@jest/fake-timers": "^29.0.2", - "@jest/types": "^29.0.2", - "@types/jsdom": "^20.0.0", - "@types/node": "*", - "jest-mock": "^29.0.2", - "jest-util": "^29.0.2", - "jsdom": "^20.0.0" - } - }, - "jest-environment-node": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.0.2.tgz", - "integrity": "sha512-4Fv8GXVCToRlMzDO94gvA8iOzKxQ7rhAbs8L+j8GPyTxGuUiYkV+63LecGeVdVhsL2KXih1sKnoqmH6tp89J7Q==", - "dev": true, - "requires": { - "@jest/environment": "^29.0.2", - "@jest/fake-timers": "^29.0.2", - "@jest/types": "^29.0.2", - "@types/node": "*", - "jest-mock": "^29.0.2", - "jest-util": "^29.0.2" - } - }, - "jest-get-type": { - "version": "29.0.0", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.0.0.tgz", - "integrity": "sha512-83X19z/HuLKYXYHskZlBAShO7UfLFXu/vWajw9ZNJASN32li8yHMaVGAQqxFW1RCFOkB7cubaL6FaJVQqqJLSw==", - "dev": true - }, - "jest-haste-map": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.0.2.tgz", - "integrity": "sha512-SOorh2ysQ0fe8gsF4gaUDhoMIWAvi2hXOkwThEO48qT3JqA8GLAUieQcIvdSEd6M0scRDe1PVmKc5tXR3Z0U0A==", - "dev": true, - "requires": { - "@jest/types": "^29.0.2", - "@types/graceful-fs": "^4.1.3", - "@types/node": "*", - "anymatch": "^3.0.3", - "fb-watchman": "^2.0.0", - "fsevents": "^2.3.2", - "graceful-fs": "^4.2.9", - "jest-regex-util": "^29.0.0", - "jest-util": "^29.0.2", - "jest-worker": "^29.0.2", - "micromatch": "^4.0.4", - "walker": "^1.0.8" - } - }, - "jest-leak-detector": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.0.2.tgz", - "integrity": "sha512-5f0493qDeAxjUldkBSQg5D1cLadRgZVyWpTQvfJeQwQUpHQInE21AyVHVv64M7P2Ue8Z5EZ4BAcoDS/dSPPgMw==", - "dev": true, - "requires": { - "jest-get-type": "^29.0.0", - "pretty-format": "^29.0.2" - } - }, - "jest-matcher-utils": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.0.2.tgz", - "integrity": "sha512-s62YkHFBfAx0JLA2QX1BlnCRFwHRobwAv2KP1+YhjzF6ZCbCVrf1sG8UJyn62ZUsDaQKpoo86XMTjkUyO5aWmQ==", - "dev": true, - "requires": { - "chalk": "^4.0.0", - "jest-diff": "^29.0.2", - "jest-get-type": "^29.0.0", - "pretty-format": "^29.0.2" - } - }, - "jest-message-util": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.0.2.tgz", - "integrity": "sha512-kcJAgms3ckJV0wUoLsAM40xAhY+pb9FVSZwicjFU9PFkaTNmqh9xd99/CzKse48wPM1ANUQKmp03/DpkY+lGrA==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.12.13", - "@jest/types": "^29.0.2", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "micromatch": "^4.0.4", - "pretty-format": "^29.0.2", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" - } - }, - "jest-mock": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.0.2.tgz", - "integrity": "sha512-giWXOIT23UCxHCN2VUfUJ0Q7SmiqQwfSFXlCaIhW5anITpNQ+3vuLPQdKt5wkuwM37GrbFyHIClce8AAK9ft9g==", - "dev": true, - "requires": { - "@jest/types": "^29.0.2", - "@types/node": "*" - } - }, - "jest-pnp-resolver": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz", - "integrity": "sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w==", - "dev": true, - "requires": {} - }, - "jest-regex-util": { - "version": "29.0.0", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.0.0.tgz", - "integrity": "sha512-BV7VW7Sy0fInHWN93MMPtlClweYv2qrSCwfeFWmpribGZtQPWNvRSq9XOVgOEjU1iBGRKXUZil0o2AH7Iy9Lug==", - "dev": true - }, - "jest-resolve": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.0.2.tgz", - "integrity": "sha512-V3uLjSA+EHxLtjIDKTBXnY71hyx+8lusCqPXvqzkFO1uCGvVpjBfuOyp+KOLBNSuY61kM2jhepiMwt4eiJS+Vw==", - "dev": true, - "requires": { - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.0.2", - "jest-pnp-resolver": "^1.2.2", - "jest-util": "^29.0.2", - "jest-validate": "^29.0.2", - "resolve": "^1.20.0", - "resolve.exports": "^1.1.0", - "slash": "^3.0.0" - } - }, - "jest-resolve-dependencies": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.0.2.tgz", - "integrity": "sha512-fSAu6eIG7wtGdnPJUkVVdILGzYAP9Dj/4+zvC8BrGe8msaUMJ9JeygU0Hf9+Uor6/icbuuzQn5See1uajLnAqg==", - "dev": true, - "requires": { - "jest-regex-util": "^29.0.0", - "jest-snapshot": "^29.0.2" - } - }, - "jest-runner": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.0.2.tgz", - "integrity": "sha512-+D82iPZejI8t+SfduOO1deahC/QgLFf8aJBO++Znz3l2ETtOMdM7K4ATsGWzCFnTGio5yHaRifg1Su5Ybza5Nw==", - "dev": true, - "requires": { - "@jest/console": "^29.0.2", - "@jest/environment": "^29.0.2", - "@jest/test-result": "^29.0.2", - "@jest/transform": "^29.0.2", - "@jest/types": "^29.0.2", - "@types/node": "*", - "chalk": "^4.0.0", - "emittery": "^0.10.2", - "graceful-fs": "^4.2.9", - "jest-docblock": "^29.0.0", - "jest-environment-node": "^29.0.2", - "jest-haste-map": "^29.0.2", - "jest-leak-detector": "^29.0.2", - "jest-message-util": "^29.0.2", - "jest-resolve": "^29.0.2", - "jest-runtime": "^29.0.2", - "jest-util": "^29.0.2", - "jest-watcher": "^29.0.2", - "jest-worker": "^29.0.2", - "p-limit": "^3.1.0", - "source-map-support": "0.5.13" - } - }, - "jest-runtime": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.0.2.tgz", - "integrity": "sha512-DO6F81LX4okOgjJLkLySv10E5YcV5NHUbY1ZqAUtofxdQE+q4hjH0P2gNsY8x3z3sqgw7O/+919SU4r18Fcuig==", - "dev": true, - "requires": { - "@jest/environment": "^29.0.2", - "@jest/fake-timers": "^29.0.2", - "@jest/globals": "^29.0.2", - "@jest/source-map": "^29.0.0", - "@jest/test-result": "^29.0.2", - "@jest/transform": "^29.0.2", - "@jest/types": "^29.0.2", - "@types/node": "*", - "chalk": "^4.0.0", - "cjs-module-lexer": "^1.0.0", - "collect-v8-coverage": "^1.0.0", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.0.2", - "jest-message-util": "^29.0.2", - "jest-mock": "^29.0.2", - "jest-regex-util": "^29.0.0", - "jest-resolve": "^29.0.2", - "jest-snapshot": "^29.0.2", - "jest-util": "^29.0.2", - "slash": "^3.0.0", - "strip-bom": "^4.0.0" - } - }, - "jest-snapshot": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.0.2.tgz", - "integrity": "sha512-26C4PzGKaX5gkoKg8UzYGVy2HPVcTaROSkf0gwnHu3lGeTB7bAIJBovvVPZoiJ20IximJELQs/r8WSDRCuGX2A==", - "dev": true, - "requires": { - "@babel/core": "^7.11.6", - "@babel/generator": "^7.7.2", - "@babel/plugin-syntax-jsx": "^7.7.2", - "@babel/plugin-syntax-typescript": "^7.7.2", - "@babel/traverse": "^7.7.2", - "@babel/types": "^7.3.3", - "@jest/expect-utils": "^29.0.2", - "@jest/transform": "^29.0.2", - "@jest/types": "^29.0.2", - "@types/babel__traverse": "^7.0.6", - "@types/prettier": "^2.1.5", - "babel-preset-current-node-syntax": "^1.0.0", - "chalk": "^4.0.0", - "expect": "^29.0.2", - "graceful-fs": "^4.2.9", - "jest-diff": "^29.0.2", - "jest-get-type": "^29.0.0", - "jest-haste-map": "^29.0.2", - "jest-matcher-utils": "^29.0.2", - "jest-message-util": "^29.0.2", - "jest-util": "^29.0.2", - "natural-compare": "^1.4.0", - "pretty-format": "^29.0.2", - "semver": "^7.3.5" - } - }, - "jest-util": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.0.2.tgz", - "integrity": "sha512-ozk8ruEEEACxqpz0hN9UOgtPZS0aN+NffwQduR5dVlhN+eN47vxurtvgZkYZYMpYrsmlAEx1XabkB3BnN0GfKQ==", - "dev": true, - "requires": { - "@jest/types": "^29.0.2", - "@types/node": "*", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "graceful-fs": "^4.2.9", - "picomatch": "^2.2.3" - } - }, - "jest-validate": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.0.2.tgz", - "integrity": "sha512-AeRKm7cEucSy7tr54r3LhiGIXYvOILUwBM1S7jQkKs6YelwAlWKsmZGVrQR7uwsd31rBTnR5NQkODi1Z+6TKIQ==", - "dev": true, - "requires": { - "@jest/types": "^29.0.2", - "camelcase": "^6.2.0", - "chalk": "^4.0.0", - "jest-get-type": "^29.0.0", - "leven": "^3.1.0", - "pretty-format": "^29.0.2" - }, - "dependencies": { - "camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "dev": true - } - } - }, - "jest-watcher": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.0.2.tgz", - "integrity": "sha512-ds2bV0oyUdYoyrUTv4Ga5uptz4cEvmmP/JzqDyzZZanvrIn8ipxg5l3SDOAIiyuAx1VdHd2FBzeXPFO5KPH8vQ==", - "dev": true, - "requires": { - "@jest/test-result": "^29.0.2", - "@jest/types": "^29.0.2", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "emittery": "^0.10.2", - "jest-util": "^29.0.2", - "string-length": "^4.0.1" - } - }, - "jest-worker": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.0.2.tgz", - "integrity": "sha512-EyvBlYcvd2pg28yg5A3OODQnqK9LI1kitnGUZUG5/NYIeaRgewtYBKB5wlr7oXj8zPCkzev7EmnTCsrXK7V+Xw==", - "dev": true, - "requires": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - }, - "dependencies": { - "supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "joi": { - "version": "17.6.0", - "resolved": "https://registry.npmjs.org/joi/-/joi-17.6.0.tgz", - "integrity": "sha512-OX5dG6DTbcr/kbMFj0KGYxuew69HPcAE3K/sZpEV2nP6e/j/C0HV+HNiBPCASxdx5T7DMoa0s8UeHWMnb6n2zw==", - "dev": true, - "requires": { - "@hapi/hoek": "^9.0.0", - "@hapi/topo": "^5.0.0", - "@sideway/address": "^4.1.3", - "@sideway/formula": "^3.0.0", - "@sideway/pinpoint": "^2.0.0" - } - }, - "js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, - "js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "requires": { - "argparse": "^2.0.1" - } - }, - "jsdom": { - "version": "20.0.0", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-20.0.0.tgz", - "integrity": "sha512-x4a6CKCgx00uCmP+QakBDFXwjAJ69IkkIWHmtmjd3wvXPcdOS44hfX2vqkOQrVrq8l9DhNNADZRXaCEWvgXtVA==", - "dev": true, - "requires": { - "abab": "^2.0.6", - "acorn": "^8.7.1", - "acorn-globals": "^6.0.0", - "cssom": "^0.5.0", - "cssstyle": "^2.3.0", - "data-urls": "^3.0.2", - "decimal.js": "^10.3.1", - "domexception": "^4.0.0", - "escodegen": "^2.0.0", - "form-data": "^4.0.0", - "html-encoding-sniffer": "^3.0.0", - "http-proxy-agent": "^5.0.0", - "https-proxy-agent": "^5.0.1", - "is-potential-custom-element-name": "^1.0.1", - "nwsapi": "^2.2.0", - "parse5": "^7.0.0", - "saxes": "^6.0.0", - "symbol-tree": "^3.2.4", - "tough-cookie": "^4.0.0", - "w3c-hr-time": "^1.0.2", - "w3c-xmlserializer": "^3.0.0", - "webidl-conversions": "^7.0.0", - "whatwg-encoding": "^2.0.0", - "whatwg-mimetype": "^3.0.0", - "whatwg-url": "^11.0.0", - "ws": "^8.8.0", - "xml-name-validator": "^4.0.0" - } - }, - "jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "dev": true - }, - "json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true - }, - "json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true - }, - "json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "dev": true - }, - "kleur": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", - "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", - "dev": true - }, - "leven": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", - "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", - "dev": true - }, - "levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "requires": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - } - }, - "lines-and-columns": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "dev": true - }, - "locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "requires": { - "p-locate": "^5.0.0" - } - }, - "lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true - }, - "lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true - }, - "lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "requires": { - "yallist": "^4.0.0" - } - }, - "make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dev": true, - "requires": { - "semver": "^6.0.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } - } - }, - "makeerror": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", - "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", - "dev": true, - "requires": { - "tmpl": "1.0.5" - } - }, - "merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true - }, - "merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true - }, - "micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", - "dev": true, - "requires": { - "braces": "^3.0.2", - "picomatch": "^2.3.1" - } - }, - "mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "dev": true - }, - "mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dev": true, - "requires": { - "mime-db": "1.52.0" - } - }, - "mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true - }, - "minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", - "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", - "dev": true - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true - }, - "node-domexception": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", - "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", - "dev": true - }, - "node-fetch": { - "version": "3.2.10", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.2.10.tgz", - "integrity": "sha512-MhuzNwdURnZ1Cp4XTazr69K0BTizsBroX7Zx3UgDSVcZYKF/6p0CBe4EUb/hLqmzVhl0UpYfgRljQ4yxE+iCxA==", - "dev": true, - "requires": { - "data-uri-to-buffer": "^4.0.0", - "fetch-blob": "^3.1.4", - "formdata-polyfill": "^4.0.10" - } - }, - "node-int64": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", - "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", - "dev": true - }, - "node-releases": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz", - "integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==", - "dev": true - }, - "normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true - }, - "npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "dev": true, - "requires": { - "path-key": "^3.0.0" - } - }, - "nwsapi": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.2.tgz", - "integrity": "sha512-90yv+6538zuvUMnN+zCr8LuV6bPFdq50304114vJYJ8RDyK8D5O9Phpbd6SZWgI7PwzmmfN1upeOJlvybDSgCw==", - "dev": true - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, - "requires": { - "wrappy": "1" - } - }, - "onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dev": true, - "requires": { - "mimic-fn": "^2.1.0" - } - }, - "optionator": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", - "dev": true, - "requires": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.3" - } - }, - "os-homedir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", - "integrity": "sha512-B5JU3cabzk8c67mRRd3ECmROafjYMXbuzlwtqdM8IbS8ktlTix8aFGb2bAGKrSRIlnfKwovGUUr72JUPyOb6kQ==", - "dev": true - }, - "p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "requires": { - "yocto-queue": "^0.1.0" - } - }, - "p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "requires": { - "p-limit": "^3.0.2" - } - }, - "p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true - }, - "parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "requires": { - "callsites": "^3.0.0" - } - }, - "parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - } - }, - "parse-passwd": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", - "integrity": "sha512-1Y1A//QUXEZK7YKz+rD9WydcE1+EuPr6ZBgKecAB8tmoW6UFv0NREVJe1p+jRxtThkcbbKkfwIbWJe/IeE6m2Q==", - "dev": true - }, - "parse5": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.1.tgz", - "integrity": "sha512-kwpuwzB+px5WUg9pyK0IcK/shltJN5/OVhQagxhCQNtT9Y9QRZqNY2e1cmbu/paRh5LMnz/oVTVLBpjFmMZhSg==", - "dev": true, - "requires": { - "entities": "^4.4.0" - } - }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true - }, - "path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true - }, - "path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true - }, - "path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true - }, - "picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", - "dev": true - }, - "picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true - }, - "pirates": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz", - "integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==", - "dev": true - }, - "pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "dev": true, - "requires": { - "find-up": "^4.0.0" - }, - "dependencies": { - "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "requires": { - "p-locate": "^4.1.0" - } - }, - "p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "requires": { - "p-limit": "^2.2.0" - } - } - } - }, - "prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true - }, - "pretty-format": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.0.2.tgz", - "integrity": "sha512-wp3CdtUa3cSJVFn3Miu5a1+pxc1iPIQTenOAn+x5erXeN1+ryTcLesV5pbK/rlW5EKwp27x38MoYfNGaNXDDhg==", - "dev": true, - "requires": { - "@jest/schemas": "^29.0.0", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true - } - } - }, - "prompts": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", - "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", - "dev": true, - "requires": { - "kleur": "^3.0.3", - "sisteransi": "^1.0.5" - } - }, - "psl": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", - "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==", - "dev": true - }, - "punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "dev": true - }, - "querystringify": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", - "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", - "dev": true - }, - "queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true - }, - "react-is": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", - "dev": true - }, - "regexpp": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", - "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", - "dev": true - }, - "require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "dev": true - }, - "requires-port": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", - "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", - "dev": true - }, - "resolve": { - "version": "1.22.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", - "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", - "dev": true, - "requires": { - "is-core-module": "^2.9.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - } - }, - "resolve-cwd": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", - "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", - "dev": true, - "requires": { - "resolve-from": "^5.0.0" - }, - "dependencies": { - "resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true - } - } - }, - "resolve-dir": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-0.1.1.tgz", - "integrity": "sha512-QxMPqI6le2u0dCLyiGzgy92kjkkL6zO0XyvHzjdTNH3zM6e5Hz3BwG6+aEyNgiQ5Xz6PwTwgQEj3U50dByPKIA==", - "dev": true, - "requires": { - "expand-tilde": "^1.2.2", - "global-modules": "^0.2.3" - } - }, - "resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true - }, - "resolve.exports": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-1.1.0.tgz", - "integrity": "sha512-J1l+Zxxp4XK3LUDZ9m60LRJF/mAe4z6a4xyabPHk7pvK5t35dACV32iIjJDFeWZFfZlO29w6SZ67knR0tHzJtQ==", - "dev": true - }, - "reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true - }, - "rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - }, - "run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "requires": { - "queue-microtask": "^1.2.2" - } - }, - "rxjs": { - "version": "7.5.5", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.5.5.tgz", - "integrity": "sha512-sy+H0pQofO95VDmFLzyaw9xNJU4KTRSwQIGM6+iG3SypAtCiLDzpeG8sJrNCWn2Up9km+KhkvTdbkrdy+yzZdw==", - "dev": true, - "requires": { - "tslib": "^2.1.0" - }, - "dependencies": { - "tslib": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", - "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==", - "dev": true - } - } - }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - }, - "safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true - }, - "saxes": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", - "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", - "dev": true, - "requires": { - "xmlchars": "^2.2.0" - } - }, - "semver": { - "version": "7.3.7", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", - "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - }, - "shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "requires": { - "shebang-regex": "^3.0.0" - } - }, - "shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true - }, - "signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true - }, - "sisteransi": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", - "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", - "dev": true - }, - "slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - }, - "source-map-support": { - "version": "0.5.13", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", - "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", - "dev": true, - "requires": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "spawnd": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/spawnd/-/spawnd-6.0.2.tgz", - "integrity": "sha512-+YJtx0dvy2wt304MrHD//tASc84zinBUYU1jacPBzrjhZUd7RsDo25krxr4HUHAQzEQFuMAs4/p+yLYU5ciZ1w==", - "dev": true, - "requires": { - "exit": "^0.1.2", - "signal-exit": "^3.0.6", - "tree-kill": "^1.2.2" - } - }, - "sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", - "dev": true - }, - "stack-utils": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.5.tgz", - "integrity": "sha512-xrQcmYhOsn/1kX+Vraq+7j4oE2j/6BFscZ0etmYg81xuM8Gq0022Pxb8+IqgOFUIaxHs0KaSb7T1+OegiNrNFA==", - "dev": true, - "requires": { - "escape-string-regexp": "^2.0.0" - }, - "dependencies": { - "escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "dev": true - } - } - }, - "string-length": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", - "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", - "dev": true, - "requires": { - "char-regex": "^1.0.2", - "strip-ansi": "^6.0.0" - } - }, - "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==", - "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - } - }, - "strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.1" - } - }, - "strip-bom": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", - "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", - "dev": true - }, - "strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", - "dev": true - }, - "strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - }, - "supports-hyperlinks": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.3.0.tgz", - "integrity": "sha512-RpsAZlpWcDwOPQA22aCH4J0t7L8JmAvsCxfOSEwm7cQs3LshN36QaTkwd70DnBOXDWGssw2eUoc8CaRWT0XunA==", - "dev": true, - "requires": { - "has-flag": "^4.0.0", - "supports-color": "^7.0.0" - } - }, - "supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true - }, - "symbol-tree": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", - "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", - "dev": true - }, - "terminal-link": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-2.1.1.tgz", - "integrity": "sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==", - "dev": true, - "requires": { - "ansi-escapes": "^4.2.1", - "supports-hyperlinks": "^2.0.0" - } - }, - "test-exclude": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", - "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", - "dev": true, - "requires": { - "@istanbuljs/schema": "^0.1.2", - "glob": "^7.1.4", - "minimatch": "^3.0.4" - } - }, - "text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true - }, - "tmpl": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", - "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", - "dev": true - }, - "to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", - "dev": true - }, - "to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "requires": { - "is-number": "^7.0.0" - } - }, - "tough-cookie": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.3.tgz", - "integrity": "sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==", - "dev": true, - "requires": { - "psl": "^1.1.33", - "punycode": "^2.1.1", - "universalify": "^0.2.0", - "url-parse": "^1.5.3" - } - }, - "tr46": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-3.0.0.tgz", - "integrity": "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==", - "dev": true, - "requires": { - "punycode": "^2.1.1" - } - }, - "tree-kill": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", - "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", - "dev": true - }, - "tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - }, - "tsutils": { - "version": "3.21.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", - "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", - "dev": true, - "requires": { - "tslib": "^1.8.1" - } - }, - "type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "requires": { - "prelude-ls": "^1.2.1" - } - }, - "type-detect": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", - "dev": true - }, - "type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true - }, - "typescript": { - "version": "4.7.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.3.tgz", - "integrity": "sha512-WOkT3XYvrpXx4vMMqlD+8R8R37fZkjyLGlxavMc4iB8lrl8L0DeTcHbYgw/v0N/z9wAFsgBhcsF0ruoySS22mA==", - "dev": true, - "peer": true - }, - "universalify": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", - "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", - "dev": true - }, - "update-browserslist-db": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.7.tgz", - "integrity": "sha512-iN/XYesmZ2RmmWAiI4Z5rq0YqSiv0brj9Ce9CfhNE4xIW2h+MFxcgkxIzZ+ShkFPUkjU3gQ+3oypadD3RAMtrg==", - "dev": true, - "requires": { - "escalade": "^3.1.1", - "picocolors": "^1.0.0" - } - }, - "uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "requires": { - "punycode": "^2.1.0" - } - }, - "url-parse": { - "version": "1.5.10", - "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", - "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", - "dev": true, - "requires": { - "querystringify": "^2.1.1", - "requires-port": "^1.0.0" - } - }, - "v8-to-istanbul": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.0.1.tgz", - "integrity": "sha512-74Y4LqY74kLE6IFyIjPtkSTWzUZmj8tdHT9Ii/26dvQ6K9Dl2NbEfj0XgU2sHCtKgt5VupqhlO/5aWuqS+IY1w==", - "dev": true, - "requires": { - "@jridgewell/trace-mapping": "^0.3.12", - "@types/istanbul-lib-coverage": "^2.0.1", - "convert-source-map": "^1.6.0" - } - }, - "w3c-hr-time": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", - "integrity": "sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==", - "dev": true, - "requires": { - "browser-process-hrtime": "^1.0.0" - } - }, - "w3c-xmlserializer": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-3.0.0.tgz", - "integrity": "sha512-3WFqGEgSXIyGhOmAFtlicJNMjEps8b1MG31NCA0/vOF9+nKMUW1ckhi9cnNHmf88Rzw5V+dwIwsm2C7X8k9aQg==", - "dev": true, - "requires": { - "xml-name-validator": "^4.0.0" - } - }, - "wait-on": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/wait-on/-/wait-on-6.0.1.tgz", - "integrity": "sha512-zht+KASY3usTY5u2LgaNqn/Cd8MukxLGjdcZxT2ns5QzDmTFc4XoWBgC+C/na+sMRZTuVygQoMYwdcVjHnYIVw==", - "dev": true, - "requires": { - "axios": "^0.25.0", - "joi": "^17.6.0", - "lodash": "^4.17.21", - "minimist": "^1.2.5", - "rxjs": "^7.5.4" - } - }, - "walker": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", - "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", - "dev": true, - "requires": { - "makeerror": "1.0.12" - } - }, - "web-streams-polyfill": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz", - "integrity": "sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==", - "dev": true - }, - "webidl-conversions": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", - "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", - "dev": true - }, - "whatwg-encoding": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz", - "integrity": "sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==", - "dev": true, - "requires": { - "iconv-lite": "0.6.3" - } - }, - "whatwg-mimetype": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-3.0.0.tgz", - "integrity": "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==", - "dev": true - }, - "whatwg-url": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-11.0.0.tgz", - "integrity": "sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==", - "dev": true, - "requires": { - "tr46": "^3.0.0", - "webidl-conversions": "^7.0.0" - } - }, - "which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - }, - "word-wrap": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.4.tgz", - "integrity": "sha512-2V81OA4ugVo5pRo46hAoD2ivUJx8jXmWXfUkY4KFNw0hEptvN0QfH3K4nHiwzGeKl5rFKedV48QVoqYavy4YpA==", - "dev": true - }, - "wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "requires": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - } - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true - }, - "write-file-atomic": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", - "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", - "dev": true, - "requires": { - "imurmurhash": "^0.1.4", - "signal-exit": "^3.0.7" - } - }, - "ws": { - "version": "8.8.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.8.1.tgz", - "integrity": "sha512-bGy2JzvzkPowEJV++hF07hAD6niYSr0JzBNo/J29WsB57A2r7Wlc1UFcTR9IzrPvuNVO4B8LGqF8qcpsVOhJCA==", - "dev": true, - "requires": {} - }, - "xml-name-validator": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-4.0.0.tgz", - "integrity": "sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==", - "dev": true - }, - "xmlchars": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", - "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", - "dev": true - }, - "y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true - }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "yargs": { - "version": "17.5.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.5.1.tgz", - "integrity": "sha512-t6YAJcxDkNX7NFYiVtKvWUz8l+PaKTLiL63mJYWR2GnHq2gjEWISzsLp9wg3aY36dY1j+gfIEL3pIF+XlJJfbA==", - "dev": true, - "requires": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.0.0" - } - }, - "yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "dev": true - }, - "yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true - } - } -} diff --git a/WebApp/client/package.json b/WebApp/client/package.json deleted file mode 100644 index 8e46442..0000000 --- a/WebApp/client/package.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "name": "webclient", - "version": "3.1.0", - "private": true, - "scripts": { - "test": "node --experimental-vm-modules node_modules/jest/bin/jest.js", - "lint": "eslint public/**/*.js src/**/*.js test/**/*.js" - }, - "devDependencies": { - "eslint": "^8.23.0", - "eslint-plugin-jest": "^27.0.1", - "jest": "^29.0.2", - "jest-dev-server": "^6.1.1", - "jest-environment-jsdom": "^29.0.2", - "node-fetch": "^3.2.10" - }, - "type": "module" -} diff --git a/WebApp/client/public/bidirectional/css/style.css b/WebApp/client/public/bidirectional/css/style.css deleted file mode 100644 index b5617d6..0000000 --- a/WebApp/client/public/bidirectional/css/style.css +++ /dev/null @@ -1,54 +0,0 @@ -div#select, div#resolution { - margin: 1em; -} - -button { - margin: 0 20px 5px 0; - vertical-align: top; - width: 155px; -} - -div#buttons { - border-top: 1px solid #eee; - border-bottom: 1px solid #eee; - margin: 1em 0 1em 0; - padding: 1em 0 1em 0; -} - -div#local { - margin: 0 20px 0 0; -} - -div#preview { - border-bottom: 1px solid #eee; - margin: 0 0 1em 0; - padding: 0 0 0.5em 0; -} - -div#preview>div { - display: inline-block; - vertical-align: top; - width: calc(50% - 20px); -} - -div#connectionId { - margin: 1em; -} - -h2 { - margin: 0 0 0.5em 0; -} - -textarea { - color: #444; - font-size: 0.9em; - font-weight: 300; - width: calc(20% - 10px); - height: 1.3em; - line-height: 1.3; - vertical-align: middle; -} - -video { - height: 225px; -} \ No newline at end of file diff --git a/WebApp/client/public/bidirectional/index.html b/WebApp/client/public/bidirectional/index.html deleted file mode 100644 index 84dad5e..0000000 --- a/WebApp/client/public/bidirectional/index.html +++ /dev/null @@ -1,83 +0,0 @@ - - - - - - - - - Bidirectional Sample - - - -
-

Bidirectional Sample

- - - -
- - - - -
- -
- -
-
- - -
- -
- - - -
- -
-
-

Local

- -
-
-
-

Remote

- -
-
-
- -
- Connection ID: - -
-
- Codec preferences: - -
- -

For more information about Bidirectional sample, see Bidirectional - sample document page.

- -
- -
- View source on GitHub -
-
- - - - - - - - - - diff --git a/WebApp/client/public/bidirectional/js/main.js b/WebApp/client/public/bidirectional/js/main.js deleted file mode 100644 index 2e4df80..0000000 --- a/WebApp/client/public/bidirectional/js/main.js +++ /dev/null @@ -1,382 +0,0 @@ -/** - * 双向视频通话应用主文件 - * 负责初始化视频设备、建立WebRTC连接、处理信令和显示视频流 - */ - -// 导入必要的模块 -import { SendVideo } from "./sendvideo.js"; // 视频发送和接收处理 -import { getServerConfig, getRTCConfiguration } from "../../js/config.js"; // 服务器配置和RTC配置 -import { createDisplayStringArray } from "../../js/stats.js"; // 统计信息处理 -import { RenderStreaming } from "../../module/renderstreaming.js"; // WebRTC连接管理 -import { Signaling, WebSocketSignaling } from "../../module/signaling.js"; // 信令管理 - -// 默认视频流尺寸 -const defaultStreamWidth = 1280; -const defaultStreamHeight = 720; - -// 预定义的视频分辨率列表 -const streamSizeList = - [ - { width: 640, height: 360 }, // 标清 - { width: 1280, height: 720 }, // 高清 - { width: 1920, height: 1080 }, // 全高清 - { width: 2560, height: 1440 }, // 2K - { width: 3840, height: 2160 }, // 4K - { width: 360, height: 640 }, // 竖屏标清 - { width: 720, height: 1280 }, // 竖屏高清 - { width: 1080, height: 1920 }, // 竖屏全高清 - { width: 1440, height: 2560 }, // 竖屏2K - { width: 2160, height: 3840 }, // 竖屏4K - ]; - -// DOM元素引用 -const localVideo = document.getElementById('localVideo'); // 本地视频元素 -const remoteVideo = document.getElementById('remoteVideo'); // 远程视频元素 -const localVideoStatsDiv = document.getElementById('localVideoStats'); // 本地视频统计信息 -const remoteVideoStatsDiv = document.getElementById('remoteVideoStats'); // 远程视频统计信息 -const textForConnectionId = document.getElementById('textForConnectionId'); // 连接ID输入框 -textForConnectionId.value = getRandom(); // 生成随机连接ID -const videoSelect = document.querySelector('select#videoSource'); // 视频设备选择 -const audioSelect = document.querySelector('select#audioSource'); // 音频设备选择 -const videoResolutionSelect = document.querySelector('select#videoResolution'); // 视频分辨率选择 -const cameraWidthInput = document.querySelector('input#cameraWidth'); // 自定义宽度输入 -const cameraHeightInput = document.querySelector('input#cameraHeight'); // 自定义高度输入 - -// 编解码器偏好设置 -const codecPreferences = document.getElementById('codecPreferences'); -// 检查浏览器是否支持设置编解码器偏好 -const supportsSetCodecPreferences = window.RTCRtpTransceiver && - 'setCodecPreferences' in window.RTCRtpTransceiver.prototype; -const messageDiv = document.getElementById('message'); // 消息显示区域 -messageDiv.style.display = 'none'; // 初始隐藏消息区域 - -let useCustomResolution = false; // 是否使用自定义分辨率 - -// 初始化输入选择和编解码器选择 -setUpInputSelect(); -showCodecSelect(); - -/** @type {SendVideo} */ -let sendVideo = new SendVideo(localVideo, remoteVideo); // 视频处理实例 -/** @type {RenderStreaming} */ -let renderstreaming; // WebRTC连接管理实例 -let useWebSocket; // 是否使用WebSocket信令 -let connectionId; // 连接ID - -// 按钮事件绑定 -const startButton = document.getElementById('startVideoButton'); -startButton.addEventListener('click', startVideo); // 启动视频按钮 -const setupButton = document.getElementById('setUpButton'); -setupButton.addEventListener('click', setUp); // 设置连接按钮 -const hangUpButton = document.getElementById('hangUpButton'); -hangUpButton.addEventListener('click', hangUp); // 挂断按钮 - -// 页面卸载前清理 -window.addEventListener('beforeunload', async () => { - if(!renderstreaming) - return; - await renderstreaming.stop(); // 停止WebRTC连接 -}, true); - -// 初始化配置 -setupConfig(); - -/** - * 初始化服务器配置 - * @async - * @returns {Promise} - */ -async function setupConfig() { - const res = await getServerConfig(); // 获取服务器配置 - useWebSocket = res.useWebSocket; // 设置是否使用WebSocket - showWarningIfNeeded(res.startupMode); // 显示启动模式警告 -} - -/** - * 根据启动模式显示警告信息 - * @param {string} startupMode - 启动模式,可能的值包括"public"和"private" - */ -function showWarningIfNeeded(startupMode) { - const warningDiv = document.getElementById("warning"); - if (startupMode == "public") { - warningDiv.innerHTML = "

Warning

This sample is not working on Public Mode."; - warningDiv.hidden = false; - } -} - -/** - * 启动本地视频 - * @async - * @returns {Promise} - */ -async function startVideo() { - // 禁用相关输入控件 - videoSelect.disabled = true; - audioSelect.disabled = true; - videoResolutionSelect.disabled = true; - cameraWidthInput.disabled = true; - cameraHeightInput.disabled = true; - startButton.disabled = true; - - let width = 0; - let height = 0; - - // 根据选择的分辨率设置视频尺寸 - if (useCustomResolution) { - width = cameraWidthInput.value ? cameraWidthInput.value : defaultStreamWidth; - height = cameraHeightInput.value ? cameraHeightInput.value : defaultStreamHeight; - } else { - const size = streamSizeList[videoResolutionSelect.value]; - width = size.width; - height = size.height; - } - - // 启动本地视频 - await sendVideo.startLocalVideo(videoSelect.value, audioSelect.value, width, height); - - // 启用设置按钮 - setupButton.disabled = false; -} - -/** - * 设置WebRTC连接 - * @async - * @returns {Promise} - */ -async function setUp() { - setupButton.disabled = true; // 禁用设置按钮 - hangUpButton.disabled = false; // 启用挂断按钮 - connectionId = textForConnectionId.value; // 获取连接ID - codecPreferences.disabled = true; // 禁用编解码器选择 - - // 创建信令实例 - const signaling = useWebSocket ? new WebSocketSignaling() : new Signaling(); - const config = getRTCConfiguration(); // 获取RTC配置 - renderstreaming = new RenderStreaming(signaling, config); // 创建WebRTC连接管理实例 - - // 连接建立回调 - renderstreaming.onConnect = () => { - const tracks = sendVideo.getLocalTracks(); // 获取本地媒体轨道 - for (const track of tracks) { - renderstreaming.addTransceiver(track, { direction: 'sendonly' }); // 添加发送轨道 - } - setCodecPreferences(); // 设置编解码器偏好 - showStatsMessage(); // 显示统计信息 - }; - - // 连接断开回调 - renderstreaming.onDisconnect = () => { - hangUp(); // 挂断连接 - }; - - // 轨道事件回调 - renderstreaming.onTrackEvent = (data) => { - const direction = data.transceiver.direction; - if (direction == "sendrecv" || direction == "recvonly") { - sendVideo.addRemoteTrack(data.track); // 添加远程轨道 - } - }; - - // 启动WebRTC连接 - await renderstreaming.start(); - await renderstreaming.createConnection(connectionId); - -} - -/** - * 设置编解码器偏好 - */ -function setCodecPreferences() { - /** @type {RTCRtpCodecCapability[] | null} */ - let selectedCodecs = null; - - if (supportsSetCodecPreferences) { - const preferredCodec = codecPreferences.options[codecPreferences.selectedIndex]; - if (preferredCodec.value !== '') { - const [mimeType, sdpFmtpLine] = preferredCodec.value.split(' '); - const { codecs } = RTCRtpSender.getCapabilities('video'); - const selectedCodecIndex = codecs.findIndex(c => c.mimeType === mimeType && c.sdpFmtpLine === sdpFmtpLine); - const selectCodec = codecs[selectedCodecIndex]; - selectedCodecs = [selectCodec]; - } - } - - if (selectedCodecs == null) { - return; - } - - // 获取视频收发器并设置编解码器偏好 - const transceivers = renderstreaming.getTransceivers().filter(t => t.receiver.track.kind == "video"); - if (transceivers && transceivers.length > 0) { - transceivers.forEach(t => t.setCodecPreferences(selectedCodecs)); - } -} - -/** - * 挂断WebRTC连接 - * @async - * @returns {Promise} - */ -async function hangUp() { - clearStatsMessage(); // 清除统计信息 - messageDiv.style.display = 'block'; - messageDiv.innerText = `Disconnect peer on ${connectionId}.`; - - hangUpButton.disabled = true; // 禁用挂断按钮 - setupButton.disabled = false; // 启用设置按钮 - - // 删除连接并停止WebRTC - await renderstreaming.deleteConnection(); - await renderstreaming.stop(); - renderstreaming = null; - remoteVideo.srcObject = null; // 清除远程视频源 - - textForConnectionId.value = getRandom(); // 生成新的随机连接ID - connectionId = null; - - // 启用编解码器选择 - if (supportsSetCodecPreferences) { - codecPreferences.disabled = false; - } -} - -/** - * 生成随机连接ID - * @returns {string} 5位随机数字字符串 - */ -function getRandom() { - const max = 99999; - const length = String(max).length; - const number = Math.floor(Math.random() * max); - return (Array(length).join('0') + number).slice(-length); // 补零确保5位 -} - -/** - * 设置输入选择控件 - * @async - * @returns {Promise} - */ -async function setUpInputSelect() { - // 获取媒体设备列表 - const deviceInfos = await navigator.mediaDevices.enumerateDevices(); - - // 填充视频设备选择 - for (let i = 0; i !== deviceInfos.length; ++i) { - const deviceInfo = deviceInfos[i]; - if (deviceInfo.kind === 'videoinput') { - const option = document.createElement('option'); - option.value = deviceInfo.deviceId; - option.text = deviceInfo.label || `camera ${videoSelect.length + 1}`; - videoSelect.appendChild(option); - } else if (deviceInfo.kind === 'audioinput') { - // 填充音频设备选择 - const option = document.createElement('option'); - option.value = deviceInfo.deviceId; - option.text = deviceInfo.label || `mic ${audioSelect.length + 1}`; - audioSelect.appendChild(option); - } - } - - // 填充视频分辨率选择 - for (let i = 0; i < streamSizeList.length; i++) { - const streamSize = streamSizeList[i]; - const option = document.createElement('option'); - option.value = i; - option.text = `${streamSize.width} x ${streamSize.height}`; - videoResolutionSelect.appendChild(option); - } - - // 添加自定义分辨率选项 - const option = document.createElement('option'); - option.value = streamSizeList.length; - option.text = 'Custom'; - videoResolutionSelect.appendChild(option); - videoResolutionSelect.value = 1; // 默认选择1280 x 720 - - // 分辨率选择变化事件 - videoResolutionSelect.addEventListener('change', (event) => { - const isCustom = event.target.value >= streamSizeList.length; - cameraWidthInput.disabled = !isCustom; - cameraHeightInput.disabled = !isCustom; - useCustomResolution = isCustom; - }); -} - -/** - * 显示编解码器选择 - */ -function showCodecSelect() { - if (!supportsSetCodecPreferences) { - messageDiv.style.display = 'block'; - messageDiv.innerHTML = `Current Browser does not support RTCRtpTransceiver.setCodecPreferences.`; - return; - } - - // 获取视频编解码器能力 - const codecs = RTCRtpSender.getCapabilities('video').codecs; - codecs.forEach(codec => { - // 跳过冗余和FEC编解码器 - if (['video/red', 'video/ulpfec', 'video/rtx'].includes(codec.mimeType)) { - return; - } - const option = document.createElement('option'); - option.value = (codec.mimeType + ' ' + (codec.sdpFmtpLine || '')).trim(); - option.innerText = option.value; - codecPreferences.appendChild(option); - }); - codecPreferences.disabled = false; -} - -// 统计信息相关变量 -let lastStats; // 上次统计信息 -let intervalId; // 统计信息更新间隔ID - -/** - * 显示统计信息 - */ -function showStatsMessage() { - // 每秒更新一次统计信息 - intervalId = setInterval(async () => { - // 显示本地视频分辨率 - if (localVideo.videoWidth) { - localVideoStatsDiv.innerHTML = `Sending resolution: ${localVideo.videoWidth} x ${localVideo.videoHeight} px`; - } - // 显示远程视频分辨率 - if (remoteVideo.videoWidth) { - remoteVideoStatsDiv.innerHTML = `Receiving resolution: ${remoteVideo.videoWidth} x ${remoteVideo.videoHeight} px`; - } - - if (renderstreaming == null || connectionId == null) { - return; - } - - // 获取WebRTC统计信息 - const stats = await renderstreaming.getStats(); - if (stats == null) { - return; - } - - // 创建统计信息显示数组 - const array = createDisplayStringArray(stats, lastStats); - if (array.length) { - messageDiv.style.display = 'block'; - messageDiv.innerHTML = array.join('
'); - } - lastStats = stats; - }, 1000); -} - -/** - * 清除统计信息 - */ -function clearStatsMessage() { - if (intervalId) { - clearInterval(intervalId); // 清除定时器 - } - lastStats = null; - intervalId = null; - localVideoStatsDiv.innerHTML = ''; - remoteVideoStatsDiv.innerHTML = ''; - messageDiv.style.display = 'none'; - messageDiv.innerHTML = ''; -} diff --git a/WebApp/client/public/bidirectional/js/sendvideo.js b/WebApp/client/public/bidirectional/js/sendvideo.js deleted file mode 100644 index 8cea080..0000000 --- a/WebApp/client/public/bidirectional/js/sendvideo.js +++ /dev/null @@ -1,53 +0,0 @@ -import * as Logger from "../../module/logger.js"; - -export class SendVideo { - constructor(localVideoElement, remoteVideoElement) { - this.localVideo = localVideoElement; - this.remoteVideo = remoteVideoElement; - } - - /** - * @param {MediaTrackConstraints} videoSource - * @param {MediaTrackConstraints} audioSource - * @param {number} videoWidth - * @param {number} videoHeight - */ - async startLocalVideo(videoSource, audioSource, videoWidth, videoHeight) { - try { - const constraints = { - video: { deviceId: videoSource ? { exact: videoSource } : undefined }, - audio: { deviceId: audioSource ? { exact: audioSource } : undefined } - }; - - if (videoWidth != null || videoWidth != 0) { - constraints.video.width = videoWidth; - } - if (videoHeight != null || videoHeight != 0) { - constraints.video.height = videoHeight; - } - - const localStream = await navigator.mediaDevices.getUserMedia(constraints); - this.localVideo.srcObject = localStream; - await this.localVideo.play(); - } catch (err) { - Logger.error(`mediaDevice.getUserMedia() error:${err}`); - } - } - - /** - * @returns {MediaStreamTrack[]} - */ - getLocalTracks() { - return this.localVideo.srcObject.getTracks(); - } - - /** - * @param {MediaStreamTrack} track - */ - addRemoteTrack(track) { - if (this.remoteVideo.srcObject == null) { - this.remoteVideo.srcObject = new MediaStream(); - } - this.remoteVideo.srcObject.addTrack(track); - } -} diff --git a/WebApp/client/public/css/main.css b/WebApp/client/public/css/main.css deleted file mode 100644 index 28f66a2..0000000 --- a/WebApp/client/public/css/main.css +++ /dev/null @@ -1,147 +0,0 @@ -h1 { - border-bottom: 1px solid #ccc; - font-weight: 500; - margin: 0 0 0.8em 0; - padding: 0 0 0.2em 0; -} - -h4 { - margin: 0; - padding: 0 0 0.2em 0; -} - -body { - font-family: 'Roboto', sans-serif; - font-weight: 300; - margin: 0; - padding: 1em; - word-break: break-word; -} - -button { - margin: 20px 10px 0 0; - width: 130px; -} - -button#gather { - display: block; -} - -section { - border-bottom: 1px solid #eee; - margin: 0 0 1.5em 0; - padding: 0 0 1.5em 0; -} - -section#iceServers label { - display: inline-block; - width: 150px; -} - -section#iceServers input { - margin: 0 0 10px; - width: 260px; -} - -select { - margin: 0 1em 1em 0; - position: relative; - top: -1px; -} - -select#servers { - font-size: 1em; - padding: 5px; - width: 420px; -} - -section:last-child { - border-bottom: none; - margin: 0; - padding: 0; -} - -div#container { - margin: 0 auto 0 auto; - max-width: 60em; - padding: 1em 1.5em 1.3em 1.5em; -} - -code { - padding: 0.1em 0.25em; - color: #444; - background-color: #e7edf3; - border-radius: 3px; - border: solid 1px #d6dde4; - font-weight: 400; -} - -p { - color: #444; - font-weight: 300; -} - -p#data { - border-top: 1px dotted #666; - line-height: 1.3em; - max-height: 1000px; - overflow-y: auto; - padding: 1em 0 0 0; -} - -p.borderBelow { - border-bottom: 1px solid #aaa; - padding: 0 0 20px 0; -} - -video { - background: #222; - margin: 0 0 20px 0; - --width: 100%; - width: var(--width); - height: calc(var(--width) * 0.75); -} - -div#warning { - color: #8a6d3b; - background-color: #fcf8e3; - border-color: #faebcc; - padding: 1em; - border: 1px solid transparent; -} - -div.box { - margin: 1em; -} - -div#message { - border-top: 1px solid #666; - margin: 1em; - padding: 1em; -} - -@media screen and (max-width: 650px) { - .highlight { - font-size: 1em; - margin: 0 0 20px 0; - padding: 0.2em 1em; - } - h1 { - font-size: 24px; - } -} - -@media screen and (max-width: 550px) { - button:active { - background-color: darkRed; - } - h1 { - font-size: 22px; - } -} - -@media screen and (max-width: 450px) { - h1 { - font-size: 20px; - } -} \ No newline at end of file diff --git a/WebApp/client/public/images/FullScreen.png b/WebApp/client/public/images/FullScreen.png deleted file mode 100644 index ba386e6..0000000 Binary files a/WebApp/client/public/images/FullScreen.png and /dev/null differ diff --git a/WebApp/client/public/images/Play.png b/WebApp/client/public/images/Play.png deleted file mode 100644 index 9d8dbd1..0000000 Binary files a/WebApp/client/public/images/Play.png and /dev/null differ diff --git a/WebApp/client/public/images/favicon.ico b/WebApp/client/public/images/favicon.ico deleted file mode 100644 index bd5b982..0000000 Binary files a/WebApp/client/public/images/favicon.ico and /dev/null differ diff --git a/WebApp/client/public/images/p1.png b/WebApp/client/public/images/p1.png deleted file mode 100644 index bf2c348..0000000 Binary files a/WebApp/client/public/images/p1.png and /dev/null differ diff --git a/WebApp/client/public/images/p2.png b/WebApp/client/public/images/p2.png deleted file mode 100644 index dac4c6a..0000000 Binary files a/WebApp/client/public/images/p2.png and /dev/null differ diff --git a/WebApp/client/public/images/screenshot.png b/WebApp/client/public/images/screenshot.png deleted file mode 100644 index 914f009..0000000 Binary files a/WebApp/client/public/images/screenshot.png and /dev/null differ diff --git a/WebApp/client/public/index.html b/WebApp/client/public/index.html deleted file mode 100644 index b71b437..0000000 --- a/WebApp/client/public/index.html +++ /dev/null @@ -1,77 +0,0 @@ - - - - - Unity Render Streaming Samples - - - -
-

Unity Render Streaming Samples

- -
-

These are WebClient samples for use with Unity Render - Streaming.

-
- -
-

Server Configuration

-
-
- -
-

ICE servers

- -
- - -
-
- - -
-
- - -
-
- - - -
-
- -
-

Receiver Sample

-

This is a sample for receiving video / audio from Unity.

-

It can be used in combination with the Broadcast scene of Unity Render Streaming.

-
- -
-

Bidirectional Sample

-

This is a sample for sending and receiving video in both directions.

-

It can be used in combination with the Bidirectional scene of Unity Render Streaming.

-

The WebApp must be running in Private mode.

-
- -
-

Multiplay Sample

-

This sample connects as a Guest in the Multiplay scene of Unity Render Streaming.

-
- -
-

VideoPlayer Sample

-

This is a sample to receive the camera image rendered on Unity. You can operate the camera in Unity from the - browser.

-

It can be used in combination with the WebBrowserInput scene of Unity Render Streaming.

-

The WebApp must be running in Public mode.

-
- -
- View source on GitHub -
-
- - - diff --git a/WebApp/client/public/js/config.js b/WebApp/client/public/js/config.js deleted file mode 100644 index 487f439..0000000 --- a/WebApp/client/public/js/config.js +++ /dev/null @@ -1,38 +0,0 @@ -import {getServers} from "./icesettings.js"; - -export async function getServerConfig() { - const protocolEndPoint = location.origin + '/config'; - const createResponse = await fetch(protocolEndPoint); - return await createResponse.json(); -} - -export function getRTCConfiguration() { - let config = {}; - config.sdpSemantics = 'unified-plan'; - config.iceServers = getServers(); - - // 添加音频处理选项,增强回声消除 - config.mediaConstraints = { - audio: { - echoCancellation: true, - noiseSuppression: true, - autoGainControl: true, - highpassFilter: true, - typingNoiseDetection: true - } - }; - - // 添加WebRTC音频处理选项 - config.rtcConfiguration = { - 'googEchoCancellation': true, - 'googEchoCancellation2': true, - 'googNoiseSuppression': true, - 'googNoiseSuppression2': true, - 'googAutoGainControl': true, - 'googAutoGainControl2': true, - 'googHighpassFilter': true, - 'googTypingNoiseDetection': true - }; - - return config; -} diff --git a/WebApp/client/public/js/icesettings.js b/WebApp/client/public/js/icesettings.js deleted file mode 100644 index 22b986f..0000000 --- a/WebApp/client/public/js/icesettings.js +++ /dev/null @@ -1,103 +0,0 @@ -// This code is referenced from webrtc sample. -// https://github.com/webrtc/samples/blob/gh-pages/src/content/peerconnection/trickle-ice/js/main.js - -const servers = document.querySelector('select#servers'); -const urlInput = document.querySelector('input#url'); -const usernameInput = document.querySelector('input#username'); -const passwordInput = document.querySelector('input#password'); - -const allServersKey = 'servers'; - -export function addServer() { - const scheme = urlInput.value.split(':')[0]; - if (!['stun', 'stuns', 'turn', 'turns'].includes(scheme)) { - alert(`URI scheme ${scheme} is not valid`); - return; - } - - // Store the ICE server as a stringified JSON object in option.value. - const option = document.createElement('option'); - const iceServer = { - urls: [urlInput.value], - username: usernameInput.value, - credential: passwordInput.value - }; - option.value = JSON.stringify(iceServer); - option.text = `${urlInput.value} `; - const username = usernameInput.value; - const password = passwordInput.value; - if (username || password) { - option.text += (` [${username}:${password}]`); - } - option.ondblclick = selectServer; - servers.add(option); - urlInput.value = usernameInput.value = passwordInput.value = ''; - writeServersToLocalStorage(); -} - -export function removeServer() { - for (let i = servers.options.length - 1; i >= 0; --i) { - if (servers.options[i].selected) { - servers.remove(i); - } - } - writeServersToLocalStorage(); -} - -export function reset() { - window.localStorage.clear(); - document.querySelectorAll('select#servers option').forEach(option => option.remove()); - const serversSelect = document.querySelector('select#servers'); - setDefaultServer(serversSelect); -} - -function selectServer(event) { - const option = event.target; - const value = JSON.parse(option.value); - urlInput.value = value.urls[0]; - usernameInput.value = value.username || ''; - passwordInput.value = value.credential || ''; -} - -function setDefaultServer(serversSelect) { - const option = document.createElement('option'); - option.value = '{"urls":["stun:stun.l.google.com:19302"]}'; - option.text = 'stun:stun.l.google.com:19302'; - option.ondblclick = selectServer; - serversSelect.add(option); -} - -function writeServersToLocalStorage() { - const serversSelect = document.querySelector('select#servers'); - const allServers = JSON.stringify(Object.values(serversSelect.options).map(o => JSON.parse(o.value))); - window.localStorage.setItem(allServersKey, allServers); -} - -export function readServersFromLocalStorage() { - document.querySelectorAll('select#servers option').forEach(option => option.remove()); - const serversSelect = document.querySelector('select#servers'); - const storedServers = window.localStorage.getItem(allServersKey); - - if (storedServers === null || storedServers === '') { - setDefaultServer(serversSelect); - } else { - JSON.parse(storedServers).forEach((server) => { - const o = document.createElement('option'); - o.value = JSON.stringify(server); - o.text = server.urls[0]; - o.ondblclick = selectServer; - serversSelect.add(o); - }); - } -} - -export function getServers() { - const storedServers = window.localStorage.getItem(allServersKey); - - if (storedServers === null || storedServers === '') { - return [{ urls: ['stun:stun.l.google.com:19302'] }]; - } - else { - return JSON.parse(storedServers); - } -} diff --git a/WebApp/client/public/js/main.js b/WebApp/client/public/js/main.js deleted file mode 100644 index cdf5825..0000000 --- a/WebApp/client/public/js/main.js +++ /dev/null @@ -1,27 +0,0 @@ -import * as Config from "./config.js"; -import {addServer, removeServer, reset, readServersFromLocalStorage} from "./icesettings.js"; - -const addButton = document.querySelector('button#add'); -const removeButton = document.querySelector('button#remove'); -const resetButton = document.querySelector('button#reset'); -const startupDiv = document.getElementById("startup"); - -addButton.onclick = addServer; -removeButton.onclick = removeServer; -resetButton.onclick = reset; -startupDiv.innerHTML = ""; - -const displayConfig = async () => { - const res = await Config.getServerConfig(); - if (res.useWebSocket) { - startupDiv.innerHTML += "
  • Signaling Protocol : WebSocket
  • "; - } else { - startupDiv.innerHTML += "
  • Signaling Protocol : HTTP
  • "; - } - - const mode = res.startupMode.replace(/^./, res.startupMode[0].toUpperCase()); - startupDiv.innerHTML += `
  • Signaling Mode : ${mode}
  • `; -}; - -displayConfig(); -readServersFromLocalStorage(); diff --git a/WebApp/client/public/js/stats.js b/WebApp/client/public/js/stats.js deleted file mode 100644 index 6d60671..0000000 --- a/WebApp/client/public/js/stats.js +++ /dev/null @@ -1,91 +0,0 @@ -/** - * create display string array from RTCStatsReport - * @param {RTCStatsReport} report - current RTCStatsReport - * @param {RTCStatsReport} lastReport - latest RTCStatsReport - * @return {Array} - display string Array - */ -export function createDisplayStringArray(report, lastReport) { - let array = new Array(); - - report.forEach(stat => { - if (stat.type === 'inbound-rtp') { - array.push(`${stat.kind} receiving stream stats`); - - if (stat.codecId != undefined) { - const codec = report.get(stat.codecId); - array.push(`Codec: ${codec.mimeType}`); - - if (codec.sdpFmtpLine) { - codec.sdpFmtpLine.split(";").forEach(fmtp => { - array.push(` - ${fmtp}`); - }); - } - - if (codec.payloadType) { - array.push(` - payloadType=${codec.payloadType}`); - } - - if (codec.clockRate) { - array.push(` - clockRate=${codec.clockRate}`); - } - - if (codec.channels) { - array.push(` - channels=${codec.channels}`); - } - } - - if (stat.kind == "video") { - array.push(`Decoder: ${stat.decoderImplementation}`); - array.push(`Resolution: ${stat.frameWidth}x${stat.frameHeight}`); - array.push(`Framerate: ${stat.framesPerSecond}`); - } - - if (lastReport && lastReport.has(stat.id)) { - const lastStats = lastReport.get(stat.id); - const duration = (stat.timestamp - lastStats.timestamp) / 1000; - const bitrate = (8 * (stat.bytesReceived - lastStats.bytesReceived) / duration) / 1000; - array.push(`Bitrate: ${bitrate.toFixed(2)} kbit/sec`); - } - } else if (stat.type === 'outbound-rtp') { - array.push(`${stat.kind} sending stream stats`); - - if (stat.codecId != undefined) { - const codec = report.get(stat.codecId); - array.push(`Codec: ${codec.mimeType}`); - - if (codec.sdpFmtpLine) { - codec.sdpFmtpLine.split(";").forEach(fmtp => { - array.push(` - ${fmtp}`); - }); - } - - if (codec.payloadType) { - array.push(` - payloadType=${codec.payloadType}`); - } - - if (codec.clockRate) { - array.push(` - clockRate=${codec.clockRate}`); - } - - if (codec.channels) { - array.push(` - channels=${codec.channels}`); - } - } - - if (stat.kind == "video") { - array.push(`Encoder: ${stat.encoderImplementation}`); - array.push(`Resolution: ${stat.frameWidth}x${stat.frameHeight}`); - array.push(`Framerate: ${stat.framesPerSecond}`); - } - - if (lastReport && lastReport.has(stat.id)) { - const lastStats = lastReport.get(stat.id); - const duration = (stat.timestamp - lastStats.timestamp) / 1000; - const bitrate = (8 * (stat.bytesSent - lastStats.bytesSent) / duration) / 1000; - array.push(`Bitrate: ${bitrate.toFixed(2)} kbit/sec`); - } - } - }); - - return array; -} \ No newline at end of file diff --git a/WebApp/client/public/js/videoplayer.js b/WebApp/client/public/js/videoplayer.js deleted file mode 100644 index 6945540..0000000 --- a/WebApp/client/public/js/videoplayer.js +++ /dev/null @@ -1,213 +0,0 @@ -import { Observer, Sender } from "../module/sender.js"; -import { InputRemoting } from "../module/inputremoting.js"; - -export class VideoPlayer { - constructor() { - this.playerElement = null; - this.lockMouseCheck = null; - this.videoElement = null; - this.fullScreenButtonElement = null; - this.inputRemoting = null; - this.sender = null; - this.inputSenderChannel = null; - } - - /** - * @param {Element} playerElement parent element for create video player - * @param {HTMLInputElement} lockMouseCheck use checked propety for lock mouse - */ - createPlayer(playerElement, lockMouseCheck) { - this.playerElement = playerElement; - this.lockMouseCheck = lockMouseCheck; - - this.videoElement = document.createElement('video'); - this.videoElement.id = 'Video'; - this.videoElement.style.touchAction = 'none'; - this.videoElement.playsInline = true; - this.videoElement.srcObject = new MediaStream(); - this.videoElement.addEventListener('loadedmetadata', this._onLoadedVideo.bind(this), true); - this.playerElement.appendChild(this.videoElement); - - // add fullscreen button - this.fullScreenButtonElement = document.createElement('img'); - this.fullScreenButtonElement.id = 'fullscreenButton'; - this.fullScreenButtonElement.src = '../images/FullScreen.png'; - this.fullScreenButtonElement.addEventListener("click", this._onClickFullscreenButton.bind(this)); - this.playerElement.appendChild(this.fullScreenButtonElement); - - document.addEventListener('webkitfullscreenchange', this._onFullscreenChange.bind(this)); - document.addEventListener('fullscreenchange', this._onFullscreenChange.bind(this)); - this.videoElement.addEventListener("click", this._mouseClick.bind(this), false); - } - - _onLoadedVideo() { - this.videoElement.play(); - this.resizeVideo(); - } - - _onClickFullscreenButton() { - if (!document.fullscreenElement || !document.webkitFullscreenElement) { - if (document.documentElement.requestFullscreen) { - document.documentElement.requestFullscreen(); - } - else if (document.documentElement.webkitRequestFullscreen) { - document.documentElement.webkitRequestFullscreen(Element.ALLOW_KEYBOARD_INPUT); - } else { - if (this.playerElement.style.position == "absolute") { - this.playerElement.style.position = "relative"; - } else { - this.playerElement.style.position = "absolute"; - } - } - } - } - - _onFullscreenChange() { - if (document.webkitFullscreenElement || document.fullscreenElement) { - this.playerElement.style.position = "absolute"; - this.fullScreenButtonElement.style.display = 'none'; - - if (this.lockMouseCheck.checked) { - if (document.webkitFullscreenElement.requestPointerLock) { - document.webkitFullscreenElement.requestPointerLock(); - } else if (document.fullscreenElement.requestPointerLock) { - document.fullscreenElement.requestPointerLock(); - } else if (document.mozFullScreenElement.requestPointerLock) { - document.mozFullScreenElement.requestPointerLock(); - } - - // Subscribe to events - document.addEventListener('mousemove', this._mouseMove.bind(this), false); - document.addEventListener('click', this._mouseClickFullScreen.bind(this), false); - } - } - else { - this.playerElement.style.position = "relative"; - this.fullScreenButtonElement.style.display = 'block'; - - document.removeEventListener('mousemove', this._mouseMove.bind(this), false); - document.removeEventListener('click', this._mouseClickFullScreen.bind(this), false); - } - } - - _mouseMove(event) { - // Forward mouseMove event of fullscreen player directly to sender - // This is required, as the regular mousemove event doesn't fire when in fullscreen mode - this.sender._onMouseEvent(event); - } - - _mouseClick() { - // Restores pointer lock when we unfocus the player and click on it again - if (this.lockMouseCheck.checked) { - if (this.videoElement.requestPointerLock) { - this.videoElement.requestPointerLock().catch(function () { }); - } - } - } - - _mouseClickFullScreen() { - // Restores pointer lock when we unfocus the fullscreen player and click on it again - if (this.lockMouseCheck.checked) { - if (document.webkitFullscreenElement.requestPointerLock) { - document.webkitFullscreenElement.requestPointerLock(); - } else if (document.fullscreenElement.requestPointerLock) { - document.fullscreenElement.requestPointerLock(); - } else if (document.mozFullScreenElement.requestPointerLock) { - document.mozFullScreenElement.requestPointerLock(); - } - } - } - - /** - * @param {MediaStreamTrack} track - */ - addTrack(track) { - if (!this.videoElement.srcObject) { - return; - } - - this.videoElement.srcObject.addTrack(track); - } - - resizeVideo() { - if (!this.videoElement) { - return; - } - - const clientRect = this.videoElement.getBoundingClientRect(); - const videoRatio = this.videoWidth / this.videoHeight; - const clientRatio = clientRect.width / clientRect.height; - - this._videoScale = videoRatio > clientRatio ? clientRect.width / this.videoWidth : clientRect.height / this.videoHeight; - const videoOffsetX = videoRatio > clientRatio ? 0 : (clientRect.width - this.videoWidth * this._videoScale) * 0.5; - const videoOffsetY = videoRatio > clientRatio ? (clientRect.height - this.videoHeight * this._videoScale) * 0.5 : 0; - this._videoOriginX = clientRect.left + videoOffsetX; - this._videoOriginY = clientRect.top + videoOffsetY; - } - - get videoWidth() { - return this.videoElement.videoWidth; - } - - get videoHeight() { - return this.videoElement.videoHeight; - } - - get videoOriginX() { - return this._videoOriginX; - } - - get videoOriginY() { - return this._videoOriginY; - } - - get videoScale() { - return this._videoScale; - } - - deletePlayer() { - if (this.inputRemoting) { - this.inputRemoting.stopSending(); - } - this.inputRemoting = null; - this.sender = null; - this.inputSenderChannel = null; - - while (this.playerElement.firstChild) { - this.playerElement.removeChild(this.playerElement.firstChild); - } - - this.playerElement = null; - this.lockMouseCheck = null; - } - - _isTouchDevice() { - return (('ontouchstart' in window) || - (navigator.maxTouchPoints > 0) || - (navigator.msMaxTouchPoints > 0)); - } - - /** - * setup datachannel for player input (muouse/keyboard/touch/gamepad) - * @param {RTCDataChannel} channel - */ - setupInput(channel) { - this.sender = new Sender(this.videoElement); - this.sender.addMouse(); - this.sender.addKeyboard(); - if (this._isTouchDevice()) { - this.sender.addTouchscreen(); - } - this.sender.addGamepad(); - this.inputRemoting = new InputRemoting(this.sender); - - this.inputSenderChannel = channel; - this.inputSenderChannel.onopen = this._onOpenInputSenderChannel.bind(this); - this.inputRemoting.subscribe(new Observer(this.inputSenderChannel)); - } - - async _onOpenInputSenderChannel() { - await new Promise(resolve => setTimeout(resolve, 100)); - this.inputRemoting.startSending(); - } -} \ No newline at end of file diff --git a/WebApp/client/public/multiplay/css/style.css b/WebApp/client/public/multiplay/css/style.css deleted file mode 100644 index 73ce19f..0000000 --- a/WebApp/client/public/multiplay/css/style.css +++ /dev/null @@ -1,99 +0,0 @@ -body { - margin: 0px; -} - -#player { - position: relative; - top: 0; - right: 0; - bottom: 0; - left: 0; - align-items: center; - justify-content: center; - display: flex; - background-color: #323232; -} - -#player:before { - content: ""; - display: block; - padding-top: 66%; -} - -#playButton { - width: 15%; - max-width: 200px; - cursor: pointer; -} - -#Video { - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; -} - -#VideoThumbnail { - position: absolute; - top: 0; - left: 0; - width: 30%; - height: 30%; -} - -#greenButton { - position: absolute; - bottom: 10px; - left: 10px; - width: 160px; - background-color: #4CAF50; - /* Green */ - border: none; - color: white; - padding: 15px 32px; - text-align: center; - text-decoration: none; - display: inline-block; - font-size: 16px; -} - -#blueButton { - position: absolute; - bottom: 10px; - left: 180px; - width: 160px; - background-color: #447FAF; - /* Blue */ - border: none; - color: white; - padding: 15px 32px; - text-align: center; - text-decoration: none; - display: inline-block; - font-size: 16px; -} - -#orangeButton { - position: absolute; - bottom: 10px; - left: 350px; - width: 160px; - background-color: #FF7700; - /* Blue */ - border: none; - color: white; - padding: 15px 32px; - text-align: center; - text-decoration: none; - display: inline-block; - font-size: 16px; -} - -#fullscreenButton { - position: absolute; - top: 25px; - right: 25px; - width: 32px; - height: 32px; -} \ No newline at end of file diff --git a/WebApp/client/public/multiplay/index.html b/WebApp/client/public/multiplay/index.html deleted file mode 100644 index 7cbf3d5..0000000 --- a/WebApp/client/public/multiplay/index.html +++ /dev/null @@ -1,53 +0,0 @@ - - - - - - - - - Multiplay Sample - - - - -
    -

    Multiplay Sample

    - - - -
    - -
    - Codec preferences: - -
    - -
    - Lock Cursor to Player: - -
    - -

    - For more information about sample, see Multiplay sample document page. -

    - -
    - -
    - View source on GitHub -
    -
    - - - - - - - - - diff --git a/WebApp/client/public/multiplay/js/main.js b/WebApp/client/public/multiplay/js/main.js deleted file mode 100644 index b9f147c..0000000 --- a/WebApp/client/public/multiplay/js/main.js +++ /dev/null @@ -1,203 +0,0 @@ -import { getServerConfig, getRTCConfiguration } from "../../js/config.js"; -import { createDisplayStringArray } from "../../js/stats.js"; -import { VideoPlayer } from "../../js/videoplayer.js"; -import { RenderStreaming } from "../../module/renderstreaming.js"; -import { Signaling, WebSocketSignaling } from "../../module/signaling.js"; - -/** @enum {number} */ -const ActionType = { - ChangeLabel: 0 -}; - -/** @type {Element} */ -let playButton; -/** @type {RenderStreaming} */ -let renderstreaming; -/** @type {boolean} */ -let useWebSocket; -/** @type {RTCDataChannel} */ -let multiplayChannel; - -const codecPreferences = document.getElementById('codecPreferences'); -const supportsSetCodecPreferences = window.RTCRtpTransceiver && - 'setCodecPreferences' in window.RTCRtpTransceiver.prototype; -const messageDiv = document.getElementById('message'); -messageDiv.style.display = 'none'; - -const playerDiv = document.getElementById('player'); -const lockMouseCheck = document.getElementById('lockMouseCheck'); -const videoPlayer = new VideoPlayer(); - -setup(); - -window.document.oncontextmenu = function () { - return false; // cancel default menu -}; - -window.addEventListener('resize', function () { - videoPlayer.resizeVideo(); -}, true); - -window.addEventListener('beforeunload', async () => { - if(!renderstreaming) - return; - await renderstreaming.stop(); -}, true); - -async function setup() { - const res = await getServerConfig(); - useWebSocket = res.useWebSocket; - showWarningIfNeeded(res.startupMode); - showCodecSelect(); - showPlayButton(); -} - -function showWarningIfNeeded(startupMode) { - const warningDiv = document.getElementById("warning"); - if (startupMode == "private") { - warningDiv.innerHTML = "

    Warning

    This sample is not working on Private Mode."; - warningDiv.hidden = false; - } -} - -function showPlayButton() { - if (!document.getElementById('playButton')) { - const elementPlayButton = document.createElement('img'); - elementPlayButton.id = 'playButton'; - elementPlayButton.src = '../../images/Play.png'; - elementPlayButton.alt = 'Start Streaming'; - playButton = document.getElementById('player').appendChild(elementPlayButton); - playButton.addEventListener('click', onClickPlayButton); - } -} - -function onClickPlayButton() { - playButton.style.display = 'none'; - - // add video player - videoPlayer.createPlayer(playerDiv, lockMouseCheck); - setupRenderStreaming(); -} - -async function setupRenderStreaming() { - codecPreferences.disabled = true; - - const signaling = useWebSocket ? new WebSocketSignaling() : new Signaling(); - const config = getRTCConfiguration(); - renderstreaming = new RenderStreaming(signaling, config); - renderstreaming.onConnect = onConnect; - renderstreaming.onDisconnect = onDisconnect; - renderstreaming.onTrackEvent = (data) => videoPlayer.addTrack(data.track); - renderstreaming.onGotOffer = setCodecPreferences; - - await renderstreaming.start(); - await renderstreaming.createConnection(); -} - -function onConnect() { - const channel = renderstreaming.createDataChannel("input"); - videoPlayer.setupInput(channel); - multiplayChannel = renderstreaming.createDataChannel("multiplay"); - multiplayChannel.onopen = onOpenMultiplayChannel; - showStatsMessage(); -} - -async function onOpenMultiplayChannel() { - await new Promise(resolve => setTimeout(resolve, 100)); - const num = Math.floor(Math.random() * 100000); - const json = JSON.stringify({ type: ActionType.ChangeLabel, argument: String(num) }); - multiplayChannel.send(json); -} - -async function onDisconnect(connectionId) { - clearStatsMessage(); - messageDiv.style.display = 'block'; - messageDiv.innerText = `Disconnect peer on ${connectionId}.`; - - await renderstreaming.stop(); - renderstreaming = null; - multiplayChannel = null; - videoPlayer.deletePlayer(); - if (supportsSetCodecPreferences) { - codecPreferences.disabled = false; - } - showPlayButton(); -} - -function setCodecPreferences() { - /** @type {RTCRtpCodecCapability[] | null} */ - let selectedCodecs = null; - if (supportsSetCodecPreferences) { - const preferredCodec = codecPreferences.options[codecPreferences.selectedIndex]; - if (preferredCodec.value !== '') { - const [mimeType, sdpFmtpLine] = preferredCodec.value.split(' '); - const { codecs } = RTCRtpSender.getCapabilities('video'); - const selectedCodecIndex = codecs.findIndex(c => c.mimeType === mimeType && c.sdpFmtpLine === sdpFmtpLine); - const selectCodec = codecs[selectedCodecIndex]; - selectedCodecs = [selectCodec]; - } - } - - if (selectedCodecs == null) { - return; - } - const transceivers = renderstreaming.getTransceivers().filter(t => t.receiver.track.kind == "video"); - if (transceivers && transceivers.length > 0) { - transceivers.forEach(t => t.setCodecPreferences(selectedCodecs)); - } -} - -function showCodecSelect() { - if (!supportsSetCodecPreferences) { - messageDiv.style.display = 'block'; - messageDiv.innerHTML = `Current Browser does not support RTCRtpTransceiver.setCodecPreferences.`; - return; - } - - const codecs = RTCRtpSender.getCapabilities('video').codecs; - codecs.forEach(codec => { - if (['video/red', 'video/ulpfec', 'video/rtx'].includes(codec.mimeType)) { - return; - } - const option = document.createElement('option'); - option.value = (codec.mimeType + ' ' + (codec.sdpFmtpLine || '')).trim(); - option.innerText = option.value; - codecPreferences.appendChild(option); - }); - codecPreferences.disabled = false; -} - -/** @type {RTCStatsReport} */ -let lastStats; -/** @type {number} */ -let intervalId; - -function showStatsMessage() { - intervalId = setInterval(async () => { - if (renderstreaming == null) { - return; - } - - const stats = await renderstreaming.getStats(); - if (stats == null) { - return; - } - - const array = createDisplayStringArray(stats, lastStats); - if (array.length) { - messageDiv.style.display = 'block'; - messageDiv.innerHTML = array.join('
    '); - } - lastStats = stats; - }, 1000); -} - -function clearStatsMessage() { - if (intervalId) { - clearInterval(intervalId); - } - lastStats = null; - intervalId = null; - messageDiv.style.display = 'none'; - messageDiv.innerHTML = ''; -} diff --git a/WebApp/client/public/onebyone/README.md b/WebApp/client/public/onebyone/README.md deleted file mode 100644 index 27e4bfd..0000000 --- a/WebApp/client/public/onebyone/README.md +++ /dev/null @@ -1,157 +0,0 @@ -OneByOne 视频通话应用代码结构分析 -1. 项目概述 -OneByOne 是一个基于 WebRTC 和 WebSocket 的一对一视频通话应用,具有现代化的用户界面和丰富的功能。 - -2. 目录结构 - -plainText -onebyone/ -├── index.html # 主HTML文件,包含页面结构 -├── main.js # 主入口文件,初始化应用 -├── renderer.js # UI渲染器,负责将状态映射到DOM -├── store.js # 状态管理,使用Observable模式 -├── models.js # 数据模型定义 -├── websocket.js # WebSocket管理 -├── utils.js # 工具函数 -└── style.css # 样式文件 -3. 核心模块分析 -3.1 数据模型 (models.js) -定义了应用的核心数据结构: - -CallSession: 通话会话,包含通话ID、类型、状态、时长等信息 -LocalUser: 本地用户,包含用户ID、名称、头像、媒体状态等 -RemoteUser: 远端用户,包含用户ID、名称、头像、状态、网络质量等 -MediaState: 媒体状态,包含音频、视频、屏幕共享、录屏、说话状态等 -ChatMessage: 聊天消息,包含消息ID、发送者信息、内容、类型、时间戳等 -3.2 状态管理 (store.js) -使用简单的 Observable 模式实现状态管理: - -核心状态:通话会话、消息列表、侧边栏状态、未读消息数、媒体流等 -状态更新方法: -updateLocalMedia(): 更新本地媒体状态 -updateRemoteMedia(): 更新远端媒体状态 -addMessage(): 添加消息 -toggleSidebar(): 切换侧边栏 -endCall(): 结束通话 -事件通知:通过 notify() 方法通知所有监听器状态变化 -3.3 UI渲染器 (renderer.js) -负责将状态映射到DOM: - -DOM元素缓存:缓存常用DOM元素,提高性能 -渲染方法: -renderHeader(): 渲染头部 -renderCallDuration(): 渲染通话时长 -renderRemoteVideo(): 渲染远端视频 -renderLocalVideo(): 渲染本地视频 -renderControlButtons(): 渲染控制按钮 -renderChatMessages(): 渲染聊天消息 -renderLocalUserStatus(): 渲染本地用户状态 -消息渲染:支持文本消息和图片消息的渲染 -3.4 WebSocket管理 (websocket.js) -管理WebSocket连接和事件: - -连接管理:连接、断开、重连 -消息处理:处理服务器发送的消息 -事件订阅:支持事件订阅和触发 -心跳检测:支持ping/pong心跳机制 -3.5 主入口 (main.js) -初始化应用,连接各个模块: - -应用初始化:初始化渲染器、WebSocket连接、事件绑定 -WebSocket事件绑定:处理服务器事件 -DOM事件绑定:处理用户交互 -功能实现: -麦克风、视频、录屏控制 -聊天消息发送 -图片上传和发送 -通话结束确认 -3.6 样式文件 (style.css) -提供应用的样式: - -基础样式:布局、颜色、字体等 -组件样式:玻璃效果、控制按钮、聊天消息等 -动画效果:消息滑入、音频波形、视频淡入等 -4. 核心功能 -4.1 视频通话 -支持一对一视频通话 -本地视频预览(画中画模式) -远端视频显示 -视频开关控制 -4.2 音频控制 -麦克风开关控制 -说话状态检测 -音频波形动画 -4.3 聊天功能 -文本消息发送 -图片消息发送(支持文件选择和预览) -消息时间戳 -消息类型区分(系统消息、自己的消息、对方的消息) -4.4 录屏功能 -录屏开关控制 -录制状态通知 -4.5 网络状态 -网络质量检测和显示 -连接状态提示 -4.6 其他功能 -端到端加密提示 -通话时长显示 -键盘快捷键(空格键静音,Ctrl+V切换视频) -通知系统 -5. 技术特点 -5.1 模块化设计 -代码按功能模块分离,职责清晰 -使用ES6模块系统,便于维护和扩展 -5.2 状态管理 -使用Observable模式实现简单的状态管理 -状态变化自动触发UI更新 -5.3 响应式设计 -使用Tailwind CSS实现响应式布局 -适配不同屏幕尺寸 -5.4 现代化UI -玻璃拟态效果 -平滑动画 -清晰的视觉层次 -5.5 事件驱动 -使用事件机制处理用户交互和系统通知 -松耦合的组件通信 -6. API接口 -应用定义了以下API接口: - -GET /api/call/:callId - 获取通话信息 -POST /api/call/:callId/join - 加入通话 -POST /api/call/:callId/leave - 离开通话 -POST /api/call/:callId/media - 更新媒体状态 -GET /api/call/:callId/messages - 获取历史消息 -POST /api/call/:callId/message - 发送消息 -7. WebSocket事件 -应用使用WebSocket处理实时通信,支持以下事件: - -connect - 连接建立 -disconnect - 连接断开 -user-joined - 用户加入 -user-left - 用户离开 -media-state-changed - 媒体状态变化 -message-received - 收到消息 -network-quality - 网络质量变化 -call-ended - 通话结束 -8. 代码优化建议 -错误处理:增加更完善的错误处理机制,特别是WebSocket连接和API调用 -性能优化: -减少DOM操作,使用虚拟DOM或批量更新 -优化图片加载和处理 -安全性: -增加输入验证,防止XSS攻击 -实现真正的端到端加密 -可扩展性: -考虑使用更成熟的状态管理库(如Redux) -增加单元测试和集成测试 -用户体验: -增加更多的动画和过渡效果 -优化移动端体验 -增加更多的用户反馈 -9. 总结 -OneByOne 是一个功能完整、界面现代化的一对一视频通话应用,采用了模块化设计和现代化的前端技术。它具有视频通话、音频控制、聊天功能、录屏功能等核心功能,并且支持实时通信和状态管理。 - -应用的代码结构清晰,职责分离明确,使用了Observable模式进行状态管理,WebSocket进行实时通信,Tailwind CSS进行样式设计。这些技术选择使得应用具有良好的可维护性和可扩展性。 - -通过进一步的优化和扩展,OneByOne可以成为一个功能更加强大、用户体验更加出色的视频通话应用。 diff --git a/WebApp/client/public/onebyone/chatmessage.js b/WebApp/client/public/onebyone/chatmessage.js deleted file mode 100644 index 043d16c..0000000 --- a/WebApp/client/public/onebyone/chatmessage.js +++ /dev/null @@ -1,248 +0,0 @@ -/** - * 消息模块 - * 处理聊天消息的发送、接收和显示 - */ -import { showNotification, generateId } from './utils.js'; -import store from './store.js'; -import { mockMessages } from './models.js'; - -const MAX_IMAGE_SIZE = 5 * 1024 * 1024; // 5MB - -// 消息相关的状态管理方法 -let messageState = { - messages: [...mockMessages], - unreadCount: 0, - isSidebarOpen: false -}; - -let listeners = []; - -/** - * 订阅状态变化 - * @param {Function} callback - 回调函数 - * @returns {Function} 取消订阅的函数 - */ -function subscribe(callback) { - listeners.push(callback); - return () => { - listeners = listeners.filter(cb => cb !== callback); - }; -} - -/** - * 通知所有监听器 - * @param {Object} changes - 变化对象 - */ -function notify(changes) { - listeners.forEach(cb => cb(messageState, changes)); -} - -/** - * 添加消息 - * @param {Object} message - 消息对象 - */ -function addMessage (message) { - messageState.messages.push(message); - - // 如果侧边栏关闭且不是自己发的,增加未读 - if (!messageState.isSidebarOpen && !message.isSelf) { - messageState.unreadCount++; - notify({ type: 'SIDEBAR_TOGGLE', unreadCount: messageState.unreadCount }); - } - - notify({ type: 'NEW_MESSAGE', message, unreadCount: messageState.unreadCount }); -} - -/** - * 发送聊天消息 - * @param {Object} message - 消息对象 - * @param {Object} renderstreaming - WebRTC连接管理实例 - */ -function sendChatMessage(message) { - if (store.getRenderStreaming()) { - store.getRenderStreaming().sendMessage({ - type: 'chat-message', - message: message, - }); - } -} - -/** - * 处理接收到的聊天消息 - * @param {Object} data - 消息数据 - */ -function handleChatMessage(data) { - console.log('处理聊天:', data); - addMessage(data); - - const isImage = data.content && data.content.startsWith('data:image/'); - - // 显示通知 - if (!data.isSelf) { - const content = isImage ? '[图片]' : data.content; - showNotification(`${data.senderName}: ${content.substring(0, 20)}${content.length > 20 ? '...' : ''}`); - } -} - -/** - * 切换侧边栏 - * @returns {boolean} 切换后的状态 - */ -function toggleSidebar() { - messageState.isSidebarOpen = !messageState.isSidebarOpen; - if (messageState.isSidebarOpen) { - messageState.unreadCount = 0; - } - notify({ type: 'SIDEBAR_TOGGLE', isOpen: messageState.isSidebarOpen, unreadCount: messageState.unreadCount }); - return messageState.isSidebarOpen; -} - -/** - * 获取消息状态 - * @returns {Object} 消息状态 - */ -function getMessageState() { - return messageState; -} - -/** - * 发送消息 - */ -function sendMessage() { - const chatInput = document.getElementById('chatInput'); - const content = chatInput.value.trim(); - - if (content) { - const state = store.getState(); - const message = { - id: generateId(), - senderId: state.session.localUser.id, - senderName: state.session.localUser.name, - senderAvatar: state.session.localUser.avatar, - content: content, - type: 'text', - timestamp: new Date().toISOString(), - isSelf: true - }; - - addMessage(message); - - const newMessage = { ...message }; - newMessage.isSelf = false; - chatInput.value = ''; - // 发送消息到服务器 - sendChatMessage(newMessage); - - //wsManager.send('chat-message', message); - } -} - -/** - * 处理聊天输入回车 - * @param {KeyboardEvent} event - 键盘事件 - */ -function handleChatSubmit(event) { - if (event.key === 'Enter') { - sendMessage(); - } -} - -/** - * 打开图片选择器 - */ -function openImagePicker() { - document.getElementById('imageInput').click(); -} - -/** - * 处理图片上传 - * @param {Event} event - 事件对象 - */ -function handleImageUpload(event) { - const file = event.target.files[0]; - if (file) { - // 检查文件类型 - if (!file.type.startsWith('image/')) { - showNotification('请选择图片文件', 3000); - return; - } - - // 检查文件大小(限制为5MB) - if (file.size > MAX_IMAGE_SIZE) { - showNotification('图片文件不能超过5MB', 3000); - return; - } - - // 读取图片文件 - const reader = new FileReader(); - reader.onload = function (e) { - const imageUrl = e.target.result; - sendImageMessage(imageUrl, file.name); - }; - reader.readAsDataURL(file); - - // 重置文件输入 - event.target.value = ''; - } -} - -/** - * 发送图片消息 - * @param {string} imageUrl - 图片URL - * @param {string} fileName - 文件名 - */ -function sendImageMessage(imageUrl, fileName) { - const state = store.getState(); - const newMessage = { - id: generateId(), - senderId: state.session.localUser.id, - senderName: state.session.localUser.name, - senderAvatar: state.session.localUser.avatar, - content: imageUrl, - fileName: fileName, - type: 'file', - timestamp: new Date().toISOString(), - isSelf: true - }; - - // 添加消息到本地列表 - addMessage(newMessage); - - // 发送消息到服务器 - const messageToSend = { ...newMessage }; - messageToSend.isSelf = false; - sendChatMessage(messageToSend); -} - -/** - * 绑定消息相关的DOM事件 - */ -function bindMessageEvents() { - // 发送消息 - window.sendMessage = sendMessage; - - // 处理聊天输入回车 - window.handleChatSubmit = handleChatSubmit; - - // 打开图片选择器 - window.openImagePicker = openImagePicker; - - // 处理图片上传 - window.handleImageUpload = handleImageUpload; -} - -// 导出所有函数 -export default { - sendMessage, - handleChatSubmit, - openImagePicker, - handleImageUpload, - sendImageMessage, - bindMessageEvents, - addMessage, - sendChatMessage, - handleChatMessage, - toggleSidebar, - getMessageState, - subscribe -}; diff --git a/WebApp/client/public/onebyone/code-structure.md b/WebApp/client/public/onebyone/code-structure.md deleted file mode 100644 index f3731e0..0000000 --- a/WebApp/client/public/onebyone/code-structure.md +++ /dev/null @@ -1,458 +0,0 @@ -# onebyone 模块代码调用结构图 - -> 本文档基于优化后的代码自动生成,反映当前实际架构。 - ---- - -## 3.1 文件依赖关系图 - -```mermaid -graph TD - main[main.js] --> store[store.js] - main --> renderer[renderer.js] - main --> utils[utils.js] - main --> chatmsg[chatmessage.js] - - store --> models[models.js] - store --> utils - store --> chatmsg - store --> signaling[../../module/signaling.js] - store --> rs[../../module/renderstreaming.js] - store --> config[../js/config.js] - - renderer --> utils - renderer --> models - renderer --> chatmsg - renderer -.-> store - - chatmsg --> utils - chatmsg --> store - chatmsg --> models - - connect[connect/connect.js] --> store - connect --> utils - - endcall[endcall/endcall.js] --> utils - - index[index.html] --> main - connectHtml[connect/connect.html] --> connect - endcallHtml[endcall/endcall.html] --> endcall - - style utils fill:#e1f5fe - style models fill:#e1f5fe - style signaling fill:#fff3e0 - style rs fill:#fff3e0 - style config fill:#fff3e0 -``` - -**图例说明** -- 蓝色:内部工具/数据模块 -- 橙色:外部依赖模块(signaling.js、renderstreaming.js、config.js) - ---- - -## 3.2 核心调用链 - -### 通话初始化流程 - -```mermaid -sequenceDiagram - autonumber - participant Browser - participant main as main.js - participant store as store.js - participant render as renderer.js - participant RS as RenderStreaming - participant Sig as Signaling - - Browser->>main: DOMContentLoaded - main->>main: 检查 localStorage.connectionId - alt 无连接ID - main->>Browser: 跳转 connect/connect.html - else 有连接ID - main->>render: new UIRenderer(store) - render->>store: subscribe(render) - main->>store: joinCall(connectionId) - store->>store: init() - store->>store: setupConfig() / getServerConfig() - store->>store: loadUserSettings() - store->>store: getLocalStream() - store->>Browser: getUserMedia(MEDIA_CONSTRAINTS) - Browser-->>store: MediaStream - store->>store: notify(LOCAL_STREAM_OBTAINED) - store->>store: notify(LOCAL_MEDIA_CHANGE x2) - store->>store: emitMediaStateChange() - main->>store: setUp(connectionId) - store->>store: _createSignalingAndRTC() - store->>Sig: new WebSocketSignaling() / new Signaling() - store->>RS: new RenderStreaming(signaling, config) - store->>store: _registerCallbacks() - store->>store: _startConnection() - store->>RS: start() - store->>RS: createConnection(connectionId) - RS-->>store: onConnect(role, participantId) - store->>store: notify(CALL_STATUS_CHANGE, ongoing) - store->>store: sendMessage(user-info) - store->>store: emitMediaStateChange() - main->>main: bindDomEvents() - end -``` - -### 媒体控制流程 - -```mermaid -sequenceDiagram - autonumber - participant User - participant main as main.js - participant store as store.js - participant render as renderer.js - participant RS as RenderStreaming - participant Remote as 远端 - - User->>main: 点击 toggleMute / toggleVideo - main->>store: updateLocalMedia(type, value) - - alt 开启视频 - store->>Browser: getUserMedia(VIDEO_ONLY_CONSTRAINT) - Browser-->>store: newVideoTrack - store->>RS: replaceTrack / addTransceiver - store->>store: notify(LOCAL_STREAM_OBTAINED) - store->>store: notify(LOCAL_MEDIA_CHANGE, video=true) - store->>store: emitMediaStateChange() - else 关闭视频 - store->>store: track.stop() - store->>store: notify(LOCAL_MEDIA_CHANGE, video=false) - store->>store: emitMediaStateChange() - else 切换音频 - store->>store: track.enabled = value - store->>store: notify(LOCAL_MEDIA_CHANGE, audio=value) - store->>store: emitMediaStateChange() - end - - store->>render: notify(USER_LIST_UPDATE) - render->>render: renderUserList() - render->>render: renderControlButtons() - render->>render: renderLocalVideo() - - store->>RS: sendMessage(media-state-changed) - RS->>Remote: WebSocket 信令 - Remote-->>store: onMessage(media-state-changed) - store->>store: updateRemoteMedia() - store->>render: notify(REMOTE_MEDIA_CHANGE) - render->>render: renderRemoteVideo() - render->>render: renderUserList() - render->>render: renderParticipantVideoPlaceholder() -``` - -### 消息发送流程 - -```mermaid -sequenceDiagram - autonumber - participant User - participant chat as chatmessage.js - participant store as store.js - participant render as renderer.js - participant RS as RenderStreaming - participant Remote as 远端 - - User->>chat: 输入消息 / 回车 - chat->>chat: sendMessage() - chat->>chat: addMessage() 本地 - chat->>chat: notify(NEW_MESSAGE) - render->>render: renderMessageState(NEW_MESSAGE) - render->>render: renderChatMessages() - render->>render: renderUnreadCount() - - chat->>store: getRenderStreaming() - chat->>RS: sendMessage(chat-message) - RS->>Remote: WebSocket 信令 - - Remote-->>chat: handleChatMessage(data) - chat->>chat: addMessage() 远端 - chat->>chat: notify(NEW_MESSAGE) - render->>render: renderMessageState(NEW_MESSAGE) - render->>render: renderChatMessages() - render->>render: renderUnreadCount() - - User->>chat: 点击 toggleSidebar() - chat->>chat: notify(SIDEBAR_TOGGLE) - render->>render: renderMessageState(SIDEBAR_TOGGLE) - render->>render: renderSidebar() -``` - -### Participant 管理流程 - -```mermaid -sequenceDiagram - autonumber - participant store as store.js - participant render as renderer.js - participant RS as RenderStreaming - participant Remote as 远端Participant - - Note over RS,Remote: 新 Participant 加入 - RS-->>store: onParticipantJoined(participantId) - store->>store: 初始化 participant 默认信息 - store->>store: notify(PARTICIPANTS_UPDATE) - store->>RS: broadcastParticipantsList() - render->>render: renderUserList() - render->>render: syncParticipantTileNames() - - Note over RS,Remote: Participant 离开 - RS-->>store: onParticipantLeft(participantId) - store->>store: 清理 remoteStreams / participants - store->>store: notify(PARTICIPANT_LEFT) - store->>store: notify(PARTICIPANTS_UPDATE) - store->>RS: broadcastParticipantsList() - render->>render: renderParticipantLeft() - render->>render: renderUserList() - - Note over RS,Remote: 成员列表同步 - RS-->>store: onMessage(participants-sync) - store->>store: 过滤自身条目 -> state.participants - store->>store: notify(PARTICIPANTS_UPDATE) - render->>render: renderUserList() - render->>render: syncParticipantTileNames() -``` - ---- - -## 3.3 状态变化流转图 - -### Store -> Renderer 状态流转 - -```mermaid -graph LR - subgraph StoreNotify[store.js notify 类型] - A[INIT] - B[LOCAL_STREAM_OBTAINED] - C[LOCAL_MEDIA_CHANGE] - D[REMOTE_STREAM_OBTAINED] - E[REMOTE_MEDIA_CHANGE] - F[USER_LIST_UPDATE] - G[PARTICIPANTS_UPDATE] - H[NETWORK_CHANGE] - I[CALL_STATUS_CHANGE] - J[CALL_ENDED] - K[PARTICIPANT_LEFT] - L[DURATION_UPDATE] - end - - subgraph RenderMethod[renderer.js 渲染方法] - RM1[renderRemoteVideo] - RM2[renderLocalVideo] - RM3[renderLocalStream] - RM4[renderRemoteStream] - RM5[renderControlButtons] - RM6[renderUserList] - RM7[renderNetworkStatus] - RM8[renderCallStatus] - RM9[renderCallEnded] - RM10[renderParticipantLeft] - RM11[renderCallDuration] - RM12[renderHeader] - RM13[renderParticipantVideoPlaceholder] - RM14[syncParticipantTileNames] - end - - A --> RM1 & RM2 & RM5 & RM6 & RM12 - B --> RM3 & RM2 - C --> RM5 & RM2 & RM6 - D --> RM4 - E --> RM1 & RM6 & RM13 - F --> RM6 - G --> RM6 & RM14 - H --> RM7 - I --> RM8 - J --> RM9 - K --> RM10 - L --> RM11 -``` - -### chatMessage -> Renderer 状态流转 - -```mermaid -graph LR - subgraph ChatNotify[chatmessage.js notify 类型] - N[NEW_MESSAGE] - S[SIDEBAR_TOGGLE] - end - - subgraph MsgRender[renderer.js 消息渲染] - MR1[renderChatMessages] - MR2[renderUnreadCount] - MR3[renderSidebar] - end - - N --> MR1 & MR2 - S --> MR3 & MR2 -``` - ---- - -## 3.4 各模块导出函数清单 - -### main.js - -| 导出 | 类型 | 说明 | -|------|------|------| -| store | 变量 | 重新导出 store 单例,供外部调试使用 | - -**内部全局函数(绑定到 window):** - -| 函数 | 说明 | -|------|------| -| toggleSidebar | 切换侧边栏显示 | -| toggleMute | 切换麦克风状态 | -| toggleVideo | 切换摄像头状态 | -| toggleLocalVideo | 本地视频悬停控制 | -| toggleRecording | 切换录屏状态 | -| endCall | 显示结束通话确认对话框 | -| cancelEndCall | 取消结束通话 | -| confirmEndCall | 确认结束通话,调用 store.endCall() | -| showCallRequest | 显示通话请求弹窗 | -| rejectCall | 拒绝通话请求 | -| acceptCall | 接受通话请求,初始化通话 | - -### store.js (CallStateManager 类 / store 单例) - -| 方法 | 说明 | -|------|------| -| subscribe(callback) | 订阅状态变化 | -| notify(changes) | 通知所有监听器 | -| init() | 初始化配置、用户设置、本地流 | -| loadUserSettings() | 从 localStorage 加载用户设置 | -| setupConfig() | 获取服务器配置(WebSocket 模式) | -| getLocalStream() | 获取本地摄像头媒体流 | -| updateLocalMedia(mediaType, value) | 更新本地媒体状态(音频/视频/录屏) | -| _createSignalingAndRTC(connectionId) | 创建信令和 RTC 实例 | -| setUp(connectionId) | 设置 WebRTC 连接入口 | -| _registerCallbacks() | 注册所有 WebRTC 回调 | -| _startConnection(connectionId) | 启动连接和检测 | -| hangUp() | 挂断连接,清理资源 | -| sendMessage(type, data) | 通过 RenderStreaming 发送消息 | -| broadcastParticipantsList() | Host 端广播成员列表 | -| setCodecPreferences(participantId) | 设置 H264 编解码器偏好 | -| updateRemoteMedia(mediaState, participantId) | 更新远端媒体状态 | -| updateRemoteUserStatus(status) | 更新远端用户在线状态 | -| updateRemoteUserNetworkQuality(q) | 更新远端网络质量 | -| endCall() | 用户主动结束通话入口 | -| joinCall(connectionId) | 加入通话 | -| createCall() | 创建通话 | -| detectNetworkQuality() | 基于 WebRTC stats 检测网络质量 | -| startActivityDetection(stream, opts) | 启动音频活动检测(VAD) | -| startNetworkQualityDetection() | 启动定时网络质量检测 | -| stopNetworkQualityDetection() | 停止网络质量检测 | -| emitMediaStateChange() | 发送媒体状态变化信令 | -| showStatsMessage() | 显示并定时输出 WebRTC 统计信息 | -| clearStatsMessage() | 清除统计定时器 | -| getState / getLocalUser / getRemoteUser / getConnectionId / getRenderStreaming | Getter 方法 | - -### renderer.js (UIRenderer 类) - -| 方法 | 说明 | -|------|------| -| constructor(stateManager) | 构造函数,订阅 store 和 chatMessage | -| render(state, changes) | 核心渲染分发器,根据 changes.type 路由 | -| renderMessageState(msgState, changes) | 消息状态渲染分发器 | -| renderCallStatus(status) | 渲染通话状态(连接中覆盖层) | -| renderHeader(session) | 渲染头部信息 | -| renderHeaderTitle() | 渲染标题(含 connectionId) | -| renderCallDuration(duration) | 渲染通话时长 | -| renderRemoteVideo(remoteUser) | 渲染远端视频和占位符 | -| renderHeaderNetworkStatus(q) | 渲染头部网络质量文本 | -| renderLocalVideo(localUser, stream) | 渲染本地视频和占位符 | -| renderLocalStream(stream) | 将本地流绑定到 video 元素 | -| renderRemoteStream(stream, id, isHost) | 远端流渲染分发 | -| renderParticipantStream(stream, id) | Host 端多 participant 视频网格渲染 | -| renderParticipantVideoPlaceholder(id, show) | 精准更新 participant tile 占位背景 | -| syncParticipantTileNames(participants) | 同步所有 tile 名称标签 | -| updateParticipantTileName(id, name) | 更新指定 tile 名称 | -| renderSingleRemoteStream(stream) | Participant 端单路远端视频渲染 | -| renderLocalUserStatus(localUser) | 渲染本地用户媒体状态文本 | -| renderUserList(local, remote, participants) | 渲染侧边栏用户列表(支持多 participant) | -| createUserEntry(options) | 创建通用用户条目 DOM | -| getVideoResolution(track) | 获取视频轨道分辨率 | -| adjustVideoSize(video, resolution) | 调整视频元素尺寸 | -| renderControlButtons(mediaState) | 渲染底部控制按钮状态 | -| renderChatMessages(messages) | 渲染聊天消息列表 | -| createMessageElement(message) | 创建单条消息 DOM | -| renderUnreadCount(count) | 渲染未读消息角标 | -| renderSidebar(isOpen) | 渲染侧边栏显隐 | -| renderNetworkStatus(quality) | 渲染网络状态提示 | -| updateHeaderNetworkIndicator(q) | 更新头部网络指示器颜色 | -| renderCallEnded() | 渲染通话结束,跳转 endcall 页面 | -| renderParticipantLeft(id) | 清理 participant tile | -| getStatusText / getNetworkQualityText | 状态/质量文本映射 | -| destroy() | 销毁,取消订阅 | - -### chatmessage.js - -| 导出函数 | 说明 | -|----------|------| -| subscribe(callback) | 订阅消息状态变化 | -| addMessage(message) | 添加消息到列表 | -| sendChatMessage(message) | 通过 RenderStreaming 发送聊天消息 | -| handleChatMessage(data) | 处理接收到的聊天消息 | -| toggleSidebar() | 切换侧边栏,重置未读数 | -| getMessageState() | 获取当前消息状态 | -| sendMessage() | 用户发送消息入口(文本) | -| handleChatSubmit(event) | 回车发送处理 | -| openImagePicker() | 打开图片选择器 | -| handleImageUpload(event) | 处理图片上传(限制 5MB) | -| sendImageMessage(url, fileName) | 发送图片消息 | -| bindMessageEvents() | 绑定消息相关 DOM 事件到 window | - -### utils.js - -| 导出函数 | 说明 | -|----------|------| -| formatTime(seconds) | 格式化为 MM:SS | -| formatTimestamp(timestamp) | 格式化为 HH:MM | -| generateId() | 生成随机唯一 ID | -| showNotification(message, duration) | 显示顶部通知 | -| toggleElement(element, show) | 切换元素显隐(hidden 类) | -| toggleButtonState(button, active) | 切换按钮图标状态 | - -### models.js - -| 导出 | 类型 | 说明 | -|------|------|------| -| mockCallSession | 常量对象 | 默认通话会话数据结构(含 localUser / remoteUser) | -| mockMessages | 常量数组 | 默认聊天消息数组(含系统消息) | - -### connect/connect.js - -| 全局函数 | 说明 | -|----------|------| -| joinCall() | 读取输入框 connectionId,保存并跳转 | -| createCall() | 生成随机 connectionId,保存并跳转 | -| getAllConnectionIds() | 从服务器获取所有连接 ID 列表 | -| displayConnectionIds(ids) | 渲染连接 ID 列表到 DOM | -| selectConnectionId(id) | 选择指定 ID 填充输入框 | -| saveSettings() | 保存用户设置到 localStorage | -| handleAvatarUpload(event) | 上传头像(限制 2MB) | -| copyUserId() | 复制用户 ID 到剪贴板 | -| toggleSettingsMenu() | 切换设置菜单显隐 | - -### endcall/endcall.js - -| 全局函数 | 说明 | -|----------|------| -| reconnectCall() | 重新连接,跳转 index.html | -| leaveCall() | 清除 connectionId,跳转 connect.html | - ---- - -## 附录:页面跳转关系 - -```mermaid -graph LR - connect[connect/connect.html] -->|joinCall / createCall| index[index.html] - index -->|endCall| endcall[endcall/endcall.html] - endcall -->|reconnectCall| index - endcall -->|leaveCall| connect - index -->|无 connectionId| connect -``` diff --git a/WebApp/client/public/onebyone/connect/connect.html b/WebApp/client/public/onebyone/connect/connect.html deleted file mode 100644 index 7ef9a18..0000000 --- a/WebApp/client/public/onebyone/connect/connect.html +++ /dev/null @@ -1,114 +0,0 @@ - - - - - - VideoCall - 连接界面 - - - - - - -
    - - - - -
    - -
    -
    -
    - -
    -

    VideoCall

    -

    一对一视频通话

    - -
    -
    - - -
    -

    - 连接ID是用于建立点对点通话的唯一标识,由发起方生成并分享给接收方。 -

    -
    - -
    - - -
    - - - - - - -
    -
    - - -
    - - 通知内容 -
    - - - - - diff --git a/WebApp/client/public/onebyone/connect/connect.js b/WebApp/client/public/onebyone/connect/connect.js deleted file mode 100644 index ccd4e35..0000000 --- a/WebApp/client/public/onebyone/connect/connect.js +++ /dev/null @@ -1,323 +0,0 @@ -/** - * 连接界面逻辑 - * 处理初始连接、创建通话和加入通话的功能 - */ - -import { showNotification } from '../utils.js'; - -const MAX_AVATAR_SIZE = 2 * 1024 * 1024; // 2MB - -// 加入通话 -function joinCall() { - const connectionId = document.getElementById('connectionIdInput').value.trim(); - if (connectionId) { - showNotification(`正在加入通话 (${connectionId})`); - - // 保存连接ID到本地存储 - localStorage.setItem('connectionId', connectionId); - - // 跳转到通话界面 - window.location.href = '../index.html'; - } else { - showNotification('请输入连接ID', 'error'); - } -} - -// 创建通话 -function createCall() { - showNotification('正在创建通话...'); - - // 生成随机连接ID - const connectionId = 'conn_' + Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15); - - // 保存连接ID到本地存储 - localStorage.setItem('connectionId', connectionId); - - // 跳转到通话界面 - window.location.href = '../index.html'; -} - - -// 获取所有连接ID -async function getAllConnectionIds() { - showNotification('正在获取连接ID列表...'); - try { - const response = await fetch('/signaling/connection-ids'); - if (!response.ok) { - throw new Error('Failed to fetch connection IDs'); - } - const data = await response.json(); - displayConnectionIds(data.connectionIds); - } catch (error) { - console.error('Error fetching connection IDs:', error); - showNotification('获取连接ID失败', 'error'); - } -} - -// 显示连接ID列表 -function displayConnectionIds(connectionIds) { - const idsContainer = document.getElementById('idsContainer'); - const connectionIdsList = document.getElementById('connectionIdsList'); - - if (idsContainer) { - // 清空容器 - idsContainer.innerHTML = ''; - - if (connectionIds.length === 0) { - idsContainer.innerHTML = '

    暂无可用的连接ID

    '; - } else { - // 为每个连接ID创建一个元素 - connectionIds.forEach(id => { - const idElement = document.createElement('div'); - idElement.className = 'flex items-center justify-between p-2 bg-white/5 rounded-lg hover:bg-white/10 cursor-pointer transition-colors'; - idElement.innerHTML = ` - ${id} - - `; - idsContainer.appendChild(idElement); - }); - } - - // 显示连接ID列表 - if (connectionIdsList) { - connectionIdsList.classList.remove('hidden'); - } - - showNotification(`找到 ${connectionIds.length} 个连接ID`); - } -} - -// 选择连接ID -function selectConnectionId(id) { - const connectionIdInput = document.getElementById('connectionIdInput'); - if (connectionIdInput) { - connectionIdInput.value = id; - showNotification(`已选择连接ID: ${id}`); - } -} - -// 绑定事件监听器 -function bindEvents() { - // 连接按钮 - const connectBtn = document.getElementById('connectBtn'); - if (connectBtn) { - connectBtn.addEventListener('click', joinCall); - } - - // 创建通话按钮 - const createCallBtn = document.getElementById('createCallBtn'); - if (createCallBtn) { - createCallBtn.addEventListener('click', createCall); - } - - // 浏览全部ID按钮 - const browseIdsBtn = document.getElementById('browseIdsBtn'); - if (browseIdsBtn) { - browseIdsBtn.addEventListener('click', getAllConnectionIds); - } - - // 输入框回车事件 - const connectionIdInput = document.getElementById('connectionIdInput'); - if (connectionIdInput) { - connectionIdInput.addEventListener('keypress', (e) => { - if (e.key === 'Enter') { - joinCall(); - } - }); - } -} - -// 生成8位的用户ID -function generateUserId() { - // 生成8位随机字符串,包含字母和数字 - const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; - let result = 'user_'; - for (let i = 0; i < 8; i++) { - result += chars.charAt(Math.floor(Math.random() * chars.length)); - } - return result; -} - -// 加载用户设置 -function loadUserSettings() { - const defaultAvatar = '/images/p1.png'; - const userSettings = localStorage.getItem('userSettings'); - if (userSettings) { - try { - const settings = JSON.parse(userSettings); - - // 设置用户ID - if (settings.userId) { - document.getElementById('userIdInput').value = settings.userId; - } - - // 设置昵称 - if (settings.name) { - document.getElementById('nicknameInput').value = settings.name; - document.getElementById('userName').textContent = settings.name; - } - - // 设置头像 - const avatar = settings.avatar || defaultAvatar; - document.getElementById('userAvatar').src = avatar; - document.getElementById('avatarPreview').src = avatar; - } catch (error) { - console.error('Error loading user settings:', error); - // 加载失败时使用默认头像 - const defaultAvatar = '/images/p1.png'; - document.getElementById('userAvatar').src = defaultAvatar; - document.getElementById('avatarPreview').src = defaultAvatar; - } - } else { - // 生成新的用户ID - const newUserId = generateUserId(); - document.getElementById('userIdInput').value = newUserId; - - // 使用默认头像 - const defaultAvatar = '/images/p1.png'; - document.getElementById('userAvatar').src = defaultAvatar; - document.getElementById('avatarPreview').src = defaultAvatar; - - // 保存默认设置 - saveSettings(); - } -} - -// 保存用户设置 -function saveSettings() { - const defaultAvatar = '/images/p1.png'; - const settings = { - userId: document.getElementById('userIdInput').value, - name: document.getElementById('nicknameInput').value || '我', - avatar: document.getElementById('avatarPreview').src || defaultAvatar - }; - - localStorage.setItem('userSettings', JSON.stringify(settings)); - - // 更新界面显示 - document.getElementById('userName').textContent = settings.name; - document.getElementById('userAvatar').src = settings.avatar; - - showNotification('设置已保存', 'success'); -} - -// 处理头像上传 -function handleAvatarUpload(event) { - const file = event.target.files[0]; - if (file) { - // 检查文件类型 - if (!file.type.startsWith('image/')) { - showNotification('请选择图片文件', 'error'); - return; - } - - // 检查文件大小 - if (file.size > MAX_AVATAR_SIZE) { // 2MB限制 - showNotification('图片大小不能超过2MB', 'error'); - return; - } - - // 创建FormData对象 - const formData = new FormData(); - formData.append('avatar', file); - formData.append('userId', document.getElementById('userIdInput').value); - - // 显示上传中通知 - showNotification('正在上传头像...'); - - // 上传头像到服务器 - fetch('/api/upload/avatar', { - method: 'POST', - body: formData - }) - .then(response => { - if (!response.ok) { - throw new Error('上传失败'); - } - return response.json(); - }) - .then(data => { - if (data.success && data.avatarUrl) { - // 更新预览和本地存储 - const avatarUrl = data.avatarUrl; - document.getElementById('avatarPreview').src = avatarUrl; - document.getElementById('userAvatar').src = avatarUrl; - - // 保存设置 - saveSettings(); - - showNotification('头像上传成功', 'success'); - } else { - throw new Error('上传失败:' + (data.message || '未知错误')); - } - }) - .catch(error => { - console.error('Error uploading avatar:', error); - showNotification('头像上传失败,请重试', 'error'); - - // 上传失败时,使用默认头像 - const defaultAvatar = '/images/p1.png'; - document.getElementById('avatarPreview').src = defaultAvatar; - }); - } -} - -// 复制用户ID到剪贴板 -function copyUserId() { - const userIdInput = document.getElementById('userIdInput'); - userIdInput.select(); - document.execCommand('copy'); - showNotification('用户ID已复制到剪贴板', 'success'); -} - -// 切换设置菜单 -function toggleSettingsMenu() { - const settingsMenu = document.getElementById('settingsMenu'); - settingsMenu.classList.toggle('hidden'); -} - -// 点击外部关闭设置菜单 -document.addEventListener('click', function(event) { - const settingsMenu = document.getElementById('settingsMenu'); - const userSettingsBtn = document.getElementById('userSettingsBtn'); - - if (!settingsMenu.contains(event.target) && !userSettingsBtn.contains(event.target)) { - settingsMenu.classList.add('hidden'); - } -}); - -// 绑定用户设置相关事件 -function bindUserSettingsEvents() { - // 设置按钮点击事件 - const userSettingsBtn = document.getElementById('userSettingsBtn'); - if (userSettingsBtn) { - userSettingsBtn.addEventListener('click', toggleSettingsMenu); - } -} - -// 页面加载完成后初始化 -window.addEventListener('DOMContentLoaded', () => { - bindEvents(); - bindUserSettingsEvents(); - - // 检查本地存储中是否有连接ID - const savedConnectionId = localStorage.getItem('connectionId'); - if (savedConnectionId) { - const connectionIdInput = document.getElementById('connectionIdInput'); - if (connectionIdInput) { - connectionIdInput.value = savedConnectionId; - } - } - - // 加载用户设置 - loadUserSettings(); -}); - -// 导出全局函数 -window.joinCall = joinCall; -window.createCall = createCall; -window.selectConnectionId = selectConnectionId; -window.saveSettings = saveSettings; -window.handleAvatarUpload = handleAvatarUpload; -window.copyUserId = copyUserId; -window.toggleSettingsMenu = toggleSettingsMenu; diff --git a/WebApp/client/public/onebyone/css/style.css b/WebApp/client/public/onebyone/css/style.css deleted file mode 100644 index 7277e68..0000000 --- a/WebApp/client/public/onebyone/css/style.css +++ /dev/null @@ -1,255 +0,0 @@ -@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap'); - -body { - font-family: 'Inter', sans-serif; - background: #0f172a; - overflow: hidden; -} - -.bg-grid { - background-image: - linear-gradient(rgba(99, 102, 241, 0.1) 1px, transparent 1px), - linear-gradient(90deg, rgba(99, 102, 241, 0.1) 1px, transparent 1px); - background-size: 40px 40px; - -} - -@keyframes gridMove { - 0% { transform: translate(0, 0); } - 100% { transform: translate(20px, 20px); } -} - -.glass { - background: rgba(30, 41, 59, 0.7); - backdrop-filter: blur(12px); - -webkit-backdrop-filter: blur(12px); - border: 1px solid rgba(255, 255, 255, 0.1); -} - -.glass-strong { - background: rgba(15, 23, 42, 0.9); - backdrop-filter: blur(20px); - -webkit-backdrop-filter: blur(20px); -} - -.control-btn { - transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); -} - -.control-btn:hover { - transform: translateY(-2px); - box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.3); -} - -.end-call-pulse { - animation: pulse-red 2s infinite; -} - -@keyframes pulse-red { - 0%, 100% { box-shadow: 0 0 0 0 rgba(239, 68, 68, 0.7); } - 50% { box-shadow: 0 0 0 15px rgba(239, 68, 68, 0); } -} - -.chat-bubble { - animation: messageSlide 0.3s ease-out; - margin-bottom: 12px; -} - -@keyframes messageSlide { - from { opacity: 0; transform: translateX(-10px); } - to { opacity: 1; transform: translateX(0); } -} - -/* 消息样式 */ -.message-header { - display: flex; - align-items: center; - gap: 8px; - margin-bottom: 4px; -} - -.message-header img { - width: 24px; - height: 24px; - border-radius: 50%; - object-fit: cover; -} - -.message-sender { - font-size: 12px; - font-weight: 500; -} - -.message-time { - font-size: 12px; - color: #94a3b8; -} - -.message-content { - padding: 8px 16px; - border-radius: 8px; - font-size: 14px; - max-width: 70%; -} - -/* 系统消息 */ -.message-system .message-sender { - color: #60a5fa; -} - -.message-system .message-content { - background-color: rgba(30, 64, 175, 0.3); - color: #ffffff; -} - -/* 对方消息 */ -.message-other .message-sender { - color: #a5b4fc; -} - -.message-other .message-content { - background-color: #1e293b; - color: #ffffff; - border-top-left-radius: 0; -} - -/* 自己的消息 */ -.message-self { - display: flex; - flex-direction: column; - align-items: flex-end; -} - -.message-self .message-header { - flex-direction: row-reverse; -} - -.message-self .message-sender { - color: #4ade80; -} - -.message-self .message-content { - background-color: #4f46e5; - color: #ffffff; - border-top-right-radius: 0; -} - -/* 图片消息样式 */ -.message-image-container { - display: flex; - flex-direction: column; - gap: 8px; -} - -.message-image { - max-width: 200px; - max-height: 200px; - border-radius: 8px; - object-fit: cover; -} - -.message-image-name { - font-size: 12px; - color: rgba(255, 255, 255, 0.7); - text-align: center; -} - -.message-text { - word-wrap: break-word; -} - -.custom-scrollbar::-webkit-scrollbar { - width: 6px; -} -.custom-scrollbar::-webkit-scrollbar-track { - background: rgba(255, 255, 255, 0.05); -} -.custom-scrollbar::-webkit-scrollbar-thumb { - background: rgba(255, 255, 255, 0.2); - border-radius: 3px; -} - -.audio-wave { - display: flex; - align-items: center; - gap: 3px; - height: 20px; -} - -.audio-wave span { - width: 3px; - background: #10b981; - border-radius: 2px; - animation: wave 1s ease-in-out infinite; -} - -.audio-wave span:nth-child(1) { animation-delay: 0s; height: 40%; } -.audio-wave span:nth-child(2) { animation-delay: 0.1s; height: 70%; } -.audio-wave span:nth-child(3) { animation-delay: 0.2s; height: 100%; } -.audio-wave span:nth-child(4) { animation-delay: 0.3s; height: 60%; } -.audio-wave span:nth-child(5) { animation-delay: 0.4s; height: 30%; } - -@keyframes wave { - 0%, 100% { transform: scaleY(0.5); } - 50% { transform: scaleY(1); } -} - -.video-fade-in { - animation: videoFadeIn 0.5s ease-out; -} - -@keyframes videoFadeIn { - from { opacity: 0; transform: scale(1.05); } - to { opacity: 1; transform: scale(1); } -} - -/* 数据绑定标记 - 开发调试时显示 -[data-field]::after { - content: attr(data-field); - position: absolute; - top: -18px; - right: 0; - background: #f59e0b; - color: #000; - font-size: 9px; - padding: 1px 4px; - border-radius: 3px; - opacity: 0; - transition: opacity 0.2s; - pointer-events: none; - z-index: 1000; - white-space: nowrap; -} -[data-field]:hover::after { opacity: 1; } -[data-field] { position: relative; }*/ - -/* 分辨率选项样式 */ -.resolution-option { - color: rgba(255, 255, 255, 0.8); - cursor: pointer; - transition: all 0.2s; -} -.resolution-option:hover { - color: white; -} -.resolution-option.active { - background: rgba(99, 102, 241, 0.3); - color: white; -} -.resolution-option.active::before { - content: '\f00c'; - font-family: 'Font Awesome 6 Free'; - font-weight: 900; - font-size: 10px; - margin-right: 6px; - color: #818cf8; -} - -/* 更多选项菜单动画 */ -#moreOptionsMenu { - animation: menuFadeIn 0.15s ease-out; -} -@keyframes menuFadeIn { - from { opacity: 0; transform: translateX(-50%) translateY(8px); } - to { opacity: 1; transform: translateX(-50%) translateY(0); } -} diff --git a/WebApp/client/public/onebyone/endcall/endcall.html b/WebApp/client/public/onebyone/endcall/endcall.html deleted file mode 100644 index 21710db..0000000 --- a/WebApp/client/public/onebyone/endcall/endcall.html +++ /dev/null @@ -1,50 +0,0 @@ - - - - - - VideoCall - 通话结束 - - - - - - -
    -
    -
    - -
    -

    通话已结束

    -

    连接已断开,请检查网络连接后重试

    -
    - - -
    -
    -

    连接ID: --

    -

    断开时间: --

    -
    -
    -
    - - -
    - - 通知内容 -
    - - - - - diff --git a/WebApp/client/public/onebyone/endcall/endcall.js b/WebApp/client/public/onebyone/endcall/endcall.js deleted file mode 100644 index 3cf0a70..0000000 --- a/WebApp/client/public/onebyone/endcall/endcall.js +++ /dev/null @@ -1,59 +0,0 @@ -/** - * 结束通话界面逻辑 - * 处理通话结束后的操作,如重新连接或返回连接界面 - */ - -import { showNotification } from '../utils.js'; - -// 重新连接 -function reconnectCall() { - showNotification('正在重新连接...'); - - // 跳转到通话界面 - window.location.href = '../index.html'; -} - -// 离开 -function leaveCall() { - // 清除本地存储中的连接ID - localStorage.removeItem('connectionId'); - - // 跳转到连接界面 - window.location.href = '../connect/connect.html'; -} - -// 绑定事件监听器 -function bindEvents() { - // 重新连接按钮 - const reconnectBtn = document.getElementById('reconnectBtn'); - if (reconnectBtn) { - reconnectBtn.addEventListener('click', reconnectCall); - } - - // 离开按钮 - const leaveBtn = document.getElementById('leaveBtn'); - if (leaveBtn) { - leaveBtn.addEventListener('click', leaveCall); - } -} - -// 页面加载完成后初始化 -window.addEventListener('DOMContentLoaded', () => { - bindEvents(); - - // 更新断开连接信息 - const disconnectConnectionId = document.getElementById('disconnectConnectionId'); - const disconnectTime = document.getElementById('disconnectTime'); - - if (disconnectConnectionId) { - disconnectConnectionId.textContent = localStorage.getItem('connectionId') || '--'; - } - - if (disconnectTime) { - disconnectTime.textContent = new Date().toLocaleString(); - } -}); - -// 导出全局函数 -window.reconnectCall = reconnectCall; -window.leaveCall = leaveCall; diff --git a/WebApp/client/public/onebyone/index.html b/WebApp/client/public/onebyone/index.html deleted file mode 100644 index e92815b..0000000 --- a/WebApp/client/public/onebyone/index.html +++ /dev/null @@ -1,614 +0,0 @@ - - - - - - - VideoCall - 一对一视频通话 - - - - - - - - - - - -
    -
    -
    - -
    -
    - -

    - 与 Sarah 的通话 -

    -
    - - - - 优秀 - - - 00:00 -
    -
    -
    - -
    - - - - -
    -
    - -
    - - -
    - - - - - -
    - - - - - -
    -
    -
    - -
    -

    等待对方连接...

    -

    请确保对方已加入通话

    -
    -
    - - - - - - - - - - - - -
    - - -
    - - - - - - - -
    - - - -
    - - -
    - -
    -
    - -
    - - - - -
    - - -
    - - - - - -
    - - - - - - - - - - - - - - -
    - - - -
    - - - - -
    - - -
    - -
    - -
    - - -
    - - 通知内容 -
    - - - - - - - - - - - - - - diff --git a/WebApp/client/public/onebyone/knowledge-graph.md b/WebApp/client/public/onebyone/knowledge-graph.md deleted file mode 100644 index 972e808..0000000 --- a/WebApp/client/public/onebyone/knowledge-graph.md +++ /dev/null @@ -1,365 +0,0 @@ -# OneByOne 知识图谱 - -## 1. 模块依赖关系图 - -```mermaid -graph TB - subgraph Page["📄 页面层"] - INDEX[index.html
    主通话页面] - CONN[connect/connect.html
    连接页面] - END[endcall/endcall.html
    结束页面] - end - - subgraph Core["⚙️ 核心模块"] - MAIN[main.js
    应用入口] - STORE[store.js
    状态管理] - RENDER[renderer.js
    UI渲染器] - CHAT[chatmessage.js
    消息模块] - end - - subgraph Base["📦 数据与工具"] - MODELS[models.js
    数据模型] - UTILS[utils.js
    工具函数] - end - - subgraph External["🔗 外部依赖"] - SIGNALING[signaling.js
    信令管理] - RENDERSTR[renderstreaming.js
    WebRTC管理] - CONFIG[config.js
    配置管理] - end - - INDEX --> MAIN - CONN --> CONN_JS[connect.js] - END --> END_JS[endcall.js] - - MAIN --> STORE - MAIN --> RENDER - MAIN --> UTILS - MAIN --> CHAT - - STORE --> MODELS - STORE --> SIGNALING - STORE --> RENDERSTR - STORE --> CONFIG - STORE --> UTILS - STORE --> CHAT - - RENDER --> UTILS - RENDER --> MODELS - RENDER --> CHAT - - CHAT --> UTILS - CHAT --> STORE - CHAT --> MODELS - - CONN_JS --> STORE - - style STORE fill:#f9f,stroke:#333,stroke-width:2px - style RENDER fill:#bbf,stroke:#333,stroke-width:2px - style CHAT fill:#bfb,stroke:#333,stroke-width:2px -``` - -## 2. 数据模型关系图 - -```mermaid -graph TB - subgraph Models["数据模型结构"] - SESSION[CallSession
    通话会话] - LOCAL[LocalUser
    本地用户] - REMOTE[RemoteUser
    远端用户] - MEDIA[MediaState
    媒体状态] - MSG[ChatMessage
    聊天消息] - end - - SESSION --> LOCAL - SESSION --> REMOTE - LOCAL --> MEDIA - REMOTE --> MEDIA - - style SESSION fill:#f96,stroke:#333,stroke-width:2px - style MEDIA fill:#9f6,stroke:#333,stroke-width:2px -``` - -### 模型属性说明 - -| 模型 | 属性 | -|-----|------| -| **CallSession** | id, type, status, startTime, duration, isEncrypted | -| **LocalUser** | id, name, avatar, isHost, mediaState | -| **RemoteUser** | id, name, avatar, status, networkQuality, mediaState | -| **MediaState** | audio, video, screenShare, recording, isSpeaking | -| **ChatMessage** | id, senderId, senderName, content, type, timestamp, isSelf | - -## 3. 状态更新时序图 - -```mermaid -sequenceDiagram - autonumber - participant USER as 👤 用户 - participant DOM as 🖱️ DOM事件 - participant MAIN as ⚙️ main.js - participant STORE as 📦 store.js - participant RENDER as 🎨 renderer.js - participant UI as 🖥️ UI界面 - - USER->>DOM: 点击麦克风按钮 - DOM->>MAIN: toggleMute() - MAIN->>STORE: updateLocalMedia('audio', false) - STORE->>STORE: 更新 mediaState.audio - STORE->>STORE: notify({type: 'LOCAL_MEDIA_CHANGE'}) - STORE->>RENDER: 回调 render(state, changes) - RENDER->>RENDER: renderControlButtons(mediaState) - RENDER->>RENDER: renderLocalUserStatus(localUser) - RENDER->>UI: 更新DOM - UI->>USER: 显示更新后的界面 -``` - -## 4. WebRTC 连接建立时序图 - -```mermaid -sequenceDiagram - autonumber - participant USER as 👤 用户 - participant MAIN as ⚙️ main.js - participant STORE as 📦 store.js - participant SIGNAL as 📡 signaling.js - participant RTC as 🔗 renderstreaming.js - participant PEER as 👤 远端对等端 - - USER->>MAIN: 访问页面 - MAIN->>STORE: joinCall(connectionId) - STORE->>STORE: init() - STORE->>STORE: getLocalStream()
    获取本地摄像头 - MAIN->>STORE: setUp(connectionId) - STORE->>SIGNAL: 创建信令实例 - STORE->>RTC: new RenderStreaming
    (signaling, config) - RTC->>SIGNAL: start() - RTC->>SIGNAL: createConnection(connectionId) - - loop WebSocket信令交换 - PEER->>SIGNAL: 交换SDP/ICE - SIGNAL->>RTC: 信令数据 - end - - RTC->>STORE: onConnect 回调 - STORE->>STORE: 状态更新为 ongoing - PEER->>RTC: 接收媒体流 - RTC->>STORE: onTrackEvent 回调 - STORE->>STORE: notify(REMOTE_STREAM_OBTAINED) - STORE->>RENDER: 触发渲染更新 - RENDER->>UI: 显示远端视频 -``` - -## 5. 消息发送流程 - -```mermaid -sequenceDiagram - autonumber - participant USER as 👤 用户 - participant DOM as 🖱️ DOM - participant CHAT as 💬 chatmessage.js - participant STORE as 📦 store.js - participant RTC as 🔗 renderstreaming.js - participant PEER as 👤 远端用户 - - USER->>DOM: 输入消息并回车 - DOM->>CHAT: handleChatSubmit(event) - CHAT->>CHAT: sendMessage() - CHAT->>CHAT: addMessage(message)
    添加到本地列表 - CHAT->>STORE: getRenderStreaming() - STORE-->>CHAT: 返回实例 - CHAT->>RTC: sendMessage()
    发送chat-message - RTC->>PEER: 通过WebRTC数据通道发送 - - PEER->>RTC: 收到消息 - RTC->>STORE: onMessage 回调 - STORE->>CHAT: handleChatMessage(data) - CHAT->>CHAT: addMessage()
    添加到消息列表 - CHAT->>RENDER: 更新聊天UI -``` - -## 6. 页面流转状态图 - -```mermaid -stateDiagram-v2 - [*] --> 连接页面: 首次访问/无connectionId - - 连接页面: connect.html - 连接页面: - 输入连接ID - 连接页面: - 创建新通话 - 连接页面: - 用户设置 - - 通话页面: index.html - 通话页面: - 视频通话 - 通话页面: - 聊天功能 - 通话页面: - 媒体控制 - - 结束页面: endcall.html - 结束页面: - 显示断开原因 - 结束页面: - 重新连接选项 - - 连接页面 --> 通话页面: 加入/创建通话 - 通话页面 --> 结束页面: 通话结束/断开 - 通话页面 --> 连接页面: 无有效connectionId - 结束页面 --> 通话页面: 重新连接 - 结束页面 --> 连接页面: 返回 -``` - -## 7. 通话状态机 - -```mermaid -stateDiagram-v2 - [*] --> idle: 初始化 - - idle: 空闲状态 - idle --> connecting: joinCall()
    加入通话 - idle --> connecting: createCall()
    创建通话 - - connecting: 连接中 - connecting --> ongoing: onConnect
    连接成功 - connecting --> failed: 连接失败 - - ongoing: 通话中 - ongoing --> ended: hangUp()
    挂断 - ongoing --> ended: endCall()
    结束通话 - - failed: 连接失败 - failed --> connecting: 重试连接 - failed --> ended: 放弃连接 - - ended: 已结束 - ended --> [*]: 清理资源 -``` - -## 8. 组件层次结构 - -```mermaid -graph TD - subgraph index["index.html 组件结构"] - HEADER["🧭 Header 顶部栏"] - MAIN["📺 Main 主内容区"] - FOOTER["🎛️ Footer 底部控制栏"] - end - - subgraph header["Header 内容"] - TITLE["标题: 与xxx的通话"] - NETWORK["网络质量指示"] - DURATION["通话时长"] - ENCRYPT["端到端加密标识"] - end - - subgraph main["Main 内容"] - VIDEO_AREA["VideoArea 视频区"] - SIDEBAR["Sidebar 侧边栏"] - end - - subgraph video["VideoArea"] - REMOTE["RemoteVideo 远端视频"] - LOCAL["LocalVideo 本地视频画中画"] - end - - subgraph sidebar["Sidebar"] - USER_LIST["UserList 用户列表"] - CHAT_MSG["ChatMessages 聊天消息"] - CHAT_INPUT["ChatInput 消息输入"] - end - - subgraph footer["Footer 控制栏"] - CTRL_MIC["🎤 麦克风"] - CTRL_VIDEO["📹 视频"] - CTRL_RECORD["🔴 录制"] - CTRL_END["📞 结束通话"] - CTRL_CHAT["💬 聊天"] - end - - HEADER --> TITLE - HEADER --> NETWORK - HEADER --> DURATION - HEADER --> ENCRYPT - - MAIN --> VIDEO_AREA - MAIN --> SIDEBAR - - VIDEO_AREA --> REMOTE - VIDEO_AREA --> LOCAL - - SIDEBAR --> USER_LIST - SIDEBAR --> CHAT_MSG - SIDEBAR --> CHAT_INPUT - - FOOTER --> CTRL_MIC - FOOTER --> CTRL_VIDEO - FOOTER --> CTRL_RECORD - FOOTER --> CTRL_END - FOOTER --> CTRL_CHAT - - style CTRL_END fill:#f66,stroke:#333,stroke-width:2px - style ENCRYPT fill:#9f6,stroke:#333,stroke-width:2px -``` - -## 9. 文件引用汇总 - -```mermaid -graph LR - subgraph Import["导入关系"] - direction TB - M[main.js] - S[store.js] - R[renderer.js] - C[chatmessage.js] - CONN[connect.js] - - M --> S - M --> R - M --> C - S --> C - R --> C - CONN --> S - end - - subgraph Export["导出内容"] - direction TB - ST[store.js
    export default store] - RE[renderer.js
    export default UIRenderer] - UT[utils.js
    export { formatTime, showNotification, ... }] - MO[models.js
    export { mockCallSession, mockMessages }] - CH[chatmessage.js
    export { sendMessage, toggleSidebar, ... }] - end -``` - -## 10. API 接口调用图 - -```mermaid -graph LR - subgraph Client["客户端"] - CONN_JS[connect.js] - end - - subgraph Server["服务器"] - API_CALL[/api/call/:callId] - API_JOIN[/api/call/:callId/join] - API_LEAVE[/api/call/:callId/leave] - API_MEDIA[/api/call/:callId/media] - API_MSG[/api/call/:callId/messages] - API_SEND[/api/call/:callId/message] - API_CONN[/signaling/connection-ids] - API_UPLOAD[/api/upload/avatar] - end - - CONN_JS -.-> API_CONN - CONN_JS -.-> API_UPLOAD - - style API_CALL fill:#bbf,stroke:#333 - style API_JOIN fill:#bbf,stroke:#333 - style API_LEAVE fill:#bbf,stroke:#333 - style API_MEDIA fill:#bbf,stroke:#333 - style API_MSG fill:#bbf,stroke:#333 - style API_SEND fill:#bbf,stroke:#333 - style API_CONN fill:#fbf,stroke:#333 - style API_UPLOAD fill:#fbf,stroke:#333 -``` - ---- - -*文档生成时间: 2026-04-11* -*适用于 OneByOne 视频通话应用* diff --git a/WebApp/client/public/onebyone/main.js b/WebApp/client/public/onebyone/main.js deleted file mode 100644 index 3138180..0000000 --- a/WebApp/client/public/onebyone/main.js +++ /dev/null @@ -1,215 +0,0 @@ -/** - * 主入口文件 - * 初始化应用,连接各个模块 - */ -import store from './store.js'; -import UIRenderer from './renderer.js'; -import { showNotification } from './utils.js'; -import chatMessage from './chatmessage.js'; - -// 全局变量 -let connectionId = ""; -/** - * 绑定DOM事件 - */ -function bindDomEvents() { - // 切换侧边栏 - window.toggleSidebar = function () { - chatMessage.toggleSidebar(); - }; - - // 切换麦克风 - window.toggleMute = function (button) { - const state = store.getState(); - const currentState = state.session.localUser.mediaState.audio; - store.updateLocalMedia('audio', !currentState); - }; - - // 切换视频 - window.toggleVideo = function (button) { - const state = store.getState(); - const currentState = state.session.localUser.mediaState.video; - store.updateLocalMedia('video', !currentState); - }; - - // 切换本地视频(用于悬停控制) - window.toggleLocalVideo = function () { - window.toggleVideo(); - }; - - // 切换录屏 - window.toggleRecording = function (button) { - const state = store.getState(); - const currentState = state.session.localUser.mediaState.recording || false; - store.updateLocalMedia('recording', !currentState); - - // 显示录制状态通知 - if (!currentState) { - showNotification('开始录制'); - } else { - showNotification('停止录制'); - } - }; - - // 更多选项菜单切换 - window.toggleMoreOptions = function () { - const menu = document.getElementById('moreOptionsMenu'); - if (menu) { - menu.classList.toggle('hidden'); - } - }; - - // 切换视频分辨率 - window.changeResolution = function (width, height) { - store.changeResolution(width, height); - // 关闭菜单 - const menu = document.getElementById('moreOptionsMenu'); - if (menu) { - menu.classList.add('hidden'); - } - }; - - // 结束通话 - window.endCall = function () { - // 显示确认对话框 - document.getElementById('endCallDialog').classList.remove('hidden'); - }; - - // 取消结束通话 - window.cancelEndCall = function () { - document.getElementById('endCallDialog').classList.add('hidden'); - }; - - // 确认结束通话 - window.confirmEndCall = function () { - document.getElementById('endCallDialog').classList.add('hidden'); - store.endCall(); - showNotification('通话已结束'); - }; - - // 显示通话请求弹窗 - window.showCallRequest = function (caller) { - const dialog = document.getElementById('callRequestDialog'); - if (dialog) { - // 设置通话请求信息 - if (document.getElementById('callRequestName')) { - document.getElementById('callRequestName').textContent = caller.name; - } - if (document.getElementById('callRequestAvatar')) { - document.getElementById('callRequestAvatar').src = caller.avatar; - } - // 显示弹窗 - dialog.classList.remove('hidden'); - } - }; - - // 拒绝通话 - window.rejectCall = function () { - const dialog = document.getElementById('callRequestDialog'); - if (dialog) { - dialog.classList.add('hidden'); - } - showNotification('已拒绝通话请求'); - // 可以在这里添加发送拒绝通话请求到服务器的逻辑 - }; - - // 接受通话 - window.acceptCall = function () { - const dialog = document.getElementById('callRequestDialog'); - if (dialog) { - dialog.classList.add('hidden'); - } - showNotification('已接受通话请求'); - // 可以在这里添加发送接受通话请求到服务器的逻辑 - // 然后初始化通话 - store.initCall(); - store.setUp(connectionId); - }; - - // 绑定消息相关事件 - chatMessage.bindMessageEvents(); - - // 键盘快捷键 - document.addEventListener('keydown', (event) => { - // 空格键静音 - if (event.code === 'Space' && !event.target.matches('input, textarea')) { - event.preventDefault(); - window.toggleMute(); - } - - // Ctrl+V 切换视频 - if (event.ctrlKey && event.key === 'v') { - event.preventDefault(); - window.toggleVideo(); - } - }); - - // 绑定对话框事件 - document.getElementById('cancelEndCall').addEventListener('click', window.cancelEndCall); - document.getElementById('confirmEndCall').addEventListener('click', window.confirmEndCall); - - // 更多选项按钮事件 - const moreOptionsBtn = document.getElementById('moreOptionsBtn'); - if (moreOptionsBtn) { - moreOptionsBtn.addEventListener('click', window.toggleMoreOptions); - } - - // 点击外部关闭更多选项菜单 - document.addEventListener('click', function(event) { - const moreOptionsMenu = document.getElementById('moreOptionsMenu'); - const moreOptionsBtnEl = document.getElementById('moreOptionsBtn'); - if (moreOptionsMenu && moreOptionsBtnEl && - !moreOptionsMenu.contains(event.target) && - !moreOptionsBtnEl.contains(event.target)) { - moreOptionsMenu.classList.add('hidden'); - } - }); - - // 绑定通话请求对话框事件 - if (document.getElementById('rejectCall')) { - document.getElementById('rejectCall').addEventListener('click', window.rejectCall); - } - if (document.getElementById('acceptCall')) { - document.getElementById('acceptCall').addEventListener('click', window.acceptCall); - } -} - - -// 页面加载完成后初始化 -window.addEventListener('DOMContentLoaded', async () => { - try { - // 检查本地存储中是否有连接ID - const connectionId = localStorage.getItem('connectionId'); - - if (!connectionId) { - // 如果没有连接ID,跳转到连接界面 - window.location.href = './connect/connect.html'; - return; - } - - // 初始化 store - //await store.init(); - - // 初始化渲染器 - const renderer = new UIRenderer(store); - - // 加入通话 - await store.joinCall(connectionId); - - // 设置WebRTC连接 - await store.setUp(connectionId); - - renderer.renderHeaderTitle(); - - // 绑定DOM事件 - bindDomEvents(); - - console.log('Video call app initialized successfully'); - } catch (error) { - console.error('Error initializing app:', error); - showNotification('初始化失败,请刷新页面重试', 'error'); - } -}); - -// 导出全局变量 -export { store }; diff --git a/WebApp/client/public/onebyone/models.js b/WebApp/client/public/onebyone/models.js deleted file mode 100644 index c95adda..0000000 --- a/WebApp/client/public/onebyone/models.js +++ /dev/null @@ -1,112 +0,0 @@ -/** - * 类型定义和数据模型 - */ - -/** - * @typedef {Object} CallSession - * @property {string} id - 通话唯一标识 (UUID) - * @property {'video'|'audio'} type - 通话类型 - * @property {'connecting'|'ongoing'|'ended'|'failed'} status - 通话状态 - * @property {string} startTime - ISO 8601 时间戳 - * @property {number} duration - 已进行秒数 - * @property {boolean} isEncrypted - 是否启用端到端加密 - * @property {LocalUser} localUser - 本地用户信息 - * @property {RemoteUser} remoteUser - 远端用户信息 - */ - -/** - * @typedef {Object} LocalUser - * @property {string} id - 用户ID - * @property {string} name - 显示名称 - * @property {string} avatar - 头像URL - * @property {boolean} isHost - 是否主持人 - * @property {MediaState} mediaState - 媒体状态 - */ - -/** - * @typedef {Object} RemoteUser - * @property {string} id - 用户ID - * @property {string} name - 显示名称 - * @property {string} avatar - 头像URL - * @property {'online'|'offline'|'connecting'} status - 在线状态 - * @property {MediaState} mediaState - 媒体状态 - * @property {'excellent'|'good'|'fair'|'poor'} networkQuality - 网络质量 - */ - -/** - * @typedef {Object} MediaState - * @property {boolean} audio - 音频是否开启 - * @property {boolean} video - 视频是否开启 - * @property {boolean} screenShare - 是否屏幕共享 - * @property {boolean} recording - 是否正在录屏 - * @property {boolean} isSpeaking - 是否正在说话(VAD) - */ - -/** - * @typedef {Object} ChatMessage - * @property {string} id - 消息唯一ID - * @property {string} senderId - 发送者ID - * @property {string} senderName - 发送者名称 - * @property {string} senderAvatar - 发送者头像URL - * @property {string} content - 消息内容 - * @property {'text'|'file'|'system'} type - 消息类型 - * @property {string} timestamp - ISO 8601 时间戳 - * @property {boolean} isSelf - 是否为自己发送 - */ - -// 模拟通话会话数据 -const mockCallSession = { - id: "call-8842-2024-001", - type: "video", - status: "ongoing", // connecting | ongoing | ended | failed - startTime: "2024-01-15T14:30:00.000Z", - duration: 0, // 秒数,后端可不返回,前端本地计算 - isEncrypted: true, - - // 本地用户信息 - localUser: { - id: "user-local-001", - name: "我", - avatar: "/images/p1.png", - isHost: true, - mediaState: { - audio: true, - video: true, - screenShare: false, - recording: false, - isSpeaking: false - } - }, - - // 远端用户信息 - remoteUser: { - id: "user-remote-002", - name: "Unity", - avatar: "/images/p2.png", - status: "offline", // online | offline | connecting - networkQuality: "no_signal", // excellent | good | fair | poor | no_signal - mediaState: { - audio: true, - video: true, - screenShare: false, - recording: false, - isSpeaking: false - } - } -}; - -// 模拟聊天消息数据 -const mockMessages = [ - { - id: "msg-001", - senderId: "system", - senderName: "系统", - senderAvatar: "/images/screenshot.png", - content: "通话已建立连接", - type: "system", - timestamp: "2024-01-15T14:30:00.000Z", - isSelf: false - } -]; - -export { mockCallSession, mockMessages }; diff --git a/WebApp/client/public/onebyone/renderer.js b/WebApp/client/public/onebyone/renderer.js deleted file mode 100644 index 5cf1b76..0000000 --- a/WebApp/client/public/onebyone/renderer.js +++ /dev/null @@ -1,1125 +0,0 @@ -/** - * UI渲染器 - * 负责将状态映射到DOM,与状态管理解耦 - */ -import { formatTime, formatTimestamp, toggleElement, toggleButtonState } from './utils.js'; -import { mockCallSession } from './models.js'; -import chatMessage from './chatmessage.js'; -import store from './store.js'; - -const GRID_LAYOUT = { - maxColumns: 3, - breakpoints: [ - { maxParticipants: 1, template: '1fr' }, - { maxParticipants: 4, template: 'repeat(2, 1fr)' } - ], - defaultTemplate: 'repeat(3, 1fr)' -}; - -function getGridTemplateColumns(participantCount) { - for (const bp of GRID_LAYOUT.breakpoints) { - if (participantCount <= bp.maxParticipants) { - return bp.template; - } - } - return GRID_LAYOUT.defaultTemplate; -} - -class UIRenderer { - constructor(stateManager) { - this.stateManager = stateManager; - this.unsubscribe = stateManager.subscribe(this.render.bind(this)); - - // 缓存 DOM 元素 - this.elements = { - // 头部和底部 - header: document.querySelector('header'), - footer: document.querySelector('footer'), - // 多Participant视频网格 - participantGrid: document.getElementById('participantGrid'), - // 头部内容 - headerTitle: document.getElementById('headerTitle'), - callDuration: document.getElementById('callDuration'), - encryptionBadge: document.getElementById('encryptionBadge'), - unreadBadge: document.getElementById('unreadBadge'), - remoteNetworkIndicator: document.getElementById('remoteNetworkIndicator'), - remoteNetworkQuality: document.getElementById('remoteNetworkQuality'), - - // 远端视频 - remoteVideo: document.getElementById('remoteVideo'), - remoteVideoPlaceholder: document.getElementById('remoteVideoPlaceholder'), - networkStatus: document.getElementById('networkStatus'), - networkStatusText: document.getElementById('networkStatusText'), - connectingOverlay: document.getElementById('connectingOverlay'), - - // 本地视频 - localVideo: document.getElementById('localVideo'), - localVideoPlaceholder: document.getElementById('localVideoPlaceholder'), - localAudioWave: document.getElementById('localAudioWave'), - localInitials: document.getElementById('localInitials'), - - // 侧边栏 - sidebar: document.getElementById('sidebar'), - chatContent: document.getElementById('chatContent'), - userList: document.getElementById('userList'), - localMediaStatus: document.getElementById('localMediaStatus'), - localMuteIcon: document.querySelector('[data-field="localUser.muteIcon"]'), - userCountDisplay: document.getElementById('userCountDisplay'), - // 控制按钮 - micBtn: document.getElementById('micBtn'), - videoBtn: document.getElementById('videoBtn'), - recordBtn: document.getElementById('recordBtn'), - connectionQuality: document.getElementById('connectionQuality') - }; - - // 绑定事件监听器 - this.bindEventListeners(); - - // 订阅状态变化 - this.unsubscribe = stateManager.subscribe(this.render.bind(this)); - // 订阅消息状态变化 - this.messageUnsubscribe = chatMessage.subscribe(this.renderMessageState.bind(this)); - // 初始化渲染 - this.render(this.stateManager.getState(), { type: 'INIT' }); - - window.addEventListener('resize', () => { - if (this.elements.remoteVideo && this.elements.remoteVideo.srcObject) { - const stream = this.elements.remoteVideo.srcObject; - const videoTracks = stream.getVideoTracks(); - if (videoTracks.length > 0) { - const resolution = this.getVideoResolution(videoTracks[0]); - this.adjustVideoSize(this.elements.remoteVideo, resolution); - } - } - }); - } - - // 渲染消息状态变化 - renderMessageState(messageState, changes) { - switch (changes.type) { - case 'NEW_MESSAGE': - this.renderChatMessages(messageState.messages); - this.renderUnreadCount(changes.unreadCount); - break; - case 'SIDEBAR_TOGGLE': - this.renderSidebar(changes.isOpen); - // 当侧边栏打开时,重置未读消息计数 - if (changes.isOpen) { - this.renderUnreadCount(0); - } else { - this.renderUnreadCount(changes.unreadCount); - } - break; - } - } - - // 绑定事件监听器 - bindEventListeners() { - // 事件监听器 - } - - - /** - * 渲染方法 - 根据状态变化更新UI - * @param {Object} state - 当前应用状态 - * @param {Object} changes - 状态变化对象 - */ - render(state, changes) { - // 根据变化类型执行不同的渲染操作 - switch (changes.type) { - case 'INIT': - // 初始化渲染 - 渲染所有UI元素 - this.renderRemoteVideo(state.session.remoteUser); // 渲染远程视频 - this.renderLocalVideo(state.session.localUser, state.localStream); // 渲染本地视频 - this.renderControlButtons(state.session.localUser.mediaState); // 渲染控制按钮 - this.renderChatMessages(chatMessage.getMessageState().messages); // 渲染聊天消息 - this.renderUserList(state.session.localUser, state.session.remoteUser, state.participants); // 渲染用户列表 - this.renderHeader(state.session); // 渲染头部信息 - // 初始化时检查远程流状态,显示或隐藏占位背景 - if (this.elements.remoteVideoPlaceholder) { - if (state.remoteStream) { - this.elements.remoteVideoPlaceholder.classList.add('hidden'); // 有远程流时隐藏占位背景 - } else { - this.elements.remoteVideoPlaceholder.classList.remove('hidden'); // 无远程流时显示占位背景 - } - } - break; - case 'DURATION_UPDATE': - // 通话时长更新 - 渲染通话时长 - this.renderCallDuration(changes.duration); - break; - case 'LOCAL_MEDIA_CHANGE': - // 本地媒体状态变化 - 更新相关UI - this.renderControlButtons(state.session.localUser.mediaState); // 渲染控制按钮 - this.renderLocalVideo(state.session.localUser, state.localStream); // 渲染本地视频 - this.renderLocalUserStatus(state.session.localUser); // 渲染本地用户状态 - this.renderUserList(state.session.localUser, state.session.remoteUser, state.participants); // 渲染用户列表 - break; - case 'LOCAL_STREAM_OBTAINED': - this.renderLocalStream(state.localStream); - this.renderLocalVideo(state.session.localUser, state.localStream); - break; - case 'REMOTE_STREAM_OBTAINED': - // 远程流获取成功 - 更新远程视频显示 - this.renderRemoteStream(changes.stream, changes.connectionId, changes.isHost); // 渲染远程流 - // 当获取到远程流时,隐藏连接中提示 - if (this.elements.connectingOverlay) { - this.elements.connectingOverlay.classList.add('hidden'); - } - break; - case 'REMOTE_MEDIA_CHANGE': - // 远程媒体状态变化 - 更新远程视频和用户列表 - this.renderRemoteVideo(state.session.remoteUser); // 渲染远程视频 - this.renderUserList(state.session.localUser, state.session.remoteUser, state.participants); // 渲染用户列表 - // Host端:精准更新发送者participant tile的占位背景 - // 只有Host端需要处理participantId对应的tile占位符(Participant端没有其他Participant的视频流) - if (changes.participantId && state.session.localUser.isHost) { - // 从participants Map中读取该participant的video状态,而非remoteUser(多Participant场景remoteUser不精确) - const pInfo = state.participants[changes.participantId]; - const showPlaceholder = pInfo ? !pInfo.mediaState.video : true; - this.renderParticipantVideoPlaceholder(changes.participantId, showPlaceholder); - } - break; - case 'USER_LIST_UPDATE': - // 用户列表更新 - 重新渲染用户列表 - this.renderUserList(changes.localUser, changes.remoteUser, state.participants); - break; - case 'PARTICIPANTS_UPDATE': - // Participants信息变化 - 重新渲染用户列表并同步tile名称 - this.renderUserList(state.session.localUser, state.session.remoteUser, changes.participants || state.participants); - // 同步更新participant tile的名称标签 - this.syncParticipantTileNames(changes.participants || state.participants); - break; - case 'NETWORK_CHANGE': - // 网络状态变化 - 渲染网络状态 - this.renderNetworkStatus(changes.quality); - break; - case 'CALL_STATUS_CHANGE': - // 通话状态变化 - 渲染通话状态 - this.renderCallStatus(changes.status); - break; - case 'CALL_ENDED': - // 通话结束 - 渲染通话结束界面 - this.renderCallEnded(); - break; - case 'PARTICIPANT_LEFT': - // participant离开 - 更新UI但房间仍然存在 - this.renderParticipantLeft(changes.connectionId); - break; - case 'RESOLUTION_CHANGED': - // 分辨率变化 - 更新UI中的分辨率选中状态 - this.renderResolutionChanged(changes.resolution); - break; - } - } - - // 渲染通话状态 - renderCallStatus(status) { - if (this.elements.connectingOverlay) { - if (status === 'connecting') { - this.elements.connectingOverlay.classList.remove('hidden'); - } else { - this.elements.connectingOverlay.classList.add('hidden'); - } - } - } - - // 渲染头部 - renderHeader(session) { - - this.renderHeaderTitle(); - if (this.elements.encryptionBadge) { - toggleElement(this.elements.encryptionBadge, session.isEncrypted); - } - - // 始终显示网络状态指示器和质量 - if (this.elements.remoteNetworkIndicator) { - this.elements.remoteNetworkIndicator.classList.remove('hidden'); - } - if (this.elements.remoteNetworkQuality) { - this.elements.remoteNetworkQuality.classList.remove('hidden'); - } - - this.renderCallDuration(session.duration); - } - renderHeaderTitle() { - if (this.elements.headerTitle) { - const connectionId = store.getConnectionId() || ''; - // 未连接时不显示红框部分 - this.elements.headerTitle.textContent = `通话 (${connectionId})`; - - } - } - - // 渲染通话时长 - renderCallDuration(duration) { - if (this.elements.callDuration) { - this.elements.callDuration.textContent = formatTime(duration); - } - } - - // 渲染分辨率变化 - renderResolutionChanged(resolution) { - if (!resolution) return; - - // 更新分辨率选项的选中状态 - const options = document.querySelectorAll('.resolution-option'); - options.forEach(btn => { - const btnRes = btn.dataset.resolution; - const isActive = (resolution.height >= 1440 && btnRes === '1440') || - (resolution.height >= 1080 && resolution.height < 1440 && btnRes === '1080') || - (resolution.height >= 720 && resolution.height < 1080 && btnRes === '720') || - (resolution.height < 720 && btnRes === '480'); - btn.classList.toggle('active', isActive); - }); - - // 更新当前分辨率文本 - const currentResText = document.getElementById('currentResolutionText'); - if (currentResText) { - currentResText.textContent = `当前: ${resolution.label}`; - } - } - - // 渲染远端视频 - renderRemoteVideo(remoteUser) { - // 同步更新侧边栏用户列表 - this.renderUserList(this.stateManager.getState().session.localUser, remoteUser, this.stateManager.getState().participants); - - // 当远程视频关闭时显示占位符 - if (this.elements.remoteVideoPlaceholder) { - const shouldShowPlaceholder = !remoteUser.mediaState.video; - toggleElement(this.elements.remoteVideoPlaceholder, shouldShowPlaceholder); - - // 更新占位符文本内容 - if (shouldShowPlaceholder) { - const placeholderContent = this.elements.remoteVideoPlaceholder.querySelector('.text-center'); - if (placeholderContent) { - const titleElement = placeholderContent.querySelector('p.text-white.text-lg.font-medium'); - if (titleElement) { - titleElement.textContent = '对方摄像头已关闭'; - } - const subtitleElement = placeholderContent.querySelector('p.text-sm.text-gray-400'); - if (subtitleElement) { - subtitleElement.textContent = '对方暂时关闭了视频'; - } - } - } else { - // 恢复默认占位符文本 - const placeholderContent = this.elements.remoteVideoPlaceholder.querySelector('.text-center'); - if (placeholderContent) { - const titleElement = placeholderContent.querySelector('p.text-white.text-lg.font-medium'); - if (titleElement) { - titleElement.textContent = '等待对方连接...'; - } - const subtitleElement = placeholderContent.querySelector('p.text-sm.text-gray-400'); - if (subtitleElement) { - subtitleElement.textContent = '请确保对方已加入通话'; - } - } - } - } - - // 渲染网络状态 - this.renderNetworkStatus(remoteUser.networkQuality); - - // 渲染header中的网络状态 - this.renderHeaderNetworkStatus(remoteUser.networkQuality); - } - - // 渲染header中的网络状态 - renderHeaderNetworkStatus(networkQuality) { - if (this.elements.remoteNetworkQuality) { - const textElement = this.elements.remoteNetworkQuality.querySelector('span'); - const iconElement = this.elements.remoteNetworkQuality.querySelector('i'); - - if (textElement && iconElement) { - let qualityText = '未知'; - let iconClass = 'fas fa-signal text-gray-400'; - - switch (networkQuality) { - case 'excellent': - qualityText = '优秀'; - iconClass = 'fas fa-signal text-green-400'; - break; - case 'good': - qualityText = '良好'; - iconClass = 'fas fa-signal text-green-500'; - break; - case 'fair': - qualityText = '一般'; - iconClass = 'fas fa-signal text-yellow-400'; - break; - case 'poor': - qualityText = '较差'; - iconClass = 'fas fa-signal text-red-400'; - break; - } - - textElement.textContent = qualityText; - iconElement.className = iconClass; - } - } - } - - // 渲染本地视频 - renderLocalVideo(localUser, localStream) { - if (this.elements.localVideoPlaceholder) { - // 当没有视频流或视频关闭时显示占位符 - const shouldShowPlaceholder = !localStream || !localUser.mediaState.video; - toggleElement(this.elements.localVideoPlaceholder, shouldShowPlaceholder); - } - - if (this.elements.localAudioWave) { - toggleElement(this.elements.localAudioWave, localUser.mediaState.isSpeaking); - } - - // 同时渲染本地用户状态 - this.renderLocalUserStatus(localUser); - } - - // 渲染本地视频流 - renderLocalStream(stream) { - if (this.elements.localVideo && stream) { - this.elements.localVideo.srcObject = stream; - this.elements.localVideo.autoplay = true; - this.elements.localVideo.muted = true; // 本地视频静音,避免回声 - console.log('srcObject set successfully:', this.elements.localVideo.srcObject); - - // 隐藏断开连接覆盖层 - if (this.elements.disconnectedOverlay) { - this.elements.disconnectedOverlay.classList.add('hidden'); - } - } else { - console.error('Either localVideo element or stream is missing'); - } - } - - // 渲染远程视频流 - renderRemoteStream(stream, connectionId, isHost) { - if (isHost && connectionId) { - // Host端: 渲染到 participant 视频网格 - this.renderParticipantStream(stream, connectionId); - } else { - // Participant端: 渲染到单一远端视频(Host的画面) - this.renderSingleRemoteStream(stream); - } - } - - // 渲染Host端的多Participant视频网格 - // 每个participant tile显示该participant实际的远端视频流 - renderParticipantStream(stream, connectionId) { - const grid = this.elements.participantGrid; - if (!grid) return; - - // 显示网格,隐藏单路远端视频 - grid.classList.remove('hidden'); - - // 查找或创建该 connectionId 的视频格子 - let tile = grid.querySelector(`[data-participant-id="${connectionId}"]`); - if (!tile) { - tile = document.createElement('div'); - tile.className = 'relative bg-black/60 rounded-xl overflow-hidden flex items-center justify-center'; - tile.dataset.participantId = connectionId; - - const video = document.createElement('video'); - video.className = 'w-full h-full object-contain'; - video.autoplay = true; - video.playsinline = true; - video.muted = false; // 不静音,播放participant的音频 - video.id = `participantVideo_${connectionId}`; - tile.appendChild(video); - - // 参与者视频关闭时的占位背景(复用 remoteVideoPlaceholder 样式) - const placeholder = document.createElement('div'); - placeholder.className = 'participant-video-placeholder absolute inset-0 flex items-center justify-center bg-gradient-to-br from-indigo-900/80 to-purple-900/80 hidden'; - placeholder.innerHTML = ` -
    -
    - -
    -

    摄像头已关闭

    -
    - `; - tile.appendChild(placeholder); - - // 参与者名称标签(优先使用participants中的真实姓名) - const pInfo = this.stateManager.getState().participants[connectionId]; - const displayName = pInfo?.name || '参与者'; - const label = document.createElement('div'); - label.className = 'absolute bottom-3 left-3 glass px-3 py-1 rounded-full text-xs flex items-center gap-2'; - label.innerHTML = `${displayName}`; - tile.appendChild(label); - - // 在线标识 - const liveTag = document.createElement('div'); - liveTag.className = 'absolute top-3 right-3 bg-green-500/80 px-2 py-0.5 rounded-full text-xs flex items-center gap-1'; - liveTag.innerHTML = `在线`; - tile.appendChild(liveTag); - - grid.appendChild(tile); - console.log(`Created participant video tile for ${connectionId}`); - } - - if (tile) { - // 视频元素显示participant的远端视频流 - const video = tile.querySelector('video'); - if (video && stream) { - // 避免重复设置同一流对象(音频先到、视频后到时流对象相同) - if (video.srcObject === stream) { - console.log(`Same stream for participant ${connectionId}, ensuring playback`); - video.play().catch(e => console.log('Auto-play prevented:', e.message)); - } else { - video.srcObject = stream; - video.play().catch(e => console.log('Auto-play prevented:', e.message)); - console.log(`Set remote stream for participant tile ${connectionId}`); - } - } - - // 隐藏单路远端视频和占位符 - const remoteVideoDiv = this.elements.remoteVideo?.closest('.absolute.inset-0.video-fade-in'); - if (remoteVideoDiv) { - remoteVideoDiv.classList.add('hidden'); - } - } - - // 根据参与者数量调整网格列数 - const tileCount = grid.querySelectorAll('[data-participant-id]').length; - grid.style.gridTemplateColumns = getGridTemplateColumns(tileCount); - - // 隐藏连接中提示 - if (this.elements.connectingOverlay) { - this.elements.connectingOverlay.classList.add('hidden'); - } - - // 隐藏远端视频占位符 - if (this.elements.remoteVideoPlaceholder) { - this.elements.remoteVideoPlaceholder.classList.add('hidden'); - } - } - - // 精准更新指定participant tile的占位背景 - // participantId: 发送media-state-changed的participant的连接ID - // showPlaceholder: 是否显示占位背景(视频关闭时为true) - renderParticipantVideoPlaceholder(participantId, showPlaceholder) { - const grid = this.elements.participantGrid; - if (!grid) return; - const tile = grid.querySelector(`[data-participant-id="${participantId}"]`); - if (!tile) return; - const placeholder = tile.querySelector('.participant-video-placeholder'); - if (placeholder) { - toggleElement(placeholder, showPlaceholder); - console.log(`Updated placeholder for participant ${participantId}: ${showPlaceholder ? 'shown' : 'hidden'}`); - } - } - - // 同步更新所有participant tile的名称标签 - syncParticipantTileNames(participants) { - if (!participants) return; - const grid = this.elements.participantGrid; - if (!grid) return; - for (const [participantId, pInfo] of Object.entries(participants)) { - this.updateParticipantTileName(participantId, pInfo.name); - } - } - - // 更新指定participant tile的名称标签 - updateParticipantTileName(participantId, name) { - const grid = this.elements.participantGrid; - if (!grid) return; - const tile = grid.querySelector(`[data-participant-id="${participantId}"]`); - if (!tile) return; - const label = tile.querySelector('.absolute.bottom-3'); - if (label) { - const nameSpan = label.querySelector('span'); - if (nameSpan && name) { - nameSpan.textContent = name; - console.log(`Updated tile name for participant ${participantId}: ${name}`); - } - } - } - - // 渲染Participant端的单一远端视频(Host画面) - renderSingleRemoteStream(stream) { - if (!this.elements.remoteVideo || !stream) { - console.error('Either remoteVideo element or stream is missing'); - return; - } - - console.log('Rendering remote stream:', stream, 'tracks:', stream.getTracks().map(t => `${t.kind}(${t.readyState})`)); - - // 关键修复:避免 srcObject = null 的重置模式 - // 如果 srcObject 已经是同一个 stream 对象,说明是同一流的轨道更新(如音频先到,视频后到) - // 浏览器会自动识别新添加的轨道,无需重置 srcObject - if (this.elements.remoteVideo.srcObject === stream) { - console.log('Same stream object, track added - ensuring playback'); - this.elements.remoteVideo.play().catch(e => console.log('Auto-play prevented:', e.message)); - return; - } - - // 首次设置或流对象变化:直接设置 srcObject(不使用 null 重置模式) - this.elements.remoteVideo.srcObject = stream; - this.elements.remoteVideo.autoplay = true; - this.elements.remoteVideo.playsinline = true; - this.elements.remoteVideo.muted = false; - - // 确保视频开始播放 - this.elements.remoteVideo.play().catch(e => { - console.log('Auto-play prevented, will retry on interaction:', e.message); - }); - - // 隐藏断开连接覆盖层 - if (this.elements.disconnectedOverlay) { - this.elements.disconnectedOverlay.classList.add('hidden'); - } - - // 监听视频轨道变化 - const videoTracks = stream.getVideoTracks(); - const audioTracks = stream.getAudioTracks(); - console.log(`Stream has ${videoTracks.length} video tracks, ${audioTracks.length} audio tracks`); - - if (videoTracks.length > 0) { - // 有视频轨道:隐藏占位符 - if (this.elements.remoteVideoPlaceholder) { - this.elements.remoteVideoPlaceholder.classList.add('hidden'); - } - if (this.elements.connectingOverlay) { - this.elements.connectingOverlay.classList.add('hidden'); - } - - // 监听视频轨道分辨率变化 - const activeVideoTrack = videoTracks.find(track => track.readyState === 'live'); - if (activeVideoTrack) { - const resolution = this.getVideoResolution(activeVideoTrack); - this.adjustVideoSize(this.elements.remoteVideo, resolution); - activeVideoTrack.addEventListener('resize', () => { - const newResolution = this.getVideoResolution(activeVideoTrack); - this.adjustVideoSize(this.elements.remoteVideo, newResolution); - }); - } - } else { - // 只有音频轨道(视频轨道尚未到达):不显示占位符,等待视频轨道到达 - // 不设置 srcObject = null,保持音频播放 - console.log('Audio-only stream, waiting for video track...'); - } - } - - // 渲染本地用户状态 - renderLocalUserStatus(localUser) { - // 更新本地媒体状态文本 - if (this.elements.localMediaStatus) { - if (!localUser.mediaState.audio) { - this.elements.localMediaStatus.textContent = '静音中'; - this.elements.localMediaStatus.className = 'text-xs text-gray-500'; - } else if (!localUser.mediaState.video) { - this.elements.localMediaStatus.textContent = '视频关闭'; - this.elements.localMediaStatus.className = 'text-xs text-gray-500'; - } else { - this.elements.localMediaStatus.textContent = '在线'; - this.elements.localMediaStatus.className = 'text-xs text-green-400'; - } - } - - // 更新静音图标 - if (this.elements.localMuteIcon) { - if (!localUser.mediaState.audio) { - this.elements.localMuteIcon.classList.remove('hidden'); - this.elements.localMuteIcon.className = 'fas fa-microphone-slash text-gray-500 text-xs'; - } else { - this.elements.localMuteIcon.classList.add('hidden'); - } - } - } - - // 渲染侧边栏用户列表(支持多Participant动态渲染) - renderUserList(localUser, remoteUser, participants) { - if (!this.elements.userList) return; - - const participantsMap = participants || {}; - const participantCount = Object.keys(participantsMap).length; - - // 通话成员总数 = 本地用户(1) + participants中的条目数 - // Host端participants只含其他participant;Participant端participants含host+其他participant - const userCount = 1 + participantCount; - - // 更新通话成员总数显示 - const userCountElement = this.elements.userCountDisplay; - if (userCountElement) { - userCountElement.textContent = `通话成员 (${userCount})`; - } - - // 清空列表并重新渲染 - this.elements.userList.innerHTML = ''; - - // 1. 渲染本地用户 - // 判断当前用户角色:Host端localUser是主持人;Participant端localUser是参与者 - this.elements.userList.appendChild(this.createUserEntry({ - user: localUser, - role: 'local' - })); - - // 2. 渲染远端成员 - if (participantCount > 0) { - // 有participants数据(Host端或Participant端收到participants-sync后) - for (const [pid, p] of Object.entries(participantsMap)) { - if (p.role === 'host') { - this.elements.userList.appendChild(this.createUserEntry({ - user: p, - role: 'host', - id: pid - })); - } else { - this.elements.userList.appendChild(this.createUserEntry({ - user: p, - role: 'participant', - id: pid - })); - } - } - } else if (remoteUser.status !== 'offline') { - // 兼容:Participant端未收到participants-sync时,使用remoteUser显示Host - this.elements.userList.appendChild(this.createUserEntry({ - user: remoteUser, - role: 'remote' - })); - } - } - - // 创建通用用户条目 - createUserEntry(options) { - const { user, role, id } = options; - - const div = document.createElement('div'); - const baseClass = 'flex items-center gap-3 p-2 rounded-lg'; - div.className = role === 'local' - ? `${baseClass} hover:bg-white/5` - : `${baseClass} bg-white/5`; - - // dataset.userId - switch (role) { - case 'local': - div.dataset.userId = 'local'; - break; - case 'remote': - div.dataset.userId = 'remote'; - break; - case 'host': - div.dataset.userId = `host_${id}`; - break; - case 'participant': - div.dataset.userId = `participant_${id}`; - break; - } - - const mediaState = user.mediaState; - const mediaStatusText = !mediaState.audio ? '静音中' : (!mediaState.video ? '视频关闭' : '在线'); - const mediaStatusClass = (!mediaState.audio || !mediaState.video) ? 'text-xs text-gray-500' : 'text-xs text-green-400'; - const muteIconHtml = !mediaState.audio - ? '' - : ''; - - // 头像区域 - let avatarHtml; - if (role === 'local') { - avatarHtml = ``; - } else { - avatarHtml = ` -
    - -
    -
    - `; - } - - // 角色标签 - let roleTag; - if (role === 'local') { - const isHost = user.isHost; - roleTag = isHost - ? '主持人' - : '参与者'; - } else if (role === 'participant') { - roleTag = '参与者'; - } else { - // remote, host - roleTag = '主持人'; - } - - // 媒体状态 data-field(仅local) - const dataFieldAttr = role === 'local' ? ' data-field="localUser.mediaStatus"' : ''; - - // 右侧内容 - let rightHtml; - if (role === 'participant') { - const speakingHtml = (mediaState.isSpeaking && mediaState.audio) - ? '
    ' - : ''; - rightHtml = ` -
    - ${muteIconHtml} - ${speakingHtml} -
    - `; - } else { - rightHtml = muteIconHtml; - } - - div.innerHTML = ` - ${avatarHtml} -
    -
    - ${user.name} - ${roleTag} -
    -
    ${mediaStatusText}
    -
    - ${rightHtml} - `; - - return div; - } - // 在renderer.js中添加方法 - // 获取视频流分辨率 - getVideoResolution(track) { - if (track && track.getSettings) { - const settings = track.getSettings(); - return { - width: settings.width || 640, - height: settings.height || 480 - }; - } - return { width: 640, height: 480 }; // 默认值 - } - - // 调整视频元素大小并居中显示 - adjustVideoSize(videoElement, resolution) { - if (!videoElement) return; - - const { width, height } = resolution; - const aspectRatio = width / height; - - // 根据容器大小和视频宽高比调整视频显示 - const container = videoElement.parentElement; - const containerWidth = container.clientWidth; - const containerHeight = container.clientHeight; - // 启用硬件加速 - videoElement.style.transform = 'translateZ(0)'; - videoElement.style.willChange = 'transform'; - // 设置容器为flex布局,使视频居中 - container.style.display = 'flex'; - container.style.alignItems = 'center'; - container.style.justifyContent = 'center'; - // 优化图像渲染 - videoElement.style.imageRendering = 'auto'; - // 确保视频元素在容器内正确显示 - videoElement.style.maxWidth = '100%'; - videoElement.style.maxHeight = '100%'; - videoElement.style.objectFit = 'contain'; // 保持原始比例,不裁剪 - } - // 渲染控制按钮 - renderControlButtons(mediaState) { - if (this.elements.micBtn) { - toggleButtonState(this.elements.micBtn, !mediaState.audio); - } - - if (this.elements.videoBtn) { - toggleButtonState(this.elements.videoBtn, !mediaState.video); - } - - if (this.elements.recordBtn) { - toggleButtonState(this.elements.recordBtn, mediaState.recording); - } - } - - // 渲染聊天消息 - renderChatMessages(messages) { - if (!this.elements.chatContent) return; - - // 清空聊天内容 - this.elements.chatContent.innerHTML = ''; - - // 添加通话开始时间 - const startTimeElement = document.createElement('div'); - startTimeElement.className = 'text-center text-xs text-gray-500 my-4'; - const startTime = messages[0]?.timestamp || new Date().toISOString(); - startTimeElement.textContent = `通话开始 ${formatTimestamp(startTime)}`; - this.elements.chatContent.appendChild(startTimeElement); - - // 添加消息 - messages.forEach(message => { - const messageElement = this.createMessageElement(message); - this.elements.chatContent.appendChild(messageElement); - }); - - // 滚动到底部 - this.elements.chatContent.scrollTop = this.elements.chatContent.scrollHeight; - } - - // 创建消息元素 - createMessageElement(message) { - const messageDiv = document.createElement('div'); - - // 根据消息类型设置不同的CSS类 - let messageClass = 'chat-bubble'; - if (message.type === 'system') { - messageClass += ' message-system'; - } else if (message.isSelf) { - messageClass += ' message-self'; - } else { - messageClass += ' message-other'; - } - - messageDiv.className = messageClass; - messageDiv.dataset.messageId = message.id; - - let contentHTML = ''; - if (message.type === 'file' && message.content.startsWith('data:image/')) { - // 图片消息 - contentHTML = ` -
    - ${message.fileName || '图片'} - ${message.fileName ? `
    ${message.fileName}
    ` : ''} -
    - `; - } else { - // 文本消息 - contentHTML = ` -
    - ${message.content} -
    - `; - } - - messageDiv.innerHTML = ` -
    - -
    - ${message.senderName} - ${formatTimestamp(message.timestamp)} -
    -
    -
    - ${contentHTML} -
    - `; - - return messageDiv; - } - - // 渲染未读消息数 - renderUnreadCount(count) { - if (this.elements.unreadBadge) { - if (count > 0) { - this.elements.unreadBadge.textContent = count; - this.elements.unreadBadge.classList.remove('hidden'); - } else { - this.elements.unreadBadge.classList.add('hidden'); - } - } - } - - // 渲染侧边栏 - renderSidebar(isOpen) { - if (this.elements.sidebar) { - if (isOpen) { - this.elements.sidebar.classList.remove('hidden'); - } else { - this.elements.sidebar.classList.add('hidden'); - } - } - } - - // 渲染网络状态 - renderNetworkStatus(quality) { - if (this.elements.networkStatus && this.elements.networkStatusText) { - // 始终显示网络状态 - toggleElement(this.elements.networkStatus, true); - - // 根据网络质量设置不同的图标和颜色 - const networkStatus = this.elements.networkStatus; - const networkStatusText = this.elements.networkStatusText; - - // 清除之前的图标 - const existingIcon = networkStatus.querySelector('i'); - if (existingIcon) { - existingIcon.remove(); - } - - // 创建新的图标元素 - const icon = document.createElement('i'); - - // 根据网络质量设置图标和样式 - switch (quality) { - case 'excellent': - icon.className = 'fas fa-check-circle text-green-400'; - networkStatusText.textContent = this.getNetworkQualityText(quality); - networkStatusText.className = 'text-green-400'; - break; - case 'good': - icon.className = 'fas fa-signal text-blue-400'; - networkStatusText.textContent = this.getNetworkQualityText(quality); - networkStatusText.className = 'text-blue-400'; - break; - case 'fair': - icon.className = 'fas fa-exclamation-circle text-yellow-500'; - networkStatusText.textContent = this.getNetworkQualityText(quality); - networkStatusText.className = 'text-yellow-500'; - break; - case 'poor': - icon.className = 'fas fa-exclamation-triangle text-red-500'; - networkStatusText.textContent = this.getNetworkQualityText(quality); - networkStatusText.className = 'text-red-500'; - break; - case 'no_signal': - icon.className = 'fas fa-times-circle text-gray-500'; - networkStatusText.textContent = this.getNetworkQualityText(quality); - networkStatusText.className = 'text-gray-500'; - break; - default: - icon.className = 'fas fa-question-circle text-gray-400'; - networkStatusText.textContent = '未知'; - networkStatusText.className = 'text-gray-400'; - } - - // 添加图标到网络状态元素 - networkStatus.insertBefore(icon, networkStatusText); - } - - if (this.elements.connectionQuality) { - const qualityText = this.getNetworkQualityText(quality); - let statusClass = ''; - - // 根据网络质量设置文本颜色 - switch (quality) { - case 'excellent': - statusClass = 'text-green-400'; - break; - case 'good': - statusClass = 'text-blue-400'; - break; - case 'fair': - statusClass = 'text-yellow-500'; - break; - case 'poor': - statusClass = 'text-red-500'; - break; - case 'no_signal': - statusClass = 'text-gray-500'; - break; - default: - statusClass = 'text-gray-400'; - } - - // 更新连接质量文本和样式 - this.elements.connectionQuality.textContent = `连接质量: ${qualityText}`; - this.elements.connectionQuality.className = `text-xs ${statusClass}`; - } - - // 同步更新头部网络指示器 - this.updateHeaderNetworkIndicator(quality); - - // 同步更新头部网络质量文本 - this.renderHeaderNetworkStatus(quality); - } - - // 更新头部网络指示器 - updateHeaderNetworkIndicator(networkQuality) { - if (!this.elements.remoteNetworkIndicator) return; - - // 根据网络质量设置指示器颜色 - if (networkQuality === 'no_signal') { - // 无信号时显示灰色点,取消动画 - this.elements.remoteNetworkIndicator.className = 'w-2 h-2 bg-gray-500 rounded-full'; - } else { - // 有信号时显示绿色点,保持动画 - this.elements.remoteNetworkIndicator.className = 'w-2 h-2 bg-green-500 rounded-full animate-pulse'; - } - } - - - // 渲染通话结束 - renderCallEnded() { - console.log('Call ended'); - - // 清理participant网格 - const grid = this.elements.participantGrid; - if (grid) { - grid.querySelectorAll('[data-participant-id]').forEach(tile => { - const video = tile.querySelector('video'); - if (video) video.srcObject = null; - tile.remove(); - }); - grid.classList.add('hidden'); - } - - // 跳转到结束通话界面 - window.location.href = './endcall/endcall.html'; - } - - // 渲染participant离开(host端,房间仍然存在) - renderParticipantLeft(connectionId) { - console.log(`Participant left: ${connectionId}, updating UI`); - - const grid = this.elements.participantGrid; - if (grid) { - const tile = grid.querySelector(`[data-participant-id="${connectionId}"]`); - if (tile) { - const video = tile.querySelector('video'); - if (video) video.srcObject = null; - tile.remove(); - console.log(`Removed participant video tile for ${connectionId}`); - } - - const remainingTiles = grid.querySelectorAll('[data-participant-id]'); - if (remainingTiles.length === 0) { - grid.classList.add('hidden'); - const remoteVideoDiv = this.elements.remoteVideo?.closest('.absolute.inset-0.video-fade-in'); - if (remoteVideoDiv) { - remoteVideoDiv.classList.remove('hidden'); - } - if (this.elements.remoteVideoPlaceholder) { - this.elements.remoteVideoPlaceholder.classList.remove('hidden'); - } - } else { - grid.style.gridTemplateColumns = getGridTemplateColumns(remainingTiles.length); - } - } - - if (this.elements.remoteNetworkIndicator) { - this.elements.remoteNetworkIndicator.className = 'w-2 h-2 bg-gray-500 rounded-full'; - } - } - - // 获取状态文本 - getStatusText(status) { - const statusMap = { - 'online': '在线', - 'offline': '离线', - 'connecting': '连接中' - }; - return statusMap[status] || status; - } - - // 获取网络质量文本 - getNetworkQualityText(quality) { - const qualityMap = { - 'excellent': '优秀', - 'good': '良好', - 'fair': '一般', - 'poor': '较差', - 'no_signal': '无信号' - }; - return qualityMap[quality] || quality; - } - - // 销毁 - destroy() { - if (this.unsubscribe) { - this.unsubscribe(); - } - if (this.messageUnsubscribe) { - this.messageUnsubscribe(); - } - } -} - -export default UIRenderer; diff --git a/WebApp/client/public/onebyone/store.js b/WebApp/client/public/onebyone/store.js deleted file mode 100644 index b5d6978..0000000 --- a/WebApp/client/public/onebyone/store.js +++ /dev/null @@ -1,1430 +0,0 @@ -/** - * 状态管理 - * 使用简单的 Observable 模式,可替换为 Redux/Vuex/Pinia - */ -import { mockCallSession } from './models.js'; -import { Signaling, WebSocketSignaling } from "../../module/signaling.js";// 信令管理 -import { RenderStreaming } from "../../module/renderstreaming.js"; // WebRTC连接管理 -import { getServerConfig, getRTCConfiguration } from "../js/config.js";//服务器配置和RTC配置 -import { showNotification, generateId } from './utils.js'; // 导入通知函数 -import chatMessage from './chatmessage.js'; - -const AUDIO_CONFIG = { - echoCancellation: true, - noiseSuppression: true, - autoGainControl: true -}; - -const VAD_CONFIG = { - threshold: 15, - debounceTime: 500, - fftSize: 256 -}; - -const MEDIA_CONSTRAINTS = { - video: { - width: { ideal: 1920, max: 1920 }, - height: { ideal: 1080, max: 1080 }, - frameRate: { ideal: 30, max: 30 } - }, - audio: AUDIO_CONFIG -}; - -const VIDEO_ONLY_CONSTRAINT = { - video: { - width: { ideal: 1920, max: 1920 }, - height: { ideal: 1080, max: 1080 }, - frameRate: { ideal: 30, max: 30 } - }, - audio: false -}; - -class CallStateManager { - constructor() { - // 核心状态 - this.state = { - id: generateId(), - session: { - ...mockCallSession, - status: 'idle' // 初始状态为空闲 - }, - localStream: null, // MediaStream 对象 - remoteStream: null, // 单路远端流(兼容旧逻辑,participant端使用) - remoteStreams: {}, // 多路远端流 Map: { connectionId: MediaStream }(host端使用) - participants: {} // 多Participant用户信息 Map: { participantId: { id, name, avatar, mediaState, status } }(host端使用) - }; - - // 监听器数组 - this.listeners = []; - } - - // 订阅状态变化 - subscribe(callback) { - this.listeners.push(callback); - return () => { - this.listeners = this.listeners.filter(cb => cb !== callback); - }; - } - - // 通知所有监听器 - notify(changes) { - this.listeners.forEach(cb => cb(this.state, changes)); - } - - // 初始化 - async init() { - // 初始化配置 - await this.setupConfig(); - // 加载用户设置 - this.loadUserSettings(); - // 获取本地摄像头视频流 - await this.getLocalStream(); - } - - // 加载用户设置 - loadUserSettings() { - const userSettings = localStorage.getItem('userSettings'); - if (userSettings) { - try { - const settings = JSON.parse(userSettings); - - // 更新本地用户信息 - if (settings.name || settings.avatar) { - this.state.session.localUser = { - ...this.state.session.localUser, - id: settings.userId || this.state.session.localUser.id, - name: settings.name || this.state.session.localUser.name, - avatar: settings.avatar || this.state.session.localUser.avatar - }; - - // 通知UI更新 - this.notify({ type: 'USER_SETTINGS_UPDATED', user: this.state.session.localUser }); - } - - // 恢复保存的分辨率设置 - if (settings.resolution) { - this._savedResolution = settings.resolution; - console.log(`已恢复分辨率设置: ${settings.resolution.width}x${settings.resolution.height}`); - } - } catch (error) { - console.error('Error loading user settings:', error); - } - } - } - async setupConfig() { - const res = await getServerConfig(); - this.useWebSocket = res.useWebSocket; - } - // 获取本地摄像头视频流 - async getLocalStream() { - try { - console.log('Requesting camera permission...'); - - // 检查浏览器是否支持getUserMedia - if (!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia) { - console.error('getUserMedia is not supported'); - throw new Error('getUserMedia is not supported'); - } - - // 请求摄像头权限并获取媒体流,启用回声消除 - // 使用保存的分辨率(如有),否则使用默认约束 - const videoConstraints = this._savedResolution - ? { - width: { ideal: this._savedResolution.width, max: this._savedResolution.width }, - height: { ideal: this._savedResolution.height, max: this._savedResolution.height }, - frameRate: { ideal: 30, max: 30 } - } - : MEDIA_CONSTRAINTS.video; - const stream = await navigator.mediaDevices.getUserMedia({ - video: videoConstraints, - audio: AUDIO_CONFIG - }); - - console.log('Stream obtained successfully:', stream); - console.log('Video tracks:', stream.getVideoTracks()); - console.log('Audio tracks:', stream.getAudioTracks()); - - this.state.localStream = stream; - this.state.session.localUser.mediaState.video = true; - this.state.session.localUser.mediaState.audio = true; - - console.log('Local stream stored, notifying UI...'); - - // 先通知视频流已获取 - this.notify({ type: 'LOCAL_STREAM_OBTAINED', stream }); - // 再通知媒体状态变化 - this.notify({ type: 'LOCAL_MEDIA_CHANGE', mediaType: 'video', value: true }); - this.notify({ type: 'LOCAL_MEDIA_CHANGE', mediaType: 'audio', value: true }); - - // 发送媒体状态到服务器 - this.emitMediaStateChange(); - - // 启动本地音频活动检测 - this.startActivityDetection(this.state.localStream, { isLocal: true }); - } catch (error) { - console.error('Error getting local stream:', error); - // 如果获取视频失败,保持视频关闭状态 - this.state.session.localUser.mediaState.video = false; - this.state.session.localUser.mediaState.audio = false; - - // 通知媒体状态变化 - this.notify({ type: 'LOCAL_MEDIA_CHANGE', mediaType: 'video', value: false }); - this.notify({ type: 'LOCAL_MEDIA_CHANGE', mediaType: 'audio', value: false }); - } - } - - // 更新本地媒体状态 - async updateLocalMedia(mediaType, value) { - - // 如果是开启视频,重新获取摄像头资源 - if (mediaType === 'video' && value) { - try { - // 只获取新的视频轨道,不干扰正在工作的音频 - const newVideoStream = await navigator.mediaDevices.getUserMedia(VIDEO_ONLY_CONSTRAINT); - const newVideoTrack = newVideoStream.getVideoTracks()[0]; - - if (!newVideoTrack) { - throw new Error('Failed to get video track'); - } - - // 更新本地流中的视频轨道(替换旧的已停止的轨道) - if (this.state.localStream) { - const oldVideoTracks = this.state.localStream.getVideoTracks(); - oldVideoTracks.forEach(track => { - track.stop(); - this.state.localStream.removeTrack(track); - }); - this.state.localStream.addTrack(newVideoTrack); - } else { - // 本地流不存在时(不应该发生),使用新流 - this.state.localStream = newVideoStream; - } - - // 更新WebRTC连接中的视频轨道 - if (this.renderstreaming) { - console.log('Updating video track in WebRTC connection'); - - if (this.role === 'host') { - // Host端:需要遍历所有participant的peer来替换视频轨道 - const participantIds = Object.keys(this.state.remoteStreams); - for (const participantId of participantIds) { - const transceivers = this.renderstreaming.getTransceivers(participantId); - if (!transceivers) continue; - - const videoTransceivers = transceivers.filter(t => - t.sender && t.sender.track && t.sender.track.kind === 'video' - ); - - if (videoTransceivers.length > 0) { - for (const transceiver of videoTransceivers) { - try { - await transceiver.sender.replaceTrack(newVideoTrack); - console.log(`Replaced video track for participant ${participantId}`); - } catch (error) { - console.error(`Error replacing video track for ${participantId}:`, error); - } - } - } else { - // 没有视频收发器,添加新的 - try { - this.renderstreaming.addTransceiver(newVideoTrack, { direction: 'sendonly' }, participantId); - console.log(`Added new video transceiver for participant ${participantId}`); - } catch (error) { - console.error(`Error adding video transceiver for ${participantId}:`, error); - } - } - - // 设置编解码器偏好 - setTimeout(() => { this.setCodecPreferences(participantId); }, 100); - setTimeout(() => { this.setVideoEncodingParameters(participantId); }, 200); - } - } else { - // Participant端:使用单一peer - const transceivers = this.renderstreaming.getTransceivers(); - if (transceivers) { - const videoTransceivers = transceivers.filter(t => - t.sender && t.sender.track && t.sender.track.kind === 'video' - ); - - if (videoTransceivers.length > 0) { - for (const transceiver of videoTransceivers) { - try { - await transceiver.sender.replaceTrack(newVideoTrack); - console.log('Successfully replaced video track'); - } catch (error) { - console.error('Error replacing video track:', error); - } - } - } else { - try { - this.renderstreaming.addTransceiver(newVideoTrack, { direction: 'sendonly' }); - console.log('Added new video transceiver'); - } catch (error) { - console.error('Error adding video transceiver:', error); - } - } - } - setTimeout(() => { this.setCodecPreferences(); }, 100); - setTimeout(() => { this.setVideoEncodingParameters(); }, 200); - } - } - - // 更新状态和通知UI - this.state.session.localUser.mediaState.video = true; - this.notify({ type: 'LOCAL_STREAM_OBTAINED', stream: this.state.localStream }); - this.notify({ type: 'LOCAL_MEDIA_CHANGE', mediaType: 'video', value: true }); - this.emitMediaStateChange(); - this.startActivityDetection(this.state.localStream, { isLocal: true }); - - } catch (error) { - console.error('Error reopening video:', error); - this.state.session.localUser.mediaState.video = false; - this.notify({ type: 'LOCAL_MEDIA_CHANGE', mediaType: 'video', value: false }); - } - } else { - // 直接更新媒体状态 - this.state.session.localUser.mediaState[mediaType] = value; - this.notify({ type: 'LOCAL_MEDIA_CHANGE', mediaType, value }); - - // 发送媒体状态到服务器 - this.emitMediaStateChange(); - } - - - // 如果是关闭视频,释放摄像头资源 - if (mediaType === 'video' && !value && this.state.localStream) { - this.state.session.localUser.mediaState.video = false; - this.state.localStream.getTracks().forEach(track => { - if (track.kind === 'video') { - track.stop(); - } - }); - // 发送媒体状态到服务器 - this.emitMediaStateChange(); - - } - - // 如果是音频状态变化,控制本地音频轨道 - if (mediaType === 'audio' && this.state.localStream) { - this.state.session.localUser.mediaState.audio = value; - this.state.localStream.getTracks().forEach(track => { - if (track.kind === 'audio') { - track.enabled = value; - } - }); - // 发送媒体状态到服务器 - this.emitMediaStateChange(); - } - - // 通知UI更新用户列表 - this.notify({ type: 'USER_LIST_UPDATE', localUser: this.state.session.localUser, remoteUser: this.state.session.remoteUser }); - - } - - /** - * 创建信令和RTC实例 - * @async - * @param {string} connectionId - 连接ID - * @returns {Promise} - */ - async _createSignalingAndRTC(connectionId) { - this.connectionId = connectionId; // 获取连接ID - // 设置状态为连接中 - this.state.session.status = 'connecting'; - this.notify({ type: 'CALL_STATUS_CHANGE', status: 'connecting' }); - - // 确保本地流已经初始化 - if (!this.state.localStream) { - console.log('Local stream not available, waiting for initialization...'); - // 等待localStream初始化 - await new Promise((resolve) => { - const checkStream = () => { - if (this.state.localStream) { - resolve(); - } else { - setTimeout(checkStream, 100); - } - }; - checkStream(); - }); - } - - // 创建信令实例 - const signaling = this.useWebSocket ? new WebSocketSignaling() : new Signaling(); - const config = getRTCConfiguration(); // 获取RTC配置 - this.renderstreaming = new RenderStreaming(signaling, config); - } - - /** - * 设置WebRTC连接 - * @async - * @returns {Promise} - */ - async setUp(connectionId) { - await this._createSignalingAndRTC(connectionId); - this._registerCallbacks(); - await this._startConnection(connectionId); - } - - /** - * 注册所有WebRTC回调 - */ - _registerCallbacks() { - this.renderstreaming.onNewPeer = (participantId) => { - console.log(`New peer created for ${participantId}, adding local tracks`); - if (this.state.localStream) { - const tracks = this.state.localStream.getTracks(); - for (const track of tracks) { - this.renderstreaming.addTransceiver(track, { direction: 'sendonly' }, participantId); - } - this.setCodecPreferences(participantId); - this.setVideoEncodingParameters(participantId); - } - }; - - // 连接建立回调 - this.renderstreaming.onConnect = (connectionId, data) => { - // 保存角色信息(host/participant) - if (data && data.role) { - this.role = data.role; - // 更新localUser的isHost标志 - this.state.session.localUser.isHost = (this.role === 'host'); - // 保存自身的participantId,用于从participants-sync中过滤自身 - if (data.participantId) { - this.selfParticipantId = data.participantId; - } - console.log(`Connected as ${this.role}, participantId: ${this.selfParticipantId}`); - } - // 连接建立后,更新状态为ongoing - this.state.session.status = 'ongoing'; - this.notify({ type: 'CALL_STATUS_CHANGE', status: 'ongoing' }); - - // 参与者加入时默认静音:禁用音频轨道并更新状态 - if (this.role === 'participant') { - if (this.state.localStream) { - this.state.localStream.getAudioTracks().forEach(track => { - track.enabled = false; - }); - } - this.state.session.localUser.mediaState.audio = false; - this.notify({ type: 'LOCAL_MEDIA_CHANGE', mediaType: 'audio', value: false }); - console.log('Participant joined with audio muted by default'); - } - - // 连接建立后发送本地用户信息 - this.sendMessage('user-info', { - id: this.state.session.localUser.id, - name: this.state.session.localUser.name, - avatar: this.state.session.localUser.avatar - }); - - // 发送当前媒体状态,确保远端收到正确的初始状态 - this.emitMediaStateChange(); - - if (this.state.localStream) { - // const tracks = this.state.localStream.getTracks(); - // for (const track of tracks) { - // this.renderstreaming.addTransceiver(track, { direction: 'sendonly' }); - // } - // this.setCodecPreferences(); - this.showStatsMessage(); - } else { - console.error('Local stream is not available'); - showNotification('本地视频流不可用', 'error'); - } - }; - - // 连接断开回调(收到服务器的 disconnect 消息,通常是 host 离开导致房间关闭) - this.renderstreaming.onDisconnect = () => { - console.log('Received disconnect from server, host left or room closed'); - this.hangUp(); // 房间已关闭,挂断连接 - }; - - // SDP Answer 接收回调:重新设置编码参数以保障画质 - this.renderstreaming.onGotAnswer = (connectionId) => { - console.log('SDP Answer received, resetting encoding parameters for connectionId:', connectionId); - if (this.role === 'host') { - const allParticipantIds = Object.keys(this.state.remoteStreams || {}); - for (const pid of allParticipantIds) { - setTimeout(() => { this.setVideoEncodingParameters(pid); }, 50); - } - } else { - setTimeout(() => { this.setVideoEncodingParameters(); }, 50); - } - }; - - // participant加入回调(host收到,新participant加入房间) - this.renderstreaming.onParticipantJoined = (participantId) => { - console.log(`Participant joined: ${participantId}`); - if (!this.state.participants[participantId]) { - this.state.participants[participantId] = { - id: '', - name: '参与者', - avatar: '/images/p2.png', - mediaState: { audio: false, video: true, isSpeaking: false }, - status: 'online' - }; - } - this.notify({ type: 'PARTICIPANTS_UPDATE', participants: this.state.participants }); - this.broadcastParticipantsList(); - }; - - // participant离开回调(host收到,房间仍然存在) - this.renderstreaming.onParticipantLeft = (participantId) => { - console.log(`Participant left: ${participantId}, room still active`); - this.updateRemoteUserStatus('offline'); - this.updateRemoteUserNetworkQuality('no_signal'); - showNotification('对方已离开通话', 'warning'); - // 清理该 participant 的远端流 - if (this.state.remoteStreams[participantId]) { - this.state.remoteStreams[participantId].getTracks().forEach(track => track.stop()); - delete this.state.remoteStreams[participantId]; - } - if (this.state.remoteStream) { - this.state.remoteStream.getTracks().forEach(track => track.stop()); - this.state.remoteStream = null; - } - // 清理该 participant 的用户信息 - delete this.state.participants[participantId]; - // 通知UI更新,用participantId作为connectionId传给renderer - this.notify({ type: 'PARTICIPANT_LEFT', connectionId: participantId }); - this.notify({ type: 'PARTICIPANTS_UPDATE', participants: this.state.participants }); - this.broadcastParticipantsList(); - }; - - // 轨道事件回调 - this.renderstreaming.onTrackEvent = (data) => { - const direction = data.transceiver.direction; - if (direction == "sendrecv" || direction == "recvonly") { - // 使用participantId区分不同participant的流 - const trackParticipantId = data.participantId || this.connectionId; - const isHost = this.role === 'host'; - - let targetStream = null; - if (isHost) { - // Host端: 按 participantId 管理多路远端流 - if (!this.state.remoteStreams[trackParticipantId]) { - this.state.remoteStreams[trackParticipantId] = new MediaStream(); - } - targetStream = this.state.remoteStreams[trackParticipantId]; - } else { - // Participant端: 使用单一远端流 - if (this.state.remoteStream == null) { - this.state.remoteStream = new MediaStream(); - } - targetStream = this.state.remoteStream; - } - - // 检查是否已经有相同类型的轨道 - const existingTracks = targetStream.getTracks().filter(track => track.kind === data.track.kind); - existingTracks.forEach(track => { - targetStream.removeTrack(track); - console.log('Removed old track:', track.kind); - }); - - targetStream.addTrack(data.track); - console.log('Added new track:', data.track.kind, 'for participant:', trackParticipantId); - - // Host端兜底:确保participants中有该participant条目 - if (isHost && !this.state.participants[trackParticipantId]) { - this.state.participants[trackParticipantId] = { - id: '', - name: '参与者', - avatar: '/images/p2.png', - mediaState: { audio: false, video: true, isSpeaking: false }, - status: 'online' - }; - this.notify({ type: 'PARTICIPANTS_UPDATE', participants: this.state.participants }); - this.broadcastParticipantsList(); - } - - // 通知UI远程流已更新 - // 关键优化:如果是音频轨道先到达且流中尚无视频轨道, - // 延迟通知UI等待视频轨道到达,避免音频先触发的UI更新导致黑屏 - const notifyStreamUpdate = () => { - this.notify({ - type: 'REMOTE_STREAM_OBTAINED', - stream: targetStream, - connectionId: trackParticipantId, - isHost: isHost - }); - console.log('Notified UI about remote stream update'); - }; - - if (data.track.kind === 'audio' && targetStream.getVideoTracks().length === 0) { - // 音频先到,视频尚未到达:延迟200ms通知,给视频轨道到达的机会 - console.log('Audio track arrived first, delaying stream notification for video track...'); - setTimeout(() => { - const nowHasVideo = targetStream.getVideoTracks().length > 0; - console.log(`After delay, stream has video: ${nowHasVideo}`); - notifyStreamUpdate(); - }, 200); - } else { - // 视频轨道到达,或音频视频同时存在:立即通知 - notifyStreamUpdate(); - } - // 只有当收到远程流时才更新远程用户状态为在线 - if (this.state.session.remoteUser.status !== 'online') { - this.updateRemoteUserStatus('online'); - // 更新远程用户网络质量为好 - this.updateRemoteUserNetworkQuality('good'); - - this.sendMessage('user-info', { - id: this.state.session.localUser.id, - name: this.state.session.localUser.name, - avatar: this.state.session.localUser.avatar - }); - // 启动通话时长计时器(避免重复启动) - if (!this.durationInterval) { - this.durationInterval = setInterval(() => { - this.state.session.duration++; - this.notify({ type: 'DURATION_UPDATE', duration: this.state.session.duration }); - }, 1000); - } - } - // 如果是音频轨道,启动远程音频活动检测 - if (data.track.kind === 'audio') { - this.startActivityDetection(this.state.remoteStream, { isLocal: false }); - } - } else if (direction == "sendonly") { - // 本地发送轨道,启动本地音频活动检测 - if (data.track.kind === 'audio') { - this.startActivityDetection(this.state.localStream, { isLocal: true }); - } - } - }; - - this.renderstreaming.onMessage = (data) => { - console.log('收到消息:', data); - if (data.type === 'chat-message') { - // 处理聊天 - // 添加到列表并更新UI - chatMessage.handleChatMessage(data.message); - // Host端:按participantId更新对应用户信息 - if (data.participantId && this.role === 'host' && this.state.participants[data.participantId]) { - this.state.participants[data.participantId].id = data.message.senderId; - if (data.message.senderName) { - this.state.participants[data.participantId].name = data.message.senderName; - } - if (data.message.senderAvatar) { - this.state.participants[data.participantId].avatar = data.message.senderAvatar; - } - this.notify({ type: 'PARTICIPANTS_UPDATE', participants: this.state.participants }); - this.broadcastParticipantsList(); - } - // Participant端:根据消息来源更新对应用户信息 - if (!this.role || this.role !== 'host') { - if (data.participantId && this.state.participants[data.participantId]) { - // 来自其他Participant的消息:更新participants中对应条目 - if (data.message.senderName) { - this.state.participants[data.participantId].name = data.message.senderName; - } - if (data.message.senderAvatar) { - this.state.participants[data.participantId].avatar = data.message.senderAvatar; - } - this.notify({ type: 'PARTICIPANTS_UPDATE', participants: this.state.participants }); - } else if (data.message && data.message.senderId !== this.state.session.localUser.id) { - // 来自Host的消息:更新remoteUser - this.state.session.remoteUser = { - ...this.state.session.remoteUser, - id: data.message.senderId, - name: data.message.senderName, - avatar: data.message.senderAvatar - }; - this.notify({ type: 'REMOTE_MEDIA_CHANGE', mediaState: this.state.session.remoteUser.mediaState }); - } - } - } else if (data.type === 'media-state-changed') { - // 处理媒体状态变化 - console.log('收到媒体状态变化:', data.data, 'from participant:', data.participantId); - if (this.role === 'host') { - // Host端:按participantId同步更新participants中对应participant的mediaState - if (data.participantId && this.state.participants[data.participantId]) { - this.state.participants[data.participantId].mediaState = { - ...this.state.participants[data.participantId].mediaState, - ...data.data - }; - } - // 更新远端媒体状态 - this.updateRemoteMedia(data.data, data.participantId); - // 通知UI更新participants - this.notify({ type: 'PARTICIPANTS_UPDATE', participants: this.state.participants }); - // Host端广播最新成员列表(含媒体状态)给所有Participant - this.broadcastParticipantsList(); - } else { - // Participant端:根据消息来源更新对应条目 - if (data.participantId && this.state.participants[data.participantId]) { - // 来自其他Participant的媒体状态变化:仅更新participants中对应条目 - // 不调用updateRemoteMedia,因为Participant端没有其他Participant的视频流 - this.state.participants[data.participantId].mediaState = { - ...this.state.participants[data.participantId].mediaState, - ...data.data - }; - this.notify({ type: 'PARTICIPANTS_UPDATE', participants: this.state.participants }); - } else if (!data.participantId) { - // 来自Host的媒体状态变化(无participantId): - // 更新participants中Host条目 + 更新remoteUser(Host的视频流是本端远端画面) - if (this.state.participants['host']) { - this.state.participants['host'].mediaState = { - ...this.state.participants['host'].mediaState, - ...data.data - }; - } - this.updateRemoteMedia(data.data, data.participantId); - this.notify({ type: 'PARTICIPANTS_UPDATE', participants: this.state.participants }); - } - } - } else if (data.type === 'user-info') { - // 处理用户信息更新 - console.log('收到用户信息:', data.data, 'from participant:', data.participantId); - if (data.data) { - if (data.participantId && this.role === 'host') { - // Host端:按participantId存储到participants Map - if (!this.state.participants[data.participantId]) { - this.state.participants[data.participantId] = { - id: '', - name: '参与者', - avatar: '/images/p2.png', - mediaState: { audio: false, video: true, isSpeaking: false }, - status: 'online' - }; - } - this.state.participants[data.participantId].id = data.data.id || ''; - this.state.participants[data.participantId].name = data.data.name || '参与者'; - this.state.participants[data.participantId].avatar = data.data.avatar || '/images/p2.png'; - this.notify({ type: 'PARTICIPANTS_UPDATE', participants: this.state.participants }); - this.broadcastParticipantsList(); - } else { - // Participant端:更新单一remoteUser(Host的信息) - this.state.session.remoteUser = { - ...this.state.session.remoteUser, - id: data.data.id || this.state.session.remoteUser.id, - name: data.data.name || this.state.session.remoteUser.name, - avatar: data.data.avatar || this.state.session.remoteUser.avatar - }; - this.notify({ type: 'REMOTE_MEDIA_CHANGE', mediaState: this.state.session.remoteUser.mediaState }); - } - } - } else if (data.type === 'participants-sync') { - // Participant端:接收Host广播的完整成员列表 - if (this.role !== 'host' && data.data) { - console.log('收到成员列表同步:', data.data); - // 过滤掉自身条目,避免在列表中重复显示(自身已作为localUser显示) - const filtered = {}; - for (const [pid, pInfo] of Object.entries(data.data)) { - if (pid !== this.selfParticipantId) { - filtered[pid] = pInfo; - } - } - this.state.participants = filtered; - this.notify({ type: 'PARTICIPANTS_UPDATE', participants: this.state.participants }); - - // 同步通话时长:仅首次同步,将Host的时长作为基准 - if (!this.durationSynced && typeof data.callDuration === 'number') { - this.state.session.duration = data.callDuration; - this.durationSynced = true; - // 如果计时器尚未启动(远程流还未到达),先启动计时器 - if (!this.durationInterval) { - this.durationInterval = setInterval(() => { - this.state.session.duration++; - this.notify({ type: 'DURATION_UPDATE', duration: this.state.session.duration }); - }, 1000); - } - this.notify({ type: 'DURATION_UPDATE', duration: this.state.session.duration }); - console.log(`通话时长已同步,当前时长: ${data.callDuration}秒`); - } - } - } - }; - } - - /** - * 启动WebRTC连接和检测 - * @async - * @param {string} connectionId - 连接ID - * @returns {Promise} - */ - async _startConnection(connectionId) { - // 启动WebRTC连接 - await this.renderstreaming.start(); - await this.renderstreaming.createConnection(connectionId); - - // 启动网络质量检测 - this.startNetworkQualityDetection(); - - // 启动本地音频活动检测 - this.startActivityDetection(this.state.localStream, { isLocal: true }); - //启动远端音频活动检测 - this.startActivityDetection(this.state.remoteStream, { isLocal: false }); - } - - /** - * 挂断WebRTC连接 - * Host挂断:房间删除,通知所有participants - * Participant挂断:仅自己离开,房间保留 - * @async - * @returns {Promise} - */ - async hangUp() { - this.clearStatsMessage(); // 清除统计信息 - this.stopNetworkQualityDetection(); // 停止网络质量检测 - // 停止通话时长计时器 - if (this.durationInterval) { - clearInterval(this.durationInterval); - this.durationInterval = null; - } - // 重置通话时长同步标志 - this.durationSynced = false; - - const isHost = this.role === 'host'; - console.log(`Disconnect peer on ${this.connectionId}. Role: ${this.role}`); - - // 删除连接并停止WebRTC - if (this.renderstreaming) { - try { - // 发送断开连接信令给服务器 - // 服务器会根据角色决定: - // - host断开:通知所有participants,删除房间 - // - participant断开:仅通知host,保留房间 - await this.renderstreaming.deleteConnection(); - await this.renderstreaming.stop(); - } catch (error) { - console.error('Error during hangUp:', error); - } - this.renderstreaming = null; - } - - // 更新远程用户状态为离线 - this.updateRemoteUserStatus('offline'); - this.updateRemoteUserNetworkQuality('no_signal'); - // 清理participants - this.state.participants = {}; - this.selfParticipantId = null; - this.connectionId = null; - this.role = null; - this.state.session.status = 'ended'; - this.notify({ type: 'CALL_ENDED', reason: isHost ? 'host_hangup' : 'participant_hangup' }); - } - - /** - * 发送消息 - * @param {string} type - 消息类型 - * @param {Object} data - 消息数据 - */ - sendMessage(type, data) { - if (this.renderstreaming) { - this.renderstreaming.sendMessage({ - type: type, - data: data - }); - } - } - - /** - * Host端广播完整成员列表给所有Participant - * 包含Host自身信息 + 所有Participant信息 - * Participant收到后可展示完整通话成员列表 - */ - broadcastParticipantsList() { - if (this.role !== 'host' || !this.renderstreaming) return; - - const memberList = {}; - - // 添加Host自身信息 - memberList['host'] = { - id: this.state.session.localUser.id, - name: this.state.session.localUser.name, - avatar: this.state.session.localUser.avatar, - mediaState: { ...this.state.session.localUser.mediaState }, - status: 'online', - role: 'host' - }; - - // 添加所有Participant信息 - for (const [pid, pInfo] of Object.entries(this.state.participants)) { - memberList[pid] = { - ...pInfo, - role: 'participant' - }; - } - - this.renderstreaming.sendMessage({ - type: 'participants-sync', - data: memberList, - callDuration: this.state.session.duration - }); - console.log('Broadcast participants list:', Object.keys(memberList)); - } - - /** - * 设置编解码器偏好 - * 优先选择 VP9/AV1(更高效的压缩),回退到 H264 High Profile - */ - setCodecPreferences(participantId) { - const capabilities = RTCRtpSender.getCapabilities('video'); - if (!capabilities || !capabilities.codecs || capabilities.codecs.length === 0) return; - const { codecs } = capabilities; - - // 构建多codec优先级列表(而非只选一个) - let selectedCodecs = []; - - const av1Codec = codecs.find(c => c.mimeType === 'video/AV1'); - const vp9Codec = codecs.find(c => c.mimeType === 'video/VP9'); - const h264HighCodec = codecs.find(c => - c.mimeType === 'video/H264' && - c.sdpFmtpLine && c.sdpFmtpLine.includes('profile-level-id=6400') - ); - const h264Codec = codecs.find(c => c.mimeType === 'video/H264'); - - if (av1Codec) selectedCodecs.push(av1Codec); - if (vp9Codec) selectedCodecs.push(vp9Codec); - if (h264HighCodec) selectedCodecs.push(h264HighCodec); - if (h264Codec && (!h264HighCodec || h264Codec !== h264HighCodec)) selectedCodecs.push(h264Codec); - - if (selectedCodecs.length === 0) return; - - if (this.renderstreaming) { - const transceivers = this.renderstreaming.getTransceivers(participantId); - if (transceivers && transceivers.length > 0) { - const videoTransceivers = transceivers.filter(t => { - if (t.sender && t.sender.track) { - return t.sender.track.kind === 'video'; - } - return t.mid !== null && t.receiver && t.receiver.track && t.receiver.track.kind === 'video'; - }); - if (videoTransceivers && videoTransceivers.length > 0) { - videoTransceivers.forEach(t => { - try { - t.setCodecPreferences(selectedCodecs); - } catch(e) { - console.error('Error setting codec preferences:', e); - } - }); - console.log(`Codec preferences set: ${selectedCodecs.map(c => c.mimeType).join(' > ')}`); - } - } - } - } - - /** - * 设置视频发送编码参数 - * 提升 maxBitrate 以改善远端视频画质 - * @param {string} [participantId] - 目标participant(host端使用) - */ - setVideoEncodingParameters(participantId) { - if (!this.renderstreaming) return; - - const transceivers = this.renderstreaming.getTransceivers(participantId); - if (!transceivers || transceivers.length === 0) return; - - const videoTransceivers = transceivers.filter(t => - t.sender && t.sender.track && t.sender.track.kind === 'video' - ); - - for (const transceiver of videoTransceivers) { - try { - const sender = transceiver.sender; - const params = sender.getParameters(); - - if (!params.encodings || params.encodings.length === 0) { - params.encodings = [{}]; - } - - // 根据实际采集分辨率动态设置maxBitrate - const videoTrack = sender.track; - const settings = videoTrack ? videoTrack.getSettings() : {}; - const height = settings.height || 1080; - - const bitrateMap = { - 270: 1000000, - 480: 1500000, - 720: 2500000, - 1080: 4000000, - 1440: 6000000 - }; - // 找到最接近的分辨率对应的比特率 - let maxBitrate = 4000000; - const heights = Object.keys(bitrateMap).map(Number).sort((a, b) => a - b); - for (const h of heights) { - if (height <= h) { - maxBitrate = bitrateMap[h]; - break; - } - maxBitrate = bitrateMap[h]; - } - - params.encodings[0].maxBitrate = maxBitrate; - params.encodings[0].scaleResolutionDownBy = 1.0; - params.encodings[0].xGoogleMinBitrate = Math.floor(maxBitrate * 0.5); - - // 优先保持分辨率,降低帧率来适应带宽 - // 'maintain-resolution' 在带宽不足时保持清晰度 - if (params.degradationPreference !== undefined) { - params.degradationPreference = 'maintain-resolution'; - } - - sender.setParameters(params); - console.log(`Set video encoding: maxBitrate=${maxBitrate / 1000000}Mbps, scaleResolutionDownBy=1.0, xGoogleMinBitrate=${Math.floor(maxBitrate * 0.5)}${participantId ? ` for ${participantId}` : ''}`); - } catch (error) { - console.error('Error setting video encoding parameters:', error); - } - } - } - - - /** - * 动态切换视频分辨率 - * 使用 MediaStreamTrack.applyConstraints() 在通话中实时调整 - * 同时根据分辨率调整编码比特率 - * @param {number} width - 目标宽度 - * @param {number} height - 目标高度 - */ - async changeResolution(width, height) { - if (!this.state.localStream) { - showNotification('本地视频流不可用', 'error'); - return; - } - - const videoTracks = this.state.localStream.getVideoTracks(); - if (videoTracks.length === 0) { - showNotification('视频轨道不可用', 'error'); - return; - } - - const track = videoTracks[0]; - const label = height >= 1440 ? '2K 1440p' : height >= 1080 ? '1080p 超清' : height >= 720 ? '720p 高清' : '480p 流畅'; - - try { - // 使用 applyConstraints 在不重新获取流的情况下调整分辨率 - await track.applyConstraints({ - width: { ideal: width, max: width }, - height: { ideal: height, max: height }, - frameRate: { ideal: 30, max: 30 } - }); - - console.log(`分辨率已切换为 ${width}x${height}`); - - // 根据分辨率调整编码比特率 - // 480p: ~1Mbps, 720p: ~2.5Mbps, 1080p: ~4Mbps, 2K: ~6Mbps - const bitrateMap = { - 270: 1000000, // 480p - 720: 2500000, // 720p - 1080: 4000000, // 1080p - 1440: 6000000 // 2K - }; - const maxBitrate = bitrateMap[height] || 2500000; - this._applyMaxBitrate(maxBitrate); - - // 保存当前分辨率设置到本地存储 - const userSettings = JSON.parse(localStorage.getItem('userSettings') || '{}'); - userSettings.resolution = { width, height }; - localStorage.setItem('userSettings', JSON.stringify(userSettings)); - - // 通知 UI 更新 - this.notify({ type: 'RESOLUTION_CHANGED', resolution: { width, height, label } }); - showNotification(`已切换为 ${label}`, 'success'); - } catch (error) { - console.error('切换分辨率失败:', error); - showNotification('切换分辨率失败,摄像头不支持该分辨率', 'error'); - } - } - - /** - * 对所有视频 sender 应用 maxBitrate - * @param {number} maxBitrate - 最大比特率(bps) - */ - _applyMaxBitrate(maxBitrate) { - if (!this.renderstreaming) return; - - const isHost = this.role === 'host'; - const participantIds = isHost ? Object.keys(this.state.participants) : [null]; - - for (const pid of participantIds) { - const transceivers = this.renderstreaming.getTransceivers(pid); - if (!transceivers) continue; - - const videoTransceivers = transceivers.filter(t => - t.sender && t.sender.track && t.sender.track.kind === 'video' - ); - - for (const transceiver of videoTransceivers) { - try { - const sender = transceiver.sender; - const params = sender.getParameters(); - if (!params.encodings || params.encodings.length === 0) { - params.encodings = [{}]; - } - params.encodings[0].maxBitrate = maxBitrate; - sender.setParameters(params); - console.log(`Updated maxBitrate to ${maxBitrate} for ${pid || 'self'}`); - } catch (error) { - console.error('Error updating maxBitrate:', error); - } - } - } - } - - // 更新远端媒体状态 (由 WebSocket 触发) - updateRemoteMedia(mediaState, participantId) { - this.state.session.remoteUser.mediaState = { - ...this.state.session.remoteUser.mediaState, - ...mediaState - }; - this.notify({ type: 'REMOTE_MEDIA_CHANGE', mediaState, participantId }); - // 通知UI更新用户列表 - this.notify({ type: 'USER_LIST_UPDATE', localUser: this.state.session.localUser, remoteUser: this.state.session.remoteUser }); - } - - // 更新远端用户状态 - updateRemoteUserStatus(status) { - this.state.session.remoteUser.status = status; - this.notify({ type: 'REMOTE_MEDIA_CHANGE', localUser: this.state.session.localUser, remoteUser: this.state.session.remoteUser }); - } - updateRemoteUserNetworkQuality(networkQuality) { - this.state.session.remoteUser.networkQuality = networkQuality; - this.notify({ type: 'REMOTE_MEDIA_CHANGE', localUser: this.state.session.localUser, remoteUser: this.state.session.remoteUser }); - } - // 结束通话(用户主动点击挂断按钮) - async endCall() { - console.log(`endCall called. Role: ${this.role}`); - // 调用 hangUp() 正确关闭 WebRTC 连接并发送断开信令 - // hangUp 内部会根据角色区分: - // - host: 通知所有participants,删除房间 - // - participant: 仅自己离开,房间保留 - await this.hangUp(); - } - - // 加入通话 - async joinCall(connectionId) { - this.state.session.status = 'connecting'; - this.notify({ type: 'CALL_STATUS_CHANGE', status: 'connecting' }); - showNotification(`正在加入通话 (${connectionId})`); - - // 初始化 - await this.init(); - - // 保存连接ID - this.connectionId = connectionId; - } - - // 创建通话 - async createCall() { - this.state.session.status = 'connecting'; - this.notify({ type: 'CALL_STATUS_CHANGE', status: 'connecting' }); - showNotification('正在创建通话...'); - - // 初始化 - await this.init(); - } - - // 真实网络质量检测 - async detectNetworkQuality() { - if (!this.renderstreaming) { - return; - } - - try { - const stats = await this.renderstreaming.getStats(); - if (!stats) { - return; - } - - let totalPacketsLost = 0; - let totalPacketsReceived = 0; - let inboundRTPCount = 0; - let jitter = 0; - let roundTripTime = 0; - - // 分析统计信息 - stats.forEach(report => { - if (report.type === 'inbound-rtp' && report.mediaType === 'video') { - inboundRTPCount++; - - // 计算丢包率 - if (report.packetsLost !== undefined && report.packetsReceived !== undefined) { - totalPacketsLost += report.packetsLost; - totalPacketsReceived += report.packetsReceived; - } - - // 获取抖动 - if (report.jitter !== undefined) { - jitter = Math.max(jitter, report.jitter); - } - - // 获取往返时间 - if (report.roundTripTime !== undefined) { - roundTripTime = Math.max(roundTripTime, report.roundTripTime); - } - } - }); - - // 计算网络质量指标 - let quality = 'excellent'; - - if (inboundRTPCount > 0) { - // 基于丢包率判断 - const packetLossRate = totalPacketsReceived > 0 ? (totalPacketsLost / (totalPacketsLost + totalPacketsReceived)) : 0; - - // 基于抖动判断 - const jitterMs = jitter * 1000; - - // 基于往返时间判断 - const rttMs = roundTripTime * 1000; - - // 综合评估网络质量 - if (packetLossRate > 0.05 || jitterMs > 100 || rttMs > 300) { - quality = 'poor'; - } else if (packetLossRate > 0.02 || jitterMs > 50 || rttMs > 150) { - quality = 'fair'; - } else if (packetLossRate > 0.01 || jitterMs > 30 || rttMs > 100) { - quality = 'good'; - } else { - quality = 'excellent'; - } - } else { - // 没有收到任何RTP包,设置为无信号状态 - quality = 'no_signal'; - } - - // 更新网络质量状态 - if (this.state.session.remoteUser.networkQuality !== quality) { - this.state.session.remoteUser.networkQuality = quality; - this.notify({ type: 'NETWORK_CHANGE', quality }); - } - - } catch (error) { - console.error('Error detecting network quality:', error); - } - } - // 音频活动检测 - startActivityDetection(stream, { isLocal = false } = {}) { - if (!stream) { - return; - } - - const audioTracks = stream.getAudioTracks(); - if (audioTracks.length === 0) { - return; - } - - try { - const { threshold, debounceTime, fftSize } = VAD_CONFIG; - - const audioContext = new (window.AudioContext || window.webkitAudioContext)(); - const source = audioContext.createMediaStreamSource(stream); - const analyser = audioContext.createAnalyser(); - analyser.fftSize = fftSize; - - source.connect(analyser); - - const dataArray = new Uint8Array(analyser.frequencyBinCount); - let isSpeaking = false; - let lastActivityTime = 0; - - const detectActivity = () => { - if (!stream || !this.renderstreaming) { - return; - } - - analyser.getByteTimeDomainData(dataArray); - - let sum = 0; - for (let i = 0; i < dataArray.length; i++) { - const amplitude = dataArray[i] - 128; - sum += amplitude * amplitude; - } - const rms = Math.sqrt(sum / dataArray.length); - const level = rms / 128; - - const currentTime = Date.now(); - if (level > threshold / 100) { - lastActivityTime = currentTime; - if (!isSpeaking) { - isSpeaking = true; - if (isLocal) { - this.state.session.localUser.mediaState.isSpeaking = true; - this.notify({ type: 'LOCAL_MEDIA_CHANGE', mediaType: 'isSpeaking', value: true }); - this.emitMediaStateChange(); - } else { - this.updateRemoteMedia({ isSpeaking: true }); - } - } - } else if (isSpeaking && currentTime - lastActivityTime > debounceTime) { - isSpeaking = false; - if (isLocal) { - this.state.session.localUser.mediaState.isSpeaking = false; - this.notify({ type: 'LOCAL_MEDIA_CHANGE', mediaType: 'isSpeaking', value: false }); - this.emitMediaStateChange(); - } else { - this.updateRemoteMedia({ isSpeaking: false }); - } - } - - if (this.state.session.status === 'ongoing') { - requestAnimationFrame(detectActivity); - } - }; - - detectActivity(); - - console.log(`${isLocal ? 'Local' : 'Remote'} activity detection started`); - - } catch (error) { - console.error(`Error starting ${isLocal ? 'local' : 'remote'} activity detection:`, error); - } - } - // 启动网络质量检测 - startNetworkQualityDetection() { - // 每3秒检测一次网络质量 - this.networkQualityInterval = setInterval(() => { - this.detectNetworkQuality(); - }, 3000); - } - - // 停止网络质量检测 - stopNetworkQualityDetection() { - if (this.networkQualityInterval) { - clearInterval(this.networkQualityInterval); - this.networkQualityInterval = null; - } - } - - - - // 发送媒体状态到服务器 - emitMediaStateChange() { - const payload = { - userId: this.state.session.localUser.id, - ...this.state.session.localUser.mediaState - }; - console.log('[WebSocket Emit] media-state-changed:', payload); - // 使用WebRTC发送媒体状态变化 - if (this.renderstreaming) { - this.renderstreaming.sendMessage({ - type: 'media-state-changed', - data: payload - }); - } - } - - // 显示统计信息 - async showStatsMessage() { - console.log('Showing stats message'); - - // 立即执行一次网络质量检测 - await this.detectNetworkQuality(); - - // 定期显示详细统计信息 - this.statsInterval = setInterval(async () => { - if (!this.renderstreaming) { - return; - } - - try { - const stats = await this.renderstreaming.getStats(); - if (!stats) { - return; - } - - let statsSummary = { - video: { - packetsLost: 0, - packetsReceived: 0, - bytesReceived: 0, - jitter: 0, - roundTripTime: 0, - fps: 0, - bitrate: 0 - }, - audio: { - packetsLost: 0, - packetsReceived: 0, - bytesReceived: 0, - jitter: 0 - } - }; - - // 分析统计信息 - stats.forEach(report => { - if (report.type === 'inbound-rtp') { - if (report.mediaType === 'video') { - statsSummary.video.packetsLost = report.packetsLost || 0; - statsSummary.video.packetsReceived = report.packetsReceived || 0; - statsSummary.video.bytesReceived = report.bytesReceived || 0; - statsSummary.video.jitter = report.jitter || 0; - statsSummary.video.roundTripTime = report.roundTripTime || 0; - statsSummary.video.fps = report.framesPerSecond || 0; - - // 计算视频比特率 (kbps) - if (report.bytesReceived && report.timestamp) { - const duration = report.timestamp / 1000; // 转换为秒 - statsSummary.video.bitrate = duration > 0 ? Math.round((report.bytesReceived * 8) / (duration * 1000)) : 0; - } - } else if (report.mediaType === 'audio') { - statsSummary.audio.packetsLost = report.packetsLost || 0; - statsSummary.audio.packetsReceived = report.packetsReceived || 0; - statsSummary.audio.bytesReceived = report.bytesReceived || 0; - statsSummary.audio.jitter = report.jitter || 0; - } - } - }); - - // 输出详细统计信息 - console.log('=== WebRTC Statistics ==='); - console.log(`Network Quality: ${this.state.session.remoteUser.networkQuality}`); - console.log('Video Stats:', { - 'Packets Lost': statsSummary.video.packetsLost, - 'Packets Received': statsSummary.video.packetsReceived, - 'Packet Loss Rate': statsSummary.video.packetsReceived > 0 ? - `${((statsSummary.video.packetsLost / (statsSummary.video.packetsLost + statsSummary.video.packetsReceived)) * 100).toFixed(2)}%` : '0%', - 'Jitter': `${(statsSummary.video.jitter * 1000).toFixed(2)}ms`, - 'Round Trip Time': `${(statsSummary.video.roundTripTime * 1000).toFixed(2)}ms`, - 'FPS': statsSummary.video.fps.toFixed(1), - 'Bitrate': `${statsSummary.video.bitrate}kbps` - }); - console.log('Audio Stats:', { - 'Packets Lost': statsSummary.audio.packetsLost, - 'Packets Received': statsSummary.audio.packetsReceived, - 'Packet Loss Rate': statsSummary.audio.packetsReceived > 0 ? - `${((statsSummary.audio.packetsLost / (statsSummary.audio.packetsLost + statsSummary.audio.packetsReceived)) * 100).toFixed(2)}%` : '0%', - 'Jitter': `${(statsSummary.audio.jitter * 1000).toFixed(2)}ms` - }); - console.log('========================'); - - } catch (error) { - console.error('Error showing stats message:', error); - } - }, 5000); // 每5秒更新一次统计信息 - } - - // 清除统计信息 - clearStatsMessage() { - console.log('Clearing stats message'); - - // 清理统计信息定时器 - if (this.statsInterval) { - clearInterval(this.statsInterval); - this.statsInterval = null; - } - } - - // Getters - getState() { return this.state; } - getLocalUser() { return this.state.session.localUser; } - getRemoteUser() { return this.state.session.remoteUser; } - - getConnectionId() { return this.connectionId; } - - getRenderStreaming() { return this.renderstreaming; } -} - -// 创建单例实例 -const store = new CallStateManager(); - -// 页面卸载前清理 -window.addEventListener('beforeunload', async () => { - if (!store.renderstreaming) - return; - await store.renderstreaming.stop(); // 停止WebRTC连接 -}, true); -export default store; diff --git a/WebApp/client/public/onebyone/utils.js b/WebApp/client/public/onebyone/utils.js deleted file mode 100644 index 213b170..0000000 --- a/WebApp/client/public/onebyone/utils.js +++ /dev/null @@ -1,94 +0,0 @@ -/** - * 工具函数 - */ - -/** - * 格式化时间为 MM:SS 格式 - * @param {number} seconds - 秒数 - * @returns {string} 格式化后的时间字符串 - */ -export function formatTime(seconds) { - const mins = Math.floor(seconds / 60); - const secs = seconds % 60; - return `${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`; -} - -/** - * 格式化时间戳为 HH:MM 格式 - * @param {string} timestamp - ISO 8601 时间戳 - * @returns {string} 格式化后的时间字符串 - */ -export function formatTimestamp(timestamp) { - const date = new Date(timestamp); - const hours = date.getHours().toString().padStart(2, '0'); - const minutes = date.getMinutes().toString().padStart(2, '0'); - return `${hours}:${minutes}`; -} - -/** - * 生成唯一ID - * @returns {string} 唯一ID - */ -export function generateId() { - return 'id-' + Math.random().toString(36).substr(2, 9); -} - -/** - * 显示通知 - * @param {string} message - 通知内容 - * @param {number} duration - 显示时长(毫秒) - */ -export function showNotification(message, duration = 3000) { - const notification = document.getElementById('notification'); - const notificationText = document.getElementById('notificationText'); - - if (notification && notificationText) { - notificationText.textContent = message; - notification.classList.remove('opacity-0', 'translate-y-[-20px]'); - notification.classList.add('opacity-100', 'translate-y-0'); - - setTimeout(() => { - notification.classList.remove('opacity-100', 'translate-y-0'); - notification.classList.add('opacity-0', 'translate-y-[-20px]'); - }, duration); - } -} - -/** - * 切换元素的显示/隐藏 - * @param {HTMLElement} element - DOM元素 - * @param {boolean} show - 是否显示 - */ -export function toggleElement(element, show) { - if (element) { - if (show) { - element.classList.remove('hidden'); - } else { - element.classList.add('hidden'); - } - } -} - -/** - * 切换按钮状态 - * @param {HTMLElement} button - 按钮元素 - * @param {boolean} active - 是否激活 - */ -export function toggleButtonState(button, active) { - if (button) { - button.dataset.active = active; - - const defaultIcon = button.querySelector('[data-icon="default"]'); - const activeIcon = button.querySelector('[data-icon="active"]'); - - if (defaultIcon && activeIcon) { - if (active) { - defaultIcon.classList.add('hidden'); - activeIcon.classList.remove('hidden'); - } else { - defaultIcon.classList.remove('hidden'); - activeIcon.classList.add('hidden'); - } - } - } -} diff --git a/WebApp/client/public/receiver/css/style.css b/WebApp/client/public/receiver/css/style.css deleted file mode 100644 index 4248609..0000000 --- a/WebApp/client/public/receiver/css/style.css +++ /dev/null @@ -1,43 +0,0 @@ -body { - margin: 0px; -} - -#player { - position: relative; - top: 0; - right: 0; - bottom: 0; - left: 0; - align-items: center; - justify-content: center; - display: flex; - background-color: #323232; -} - -#player:before { - content: ""; - display: block; - padding-top: 66%; -} - -#playButton { - width: 15%; - max-width: 200px; - cursor: pointer; -} - -#Video { - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; -} - -#fullscreenButton { - position: absolute; - top: 25px; - right: 25px; - width: 32px; - height: 32px; -} \ No newline at end of file diff --git a/WebApp/client/public/receiver/index.html b/WebApp/client/public/receiver/index.html deleted file mode 100644 index 56b281b..0000000 --- a/WebApp/client/public/receiver/index.html +++ /dev/null @@ -1,53 +0,0 @@ - - - - - - - - - Receiver Sample - - - - -
    -

    Receiver Sample

    - - - -
    - -
    - Codec preferences: - -
    - -
    - Lock Cursor to Player: - -
    - -

    - For more information about sample, see - Broadcast sample document page. -

    - -
    - -
    - View source on GitHub -
    -
    - - - - - - - - - diff --git a/WebApp/client/public/receiver/js/main.js b/WebApp/client/public/receiver/js/main.js deleted file mode 100644 index ba41f78..0000000 --- a/WebApp/client/public/receiver/js/main.js +++ /dev/null @@ -1,186 +0,0 @@ -import { getServerConfig, getRTCConfiguration } from "../../js/config.js"; -import { createDisplayStringArray } from "../../js/stats.js"; -import { VideoPlayer } from "../../js/videoplayer.js"; -import { RenderStreaming } from "../../module/renderstreaming.js"; -import { Signaling, WebSocketSignaling } from "../../module/signaling.js"; - -/** @type {Element} */ -let playButton; -/** @type {RenderStreaming} */ -let renderstreaming; -/** @type {boolean} */ -let useWebSocket; - -const codecPreferences = document.getElementById('codecPreferences'); -const supportsSetCodecPreferences = window.RTCRtpTransceiver && - 'setCodecPreferences' in window.RTCRtpTransceiver.prototype; -const messageDiv = document.getElementById('message'); -messageDiv.style.display = 'none'; - -const playerDiv = document.getElementById('player'); -const lockMouseCheck = document.getElementById('lockMouseCheck'); -const videoPlayer = new VideoPlayer(); - -setup(); - -window.document.oncontextmenu = function () { - return false; // cancel default menu -}; - -window.addEventListener('resize', function () { - videoPlayer.resizeVideo(); -}, true); - -window.addEventListener('beforeunload', async () => { - if(!renderstreaming) - return; - await renderstreaming.stop(); -}, true); - -async function setup() { - const res = await getServerConfig(); - useWebSocket = res.useWebSocket; - showWarningIfNeeded(res.startupMode); - showCodecSelect(); - showPlayButton(); -} - -function showWarningIfNeeded(startupMode) { - const warningDiv = document.getElementById("warning"); - if (startupMode == "private") { - warningDiv.innerHTML = "

    Warning

    This sample is not working on Private Mode."; - warningDiv.hidden = false; - } -} - -function showPlayButton() { - if (!document.getElementById('playButton')) { - const elementPlayButton = document.createElement('img'); - elementPlayButton.id = 'playButton'; - elementPlayButton.src = '../../images/Play.png'; - elementPlayButton.alt = 'Start Streaming'; - playButton = document.getElementById('player').appendChild(elementPlayButton); - playButton.addEventListener('click', onClickPlayButton); - } -} - -function onClickPlayButton() { - playButton.style.display = 'none'; - - // add video player - videoPlayer.createPlayer(playerDiv, lockMouseCheck); - setupRenderStreaming(); -} - -async function setupRenderStreaming() { - codecPreferences.disabled = true; - - const signaling = useWebSocket ? new WebSocketSignaling() : new Signaling(); - const config = getRTCConfiguration(); - renderstreaming = new RenderStreaming(signaling, config); - renderstreaming.onConnect = onConnect; - renderstreaming.onDisconnect = onDisconnect; - renderstreaming.onTrackEvent = (data) => videoPlayer.addTrack(data.track); - renderstreaming.onGotOffer = setCodecPreferences; - - await renderstreaming.start(); - await renderstreaming.createConnection(); -} - -function onConnect() { - const channel = renderstreaming.createDataChannel("input"); - videoPlayer.setupInput(channel); - showStatsMessage(); -} - -async function onDisconnect(connectionId) { - clearStatsMessage(); - messageDiv.style.display = 'block'; - messageDiv.innerText = `Disconnect peer on ${connectionId}.`; - - await renderstreaming.stop(); - renderstreaming = null; - videoPlayer.deletePlayer(); - if (supportsSetCodecPreferences) { - codecPreferences.disabled = false; - } - showPlayButton(); -} - -function setCodecPreferences() { - /** @type {RTCRtpCodecCapability[] | null} */ - let selectedCodecs = null; - if (supportsSetCodecPreferences) { - const preferredCodec = codecPreferences.options[codecPreferences.selectedIndex]; - if (preferredCodec.value !== '') { - const [mimeType, sdpFmtpLine] = preferredCodec.value.split(' '); - const { codecs } = RTCRtpSender.getCapabilities('video'); - const selectedCodecIndex = codecs.findIndex(c => c.mimeType === mimeType && c.sdpFmtpLine === sdpFmtpLine); - const selectCodec = codecs[selectedCodecIndex]; - selectedCodecs = [selectCodec]; - } - } - - if (selectedCodecs == null) { - return; - } - const transceivers = renderstreaming.getTransceivers().filter(t => t.receiver.track.kind == "video"); - if (transceivers && transceivers.length > 0) { - transceivers.forEach(t => t.setCodecPreferences(selectedCodecs)); - } -} - -function showCodecSelect() { - if (!supportsSetCodecPreferences) { - messageDiv.style.display = 'block'; - messageDiv.innerHTML = `Current Browser does not support RTCRtpTransceiver.setCodecPreferences.`; - return; - } - - const codecs = RTCRtpSender.getCapabilities('video').codecs; - codecs.forEach(codec => { - if (['video/red', 'video/ulpfec', 'video/rtx'].includes(codec.mimeType)) { - return; - } - const option = document.createElement('option'); - option.value = (codec.mimeType + ' ' + (codec.sdpFmtpLine || '')).trim(); - option.innerText = option.value; - codecPreferences.appendChild(option); - }); - codecPreferences.disabled = false; -} - -/** @type {RTCStatsReport} */ -let lastStats; -/** @type {number} */ -let intervalId; - -function showStatsMessage() { - intervalId = setInterval(async () => { - if (renderstreaming == null) { - return; - } - - const stats = await renderstreaming.getStats(); - if (stats == null) { - return; - } - - const array = createDisplayStringArray(stats, lastStats); - if (array.length) { - messageDiv.style.display = 'block'; - messageDiv.innerHTML = array.join('
    '); - } - lastStats = stats; - }, 1000); -} - -function clearStatsMessage() { - if (intervalId) { - clearInterval(intervalId); - } - lastStats = null; - intervalId = null; - messageDiv.style.display = 'none'; - messageDiv.innerHTML = ''; -} \ No newline at end of file diff --git a/WebApp/client/public/videoplayer/css/style.css b/WebApp/client/public/videoplayer/css/style.css deleted file mode 100644 index 0efec66..0000000 --- a/WebApp/client/public/videoplayer/css/style.css +++ /dev/null @@ -1,103 +0,0 @@ - -body { - margin: 0px; -} -button#muteButton { - margin: 5px 0; - width: auto; -} -#player { - position: relative; - top: 0; - right: 0; - bottom: 0; - left: 0; - align-items: center; - justify-content: center; - display: flex; - background-color: #323232; -} - -#player:before { - content: ""; - display: block; - padding-top: 66%; -} - -#playButton { - width: 15%; - max-width: 200px; - cursor: pointer; -} - -#Video { - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; -} - -#VideoThumbnail { - position: absolute; - top: 0; - left: 0; - width: 30%; - height: 30%; -} - -#greenButton { - position: absolute; - bottom: 10px; - left: 10px; - width: 160px; - background-color: #4CAF50; - /* Green */ - border: none; - color: white; - padding: 15px 32px; - text-align: center; - text-decoration: none; - display: inline-block; - font-size: 16px; -} - -#blueButton { - position: absolute; - bottom: 10px; - left: 180px; - width: 160px; - background-color: #447FAF; - /* Blue */ - border: none; - color: white; - padding: 15px 32px; - text-align: center; - text-decoration: none; - display: inline-block; - font-size: 16px; -} - -#orangeButton { - position: absolute; - bottom: 10px; - left: 350px; - width: 160px; - background-color: #FF7700; - /* Blue */ - border: none; - color: white; - padding: 15px 32px; - text-align: center; - text-decoration: none; - display: inline-block; - font-size: 16px; -} - -#fullscreenButton { - position: absolute; - top: 25px; - right: 25px; - width: 32px; - height: 32px; -} diff --git a/WebApp/client/public/videoplayer/images/FullScreen.png b/WebApp/client/public/videoplayer/images/FullScreen.png deleted file mode 100644 index ba386e6..0000000 Binary files a/WebApp/client/public/videoplayer/images/FullScreen.png and /dev/null differ diff --git a/WebApp/client/public/videoplayer/images/Play.png b/WebApp/client/public/videoplayer/images/Play.png deleted file mode 100644 index 9d8dbd1..0000000 Binary files a/WebApp/client/public/videoplayer/images/Play.png and /dev/null differ diff --git a/WebApp/client/public/videoplayer/index.html b/WebApp/client/public/videoplayer/index.html deleted file mode 100644 index 58dfc6b..0000000 --- a/WebApp/client/public/videoplayer/index.html +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - - - VideoPlayer Sample - - - - -
    -

    VideoPlayer Sample

    - - - -
    - -

    For more information about WebBrowserInput sample, see WebBrowserInput - sample document page.

    - -
    - View source on GitHub -
    -
    - - - - - - - - - diff --git a/WebApp/client/public/videoplayer/js/gamepadEvents.js b/WebApp/client/public/videoplayer/js/gamepadEvents.js deleted file mode 100644 index 7b164ff..0000000 --- a/WebApp/client/public/videoplayer/js/gamepadEvents.js +++ /dev/null @@ -1,146 +0,0 @@ -import * as Logger from "../../module/logger.js"; - -const _e = 0.09; -const _gameloopInterval = 16.67; //in milliseconds, 60 times a second -var gameloop = null; -var gamepadsPreviousButtonsStates = {}; -var gamepadsPreviousAxesStates = {}; -var gamepadsConnectedTimeStamp = {}; -const _axisOffset = 100; -const _axisMultiplier = 1; -const _axisYInverted = -1; - -class GamepadButtonEvent extends Event { - constructor() { - super(...arguments); - this.index = arguments[1].index; - this.id = arguments[1].id; - this.value = arguments[1].value; - } -} - -class GamepadAxisEvent extends Event { - constructor() { - super(...arguments); - this.index = arguments[1].index; - this.x = arguments[1].x; - this.y = arguments[1].y; - this.id = arguments[1].id; - } -} - -function storePreviousState(gamepad) { - gamepadsPreviousButtonsStates[gamepad.index] = {}; - gamepad.buttons.forEach(function (button, index) { - gamepadsPreviousButtonsStates[gamepad.index][index] = { value: button.value, pressed: button.pressed }; - }); - - gamepadsPreviousAxesStates[gamepad.index] = [gamepad.axes.length]; - for (var index = 0; index < gamepad.axes.length; index++) - gamepadsPreviousAxesStates[gamepad.index][index] = gamepad.axes[index]; -} - -function checkAxes(gamepad, previousGamePad) { - for (var i = 0; i < gamepad.axes.length; i += 2) { - var absX = Math.abs(gamepad.axes[i]); - var absY = Math.abs(gamepad.axes[i + 1]); - var event = null; - if ((absX > _e) || - (absY > _e)) { - - event = new GamepadAxisEvent('gamepadAxis', { id: gamepadsConnectedTimeStamp[gamepad.index], index: i / 2 + _axisOffset, x: gamepad.axes[i] * _axisMultiplier, y: gamepad.axes[i + 1] * _axisMultiplier * _axisYInverted }); - document.dispatchEvent(event); - } - else { - var previousAbsX = Math.abs(previousGamePad[i]); - var previousAbsY = Math.abs(previousGamePad[i + 1]); - - //have to send if previously was moved - if ((previousAbsX > _e) || - (previousAbsY > _e)) { - event = new GamepadAxisEvent('gamepadAxis', { id: gamepadsConnectedTimeStamp[gamepad.index], index: i / 2 + _axisOffset, x: 0.0, y: 0.0 }); - document.dispatchEvent(event); - } - } - } -} - -function gameLoop() { - Object.keys(gamepadsPreviousAxesStates).forEach(function (gamepadIndex) { - var gamepad = navigator.webkitGetGamepads ? navigator.webkitGetGamepads()[gamepadIndex] : navigator.getGamepads()[gamepadIndex]; - var previousButtons = gamepadsPreviousButtonsStates[gamepadIndex]; - gamepad.buttons.forEach(function (button, index) { - var buttonStatus = navigator.webkitGetGamepads ? button == 1 : (button.value > 0 || button.pressed == true); - var previousButtonStatus = navigator.webkitGetGamepads ? previousButtons[index].value == 1 : (previousButtons[index].value > 0 || previousButtons[index].pressed == true); - var event; - if (buttonStatus != previousButtonStatus) { - if (buttonStatus) { - event = new GamepadButtonEvent('gamepadButtonDown', { id: gamepadsConnectedTimeStamp[gamepad.index], index: index, value: button.value }); - } - else { - event = new GamepadButtonEvent('gamepadButtonUp', { id: gamepadsConnectedTimeStamp[gamepad.index], index: index, value: 0 }); - } - document.dispatchEvent(event); - } - else if (buttonStatus) { - event = new GamepadButtonEvent('gamepadButtonPressed', { id: gamepadsConnectedTimeStamp[gamepad.index], index: index, value: button.value }); - document.dispatchEvent(event); - } - - }); - checkAxes(gamepad, gamepadsPreviousAxesStates[gamepadIndex]); - storePreviousState(gamepad); - }); -} - -function getCookie(cname) { - var name = cname + "="; - var decodedCookie = decodeURIComponent(document.cookie); - var ca = decodedCookie.split(';'); - for (var i = 0; i < ca.length; i++) { - var c = ca[i]; - while (c.charAt(0) == ' ') { - c = c.substring(1); - } - if (c.indexOf(name) == 0) { - return c.substring(name.length, c.length); - } - } - return ""; -} - -export function gamepadHandler(event, connecting) { - var gamepad = event.gamepad; - - var key = gamepad.id.replace(/\s/g, ''); - var cookieTimeStamp = getCookie(key); - - if (connecting) { - storePreviousState(gamepad); - if (Object.keys(gamepadsPreviousAxesStates).length == 1) { - gameloop = setInterval(gameLoop, _gameloopInterval); - } - - //try to find the timestamp - //need to strip the : from the id - - if (cookieTimeStamp == "") { - document.cookie = key + "=" + gamepad.timestamp; - gamepadsConnectedTimeStamp[gamepad.index] = gamepad.timestamp; - } - else { - gamepadsConnectedTimeStamp[gamepad.index] = cookieTimeStamp; - } - - Logger.log("connected: " + gamepadsConnectedTimeStamp[gamepad.index]); - - } else { - delete gamepadsPreviousAxesStates[gamepad.index]; - delete gamepadsPreviousButtonsStates[gamepad.index]; - if (Object.keys(gamepadsPreviousAxesStates).length == 0) { - clearInterval(gameloop); - gameloop = null; - } - Logger.log("disconnected: " + gamepad.id); - } -} diff --git a/WebApp/client/public/videoplayer/js/main.js b/WebApp/client/public/videoplayer/js/main.js deleted file mode 100644 index 4eb8987..0000000 --- a/WebApp/client/public/videoplayer/js/main.js +++ /dev/null @@ -1,156 +0,0 @@ -import { VideoPlayer } from "./video-player.js"; -import { registerGamepadEvents, registerKeyboardEvents, registerMouseEvents, sendClickEvent } from "./register-events.js"; -import { getServerConfig } from "../../js/config.js"; - -setup(); - -let playButton; -let videoPlayer; -let useWebSocket; - -window.document.oncontextmenu = function () { - return false; // cancel default menu -}; - -window.addEventListener('resize', function () { - videoPlayer.resizeVideo(); -}, true); - -window.addEventListener('beforeunload', async () => { - await videoPlayer.stop(); -}, true); - -async function setup() { - const res = await getServerConfig(); - useWebSocket = res.useWebSocket; - showWarningIfNeeded(res.startupMode); - showPlayButton(); -} - -function showWarningIfNeeded(startupMode) { - const warningDiv = document.getElementById("warning"); - if (startupMode == "private") { - warningDiv.innerHTML = "

    Warning

    This sample is not working on Private Mode."; - warningDiv.hidden = false; - } -} - -function showPlayButton() { - if (!document.getElementById('playButton')) { - let elementPlayButton = document.createElement('img'); - elementPlayButton.id = 'playButton'; - elementPlayButton.src = 'images/Play.png'; - elementPlayButton.alt = 'Start Streaming'; - playButton = document.getElementById('player').appendChild(elementPlayButton); - playButton.addEventListener('click', onClickPlayButton); - } -} - -function onClickPlayButton() { - - playButton.style.display = 'none'; - - const playerDiv = document.getElementById('player'); - - // add video player - const elementVideo = document.createElement('video'); - elementVideo.id = 'Video'; - elementVideo.style.touchAction = 'none'; - playerDiv.appendChild(elementVideo); - - // add video thumbnail - const elementVideoThumb = document.createElement('video'); - elementVideoThumb.id = 'VideoThumbnail'; - elementVideoThumb.style.touchAction = 'none'; - playerDiv.appendChild(elementVideoThumb); - - setupVideoPlayer([elementVideo, elementVideoThumb]).then(value => videoPlayer = value); - - // add blue button - const elementBlueButton = document.createElement('button'); - elementBlueButton.id = "blueButton"; - elementBlueButton.innerHTML = "Light on"; - playerDiv.appendChild(elementBlueButton); - elementBlueButton.addEventListener("click", function () { - sendClickEvent(videoPlayer, 1); - }); - - // add green button - const elementGreenButton = document.createElement('button'); - elementGreenButton.id = "greenButton"; - elementGreenButton.innerHTML = "Light off"; - playerDiv.appendChild(elementGreenButton); - elementGreenButton.addEventListener("click", function () { - sendClickEvent(videoPlayer, 2); - }); - - // add orange button - const elementOrangeButton = document.createElement('button'); - elementOrangeButton.id = "orangeButton"; - elementOrangeButton.innerHTML = "Play audio"; - playerDiv.appendChild(elementOrangeButton); - elementOrangeButton.addEventListener("click", function () { - sendClickEvent(videoPlayer, 3); - }); - - // add fullscreen button - const elementFullscreenButton = document.createElement('img'); - elementFullscreenButton.id = 'fullscreenButton'; - elementFullscreenButton.src = 'images/FullScreen.png'; - playerDiv.appendChild(elementFullscreenButton); - elementFullscreenButton.addEventListener("click", function () { - if (!document.fullscreenElement || !document.webkitFullscreenElement) { - if (document.documentElement.requestFullscreen) { - document.documentElement.requestFullscreen(); - } - else if (document.documentElement.webkitRequestFullscreen) { - document.documentElement.webkitRequestFullscreen(Element.ALLOW_KEYBOARD_INPUT); - } else { - if (playerDiv.style.position == "absolute") { - playerDiv.style.position = "relative"; - } else { - playerDiv.style.position = "absolute"; - } - } - } - }); - document.addEventListener('webkitfullscreenchange', onFullscreenChange); - document.addEventListener('fullscreenchange', onFullscreenChange); - - function onFullscreenChange() { - if (document.webkitFullscreenElement || document.fullscreenElement) { - playerDiv.style.position = "absolute"; - elementFullscreenButton.style.display = 'none'; - } - else { - playerDiv.style.position = "relative"; - elementFullscreenButton.style.display = 'block'; - } - } -} - -async function setupVideoPlayer(elements) { - const videoPlayer = new VideoPlayer(elements); - await videoPlayer.setupConnection(useWebSocket); - - videoPlayer.ondisconnect = onDisconnect; - registerGamepadEvents(videoPlayer); - registerKeyboardEvents(videoPlayer); - registerMouseEvents(videoPlayer, elements[0]); - - return videoPlayer; -} - -function onDisconnect() { - const playerDiv = document.getElementById('player'); - clearChildren(playerDiv); - videoPlayer.stop(); - videoPlayer = null; - showPlayButton(); -} - -function clearChildren(element) { - while (element.firstChild) { - element.removeChild(element.firstChild); - } -} diff --git a/WebApp/client/public/videoplayer/js/register-events.js b/WebApp/client/public/videoplayer/js/register-events.js deleted file mode 100644 index 4ef129e..0000000 --- a/WebApp/client/public/videoplayer/js/register-events.js +++ /dev/null @@ -1,307 +0,0 @@ -import { gamepadHandler } from "./gamepadEvents.js"; -import * as Logger from "../../module/logger.js"; -import { Keymap } from "../../module/keymap.js"; - -const InputEvent = { - Keyboard: 0, - Mouse: 1, - MouseWheel: 2, - Touch: 3, - ButtonClick: 4, - Gamepad: 5 -}; - -const KeyboardEventType = { - Up: 0, - Down: 1 -}; - -const GamepadEventType = { - ButtonUp: 0, - ButtonDown: 1, - ButtonPressed: 2, - Axis: 3 -}; - -const PointerPhase = { - None: 0, - Began: 1, - Moved: 2, - Ended: 3, - Canceled: 4, - Stationary: 5 -}; - -let sendGamepadButtonDown = undefined; -let sendGamepadButtonUp = undefined; -let sendGamepadButtonPressed; -let gamepadAxisChange = undefined; -let gamepadConnected = undefined; -let gamepadDisconnected = undefined; - -export function registerGamepadEvents(videoPlayer) { - - const _videoPlayer = videoPlayer; - - sendGamepadButtonDown = (e) => { - Logger.log("gamepad id: " + e.id + " button index: " + e.index + " value " + e.value + " down"); - let data = new DataView(new ArrayBuffer(19)); - data.setUint8(0, InputEvent.Gamepad); - data.setUint8(1, GamepadEventType.ButtonDown); - data.setUint8(2, e.index); - data.setFloat64(3, e.value, true); - - _videoPlayer && _videoPlayer.sendMsg(data.buffer); - }; - - sendGamepadButtonUp = (e) => { - Logger.log("gamepad id: " + e.id + " button index: " + e.index + " value " + e.value + " up"); - let data = new DataView(new ArrayBuffer(19)); - data.setUint8(0, InputEvent.Gamepad); - data.setUint8(1, GamepadEventType.ButtonUp); - data.setUint8(2, e.index); - data.setFloat64(3, e.value, true); - - _videoPlayer && _videoPlayer.sendMsg(data.buffer); - }; - - sendGamepadButtonPressed = (e) => { - Logger.log("gamepad id: " + e.id + " button index: " + e.index + " value " + e.value + " pressed"); - let data = new DataView(new ArrayBuffer(19)); - data.setUint8(0, InputEvent.Gamepad); - data.setUint8(1, GamepadEventType.ButtonPressed); - data.setUint8(2, e.index); - data.setFloat64(3, e.value, true); - - _videoPlayer && _videoPlayer.sendMsg(data.buffer); - }; - - gamepadAxisChange = (e) => { - Logger.log("gamepad id: " + e.id + " axis: " + e.index + " value " + e.value + " x:" + e.x + " y:" + e.y); - let data = new DataView(new ArrayBuffer(27)); - data.setUint8(0, InputEvent.Gamepad); - data.setUint8(1, GamepadEventType.Axis); - data.setUint8(2, e.index); - data.setFloat64(3, e.x, true); - data.setFloat64(11, e.y, true); - _videoPlayer && _videoPlayer.sendMsg(data.buffer); - }; - - gamepadConnected = (e) => { gamepadHandler(e, true); }; - gamepadDisconnected = (e) => { gamepadHandler(e, false); }; - - - document.addEventListener("gamepadButtonDown", sendGamepadButtonDown, false); - document.addEventListener("gamepadButtonUp", sendGamepadButtonUp, false); - document.addEventListener("gamepadButtonPressed", sendGamepadButtonPressed, false); - document.addEventListener("gamepadAxis", gamepadAxisChange, false); - - window.addEventListener("gamepadconnected", gamepadConnected, false); - window.addEventListener("gamepaddisconnected", gamepadDisconnected, false); -} - -export function unregisterGamepadEvents() { - - document.removeEventListener("gamepadButtonDown", sendGamepadButtonDown, false); - document.removeEventListener("gamepadButtonUp", sendGamepadButtonUp, false); - document.removeEventListener("gamepadButtonPressed", sendGamepadButtonPressed, false); - document.removeEventListener("gamepadAxis", gamepadAxisChange, false); - - window.removeEventListener("gamepadconnected", gamepadConnected, false); - window.removeEventListener("gamepaddisconnected", gamepadDisconnected, false); - -} - - -let sendKeyUp = undefined; -let sendKeyDown = undefined; - - -export function registerKeyboardEvents(videoPlayer) { - - const _videoPlayer = videoPlayer; - - function sendKey(e, type) { - const key = Keymap[e.code]; - const character = e.key.length === 1 ? e.key.charCodeAt(0) : 0; - Logger.log("key down " + key + ", repeat = " + e.repeat + ", character = " + character); - _videoPlayer && _videoPlayer.sendMsg(new Uint8Array([InputEvent.Keyboard, type, e.repeat, key, character]).buffer); - } - - - sendKeyUp = (e) => { - sendKey(e, KeyboardEventType.Up); - }; - - sendKeyDown = (e) => { - sendKey(e, KeyboardEventType.Down); - }; - - document.addEventListener('keyup', sendKeyUp, false); - document.addEventListener('keydown', sendKeyDown, false); -} - - -export function unregisterKeyboardEvents() { - - //Stop listening to keyboard events - document.removeEventListener('keyup', sendKeyUp, false); - document.removeEventListener('keydown', sendKeyDown, false); -} - - -let sendMouse = undefined; -let sendMouseWheel = undefined; -let sendTouchEnd = undefined; -let sendTouchStart = undefined; -let sendTouchCancel = undefined; -let sendTouchMove = undefined; - - -export function registerMouseEvents(videoPlayer, playerElement) { - - const _videoPlayer = videoPlayer; - - function sendTouch(e, phase) { - const changedTouches = Array.from(e.changedTouches); - const touches = Array.from(e.touches); - const phrases = []; - - for (let i = 0; i < changedTouches.length; i++) { - if (touches.find(function (t) { - return t.identifier === changedTouches[i].identifier; - }) === undefined) { - touches.push(changedTouches[i]); - } - } - - for (let i = 0; i < touches.length; i++) { - touches[i].identifier; - phrases[i] = changedTouches.find( - function (e) { - return e.identifier === touches[i].identifier; - }) === undefined ? PointerPhase.Stationary : phase; - } - - Logger.log("touch phase:" + phase + " length:" + changedTouches.length + " pageX" + changedTouches[0].pageX + ", pageX: " + changedTouches[0].pageY + ", force:" + changedTouches[0].force); - - let data = new DataView(new ArrayBuffer(2 + 13 * touches.length)); - data.setUint8(0, InputEvent.Touch); - data.setUint8(1, touches.length); - let byteOffset = 2; - for (let i = 0; i < touches.length; i++) { - - const scale = _videoPlayer.videoScale; - const originX = _videoPlayer.videoOriginX; - const originY = _videoPlayer.videoOriginY; - - const x = (touches[i].pageX - originX) / scale; - // According to Unity Coordinate system - // const y = (touches[i].pageX - originY) / scale; - const y = _videoPlayer.videoHeight - (touches[i].pageY - originY) / scale; - - data.setInt32(byteOffset, touches[i].identifier, true); - byteOffset += 4; - data.setUint8(byteOffset, phrases[i]); - byteOffset += 1; - data.setInt16(byteOffset, x, true); - byteOffset += 2; - data.setInt16(byteOffset, y, true); - byteOffset += 2; - data.setFloat32(byteOffset, touches[i].force, true); - byteOffset += 4; - } - _videoPlayer && _videoPlayer.sendMsg(data.buffer); - } - - sendTouchMove = (e) => { - sendTouch(e, PointerPhase.Moved); - e.preventDefault(); - }; - - sendTouchStart = (e) => { - sendTouch(e, PointerPhase.Began); - e.preventDefault(); - }; - - sendTouchEnd = (e) => { - sendTouch(e, PointerPhase.Ended); - e.preventDefault(); - }; - - sendTouchCancel = (e) => { - sendTouch(e, PointerPhase.Canceled); - e.preventDefault(); - }; - - sendMouse = (e) => { - const scale = _videoPlayer.videoScale; - const originX = _videoPlayer.videoOriginX; - const originY = _videoPlayer.videoOriginY; - - const x = (e.clientX - originX) / scale; - // According to Unity Coordinate system - // const y = (e.clientY - originY) / scale; - const y = _videoPlayer.videoHeight - (e.clientY - originY) / scale; - - Logger.log("x: " + x + ", y: " + y + ", scale: " + scale + ", originX: " + originX + ", originY: " + originY + " mouse button:" + e.buttons); - let data = new DataView(new ArrayBuffer(6)); - data.setUint8(0, InputEvent.Mouse); - data.setInt16(1, x, true); - data.setInt16(3, y, true); - data.setUint8(5, e.buttons); - _videoPlayer && _videoPlayer.sendMsg(data.buffer); - }; - - function sendMouseWheel(e) { - Logger.log("mouse wheel with delta " + e.wheelDelta); - let data = new DataView(new ArrayBuffer(9)); - data.setUint8(0, InputEvent.MouseWheel); - data.setFloat32(1, e.deltaX, true); - data.setFloat32(5, e.deltaY, true); - _videoPlayer && _videoPlayer.sendMsg(data.buffer); - } - - // Listen to mouse events - playerElement.addEventListener('click', sendMouse, false); - playerElement.addEventListener('mousedown', sendMouse, false); - playerElement.addEventListener('mouseup', sendMouse, false); - playerElement.addEventListener('mousemove', sendMouse, false); - playerElement.addEventListener('wheel', sendMouseWheel, false); - - // Listen to touch events based on "Touch Events Level1" TR. - // - // Touch event Level1 https://www.w3.org/TR/touch-events/ - // Touch event Level2 https://w3c.github.io/touch-events/ - // - playerElement.addEventListener('touchend', sendTouchEnd, false); - playerElement.addEventListener('touchstart', sendTouchStart, false); - playerElement.addEventListener('touchcancel', sendTouchCancel, false); - playerElement.addEventListener('touchmove', sendTouchMove, false); -} - - -export function unregisterMouseEvents(playerElement) { - - // Stop listening to mouse events - playerElement.removeEventListener('click', sendMouse, false); - playerElement.removeEventListener('mousedown', sendMouse, false); - playerElement.removeEventListener('mouseup', sendMouse, false); - playerElement.removeEventListener('mousemove', sendMouse, false); - playerElement.removeEventListener('wheel', sendMouseWheel, false); - - // Stop listening to touch events based on "Touch Events Level1" TR. - playerElement.removeEventListener('touchend', sendTouchEnd, false); - playerElement.removeEventListener('touchstart', sendTouchStart, false); - playerElement.removeEventListener('touchcancel', sendTouchCancel, false); - playerElement.removeEventListener('touchmove', sendTouchMove, false); - -} - - -export function sendClickEvent(videoPlayer, elementId) { - let data = new DataView(new ArrayBuffer(3)); - data.setUint8(0, InputEvent.ButtonClick); - data.setInt16(1, elementId, true); - videoPlayer && videoPlayer.sendMsg(data.buffer); -} diff --git a/WebApp/client/public/videoplayer/js/video-player.js b/WebApp/client/public/videoplayer/js/video-player.js deleted file mode 100644 index 19bfaca..0000000 --- a/WebApp/client/public/videoplayer/js/video-player.js +++ /dev/null @@ -1,246 +0,0 @@ -import { Signaling, WebSocketSignaling } from "../../module/signaling.js"; -import Peer from "../../module/peer.js"; -import * as Logger from "../../module/logger.js"; - - -// enum type of event sending from Unity -var UnityEventType = { - SWITCH_VIDEO: 0 -}; - -function uuid4() { - var temp_url = URL.createObjectURL(new Blob()); - var uuid = temp_url.toString(); - URL.revokeObjectURL(temp_url); - return uuid.split(/[:/]/g).pop().toLowerCase(); // remove prefixes -} - -export class VideoPlayer { - constructor(elements) { - const _this = this; - this.pc = null; - this.channel = null; - this.connectionId = null; - - // main video - this.localStream = new MediaStream(); - this.video = elements[0]; - this.video.playsInline = true; - this.video.addEventListener('loadedmetadata', function () { - _this.video.play(); - _this.resizeVideo(); - }, true); - - // secondly video - this.localStream2 = new MediaStream(); - this.videoThumb = elements[1]; - this.videoThumb.playsInline = true; - this.videoThumb.addEventListener('loadedmetadata', function () { - _this.videoThumb.play(); - }, true); - - this.videoTrackList = []; - this.videoTrackIndex = 0; - this.maxVideoTrackLength = 2; - - this.ondisconnect = function () { }; - } - - async setupConnection(useWebSocket) { - const _this = this; - // close current RTCPeerConnection - if (this.pc) { - Logger.log('Close current PeerConnection'); - this.pc.close(); - this.pc = null; - } - - if (useWebSocket) { - this.signaling = new WebSocketSignaling(); - } else { - this.signaling = new Signaling(); - } - - this.connectionId = uuid4(); - - // Create peerConnection with proxy server and set up handlers - this.pc = new Peer(this.connectionId, true); - this.pc.addEventListener('disconnect', () => { - _this.ondisconnect(); - }); - this.pc.addEventListener('trackevent', (e) => { - const data = e.detail; - if (data.track.kind == 'video') { - _this.videoTrackList.push(data.track); - } - if (data.track.kind == 'audio') { - _this.localStream.addTrack(data.track); - } - if (_this.videoTrackList.length == _this.maxVideoTrackLength) { - _this.switchVideo(_this.videoTrackIndex); - } - }); - this.pc.addEventListener('sendoffer', (e) => { - const offer = e.detail; - _this.signaling.sendOffer(offer.connectionId, offer.sdp); - }); - this.pc.addEventListener('sendanswer', (e) => { - const answer = e.detail; - _this.signaling.sendAnswer(answer.connectionId, answer.sdp); - }); - this.pc.addEventListener('sendcandidate', (e) => { - const candidate = e.detail; - _this.signaling.sendCandidate(candidate.connectionId, candidate.candidate, candidate.sdpMid, candidate.sdpMLineIndex); - }); - - this.signaling.addEventListener('disconnect', async (e) => { - const data = e.detail; - if (_this.pc != null && _this.pc.connectionId == data.connectionId) { - _this.ondisconnect(); - } - }); - this.signaling.addEventListener('offer', async (e) => { - const offer = e.detail; - const desc = new RTCSessionDescription({ sdp: offer.sdp, type: "offer" }); - if (_this.pc != null) { - await _this.pc.onGotDescription(offer.connectionId, desc); - } - }); - this.signaling.addEventListener('answer', async (e) => { - const answer = e.detail; - const desc = new RTCSessionDescription({ sdp: answer.sdp, type: "answer" }); - if (_this.pc != null) { - await _this.pc.onGotDescription(answer.connectionId, desc); - } - }); - this.signaling.addEventListener('candidate', async (e) => { - const candidate = e.detail; - const iceCandidate = new RTCIceCandidate({ candidate: candidate.candidate, sdpMid: candidate.sdpMid, sdpMLineIndex: candidate.sdpMLineIndex }); - if (_this.pc != null) { - await _this.pc.onGotCandidate(candidate.connectionId, iceCandidate); - } - }); - - // setup signaling - await this.signaling.start(); - - // Create data channel with proxy server and set up handlers - this.channel = this.pc.createDataChannel(this.connectionId, 'data'); - this.channel.onopen = function () { - Logger.log('Datachannel connected.'); - }; - this.channel.onerror = function (e) { - Logger.log("The error " + e.error.message + " occurred\n while handling data with proxy server."); - }; - this.channel.onclose = function () { - Logger.log('Datachannel disconnected.'); - }; - this.channel.onmessage = async (msg) => { - // receive message from unity and operate message - let data; - // receive message data type is blob only on Firefox - if (navigator.userAgent.indexOf('Firefox') != -1) { - data = await msg.data.arrayBuffer(); - } else { - data = msg.data; - } - const bytes = new Uint8Array(data); - _this.videoTrackIndex = bytes[1]; - switch (bytes[0]) { - case UnityEventType.SWITCH_VIDEO: - _this.switchVideo(_this.videoTrackIndex); - break; - } - }; - } - - resizeVideo() { - const clientRect = this.video.getBoundingClientRect(); - const videoRatio = this.videoWidth / this.videoHeight; - const clientRatio = clientRect.width / clientRect.height; - - this._videoScale = videoRatio > clientRatio ? clientRect.width / this.videoWidth : clientRect.height / this.videoHeight; - const videoOffsetX = videoRatio > clientRatio ? 0 : (clientRect.width - this.videoWidth * this._videoScale) * 0.5; - const videoOffsetY = videoRatio > clientRatio ? (clientRect.height - this.videoHeight * this._videoScale) * 0.5 : 0; - this._videoOriginX = clientRect.left + videoOffsetX; - this._videoOriginY = clientRect.top + videoOffsetY; - } - - // switch streaming destination main video and secondly video - switchVideo(indexVideoTrack) { - this.video.srcObject = this.localStream; - this.videoThumb.srcObject = this.localStream2; - - if (indexVideoTrack == 0) { - this.replaceTrack(this.localStream, this.videoTrackList[0]); - this.replaceTrack(this.localStream2, this.videoTrackList[1]); - } - else { - this.replaceTrack(this.localStream, this.videoTrackList[1]); - this.replaceTrack(this.localStream2, this.videoTrackList[0]); - } - } - - // replace video track related the MediaStream - replaceTrack(stream, newTrack) { - const tracks = stream.getVideoTracks(); - for (const track of tracks) { - if (track.kind == 'video') { - stream.removeTrack(track); - } - } - stream.addTrack(newTrack); - } - - get videoWidth() { - return this.video.videoWidth; - } - - get videoHeight() { - return this.video.videoHeight; - } - - get videoOriginX() { - return this._videoOriginX; - } - - get videoOriginY() { - return this._videoOriginY; - } - - get videoScale() { - return this._videoScale; - } - - sendMsg(msg) { - if (this.channel == null) { - return; - } - switch (this.channel.readyState) { - case 'connecting': - Logger.log('Connection not ready'); - break; - case 'open': - this.channel.send(msg); - break; - case 'closing': - Logger.log('Attempt to sendMsg message while closing'); - break; - case 'closed': - Logger.log('Attempt to sendMsg message while connection closed.'); - break; - } - } - - async stop() { - if (this.signaling) { - await this.signaling.stop(); - this.signaling = null; - } - - if (this.pc) { - this.pc.close(); - this.pc = null; - } - } -} diff --git a/WebApp/client/src/charnumber.js b/WebApp/client/src/charnumber.js deleted file mode 100644 index 2c79237..0000000 --- a/WebApp/client/src/charnumber.js +++ /dev/null @@ -1,109 +0,0 @@ -// KeyboardEvent.charcode is already deprecated. -// -export const CharNumber = { - "Backspace": 8, - "Tab": 9, - "Enter": 13, - "Shift": 16, - "Control": 17, - "Alt": 18, - "Pause": 19, - "CapsLock": 20, - "Escape": 27, - " ": 32, - "!": 33, - "\"": 34, - "#": 35, - "$": 36, - "%": 37, - "&": 38, - "'": 39, - "(": 40, - ")": 41, - "*": 42, - "+": 43, - ",": 44, - "-": 45, - ".": 46, - "/": 47, - "0": 48, - "1": 49, - "2": 50, - "3": 51, - "4": 52, - "5": 53, - "6": 54, - "7": 55, - "8": 56, - "9": 57, - ":": 58, - ";": 59, - "<": 60, - "=": 61, - ">": 62, - "?": 63, - "@": 64, - "A": 65, - "B": 66, - "C": 67, - "D": 68, - "E": 69, - "F": 70, - "G": 71, - "H": 72, - "I": 73, - "J": 74, - "K": 75, - "L": 76, - "M": 77, - "N": 78, - "O": 79, - "P": 80, - "Q": 81, - "R": 82, - "S": 83, - "T": 84, - "U": 85, - "V": 86, - "W": 87, - "X": 88, - "Y": 89, - "Z": 90, - "[": 91, - "\\": 92, - "]": 93, - "^": 94, - "_": 95, - "`": 96, - "a": 97, - "b": 98, - "c": 99, - "d": 100, - "e": 101, - "f": 102, - "g": 103, - "h": 104, - "i": 105, - "j": 106, - "k": 107, - "l": 108, - "m": 109, - "n": 110, - "o": 111, - "p": 112, - "q": 113, - "r": 114, - "s": 115, - "t": 116, - "u": 117, - "v": 118, - "w": 119, - "x": 120, - "y": 121, - "z": 122, - "{": 123, - "|": 124, - "}": 125, - "~": 126, - "Delete": 127 - }; diff --git a/WebApp/client/src/gamepadbutton.js b/WebApp/client/src/gamepadbutton.js deleted file mode 100644 index 047d248..0000000 --- a/WebApp/client/src/gamepadbutton.js +++ /dev/null @@ -1,26 +0,0 @@ -export const GamepadButton = { - DpadUp: 0, - DpadDown: 1, - DpadLeft: 2, - DpadRight: 3, - North: 4, - East: 5, - South: 6, - West: 7, - LeftStick: 8, - RightStick: 9, - LeftShoulder: 10, - RightShoulder: 11, - Start: 12, - Select: 13, - LeftTrigger: 32, - RightTrigger: 33, - X: 7, // West - Y: 4, // North - A: 6, // South, - B: 5, // East, - Cross: 6, // South, - Square: 7, // West, - Triangle: 4, //North, - Circle: 5 // East, -}; \ No newline at end of file diff --git a/WebApp/client/src/gamepadhandler.js b/WebApp/client/src/gamepadhandler.js deleted file mode 100644 index d74dd0b..0000000 --- a/WebApp/client/src/gamepadhandler.js +++ /dev/null @@ -1,44 +0,0 @@ -export class GamepadHandler extends EventTarget { - constructor() { - super(); - this._controllers = {}; - window.requestAnimationFrame(this._updateStatus.bind(this)); - } - - /** - * @param {Gamepad} gamepad - */ - addGamepad(gamepad) { - this._controllers[gamepad.index] = gamepad; - } - - /** - * @param {Gamepad} gamepad - */ - removeGamepad(gamepad) { - delete this._controllers[gamepad.index]; - } - - _updateStatus() { - this._scanGamepad(); - for(let i in this._controllers) { - const controller = this._controllers[i]; - - // gamepadupdated event type is own definition - this.dispatchEvent(new GamepadEvent('gamepadupdated', { - gamepad: controller - })); - } - window.requestAnimationFrame(this._updateStatus.bind(this)); - } - - _scanGamepad() { - let gamepads = navigator.getGamepads(); - for (let i = 0; i < gamepads.length; i++) { - if (gamepads[i] && (gamepads[i].index in this._controllers)) { - this._controllers[gamepads[i].index] = gamepads[i]; - } - } - } -} - diff --git a/WebApp/client/src/inputdevice.js b/WebApp/client/src/inputdevice.js deleted file mode 100644 index 50090f4..0000000 --- a/WebApp/client/src/inputdevice.js +++ /dev/null @@ -1,718 +0,0 @@ -import { - MemoryHelper, -} from "./memoryhelper.js"; - -import { CharNumber } from "./charnumber.js"; -import { Keymap } from "./keymap.js"; -import { MouseButton } from "./mousebutton.js"; -import { GamepadButton } from "./gamepadbutton.js"; -import { TouchPhase } from "./touchphase.js"; -import { TouchFlags } from "./touchflags.js"; - -export class FourCC { - /** - * {Number} _code; - */ - - /** - * - * @param {String} a - * @param {String} b - * @param {String} c - * @param {String} d - */ - constructor(a, b, c, d) { - this._code = (a.charCodeAt() << 24) - | (b.charCodeAt() << 16) - | (c.charCodeAt() << 8) - | d.charCodeAt(); - } - - /** - * @returns {Number} - */ - toInt32() { - return this._code; - } -} - - -export class InputDevice { - - /** - * - * name; - * layout; - * deviceId; - * usages; - * description; - * - * _inputState; - */ - - /** - * - * @param {Number} name - * @param {String} layout - * @param {Number} deviceId - * @param {String[]} usages - * @param {Object} description - */ - constructor(name, layout, deviceId, usages, description) { - this.name = name; - this.layout = layout; - this.deviceId = deviceId; - this.usages = usages; - this.description = description; - - this._inputState = null; - } - - /** - * - * @param {IInputState} state - */ - updateState(state) { - this._inputState = state; - } - - queueEvent(event) { - throw new Error(`Please implement this method. event:${event}`); - } - - /** - * @returns {IInputState} - */ - get currentState() { - return this._inputState; - } -} - -export class Mouse extends InputDevice { - /** - * @param {(MouseEvent|WheelEvent)} event - */ - queueEvent(event) { - this.updateState(new MouseState(event)); - } -} - -export class Keyboard extends InputDevice { - static get keycount() { return 110; } - /** - * - * @param {KeyboardEvent} event - */ - queueEvent(event) { - this.updateState(new KeyboardState(event, this.currentState)); - } -} - -export class Touchscreen extends InputDevice { - /** - * @param {TouchScreenEvent} event - */ - queueEvent(event, time) { - this.updateState(new TouchscreenState(event, this.currentState, time)); - } -} - -export class Gamepad extends InputDevice { - /** - * @param {GamepadButtonEvent | GamepadAxisEvent} event - */ - queueEvent(event) { - this.updateState(new GamepadState(event)); - } -} - -export class InputEvent { - static get invalidEventId() { return 0; } - static get size() { return 20; } - - /** - * field offset 0 - * @member {Number} type; - * - * field offset 4 - * @member {Number} sizeInBytes; - * - * field offset 6 - * @member {Number} deviceId; - * - * field offset 8 - * @member {Number} time; - * - * field offset 16 - * @member {Number} eventId; - */ - - /** - * - * @param {Number} type - * @param {Number} sizeInBytes - * @param {Number} deviceId - * @param {Number} time - */ - constructor(type, sizeInBytes, deviceId, time) { - this.type = type; - this.sizeInBytes = sizeInBytes; - this.deviceId = deviceId; - this.time = time; - this.eventId = InputEvent.invalidEventId; - } - - /** - * @returns {ArrayBuffer} - */ - get buffer() { - let _buffer = new ArrayBuffer(InputEvent.size); - let view = new DataView(_buffer); - view.setInt32(0, this.type, true); - view.setInt16(4, this.sizeInBytes, true); - view.setInt16(6, this.deviceId, true); - view.setFloat64(8, this.time, true); - view.setInt16(16, this.sizeInBytes, true); - return _buffer; - } -} - -export class IInputState { - /** - * @returns {ArrayBuffer} - */ - get buffer() { - throw new Error('Please implement this field'); - } - /** - * @returns {Number} - */ - get format() { - throw new Error('Please implement this field'); - } -} - -export class MouseState extends IInputState { - static get size() { return 30; } - static get format() { return new FourCC('M', 'O', 'U', 'S').toInt32(); } - - /** - * field offset 0 - * @member {Array} position; - * - * field offset 8 - * @member {Array} delta; - * - * field offset 16 - * @member {Array} scroll; - * - * field offset 24 - * @member {ArrayBuffer} buttons; - * - * field offset 26 - * @member {Array} displayIndex; - * - * field offset 28 - * @member {Array} clickCount; - */ - - /** - * @param {MouseEvent | WheelEvent} event - */ - constructor(event) { - super(); - - this.position = [event.clientX, event.clientY]; - this.delta = [event.movementX, -event.movementY]; - this.scroll = [0, 0]; - if(event.type === 'wheel') { - this.scroll = [event.deltaX, event.deltaY]; - } - this.buttons = new ArrayBuffer(2); - - const left = event.buttons & 1 << 0; - const right = event.buttons & 1 << 1; - const middle = event.buttons & 1 << 2; - const back = event.buttons & 1 << 3; - const forward = event.buttons & 1 << 4; - - MemoryHelper.writeSingleBit(this.buttons, MouseButton.Left, left); - MemoryHelper.writeSingleBit(this.buttons, MouseButton.Right, right); - MemoryHelper.writeSingleBit(this.buttons, MouseButton.Middle, middle); - MemoryHelper.writeSingleBit(this.buttons, MouseButton.Forward, forward); - MemoryHelper.writeSingleBit(this.buttons, MouseButton.Back, back); - } - - /** - * @returns {ArrayBuffer} - */ - get buffer() { - const size = MouseState.size; - const buttons = new Uint16Array(this.buttons)[0]; - let _buffer = new ArrayBuffer(size); - let view = new DataView(_buffer); - view.setFloat32(0, this.position[0], true); - view.setFloat32(4, this.position[1], true); - view.setFloat32(8, this.delta[0], true); - view.setFloat32(12, this.delta[1], true); - view.setFloat32(16, this.scroll[0], true); - view.setFloat32(20, this.scroll[1], true); - view.setUint16(24, buttons, true); - view.setUint16(26, this.displayIndex, true); - view.setUint16(28, this.clickCount, true); - return _buffer; - } - - /** - * @returns {Number} - */ - get format() { - return MouseState.format; - } -} - -export class KeyboardState extends IInputState { - static get sizeInBits() { return Keyboard.keycount; } - static get sizeInBytes() { return (KeyboardState.sizeInBits + 7) >> 3; } - static get format() { return new FourCC('K', 'E', 'Y', 'S').toInt32(); } - - /** - * field offset 0 - * @number {ArrayBuffer} keys; - */ - - /** - * @param {KeyboardEvent} event - */ - constructor(event, state) { - super(); - if (state == null || state.keys == null) { - this.keys = new ArrayBuffer(KeyboardState.sizeInBytes); - } else { - this.keys = state.keys; - } - let value = false; - switch(event.type) { - case 'keydown': - value = true; - break; - case 'keyup': - value = false; - break; - default: - throw new Error(`unknown event type ${event.type})`); - } - const key = Keymap[event.code]; - MemoryHelper.writeSingleBit(this.keys, key, value); - } - - /** - * @returns {ArrayBuffer} - */ - get buffer() { - return this.keys; - } - - /** - * @returns {Number} - */ - get format() { - return KeyboardState.format; - } -} - -export class TouchState { - static get format() { return new FourCC('T', 'O', 'U', 'C').toInt32(); } - static get size() { return 56; } - static incrementTouchId() { - if(TouchState._currentTouchId === undefined) { - TouchState._currentTouchId = 0; - } - return ++TouchState._currentTouchId; - } - static prevTouches() { - if(TouchState._prevTouches === undefined) { - // max touch count is 10 - TouchState._prevTouches = new Array(10); - } - return TouchState._prevTouches; - } - - /** - * field offset 0 - * @number {Number} touchId; - * field offset 4 - * @number {Number[]} position; - * field offset 12 - * @number {Number[]} delta; - * field offset 20 - * @number {Number} pressure; - * field offset 24 - * @number {Number[]} radius; - * field offset 32 - * @number {Number} phase; - * field offset 33 - * @number {Number} tapCount; - * field offset 34 - * @number {Number} displayIndex; - * field offset 35 - * @number {Number} flag; - * field offset 36 - * @number {Number} padding; - * field offset 40 - * @number {Number} startTime; - * field offset 48 - * @number {Number[]} startPosition; - */ - - - /** - * @param {Touch} touchId - * @param {TouchState} prevState - * @param {Number[]} position - * @param {Number} pressure - * @param {Number[]} radius - * @param {TouchPhase} phaseId - * @param {Number} time - */ - constructor(touchId, prevState, position, pressure, radius, phaseId, time) { - this.touchId = touchId; - this.position = position != null ? position.slice() : null; - if(phaseId == TouchPhase.Moved) { - this.delta = [this.position[0] - prevState.position[0], this.position[1] - prevState.position[1]]; - } else { - this.delta = [0, 0]; - } - this.pressure = pressure; - this.radius = radius != null ? radius.slice(): null; - this.phaseId = phaseId; - this.tapCount = 0; - this.displayIndex = 0; - this.flags = 0; - this.padding = 0; - if(phaseId == TouchPhase.Began) { - this.startTime = time; - this.startPosition = this.position.slice(); - } else { - this.startTime = prevState != null ? prevState.startTime : null; - this.startPosition = prevState != null ? prevState.startPosition.slice() : null; - } - } - - - copy() { - let state = new TouchState(); - state.touchId = this.touchId; - state.position = this.position.slice(); - state.delta = this.delta.slice(); - state.pressure = this.pressure; - state.radius = this.radius.slice(); - state.phaseId = this.phaseId; - state.tapCount = this.tapCount; - state.displayIndex = this.displayIndex; - state.flags = this.flags; - state.padding = this.padding; - state.startTime = this.startTime; - state.startPosition = this.startPosition.slice(); - return state; - } - - /** - * @returns {ArrayBuffer} - */ - get buffer() { - const size = TouchState.size; // todo - let _buffer = new ArrayBuffer(size); - let view = new DataView(_buffer); - - view.setInt32(0, this.touchId, true); - view.setFloat32(4, this.position[0], true); - view.setFloat32(8, this.position[1], true); - view.setFloat32(12, this.delta[0], true); - view.setFloat32(16, this.delta[1], true); - view.setFloat32(20, this.pressure, true); - view.setFloat32(24, this.radius[0], true); - view.setFloat32(28, this.radius[1], true); - view.setInt8(32, this.phaseId, true); - view.setInt8(33, this.tapCount, true); - view.setInt8(34, this.displayIndex, true); - view.setInt8(35, this.flags, true); - view.setInt32(36, this.padding, true); - view.setFloat64(40, this.startTime, true); - view.setFloat32(48, this.startPosition[0], true); - view.setFloat32(52, this.startPosition[1], true); - return _buffer; - } - - /** - * @returns {Number} - */ - get format() { - return TouchState.format; - } -} - -export class TouchscreenState extends IInputState { - static get maxTouches() { return 10; } - static get format() { return new FourCC('T', 'S', 'C', 'R').toInt32(); } - static convertPhaseId(type) { - let phaseId = TouchPhase.Stationary; - switch(type) { - case 'touchstart': - phaseId = TouchPhase.Began; break; - case 'touchend': - phaseId = TouchPhase.Ended; break; - case 'touchmove': - phaseId = TouchPhase.Moved; break; - case 'touchcancel': - phaseId = TouchPhase.Canceled; break; - } - return phaseId; - } - - /** - * @param {TouchEvent} event - * @param {TouchScreenState} state - * @param {Date} time - */ - constructor(event, state, time) { - super(); - - switch(event.type) { - // `click` event is called when releasing mouse button or finger on screen. - case 'click' : { - this.touchData = new Array(state.touchData.length); - for(let i = 0; i < state.touchData.length; i++) { - this.touchData[i] = state.touchData[i]; - if(this.touchData[i].phaseId == TouchPhase.Ended) { - this.touchData[i].tapCount = 1; - this.touchData[i].flags |= TouchFlags.Tap; - } - } - break; - } - default: { - let touches = event.changedTouches; - this.touchData = new Array(touches.length); - for(let i = 0; i < touches.length; i++) { - const touch = touches[i]; - const position = [touch.clientX, touch.clientY]; - const phaseId = TouchscreenState.convertPhaseId(event.type); - const pressure = touch.force; - const radius = [touch.radiusX, touch.radiusY]; - - // `touchId` in InputSystem must be set uniquely. - // The numbers of `touch.identifier` in Web API are reused, so these are not unique. - const touchId = phaseId == TouchPhase.Began ? TouchState.incrementTouchId() : TouchState.prevTouches()[touch.identifier].touchId; - const prevState = phaseId != TouchPhase.Began ? TouchState.prevTouches()[touch.identifier] : null; - const touchData = new TouchState(touchId, prevState, position, pressure, radius, phaseId, time); - - // cache state - TouchState.prevTouches()[touch.identifier] = touchData; - this.touchData[i] = touchData; - } - break; - } - } - } - - /** - * @returns {ArrayBuffer} - */ - get buffer() { - const size = TouchState.size * this.touchData.length; - let _buffer = new ArrayBuffer(size); - let view = new Uint8Array(_buffer); - for(let i = 0; i < this.touchData.length; i++) { - view.set(new Uint8Array(this.touchData[i].buffer), TouchState.size * i); - } - return _buffer; - } - - /** - * @returns {Number} - */ - get format() { - return TouchscreenState.format; - } -} - -export class GamepadState extends IInputState { - static get size() { return 28; } - static get format() { return new FourCC('G', 'P', 'A', 'D').toInt32(); } - - /** - * field offset 0 - * @member buttons; - * - * field offset 4 - * @member leftStick; - * - * field offset 12 - * @member rightStick; - * - * field offset 20 - * @member leftTrigger; - * - * field offset 24 - * @member rightTrigger; - */ - - /** - * - * @param {GamepadButtonEvent | GamepadAxisEvent} event - */ - constructor(event) { - super(); - const gamepad = event.gamepad; - const buttons = event.gamepad.buttons; - - this.buttons = new ArrayBuffer(4); - this.leftStick = [ gamepad.axes[0], -gamepad.axes[1] ]; - this.rightStick = [ gamepad.axes[2], -gamepad.axes[3] ]; - this.leftTrigger = buttons[6].value; - this.rightTrigger = buttons[7].value; - - // see https://w3c.github.io/gamepad/#remapping - MemoryHelper.writeSingleBit(this.buttons, GamepadButton.A, buttons[0].pressed); - MemoryHelper.writeSingleBit(this.buttons, GamepadButton.B, buttons[1].pressed); - MemoryHelper.writeSingleBit(this.buttons, GamepadButton.X, buttons[2].pressed); - MemoryHelper.writeSingleBit(this.buttons, GamepadButton.Y, buttons[3].pressed); - MemoryHelper.writeSingleBit(this.buttons, GamepadButton.LeftShoulder, buttons[4].pressed); - MemoryHelper.writeSingleBit(this.buttons, GamepadButton.RightShoulder, buttons[5].pressed); - MemoryHelper.writeSingleBit(this.buttons, GamepadButton.LeftTrigger, buttons[6].pressed); - MemoryHelper.writeSingleBit(this.buttons, GamepadButton.RightTrigger, buttons[7].pressed); - MemoryHelper.writeSingleBit(this.buttons, GamepadButton.Select, buttons[8].pressed); - MemoryHelper.writeSingleBit(this.buttons, GamepadButton.Start, buttons[9].pressed); - MemoryHelper.writeSingleBit(this.buttons, GamepadButton.LeftStick, buttons[10].pressed); - MemoryHelper.writeSingleBit(this.buttons, GamepadButton.RightStick, buttons[11].pressed); - MemoryHelper.writeSingleBit(this.buttons, GamepadButton.DpadUp, buttons[12].pressed); - MemoryHelper.writeSingleBit(this.buttons, GamepadButton.DpadDown, buttons[13].pressed); - MemoryHelper.writeSingleBit(this.buttons, GamepadButton.DpadLeft, buttons[14].pressed); - MemoryHelper.writeSingleBit(this.buttons, GamepadButton.DpadRight, buttons[15].pressed); - } - - /** - * @returns {ArrayBuffer} - */ - get buffer() { - const size = GamepadState.size; - let _buffer = new ArrayBuffer(size); - let view = new DataView(_buffer); - view.setUint32(0, new Uint32Array(this.buttons)[0], true); - view.setFloat32(4, this.leftStick[0], true); - view.setFloat32(8, this.leftStick[1], true); - view.setFloat32(12, this.rightStick[0], true); - view.setFloat32(16, this.rightStick[1], true); - view.setFloat32(20, this.leftTrigger, true); - view.setFloat32(24, this.rightTrigger, true); - return _buffer; - } - - /** - * @returns {Number} - */ - get format() { - return GamepadState.format; - } -} - -export class TextEvent { - static get format() { return new FourCC('T', 'E', 'X', 'T').toInt32(); } - - /** - * field offset 0 - * @member {InputEvent} baseEvent; - * - * field offset 20 - * @member {Number} character; - */ - - /** - * - * @param {Number} deviceId - * @param {KeyboardEvent} event - * @param {Number} time - * @returns {TextEvent} - - */ - static create(deviceId, event, time) { - const eventSize = InputEvent.size + MemoryHelper.sizeOfInt; - - let textEvent = new TextEvent(); - textEvent.baseEvent = new InputEvent(TextEvent.format, eventSize, deviceId, time); - textEvent.character = CharNumber[event.key]; - return textEvent; - } - - /** - * @returns {ArrayBuffer} - */ - get buffer() { - const size = InputEvent.size + MemoryHelper.sizeOfInt; - let _buffer = new ArrayBuffer(size); - let arrayView = new Uint8Array(_buffer); - let dataView = new DataView(_buffer); - arrayView.set(new Uint8Array(this.baseEvent.buffer), 0); - dataView.setInt32(InputEvent.size, this.character, true); - return _buffer; - } -} - -export class StateEvent { - static get format() { return new FourCC('S', 'T', 'A', 'T').toInt32(); } - - /** - * field offset 0 - * @member {InputEvent} baseEvent; - * - * field offset 20 - * @member {Number} stateFormat; - * - * field offset 24 - * @member {ArrayBuffer} stateData; - */ - - /** - * - * @param {InputDevice} device - * @param {Number} time - * @returns {StateEvent} - */ - static from(device, time) { - return StateEvent.fromState(device.currentState, device.deviceId, time); - } - - /** - * - * @param {IInputState} state - * @param {Number} deviceId - * @param {Number} time - */ - static fromState(state, deviceId, time) { - const stateData = state.buffer; - const stateSize = stateData.byteLength; - const eventSize = InputEvent.size + MemoryHelper.sizeOfInt + stateSize; - - let stateEvent = new StateEvent(); - stateEvent.baseEvent = new InputEvent(StateEvent.format, eventSize, deviceId, time); - stateEvent.stateFormat = state.format; - stateEvent.stateData = stateData; - return stateEvent; - } - - /** - * @returns {ArrayBuffer} - */ - get buffer() { - const stateSize = this.stateData.byteLength; - const size = InputEvent.size + MemoryHelper.sizeOfInt + stateSize; - let _buffer = new ArrayBuffer(size); - let uint8View = new Uint8Array(_buffer); - let dataView = new DataView(_buffer); - uint8View.set(new Uint8Array(this.baseEvent.buffer), 0); - dataView.setInt32(InputEvent.size, this.stateFormat, true); - uint8View.set(new Uint8Array(this.stateData), InputEvent.size+MemoryHelper.sizeOfInt); - return _buffer; - } -} diff --git a/WebApp/client/src/inputremoting.js b/WebApp/client/src/inputremoting.js deleted file mode 100644 index f1f82e6..0000000 --- a/WebApp/client/src/inputremoting.js +++ /dev/null @@ -1,299 +0,0 @@ -import { - StateEvent, -} from "./inputdevice.js"; - -import { - MemoryHelper -} from "./memoryhelper.js"; - -export class LocalInputManager { - constructor() { - this._onevent = new EventTarget(); - } - - /** - * event type 'event', 'changedeviceusage' - * @return {Event} - */ - get onEvent() { - return this._onevent; - } - - /** - * @return {Event} - */ - get devices() { - throw new Error(`Please implement this method.`); - } - - /** - * @return {Number} time (sec) - */ - get startTime() { - return this._startTime; - } - - /** - * @return {Number} time (sec) - */ - get timeSinceStartup() { - return Date.now()/1000 - this.startTime; - } - - /** - * @param {Number} time (sec) - */ - setStartTime(time) { - this._startTime = time; - } -} - -export const InputDeviceChange = { - Added: 0, - Removed: 1, - Disconnected: 2, - Reconnected: 3, - Enabled: 4, - Disabled: 5, - UsageChanged: 6, - ConfigurationChanged: 7, - Destroyed: 8, -}; - -export class InputRemoting { - /** - * @param {LocalInputManager} manager - */ - constructor(manager) { - this._localManager = manager; - this._subscribers = new Array(); - this._sending = false; - } - - startSending() { - if(this._sending) { - return; - } - this._sending = true; - - const onEvent = e => { - this._sendEvent(e.detail.event); - }; - - const onDeviceChange = e => { - this._sendDeviceChange(e.detail.device, e.detail.change); - }; - - this._localManager.setStartTime(Date.now()/1000); - this._localManager.onEvent.addEventListener("event", onEvent); - this._localManager.onEvent.addEventListener("changedeviceusage", onDeviceChange); - this._sendInitialMessages(); - } - - stopSending() { - if (!this._sending) { - return; - } - this._sending = false; - } - - /** - * - * @param {Observer} observer - */ - subscribe(observer) { - this._subscribers.push(observer); - } - - _sendInitialMessages() { - this._sendAllGeneratedLayouts(); - this._sendAllDevices(); - } - - _sendAllGeneratedLayouts() { - // todo: - } - - _sendAllDevices() { - var devices = this._localManager.devices; - if(devices == null) - return; - for (const device of devices) { - this._sendDevice(device); - } - } - - _sendDevice(device) { - const newDeviceMessage = NewDeviceMsg.create(device); - this._send(newDeviceMessage); - - // Send current state. We do this here in this case as the device - // may have been added some time ago and thus have already received events. - - // todo: - // const stateEventMessage = NewEventsMsg.createStateEvent(device); - // this._send(stateEventMessage); - } - - _sendEvent(event) { - const message = NewEventsMsg.create(event); - this._send(message); - } - - _sendDeviceChange(device, change) { - if (this._subscribers == null) - return; - - let msg = null; - switch (change) { - case InputDeviceChange.Added: - msg = NewDeviceMsg.Create(device); - break; - case InputDeviceChange.Removed: - msg = RemoveDeviceMsg.Create(device); - break; - case InputDeviceChange.UsageChanged: - msg = ChangeUsageMsg.Create(device); - break; - default: - return; - } - this._send(msg); - } - - _send(message) { - for(let subscriber of this._subscribers) { - subscriber.onNext(message); - } - } -} - -export const MessageType = { - Connect: 0, - Disconnect: 1, - NewLayout: 2, - NewDevice: 3, - NewEvents: 4, - RemoveDevice: 5, - RemoveLayout: 6, - ChangeUsages: 7, - StartSending: 8, - StopSending: 9, -}; - -export class Message { - /** - * field offset 0 - * {Number} participant_id; - * - * field offset 4 - * {Number} type; - * - * field offset 8 - * {Number} length; - * - * field offset 12 - * {ArrayBuffer} data; - */ - - /** - * - * @param {number} participantId - * @param {MessageType} type - * @param {ArrayBuffer} data - */ - constructor(participantId, type, data) { - this.participant_id = participantId; - this.type = type; - this.length = data.byteLength; - this.data = data; - } - - /** - * - * @returns {ArrayBuffer} - */ - get buffer() { - const totalSize = - MemoryHelper.sizeOfInt + // size of this.participant_id - MemoryHelper.sizeOfInt + // size of this.type - MemoryHelper.sizeOfInt + // size of this.length - this.data.byteLength; // size of this.data - - let buffer = new ArrayBuffer(totalSize); - let dataView = new DataView(buffer); - let uint8view = new Uint8Array(buffer); - dataView.setUint32(0, this.participant_id, true); - dataView.setUint32(4, this.type, true); - dataView.setUint32(8, this.length, true); - uint8view.set(new Uint8Array(this.data), 12); - return buffer; - } -} - -export class NewDeviceMsg { - /** - * @param {InputDevice} device - * @returns {Message} - */ - static create(device) { - const data = { - name: device.name, - layout: device.layout, - deviceId: device.deviceId, - variants: device.variants, - description: device.description - }; - const json = JSON.stringify(data); - let buffer = new ArrayBuffer(json.length*2); // 2 bytes for each char - let view = new Uint8Array(buffer); - const length = json.length; - for (let i = 0; i < length; i++) { - view[i] = json.charCodeAt(i); - } - return new Message(0, MessageType.NewDevice, buffer); - } -} - -export class NewEventsMsg { - /** - * - * @param {InputDevice} device - * @returns {Message} - */ - static createStateEvent(device) { - const events = StateEvent.from(device); - return NewEventsMsg.create(events); - } - - /** - * - * @param {StateEvent} event - * @returns {Message} - */ - static create(event) { - return new Message(0, MessageType.NewEvents, event.buffer); - } -} - -export class RemoveDeviceMsg { - /** - * - * @param {InputDevice} device - * @returns {Message} - */ - static create(device) { - let buffer = new ArrayBuffer(MemoryHelper.sizeOfInt); - let view = new DataView(buffer); - view.setInt32(device.deviceId); - return new Message(0, MessageType.RemoveDevice, buffer); - } -} - -export class ChangeUsageMsg { - - static create(device) { - // todo: - throw new Error(`ChangeUsageMsg class is not implemented. device=${device}`); - } -} diff --git a/WebApp/client/src/keymap.js b/WebApp/client/src/keymap.js deleted file mode 100644 index 5dbca1e..0000000 --- a/WebApp/client/src/keymap.js +++ /dev/null @@ -1,120 +0,0 @@ -export const Keymap = { - "Space": 1, - "Enter": 2, - "Tab": 3, - "Backquote": 4, - "Quote": 5, - "Semicolon": 6, - "Comma": 7, - "Period": 8, - "Slash": 9, - "Backslash": 10, - "BracketLeft": 11, - "BracketRight": 12, - "Minus": 13, - "Equal": 14, - "KeyA": 15, - "KeyB": 16, - "KeyC": 17, - "KeyD": 18, - "KeyE": 19, - "KeyF": 20, - "KeyG": 21, - "KeyH": 22, - "KeyI": 23, - "KeyJ": 24, - "KeyK": 25, - "KeyL": 26, - "KeyM": 27, - "KeyN": 28, - "KeyO": 29, - "KeyP": 30, - "KeyQ": 31, - "KeyR": 32, - "KeyS": 33, - "KeyT": 34, - "KeyU": 35, - "KeyV": 36, - "KeyW": 37, - "KeyX": 38, - "KeyY": 39, - "KeyZ": 40, - "Digit1": 41, - "Digit2": 42, - "Digit3": 43, - "Digit4": 44, - "Digit5": 45, - "Digit6": 46, - "Digit7": 47, - "Digit8": 48, - "Digit9": 49, - "Digit0": 50, - "ShiftLeft": 51, - "ShiftRight": 52, - "AltLeft": 53, - "AltRight": 54, - // "AltGr": 54, - "ControlLeft": 55, - "ControlRight": 56, - "MetaLeft": 57, - "MetaRight": 58, - // "LeftWindows": 57, - // "RightWindows": 58, - // "LeftApple": 57, - // "RightApple": 58, - // "LeftCommand": 57, - // "RightCommand": 58, - "ContextMenu": 59, - "Escape": 60, - "ArrowLeft": 61, - "ArrowRight": 62, - "ArrowUp": 63, - "ArrowDown": 64, - "Backspace": 65, - "PageDown": 66, - "PageUp": 67, - "Home": 68, - "End": 69, - "Insert": 70, - "Delete": 71, - "CapsLock": 72, - "NumLock": 73, - "PrintScreen": 74, - "ScrollLock": 75, - "Pause": 76, - "NumpadEnter": 77, - "NumpadDivide": 78, - "NumpadMultiply": 79, - "NumpadAdd": 80, - "NumpadSubtract": 81, - "NumpadDecimal": 82, - "NumpadEquals": 83, - "Numpad0": 84, - "Numpad1": 85, - "Numpad2": 86, - "Numpad3": 87, - "Numpad4": 88, - "Numpad5": 89, - "Numpad6": 90, - "Numpad7": 91, - "Numpad8": 92, - "Numpad9": 93, - "F1": 94, - "F2": 95, - "F3": 96, - "F4": 97, - "F5": 98, - "F6": 99, - "F7": 100, - "F8": 101, - "F9": 102, - "F10": 103, - "F11": 104, - "F12": 105, - // "OEM1": 106, - // "OEM2": 107, - // "OEM3": 108, - // "OEM4": 109, - // "OEM5": 110, - // "IMESelected": 111, - }; \ No newline at end of file diff --git a/WebApp/client/src/logger.js b/WebApp/client/src/logger.js deleted file mode 100644 index 359ab39..0000000 --- a/WebApp/client/src/logger.js +++ /dev/null @@ -1,29 +0,0 @@ -let isDebug = false; - -export function enable() { - isDebug = true; -} - -export function disable() { - isDebug = false; -} - -export function debug(msg) { - isDebug && console.debug(msg); -} - -export function info(msg) { - isDebug && console.info(msg); -} - -export function log(msg) { - isDebug && console.log(msg); -} - -export function warn(msg) { - isDebug && console.warn(msg); -} - -export function error(msg) { - isDebug && console.error(msg); -} diff --git a/WebApp/client/src/memoryhelper.js b/WebApp/client/src/memoryhelper.js deleted file mode 100644 index 3021008..0000000 --- a/WebApp/client/src/memoryhelper.js +++ /dev/null @@ -1,28 +0,0 @@ -export class MemoryHelper { - /** - * @param {ArrayBuffer} buffer - * @param {number} bitOffset - * @param {boolean} value - */ - static writeSingleBit(buffer, bitOffset, value) { - let view = new Uint8Array(buffer); - const index = Math.floor(bitOffset / 8); - bitOffset = bitOffset % 8; - const byte = view[index]; - let newByte = 1 << bitOffset; - if(value) { - newByte = newByte | byte; - } - else { - newByte = ~newByte & byte; - } - view[index] = newByte; - } - - /** - * @return {Number} - */ - static get sizeOfInt() { - return 4; - } -} \ No newline at end of file diff --git a/WebApp/client/src/mousebutton.js b/WebApp/client/src/mousebutton.js deleted file mode 100644 index 0ed88f7..0000000 --- a/WebApp/client/src/mousebutton.js +++ /dev/null @@ -1,7 +0,0 @@ -export const MouseButton = { - Left: 0, - Right: 1, - Middle: 2, - Foaward: 3, - Back: 4, -}; \ No newline at end of file diff --git a/WebApp/client/src/peer.js b/WebApp/client/src/peer.js deleted file mode 100644 index da379a0..0000000 --- a/WebApp/client/src/peer.js +++ /dev/null @@ -1,187 +0,0 @@ -import * as Logger from "./logger.js"; - -export default class Peer extends EventTarget { - constructor(connectionId, polite, config, resendIntervalMsec = 5000) { - super(); - const _this = this; - this.connectionId = connectionId; - this.polite = polite; - this.config = config; - this.pc = new RTCPeerConnection(this.config); - this.makingOffer = false; - this.waitingAnswer = false; - this.ignoreOffer = false; - this.srdAnswerPending = false; - this.log = str => void Logger.log(`[${_this.polite ? 'POLITE' : 'IMPOLITE'}] ${str}`); - this.warn = str => void Logger.warn(`[${_this.polite ? 'POLITE' : 'IMPOLITE'}] ${str}`); - this.assert_equals = window.assert_equals ? window.assert_equals : (a, b, msg) => { if (a === b) { return; } throw new Error(`${msg} expected ${b} but got ${a}`); }; - this.interval = resendIntervalMsec; - this.sleep = msec => new Promise(resolve => setTimeout(resolve, msec)); - - this.pc.ontrack = e => { - _this.log(`ontrack:${e}`); - _this.dispatchEvent(new CustomEvent('trackevent', { detail: e })); - }; - this.pc.ondatachannel = e => { - _this.log(`ondatachannel:${e}`); - _this.dispatchEvent(new CustomEvent('adddatachannel', { detail: e })); - }; - this.pc.onicecandidate = ({ candidate }) => { - _this.log(`send candidate:${candidate}`); - if (candidate == null) { - return; - } - _this.dispatchEvent(new CustomEvent('sendcandidate', { detail: { connectionId: _this.connectionId, candidate: candidate.candidate, sdpMLineIndex: candidate.sdpMLineIndex, sdpMid: candidate.sdpMid } })); - }; - - this.pc.onnegotiationneeded = this._onNegotiation.bind(this); - - this.pc.onsignalingstatechange = () => { - _this.log(`signalingState changed:${_this.pc.signalingState}`); - }; - - this.pc.oniceconnectionstatechange = () => { - _this.log(`iceConnectionState changed:${_this.pc.iceConnectionState}`); - if (_this.pc.iceConnectionState === 'failed') { - this.dispatchEvent(new Event('disconnect')); - } - }; - - this.pc.onicegatheringstatechange = () => { - _this.log(`iceGatheringState changed:${_this.pc.iceGatheringState}'`); - }; - - this.loopResendOffer(); - } - - async _onNegotiation() { - try { - this.log(`SLD due to negotiationneeded`); - this.assert_equals(this.pc.signalingState, 'stable', 'negotiationneeded always fires in stable state'); - this.assert_equals(this.makingOffer, false, 'negotiationneeded not already in progress'); - this.makingOffer = true; - await this.pc.setLocalDescription(); - this.assert_equals(this.pc.signalingState, 'have-local-offer', 'negotiationneeded not racing with onmessage'); - this.assert_equals(this.pc.localDescription.type, 'offer', 'negotiationneeded SLD worked'); - this.waitingAnswer = true; - this.dispatchEvent(new CustomEvent('sendoffer', { detail: { connectionId: this.connectionId, sdp: this.pc.localDescription.sdp } })); - } catch (e) { - this.log(e); - } finally { - this.makingOffer = false; - } - } - - async loopResendOffer() { - while (this.connectionId) { - if (this.pc && this.waitingAnswer) { - this.dispatchEvent(new CustomEvent('sendoffer', { detail: { connectionId: this.connectionId, sdp: this.pc.localDescription.sdp } })); - } - await this.sleep(this.interval); - } - } - - close() { - this.connectionId = null; - if (this.pc) { - this.pc.close(); - this.pc = null; - } - } - - getTransceivers(connectionId) { - if (this.connectionId != connectionId) { - return null; - } - - return this.pc.getTransceivers(); - } - - addTrack(connectionId, track) { - if (this.connectionId != connectionId) { - return null; - } - - return this.pc.addTrack(track); - } - - addTransceiver(connectionId, trackOrKind, init) { - if (this.connectionId != connectionId) { - return null; - } - - return this.pc.addTransceiver(trackOrKind, init); - } - - createDataChannel(connectionId, label) { - if (this.connectionId != connectionId) { - return null; - } - - return this.pc.createDataChannel(label); - } - - async getStats(connectionId) { - if (this.connectionId != connectionId) { - return null; - } - - return await this.pc.getStats(); - } - - async onGotDescription(connectionId, description) { - if (this.connectionId != connectionId) { - return; - } - - const _this = this; - const isStable = - this.pc.signalingState == 'stable' || - (this.pc.signalingState == 'have-local-offer' && this.srdAnswerPending); - this.ignoreOffer = - description.type == 'offer' && !this.polite && (this.makingOffer || !isStable); - - if (this.ignoreOffer) { - _this.log(`glare - ignoring offer`); - return; - } - - this.waitingAnswer = false; - this.srdAnswerPending = description.type == 'answer'; - _this.log(`SRD(${description.type})`); - await this.pc.setRemoteDescription(description); - this.srdAnswerPending = false; - - if (description.type == 'offer') { - _this.dispatchEvent(new CustomEvent('ongotoffer', { detail: { connectionId: _this.connectionId } })); - - _this.assert_equals(this.pc.signalingState, 'have-remote-offer', 'Remote offer'); - _this.assert_equals(this.pc.remoteDescription.type, 'offer', 'SRD worked'); - _this.log('SLD to get back to stable'); - await this.pc.setLocalDescription(); - _this.assert_equals(this.pc.signalingState, 'stable', 'onmessage not racing with negotiationneeded'); - _this.assert_equals(this.pc.localDescription.type, 'answer', 'onmessage SLD worked'); - _this.dispatchEvent(new CustomEvent('sendanswer', { detail: { connectionId: _this.connectionId, sdp: _this.pc.localDescription.sdp } })); - - } else { - _this.dispatchEvent(new CustomEvent('ongotanswer', { detail: { connectionId: _this.connectionId } })); - - _this.assert_equals(this.pc.remoteDescription.type, 'answer', 'Answer was set'); - _this.assert_equals(this.pc.signalingState, 'stable', 'answered'); - this.pc.dispatchEvent(new Event('negotiated')); - } - } - - async onGotCandidate(connectionId, candidate) { - if (this.connectionId != connectionId) { - return; - } - - try { - await this.pc.addIceCandidate(candidate); - } catch (e) { - if (this.pc && !this.ignoreOffer) - this.warn(`${this.pc} this candidate can't accept current signaling state ${this.pc.signalingState}.`); - } - } -} diff --git a/WebApp/client/src/pointercorrect.js b/WebApp/client/src/pointercorrect.js deleted file mode 100644 index 04e0f61..0000000 --- a/WebApp/client/src/pointercorrect.js +++ /dev/null @@ -1,124 +0,0 @@ -export const LetterBoxType = { - Vertical: 0, - Horizontal: 1 -}; - -export class PointerCorrector { - /** - * @param {Number} videoWidth - * @param {Number} videoHeight - * @param {HTMLVideoElement} videoElem - */ - constructor(videoWidth, videoHeight, videoElem) { - this.reset(videoWidth, videoHeight, videoElem); - } - - /** - * @param {Number[]} position MouseEvent.clientX, MouseEvent.clientY - * @returns {Number[]} - */ - map(position) { - var rect = this._videoElem.getBoundingClientRect(); - const _position = new Array(2); - - // (1) set origin point to zero - _position[0] = position[0] - rect.left; - _position[1] = position[1] - rect.top; - - // (2) translate Unity coordinate system (reverse y-axis) - _position[1] = rect.height - _position[1]; - - // (3) add offset of letterbox - _position[0] -= this._contentRect.x; - _position[1] -= this._contentRect.y; - - // (4) mapping element rectangle to video rectangle - _position[0] = _position[0] / this._contentRect.width * this._videoWidth; - _position[1] = _position[1] / this._contentRect.height * this._videoHeight; - - return _position; - } - - /** - * @param {Number} videoWidth - */ - setVideoWidth(videoWidth) { - this._videoWidth = videoWidth; - this._reset(); - } - - /** - * @param {Number} videoHeight - */ - setVideoHeight(videoHeight) { - this._videoHeight = videoHeight; - this._reset(); - } - - /** - * @param {HTMLVideoElement} videoElem - */ - setRect(videoElem) { - this._videoElem = videoElem; - this._reset(); - } - - /** - * @param {Number} videoWidth - * @param {Number} videoHeight - * @param {HTMLVideoElement} videoElem - */ - reset(videoWidth, videoHeight, videoElem) { - this._videoWidth = videoWidth; - this._videoHeight = videoHeight; - this._videoElem = videoElem; - this._reset(); - } - - get letterBoxType() { - const videoRatio = this._videoHeight / this._videoWidth; - var rect = this._videoElem.getBoundingClientRect(); - const rectRatio = rect.height / rect.width; - return videoRatio > rectRatio ? LetterBoxType.Vertical : LetterBoxType.Horizontal; - } - - get letterBoxSize() { - var rect = this._videoElem.getBoundingClientRect(); - switch(this.letterBoxType) { - case LetterBoxType.Horizontal: { - const ratioWidth = rect.width / this._videoWidth; - const height = this._videoHeight * ratioWidth; - return (rect.height - height) * 0.5; - } - case LetterBoxType.Vertical: { - const ratioHeight = rect.height / this._videoHeight; - const width = this._videoWidth * ratioHeight; - return (rect.width - width) * 0.5; - } - } - throw 'invalid status'; - } - - /** - * Returns rectangle for displaying video with the origin at the left-top of the element. - * Not considered applying CSS like `object-fit`. - * @returns {Object} - */ - get contentRect() { - const letterBoxType = this.letterBoxType; - const letterBoxSize = this.letterBoxSize; - - var rect = this._videoElem.getBoundingClientRect(); - - const x = letterBoxType == LetterBoxType.Vertical ? letterBoxSize : 0; - const y = letterBoxType == LetterBoxType.Horizontal ? letterBoxSize : 0; - const width = letterBoxType == LetterBoxType.Vertical ? rect.width - letterBoxSize * 2 : rect.width; - const height = letterBoxType == LetterBoxType.Horizontal ? rect.height - letterBoxSize * 2 : rect.height; - - return {x: x, y: y, width: width, height: height}; - } - - _reset() { - this._contentRect = this.contentRect; - } -} diff --git a/WebApp/client/src/renderstreaming.js b/WebApp/client/src/renderstreaming.js deleted file mode 100644 index 52cbef1..0000000 --- a/WebApp/client/src/renderstreaming.js +++ /dev/null @@ -1,317 +0,0 @@ -import Peer from "./peer.js"; -import * as Logger from "./logger.js"; - -function uuid4() { - var temp_url = URL.createObjectURL(new Blob()); - var uuid = temp_url.toString(); - URL.revokeObjectURL(temp_url); - return uuid.split(/[:/]/g).pop().toLowerCase(); -} - -export class RenderStreaming { - constructor(signaling, config) { - this._peer = null; // participant端:单一peer - this._peers = new Map(); // host端:多peer Map (participantId → Peer) - this._connectionId = null; - this._participantId = null; // 自己的participantId - this._isHost = false; - this.onConnect = function (connectionId, data) { Logger.log(`Connect peer on ${connectionId}.`); }; - this.onDisconnect = function (connectionId) { Logger.log(`Disconnect peer on ${connectionId}.`); }; - this.onGotOffer = function (connectionId) { Logger.log(`On got Offer on ${connectionId}.`); }; - this.onGotAnswer = function (connectionId) { Logger.log(`On got Answer on ${connectionId}.`); }; - this.onTrackEvent = function (data) { Logger.log(`OnTrack event peer with data:${data}`); }; - this.onAddChannel = function (data) { Logger.log(`onAddChannel event peer with data:${data}`); }; - this.onMessage = function (data) { Logger.log(`On message: ${data}`); }; - this.onParticipantLeft = function (participantId) { Logger.log(`Participant left: ${participantId}.`); }; - this.onParticipantJoined = function (participantId) { Logger.log(`Participant joined: ${participantId}.`); }; - this.onNewPeer = function (participantId) { Logger.log(`New peer created for ${participantId}.`); }; - this._config = config; - this._signaling = signaling; - this._signaling.addEventListener('connect', this._onConnect.bind(this)); - this._signaling.addEventListener('disconnect', this._onDisconnect.bind(this)); - this._signaling.addEventListener('offer', this._onOffer.bind(this)); - this._signaling.addEventListener('answer', this._onAnswer.bind(this)); - this._signaling.addEventListener('candidate', this._onIceCandidate.bind(this)); - this._signaling.addEventListener('on-message', this._onMessage.bind(this)); - this._signaling.addEventListener('participant-left', this._onParticipantLeft.bind(this)); - this._signaling.addEventListener('participant-joined', this._onParticipantJoined.bind(this)); - } - - async _onConnect(e) { - const data = e.detail; - if (this._connectionId == data.connectionId) { - this._participantId = data.participantId; - this._isHost = data.role === 'host'; - - if (!this._isHost) { - // participant端:立即创建单一peer并开始协商 - this._preparePeerConnection(this._connectionId, data.polite, null); - } - // host端:不在connect时创建peer,等participant加入后再创建 - - this.onConnect(data.connectionId, data); - } - } - - async _onDisconnect(e) { - const data = e.detail; - if (this._connectionId == data.connectionId) { - this.onDisconnect(data.connectionId); - if (this._peer) { - this._peer.close(); - this._peer = null; - } - // 关闭所有host端peers - this._peers.forEach((peer, participantId) => { - peer.close(); - }); - this._peers.clear(); - } - } - - async _onOffer(e) { - const offer = e.detail; - const participantId = offer.participantId; - - if (this._isHost) { - // host端:为该participant创建或复用peer - let peer = this._peers.get(participantId); - if (!peer || (peer.pc && peer.pc.iceConnectionState === 'disconnected')) { - if (peer) peer.close(); - peer = this._preparePeerConnection(this._connectionId, offer.polite, participantId); - } - const desc = new RTCSessionDescription({ sdp: offer.sdp, type: "offer" }); - try { - await peer.onGotDescription(this._connectionId, desc); - } catch (error) { - Logger.warn(`Error on GotDescription for participant ${participantId}: ${error}`); - } - } else { - // participant端:使用单一peer - if (this._peer && this._peer.pc && this._peer.pc.iceConnectionState === 'disconnected') { - this._peer.close(); - this._peer = null; - } - if (!this._peer) { - this._preparePeerConnection(offer.connectionId, offer.polite, null); - } - const desc = new RTCSessionDescription({ sdp: offer.sdp, type: "offer" }); - try { - await this._peer.onGotDescription(offer.connectionId, desc); - } catch (error) { - Logger.warn(`Error on GotDescription: ${error}`); - } - } - } - - async _onAnswer(e) { - const answer = e.detail; - const participantId = answer.participantId; - const desc = new RTCSessionDescription({ sdp: answer.sdp, type: "answer" }); - - if (this._isHost && participantId) { - // host端:路由到对应participant的peer - const peer = this._peers.get(participantId); - if (peer) { - try { - await peer.onGotDescription(this._connectionId, desc); - } catch (error) { - Logger.warn(`Error on GotDescription answer for ${participantId}: ${error}`); - } - } - } else if (this._peer) { - // participant端 - try { - await this._peer.onGotDescription(answer.connectionId, desc); - } catch (error) { - Logger.warn(`Error on GotDescription answer: ${error}`); - } - } - } - - async _onIceCandidate(e) { - const candidate = e.detail; - const participantId = candidate.participantId; - const iceCandidate = new RTCIceCandidate({ candidate: candidate.candidate, sdpMid: candidate.sdpMid, sdpMLineIndex: candidate.sdpMLineIndex }); - - if (this._isHost && participantId) { - // host端:路由到对应participant的peer - const peer = this._peers.get(participantId); - if (peer) { - await peer.onGotCandidate(this._connectionId, iceCandidate); - } - } else if (this._peer) { - // participant端 - await this._peer.onGotCandidate(candidate.connectionId, iceCandidate); - } - } - - async _onMessage(e) { - const data = e.detail; - this.onMessage(data); - } - - async _onParticipantLeft(e) { - const data = e.detail; - const participantId = data.participantId; - Logger.log(`Participant left: ${participantId}`); - - // 关闭该participant的peer - if (this._peers.has(participantId)) { - const peer = this._peers.get(participantId); - peer.close(); - this._peers.delete(participantId); - } - - this.onParticipantLeft(participantId); - } - - async _onParticipantJoined(e) { - const data = e.detail; - const participantId = data.participantId; - Logger.log(`Participant joined: ${participantId}`); - - // host端:为新participant创建peer - if (this._isHost && !this._peers.has(participantId)) { - this._preparePeerConnection(this._connectionId, false, participantId); - } - - this.onParticipantJoined(participantId); - } - - async createConnection(connectionId) { - this._connectionId = connectionId ? connectionId : uuid4(); - await this._signaling.createConnection(this._connectionId); - } - - async deleteConnection() { - await this._signaling.deleteConnection(this._connectionId); - } - - _preparePeerConnection(connectionId, polite, participantId) { - // host端多peer模式:participantId标识目标participant - // participant端单peer模式:participantId为null - - const peer = new Peer(connectionId, polite, this._config); - - // 保存peer - if (participantId) { - if (this._peers.has(participantId)) { - const oldPeer = this._peers.get(participantId); - oldPeer.close(); - } - this._peers.set(participantId, peer); - } else { - if (this._peer) { - this._peer.close(); - } - this._peer = peer; - } - - // 事件处理:附加participantId用于路由 - peer.addEventListener('trackevent', (e) => { - const data = e.detail; - data.participantId = participantId; - this.onTrackEvent(data); - }); - - peer.addEventListener('adddatachannel', (e) => { - const data = e.detail; - this.onAddChannel(data); - }); - - peer.addEventListener('ongotoffer', (e) => { - const id = e.detail.connectionId; - this.onGotOffer(id); - }); - - peer.addEventListener('ongotanswer', (e) => { - const id = e.detail.connectionId; - this.onGotAnswer(id); - }); - - peer.addEventListener('sendoffer', (e) => { - const offer = e.detail; - this._signaling.sendOffer(offer.connectionId, offer.sdp, participantId); - }); - - peer.addEventListener('sendanswer', (e) => { - const answer = e.detail; - this._signaling.sendAnswer(answer.connectionId, answer.sdp, participantId); - }); - - peer.addEventListener('sendcandidate', (e) => { - const candidate = e.detail; - this._signaling.sendCandidate(candidate.connectionId, candidate.candidate, candidate.sdpMid, candidate.sdpMLineIndex, participantId); - }); - - this.onNewPeer(participantId || connectionId); - return peer; - } - - async getStats(participantId) { - if (this._isHost && participantId) { - const peer = this._peers.get(participantId); - return peer ? await peer.getStats(this._connectionId) : null; - } - return this._peer ? await this._peer.getStats(this._connectionId) : null; - } - - createDataChannel(label, participantId) { - if (this._isHost && participantId) { - const peer = this._peers.get(participantId); - return peer ? peer.createDataChannel(this._connectionId, label) : null; - } - return this._peer ? this._peer.createDataChannel(this._connectionId, label) : null; - } - - addTrack(track, participantId) { - if (this._isHost && participantId) { - const peer = this._peers.get(participantId); - return peer ? peer.addTrack(this._connectionId, track) : null; - } - return this._peer ? this._peer.addTrack(this._connectionId, track) : null; - } - - addTransceiver(trackOrKind, init, participantId) { - if (this._isHost && participantId) { - const peer = this._peers.get(participantId); - return peer ? peer.addTransceiver(this._connectionId, trackOrKind, init) : null; - } - return this._peer ? this._peer.addTransceiver(this._connectionId, trackOrKind, init) : null; - } - - getTransceivers(participantId) { - if (this._isHost && participantId) { - const peer = this._peers.get(participantId); - return peer ? peer.getTransceivers(this._connectionId) : null; - } - return this._peer ? this._peer.getTransceivers(this._connectionId) : null; - } - - sendMessage(message) { - if (this._signaling && this._connectionId) { - this._signaling.sendMessage(this._connectionId, message); - } - } - - async start() { - await this._signaling.start(); - } - - async stop() { - if (this._peer) { - this._peer.close(); - this._peer = null; - } - this._peers.forEach((peer) => { - peer.close(); - }); - this._peers.clear(); - - if (this._signaling) { - await this._signaling.stop(); - this._signaling = null; - } - } -} \ No newline at end of file diff --git a/WebApp/client/src/sender.js b/WebApp/client/src/sender.js deleted file mode 100644 index f5fb66d..0000000 --- a/WebApp/client/src/sender.js +++ /dev/null @@ -1,208 +0,0 @@ -import { - Mouse, - Keyboard, - Gamepad, - Touchscreen, - StateEvent, - TextEvent -} from "./inputdevice.js"; - -import { LocalInputManager } from "./inputremoting.js"; -import { GamepadHandler } from "./gamepadhandler.js"; -import { PointerCorrector } from "./pointercorrect.js"; - -export class Sender extends LocalInputManager { - constructor(elem) { - super(); - this._devices = []; - this._elem = elem; - this._corrector = new PointerCorrector( - this._elem.videoWidth, - this._elem.videoHeight, - this._elem - ); - - //since line 27 cannot complete resize initialization but can only monitor div dimension changes, line 26 needs to be reserved - this._elem.addEventListener('resize', this._onResizeEvent.bind(this), false); - const observer = new ResizeObserver(this._onResizeEvent.bind(this)); - observer.observe(this._elem); - } - - addMouse() { - const descriptionMouse = { - m_InterfaceName: "RawInput", - m_DeviceClass: "Mouse", - m_Manufacturer: "", - m_Product: "", - m_Serial: "", - m_Version: "", - m_Capabilities: "" - }; - this.mouse = new Mouse("Mouse", "Mouse", 1, null, descriptionMouse); - this._devices.push(this.mouse); - - this._elem.addEventListener('click', this._onMouseEvent.bind(this), false); - this._elem.addEventListener('mousedown', this._onMouseEvent.bind(this), false); - this._elem.addEventListener('mouseup', this._onMouseEvent.bind(this), false); - this._elem.addEventListener('mousemove', this._onMouseEvent.bind(this), false); - this._elem.addEventListener('wheel', this._onWheelEvent.bind(this), false); - } - - addKeyboard() { - const descriptionKeyboard = { - m_InterfaceName: "RawInput", - m_DeviceClass: "Keyboard", - m_Manufacturer: "", - m_Product: "", - m_Serial: "", - m_Version: "", - m_Capabilities: "" - }; - this.keyboard = new Keyboard("Keyboard", "Keyboard", 2, null, descriptionKeyboard); - this._devices.push(this.keyboard); - - document.addEventListener('keyup', this._onKeyEvent.bind(this), false); - document.addEventListener('keydown', this._onKeyEvent.bind(this), false); - } - - addGamepad() { - const descriptionGamepad = { - m_InterfaceName: "RawInput", - m_DeviceClass: "Gamepad", - m_Manufacturer: "", - m_Product: "", - m_Serial: "", - m_Version: "", - m_Capabilities: "" - }; - this.gamepad = new Gamepad("Gamepad", "Gamepad", 3, null, descriptionGamepad); - this._devices.push(this.gamepad); - - window.addEventListener("gamepadconnected", this._onGamepadEvent.bind(this), false); - window.addEventListener("gamepaddisconnected", this._onGamepadEvent.bind(this), false); - this._gamepadHandler = new GamepadHandler(); - this._gamepadHandler.addEventListener("gamepadupdated", this._onGamepadEvent.bind(this), false); - } - - addTouchscreen() { - const descriptionTouch = { - m_InterfaceName: "RawInput", - m_DeviceClass: "Touch", - m_Manufacturer: "", - m_Product: "", - m_Serial: "", - m_Version: "", - m_Capabilities: "" - }; - this.touchscreen = new Touchscreen("Touchscreen", "Touchscreen", 4, null, descriptionTouch); - this._devices.push(this.touchscreen); - - this._elem.addEventListener('touchend', this._onTouchEvent.bind(this), false); - this._elem.addEventListener('touchstart', this._onTouchEvent.bind(this), false); - this._elem.addEventListener('touchcancel', this._onTouchEvent.bind(this), false); - this._elem.addEventListener('touchmove', this._onTouchEvent.bind(this), false); - this._elem.addEventListener('click', this._onTouchEvent.bind(this), false); - } - - /** - * @returns {InputDevice[]} - */ - get devices() { - return this._devices; - } - - _onResizeEvent() { - this._corrector.reset( - this._elem.videoWidth, - this._elem.videoHeight, - this._elem - ); - } - _onMouseEvent(event) { - this.mouse.queueEvent(event); - this.mouse.currentState.position = this._corrector.map(this.mouse.currentState.position); - this._queueStateEvent(this.mouse.currentState, this.mouse); - } - _onWheelEvent(event) { - this.mouse.queueEvent(event); - this._queueStateEvent(this.mouse.currentState, this.mouse); - } - _onKeyEvent(event) { - if(event.type == 'keydown') { - if(!event.repeat) { // StateEvent - this.keyboard.queueEvent(event); - this._queueStateEvent(this.keyboard.currentState, this.keyboard); - } - // TextEvent - this._queueTextEvent(this.keyboard, event); - } - else if(event.type == 'keyup') { - this.keyboard.queueEvent(event); - this._queueStateEvent(this.keyboard.currentState, this.keyboard); - } - } - _onTouchEvent(event) { - this.touchscreen.queueEvent(event, this.timeSinceStartup); - for(let touch of this.touchscreen.currentState.touchData) { - let clone = touch.copy(); - clone.position = this._corrector.map(clone.position); - this._queueStateEvent(clone, this.touchscreen); - } - } - _onGamepadEvent(event) { - switch(event.type) { - case 'gamepadconnected': { - this._gamepadHandler.addGamepad(event.gamepad); - break; - } - case 'gamepaddisconnected': { - this._gamepadHandler.removeGamepad(event.gamepad); - break; - } - case 'gamepadupdated': { - this.gamepad.queueEvent(event); - this._queueStateEvent(this.gamepad.currentState, this.gamepad); - break; - } - } - } - - _queueStateEvent(state, device) { - const stateEvent = - StateEvent.fromState(state, device.deviceId, this.timeSinceStartup); - const e = new CustomEvent( - 'event', {detail: { event: stateEvent, device: device}}); - super.onEvent.dispatchEvent(e); - } - _queueTextEvent(device, event) { - const textEvent = TextEvent.create(device.deviceId, event, this.timeSinceStartup); - const e = new CustomEvent( - 'event', {detail: { event: textEvent, device: device}}); - super.onEvent.dispatchEvent(e); - } - _queueDeviceChange(device, usage) { - const e = new CustomEvent( - 'changedeviceusage', {detail: { device: device, usage: usage }}); - super.onEvent.dispatchEvent(e); - } -} - -export class Observer { - /** - * - * @param {RTCDataChannel} channel - */ - constructor(channel) { - this.channel = channel; - } - /** - * - * @param {Message} message - */ - onNext(message) { - if(this.channel == null || this.channel.readyState != 'open') { - return; - } - this.channel.send(message.buffer); - } -} diff --git a/WebApp/client/src/signaling.js b/WebApp/client/src/signaling.js deleted file mode 100644 index f989113..0000000 --- a/WebApp/client/src/signaling.js +++ /dev/null @@ -1,276 +0,0 @@ -import * as Logger from "./logger.js"; - -export class Signaling extends EventTarget { - - constructor(interval = 1000) { - super(); - this.running = false; - this.interval = interval; - this.sleep = msec => new Promise(resolve => setTimeout(resolve, msec)); - } - - headers() { - if (this.sessionId !== undefined) { - return { 'Content-Type': 'application/json', 'Session-Id': this.sessionId }; - } - else { - return { 'Content-Type': 'application/json' }; - } - } - - url(method, parameter = '') { - let ret = location.origin + '/signaling'; - if (method) - ret += '/' + method; - if (parameter) - ret += '?' + parameter; - return ret; - } - - async start() { - if (this.running) { - return; - } - - this.running = true; - while (!this.sessionId) { - const createResponse = await fetch(this.url(''), { method: 'PUT', headers: this.headers() }); - const session = await createResponse.json(); - this.sessionId = session.sessionId; - - if (!this.sessionId) { - await this.sleep(this.interval); - } - } - - this.loopGetAll(); - } - - async loopGetAll() { - let lastTimeRequest = Date.now() - 30000; - while (this.running) { - const res = await this.getAll(lastTimeRequest); - const data = await res.json(); - lastTimeRequest = data.datetime ? data.datetime : Date.now(); - - const messages = data.messages; - - for (const msg of messages) { - switch (msg.type) { - case "connect": - break; - case "disconnect": - this.dispatchEvent(new CustomEvent('disconnect', { detail: msg })); - break; - case "offer": - this.dispatchEvent(new CustomEvent('offer', { detail: msg })); - break; - case "answer": - this.dispatchEvent(new CustomEvent('answer', { detail: msg })); - break; - case "candidate": - this.dispatchEvent(new CustomEvent('candidate', { detail: msg })); - break; - case "on-message": - this.dispatchEvent(new CustomEvent('on-message', { detail: msg.data })); - break; - default: - break; - } - } - await this.sleep(this.interval); - } - } - - async stop() { - this.running = false; - await fetch(this.url(''), { method: 'DELETE', headers: this.headers() }); - this.sessionId = null; - } - - async createConnection(connectionId) { - const data = { 'connectionId': connectionId }; - const res = await fetch(this.url('connection'), { method: 'PUT', headers: this.headers(), body: JSON.stringify(data) }); - const json = await res.json(); - Logger.log(`Signaling: HTTP create connection, connectionId: ${json.connectionId}, polite:${json.polite}`); - - this.dispatchEvent(new CustomEvent('connect', { detail: json })); - return json; - } - - async deleteConnection(connectionId) { - const data = { 'connectionId': connectionId }; - const res = await fetch(this.url('connection'), { method: 'DELETE', headers: this.headers(), body: JSON.stringify(data) }); - const json = await res.json(); - this.dispatchEvent(new CustomEvent('disconnect', { detail: json })); - return json; - } - - async sendOffer(connectionId, sdp) { - const data = { 'sdp': sdp, 'connectionId': connectionId }; - Logger.log('sendOffer:' + data); - await fetch(this.url('offer'), { method: 'POST', headers: this.headers(), body: JSON.stringify(data) }); - } - - async sendAnswer(connectionId, sdp) { - const data = { 'sdp': sdp, 'connectionId': connectionId }; - Logger.log('sendAnswer:' + data); - await fetch(this.url('answer'), { method: 'POST', headers: this.headers(), body: JSON.stringify(data) }); - } - - async sendCandidate(connectionId, candidate, sdpMid, sdpMLineIndex) { - const data = { - 'candidate': candidate, - 'sdpMLineIndex': sdpMLineIndex, - 'sdpMid': sdpMid, - 'connectionId': connectionId - }; - Logger.log('sendCandidate:' + data); - await fetch(this.url('candidate'), { method: 'POST', headers: this.headers(), body: JSON.stringify(data) }); - } - // 在 Signaling 类中添加 - async sendMessage(connectionId, message) { - const data = { - 'message': message, - 'connectionId': connectionId - }; - await fetch(this.url('on-message'), { method: 'POST', headers: this.headers(), body: JSON.stringify(data) }); - } - async getAll(fromTime = 0) { - return await fetch(this.url(``, `fromtime=${fromTime}`), { method: 'GET', headers: this.headers() }); - } -} - -export class WebSocketSignaling extends EventTarget { - - constructor(interval = 1000) { - super(); - this.interval = interval; - this.sleep = msec => new Promise(resolve => setTimeout(resolve, msec)); - - let websocketUrl; - if (location.protocol === "https:") { - websocketUrl = "wss://" + location.host; - } else { - websocketUrl = "ws://" + location.host; - } - - this.websocket = new WebSocket(websocketUrl); - this.connectionId = null; - - this.websocket.onopen = () => { - this.isWsOpen = true; - }; - - this.websocket.onclose = () => { - this.isWsOpen = false; - }; - - this.websocket.onmessage = (event) => { - const msg = JSON.parse(event.data); - if (!msg || !this) { - return; - } - - Logger.log(msg); - - switch (msg.type) { - case "connect": - this.dispatchEvent(new CustomEvent('connect', { detail: msg })); - break; - case "disconnect": - this.dispatchEvent(new CustomEvent('disconnect', { detail: msg })); - break; - case "offer": - this.dispatchEvent(new CustomEvent('offer', { detail: { connectionId: msg.from, sdp: msg.data.sdp, polite: msg.data.polite, participantId: msg.participantId } })); - break; - case "answer": - this.dispatchEvent(new CustomEvent('answer', { detail: { connectionId: msg.from, sdp: msg.data.sdp, participantId: msg.participantId } })); - break; - case "candidate": - this.dispatchEvent(new CustomEvent('candidate', { detail: { connectionId: msg.from, candidate: msg.data.candidate, sdpMLineIndex: msg.data.sdpMLineIndex, sdpMid: msg.data.sdpMid, participantId: msg.participantId } })); - break; - case "on-message": - // 将participantId附加到消息数据中,以便Host识别消息发送者 - if (msg.participantId) { - msg.data.participantId = msg.participantId; - } - this.dispatchEvent(new CustomEvent('on-message', { detail: msg.data })); - break; - case "participant-left": - this.dispatchEvent(new CustomEvent('participant-left', { detail: msg })); - break; - case "participant-joined": - this.dispatchEvent(new CustomEvent('participant-joined', { detail: msg })); - break; - case "broadcast": - this.dispatchEvent(new CustomEvent('on-message', { detail: msg.message })); - break; - default: - break; - } - }; - } - - async start() { - while (!this.isWsOpen) { - await this.sleep(100); - } - } - - async stop() { - this.websocket.close(); - while (this.isWsOpen) { - await this.sleep(100); - } - } - - createConnection(connectionId) { - const sendJson = JSON.stringify({ type: "connect", connectionId: connectionId }); - Logger.log(sendJson); - this.websocket.send(sendJson); - } - - deleteConnection(connectionId) { - const sendJson = JSON.stringify({ type: "disconnect", connectionId: connectionId }); - Logger.log(sendJson); - this.websocket.send(sendJson); - } - - sendOffer(connectionId, sdp, participantId) { - const data = { 'sdp': sdp, 'connectionId': connectionId }; - const sendJson = JSON.stringify({ type: "offer", from: connectionId, data: data, participantId: participantId || '' }); - Logger.log(sendJson); - this.websocket.send(sendJson); - } - - sendAnswer(connectionId, sdp, participantId) { - const data = { 'sdp': sdp, 'connectionId': connectionId }; - const sendJson = JSON.stringify({ type: "answer", from: connectionId, data: data, participantId: participantId || '' }); - Logger.log(sendJson); - this.websocket.send(sendJson); - } - - sendCandidate(connectionId, candidate, sdpMLineIndex, sdpMid, participantId) { - const data = { - 'candidate': candidate, - 'sdpMLineIndex': sdpMLineIndex, - 'sdpMid': sdpMid, - 'connectionId': connectionId - }; - const sendJson = JSON.stringify({ type: "candidate", from: connectionId, data: data, participantId: participantId || '' }); - Logger.log(sendJson); - this.websocket.send(sendJson); - } - // 在 WebSocketSignaling 类中添加 - sendMessage(connectionId, message) { - const data = { - 'message': message, - 'senderId': message.senderId, - 'connectionId': connectionId - }; - const sendJson = JSON.stringify({ type: "on-message", data: data }); - Logger.log(sendJson); - this.websocket.send(sendJson); - } -} diff --git a/WebApp/client/src/touchflags.js b/WebApp/client/src/touchflags.js deleted file mode 100644 index 154ea64..0000000 --- a/WebApp/client/src/touchflags.js +++ /dev/null @@ -1,7 +0,0 @@ -export const TouchFlags = -{ - IndirectTouch: 1 << 0, - PrimaryTouch: 1 << 4, - Tap: 1 << 5, - OrphanedPrimaryTouch: 1 << 6, -}; diff --git a/WebApp/client/src/touchphase.js b/WebApp/client/src/touchphase.js deleted file mode 100644 index e461dcd..0000000 --- a/WebApp/client/src/touchphase.js +++ /dev/null @@ -1,8 +0,0 @@ -export const TouchPhase = { - None: 0, - Began: 1, - Moved: 2, - Ended: 3, - Canceled: 4, - Stationary: 5 - }; diff --git a/WebApp/client/test/domrect.js b/WebApp/client/test/domrect.js deleted file mode 100644 index 2b78492..0000000 --- a/WebApp/client/test/domrect.js +++ /dev/null @@ -1,16 +0,0 @@ -// mock class - -export class DOMRect { - constructor(x, y, width, height) { - this.x = x; - this.y = y; - this.width = width; - this.height = height; - } - get left() { - return this.x; - } - get top() { - return this.y; - } -} \ No newline at end of file diff --git a/WebApp/client/test/domvideoelement.js b/WebApp/client/test/domvideoelement.js deleted file mode 100644 index 858f7d7..0000000 --- a/WebApp/client/test/domvideoelement.js +++ /dev/null @@ -1,11 +0,0 @@ -// mock class - -export class DOMHTMLVideoElement { - constructor(rect) { - this.rect = rect; - } - - getBoundingClientRect() { - return this.rect; - } -} diff --git a/WebApp/client/test/inputdevice.test.js b/WebApp/client/test/inputdevice.test.js deleted file mode 100644 index 5d39ab0..0000000 --- a/WebApp/client/test/inputdevice.test.js +++ /dev/null @@ -1,172 +0,0 @@ -import { - FourCC, - Mouse, - Keyboard, - Touchscreen, - Gamepad, - KeyboardState, - MouseState, - TouchscreenState, - GamepadState, - StateEvent, - InputEvent, - TextEvent - } from "../src/inputdevice.js"; - -describe(`FourCC`, () => { - test('toInt32', () => { - const number = new FourCC('A', 'A', 'A', 'A').toInt32(); - expect(number).toBe(0x41414141); - }); -}); - -describe(`MouseState`, () => { - describe(`with MouseEvent`, () => { - let event; - beforeEach(() => { - event = new MouseEvent('click', { buttons:1, clientX:0, clientY:0}); - }); - test('format', () => { - const format = new MouseState(event).format; - expect(format).toBe(0x4d4f5553); - }); - test('buffer', () => { - const state = new MouseState(event); - expect(state.buffer.byteLength).toBeGreaterThan(0); - }); - }); - describe(`with WheelEvent`, () => { - let event; - beforeEach(() => { - event = new WheelEvent('wheel', { deltaX:0, deltaY:0 }); - }); - test('format', () => { - const format = new MouseState(event).format; - expect(format).toBe(0x4d4f5553); - }); - test('buffer', () => { - const state = new MouseState(event); - expect(state.buffer.byteLength).toBeGreaterThan(0); - }); - }); -}); - -describe(`KeyboardState`, () => { - let event; - beforeEach(() => { - event = new KeyboardEvent('keydown', { code: 'KeyA' }); - }); - test('format', () => { - const format = new KeyboardState(event).format; - expect(format).toBe(0x4b455953); - }); - test('buffer', () => { - const state = new KeyboardState(event); - expect(state.buffer.byteLength).toBeGreaterThan(0); - }); -}); - -describe(`TouchscreenState`, () => { - let event; - beforeEach(() => { - event = new TouchEvent("touchstart", { - changedTouches: [{ // InputInit - identifier: 0, - target: null, - clientX: 0, - clientY: 0, - screenX: 0, - screenY: 0, - pageX: 0, - pageY: 0, - radiusX: 0, - radiusY: 0, - rotationAngle: 0, - force: 0, - altitudeAngle: 0, - azimuthAngle:0, - touchType: "direct" - }] - }); - }); - test('format', () => { - const format = new TouchscreenState(event, null, Date.now()).format; - expect(format).toBe(0x54534352); - }); - test('buffer', () => { - const state = new TouchscreenState(event, null, Date.now()); - expect(state.buffer.byteLength).toBeGreaterThan(0); - }); -}); - -describe(`GamepadState`, () => { - let event; - beforeEach(() => { - event = { - type: 'gamepadupdated', - gamepad : { - id: 1, - buttons: Array(16).fill({ pressed: false, value: 1 }), - axes:[0, 0, 0, 0] - }}; - }); - test('format', () => { - const format = new GamepadState(event).format; - expect(format).toBe(0x47504144); - }); - test('buffer', () => { - const state = new GamepadState(event); - expect(state.buffer.byteLength).toBeGreaterThan(0); - }); -}); - -describe(`StateEvent`, () => { - let state; - beforeEach(() => { - const event = new KeyboardEvent('keydown', { code: 'KeyA' }); - state = new KeyboardState(event); - }); - test('buffer', () => { - const stateEvent = StateEvent.fromState(state, 0, Date.now()); - expect(new Int32Array(stateEvent.buffer.slice(0, 4))[0]).toBe(StateEvent.format); - }); -}); - -describe(`TextEvent`, () => { - test('buffer', () => { - const event = new KeyboardEvent('keydown', { code: 'KeyA', key: "a"}); - const textEvent = TextEvent.create(0, event, Date.now()); - expect(new Int32Array(textEvent.buffer.slice(0, 4))[0]).toBe(TextEvent.format); - const offset = InputEvent.size; - // 'a' is 97 - expect(new Uint32Array(textEvent.buffer.slice(offset, offset+4))[0]).toBe(97); - }); -}); - -describe(`Mouse`, () => { - test('alignedSizeInBytes', () => { - let device = new Mouse("Mouse", "Mouse", 1, null, null); - expect(device).toBeInstanceOf(Mouse); - }); -}); - -describe(`Keyboard`, () => { - test('alignedSizeInBytes', () => { - let device = new Keyboard("Keyboard", "Keyboard", 1, null, null); - expect(device).toBeInstanceOf(Keyboard); - }); -}); - -describe(`Touchscreen`, () => { - test('alignedSizeInBytes', () => { - let device = new Touchscreen("Touchscreen", "Touchscreen", 1, null, null); - expect(device).toBeInstanceOf(Touchscreen); - }); -}); - -describe(`Gamepad`, () => { - test('alignedSizeInBytes', () => { - let device = new Gamepad("Gamepad", "Gamepad", 1, null, null); - expect(device).toBeInstanceOf(Gamepad); - }); -}); diff --git a/WebApp/client/test/inputremoting.test.js b/WebApp/client/test/inputremoting.test.js deleted file mode 100644 index abcee80..0000000 --- a/WebApp/client/test/inputremoting.test.js +++ /dev/null @@ -1,132 +0,0 @@ -import { - InputDevice, - MouseState, - KeyboardState, - TouchscreenState, - GamepadState -} from "../src/inputdevice.js"; - -import { - MessageType, - NewDeviceMsg, - NewEventsMsg, - RemoveDeviceMsg, - InputRemoting, -} from "../src/inputremoting.js"; - -import { - Sender, - Observer -} from "../src/sender.js"; - -import {DOMRect} from "./domrect.js"; - -describe(`InputRemoting`, () => { - let sender = null; - let inputRemoting = null; - let observer = null; - beforeEach(async () => { - document.getBoundingClientRect = function(){ return new DOMRect(0,0,0,0); }; - sender = new Sender(document); - inputRemoting = new InputRemoting(sender); - let dc = null; - observer = new Observer(dc); - }); - test('startSending', () => { - expect.assertions(0); - inputRemoting.startSending(); - }); - test('stopSending', () => { - expect.assertions(0); - inputRemoting.startSending(); - inputRemoting.stopSending(); - }); - test('subscribe', () => { - expect.assertions(0); - inputRemoting.subscribe(observer); - }); -}); - -test('create NewDeviceMsg', () => { - const device = new InputDevice("Keyboard", "Keyboard", 0, null, null); - const msg = NewDeviceMsg.create(device); - expect(msg.participant_id).toBe(0); - expect(msg.type).toBe(MessageType.NewDevice); - expect(msg.data).toBeInstanceOf(ArrayBuffer); - expect(msg.data.byteLength).toBeGreaterThan(0); -}); - -describe('create NewEventMsg', () => { - test('using MouseState', () => { - const event = new MouseEvent('click', { buttons:0, clientX:0, clientY:0} ); - const state = new MouseState(event); - const msg = NewEventsMsg.create(state); - expect(msg.participant_id).toBe(0); - expect(msg.type).toBe(MessageType.NewEvents); - expect(msg.data).toBeInstanceOf(ArrayBuffer); - expect(msg.data.byteLength).toBeGreaterThan(0); - }); - test('using KeyboardState', () => { - const event = new KeyboardEvent("keydown", { code: 'KeyA' }); - const state = new KeyboardState(event); - const msg = NewEventsMsg.create(state); - expect(msg.participant_id).toBe(0); - expect(msg.type).toBe(MessageType.NewEvents); - expect(msg.data).toBeInstanceOf(ArrayBuffer); - expect(msg.data.byteLength).toBeGreaterThan(0); - }); - test('using TouchscreenState', () => { - const event = new TouchEvent("touchstart", { - changedTouches: [{ // InputInit - identifier: 0, - target: null, - clientX: 0, - clientY: 0, - screenX: 0, - screenY: 0, - pageX: 0, - pageY: 0, - radiusX: 0, - radiusY: 0, - rotationAngle: 0, - force: 0, - altitudeAngle: 0, - azimuthAngle:0, - touchType: "direct" - }] - }); - const state = new TouchscreenState(event, null, Date.now()); - expect(state.touchData).not.toBeNull(); - expect(state.touchData).toHaveLength(1); - const msg = NewEventsMsg.create(state.touchData[0]); - expect(msg.participant_id).toBe(0); - expect(msg.type).toBe(MessageType.NewEvents); - expect(msg.data).toBeInstanceOf(ArrayBuffer); - expect(msg.data.byteLength).toBeGreaterThan(0); - }); - test('using GamepadState', () => { - const event = { - type: 'gamepadupdated', - gamepad : { - id: 1, - buttons: Array(16).fill({ pressed: false, value: 1 }), - axes:[1, 1, 1, 1] - }}; - const state = new GamepadState(event); - const msg = NewEventsMsg.create(state); - expect(msg.participant_id).toBe(0); - expect(msg.type).toBe(MessageType.NewEvents); - expect(msg.data).toBeInstanceOf(ArrayBuffer); - expect(msg.data.byteLength).toBeGreaterThan(0); - }); -}); - -test('create RemoveDeviceMsg', () => { - const device = new InputDevice("Keyboard", "Keyboard", 0, null, null); - const msg = RemoveDeviceMsg.create(device); - expect(msg.participant_id).toBe(0); - expect(msg.type).toBe(MessageType.RemoveDevice); - expect(msg.data).toBeInstanceOf(ArrayBuffer); - expect(msg.data.byteLength).toBeGreaterThan(0); -}); - \ No newline at end of file diff --git a/WebApp/client/test/memoryhelper.test.js b/WebApp/client/test/memoryhelper.test.js deleted file mode 100644 index a45ccd7..0000000 --- a/WebApp/client/test/memoryhelper.test.js +++ /dev/null @@ -1,67 +0,0 @@ -import { - MemoryHelper -} from "../src/memoryhelper.js"; - -describe(`MemoryHelper.writeSingleBit`, () => { - test('turn on with offset 0', () => { - let bytes = new ArrayBuffer(3); - MemoryHelper.writeSingleBit(bytes, 0, false); - - // check 00 00 00 - const view = new Uint8Array(bytes); - expect(view[0]).toBe(0); - expect(view[1]).toBe(0); - expect(view[2]).toBe(0); - }); - test('turn off with offset 0', () => { - let bytes = new ArrayBuffer(3); - MemoryHelper.writeSingleBit(bytes, 0, true); - - // check 00 00 01 - const view = new Uint8Array(bytes); - expect(view[0]).toBe(1); - expect(view[1]).toBe(0); - expect(view[2]).toBe(0); - - MemoryHelper.writeSingleBit(bytes, 0, false); - - // check 00 00 00 - expect(view[0]).toBe(0); - expect(view[1]).toBe(0); - expect(view[2]).toBe(0); - }); - test('turn on with offset 32', () => { - let bytes = new ArrayBuffer(3); - MemoryHelper.writeSingleBit(bytes, 8, true); - - // check 00 01 00 - const view = new Uint8Array(bytes); - expect(view[0]).toBe(0); - expect(view[1]).toBe(1); - expect(view[2]).toBe(0); - - MemoryHelper.writeSingleBit(bytes, 0, true); - - // check 00 01 01 - expect(view[0]).toBe(1); - expect(view[1]).toBe(1); - expect(view[2]).toBe(0); - }); - test('turn on with offset 15', () => { - let bytes = new ArrayBuffer(3); - MemoryHelper.writeSingleBit(bytes, 15, true); - - // check 00 80 00 - const view = new Uint8Array(bytes); - expect(view[0]).toBe(0); - expect(view[1]).toBe(128); - expect(view[2]).toBe(0); - - MemoryHelper.writeSingleBit(bytes, 15, false); - - // check 00 00 00 - expect(view[0]).toBe(0); - expect(view[1]).toBe(0); - expect(view[2]).toBe(0); - }); -}); \ No newline at end of file diff --git a/WebApp/client/test/mocksignaling.js b/WebApp/client/test/mocksignaling.js deleted file mode 100644 index e82d66c..0000000 --- a/WebApp/client/test/mocksignaling.js +++ /dev/null @@ -1,224 +0,0 @@ -import { sleep } from "./testutils"; - -/** @type {MockPrivateSignalingManager | MockPublicSignalingManager} */ -let manager; - -export function reset(isPrivate) { - manager = isPrivate ? new MockPrivateSignalingManager() : new MockPublicSignalingManager(); -} - -export class MockSignaling extends EventTarget { - - constructor(interval = 1000) { - super(); - this.interval = interval; - } - - async start() { - await manager.add(this); - } - - async stop() { - await manager.remove(this); - } - - async createConnection(connectionId) { - await manager.openConnection(this, connectionId); - } - - async deleteConnection(connectionId) { - await manager.closeConnection(this, connectionId); - } - - async sendOffer(connectionId, sdp) { - const data = { 'sdp': sdp, 'connectionId': connectionId }; - await manager.offer(this, data); - } - - async sendAnswer(connectionId, sdp) { - const data = { 'sdp': sdp, 'connectionId': connectionId }; - await manager.answer(this, data); - } - - async sendCandidate(connectionId, candidate, sdpMLineIndex, sdpMid) { - const data = { - 'candidate': candidate, - 'sdpMLineIndex': sdpMLineIndex, - 'sdpMid': sdpMid, - 'connectionId': connectionId - }; - await manager.candidate(this, data); - } -} - -class MockPublicSignalingManager { - constructor() { - this.list = new Set(); - this.delay = async () => await sleep(10); - } - - async add(signaling) { - await this.delay(); - this.list.add(signaling); - signaling.dispatchEvent(new Event("start")); - } - - async remove(signaling) { - await this.delay(); - this.list.delete(signaling); - signaling.dispatchEvent(new Event("end")); - } - - async openConnection(signaling, connectionId) { - await this.delay(); - const data = { connectionId: connectionId, polite: true }; - signaling.dispatchEvent(new CustomEvent("connect", { detail: data })); - } - - async closeConnection(signaling, connectionId) { - await this.delay(); - const data = { connectionId: connectionId }; - for (const element of this.list) { - element.dispatchEvent(new CustomEvent("disconnect", { detail: data })); - } - } - - async offer(owner, data) { - await this.delay(); - data.polite = false; - for (const signaling of this.list) { - if (signaling != owner) { - signaling.dispatchEvent(new CustomEvent("offer", { detail: data })); - } - } - } - - async answer(owner, data) { - await this.delay(); - for (const signaling of this.list) { - if (signaling != owner) { - signaling.dispatchEvent(new CustomEvent("answer", { detail: data })); - } - } - } - - async candidate(owner, data) { - await this.delay(); - for (const signaling of this.list) { - if (signaling != owner) { - signaling.dispatchEvent(new CustomEvent("candidate", { detail: data })); - } - } - } -} - -class MockPrivateSignalingManager { - constructor() { - // structure Map> connectionIds - this.connectionIds = new Map(); - this.delay = async () => await sleep(10); - } - - async add(signaling) { - await this.delay(); - signaling.dispatchEvent(new Event("start")); - } - - async remove(signaling) { - await this.delay(); - signaling.dispatchEvent(new Event("end")); - } - - async openConnection(signaling, connectionId) { - await this.delay(); - const peerExists = this.connectionIds.has(connectionId); - if (!peerExists) { - this.connectionIds.set(connectionId, new Set()); - } - - const list = this.connectionIds.get(connectionId); - list.add(signaling); - - const data = { connectionId: connectionId, polite: peerExists }; - signaling.dispatchEvent(new CustomEvent("connect", { detail: data })); - } - - async closeConnection(signaling, connectionId) { - await this.delay(); - const peerExists = this.connectionIds.has(connectionId); - const list = this.connectionIds.get(connectionId); - if (!peerExists || !list.has(signaling)) { - console.error(`${connectionId} This connection id is not used.`); - } - - const data = { connectionId: connectionId }; - for (const element of list) { - element.dispatchEvent(new CustomEvent("disconnect", { detail: data })); - } - - list.delete(signaling); - if (list.size == 0) { - this.connectionIds.delete(connectionId); - } - } - - findList(owner, connectionId) { - if (!this.connectionIds.has(connectionId)) { - return null; - } - - const list = new Set(this.connectionIds.get(connectionId)); - list.delete(owner); - if (list.Count == 0) { - return null; - } - - return list; - } - - async offer(owner, data) { - await this.delay(); - const list = this.findList(owner, data.connectionId); - if (list == null) { - console.warn(`${data.connectionId} This connection id is not ready other session.`); - return; - } - - data.polite = true; - for (const signaling of list) { - if (signaling != owner) { - signaling.dispatchEvent(new CustomEvent("offer", { detail: data })); - } - } - } - - async answer(owner, data) { - await this.delay(); - const list = this.findList(owner, data.connectionId); - if (list == null) { - console.warn(`${data.connectionId} This connection id is not ready other session.`); - return; - } - - for (const signaling of list) { - if (signaling != owner) { - signaling.dispatchEvent(new CustomEvent("answer", { detail: data })); - } - } - } - - async candidate(owner, data) { - await this.delay(); - const list = this.findList(owner, data.connectionId); - if (list == null) { - console.warn(`${data.connectionId} This connection id is not ready other session.`); - return; - } - - for (const signaling of list) { - if (signaling != owner) { - signaling.dispatchEvent(new CustomEvent("candidate", { detail: data })); - } - } - } -} diff --git a/WebApp/client/test/peerconnection.test.js b/WebApp/client/test/peerconnection.test.js deleted file mode 100644 index 78fb90a..0000000 --- a/WebApp/client/test/peerconnection.test.js +++ /dev/null @@ -1,250 +0,0 @@ -import Peer from "../src/peer.js"; -import { waitFor, sleep, getUniqueId, getRTCConfiguration } from "./testutils.js"; - - -describe(`peer connection test`, () => { - const connectionId = "12345"; - - test(`constructor`, () => { - const peer = new Peer(connectionId, true); - expect(peer).not.toBeNull(); - - const rtcPeer = peer.pc; - expect(rtcPeer).not.toBeNull(); - expect(rtcPeer.ontrack).not.toBeNull(); - expect(rtcPeer.onicecandidate).not.toBeNull(); - expect(rtcPeer.onnegotiationneeded).not.toBeNull(); - expect(rtcPeer.onsignalingstatechange).not.toBeNull(); - expect(rtcPeer.oniceconnectionstatechange).not.toBeNull(); - expect(rtcPeer.onicegatheringstatechange).not.toBeNull(); - }); - - test(`close peer`, async () => { - const config = getRTCConfiguration(); - const peer = new Peer(connectionId, true, config); - expect(peer).not.toBeNull(); - - peer.close(); - expect(peer.connectionId).toBeNull(); - expect(peer.pc).toBeNull(); - }); - - test(`transceiver direction is sendrecv if using addtrack`, () => { - const config = getRTCConfiguration(); - const peer = new Peer(connectionId, true, config); - expect(peer).not.toBeNull(); - - const track = { id: getUniqueId(), kind: "audio" }; - const sender = peer.addTrack(connectionId, track); - const transceiver = peer.getTransceivers(connectionId).find(t => t.sender == sender); - expect(transceiver.direction).toBe("sendrecv"); - }); - - test(`fire trackevent when addtrack`, async () => { - let trackEvent; - const config = getRTCConfiguration(); - const peer = new Peer(connectionId, true, config); - expect(peer).not.toBeNull(); - peer.addEventListener('trackevent', (e) => trackEvent = e.detail); - - const track = { id: getUniqueId(), kind: "audio" }; - peer.addTrack(connectionId, track); - await waitFor(() => trackEvent != null); - expect(trackEvent.track).toBe(track); - }); - - test(`fire trackevent when on got offer description include track`, async () => { - let trackEvent; - const config = getRTCConfiguration(); - const peer = new Peer(connectionId, true, config); - expect(peer).not.toBeNull(); - peer.addEventListener('trackevent', (e) => trackEvent = e.detail); - - const testDesc = { type: "offer", sdp: "newtracksdp" }; - peer.onGotDescription(connectionId, testDesc); - await waitFor(() => trackEvent != null); - expect(trackEvent.track).not.toBeNull(); - }); - - test(`fire sendoffer when addtrack`, async () => { - let offer; - const config = getRTCConfiguration(); - const peer = new Peer(connectionId, true, config); - expect(peer).not.toBeNull(); - peer.addEventListener('sendoffer', (e) => offer = e.detail); - - const track = { id: getUniqueId(), kind: "audio" }; - peer.addTrack(connectionId, track); - await waitFor(() => offer != null); - expect(offer.connectionId).toBe(connectionId); - }); - - test(`fire sendoffer when addTransceiver`, async () => { - let offer; - const config = getRTCConfiguration(); - const peer = new Peer(connectionId, true, config); - expect(peer).not.toBeNull(); - peer.addEventListener('sendoffer', (e) => offer = e.detail); - - peer.addTransceiver(connectionId, "video"); - await waitFor(() => offer != null); - expect(offer.connectionId).toBe(connectionId); - }); - - test(`fire sendoffer when createDataChannel`, async () => { - let offer; - const config = getRTCConfiguration(); - const peer = new Peer(connectionId, true, config); - expect(peer).not.toBeNull(); - peer.addEventListener('sendoffer', (e) => offer = e.detail); - - peer.createDataChannel(connectionId, "testChannel"); - await waitFor(() => offer != null); - expect(offer.connectionId).toBe(connectionId); - }); - - test(`re-fire sendoffer if get answer not yet`, async () => { - let sendOfferCount = 0; - let offer; - const config = getRTCConfiguration(); - const peer = new Peer(connectionId, true, config, 100); - expect(peer).not.toBeNull(); - peer.addEventListener('sendoffer', (e) => { - offer = e.detail; - sendOfferCount++; - }); - - const track = { id: getUniqueId(), kind: "audio" }; - peer.addTrack(connectionId, track); - await waitFor(() => sendOfferCount > 2); - expect(offer.connectionId).toBe(connectionId); - expect(sendOfferCount).toBeGreaterThan(2); - }); - - test(`fire sendanswer when on got offer description in polite`, async () => { - let answer; - const config = getRTCConfiguration(); - const peer = new Peer(connectionId, true, config); - expect(peer).not.toBeNull(); - peer.addEventListener('sendanswer', (e) => answer = e.detail); - - const testDesc = { type: "offer", sdp: "newtracksdp" }; - peer.onGotDescription(connectionId, testDesc); - await waitFor(() => answer != null); - expect(answer.connectionId).toBe(connectionId); - }); - - test(`fire sendanswer when on got offer description in polite that have offer`, async () => { - let offer; - let answer; - const config = getRTCConfiguration(); - const peer = new Peer(connectionId, true, config); - expect(peer).not.toBeNull(); - peer.addEventListener('sendoffer', (e) => offer = e.detail); - peer.addEventListener('sendanswer', (e) => answer = e.detail); - - const track = { id: getUniqueId(), kind: "audio" }; - peer.addTrack(connectionId, track); - await waitFor(() => offer != null); - expect(offer.connectionId).toBe(connectionId); - - const testDesc = { type: "offer", sdp: "newtracksdp" }; - peer.onGotDescription(connectionId, testDesc); - await waitFor(() => answer != null); - expect(answer.connectionId).toBe(connectionId); - }); - - test(`fire sendanswer when on got offer description in impolite that don't have offer`, async () => { - let answer; - const config = getRTCConfiguration(); - const peer = new Peer(connectionId, false, config); - expect(peer).not.toBeNull(); - peer.addEventListener('sendanswer', (e) => answer = e.detail); - - const testDesc = { type: "offer", sdp: "newtracksdp" }; - peer.onGotDescription(connectionId, testDesc); - await waitFor(() => answer != null); - expect(answer.connectionId).toBe(connectionId); - }); - - test(`don't fire sendanswer when on got offer description in impolite that have offer`, async () => { - let offer; - let answer; - const config = getRTCConfiguration(); - const peer = new Peer(connectionId, false, config); - expect(peer).not.toBeNull(); - peer.addEventListener('sendoffer', (e) => offer = e.detail); - peer.addEventListener('sendanswer', (e) => answer = e.detail); - - const track = { id: getUniqueId(), kind: "audio" }; - peer.addTrack(connectionId, track); - await waitFor(() => offer != null); - expect(offer.connectionId).toBe(connectionId); - - const testDesc = { type: "offer", sdp: "newtracksdp" }; - peer.onGotDescription(connectionId, testDesc); - await sleep(100); - expect(answer).toBeUndefined(); - }); - - test(`fire nagotiated when on got answer description that have offer`, async () => { - let offer; - let negotiated = false; - const config = getRTCConfiguration(); - const peer = new Peer(connectionId, true, config); - expect(peer).not.toBeNull(); - peer.addEventListener('sendoffer', (e) => offer = e.detail); - peer.pc.addEventListener('negotiated', () => negotiated = true); - - const track = { id: getUniqueId(), kind: "audio" }; - peer.addTrack(connectionId, track); - await waitFor(() => offer != null); - expect(offer.connectionId).toBe(connectionId); - - const answerDesc = { type: "answer", sdp: "newtracksdp" }; - peer.onGotDescription(connectionId, answerDesc); - await waitFor(() => negotiated); - expect(negotiated).toBeTruthy(); - }); - - test(`fire sendcandidate when on addTransceiver`, async () => { - let candidate; - const config = getRTCConfiguration(); - const peer = new Peer(connectionId, true, config); - expect(peer).not.toBeNull(); - peer.addEventListener('sendcandidate', (e) => candidate = e.detail); - - peer.addTransceiver(connectionId, { id: getUniqueId(), kind: "video" }); - await waitFor(() => candidate != null); - expect(candidate.connectionId).toBe(connectionId); - }); - - test(`accept candidate when on got candidate that have remote description`, async () => { - let answer; - const config = getRTCConfiguration(); - const peer = new Peer(connectionId, false, config); - expect(peer).not.toBeNull(); - peer.addEventListener('sendanswer', (e) => answer = e.detail); - - const testDesc = { type: "offer", sdp: "newtracksdp" }; - peer.onGotDescription(connectionId, testDesc); - await waitFor(() => answer != null); - expect(answer.connectionId).toBe(connectionId); - - const testCandidate = { candidate: getUniqueId(), sdpMLineIndex: 0, sdpMid: 0 }; - peer.onGotCandidate(connectionId, testCandidate); - await waitFor(() => peer.pc.candidates.length > 0); - expect(peer.pc.candidates.length).toBeGreaterThan(0); - }); - - test(`don't accept candidate when on got candidate that don't have remote description`, async () => { - const config = getRTCConfiguration(); - const peer = new Peer(connectionId, false, config); - expect(peer).not.toBeNull(); - - const testCandidate = { candidate: getUniqueId(), sdpMLineIndex: 0, sdpMid: 0 }; - peer.onGotCandidate(connectionId, testCandidate); - await sleep(100); - expect(peer.pc.candidates.length).toBe(0); - }); -}); diff --git a/WebApp/client/test/peerconnectionmock.js b/WebApp/client/test/peerconnectionmock.js deleted file mode 100644 index 96d1cd3..0000000 --- a/WebApp/client/test/peerconnectionmock.js +++ /dev/null @@ -1,316 +0,0 @@ -import { sleep, getUniqueId } from './testutils'; - -export class PeerConnectionMock extends EventTarget { - constructor(config) { - super(); - this.delay = async () => await sleep(10); - this.config = config; - this.ontrack = undefined; - this.ondatachannel = undefined; - this.onicecandidate = undefined; - this.onnegotiationneeded = undefined; - this.onsignalingstatechange = undefined; - this.oniceconnectionstatechange = undefined; - this.onicegatheringstatechange = undefined; - this.pendingLocalDescription = null; - this.currentLocalDescription = null; - this.pendingRemoteDescription = null; - this.currentRemoteDescription = null; - this.candidates = []; - this.signalingState = "stable"; - this.iceConnectionState = "new"; - this.iceGatheringState = "new"; - this.audioTracks = new Map(); - this.videoTracks = new Map(); - this.channels = new Map(); - this.transceiverCount = 0; - this.transceivers = new Map(); - } - - get localDescription() { - if (this.pendingLocalDescription) { - return this.pendingLocalDescription; - } - - return this.currentLocalDescription; - } - - get remoteDescription() { - if (this.pendingRemoteDescription) { - return this.pendingRemoteDescription; - } - - return this.currentRemoteDescription; - } - - close() { - this.ontrack = undefined; - this.ondatachannel = undefined; - this.onicecandidate = undefined; - this.onnegotiationneeded = undefined; - this.onsignalingstatechange = undefined; - this.oniceconnectionstatechange = undefined; - this.onicegatheringstatechange = undefined; - this.pendingLocalDescription = null; - this.currentLocalDescription = null; - this.pendingRemoteDescription = null; - this.currentRemoteDescription = null; - this.candidates = []; - this.signalingState = "close"; - this.iceConnectionState = "closed"; - this.audioTracks.clear(); - this.videoTracks.clear(); - this.channels.clear(); - this.transceiverCount = 0; - this.transceivers.clear(); - } - - fireOnNegotiationNeeded() { - if (this.onnegotiationneeded) { - this.onnegotiationneeded(); - } - } - - getTransceivers() { - return Array.from(this.transceivers.values()); - } - - addTrack(track) { - if (track.kind == "audio") { - this.audioTracks.set(track.id, track); - } else { - this.videoTracks.set(track.id, track); - } - const transceiver = { direction: "sendrecv", sender: { track: track }, receiver: null, setCodecPreferences: (codecs) => { console.log(codecs); } }; - this.transceivers.set(this.transceiverCount++, transceiver); - this.fireOnNegotiationNeeded(); - return transceiver.sender; - } - - addTransceiver(trackOrKind) { - if (typeof trackOrKind == "string") { - const track = { id: getUniqueId(), kind: trackOrKind }; - if (track.kind == "audio") { - this.audioTracks.set(track.id, track); - } else { - this.videoTracks.set(track.id, track); - } - const transceiver = { direction: "sendrecv", sender: { track: track }, receiver: null, setCodecPreferences: (codecs) => { console.log(codecs); } }; - this.transceivers.set(this.transceiverCount++, transceiver); - this.fireOnNegotiationNeeded(); - return transceiver; - } - - if (trackOrKind.kind == "audio") { - this.audioTracks.set(trackOrKind.id, trackOrKind); - } else { - this.videoTracks.set(trackOrKind.id, trackOrKind); - } - const transceiver = { direction: "sendrecv", sender: { track: trackOrKind }, receiver: null, setCodecPreferences: (codecs) => { console.log(codecs); } }; - this.transceivers.set(this.transceiverCount++, transceiver); - this.fireOnNegotiationNeeded(); - return transceiver; - } - - createDataChannel(label) { - const channel = { id: getUniqueId(), label: label }; - this.channels.set(channel.id, channel); - this.fireOnNegotiationNeeded(); - return channel; - } - - async setLocalDescription(description = null) { - if (description == null) { - description = this._createSessionDescription(); - } - await this.delay(); - this._setSessionDescription(description, false); - } - - async setRemoteDescription(description) { - await this.delay(); - if (description.type == "offer" && this.signalingState == "have-local-offer") { - this._setSessionDescription({ type: "rollback", sdp: "" }, true); - } - this._setSessionDescription(description, true); - } - - _createSessionDescription() { - let dummySdp = "testsdp"; - if (this.videoTracks.size > 0) { - dummySdp += "videotrack"; - } - if (this.audioTracks.size > 0) { - dummySdp += "audiotrack"; - } - if (this.channels.size > 0) { - dummySdp += "datachannel"; - } - - if (this.signalingState == "stable" || this.signalingState == "have-local-offer" || this.signalingState == "have-remote-pranswer") { - return { type: "offer", sdp: dummySdp }; - } - return { type: "answer", sdp: dummySdp }; - } - - _setSessionDescription(description, remote) { - if (description.type == "rollback" - && (this.signalingState == "stable" || this.signalingState == "have-local-pranswer" || this.signalingState == "have-remote-pranswer")) { - throw "InvalidStateError"; - } - - if (description.type != "rollback") { - if (remote) { - if (description.type == "offer") { - this.pendingRemoteDescription = description; - this.signalingState = "have-remote-offer"; - this.onsignalingstatechange(this.signalingState); - // if sdp contains track string, create dummy track - if (description.sdp.includes("track")) { - const isVideo = description.sdp.includes("video"); - const kind = isVideo ? "video" : "audio"; - this._createTrackAndTransceiver(kind); - } - if (description.sdp.includes("datachannel")) { - const channel = { id: getUniqueId(), label: "dummychannel" }; - this.channels.set(channel.id, channel); - } - } - if (description.type == "answer") { - this.currentRemoteDescription = description; - this.currentLocalDescription = this.pendingLocalDescription; - this.pendingLocalDescription = null; - this.pendingRemoteDescription = null; - this.signalingState = "stable"; - this.onsignalingstatechange(this.signalingState); - } - if (description.type == "pranswer") { - this.pendingRemoteDescription = description; - this.signalingState = "have-remote-pranswer"; - this.onsignalingstatechange(this.signalingState); - } - } else { - if (description.type == "offer") { - this.pendingLocalDescription = description; - this.signalingState = "have-local-offer"; - this.onsignalingstatechange(this.signalingState); - } - if (description.type == "answer") { - this.currentLocalDescription = description; - this.currentRemoteDescription = this.pendingRemoteDescription; - this.pendingLocalDescription = null; - this.pendingRemoteDescription = null; - this.signalingState = "stable"; - this.onsignalingstatechange(this.signalingState); - // if sdp contains track string, create dummy track - if (description.sdp.includes("track")) { - const isVideo = description.sdp.includes("video"); - const kind = isVideo ? "video" : "audio"; - this._createTrackAndTransceiver(kind); - } - if (description.sdp.includes("datachannel")) { - const channel = { id: getUniqueId(), label: "dummychannel" }; - this.channels.set(channel.id, channel); - } - } - if (description.type == "pranswer") { - this.pendingLocalDescription = description; - this.signalingState = "have-local-pranswer"; - this.onsignalingstatechange(this.signalingState); - } - } - } else { - this.pendingLocalDescription = null; - this.pendingRemoteDescription = null; - this.signalingState = "stable"; - this.onsignalingstatechange(this.signalingState); - } - - if (this.videoTracks.size != 0 || this.audioTracks.size != 0) { - this._mockGatheringIceCandidate(this.videoTracks.size + this.audioTracks.size); - } - - //fire ontrack with new tracks, after using tracks clear. - if (this.ontrack) { - for (const track of this.videoTracks.values()) { - this.ontrack({ track: track }); - } - this.videoTracks.clear(); - - for (const track of this.audioTracks.values()) { - this.ontrack({ track: track }); - } - this.audioTracks.clear(); - } - - if (this.ondatachannel) { - for (const channel of this.channels.values()) { - this.ondatachannel({ channel: channel }); - } - this.channels.clear(); - } - } - - async _mockGatheringIceCandidate(count) { - this.iceGatheringState = "gathering"; - if (this.onicegatheringstatechange) { - this.onicegatheringstatechange(this.iceGatheringState); - } - for (let index = 0; index < count; index++) { - await this.delay(); - const newCandidate = { candidate: getUniqueId(), sdpMLineIndex: index, sdpMid: index }; - if (this.onicecandidate) { - this.onicecandidate(newCandidate); - } - } - this.iceGatheringState = "complete"; - if (this.onicegatheringstatechange) { - this.onicegatheringstatechange(this.iceGatheringState); - } - if (this.onicecandidate) { - this.onicecandidate({ candidate: null, sdpMLineIndex: null, sdpMid: null }); - } - } - - async addIceCandidate(candidate) { - await this.delay(); - if (this.remoteDescription == null) { - throw "InvalidStateError"; - } - this.candidates.push(candidate); - } - - _createTrackAndTransceiver(kind) { - const track = { id: getUniqueId(), kind: kind }; - if (kind == "video") { - this.videoTracks.set(track.id, track); - } else { - this.audioTracks.set(track.id, track); - } - const transceiver = { direction: "sendrecv", sender: { track: track }, receiver: null, setCodecPreferences: (codecs) => { console.log(codecs); } }; - this.transceivers.set(this.transceiverCount++, transceiver); - } -} - -export class SessionDescriptionMock { - - constructor(object) { - this.sdp = object.sdp; - this.type = object.type; - } - - sdp; - type; -} - -export class IceCandidateMock { - constructor(object) { - this.candidate = object.candidate; - this.sdpMLineIndex = object.sdpMLineIndex; - this.sdpMid = object.sdpMid; - } - - candidate; - sdpMLineIndex; - sdpMid; -} \ No newline at end of file diff --git a/WebApp/client/test/pointercorrect.test.js b/WebApp/client/test/pointercorrect.test.js deleted file mode 100644 index d85857f..0000000 --- a/WebApp/client/test/pointercorrect.test.js +++ /dev/null @@ -1,45 +0,0 @@ -import { - LetterBoxType, - PointerCorrector -} from "../src/pointercorrect.js"; - -import {DOMRect} from "./domrect.js"; -import {DOMHTMLVideoElement} from "./domvideoelement.js"; - -describe(`PointerCorrector.map`, () => { - test('letterboxType', () => { - const rect = new DOMRect(10, 10, 200, 200); - const element = new DOMHTMLVideoElement(rect); - let corrector = new PointerCorrector(50, 100, element); - expect(corrector.letterBoxType).toBe(LetterBoxType.Vertical); - corrector.reset(100, 50, element); - expect(corrector.letterBoxType).toBe(LetterBoxType.Horizontal); - }); - test('letterboxSize', () => { - const rect = new DOMRect(0, 0, 100, 100); - const element = new DOMHTMLVideoElement(rect); - let corrector = new PointerCorrector(50, 100, element); - expect(corrector.letterBoxSize).toBe(25); - }); - test('contentRect', () => { - const rect = new DOMRect(0, 0, 100, 100); - const element = new DOMHTMLVideoElement(rect); - let corrector = new PointerCorrector(50, 100, element); - expect(corrector.contentRect.x).toBe(25); - expect(corrector.contentRect.y).toBe(0); - expect(corrector.contentRect.width).toBe(50); - expect(corrector.contentRect.height).toBe(100); - }); - test('mapping', () => { - const rect = new DOMRect(10, 10, 200, 200); - const element = new DOMHTMLVideoElement(rect); - const videoWidth = 100; - const videoHeight = 100; - let corrector = new PointerCorrector(videoWidth, videoHeight, element); - const position = [10, 10]; - const newPosition = corrector.map(position); - expect(newPosition[0]).toBe(0); - expect(newPosition[1]).toBe(100); - }); - -}); diff --git a/WebApp/client/test/renderstreaming.test.js b/WebApp/client/test/renderstreaming.test.js deleted file mode 100644 index f2bc5f8..0000000 --- a/WebApp/client/test/renderstreaming.test.js +++ /dev/null @@ -1,187 +0,0 @@ -import { MockSignaling, reset } from "./mocksignaling.js"; -import { waitFor, getUniqueId, getRTCConfiguration } from "./testutils.js"; -import { RenderStreaming } from "../src/renderstreaming.js"; - -describe.each([ - { mode: "private" }, - { mode: "public" } -])('renderstreaming test', ({ mode }) => { - const connectionId1 = "12345"; - - test(`createConnection in ${mode} mode`, async () => { - reset(mode == "private"); - const config = getRTCConfiguration(); - const renderstreaming = new RenderStreaming(new MockSignaling(), config); - await renderstreaming.start(); - - let isConnect = false; - renderstreaming.onConnect = () => isConnect = true; - await renderstreaming.createConnection(connectionId1); - await waitFor(() => isConnect); - expect(isConnect).toBe(true); - - await renderstreaming.stop(); - }); - - test(`addTrack in ${mode} mode`, async () => { - reset(mode == "private"); - const config = getRTCConfiguration(); - const renderstreaming = new RenderStreaming(new MockSignaling(), config); - await renderstreaming.start(); - - let isConnect = false; - renderstreaming.onConnect = () => isConnect = true; - await renderstreaming.createConnection(connectionId1); - await waitFor(() => isConnect); - expect(isConnect).toBe(true); - expect(renderstreaming.getTransceivers(connectionId1).length).toBe(0); - - const track = { id: getUniqueId(), kind: "audio" }; - renderstreaming.addTrack(track); - expect(renderstreaming.getTransceivers(connectionId1).length).toBe(1); - - let isDisconnect = false; - renderstreaming.onDisconnect = () => isDisconnect = true; - await renderstreaming.deleteConnection(); - await waitFor(() => isDisconnect); - expect(isDisconnect).toBe(true); - - await renderstreaming.stop(); - }); - - test(`createChannel in ${mode} mode`, async () => { - reset(mode == "private"); - const config = getRTCConfiguration(); - const renderstreaming = new RenderStreaming(new MockSignaling(), config); - await renderstreaming.start(); - - let isConnect = false; - renderstreaming.onConnect = () => isConnect = true; - await renderstreaming.createConnection(connectionId1); - await waitFor(() => isConnect); - expect(isConnect).toBe(true); - expect(renderstreaming.getTransceivers(connectionId1).length).toBe(0); - - const label = "testlabel"; - const channel = renderstreaming.createDataChannel(label); - expect(channel.label).toBe(label); - - let isDisconnect = false; - renderstreaming.onDisconnect = () => isDisconnect = true; - await renderstreaming.deleteConnection(); - await waitFor(() => isDisconnect); - expect(isDisconnect).toBe(true); - - await renderstreaming.stop(); - }); - - test(`onTrackEvent in ${mode} mode`, async () => { - reset(mode == "private"); - - const config = getRTCConfiguration(); - const renderstreaming1 = new RenderStreaming(new MockSignaling(), config); - const renderstreaming2 = new RenderStreaming(new MockSignaling(), config); - await renderstreaming1.start(); - await renderstreaming2.start(); - - let isConnect1 = false; - renderstreaming1.onConnect = () => isConnect1 = true; - let isConnect2 = false; - renderstreaming2.onConnect = () => isConnect2 = true; - - await renderstreaming1.createConnection(connectionId1); - await renderstreaming2.createConnection(connectionId1); - await waitFor(() => isConnect1 && isConnect2); - expect(isConnect1).toBe(true); - expect(isConnect2).toBe(true); - - let isGotOffer1 = false; - let isOnTrack1 = false; - let isGotAnswer2 = false; - renderstreaming1.onGotOffer = () => { isGotOffer1 = true; }; - renderstreaming1.onTrackEvent = () => { isOnTrack1 = true; }; - renderstreaming2.onGotAnswer = () => { isGotAnswer2 = true; }; - - expect(renderstreaming1.getTransceivers(connectionId1).length).toBe(0); - - const track = { id: getUniqueId(), kind: "audio" }; - renderstreaming2.addTrack(track); - expect(renderstreaming2.getTransceivers(connectionId1).length).toBe(1); - await waitFor(() => isGotOffer1); - expect(isGotOffer1).toBe(true); - - await waitFor(() => isOnTrack1); - expect(isOnTrack1).toBe(true); - expect(renderstreaming1.getTransceivers(connectionId1).length).toBe(1); - - await waitFor(() => isGotAnswer2); - expect(isGotAnswer2).toBe(true); - - let isDisconnect1 = false; - renderstreaming1.onDisconnect = () => isDisconnect1 = true; - let isDisconnect2 = false; - renderstreaming2.onDisconnect = () => isDisconnect2 = true; - - await renderstreaming1.deleteConnection(); - await renderstreaming2.deleteConnection(); - await waitFor(() => isDisconnect1 && isDisconnect2); - expect(isDisconnect1).toBe(true); - expect(isDisconnect2).toBe(true); - - await renderstreaming1.stop(); - await renderstreaming2.stop(); - }); - - test(`onAddDataChannel in ${mode} mode`, async () => { - reset(mode == "private"); - - const config = getRTCConfiguration(); - const renderstreaming1 = new RenderStreaming(new MockSignaling(), config); - const renderstreaming2 = new RenderStreaming(new MockSignaling(), config); - await renderstreaming1.start(); - await renderstreaming2.start(); - - let isConnect1 = false; - renderstreaming1.onConnect = () => isConnect1 = true; - let isConnect2 = false; - renderstreaming2.onConnect = () => isConnect2 = true; - - await renderstreaming1.createConnection(connectionId1); - await renderstreaming2.createConnection(connectionId1); - await waitFor(() => isConnect1 && isConnect2); - expect(isConnect1).toBe(true); - expect(isConnect2).toBe(true); - - let isGotOffer1 = false; - let isAddChannel1 = false; - let isGotAnswer2 = false; - renderstreaming1.onGotOffer = () => { isGotOffer1 = true; }; - renderstreaming1.onAddChannel = () => { isAddChannel1 = true; }; - renderstreaming2.onGotAnswer = () => { isGotAnswer2 = true; }; - - renderstreaming2.createDataChannel("testchannel"); - await waitFor(() => isGotOffer1); - expect(isGotOffer1).toBe(true); - - await waitFor(() => isAddChannel1); - expect(isAddChannel1).toBe(true); - - await waitFor(() => isGotAnswer2); - expect(isGotAnswer2).toBe(true); - - let isDisconnect1 = false; - renderstreaming1.onDisconnect = () => isDisconnect1 = true; - let isDisconnect2 = false; - renderstreaming2.onDisconnect = () => isDisconnect2 = true; - - await renderstreaming1.deleteConnection(); - await renderstreaming2.deleteConnection(); - await waitFor(() => isDisconnect1 && isDisconnect2); - expect(isDisconnect1).toBe(true); - expect(isDisconnect2).toBe(true); - - await renderstreaming1.stop(); - await renderstreaming2.stop(); - }); - -}); diff --git a/WebApp/client/test/resizeobservermock.js b/WebApp/client/test/resizeobservermock.js deleted file mode 100644 index d7bc378..0000000 --- a/WebApp/client/test/resizeobservermock.js +++ /dev/null @@ -1,18 +0,0 @@ -// mock class - -/* eslint-disable no-unused-vars */ -let instanceResize = null; -/* eslint-disable no-unused-vars */ -let callbackResize = null; - -export default class ResizeObserverMock { - constructor(callback) { - instanceResize = this; - callbackResize = callback; - } - disconnect() { } - /* eslint-disable no-unused-vars */ - observe(target, options) { } - /* eslint-disable no-unused-vars */ - unobserve(target) { } -} \ No newline at end of file diff --git a/WebApp/client/test/sender.test.js b/WebApp/client/test/sender.test.js deleted file mode 100644 index d573702..0000000 --- a/WebApp/client/test/sender.test.js +++ /dev/null @@ -1,143 +0,0 @@ -import { - InputRemoting, -} from "../src/inputremoting.js"; - -import { - Sender, - Observer -} from "../src/sender.js"; - -import {jest} from '@jest/globals'; -import {DOMRect} from "./domrect.js"; - -// mock - -class RTCDataChannel { - get readyState() { - return "open"; - } - /* eslint-disable no-unused-vars */ - send(message) { - } -} - -describe(`Sender`, () => { - let inputRemoting = null; - let sender = null; - let observer = null; - let events = {}; - let dc = null; - beforeEach(async () => { - // Empty our events before each test case - events = {}; - - // Define the addEventListener method with a Jest mock function - document.addEventListener = jest.fn((event, callback) => { - events[event] = callback; - }); - - document.removeEventListener = jest.fn((event, callback) => { - delete events[event]; - }); - document.getBoundingClientRect = function(){ return new DOMRect(0,0,0,0); }; - sender = new Sender(document); - inputRemoting = new InputRemoting(sender); - dc = new RTCDataChannel(); - observer = new Observer(dc); - }); - test('devices', () => { - sender.addMouse(); - expect(sender.devices.length).toBe(1); - sender.addKeyboard(); - expect(sender.devices.length).toBe(2); - }); - test('send messages while called startSending', () => { - jest.spyOn(dc, 'send'); - sender.addMouse(); - sender.addKeyboard(); - inputRemoting.subscribe(observer); - inputRemoting.startSending(); - expect(dc.send).toHaveBeenCalled(); - }); - describe('mouse', () => { - test('click', () => { - jest.spyOn(dc, 'send'); - sender.addMouse(); - inputRemoting.subscribe(observer); - inputRemoting.startSending(); - events.click( - new MouseEvent('click', { buttons:1, clientX:0, clientY:0} )); - expect(dc.send).toHaveBeenCalledWith(expect.any(ArrayBuffer)); - }); - test('mousemove', () => { - jest.spyOn(dc, 'send'); - sender.addMouse(); - inputRemoting.subscribe(observer); - inputRemoting.startSending(); - events.mousemove( - new MouseEvent('mousemove', { buttons:1, deltaX:0, deltaY:0 })); - expect(dc.send).toHaveBeenCalledWith(expect.any(ArrayBuffer)); - }); - test('wheel', () => { - jest.spyOn(dc, 'send'); - sender.addMouse(); - inputRemoting.subscribe(observer); - inputRemoting.startSending(); - events.wheel( - new WheelEvent('wheel', { wheelDelta:0, deltaX:0, deltaY:0 })); - expect(dc.send).toHaveBeenCalledWith(expect.any(ArrayBuffer)); - }); - }); - describe('keyboard', () => { - test('keydown', () => { - jest.spyOn(dc, 'send'); - sender.addKeyboard(); - inputRemoting.subscribe(observer); - inputRemoting.startSending(); - events.keydown( - new KeyboardEvent('keydown', { code: 'KeyA' })); - expect(dc.send).toHaveBeenCalledWith(expect.any(ArrayBuffer)); - }); - test('keydown repeat', () => { - jest.spyOn(dc, 'send'); - sender.addKeyboard(); - inputRemoting.subscribe(observer); - inputRemoting.startSending(); - events.keydown( - new KeyboardEvent('keydown', { code: 'KeyA', repeat: true })); - expect(dc.send).toHaveBeenCalledWith(expect.any(ArrayBuffer)); - }); - }); - describe('touchscreen', () => { - test('touchstart', () => { - jest.spyOn(dc, 'send'); - sender.addTouchscreen(); - inputRemoting.subscribe(observer); - inputRemoting.startSending(); - events.touchstart( - new TouchEvent("touchstart", { - changedTouches: [{ // InputInit - identifier: 0, - target: null, - clientX: 0, - clientY: 0, - screenX: 0, - screenY: 0, - pageX: 0, - pageY: 0, - radiusX: 0, - radiusY: 0, - rotationAngle: 0, - force: 0, - altitudeAngle: 0, - azimuthAngle:0, - touchType: "direct" - }] - })); - expect(dc.send).toHaveBeenCalledWith(expect.any(ArrayBuffer)); - }); - }); - describe('gamepad', () => { - //todo - }); -}); \ No newline at end of file diff --git a/WebApp/client/test/signaling.test.js b/WebApp/client/test/signaling.test.js deleted file mode 100644 index 5ed9e73..0000000 --- a/WebApp/client/test/signaling.test.js +++ /dev/null @@ -1,484 +0,0 @@ -import { jest } from '@jest/globals'; -import * as Path from 'path'; -import { setup, teardown } from 'jest-dev-server'; -import { Signaling, WebSocketSignaling } from "../src/signaling.js"; -import { MockSignaling, reset } from "./mocksignaling.js"; -import { waitFor, sleep, serverExeName } from "./testutils.js"; - -const portNumber = 8081; -jest.setTimeout(10000); - -describe.each([ - { mode: "mock" }, - { mode: "http" }, - { mode: "websocket" }, -])('signaling test in public mode', ({ mode }) => { - let signaling1; - let signaling2; - const connectionId1 = "12345"; - const connectionId2 = "67890"; - const testsdp = "test sdp"; - const testcandidate = "test candidate"; - - beforeAll(async () => { - if (mode == "mock") { - reset(false); - signaling1 = new MockSignaling(1); - signaling2 = new MockSignaling(1); - } else { - const path = Path.resolve(`../bin~/${serverExeName()}`); - let cmd = `${path} -p ${portNumber}`; - if (mode == "http") { - cmd += " -t http"; - } - - await setup({ command: cmd, port: portNumber, usedPortAction: 'error' }); - - if (mode == "http") { - signaling1 = new Signaling(1); - signaling2 = new Signaling(1); - } - - if (mode == "websocket") { - signaling1 = new WebSocketSignaling(1); - signaling2 = new WebSocketSignaling(1); - } - } - - await signaling1.start(); - await signaling2.start(); - }); - - afterAll(async () => { - await signaling1.stop(); - await signaling2.stop(); - signaling1 = null; - signaling2 = null; - - if (mode == "mock") { - return; - } - - await teardown(); - // work around for linux, waitng kill server process - await sleep(1000); - }); - - test(`onConnect using ${mode}`, async () => { - const signaling1Spy = jest.spyOn(signaling1, 'dispatchEvent'); - let connectRes; - let disconnectRes; - signaling1.addEventListener('connect', (e) => connectRes = e.detail); - signaling1.addEventListener('disconnect', (e) => disconnectRes = e.detail); - - await signaling1.createConnection(connectionId1); - await waitFor(() => connectRes != null); - expect(connectRes.connectionId).toBe(connectionId1); - expect(connectRes.polite).toBe(true); - - await signaling1.deleteConnection(connectionId1); - await waitFor(() => disconnectRes != null); - expect(disconnectRes.connectionId).toBe(connectionId1); - - const disconnectCalledCount = signaling1Spy.mock.calls.map(x => x[0].type).filter(x => x == "disconnect").length; - expect(disconnectCalledCount).toBe(1); - - signaling1Spy.mockRestore(); - }); - - test(`onOffer using ${mode}`, async () => { - let connectRes1; - let disconnectRes1; - signaling1.addEventListener('connect', (e) => connectRes1 = e.detail); - signaling1.addEventListener('disconnect', (e) => disconnectRes1 = e.detail); - - let connectRes2; - let disconnectRes2; - let offerRes2; - signaling2.addEventListener('connect', (e) => connectRes2 = e.detail); - signaling2.addEventListener('disconnect', (e) => disconnectRes2 = e.detail); - signaling2.addEventListener('offer', (e) => offerRes2 = e.detail); - - await signaling1.createConnection(connectionId1); - await signaling2.createConnection(connectionId2); - await waitFor(() => connectRes1 != null && connectRes2 != null); - expect(connectRes1.connectionId).toBe(connectionId1); - expect(connectRes2.connectionId).toBe(connectionId2); - - await signaling1.sendOffer(connectionId1, testsdp); - await waitFor(() => offerRes2 != null); - expect(offerRes2.connectionId).toBe(connectionId1); - expect(offerRes2.polite).toBe(false); - - await signaling1.deleteConnection(connectionId1); - await waitFor(() => disconnectRes1 != null); - expect(disconnectRes1.connectionId).toBe(connectionId1); - await signaling2.deleteConnection(connectionId2); - await waitFor(() => disconnectRes2 != null); - expect(disconnectRes2.connectionId).toBe(connectionId2); - }); - - test(`onAnswer using ${mode}`, async () => { - let connectRes1; - let disconnectRes1; - let answerRes1; - signaling1.addEventListener('connect', (e) => connectRes1 = e.detail); - signaling1.addEventListener('disconnect', (e) => disconnectRes1 = e.detail); - signaling1.addEventListener('answer', (e) => answerRes1 = e.detail); - - let connectRes2; - let disconnectRes2; - let offerRes2; - signaling2.addEventListener('connect', (e) => connectRes2 = e.detail); - signaling2.addEventListener('disconnect', (e) => disconnectRes2 = e.detail); - signaling2.addEventListener('offer', (e) => offerRes2 = e.detail); - - await signaling1.createConnection(connectionId1); - await signaling2.createConnection(connectionId2); - await waitFor(() => connectRes1 != null && connectRes2 != null); - - await signaling1.sendOffer(connectionId1, testsdp); - await waitFor(() => offerRes2 != null); - expect(offerRes2.connectionId).toBe(connectionId1); - expect(offerRes2.sdp).toBe(testsdp); - - signaling2.sendAnswer(connectionId1, testsdp); - await waitFor(() => answerRes1 != null); - expect(answerRes1.connectionId).toBe(connectionId1); - expect(answerRes1.sdp).toBe(testsdp); - - await signaling1.deleteConnection(connectionId1); - await waitFor(() => disconnectRes1 != null); - await signaling2.deleteConnection(connectionId2); - await waitFor(() => disconnectRes2 != null); - }); - - test(`onCandidate using ${mode}`, async () => { - let connectRes1; - let disconnectRes1; - let answerRes1; - let candidateRes1; - signaling1.addEventListener('connect', (e) => connectRes1 = e.detail); - signaling1.addEventListener('disconnect', (e) => disconnectRes1 = e.detail); - signaling1.addEventListener('answer', (e) => answerRes1 = e.detail); - signaling1.addEventListener('candidate', (e) => candidateRes1 = e.detail); - - let connectRes2; - let disconnectRes2; - let offerRes2; - let candidateRes2; - signaling2.addEventListener('connect', (e) => connectRes2 = e.detail); - signaling2.addEventListener('disconnect', (e) => disconnectRes2 = e.detail); - signaling2.addEventListener('offer', (e) => offerRes2 = e.detail); - signaling2.addEventListener('candidate', (e) => candidateRes2 = e.detail); - - await signaling1.createConnection(connectionId1); - await signaling2.createConnection(connectionId2); - await waitFor(() => connectRes1 != null && connectRes2 != null); - - await signaling1.sendOffer(connectionId1, testsdp); - await waitFor(() => offerRes2 != null); - expect(offerRes2.connectionId).toBe(connectionId1); - expect(offerRes2.sdp).toBe(testsdp); - - signaling2.sendAnswer(connectionId1, testsdp); - await waitFor(() => answerRes1 != null); - expect(answerRes1.connectionId).toBe(connectionId1); - expect(answerRes1.sdp).toBe(testsdp); - - await signaling2.sendCandidate(connectionId1, testcandidate, 1, 1); - await waitFor(() => candidateRes1 != null); - expect(candidateRes1.connectionId).toBe(connectionId1); - expect(candidateRes1.candidate).toBe(testcandidate); - expect(candidateRes1.sdpMid).toBe(1); - expect(candidateRes1.sdpMLineIndex).toBe(1); - - await signaling1.sendCandidate(connectionId1, testcandidate, 1, 1); - await waitFor(() => candidateRes2 != null); - expect(candidateRes2.connectionId).toBe(connectionId1); - expect(candidateRes2.candidate).toBe(testcandidate); - expect(candidateRes2.sdpMid).toBe(1); - expect(candidateRes2.sdpMLineIndex).toBe(1); - - await signaling1.deleteConnection(connectionId1); - await waitFor(() => disconnectRes1 != null); - await signaling2.deleteConnection(connectionId2); - await waitFor(() => disconnectRes2 != null); - }); -}); - -describe.each([ - { mode: "mock" }, - { mode: "http" }, - { mode: "websocket" }, -])('signaling test in private mode', ({ mode }) => { - let signaling1; - let signaling2; - const connectionId = "12345"; - const testsdp = "test sdp"; - const testcandidate = "test candidate"; - - beforeAll(async () => { - if (mode == "mock") { - reset(true); - signaling1 = new MockSignaling(1); - signaling2 = new MockSignaling(1); - return; - } - - const path = Path.resolve(`../bin~/${serverExeName()}`); - let cmd = `${path} -p ${portNumber} -m private`; - if (mode == "http") { - cmd += " -t http"; - } - - await setup({ command: cmd, port: portNumber, usedPortAction: 'error' }); - - if (mode == "http") { - signaling1 = new Signaling(1); - signaling2 = new Signaling(1); - } - - if (mode == "websocket") { - signaling1 = new WebSocketSignaling(1); - signaling2 = new WebSocketSignaling(1); - } - - await signaling1.start(); - await signaling2.start(); - }); - - afterAll(async () => { - await signaling1.stop(); - await signaling2.stop(); - signaling1 = null; - signaling2 = null; - - if (mode == "mock") { - return; - } - - await teardown(); - // work around for linux, waitng kill server process - await sleep(1000); - }); - - test(`onConnect using ${mode}`, async () => { - let connectRes1; - let disconnectRes1; - signaling1.addEventListener('connect', (e) => connectRes1 = e.detail); - signaling1.addEventListener('disconnect', (e) => disconnectRes1 = e.detail); - - let connectRes2; - let disconnectRes2; - signaling2.addEventListener('connect', (e) => connectRes2 = e.detail); - signaling2.addEventListener('disconnect', (e) => disconnectRes2 = e.detail); - - await signaling1.createConnection(connectionId); - await waitFor(() => connectRes1 != null); - expect(connectRes1.connectionId).toBe(connectionId); - expect(connectRes1.polite).toBe(false); - - await signaling2.createConnection(connectionId); - await waitFor(() => connectRes2 != null); - expect(connectRes2.connectionId).toBe(connectionId); - expect(connectRes2.polite).toBe(true); - - await sleep(signaling1.interval * 2); - - await signaling1.deleteConnection(connectionId); - await waitFor(() => disconnectRes1 != null && disconnectRes2 != null); - expect(disconnectRes1.connectionId).toBe(connectionId); - expect(disconnectRes2.connectionId).toBe(connectionId); - - disconnectRes2 = null; - await signaling2.deleteConnection(connectionId); - await waitFor(() => disconnectRes2 != null); - }); - - test(`onOffer using ${mode}`, async () => { - let connectRes1; - let disconnectRes1; - signaling1.addEventListener('connect', (e) => connectRes1 = e.detail); - signaling1.addEventListener('disconnect', (e) => disconnectRes1 = e.detail); - - let connectRes2; - let disconnectRes2; - let offerRes2; - signaling2.addEventListener('connect', (e) => connectRes2 = e.detail); - signaling2.addEventListener('disconnect', (e) => disconnectRes2 = e.detail); - signaling2.addEventListener('offer', (e) => offerRes2 = e.detail); - - await signaling1.createConnection(connectionId); - await waitFor(() => connectRes1 != null); - expect(connectRes1.connectionId).toBe(connectionId); - - signaling1.sendOffer(connectionId, testsdp); - await sleep(signaling1.interval * 2); - // Do not receive offer other signaling if not connected same sendoffer connectionId in private mode - expect(offerRes2).toBeUndefined(); - - await signaling2.createConnection(connectionId); - await waitFor(() => connectRes2 != null); - expect(connectRes2.connectionId).toBe(connectionId); - - await signaling1.sendOffer(connectionId, testsdp); - await waitFor(() => offerRes2 != null); - expect(offerRes2.connectionId).toBe(connectionId); - expect(offerRes2.polite).toBe(true); - - await signaling1.deleteConnection(connectionId); - await waitFor(() => disconnectRes1 != null && disconnectRes2 != null); - expect(disconnectRes1.connectionId).toBe(connectionId); - expect(disconnectRes2.connectionId).toBe(connectionId); - - disconnectRes2 = null; - await signaling2.deleteConnection(connectionId); - await waitFor(() => disconnectRes2 != null); - }); - - test(`onAnswer using ${mode}`, async () => { - let connectRes1; - let disconnectRes1; - let answerRes1; - signaling1.addEventListener('connect', (e) => connectRes1 = e.detail); - signaling1.addEventListener('disconnect', (e) => disconnectRes1 = e.detail); - signaling1.addEventListener('answer', (e) => answerRes1 = e.detail); - - let connectRes2; - let disconnectRes2; - let offerRes2; - signaling2.addEventListener('connect', (e) => connectRes2 = e.detail); - signaling2.addEventListener('disconnect', (e) => disconnectRes2 = e.detail); - signaling2.addEventListener('offer', (e) => offerRes2 = e.detail); - - await signaling1.createConnection(connectionId); - await signaling2.createConnection(connectionId); - await waitFor(() => connectRes1 != null && connectRes2 != null); - - await signaling1.sendOffer(connectionId, testsdp); - await waitFor(() => offerRes2 != null); - expect(offerRes2.connectionId).toBe(connectionId); - expect(offerRes2.sdp).toBe(testsdp); - - await signaling2.sendAnswer(connectionId, testsdp); - await waitFor(() => answerRes1 != null); - expect(answerRes1.connectionId).toBe(connectionId); - expect(answerRes1.sdp).toBe(testsdp); - - await signaling1.deleteConnection(connectionId); - await waitFor(() => disconnectRes1 != null && disconnectRes2 != null); - expect(disconnectRes1.connectionId).toBe(connectionId); - expect(disconnectRes2.connectionId).toBe(connectionId); - - disconnectRes2 = null; - await signaling2.deleteConnection(connectionId); - await waitFor(() => disconnectRes2 != null); - }); - - test(`onCandidate using ${mode}`, async () => { - let connectRes1; - let disconnectRes1; - let answerRes1; - let candidateRes1; - signaling1.addEventListener('connect', (e) => connectRes1 = e.detail); - signaling1.addEventListener('disconnect', (e) => disconnectRes1 = e.detail); - signaling1.addEventListener('answer', (e) => answerRes1 = e.detail); - signaling1.addEventListener('candidate', (e) => candidateRes1 = e.detail); - - let connectRes2; - let disconnectRes2; - let offerRes2; - let candidateRes2; - signaling2.addEventListener('connect', (e) => connectRes2 = e.detail); - signaling2.addEventListener('disconnect', (e) => disconnectRes2 = e.detail); - signaling2.addEventListener('offer', (e) => offerRes2 = e.detail); - signaling2.addEventListener('candidate', (e) => candidateRes2 = e.detail); - - await signaling1.createConnection(connectionId); - await signaling2.createConnection(connectionId); - await waitFor(() => connectRes1 != null && connectRes2 != null); - - await signaling1.sendOffer(connectionId, testsdp); - await waitFor(() => offerRes2 != null); - expect(offerRes2.connectionId).toBe(connectionId); - expect(offerRes2.sdp).toBe(testsdp); - - await signaling2.sendAnswer(connectionId, testsdp); - await waitFor(() => answerRes1 != null); - expect(answerRes1.connectionId).toBe(connectionId); - expect(answerRes1.sdp).toBe(testsdp); - - await signaling2.sendCandidate(connectionId, testcandidate, 1, 1); - await waitFor(() => candidateRes1 != null); - expect(candidateRes1.connectionId).toBe(connectionId); - expect(candidateRes1.candidate).toBe(testcandidate); - expect(candidateRes1.sdpMLineIndex).toBe(1); - expect(candidateRes1.sdpMid).toBe(1); - - await signaling1.sendCandidate(connectionId, testcandidate, 1, 1); - await waitFor(() => candidateRes2 != null); - expect(candidateRes2.connectionId).toBe(connectionId); - expect(candidateRes2.candidate).toBe(testcandidate); - expect(candidateRes2.sdpMLineIndex).toBe(1); - expect(candidateRes2.sdpMid).toBe(1); - - await signaling1.deleteConnection(connectionId); - await waitFor(() => disconnectRes1 != null && disconnectRes2 != null); - expect(disconnectRes1.connectionId).toBe(connectionId); - expect(disconnectRes2.connectionId).toBe(connectionId); - - disconnectRes2 = null; - await signaling2.deleteConnection(connectionId); - await waitFor(() => disconnectRes2 != null); - }); - - test(`notReceiveOwnOfferAnswer using ${mode}`, async () => { - let connectRes1; - let disconnectRes1; - let offerRes1; - let answerRes1; - signaling1.addEventListener('connect', (e) => connectRes1 = e.detail); - signaling1.addEventListener('disconnect', (e) => disconnectRes1 = e.detail); - - let connectRes2; - let disconnectRes2; - let offerRes2; - let answerRes2; - signaling2.addEventListener('connect', (e) => connectRes2 = e.detail); - signaling2.addEventListener('disconnect', (e) => disconnectRes2 = e.detail); - - await signaling1.createConnection(connectionId); - await signaling2.createConnection(connectionId); - await waitFor(() => connectRes1 != null && connectRes2 != null); - - signaling1.addEventListener('offer', (e) => offerRes1 = e.detail); - signaling2.addEventListener('offer', (e) => offerRes2 = e.detail); - await signaling1.sendOffer(connectionId, testsdp); - await waitFor(() => offerRes2 != null); - await sleep(signaling1.interval * 2); - expect(offerRes1).toBeUndefined(); - expect(offerRes2).not.toBeUndefined(); - expect(offerRes2.connectionId).toBe(connectionId); - expect(offerRes2.sdp).toBe(testsdp); - - signaling1.addEventListener('answer', (e) => answerRes1 = e.detail); - signaling2.addEventListener('answer', (e) => answerRes2 = e.detail); - await signaling2.sendAnswer(connectionId, testsdp); - await waitFor(() => answerRes1 != null); - await sleep(signaling2.interval * 2); - expect(answerRes1).not.toBeUndefined(); - expect(answerRes1.connectionId).toBe(connectionId); - expect(answerRes1.sdp).toBe(testsdp); - expect(answerRes2).toBeUndefined(); - - await signaling1.deleteConnection(connectionId); - await waitFor(() => disconnectRes1 != null && disconnectRes2 != null); - expect(disconnectRes1.connectionId).toBe(connectionId); - expect(disconnectRes2.connectionId).toBe(connectionId); - - disconnectRes2 = null; - await signaling2.deleteConnection(connectionId); - await waitFor(() => disconnectRes2 != null); - }); -}); diff --git a/WebApp/client/test/testutils.js b/WebApp/client/test/testutils.js deleted file mode 100644 index 80f60db..0000000 --- a/WebApp/client/test/testutils.js +++ /dev/null @@ -1,39 +0,0 @@ -import process from "process"; - -export function waitFor(conditionFunction) { - - const poll = resolve => { - if (conditionFunction()) resolve(); - else setTimeout(() => poll(resolve), 100); - }; - - return new Promise(poll); -} - -export async function sleep(milisecond) { - return new Promise(resolve => setTimeout(resolve, milisecond)); -} - -export function serverExeName() { - switch (process.platform) { - case 'win32': - return 'webserver.exe'; - case 'darwin': - return 'webserver_mac'; - case 'linux': - return 'webserver'; - default: - return null; - } -} - -export function getUniqueId() { - return new Date().getTime().toString(16) + Math.floor(1000 * Math.random()).toString(16); -} - -export function getRTCConfiguration() { - let config = {}; - config.sdpSemantics = 'unified-plan'; - config.iceServers = [{ urls: ['stun:stun.l.google.com:19302'] }]; - return config; -} \ No newline at end of file diff --git a/WebApp/jest.config.js b/WebApp/jest.config.js deleted file mode 100644 index 886ea2b..0000000 --- a/WebApp/jest.config.js +++ /dev/null @@ -1,195 +0,0 @@ -/* - * For a detailed explanation regarding each configuration property, visit: - * https://jestjs.io/docs/configuration - */ - -module.exports = { - // All imported modules in your tests should be mocked automatically - // automock: false, - - // Stop running tests after `n` failures - // bail: 0, - - // The directory where Jest should store its cached dependency information - // cacheDirectory: "/private/var/folders/wt/swsbjj0x061bdb0y4dqc0g4c0000gn/T/jest_dx", - - // Automatically clear mock calls and instances between every test - // clearMocks: false, - - // Indicates whether the coverage information should be collected while executing the test - collectCoverage: true, - - // An array of glob patterns indicating a set of files for which coverage information should be collected - // collectCoverageFrom: undefined, - - // The directory where Jest should output its coverage files - coverageDirectory: "coverage", - - // An array of regexp pattern strings used to skip coverage collection - // coveragePathIgnorePatterns: [ - // "/node_modules/" - // ], - - // Indicates which provider should be used to instrument code for coverage - coverageProvider: "v8", - - // A list of reporter names that Jest uses when writing coverage reports - // coverageReporters: [ - // "json", - // "text", - // "lcov", - // "clover" - // ], - - // An object that configures minimum threshold enforcement for coverage results - // coverageThreshold: undefined, - - // A path to a custom dependency extractor - // dependencyExtractor: undefined, - - // Make calling deprecated APIs throw helpful error messages - // errorOnDeprecated: false, - - // Force coverage collection from ignored files using an array of glob patterns - // forceCoverageMatch: [], - - // A path to a module which exports an async function that is triggered once before all test suites - // globalSetup: undefined, - - // A path to a module which exports an async function that is triggered once after all test suites - // globalTeardown: undefined, - - // A set of global variables that need to be available in all test environments - // globals: {}, - - // The maximum amount of workers used to run your tests. Can be specified as % or a number. E.g. maxWorkers: 10% will use 10% of your CPU amount + 1 as the maximum worker number. maxWorkers: 2 will use a maximum of 2 workers. - // maxWorkers: "50%", - - // An array of directory names to be searched recursively up from the requiring module's location - // moduleDirectories: [ - // "node_modules" - // ], - - // An array of file extensions your modules use - moduleFileExtensions: [ - "js", - "jsx", - "ts", - "tsx", - "json", - "node" - ], - - // A map from regular expressions to module names or to arrays of module names that allow to stub out resources with a single module - // moduleNameMapper: {}, - - // An array of regexp pattern strings, matched against all module paths before considered 'visible' to the module loader - // modulePathIgnorePatterns: [], - - // Activates notifications for test results - // notify: false, - - // An enum that specifies notification mode. Requires { notify: true } - // notifyMode: "failure-change", - - // A preset that is used as a base for Jest's configuration - // preset: undefined, - - // Run tests from one or more projects - // projects: undefined, - - // Use this configuration option to add custom reporters to Jest - // reporters: undefined, - - // Automatically reset mock state between every test - // resetMocks: false, - - // Reset the module registry before running each individual test - // resetModules: false, - - // A path to a custom resolver - // resolver: undefined, - - // Automatically restore mock state between every test - // restoreMocks: false, - - // The root directory that Jest should scan for tests and modules within - // rootDir: undefined, - - // A list of paths to directories that Jest should use to search for files in - // roots: [ - // "" - // ], - - // Allows you to use a custom runner instead of Jest's default test runner - // runner: "jest-runner", - - // The paths to modules that run some code to configure or set up the testing environment before each test - // setupFiles: [], - - // A list of paths to modules that run some code to configure or set up the testing framework before each test - // setupFilesAfterEnv: [], - - // The number of seconds after which a test is considered as slow and reported as such in the results. - // slowTestThreshold: 5, - - // A list of paths to snapshot serializer modules Jest should use for snapshot testing - // snapshotSerializers: [], - - // The test environment that will be used for testing - testEnvironment: "node", - - // Options that will be passed to the testEnvironment - testEnvironmentOptions: { - url: "http://localhost" - }, - - // Adds a location field to test results - // testLocationInResults: false, - - // The glob patterns Jest uses to detect test files - testMatch: [ - "**/__tests__/**/*.[jt]s?(x)", - "**/?(*.)+(spec|test).[tj]s?(x)" - ], - - // An array of regexp pattern strings that are matched against all test paths, matched tests are skipped - // testPathIgnorePatterns: [ - // "/node_modules/" - // ], - - // The regexp pattern or array of patterns that Jest uses to detect test files - // testRegex: [], - - // This option allows the use of a custom results processor - // testResultsProcessor: undefined, - - // This option allows use of a custom test runner - // testRunner: "jest-circus/runner", - - // Setting this value to "fake" allows the use of fake timers for functions such as "setTimeout" - // timers: "real", - - // A map from regular expressions to paths to transformers - transform: { - '^.+\\.tsx?$': 'ts-jest' - }, - - // An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation - // transformIgnorePatterns: [ - // "/node_modules/", - // "\\.pnp\\.[^\\/]+$" - // ], - - // An array of regexp pattern strings that are matched against all modules before the module loader will automatically return a mock for them - // unmockedModulePathPatterns: undefined, - - // Indicates whether each individual test should be reported during the run - // verbose: undefined, - - // An array of regexp patterns that are matched against all source file paths before re-running tests in watch mode - // watchPathIgnorePatterns: [], - - // Whether to use watchman for file crawling - // watchman: true, -}; diff --git a/WebApp/package-lock.json b/WebApp/package-lock.json deleted file mode 100644 index 4679f12..0000000 --- a/WebApp/package-lock.json +++ /dev/null @@ -1,15324 +0,0 @@ -{ - "name": "webserver", - "version": "3.1.0", - "lockfileVersion": 2, - "requires": true, - "packages": { - "": { - "name": "webserver", - "version": "3.1.0", - "dependencies": { - "@types/express": "^4.17.13", - "@types/node": "^18.7.15", - "@types/ws": "^8.5.3", - "cors": "^2.8.5", - "debug": "~4.3.4", - "express": "~4.18.1", - "morgan": "^1.10.0", - "multer": "^2.1.1", - "swagger-jsdoc": "^6.2.1", - "swagger-ui-express": "^4.5.0", - "uuid": "^9.0.0", - "ws": "^8.8.1" - }, - "bin": { - "webserver": "build/index.js" - }, - "devDependencies": { - "@jest-mock/express": "^2.0.1", - "@types/jest": "^29.0.2", - "@types/morgan": "^1.9.3", - "@types/swagger-jsdoc": "^6.0.1", - "@types/swagger-ui-express": "^4.1.3", - "@typescript-eslint/eslint-plugin": "^5.36.2", - "@typescript-eslint/parser": "^5.36.2", - "eslint": "^8.23.0", - "eslint-plugin-jest": "^27.0.1", - "jest": "^29.0.2", - "jest-websocket-mock": "^2.4.0", - "mock-socket": "^9.1.5", - "newman": "^6.0.0", - "pkg": "^5.8.0", - "ts-jest": "^29.0.2", - "ts-node": "^10.9.1", - "typescript": "^4.8.2" - } - }, - "node_modules/@ampproject/remapping": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", - "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", - "dev": true, - "dependencies": { - "@jridgewell/gen-mapping": "^0.1.0", - "@jridgewell/trace-mapping": "^0.3.9" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@apidevtools/json-schema-ref-parser": { - "version": "9.1.2", - "resolved": "https://registry.npmjs.org/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-9.1.2.tgz", - "integrity": "sha512-r1w81DpR+KyRWd3f+rk6TNqMgedmAxZP5v5KWlXQWlgMUUtyEJch0DKEci1SorPMiSeM8XPl7MZ3miJ60JIpQg==", - "dependencies": { - "@jsdevtools/ono": "^7.1.3", - "@types/json-schema": "^7.0.6", - "call-me-maybe": "^1.0.1", - "js-yaml": "^4.1.0" - } - }, - "node_modules/@apidevtools/openapi-schemas": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@apidevtools/openapi-schemas/-/openapi-schemas-2.1.0.tgz", - "integrity": "sha512-Zc1AlqrJlX3SlpupFGpiLi2EbteyP7fXmUOGup6/DnkRgjP9bgMM/ag+n91rsv0U1Gpz0H3VILA/o3bW7Ua6BQ==", - "engines": { - "node": ">=10" - } - }, - "node_modules/@apidevtools/swagger-methods": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@apidevtools/swagger-methods/-/swagger-methods-3.0.2.tgz", - "integrity": "sha512-QAkD5kK2b1WfjDS/UQn/qQkbwF31uqRjPTrsCs5ZG9BQGAkjwvqGFjjPqAuzac/IYzpPtRzjCP1WrTuAIjMrXg==" - }, - "node_modules/@apidevtools/swagger-parser": { - "version": "10.0.3", - "resolved": "https://registry.npmjs.org/@apidevtools/swagger-parser/-/swagger-parser-10.0.3.tgz", - "integrity": "sha512-sNiLY51vZOmSPFZA5TF35KZ2HbgYklQnTSDnkghamzLb3EkNtcQnrBQEj5AOCxHpTtXpqMCRM1CrmV2rG6nw4g==", - "dependencies": { - "@apidevtools/json-schema-ref-parser": "^9.0.6", - "@apidevtools/openapi-schemas": "^2.0.4", - "@apidevtools/swagger-methods": "^3.0.2", - "@jsdevtools/ono": "^7.1.3", - "call-me-maybe": "^1.0.1", - "z-schema": "^5.0.1" - }, - "peerDependencies": { - "openapi-types": ">=7" - } - }, - "node_modules/@babel/code-frame": { - "version": "7.22.13", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", - "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", - "dev": true, - "dependencies": { - "@babel/highlight": "^7.22.13", - "chalk": "^2.4.2" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/code-frame/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/code-frame/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/code-frame/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/@babel/code-frame/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, - "node_modules/@babel/code-frame/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/@babel/code-frame/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/code-frame/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/compat-data": { - "version": "7.17.10", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.17.10.tgz", - "integrity": "sha512-GZt/TCsG70Ms19gfZO1tM4CVnXsPgEPBCpJu+Qz3L0LUDsY5nZqFZglIoPC1kIYOtNBZlrnFT+klg12vFGZXrw==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/core": { - "version": "7.18.2", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.18.2.tgz", - "integrity": "sha512-A8pri1YJiC5UnkdrWcmfZTJTV85b4UXTAfImGmCfYmax4TR9Cw8sDS0MOk++Gp2mE/BefVJ5nwy5yzqNJbP/DQ==", - "dev": true, - "dependencies": { - "@ampproject/remapping": "^2.1.0", - "@babel/code-frame": "^7.16.7", - "@babel/generator": "^7.18.2", - "@babel/helper-compilation-targets": "^7.18.2", - "@babel/helper-module-transforms": "^7.18.0", - "@babel/helpers": "^7.18.2", - "@babel/parser": "^7.18.0", - "@babel/template": "^7.16.7", - "@babel/traverse": "^7.18.2", - "@babel/types": "^7.18.2", - "convert-source-map": "^1.7.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.1", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" - } - }, - "node_modules/@babel/core/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@babel/generator": { - "version": "7.18.2", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.18.2.tgz", - "integrity": "sha512-W1lG5vUwFvfMd8HVXqdfbuG7RuaSrTCCD8cl8fP8wOivdbtbIg2Db3IWUcgvfxKbbn6ZBGYRW/Zk1MIwK49mgw==", - "dev": true, - "dependencies": { - "@babel/types": "^7.18.2", - "@jridgewell/gen-mapping": "^0.3.0", - "jsesc": "^2.5.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/generator/node_modules/@jridgewell/gen-mapping": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.1.tgz", - "integrity": "sha512-GcHwniMlA2z+WFPWuY8lp3fsza0I8xPFMWL5+n8LYyP6PSvPrXf4+n8stDHZY2DM0zy9sVkRDy1jDI4XGzYVqg==", - "dev": true, - "dependencies": { - "@jridgewell/set-array": "^1.0.0", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/helper-compilation-targets": { - "version": "7.18.2", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.18.2.tgz", - "integrity": "sha512-s1jnPotJS9uQnzFtiZVBUxe67CuBa679oWFHpxYYnTpRL/1ffhyX44R9uYiXoa/pLXcY9H2moJta0iaanlk/rQ==", - "dev": true, - "dependencies": { - "@babel/compat-data": "^7.17.10", - "@babel/helper-validator-option": "^7.16.7", - "browserslist": "^4.20.2", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-compilation-targets/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@babel/helper-environment-visitor": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", - "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-function-name": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", - "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", - "dev": true, - "dependencies": { - "@babel/template": "^7.22.15", - "@babel/types": "^7.23.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-function-name/node_modules/@babel/types": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz", - "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==", - "dev": true, - "dependencies": { - "@babel/helper-string-parser": "^7.22.5", - "@babel/helper-validator-identifier": "^7.22.20", - "to-fast-properties": "^2.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-hoist-variables": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", - "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", - "dev": true, - "dependencies": { - "@babel/types": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-hoist-variables/node_modules/@babel/types": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz", - "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==", - "dev": true, - "dependencies": { - "@babel/helper-string-parser": "^7.22.5", - "@babel/helper-validator-identifier": "^7.22.20", - "to-fast-properties": "^2.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-imports": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz", - "integrity": "sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg==", - "dev": true, - "dependencies": { - "@babel/types": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-transforms": { - "version": "7.18.0", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.18.0.tgz", - "integrity": "sha512-kclUYSUBIjlvnzN2++K9f2qzYKFgjmnmjwL4zlmU5f8ZtzgWe8s0rUPSTGy2HmK4P8T52MQsS+HTQAgZd3dMEA==", - "dev": true, - "dependencies": { - "@babel/helper-environment-visitor": "^7.16.7", - "@babel/helper-module-imports": "^7.16.7", - "@babel/helper-simple-access": "^7.17.7", - "@babel/helper-split-export-declaration": "^7.16.7", - "@babel/helper-validator-identifier": "^7.16.7", - "@babel/template": "^7.16.7", - "@babel/traverse": "^7.18.0", - "@babel/types": "^7.18.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-plugin-utils": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.19.0.tgz", - "integrity": "sha512-40Ryx7I8mT+0gaNxm8JGTZFUITNqdLAgdg0hXzeVZxVD6nFsdhQvip6v8dqkRHzsz1VFpFAaOCHNn0vKBL7Czw==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-simple-access": { - "version": "7.18.2", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.18.2.tgz", - "integrity": "sha512-7LIrjYzndorDY88MycupkpQLKS1AFfsVRm2k/9PtKScSy5tZq0McZTj+DiMRynboZfIqOKvo03pmhTaUgiD6fQ==", - "dev": true, - "dependencies": { - "@babel/types": "^7.18.2" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-split-export-declaration": { - "version": "7.22.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", - "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", - "dev": true, - "dependencies": { - "@babel/types": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-split-export-declaration/node_modules/@babel/types": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz", - "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==", - "dev": true, - "dependencies": { - "@babel/helper-string-parser": "^7.22.5", - "@babel/helper-validator-identifier": "^7.22.20", - "to-fast-properties": "^2.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-string-parser": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz", - "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", - "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-option": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.16.7.tgz", - "integrity": "sha512-TRtenOuRUVo9oIQGPC5G9DgK4743cdxvtOw0weQNpZXaS16SCBi5MNjZF8vba3ETURjZpTbVn7Vvcf2eAwFozQ==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helpers": { - "version": "7.18.2", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.18.2.tgz", - "integrity": "sha512-j+d+u5xT5utcQSzrh9p+PaJX94h++KN+ng9b9WEJq7pkUPAd61FGqhjuUEdfknb3E/uDBb7ruwEeKkIxNJPIrg==", - "dev": true, - "dependencies": { - "@babel/template": "^7.16.7", - "@babel/traverse": "^7.18.2", - "@babel/types": "^7.18.2" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz", - "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==", - "dev": true, - "dependencies": { - "@babel/helper-validator-identifier": "^7.22.20", - "chalk": "^2.4.2", - "js-tokens": "^4.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/@babel/highlight/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, - "node_modules/@babel/highlight/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/@babel/highlight/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/parser": { - "version": "7.18.4", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.18.4.tgz", - "integrity": "sha512-FDge0dFazETFcxGw/EXzOkN8uJp0PC7Qbm+Pe9T+av2zlBpOgunFHkQPPn+eRuClU73JF+98D531UgayY89tow==", - "dev": true, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/plugin-syntax-async-generators": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", - "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-bigint": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", - "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-class-properties": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", - "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.12.13" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-import-meta": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", - "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-json-strings": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", - "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-jsx": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.18.6.tgz", - "integrity": "sha512-6mmljtAedFGTWu2p/8WIORGwy+61PLgOMPOdazc7YoJ9ZCWUyFy3A6CpPkRKLKD1ToAesxX8KGEViAiLo9N+7Q==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-logical-assignment-operators": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", - "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", - "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-numeric-separator": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", - "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-object-rest-spread": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", - "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-optional-catch-binding": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", - "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-optional-chaining": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", - "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-top-level-await": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", - "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-typescript": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.18.6.tgz", - "integrity": "sha512-mAWAuq4rvOepWCBid55JuRNvpTNf2UGVgoz4JV0fXEKolsVZDzsa4NqCef758WZJj/GDu0gVGItjKFiClTAmZA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/template": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", - "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.22.13", - "@babel/parser": "^7.22.15", - "@babel/types": "^7.22.15" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/template/node_modules/@babel/parser": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz", - "integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==", - "dev": true, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/template/node_modules/@babel/types": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz", - "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==", - "dev": true, - "dependencies": { - "@babel/helper-string-parser": "^7.22.5", - "@babel/helper-validator-identifier": "^7.22.20", - "to-fast-properties": "^2.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse": { - "version": "7.23.2", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz", - "integrity": "sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.22.13", - "@babel/generator": "^7.23.0", - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-function-name": "^7.23.0", - "@babel/helper-hoist-variables": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/parser": "^7.23.0", - "@babel/types": "^7.23.0", - "debug": "^4.1.0", - "globals": "^11.1.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse/node_modules/@babel/generator": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz", - "integrity": "sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==", - "dev": true, - "dependencies": { - "@babel/types": "^7.23.0", - "@jridgewell/gen-mapping": "^0.3.2", - "@jridgewell/trace-mapping": "^0.3.17", - "jsesc": "^2.5.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse/node_modules/@babel/parser": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz", - "integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==", - "dev": true, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/traverse/node_modules/@babel/types": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz", - "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==", - "dev": true, - "dependencies": { - "@babel/helper-string-parser": "^7.22.5", - "@babel/helper-validator-identifier": "^7.22.20", - "to-fast-properties": "^2.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse/node_modules/@jridgewell/gen-mapping": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", - "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", - "dev": true, - "dependencies": { - "@jridgewell/set-array": "^1.0.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/traverse/node_modules/globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/types": { - "version": "7.18.4", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.18.4.tgz", - "integrity": "sha512-ThN1mBcMq5pG/Vm2IcBmPPfyPXbd8S02rS+OBIDENdufvqC7Z/jHPCv9IcP01277aKtDI8g/2XysBN4hA8niiw==", - "dev": true, - "dependencies": { - "@babel/helper-validator-identifier": "^7.16.7", - "to-fast-properties": "^2.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@bcoe/v8-coverage": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", - "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", - "dev": true - }, - "node_modules/@colors/colors": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", - "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", - "dev": true, - "optional": true, - "engines": { - "node": ">=0.1.90" - } - }, - "node_modules/@cspotcode/source-map-support": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", - "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", - "dev": true, - "dependencies": { - "@jridgewell/trace-mapping": "0.3.9" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", - "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", - "dev": true, - "dependencies": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" - } - }, - "node_modules/@eslint/eslintrc": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.1.tgz", - "integrity": "sha512-OhSY22oQQdw3zgPOOwdoj01l/Dzl1Z+xyUP33tkSN+aqyEhymJCcPHyXt+ylW8FSe0TfRC2VG+ROQOapD0aZSQ==", - "dev": true, - "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.4.0", - "globals": "^13.15.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@faker-js/faker": { - "version": "5.5.3", - "resolved": "https://registry.npmjs.org/@faker-js/faker/-/faker-5.5.3.tgz", - "integrity": "sha512-R11tGE6yIFwqpaIqcfkcg7AICXzFg14+5h5v0TfF/9+RMDL6jhzCy/pxHVOfbALGdtVYdt6JdR21tuxEgl34dw==", - "dev": true - }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.10.4", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.10.4.tgz", - "integrity": "sha512-mXAIHxZT3Vcpg83opl1wGlVZ9xydbfZO3r5YfRSH6Gpp2J/PfdBP0wbDa2sO6/qRbcalpoevVyW6A/fI6LfeMw==", - "dev": true, - "dependencies": { - "@humanwhocodes/object-schema": "^1.2.1", - "debug": "^4.1.1", - "minimatch": "^3.0.4" - }, - "engines": { - "node": ">=10.10.0" - } - }, - "node_modules/@humanwhocodes/gitignore-to-minimatch": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@humanwhocodes/gitignore-to-minimatch/-/gitignore-to-minimatch-1.0.2.tgz", - "integrity": "sha512-rSqmMJDdLFUsyxR6FMtD00nfQKKLFb1kv+qBbOVKqErvloEIJLo5bDTJTQNTYgeyp78JsA7u/NPi5jT1GR/MuA==", - "dev": true, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "dev": true, - "engines": { - "node": ">=12.22" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@humanwhocodes/object-schema": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", - "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", - "dev": true - }, - "node_modules/@istanbuljs/load-nyc-config": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", - "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", - "dev": true, - "dependencies": { - "camelcase": "^5.3.1", - "find-up": "^4.1.0", - "get-package-type": "^0.1.0", - "js-yaml": "^3.13.1", - "resolve-from": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "dependencies": { - "sprintf-js": "~1.0.2" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "dev": true, - "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/schema": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", - "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest-mock/express": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@jest-mock/express/-/express-2.0.1.tgz", - "integrity": "sha512-DvW4WMGoNBEOGx1XRCe8yZyQ7ju5dWmBN57H0zPio7AqQo27QawI+o30f9xVdLnS0bAF2wbmQQfS61LxL/t8bQ==", - "dev": true, - "dependencies": { - "@types/express": "^4.17.13" - } - }, - "node_modules/@jest/console": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.0.2.tgz", - "integrity": "sha512-Fv02ijyhF4D/Wb3DvZO3iBJQz5DnzpJEIDBDbvje8Em099N889tNMUnBw7SalmSuOI+NflNG40RA1iK71kImPw==", - "dev": true, - "dependencies": { - "@jest/types": "^29.0.2", - "@types/node": "*", - "chalk": "^4.0.0", - "jest-message-util": "^29.0.2", - "jest-util": "^29.0.2", - "slash": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/core": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.0.2.tgz", - "integrity": "sha512-imP5M6cdpHEOkmcuFYZuM5cTG1DAF7ZlVNCq1+F7kbqme2Jcl+Kh4M78hihM76DJHNkurbv4UVOnejGxBKEmww==", - "dev": true, - "dependencies": { - "@jest/console": "^29.0.2", - "@jest/reporters": "^29.0.2", - "@jest/test-result": "^29.0.2", - "@jest/transform": "^29.0.2", - "@jest/types": "^29.0.2", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.9", - "jest-changed-files": "^29.0.0", - "jest-config": "^29.0.2", - "jest-haste-map": "^29.0.2", - "jest-message-util": "^29.0.2", - "jest-regex-util": "^29.0.0", - "jest-resolve": "^29.0.2", - "jest-resolve-dependencies": "^29.0.2", - "jest-runner": "^29.0.2", - "jest-runtime": "^29.0.2", - "jest-snapshot": "^29.0.2", - "jest-util": "^29.0.2", - "jest-validate": "^29.0.2", - "jest-watcher": "^29.0.2", - "micromatch": "^4.0.4", - "pretty-format": "^29.0.2", - "slash": "^3.0.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "node_modules/@jest/core/node_modules/@jest/transform": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.0.2.tgz", - "integrity": "sha512-lajVQx2AnsR+Pa17q2zR7eikz2PkPs1+g/qPbZkqQATeS/s6eT55H+yHcsLfuI/0YQ/4VSBepSu3bOX+44q0aA==", - "dev": true, - "dependencies": { - "@babel/core": "^7.11.6", - "@jest/types": "^29.0.2", - "@jridgewell/trace-mapping": "^0.3.15", - "babel-plugin-istanbul": "^6.1.1", - "chalk": "^4.0.0", - "convert-source-map": "^1.4.0", - "fast-json-stable-stringify": "^2.1.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.0.2", - "jest-regex-util": "^29.0.0", - "jest-util": "^29.0.2", - "micromatch": "^4.0.4", - "pirates": "^4.0.4", - "slash": "^3.0.0", - "write-file-atomic": "^4.0.1" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/core/node_modules/jest-haste-map": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.0.2.tgz", - "integrity": "sha512-SOorh2ysQ0fe8gsF4gaUDhoMIWAvi2hXOkwThEO48qT3JqA8GLAUieQcIvdSEd6M0scRDe1PVmKc5tXR3Z0U0A==", - "dev": true, - "dependencies": { - "@jest/types": "^29.0.2", - "@types/graceful-fs": "^4.1.3", - "@types/node": "*", - "anymatch": "^3.0.3", - "fb-watchman": "^2.0.0", - "graceful-fs": "^4.2.9", - "jest-regex-util": "^29.0.0", - "jest-util": "^29.0.2", - "jest-worker": "^29.0.2", - "micromatch": "^4.0.4", - "walker": "^1.0.8" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "optionalDependencies": { - "fsevents": "^2.3.2" - } - }, - "node_modules/@jest/core/node_modules/jest-regex-util": { - "version": "29.0.0", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.0.0.tgz", - "integrity": "sha512-BV7VW7Sy0fInHWN93MMPtlClweYv2qrSCwfeFWmpribGZtQPWNvRSq9XOVgOEjU1iBGRKXUZil0o2AH7Iy9Lug==", - "dev": true, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/core/node_modules/jest-worker": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.0.2.tgz", - "integrity": "sha512-EyvBlYcvd2pg28yg5A3OODQnqK9LI1kitnGUZUG5/NYIeaRgewtYBKB5wlr7oXj8zPCkzev7EmnTCsrXK7V+Xw==", - "dev": true, - "dependencies": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/core/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "node_modules/@jest/environment": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.0.2.tgz", - "integrity": "sha512-Yf+EYaLOrVCgts/aTS5nGznU4prZUPa5k9S63Yct8YSOKj2jkdS17hHSUKhk5jxDFMyCy1PXknypDw7vfgc/mA==", - "dev": true, - "dependencies": { - "@jest/fake-timers": "^29.0.2", - "@jest/types": "^29.0.2", - "@types/node": "*", - "jest-mock": "^29.0.2" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/expect": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.0.2.tgz", - "integrity": "sha512-y/3geZ92p2/zovBm/F+ZjXUJ3thvT9IRzD6igqaWskFE2aR0idD+N/p5Lj/ZautEox/9RwEc6nqergebeh72uQ==", - "dev": true, - "dependencies": { - "expect": "^29.0.2", - "jest-snapshot": "^29.0.2" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/expect-utils": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.0.2.tgz", - "integrity": "sha512-+wcQF9khXKvAEi8VwROnCWWmHfsJYCZAs5dmuMlJBKk57S6ZN2/FQMIlo01F29fJyT8kV/xblE7g3vkIdTLOjw==", - "dev": true, - "dependencies": { - "jest-get-type": "^29.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/fake-timers": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.0.2.tgz", - "integrity": "sha512-2JhQeWU28fvmM5r33lxg6BxxkTKaVXs6KMaJ6eXSM8ml/MaWkt2BvbIO8G9KWAJFMdBXWbn+2h9OK1/s5urKZA==", - "dev": true, - "dependencies": { - "@jest/types": "^29.0.2", - "@sinonjs/fake-timers": "^9.1.2", - "@types/node": "*", - "jest-message-util": "^29.0.2", - "jest-mock": "^29.0.2", - "jest-util": "^29.0.2" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/globals": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.0.2.tgz", - "integrity": "sha512-4hcooSNJCVXuTu07/VJwCWW6HTnjLtQdqlcGisK6JST7z2ixa8emw4SkYsOk7j36WRc2ZUEydlUePnOIOTCNXg==", - "dev": true, - "dependencies": { - "@jest/environment": "^29.0.2", - "@jest/expect": "^29.0.2", - "@jest/types": "^29.0.2", - "jest-mock": "^29.0.2" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/reporters": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.0.2.tgz", - "integrity": "sha512-Kr41qejRQHHkCgWHC9YwSe7D5xivqP4XML+PvgwsnRFaykKdNflDUb4+xLXySOU+O/bPkVdFpGzUpVNSJChCrw==", - "dev": true, - "dependencies": { - "@bcoe/v8-coverage": "^0.2.3", - "@jest/console": "^29.0.2", - "@jest/test-result": "^29.0.2", - "@jest/transform": "^29.0.2", - "@jest/types": "^29.0.2", - "@jridgewell/trace-mapping": "^0.3.15", - "@types/node": "*", - "chalk": "^4.0.0", - "collect-v8-coverage": "^1.0.0", - "exit": "^0.1.2", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "istanbul-lib-coverage": "^3.0.0", - "istanbul-lib-instrument": "^5.1.0", - "istanbul-lib-report": "^3.0.0", - "istanbul-lib-source-maps": "^4.0.0", - "istanbul-reports": "^3.1.3", - "jest-message-util": "^29.0.2", - "jest-util": "^29.0.2", - "jest-worker": "^29.0.2", - "slash": "^3.0.0", - "string-length": "^4.0.1", - "strip-ansi": "^6.0.0", - "terminal-link": "^2.0.0", - "v8-to-istanbul": "^9.0.1" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "node_modules/@jest/reporters/node_modules/@jest/transform": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.0.2.tgz", - "integrity": "sha512-lajVQx2AnsR+Pa17q2zR7eikz2PkPs1+g/qPbZkqQATeS/s6eT55H+yHcsLfuI/0YQ/4VSBepSu3bOX+44q0aA==", - "dev": true, - "dependencies": { - "@babel/core": "^7.11.6", - "@jest/types": "^29.0.2", - "@jridgewell/trace-mapping": "^0.3.15", - "babel-plugin-istanbul": "^6.1.1", - "chalk": "^4.0.0", - "convert-source-map": "^1.4.0", - "fast-json-stable-stringify": "^2.1.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.0.2", - "jest-regex-util": "^29.0.0", - "jest-util": "^29.0.2", - "micromatch": "^4.0.4", - "pirates": "^4.0.4", - "slash": "^3.0.0", - "write-file-atomic": "^4.0.1" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/reporters/node_modules/jest-haste-map": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.0.2.tgz", - "integrity": "sha512-SOorh2ysQ0fe8gsF4gaUDhoMIWAvi2hXOkwThEO48qT3JqA8GLAUieQcIvdSEd6M0scRDe1PVmKc5tXR3Z0U0A==", - "dev": true, - "dependencies": { - "@jest/types": "^29.0.2", - "@types/graceful-fs": "^4.1.3", - "@types/node": "*", - "anymatch": "^3.0.3", - "fb-watchman": "^2.0.0", - "graceful-fs": "^4.2.9", - "jest-regex-util": "^29.0.0", - "jest-util": "^29.0.2", - "jest-worker": "^29.0.2", - "micromatch": "^4.0.4", - "walker": "^1.0.8" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "optionalDependencies": { - "fsevents": "^2.3.2" - } - }, - "node_modules/@jest/reporters/node_modules/jest-regex-util": { - "version": "29.0.0", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.0.0.tgz", - "integrity": "sha512-BV7VW7Sy0fInHWN93MMPtlClweYv2qrSCwfeFWmpribGZtQPWNvRSq9XOVgOEjU1iBGRKXUZil0o2AH7Iy9Lug==", - "dev": true, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/reporters/node_modules/jest-worker": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.0.2.tgz", - "integrity": "sha512-EyvBlYcvd2pg28yg5A3OODQnqK9LI1kitnGUZUG5/NYIeaRgewtYBKB5wlr7oXj8zPCkzev7EmnTCsrXK7V+Xw==", - "dev": true, - "dependencies": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/reporters/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "node_modules/@jest/schemas": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-28.1.3.tgz", - "integrity": "sha512-/l/VWsdt/aBXgjshLWOFyFt3IVdYypu5y2Wn2rOO1un6nkqIn8SLXzgIMYXFyYsRWDyF5EthmKJMIdJvk08grg==", - "dev": true, - "dependencies": { - "@sinclair/typebox": "^0.24.1" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/@jest/source-map": { - "version": "29.0.0", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.0.0.tgz", - "integrity": "sha512-nOr+0EM8GiHf34mq2GcJyz/gYFyLQ2INDhAylrZJ9mMWoW21mLBfZa0BUVPPMxVYrLjeiRe2Z7kWXOGnS0TFhQ==", - "dev": true, - "dependencies": { - "@jridgewell/trace-mapping": "^0.3.15", - "callsites": "^3.0.0", - "graceful-fs": "^4.2.9" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/test-result": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.0.2.tgz", - "integrity": "sha512-b5rDc0lLL6Kx73LyCx6370k9uZ8o5UKdCpMS6Za3ke7H9y8PtAU305y6TeghpBmf2In8p/qqi3GpftgzijSsNw==", - "dev": true, - "dependencies": { - "@jest/console": "^29.0.2", - "@jest/types": "^29.0.2", - "@types/istanbul-lib-coverage": "^2.0.0", - "collect-v8-coverage": "^1.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/test-sequencer": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.0.2.tgz", - "integrity": "sha512-fsyZqHBlXNMv5ZqjQwCuYa2pskXCO0DVxh5aaVCuAtwzHuYEGrhordyEncBLQNuCGQSYgElrEEmS+7wwFnnMKw==", - "dev": true, - "dependencies": { - "@jest/test-result": "^29.0.2", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.0.2", - "slash": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/test-sequencer/node_modules/jest-haste-map": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.0.2.tgz", - "integrity": "sha512-SOorh2ysQ0fe8gsF4gaUDhoMIWAvi2hXOkwThEO48qT3JqA8GLAUieQcIvdSEd6M0scRDe1PVmKc5tXR3Z0U0A==", - "dev": true, - "dependencies": { - "@jest/types": "^29.0.2", - "@types/graceful-fs": "^4.1.3", - "@types/node": "*", - "anymatch": "^3.0.3", - "fb-watchman": "^2.0.0", - "graceful-fs": "^4.2.9", - "jest-regex-util": "^29.0.0", - "jest-util": "^29.0.2", - "jest-worker": "^29.0.2", - "micromatch": "^4.0.4", - "walker": "^1.0.8" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "optionalDependencies": { - "fsevents": "^2.3.2" - } - }, - "node_modules/@jest/test-sequencer/node_modules/jest-regex-util": { - "version": "29.0.0", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.0.0.tgz", - "integrity": "sha512-BV7VW7Sy0fInHWN93MMPtlClweYv2qrSCwfeFWmpribGZtQPWNvRSq9XOVgOEjU1iBGRKXUZil0o2AH7Iy9Lug==", - "dev": true, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/test-sequencer/node_modules/jest-worker": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.0.2.tgz", - "integrity": "sha512-EyvBlYcvd2pg28yg5A3OODQnqK9LI1kitnGUZUG5/NYIeaRgewtYBKB5wlr7oXj8zPCkzev7EmnTCsrXK7V+Xw==", - "dev": true, - "dependencies": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/test-sequencer/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "node_modules/@jest/types": { - "version": "29.6.1", - "resolved": "https://registry.npmmirror.com/@jest/types/-/types-29.6.1.tgz", - "integrity": "sha512-tPKQNMPuXgvdOn2/Lg9HNfUvjYVGolt04Hp03f5hAk878uwOLikN+JzeLY0HcVgKgFl9Hs3EIqpu3WX27XNhnw==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.6.0", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/types/node_modules/@jest/schemas": { - "version": "29.6.0", - "resolved": "https://registry.npmmirror.com/@jest/schemas/-/schemas-29.6.0.tgz", - "integrity": "sha512-rxLjXyJBTL4LQeJW3aKo0M/+GkCOXsO+8i9Iu7eDb6KwtP65ayoDsitrdPBtujxQ88k4wI2FNYfa6TOGwSn6cQ==", - "dev": true, - "dependencies": { - "@sinclair/typebox": "^0.27.8" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/types/node_modules/@sinclair/typebox": { - "version": "0.27.8", - "resolved": "https://registry.npmmirror.com/@sinclair/typebox/-/typebox-0.27.8.tgz", - "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", - "dev": true - }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", - "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==", - "dev": true, - "dependencies": { - "@jridgewell/set-array": "^1.0.0", - "@jridgewell/sourcemap-codec": "^1.4.10" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", - "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", - "dev": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/set-array": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.1.tgz", - "integrity": "sha512-Ct5MqZkLGEXTVmQYbGtx9SVqD2fqwvdubdps5D3djjAkgkKwT918VNOz65pEHFaYTeWcukmJmH5SwsA9Tn2ObQ==", - "dev": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.15", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", - "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", - "dev": true - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.20", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz", - "integrity": "sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==", - "dev": true, - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, - "node_modules/@jsdevtools/ono": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/@jsdevtools/ono/-/ono-7.1.3.tgz", - "integrity": "sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==" - }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@postman/form-data": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@postman/form-data/-/form-data-3.1.1.tgz", - "integrity": "sha512-vjh8Q2a8S6UCm/KKs31XFJqEEgmbjBmpPNVV2eVav6905wyFAwaUOBGA1NPBI4ERH9MMZc6w0umFgM6WbEPMdg==", - "dev": true, - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/@postman/tough-cookie": { - "version": "4.1.3-postman.1", - "resolved": "https://registry.npmjs.org/@postman/tough-cookie/-/tough-cookie-4.1.3-postman.1.tgz", - "integrity": "sha512-txpgUqZOnWYnUHZpHjkfb0IwVH4qJmyq77pPnJLlfhMtdCLMFTEeQHlzQiK906aaNCe4NEB5fGJHo9uzGbFMeA==", - "dev": true, - "dependencies": { - "psl": "^1.1.33", - "punycode": "^2.1.1", - "universalify": "^0.2.0", - "url-parse": "^1.5.3" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/@postman/tough-cookie/node_modules/universalify": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", - "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", - "dev": true, - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/@postman/tunnel-agent": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/@postman/tunnel-agent/-/tunnel-agent-0.6.3.tgz", - "integrity": "sha512-k57fzmAZ2PJGxfOA4SGR05ejorHbVAa/84Hxh/2nAztjNXc4ZjOm9NUIk6/Z6LCrBvJZqjRZbN8e/nROVUPVdg==", - "dev": true, - "dependencies": { - "safe-buffer": "^5.0.1" - }, - "engines": { - "node": "*" - } - }, - "node_modules/@scarf/scarf": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@scarf/scarf/-/scarf-1.4.0.tgz", - "integrity": "sha512-xxeapPiUXdZAE3che6f3xogoJPeZgig6omHEy1rIY5WVsB3H2BHNnZH+gHG6x91SCWyQCzWGsuL2Hh3ClO5/qQ==", - "hasInstallScript": true - }, - "node_modules/@sinclair/typebox": { - "version": "0.24.35", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.35.tgz", - "integrity": "sha512-iN6ehuDndiTiDz2F+Orv/+oHJR+PrGv+38oghCddpsW4YEZl5qyLsWxSwYUWrKEOfjpGtXDFW6scJtjpzSLeSw==", - "dev": true - }, - "node_modules/@sinonjs/commons": { - "version": "1.8.3", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz", - "integrity": "sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ==", - "dev": true, - "dependencies": { - "type-detect": "4.0.8" - } - }, - "node_modules/@sinonjs/fake-timers": { - "version": "9.1.2", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-9.1.2.tgz", - "integrity": "sha512-BPS4ynJW/o92PUR4wgriz2Ud5gpST5vz6GQfMixEDK0Z8ZCUv2M7SkBLykH56T++Xs+8ln9zTGbOvNGIe02/jw==", - "dev": true, - "dependencies": { - "@sinonjs/commons": "^1.7.0" - } - }, - "node_modules/@tsconfig/node10": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", - "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", - "dev": true - }, - "node_modules/@tsconfig/node12": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", - "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", - "dev": true - }, - "node_modules/@tsconfig/node14": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", - "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", - "dev": true - }, - "node_modules/@tsconfig/node16": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz", - "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==", - "dev": true - }, - "node_modules/@types/babel__core": { - "version": "7.1.19", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.19.tgz", - "integrity": "sha512-WEOTgRsbYkvA/KCsDwVEGkd7WAr1e3g31VHQ8zy5gul/V1qKullU/BU5I68X5v7V3GnB9eotmom4v5a5gjxorw==", - "dev": true, - "dependencies": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0", - "@types/babel__generator": "*", - "@types/babel__template": "*", - "@types/babel__traverse": "*" - } - }, - "node_modules/@types/babel__generator": { - "version": "7.6.4", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.4.tgz", - "integrity": "sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==", - "dev": true, - "dependencies": { - "@babel/types": "^7.0.0" - } - }, - "node_modules/@types/babel__template": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz", - "integrity": "sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==", - "dev": true, - "dependencies": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0" - } - }, - "node_modules/@types/babel__traverse": { - "version": "7.17.1", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.17.1.tgz", - "integrity": "sha512-kVzjari1s2YVi77D3w1yuvohV2idweYXMCDzqBiVNN63TcDWrIlTVOYpqVrvbbyOE/IyzBoTKF0fdnLPEORFxA==", - "dev": true, - "dependencies": { - "@babel/types": "^7.3.0" - } - }, - "node_modules/@types/body-parser": { - "version": "1.19.1", - "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.1.tgz", - "integrity": "sha512-a6bTJ21vFOGIkwM0kzh9Yr89ziVxq4vYH2fQ6N8AeipEzai/cFK6aGMArIkUeIdRIgpwQa+2bXiLuUJCpSf2Cg==", - "dependencies": { - "@types/connect": "*", - "@types/node": "*" - } - }, - "node_modules/@types/connect": { - "version": "3.4.35", - "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", - "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/express": { - "version": "4.17.13", - "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.13.tgz", - "integrity": "sha512-6bSZTPaTIACxn48l50SR+axgrqm6qXFIxrdAKaG6PaJk3+zuUr35hBlgT7vOmJcum+OEaIBLtHV/qloEAFITeA==", - "dependencies": { - "@types/body-parser": "*", - "@types/express-serve-static-core": "^4.17.18", - "@types/qs": "*", - "@types/serve-static": "*" - } - }, - "node_modules/@types/express-serve-static-core": { - "version": "4.17.24", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.24.tgz", - "integrity": "sha512-3UJuW+Qxhzwjq3xhwXm2onQcFHn76frIYVbTu+kn24LFxI+dEhdfISDFovPB8VpEgW8oQCTpRuCe+0zJxB7NEA==", - "dependencies": { - "@types/node": "*", - "@types/qs": "*", - "@types/range-parser": "*" - } - }, - "node_modules/@types/graceful-fs": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz", - "integrity": "sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/istanbul-lib-coverage": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz", - "integrity": "sha512-sz7iLqvVUg1gIedBOvlkxPlc8/uVzyS5OwGz1cKjXzkl3FpL3al0crU8YGU1WoHkxn0Wxbw5tyi6hvzJKNzFsw==", - "dev": true - }, - "node_modules/@types/istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-coverage": "*" - } - }, - "node_modules/@types/istanbul-reports": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", - "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-report": "*" - } - }, - "node_modules/@types/jest": { - "version": "29.5.3", - "resolved": "https://registry.npmmirror.com/@types/jest/-/jest-29.5.3.tgz", - "integrity": "sha512-1Nq7YrO/vJE/FYnqYyw0FS8LdrjExSgIiHyKg7xPpn+yi8Q4huZryKnkJatN1ZRH89Kw2v33/8ZMB7DuZeSLlA==", - "dev": true, - "dependencies": { - "expect": "^29.0.0", - "pretty-format": "^29.0.0" - } - }, - "node_modules/@types/json-schema": { - "version": "7.0.11", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", - "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==" - }, - "node_modules/@types/mime": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", - "integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==" - }, - "node_modules/@types/morgan": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/@types/morgan/-/morgan-1.9.3.tgz", - "integrity": "sha512-BiLcfVqGBZCyNCnCH3F4o2GmDLrpy0HeBVnNlyZG4fo88ZiE9SoiBe3C+2ezuwbjlEyT+PDZ17//TAlRxAn75Q==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/node": { - "version": "18.7.15", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.7.15.tgz", - "integrity": "sha512-XnjpaI8Bgc3eBag2Aw4t2Uj/49lLBSStHWfqKvIuXD7FIrZyMLWp8KuAFHAqxMZYTF9l08N1ctUn9YNybZJVmQ==" - }, - "node_modules/@types/prettier": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.0.tgz", - "integrity": "sha512-RI1L7N4JnW5gQw2spvL7Sllfuf1SaHdrZpCHiBlCXjIlufi1SMNnbu2teze3/QE67Fg2tBlH7W+mi4hVNk4p0A==", - "dev": true - }, - "node_modules/@types/qs": { - "version": "6.9.7", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", - "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==" - }, - "node_modules/@types/range-parser": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz", - "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==" - }, - "node_modules/@types/serve-static": { - "version": "1.13.10", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.10.tgz", - "integrity": "sha512-nCkHGI4w7ZgAdNkrEu0bv+4xNV/XDqW+DydknebMOQwkpDGx8G+HTlj7R7ABI8i8nKxVw0wtKPi1D+lPOkh4YQ==", - "dependencies": { - "@types/mime": "^1", - "@types/node": "*" - } - }, - "node_modules/@types/stack-utils": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", - "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", - "dev": true - }, - "node_modules/@types/swagger-jsdoc": { - "version": "6.0.4", - "resolved": "https://registry.npmjs.org/@types/swagger-jsdoc/-/swagger-jsdoc-6.0.4.tgz", - "integrity": "sha512-W+Xw5epcOZrF/AooUM/PccNMSAFOKWZA5dasNyMujTwsBkU74njSJBpvCCJhHAJ95XRMzQrrW844Btu0uoetwQ==", - "dev": true - }, - "node_modules/@types/swagger-ui-express": { - "version": "4.1.8", - "resolved": "https://registry.npmjs.org/@types/swagger-ui-express/-/swagger-ui-express-4.1.8.tgz", - "integrity": "sha512-AhZV8/EIreHFmBV5wAs0gzJUNq9JbbSXgJLQubCC0jtIo6prnI9MIRRxnU4MZX9RB9yXxF1V4R7jtLl/Wcj31g==", - "dev": true, - "dependencies": { - "@types/express": "*", - "@types/serve-static": "*" - } - }, - "node_modules/@types/ws": { - "version": "8.5.3", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.3.tgz", - "integrity": "sha512-6YOoWjruKj1uLf3INHH7D3qTXwFfEsg1kf3c0uDdSBJwfa/llkwIjrAGV7j7mVgGNbzTQ3HiHKKDXl6bJPD97w==", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/yargs": { - "version": "17.0.12", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.12.tgz", - "integrity": "sha512-Nz4MPhecOFArtm81gFQvQqdV7XYCrWKx5uUt6GNHredFHn1i2mtWqXTON7EPXMtNi1qjtjEM/VCHDhcHsAMLXQ==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/@types/yargs-parser": { - "version": "20.2.1", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-20.2.1.tgz", - "integrity": "sha512-7tFImggNeNBVMsn0vLrpn1H1uPrUBdnARPTpZoitY37ZrdJREzf7I16tMrlK3hen349gr1NYh8CmZQa7CTG6Aw==", - "dev": true - }, - "node_modules/@typescript-eslint/eslint-plugin": { - "version": "5.36.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.36.2.tgz", - "integrity": "sha512-OwwR8LRwSnI98tdc2z7mJYgY60gf7I9ZfGjN5EjCwwns9bdTuQfAXcsjSB2wSQ/TVNYSGKf4kzVXbNGaZvwiXw==", - "dev": true, - "dependencies": { - "@typescript-eslint/scope-manager": "5.36.2", - "@typescript-eslint/type-utils": "5.36.2", - "@typescript-eslint/utils": "5.36.2", - "debug": "^4.3.4", - "functional-red-black-tree": "^1.0.1", - "ignore": "^5.2.0", - "regexpp": "^3.2.0", - "semver": "^7.3.7", - "tsutils": "^3.21.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "@typescript-eslint/parser": "^5.0.0", - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/parser": { - "version": "5.36.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.36.2.tgz", - "integrity": "sha512-qS/Kb0yzy8sR0idFspI9Z6+t7mqk/oRjnAYfewG+VN73opAUvmYL3oPIMmgOX6CnQS6gmVIXGshlb5RY/R22pA==", - "dev": true, - "dependencies": { - "@typescript-eslint/scope-manager": "5.36.2", - "@typescript-eslint/types": "5.36.2", - "@typescript-eslint/typescript-estree": "5.36.2", - "debug": "^4.3.4" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "5.36.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.36.2.tgz", - "integrity": "sha512-cNNP51L8SkIFSfce8B1NSUBTJTu2Ts4nWeWbFrdaqjmn9yKrAaJUBHkyTZc0cL06OFHpb+JZq5AUHROS398Orw==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "5.36.2", - "@typescript-eslint/visitor-keys": "5.36.2" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/type-utils": { - "version": "5.36.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.36.2.tgz", - "integrity": "sha512-rPQtS5rfijUWLouhy6UmyNquKDPhQjKsaKH0WnY6hl/07lasj8gPaH2UD8xWkePn6SC+jW2i9c2DZVDnL+Dokw==", - "dev": true, - "dependencies": { - "@typescript-eslint/typescript-estree": "5.36.2", - "@typescript-eslint/utils": "5.36.2", - "debug": "^4.3.4", - "tsutils": "^3.21.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "*" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/types": { - "version": "5.36.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.36.2.tgz", - "integrity": "sha512-9OJSvvwuF1L5eS2EQgFUbECb99F0mwq501w0H0EkYULkhFa19Qq7WFbycdw1PexAc929asupbZcgjVIe6OK/XQ==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "5.36.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.36.2.tgz", - "integrity": "sha512-8fyH+RfbKc0mTspfuEjlfqA4YywcwQK2Amcf6TDOwaRLg7Vwdu4bZzyvBZp4bjt1RRjQ5MDnOZahxMrt2l5v9w==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "5.36.2", - "@typescript-eslint/visitor-keys": "5.36.2", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "semver": "^7.3.7", - "tsutils": "^3.21.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/utils": { - "version": "5.36.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.36.2.tgz", - "integrity": "sha512-uNcopWonEITX96v9pefk9DC1bWMdkweeSsewJ6GeC7L6j2t0SJywisgkr9wUTtXk90fi2Eljj90HSHm3OGdGRg==", - "dev": true, - "dependencies": { - "@types/json-schema": "^7.0.9", - "@typescript-eslint/scope-manager": "5.36.2", - "@typescript-eslint/types": "5.36.2", - "@typescript-eslint/typescript-estree": "5.36.2", - "eslint-scope": "^5.1.1", - "eslint-utils": "^3.0.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "5.36.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.36.2.tgz", - "integrity": "sha512-BtRvSR6dEdrNt7Net2/XDjbYKU5Ml6GqJgVfXT0CxTCJlnIqK7rAGreuWKMT2t8cFUT2Msv5oxw0GMRD7T5J7A==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "5.36.2", - "eslint-visitor-keys": "^3.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/accepts": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", - "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", - "dependencies": { - "mime-types": "~2.1.34", - "negotiator": "0.6.3" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/acorn": { - "version": "8.8.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz", - "integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/acorn-walk": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", - "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "dev": true, - "dependencies": { - "debug": "4" - }, - "engines": { - "node": ">= 6.0.0" - } - }, - "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ansi-escapes": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", - "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", - "dev": true, - "dependencies": { - "type-fest": "^0.21.3" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ansi-escapes/node_modules/type-fest": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/anymatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", - "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", - "dev": true, - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/append-field": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz", - "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==", - "dev": true - }, - "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==", - "dev": true, - "dependencies": { - "delegates": "^1.0.0", - "readable-stream": "^2.0.6" - } - }, - "node_modules/arg": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "dev": true - }, - "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" - }, - "node_modules/array-flatten": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" - }, - "node_modules/array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/asn1": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", - "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", - "dev": true, - "dependencies": { - "safer-buffer": "~2.1.0" - } - }, - "node_modules/assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", - "dev": true, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/async": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz", - "integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==", - "dev": true - }, - "node_modules/asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", - "dev": true - }, - "node_modules/at-least-node": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", - "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", - "dev": true, - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/aws-sign2": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/aws4": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.12.0.tgz", - "integrity": "sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg==", - "dev": true - }, - "node_modules/babel-plugin-istanbul": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", - "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.0.0", - "@istanbuljs/load-nyc-config": "^1.0.0", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-instrument": "^5.0.4", - "test-exclude": "^6.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/babel-preset-current-node-syntax": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", - "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", - "dev": true, - "dependencies": { - "@babel/plugin-syntax-async-generators": "^7.8.4", - "@babel/plugin-syntax-bigint": "^7.8.3", - "@babel/plugin-syntax-class-properties": "^7.8.3", - "@babel/plugin-syntax-import-meta": "^7.8.3", - "@babel/plugin-syntax-json-strings": "^7.8.3", - "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.8.3", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", - "@babel/plugin-syntax-optional-chaining": "^7.8.3", - "@babel/plugin-syntax-top-level-await": "^7.8.3" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" - }, - "node_modules/base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/basic-auth": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz", - "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==", - "dependencies": { - "safe-buffer": "5.1.2" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/bcrypt-pbkdf": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", - "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", - "dev": true, - "dependencies": { - "tweetnacl": "^0.14.3" - } - }, - "node_modules/bl": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", - "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", - "dev": true, - "dependencies": { - "buffer": "^5.5.0", - "inherits": "^2.0.4", - "readable-stream": "^3.4.0" - } - }, - "node_modules/bl/node_modules/readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "dev": true, - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/bluebird": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-2.11.0.tgz", - "integrity": "sha512-UfFSr22dmHPQqPP9XWHRhq+gWnHCYguQGkXQlbyPtW5qTnhFWA8/iXg765tH0cAjy7l/zPJ1aBTO0g5XgA7kvQ==", - "dev": true - }, - "node_modules/body-parser": { - "version": "1.20.0", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.0.tgz", - "integrity": "sha512-DfJ+q6EPcGKZD1QWUjSpqp+Q7bDQTsQIF4zfUAtZ6qk+H/3/QRhg9CEp39ss+/T2vw0+HaidC0ecJj/DRLIaKg==", - "dependencies": { - "bytes": "3.1.2", - "content-type": "~1.0.4", - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "on-finished": "2.4.1", - "qs": "6.10.3", - "raw-body": "2.5.1", - "type-is": "~1.6.18", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" - } - }, - "node_modules/body-parser/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/body-parser/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - }, - "node_modules/body-parser/node_modules/on-finished": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", - "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", - "dependencies": { - "ee-first": "1.1.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "dependencies": { - "fill-range": "^7.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/brotli": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/brotli/-/brotli-1.3.3.tgz", - "integrity": "sha512-oTKjJdShmDuGW94SyyaoQvAjf30dZaHnjJ8uAF+u2/vGJkJbJPJAT1gDiOJP5v1Zb6f9KEyW/1HpuaWIXtGHPg==", - "dev": true, - "dependencies": { - "base64-js": "^1.1.2" - } - }, - "node_modules/browserslist": { - "version": "4.20.4", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.20.4.tgz", - "integrity": "sha512-ok1d+1WpnU24XYN7oC3QWgTyMhY/avPJ/r9T00xxvUOIparA/gc+UPUMaod3i+G6s+nI2nUb9xZ5k794uIwShw==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - } - ], - "dependencies": { - "caniuse-lite": "^1.0.30001349", - "electron-to-chromium": "^1.4.147", - "escalade": "^3.1.1", - "node-releases": "^2.0.5", - "picocolors": "^1.0.0" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - } - }, - "node_modules/bs-logger": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", - "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", - "dev": true, - "dependencies": { - "fast-json-stable-stringify": "2.x" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/bser": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", - "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", - "dev": true, - "dependencies": { - "node-int64": "^0.4.0" - } - }, - "node_modules/buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" - } - }, - "node_modules/buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" - }, - "node_modules/busboy": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", - "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", - "dependencies": { - "streamsearch": "^1.1.0" - }, - "engines": { - "node": ">=10.16.0" - } - }, - "node_modules/bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", - "dependencies": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/call-me-maybe": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.2.tgz", - "integrity": "sha512-HpX65o1Hnr9HH25ojC1YGs7HCQLq0GCOibSaWER0eNpgJ/Z1MZv2mTc7+xh6WOPxbRVcmgbv4hGU+uSQ/2xFZQ==" - }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/caniuse-lite": { - "version": "1.0.30001349", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001349.tgz", - "integrity": "sha512-VFaWW3jeo6DLU5rwdiasosxhYSduJgSGil4cSyX3/85fbctlE58pXAkWyuRmVA0r2RxsOSVYUTZcySJ8WpbTxw==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - } - ] - }, - "node_modules/caseless": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==", - "dev": true - }, - "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/char-regex": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", - "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/chardet": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/chardet/-/chardet-1.6.0.tgz", - "integrity": "sha512-+QOTw3otC4+FxdjK9RopGpNOglADbr4WPFi0SonkO99JbpkTPbMxmdm4NenhF5Zs+4gPXLI1+y2uazws5TMe8w==", - "dev": true - }, - "node_modules/charset": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/charset/-/charset-1.0.1.tgz", - "integrity": "sha512-6dVyOOYjpfFcL1Y4qChrAoQLRHvj2ziyhcm0QJlhOcAhykL/k1kTUPbeo+87MNRTRdk2OIIsIXbuF3x2wi5EXg==", - "dev": true, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/chownr": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", - "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", - "dev": true - }, - "node_modules/ci-info": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.3.1.tgz", - "integrity": "sha512-SXgeMX9VwDe7iFFaEWkA5AstuER9YKqy4EhHqr4DVqkwmD9rpVimkMKWHdjn30Ja45txyjhSn63lVX69eVCckg==", - "dev": true - }, - "node_modules/cjs-module-lexer": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz", - "integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==", - "dev": true - }, - "node_modules/cli-progress": { - "version": "3.12.0", - "resolved": "https://registry.npmjs.org/cli-progress/-/cli-progress-3.12.0.tgz", - "integrity": "sha512-tRkV3HJ1ASwm19THiiLIXLO7Im7wlTuKnvkYaTkyoAPefqjNg7W7DHKUlGRxy9vxDvbyCYQkQozvptuMkGCg8A==", - "dev": true, - "dependencies": { - "string-width": "^4.2.3" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/cli-table3": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.3.tgz", - "integrity": "sha512-w5Jac5SykAeZJKntOxJCrm63Eg5/4dhMWIcuTbo9rpE+brgaSZo0RuNJZeOyMgsUdhDeojvgyQLmjI+K50ZGyg==", - "dev": true, - "dependencies": { - "string-width": "^4.2.0" - }, - "engines": { - "node": "10.* || >= 12.*" - }, - "optionalDependencies": { - "@colors/colors": "1.5.0" - } - }, - "node_modules/cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "dev": true, - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } - }, - "node_modules/co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", - "dev": true, - "engines": { - "iojs": ">= 1.0.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==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/collect-v8-coverage": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz", - "integrity": "sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==", - "dev": true - }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/colors": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", - "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", - "dev": true, - "engines": { - "node": ">=0.1.90" - } - }, - "node_modules/combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dev": true, - "dependencies": { - "delayed-stream": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/commander": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-11.0.0.tgz", - "integrity": "sha512-9HMlXtt/BNoYr8ooyjjNRdIilOTkVJXB+GhxMTtOKwk0R4j4lS4NpjuqmRxroBfnfTSHQIHQB7wryHhXarNjmQ==", - "dev": true, - "engines": { - "node": ">=16" - } - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" - }, - "node_modules/concat-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-2.0.0.tgz", - "integrity": "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==", - "engines": [ - "node >= 6.0" - ], - "dependencies": { - "buffer-from": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.0.2", - "typedarray": "^0.0.6" - } - }, - "node_modules/concat-stream/node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "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==", - "dev": true - }, - "node_modules/content-disposition": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", - "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", - "dependencies": { - "safe-buffer": "5.2.1" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/content-disposition/node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/content-type": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", - "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/convert-source-map": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", - "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", - "dev": true, - "dependencies": { - "safe-buffer": "~5.1.1" - } - }, - "node_modules/cookie": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", - "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/cookie-signature": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" - }, - "node_modules/core-util-is": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", - "dev": true - }, - "node_modules/cors": { - "version": "2.8.5", - "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", - "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", - "dependencies": { - "object-assign": "^4", - "vary": "^1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/create-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", - "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "dev": true - }, - "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/csv-parse": { - "version": "4.16.3", - "resolved": "https://registry.npmjs.org/csv-parse/-/csv-parse-4.16.3.tgz", - "integrity": "sha512-cO1I/zmz4w2dcKHVvpCr7JVRu8/FymG5OEpmvsZYlccYolPBLoVGKUHgNoc4ZGkFeFlWGEDmMyBM+TTqRdW/wg==", - "dev": true - }, - "node_modules/dashdash": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==", - "dev": true, - "dependencies": { - "assert-plus": "^1.0.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/decompress-response": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-4.2.1.tgz", - "integrity": "sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==", - "dev": true, - "dependencies": { - "mimic-response": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/dedent": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", - "integrity": "sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==", - "dev": true - }, - "node_modules/deep-extend": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", - "dev": true, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true - }, - "node_modules/deepmerge": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", - "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "dev": true, - "engines": { - "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==", - "dev": true - }, - "node_modules/depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/des.js": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.1.0.tgz", - "integrity": "sha512-r17GxjhUCjSRy8aiJpr8/UadFIzMzJGexI3Nmz4ADi9LYSFx4gTBp80+NaX/YsXWWLhpZ7v/v/ubEc/bCNfKwg==", - "dev": true, - "dependencies": { - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0" - } - }, - "node_modules/destroy": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", - "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", - "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" - } - }, - "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==", - "dev": true, - "bin": { - "detect-libc": "bin/detect-libc.js" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/detect-newline": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", - "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true, - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/diff-sequences": { - "version": "29.0.0", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.0.0.tgz", - "integrity": "sha512-7Qe/zd1wxSDL4D/X/FPjOMB+ZMDt71W94KYaq05I2l0oQqgXgs7s4ftYYmV38gBSrPz2vcygxfs1xn0FT+rKNA==", - "dev": true, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, - "dependencies": { - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/ecc-jsbn": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", - "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==", - "dev": true, - "dependencies": { - "jsbn": "~0.1.0", - "safer-buffer": "^2.1.0" - } - }, - "node_modules/ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" - }, - "node_modules/electron-to-chromium": { - "version": "1.4.147", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.147.tgz", - "integrity": "sha512-czclPqxLMPqPMkahKcske4TaS5lcznsc26ByBlEFDU8grTBVK9C5W6K9I6oEEhm4Ai4jTihGnys90xY1yjXcRg==", - "dev": true - }, - "node_modules/emittery": { - "version": "0.10.2", - "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.10.2.tgz", - "integrity": "sha512-aITqOwnLanpHLNXZJENbOgjUBeHocD+xsSJmNrjovKBW5HbSpW3d1pEls7GFQPUWXiwG9+0P4GtHfEqC/4M0Iw==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sindresorhus/emittery?sponsor=1" - } - }, - "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==", - "dev": true - }, - "node_modules/encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "dev": true, - "dependencies": { - "once": "^1.4.0" - } - }, - "node_modules/error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, - "dependencies": { - "is-arrayish": "^0.2.1" - } - }, - "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" - }, - "node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint": { - "version": "8.23.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.23.0.tgz", - "integrity": "sha512-pBG/XOn0MsJcKcTRLr27S5HpzQo4kLr+HjLQIyK4EiCsijDl/TB+h5uEuJU6bQ8Edvwz1XWOjpaP2qgnXGpTcA==", - "dev": true, - "dependencies": { - "@eslint/eslintrc": "^1.3.1", - "@humanwhocodes/config-array": "^0.10.4", - "@humanwhocodes/gitignore-to-minimatch": "^1.0.2", - "@humanwhocodes/module-importer": "^1.0.1", - "ajv": "^6.10.0", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.3.2", - "doctrine": "^3.0.0", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.1.1", - "eslint-utils": "^3.0.0", - "eslint-visitor-keys": "^3.3.0", - "espree": "^9.4.0", - "esquery": "^1.4.0", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "find-up": "^5.0.0", - "functional-red-black-tree": "^1.0.1", - "glob-parent": "^6.0.1", - "globals": "^13.15.0", - "globby": "^11.1.0", - "grapheme-splitter": "^1.0.4", - "ignore": "^5.2.0", - "import-fresh": "^3.0.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "js-yaml": "^4.1.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.1", - "regexpp": "^3.2.0", - "strip-ansi": "^6.0.1", - "strip-json-comments": "^3.1.0", - "text-table": "^0.2.0" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-plugin-jest": { - "version": "27.0.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-27.0.1.tgz", - "integrity": "sha512-LosUsrkwVSs/8Z/I8Hqn5vWgTEsHrfIquDEKOsV8/cl+gbFR4tiRCE1AimEotsHjSC0Rx1tYm6vPhw8C3ktmmg==", - "dev": true, - "dependencies": { - "@typescript-eslint/utils": "^5.10.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "@typescript-eslint/eslint-plugin": "^5.0.0", - "eslint": "^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "@typescript-eslint/eslint-plugin": { - "optional": true - }, - "jest": { - "optional": true - } - } - }, - "node_modules/eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/eslint-utils": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", - "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", - "dev": true, - "dependencies": { - "eslint-visitor-keys": "^2.0.0" - }, - "engines": { - "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - }, - "peerDependencies": { - "eslint": ">=5" - } - }, - "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", - "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/eslint/node_modules/eslint-scope": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", - "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", - "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/eslint/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/eslint/node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/espree": { - "version": "9.4.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.0.tgz", - "integrity": "sha512-DQmnRpLj7f6TgN/NYb0MTzJXL+vJF9h3pHy4JhCIs3zwcgez8xmGg3sXHcEO97BrmO2OSvCwMdfdlyl+E9KjOw==", - "dev": true, - "dependencies": { - "acorn": "^8.8.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true, - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/esquery": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", - "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", - "dev": true, - "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/esquery/node_modules/estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esrecurse/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } - }, - "node_modules/exit": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", - "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/expand-template": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", - "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/expect": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/expect/-/expect-29.0.2.tgz", - "integrity": "sha512-JeJlAiLKn4aApT4pzUXBVxl3NaZidWIOdg//smaIlP9ZMBDkHZGFd9ubphUZP9pUyDEo7bC6M0IIZR51o75qQw==", - "dev": true, - "dependencies": { - "@jest/expect-utils": "^29.0.2", - "jest-get-type": "^29.0.0", - "jest-matcher-utils": "^29.0.2", - "jest-message-util": "^29.0.2", - "jest-util": "^29.0.2" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/express": { - "version": "4.18.1", - "resolved": "https://registry.npmjs.org/express/-/express-4.18.1.tgz", - "integrity": "sha512-zZBcOX9TfehHQhtupq57OF8lFZ3UZi08Y97dwFCkD8p9d/d2Y3M+ykKcwaMDEL+4qyUolgBDX6AblpR3fL212Q==", - "dependencies": { - "accepts": "~1.3.8", - "array-flatten": "1.1.1", - "body-parser": "1.20.0", - "content-disposition": "0.5.4", - "content-type": "~1.0.4", - "cookie": "0.5.0", - "cookie-signature": "1.0.6", - "debug": "2.6.9", - "depd": "2.0.0", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "finalhandler": "1.2.0", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "merge-descriptors": "1.0.1", - "methods": "~1.1.2", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "path-to-regexp": "0.1.7", - "proxy-addr": "~2.0.7", - "qs": "6.10.3", - "range-parser": "~1.2.1", - "safe-buffer": "5.2.1", - "send": "0.18.0", - "serve-static": "1.15.0", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "type-is": "~1.6.18", - "utils-merge": "1.0.1", - "vary": "~1.1.2" - }, - "engines": { - "node": ">= 0.10.0" - } - }, - "node_modules/express/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/express/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - }, - "node_modules/express/node_modules/on-finished": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", - "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", - "dependencies": { - "ee-first": "1.1.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/express/node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", - "dev": true - }, - "node_modules/extsprintf": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==", - "dev": true, - "engines": [ - "node >=0.6.0" - ] - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true - }, - "node_modules/fast-glob": { - "version": "3.2.11", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", - "integrity": "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==", - "dev": true, - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - }, - "engines": { - "node": ">=8.6.0" - } - }, - "node_modules/fast-glob/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true - }, - "node_modules/fastq": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", - "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", - "dev": true, - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/fb-watchman": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.1.tgz", - "integrity": "sha512-DkPJKQeY6kKwmuMretBhr7G6Vodr7bFwDYTXIkfG1gjvNpaxBTQV3PbXg6bR1c1UP4jPOX0jHUbbHANL9vRjVg==", - "dev": true, - "dependencies": { - "bser": "2.1.1" - } - }, - "node_modules/file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", - "dev": true, - "dependencies": { - "flat-cache": "^3.0.4" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/file-type": { - "version": "3.9.0", - "resolved": "https://registry.npmjs.org/file-type/-/file-type-3.9.0.tgz", - "integrity": "sha512-RLoqTXE8/vPmMuTI88DAzhMYC99I8BWv7zYP4A1puo5HIjEJ5EX48ighy4ZyKMG9EDXxBgW6e++cn7d1xuFghA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/filesize": { - "version": "10.0.12", - "resolved": "https://registry.npmjs.org/filesize/-/filesize-10.0.12.tgz", - "integrity": "sha512-6RS9gDchbn+qWmtV2uSjo5vmKizgfCQeb5jKmqx8HyzA3MoLqqyQxN+QcjkGBJt7FjJ9qFce67Auyya5rRRbpw==", - "dev": true, - "engines": { - "node": ">= 10.4.0" - } - }, - "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/finalhandler": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", - "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", - "dependencies": { - "debug": "2.6.9", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "statuses": "2.0.1", - "unpipe": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/finalhandler/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/finalhandler/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - }, - "node_modules/finalhandler/node_modules/on-finished": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", - "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", - "dependencies": { - "ee-first": "1.1.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/flat-cache": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", - "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", - "dev": true, - "dependencies": { - "flatted": "^3.1.0", - "rimraf": "^3.0.2" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/flatted": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.6.tgz", - "integrity": "sha512-0sQoMh9s0BYsm+12Huy/rkKxVu4R1+r96YX5cG44rHV0pQ6iC3Q+mkoMFaGWObMFYQxCVT+ssG1ksneA2MI9KQ==", - "dev": true - }, - "node_modules/forever-agent": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/forwarded": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", - "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/from2": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", - "integrity": "sha512-OMcX/4IC/uqEPVgGeyfN22LJk6AZrMkRZHxcHBMBvHScDGgwTm2GT2Wkgtocyd3JfZffjj2kYUDXXII0Fk9W0g==", - "dev": true, - "dependencies": { - "inherits": "^2.0.1", - "readable-stream": "^2.0.0" - } - }, - "node_modules/fs-constants": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", - "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", - "dev": true - }, - "node_modules/fs-extra": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", - "dev": true, - "dependencies": { - "at-least-node": "^1.0.0", - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" - }, - "node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" - }, - "node_modules/functional-red-black-tree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", - "dev": true - }, - "node_modules/gauge": { - "version": "2.7.4", - "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", - "integrity": "sha512-14x4kjc6lkD3ltw589k0NrPD6cCNTD6CWoVUNpB85+DrtONoZn+Rug6xZU5RvSC4+TZPxA5AnBibQYAvZn41Hg==", - "dev": true, - "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==", - "dev": true, - "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==", - "dev": true, - "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": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "dev": true, - "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": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true, - "dependencies": { - "ansi-regex": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true, - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "node_modules/get-intrinsic": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", - "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", - "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-package-type": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", - "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", - "dev": true, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/getpass": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==", - "dev": true, - "dependencies": { - "assert-plus": "^1.0.0" - } - }, - "node_modules/github-from-package": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", - "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==", - "dev": true - }, - "node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, - "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/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/globals": { - "version": "13.17.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.17.0.tgz", - "integrity": "sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw==", - "dev": true, - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "dev": true, - "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.10", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", - "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", - "dev": true - }, - "node_modules/grapheme-splitter": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", - "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", - "dev": true - }, - "node_modules/handlebars": { - "version": "4.7.8", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz", - "integrity": "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==", - "dev": true, - "dependencies": { - "minimist": "^1.2.5", - "neo-async": "^2.6.2", - "source-map": "^0.6.1", - "wordwrap": "^1.0.0" - }, - "bin": { - "handlebars": "bin/handlebars" - }, - "engines": { - "node": ">=0.4.7" - }, - "optionalDependencies": { - "uglify-js": "^3.1.4" - } - }, - "node_modules/har-schema": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/har-validator": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", - "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", - "deprecated": "this library is no longer supported", - "dev": true, - "dependencies": { - "ajv": "^6.12.3", - "har-schema": "^2.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dependencies": { - "function-bind": "^1.1.1" - }, - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "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==", - "dev": true - }, - "node_modules/html-escaper": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", - "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", - "dev": true - }, - "node_modules/http-errors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", - "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", - "dependencies": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/http-reasons": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/http-reasons/-/http-reasons-0.1.0.tgz", - "integrity": "sha512-P6kYh0lKZ+y29T2Gqz+RlC9WBLhKe8kDmcJ+A+611jFfxdPsbMRQ5aNmFRM3lENqFkK+HTTL+tlQviAiv0AbLQ==", - "dev": true - }, - "node_modules/http-signature": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.3.6.tgz", - "integrity": "sha512-3adrsD6zqo4GsTqtO7FyrejHNv+NgiIfAfv68+jVlFmSr9OGy7zrxONceFRLKvnnZA5jbxQBX1u9PpB6Wi32Gw==", - "dev": true, - "dependencies": { - "assert-plus": "^1.0.0", - "jsprim": "^2.0.2", - "sshpk": "^1.14.1" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/httpntlm": { - "version": "1.8.13", - "resolved": "https://registry.npmjs.org/httpntlm/-/httpntlm-1.8.13.tgz", - "integrity": "sha512-2F2FDPiWT4rewPzNMg3uPhNkP3NExENlUGADRUDPQvuftuUTGW98nLZtGemCIW3G40VhWZYgkIDcQFAwZ3mf2Q==", - "dev": true, - "funding": [ - { - "type": "paypal", - "url": "https://www.paypal.com/donate/?hosted_button_id=2CKNJLZJBW8ZC" - }, - { - "type": "buymeacoffee", - "url": "https://www.buymeacoffee.com/samdecrock" - } - ], - "dependencies": { - "des.js": "^1.0.1", - "httpreq": ">=0.4.22", - "js-md4": "^0.3.2", - "underscore": "~1.12.1" - }, - "engines": { - "node": ">=10.4.0" - } - }, - "node_modules/httpreq": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/httpreq/-/httpreq-1.1.1.tgz", - "integrity": "sha512-uhSZLPPD2VXXOSN8Cni3kIsoFHaU2pT/nySEU/fHr/ePbqHYr0jeiQRmUKLEirC09SFPsdMoA7LU7UXMd/w0Kw==", - "dev": true, - "engines": { - "node": ">= 6.15.1" - } - }, - "node_modules/https-proxy-agent": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", - "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", - "dev": true, - "dependencies": { - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/human-signals": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", - "dev": true, - "engines": { - "node": ">=10.17.0" - } - }, - "node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/ignore": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", - "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/import-local": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", - "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", - "dev": true, - "dependencies": { - "pkg-dir": "^4.2.0", - "resolve-cwd": "^3.0.0" - }, - "bin": { - "import-local-fixture": "fixtures/cli.js" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", - "dev": true, - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "node_modules/ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "dev": true - }, - "node_modules/into-stream": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/into-stream/-/into-stream-6.0.0.tgz", - "integrity": "sha512-XHbaOAvP+uFKUFsOgoNPRjLkwB+I22JFPFe5OjTkQ0nwgj6+pSjb4NmB6VMxaPshLiOf+zcpOCBQuLwC1KHhZA==", - "dev": true, - "dependencies": { - "from2": "^2.3.0", - "p-is-promise": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ipaddr.js": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "dev": true - }, - "node_modules/is-core-module": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.9.0.tgz", - "integrity": "sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A==", - "dev": true, - "dependencies": { - "has": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "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==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-generator-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", - "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", - "dev": true - }, - "node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true - }, - "node_modules/isstream": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==", - "dev": true - }, - "node_modules/istanbul-lib-coverage": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", - "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-instrument": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.0.tgz", - "integrity": "sha512-6Lthe1hqXHBNsqvgDzGO6l03XNeu3CrG4RqQ1KM9+l5+jNGpEJfIELx1NS3SEHmJQA8np/u+E4EPRKRiu6m19A==", - "dev": true, - "dependencies": { - "@babel/core": "^7.12.3", - "@babel/parser": "^7.14.7", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.2.0", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-instrument/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", - "dev": true, - "dependencies": { - "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^3.0.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-source-maps": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", - "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", - "dev": true, - "dependencies": { - "debug": "^4.1.1", - "istanbul-lib-coverage": "^3.0.0", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/istanbul-reports": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz", - "integrity": "sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==", - "dev": true, - "dependencies": { - "html-escaper": "^2.0.0", - "istanbul-lib-report": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/jest/-/jest-29.0.2.tgz", - "integrity": "sha512-enziNbNUmXTcTaTP/Uq5rV91r0Yqy2UKzLUIabxMpGm9YHz8qpbJhiRnNVNvm6vzWfzt/0o97NEHH8/3udoClA==", - "dev": true, - "dependencies": { - "@jest/core": "^29.0.2", - "@jest/types": "^29.0.2", - "import-local": "^3.0.2", - "jest-cli": "^29.0.2" - }, - "bin": { - "jest": "bin/jest.js" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "node_modules/jest-changed-files": { - "version": "29.0.0", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.0.0.tgz", - "integrity": "sha512-28/iDMDrUpGoCitTURuDqUzWQoWmOmOKOFST1mi2lwh62X4BFf6khgH3uSuo1e49X/UDjuApAj3w0wLOex4VPQ==", - "dev": true, - "dependencies": { - "execa": "^5.0.0", - "p-limit": "^3.1.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-changed-files/node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/jest-circus": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.0.2.tgz", - "integrity": "sha512-YTPEsoE1P1X0bcyDQi3QIkpt2Wl9om9k2DQRuLFdS5x8VvAKSdYAVJufgvudhnKgM8WHvvAzhBE+1DRQB8x1CQ==", - "dev": true, - "dependencies": { - "@jest/environment": "^29.0.2", - "@jest/expect": "^29.0.2", - "@jest/test-result": "^29.0.2", - "@jest/types": "^29.0.2", - "@types/node": "*", - "chalk": "^4.0.0", - "co": "^4.6.0", - "dedent": "^0.7.0", - "is-generator-fn": "^2.0.0", - "jest-each": "^29.0.2", - "jest-matcher-utils": "^29.0.2", - "jest-message-util": "^29.0.2", - "jest-runtime": "^29.0.2", - "jest-snapshot": "^29.0.2", - "jest-util": "^29.0.2", - "p-limit": "^3.1.0", - "pretty-format": "^29.0.2", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-circus/node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/jest-cli": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.0.2.tgz", - "integrity": "sha512-tlf8b+4KcUbBGr25cywIi3+rbZ4+G+SiG8SvY552m9sRZbXPafdmQRyeVE/C/R8K+TiBAMrTIUmV2SlStRJ40g==", - "dev": true, - "dependencies": { - "@jest/core": "^29.0.2", - "@jest/test-result": "^29.0.2", - "@jest/types": "^29.0.2", - "chalk": "^4.0.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.9", - "import-local": "^3.0.2", - "jest-config": "^29.0.2", - "jest-util": "^29.0.2", - "jest-validate": "^29.0.2", - "prompts": "^2.0.1", - "yargs": "^17.3.1" - }, - "bin": { - "jest": "bin/jest.js" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "node_modules/jest-config": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.0.2.tgz", - "integrity": "sha512-RU4gzeUNZAFktYVzDGimDxeYoaiTnH100jkYYZgldqFamaZukF0IqmFx8+QrzVeEWccYg10EEJT3ox1Dq5b74w==", - "dev": true, - "dependencies": { - "@babel/core": "^7.11.6", - "@jest/test-sequencer": "^29.0.2", - "@jest/types": "^29.0.2", - "babel-jest": "^29.0.2", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "deepmerge": "^4.2.2", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "jest-circus": "^29.0.2", - "jest-environment-node": "^29.0.2", - "jest-get-type": "^29.0.0", - "jest-regex-util": "^29.0.0", - "jest-resolve": "^29.0.2", - "jest-runner": "^29.0.2", - "jest-util": "^29.0.2", - "jest-validate": "^29.0.2", - "micromatch": "^4.0.4", - "parse-json": "^5.2.0", - "pretty-format": "^29.0.2", - "slash": "^3.0.0", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "@types/node": "*", - "ts-node": ">=9.0.0" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - }, - "ts-node": { - "optional": true - } - } - }, - "node_modules/jest-config/node_modules/@jest/transform": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.0.2.tgz", - "integrity": "sha512-lajVQx2AnsR+Pa17q2zR7eikz2PkPs1+g/qPbZkqQATeS/s6eT55H+yHcsLfuI/0YQ/4VSBepSu3bOX+44q0aA==", - "dev": true, - "dependencies": { - "@babel/core": "^7.11.6", - "@jest/types": "^29.0.2", - "@jridgewell/trace-mapping": "^0.3.15", - "babel-plugin-istanbul": "^6.1.1", - "chalk": "^4.0.0", - "convert-source-map": "^1.4.0", - "fast-json-stable-stringify": "^2.1.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.0.2", - "jest-regex-util": "^29.0.0", - "jest-util": "^29.0.2", - "micromatch": "^4.0.4", - "pirates": "^4.0.4", - "slash": "^3.0.0", - "write-file-atomic": "^4.0.1" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-config/node_modules/babel-jest": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.0.2.tgz", - "integrity": "sha512-yTu4/WSi/HzarjQtrJSwV+/0maoNt+iP0DmpvFJdv9yY+5BuNle8TbheHzzcSWj5gIHfuhpbLYHWRDYhWKyeKQ==", - "dev": true, - "dependencies": { - "@jest/transform": "^29.0.2", - "@types/babel__core": "^7.1.14", - "babel-plugin-istanbul": "^6.1.1", - "babel-preset-jest": "^29.0.2", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "slash": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "@babel/core": "^7.8.0" - } - }, - "node_modules/jest-config/node_modules/babel-plugin-jest-hoist": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.0.2.tgz", - "integrity": "sha512-eBr2ynAEFjcebVvu8Ktx580BD1QKCrBG1XwEUTXJe285p9HA/4hOhfWCFRQhTKSyBV0VzjhG7H91Eifz9s29hg==", - "dev": true, - "dependencies": { - "@babel/template": "^7.3.3", - "@babel/types": "^7.3.3", - "@types/babel__core": "^7.1.14", - "@types/babel__traverse": "^7.0.6" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-config/node_modules/babel-preset-jest": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.0.2.tgz", - "integrity": "sha512-BeVXp7rH5TK96ofyEnHjznjLMQ2nAeDJ+QzxKnHAAMs0RgrQsCywjAN8m4mOm5Di0pxU//3AoEeJJrerMH5UeA==", - "dev": true, - "dependencies": { - "babel-plugin-jest-hoist": "^29.0.2", - "babel-preset-current-node-syntax": "^1.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/jest-config/node_modules/jest-haste-map": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.0.2.tgz", - "integrity": "sha512-SOorh2ysQ0fe8gsF4gaUDhoMIWAvi2hXOkwThEO48qT3JqA8GLAUieQcIvdSEd6M0scRDe1PVmKc5tXR3Z0U0A==", - "dev": true, - "dependencies": { - "@jest/types": "^29.0.2", - "@types/graceful-fs": "^4.1.3", - "@types/node": "*", - "anymatch": "^3.0.3", - "fb-watchman": "^2.0.0", - "graceful-fs": "^4.2.9", - "jest-regex-util": "^29.0.0", - "jest-util": "^29.0.2", - "jest-worker": "^29.0.2", - "micromatch": "^4.0.4", - "walker": "^1.0.8" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "optionalDependencies": { - "fsevents": "^2.3.2" - } - }, - "node_modules/jest-config/node_modules/jest-regex-util": { - "version": "29.0.0", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.0.0.tgz", - "integrity": "sha512-BV7VW7Sy0fInHWN93MMPtlClweYv2qrSCwfeFWmpribGZtQPWNvRSq9XOVgOEjU1iBGRKXUZil0o2AH7Iy9Lug==", - "dev": true, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-config/node_modules/jest-worker": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.0.2.tgz", - "integrity": "sha512-EyvBlYcvd2pg28yg5A3OODQnqK9LI1kitnGUZUG5/NYIeaRgewtYBKB5wlr7oXj8zPCkzev7EmnTCsrXK7V+Xw==", - "dev": true, - "dependencies": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-config/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "node_modules/jest-diff": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.0.2.tgz", - "integrity": "sha512-b9l9970sa1rMXH1owp2Woprmy42qIwwll/htsw4Gf7+WuSp5bZxNhkKHDuCGKL+HoHn1KhcC+tNEeAPYBkD2Jg==", - "dev": true, - "dependencies": { - "chalk": "^4.0.0", - "diff-sequences": "^29.0.0", - "jest-get-type": "^29.0.0", - "pretty-format": "^29.0.2" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-docblock": { - "version": "29.0.0", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.0.0.tgz", - "integrity": "sha512-s5Kpra/kLzbqu9dEjov30kj1n4tfu3e7Pl8v+f8jOkeWNqM6Ds8jRaJfZow3ducoQUrf2Z4rs2N5S3zXnb83gw==", - "dev": true, - "dependencies": { - "detect-newline": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-each": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.0.2.tgz", - "integrity": "sha512-+sA9YjrJl35iCg0W0VCrgCVj+wGhDrrKQ+YAqJ/DHBC4gcDFAeePtRRhpJnX9gvOZ63G7gt52pwp2PesuSEx0Q==", - "dev": true, - "dependencies": { - "@jest/types": "^29.0.2", - "chalk": "^4.0.0", - "jest-get-type": "^29.0.0", - "jest-util": "^29.0.2", - "pretty-format": "^29.0.2" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-environment-node": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.0.2.tgz", - "integrity": "sha512-4Fv8GXVCToRlMzDO94gvA8iOzKxQ7rhAbs8L+j8GPyTxGuUiYkV+63LecGeVdVhsL2KXih1sKnoqmH6tp89J7Q==", - "dev": true, - "dependencies": { - "@jest/environment": "^29.0.2", - "@jest/fake-timers": "^29.0.2", - "@jest/types": "^29.0.2", - "@types/node": "*", - "jest-mock": "^29.0.2", - "jest-util": "^29.0.2" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-get-type": { - "version": "29.0.0", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.0.0.tgz", - "integrity": "sha512-83X19z/HuLKYXYHskZlBAShO7UfLFXu/vWajw9ZNJASN32li8yHMaVGAQqxFW1RCFOkB7cubaL6FaJVQqqJLSw==", - "dev": true, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-leak-detector": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.0.2.tgz", - "integrity": "sha512-5f0493qDeAxjUldkBSQg5D1cLadRgZVyWpTQvfJeQwQUpHQInE21AyVHVv64M7P2Ue8Z5EZ4BAcoDS/dSPPgMw==", - "dev": true, - "dependencies": { - "jest-get-type": "^29.0.0", - "pretty-format": "^29.0.2" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-matcher-utils": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.0.2.tgz", - "integrity": "sha512-s62YkHFBfAx0JLA2QX1BlnCRFwHRobwAv2KP1+YhjzF6ZCbCVrf1sG8UJyn62ZUsDaQKpoo86XMTjkUyO5aWmQ==", - "dev": true, - "dependencies": { - "chalk": "^4.0.0", - "jest-diff": "^29.0.2", - "jest-get-type": "^29.0.0", - "pretty-format": "^29.0.2" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-message-util": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.0.2.tgz", - "integrity": "sha512-kcJAgms3ckJV0wUoLsAM40xAhY+pb9FVSZwicjFU9PFkaTNmqh9xd99/CzKse48wPM1ANUQKmp03/DpkY+lGrA==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.12.13", - "@jest/types": "^29.0.2", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "micromatch": "^4.0.4", - "pretty-format": "^29.0.2", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-mock": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.0.2.tgz", - "integrity": "sha512-giWXOIT23UCxHCN2VUfUJ0Q7SmiqQwfSFXlCaIhW5anITpNQ+3vuLPQdKt5wkuwM37GrbFyHIClce8AAK9ft9g==", - "dev": true, - "dependencies": { - "@jest/types": "^29.0.2", - "@types/node": "*" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-pnp-resolver": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz", - "integrity": "sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w==", - "dev": true, - "engines": { - "node": ">=6" - }, - "peerDependencies": { - "jest-resolve": "*" - }, - "peerDependenciesMeta": { - "jest-resolve": { - "optional": true - } - } - }, - "node_modules/jest-resolve": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.0.2.tgz", - "integrity": "sha512-V3uLjSA+EHxLtjIDKTBXnY71hyx+8lusCqPXvqzkFO1uCGvVpjBfuOyp+KOLBNSuY61kM2jhepiMwt4eiJS+Vw==", - "dev": true, - "dependencies": { - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.0.2", - "jest-pnp-resolver": "^1.2.2", - "jest-util": "^29.0.2", - "jest-validate": "^29.0.2", - "resolve": "^1.20.0", - "resolve.exports": "^1.1.0", - "slash": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-resolve-dependencies": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.0.2.tgz", - "integrity": "sha512-fSAu6eIG7wtGdnPJUkVVdILGzYAP9Dj/4+zvC8BrGe8msaUMJ9JeygU0Hf9+Uor6/icbuuzQn5See1uajLnAqg==", - "dev": true, - "dependencies": { - "jest-regex-util": "^29.0.0", - "jest-snapshot": "^29.0.2" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-resolve-dependencies/node_modules/jest-regex-util": { - "version": "29.0.0", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.0.0.tgz", - "integrity": "sha512-BV7VW7Sy0fInHWN93MMPtlClweYv2qrSCwfeFWmpribGZtQPWNvRSq9XOVgOEjU1iBGRKXUZil0o2AH7Iy9Lug==", - "dev": true, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-resolve/node_modules/jest-haste-map": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.0.2.tgz", - "integrity": "sha512-SOorh2ysQ0fe8gsF4gaUDhoMIWAvi2hXOkwThEO48qT3JqA8GLAUieQcIvdSEd6M0scRDe1PVmKc5tXR3Z0U0A==", - "dev": true, - "dependencies": { - "@jest/types": "^29.0.2", - "@types/graceful-fs": "^4.1.3", - "@types/node": "*", - "anymatch": "^3.0.3", - "fb-watchman": "^2.0.0", - "graceful-fs": "^4.2.9", - "jest-regex-util": "^29.0.0", - "jest-util": "^29.0.2", - "jest-worker": "^29.0.2", - "micromatch": "^4.0.4", - "walker": "^1.0.8" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "optionalDependencies": { - "fsevents": "^2.3.2" - } - }, - "node_modules/jest-resolve/node_modules/jest-regex-util": { - "version": "29.0.0", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.0.0.tgz", - "integrity": "sha512-BV7VW7Sy0fInHWN93MMPtlClweYv2qrSCwfeFWmpribGZtQPWNvRSq9XOVgOEjU1iBGRKXUZil0o2AH7Iy9Lug==", - "dev": true, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-resolve/node_modules/jest-worker": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.0.2.tgz", - "integrity": "sha512-EyvBlYcvd2pg28yg5A3OODQnqK9LI1kitnGUZUG5/NYIeaRgewtYBKB5wlr7oXj8zPCkzev7EmnTCsrXK7V+Xw==", - "dev": true, - "dependencies": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-resolve/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "node_modules/jest-runner": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.0.2.tgz", - "integrity": "sha512-+D82iPZejI8t+SfduOO1deahC/QgLFf8aJBO++Znz3l2ETtOMdM7K4ATsGWzCFnTGio5yHaRifg1Su5Ybza5Nw==", - "dev": true, - "dependencies": { - "@jest/console": "^29.0.2", - "@jest/environment": "^29.0.2", - "@jest/test-result": "^29.0.2", - "@jest/transform": "^29.0.2", - "@jest/types": "^29.0.2", - "@types/node": "*", - "chalk": "^4.0.0", - "emittery": "^0.10.2", - "graceful-fs": "^4.2.9", - "jest-docblock": "^29.0.0", - "jest-environment-node": "^29.0.2", - "jest-haste-map": "^29.0.2", - "jest-leak-detector": "^29.0.2", - "jest-message-util": "^29.0.2", - "jest-resolve": "^29.0.2", - "jest-runtime": "^29.0.2", - "jest-util": "^29.0.2", - "jest-watcher": "^29.0.2", - "jest-worker": "^29.0.2", - "p-limit": "^3.1.0", - "source-map-support": "0.5.13" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-runner/node_modules/@jest/transform": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.0.2.tgz", - "integrity": "sha512-lajVQx2AnsR+Pa17q2zR7eikz2PkPs1+g/qPbZkqQATeS/s6eT55H+yHcsLfuI/0YQ/4VSBepSu3bOX+44q0aA==", - "dev": true, - "dependencies": { - "@babel/core": "^7.11.6", - "@jest/types": "^29.0.2", - "@jridgewell/trace-mapping": "^0.3.15", - "babel-plugin-istanbul": "^6.1.1", - "chalk": "^4.0.0", - "convert-source-map": "^1.4.0", - "fast-json-stable-stringify": "^2.1.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.0.2", - "jest-regex-util": "^29.0.0", - "jest-util": "^29.0.2", - "micromatch": "^4.0.4", - "pirates": "^4.0.4", - "slash": "^3.0.0", - "write-file-atomic": "^4.0.1" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-runner/node_modules/jest-haste-map": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.0.2.tgz", - "integrity": "sha512-SOorh2ysQ0fe8gsF4gaUDhoMIWAvi2hXOkwThEO48qT3JqA8GLAUieQcIvdSEd6M0scRDe1PVmKc5tXR3Z0U0A==", - "dev": true, - "dependencies": { - "@jest/types": "^29.0.2", - "@types/graceful-fs": "^4.1.3", - "@types/node": "*", - "anymatch": "^3.0.3", - "fb-watchman": "^2.0.0", - "graceful-fs": "^4.2.9", - "jest-regex-util": "^29.0.0", - "jest-util": "^29.0.2", - "jest-worker": "^29.0.2", - "micromatch": "^4.0.4", - "walker": "^1.0.8" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "optionalDependencies": { - "fsevents": "^2.3.2" - } - }, - "node_modules/jest-runner/node_modules/jest-regex-util": { - "version": "29.0.0", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.0.0.tgz", - "integrity": "sha512-BV7VW7Sy0fInHWN93MMPtlClweYv2qrSCwfeFWmpribGZtQPWNvRSq9XOVgOEjU1iBGRKXUZil0o2AH7Iy9Lug==", - "dev": true, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-runner/node_modules/jest-worker": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.0.2.tgz", - "integrity": "sha512-EyvBlYcvd2pg28yg5A3OODQnqK9LI1kitnGUZUG5/NYIeaRgewtYBKB5wlr7oXj8zPCkzev7EmnTCsrXK7V+Xw==", - "dev": true, - "dependencies": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-runner/node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/jest-runner/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "node_modules/jest-runtime": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.0.2.tgz", - "integrity": "sha512-DO6F81LX4okOgjJLkLySv10E5YcV5NHUbY1ZqAUtofxdQE+q4hjH0P2gNsY8x3z3sqgw7O/+919SU4r18Fcuig==", - "dev": true, - "dependencies": { - "@jest/environment": "^29.0.2", - "@jest/fake-timers": "^29.0.2", - "@jest/globals": "^29.0.2", - "@jest/source-map": "^29.0.0", - "@jest/test-result": "^29.0.2", - "@jest/transform": "^29.0.2", - "@jest/types": "^29.0.2", - "@types/node": "*", - "chalk": "^4.0.0", - "cjs-module-lexer": "^1.0.0", - "collect-v8-coverage": "^1.0.0", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.0.2", - "jest-message-util": "^29.0.2", - "jest-mock": "^29.0.2", - "jest-regex-util": "^29.0.0", - "jest-resolve": "^29.0.2", - "jest-snapshot": "^29.0.2", - "jest-util": "^29.0.2", - "slash": "^3.0.0", - "strip-bom": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-runtime/node_modules/@jest/transform": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.0.2.tgz", - "integrity": "sha512-lajVQx2AnsR+Pa17q2zR7eikz2PkPs1+g/qPbZkqQATeS/s6eT55H+yHcsLfuI/0YQ/4VSBepSu3bOX+44q0aA==", - "dev": true, - "dependencies": { - "@babel/core": "^7.11.6", - "@jest/types": "^29.0.2", - "@jridgewell/trace-mapping": "^0.3.15", - "babel-plugin-istanbul": "^6.1.1", - "chalk": "^4.0.0", - "convert-source-map": "^1.4.0", - "fast-json-stable-stringify": "^2.1.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.0.2", - "jest-regex-util": "^29.0.0", - "jest-util": "^29.0.2", - "micromatch": "^4.0.4", - "pirates": "^4.0.4", - "slash": "^3.0.0", - "write-file-atomic": "^4.0.1" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-runtime/node_modules/jest-haste-map": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.0.2.tgz", - "integrity": "sha512-SOorh2ysQ0fe8gsF4gaUDhoMIWAvi2hXOkwThEO48qT3JqA8GLAUieQcIvdSEd6M0scRDe1PVmKc5tXR3Z0U0A==", - "dev": true, - "dependencies": { - "@jest/types": "^29.0.2", - "@types/graceful-fs": "^4.1.3", - "@types/node": "*", - "anymatch": "^3.0.3", - "fb-watchman": "^2.0.0", - "graceful-fs": "^4.2.9", - "jest-regex-util": "^29.0.0", - "jest-util": "^29.0.2", - "jest-worker": "^29.0.2", - "micromatch": "^4.0.4", - "walker": "^1.0.8" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "optionalDependencies": { - "fsevents": "^2.3.2" - } - }, - "node_modules/jest-runtime/node_modules/jest-regex-util": { - "version": "29.0.0", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.0.0.tgz", - "integrity": "sha512-BV7VW7Sy0fInHWN93MMPtlClweYv2qrSCwfeFWmpribGZtQPWNvRSq9XOVgOEjU1iBGRKXUZil0o2AH7Iy9Lug==", - "dev": true, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-runtime/node_modules/jest-worker": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.0.2.tgz", - "integrity": "sha512-EyvBlYcvd2pg28yg5A3OODQnqK9LI1kitnGUZUG5/NYIeaRgewtYBKB5wlr7oXj8zPCkzev7EmnTCsrXK7V+Xw==", - "dev": true, - "dependencies": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-runtime/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "node_modules/jest-snapshot": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.0.2.tgz", - "integrity": "sha512-26C4PzGKaX5gkoKg8UzYGVy2HPVcTaROSkf0gwnHu3lGeTB7bAIJBovvVPZoiJ20IximJELQs/r8WSDRCuGX2A==", - "dev": true, - "dependencies": { - "@babel/core": "^7.11.6", - "@babel/generator": "^7.7.2", - "@babel/plugin-syntax-jsx": "^7.7.2", - "@babel/plugin-syntax-typescript": "^7.7.2", - "@babel/traverse": "^7.7.2", - "@babel/types": "^7.3.3", - "@jest/expect-utils": "^29.0.2", - "@jest/transform": "^29.0.2", - "@jest/types": "^29.0.2", - "@types/babel__traverse": "^7.0.6", - "@types/prettier": "^2.1.5", - "babel-preset-current-node-syntax": "^1.0.0", - "chalk": "^4.0.0", - "expect": "^29.0.2", - "graceful-fs": "^4.2.9", - "jest-diff": "^29.0.2", - "jest-get-type": "^29.0.0", - "jest-haste-map": "^29.0.2", - "jest-matcher-utils": "^29.0.2", - "jest-message-util": "^29.0.2", - "jest-util": "^29.0.2", - "natural-compare": "^1.4.0", - "pretty-format": "^29.0.2", - "semver": "^7.3.5" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-snapshot/node_modules/@jest/transform": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.0.2.tgz", - "integrity": "sha512-lajVQx2AnsR+Pa17q2zR7eikz2PkPs1+g/qPbZkqQATeS/s6eT55H+yHcsLfuI/0YQ/4VSBepSu3bOX+44q0aA==", - "dev": true, - "dependencies": { - "@babel/core": "^7.11.6", - "@jest/types": "^29.0.2", - "@jridgewell/trace-mapping": "^0.3.15", - "babel-plugin-istanbul": "^6.1.1", - "chalk": "^4.0.0", - "convert-source-map": "^1.4.0", - "fast-json-stable-stringify": "^2.1.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.0.2", - "jest-regex-util": "^29.0.0", - "jest-util": "^29.0.2", - "micromatch": "^4.0.4", - "pirates": "^4.0.4", - "slash": "^3.0.0", - "write-file-atomic": "^4.0.1" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-snapshot/node_modules/jest-haste-map": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.0.2.tgz", - "integrity": "sha512-SOorh2ysQ0fe8gsF4gaUDhoMIWAvi2hXOkwThEO48qT3JqA8GLAUieQcIvdSEd6M0scRDe1PVmKc5tXR3Z0U0A==", - "dev": true, - "dependencies": { - "@jest/types": "^29.0.2", - "@types/graceful-fs": "^4.1.3", - "@types/node": "*", - "anymatch": "^3.0.3", - "fb-watchman": "^2.0.0", - "graceful-fs": "^4.2.9", - "jest-regex-util": "^29.0.0", - "jest-util": "^29.0.2", - "jest-worker": "^29.0.2", - "micromatch": "^4.0.4", - "walker": "^1.0.8" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "optionalDependencies": { - "fsevents": "^2.3.2" - } - }, - "node_modules/jest-snapshot/node_modules/jest-regex-util": { - "version": "29.0.0", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.0.0.tgz", - "integrity": "sha512-BV7VW7Sy0fInHWN93MMPtlClweYv2qrSCwfeFWmpribGZtQPWNvRSq9XOVgOEjU1iBGRKXUZil0o2AH7Iy9Lug==", - "dev": true, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-snapshot/node_modules/jest-worker": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.0.2.tgz", - "integrity": "sha512-EyvBlYcvd2pg28yg5A3OODQnqK9LI1kitnGUZUG5/NYIeaRgewtYBKB5wlr7oXj8zPCkzev7EmnTCsrXK7V+Xw==", - "dev": true, - "dependencies": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-snapshot/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "node_modules/jest-util": { - "version": "29.6.2", - "resolved": "https://registry.npmmirror.com/jest-util/-/jest-util-29.6.2.tgz", - "integrity": "sha512-3eX1qb6L88lJNCFlEADKOkjpXJQyZRiavX1INZ4tRnrBVr2COd3RgcTLyUiEXMNBlDU/cgYq6taUS0fExrWW4w==", - "dev": true, - "dependencies": { - "@jest/types": "^29.6.1", - "@types/node": "*", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "graceful-fs": "^4.2.9", - "picomatch": "^2.2.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-validate": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.0.2.tgz", - "integrity": "sha512-AeRKm7cEucSy7tr54r3LhiGIXYvOILUwBM1S7jQkKs6YelwAlWKsmZGVrQR7uwsd31rBTnR5NQkODi1Z+6TKIQ==", - "dev": true, - "dependencies": { - "@jest/types": "^29.0.2", - "camelcase": "^6.2.0", - "chalk": "^4.0.0", - "jest-get-type": "^29.0.0", - "leven": "^3.1.0", - "pretty-format": "^29.0.2" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-validate/node_modules/camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/jest-watcher": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.0.2.tgz", - "integrity": "sha512-ds2bV0oyUdYoyrUTv4Ga5uptz4cEvmmP/JzqDyzZZanvrIn8ipxg5l3SDOAIiyuAx1VdHd2FBzeXPFO5KPH8vQ==", - "dev": true, - "dependencies": { - "@jest/test-result": "^29.0.2", - "@jest/types": "^29.0.2", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "emittery": "^0.10.2", - "jest-util": "^29.0.2", - "string-length": "^4.0.1" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-websocket-mock": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/jest-websocket-mock/-/jest-websocket-mock-2.4.0.tgz", - "integrity": "sha512-AOwyuRw6fgROXHxMOiTDl1/T4dh3fV4jDquha5N0csS/PNp742HeTZWPAuKppVRSQ8s3fUGgJHoyZT9JDO0hMA==", - "dev": true, - "dependencies": { - "jest-diff": "^28.0.2", - "mock-socket": "^9.1.0" - } - }, - "node_modules/jest-websocket-mock/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-websocket-mock/node_modules/diff-sequences": { - "version": "28.1.1", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-28.1.1.tgz", - "integrity": "sha512-FU0iFaH/E23a+a718l8Qa/19bF9p06kgE0KipMOMadwa3SjnaElKzPaUC0vnibs6/B/9ni97s61mcejk8W1fQw==", - "dev": true, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/jest-websocket-mock/node_modules/jest-diff": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-28.1.3.tgz", - "integrity": "sha512-8RqP1B/OXzjjTWkqMX67iqgwBVJRgCyKD3L9nq+6ZqJMdvjE8RgHktqZ6jNrkdMT+dJuYNI3rhQpxaz7drJHfw==", - "dev": true, - "dependencies": { - "chalk": "^4.0.0", - "diff-sequences": "^28.1.1", - "jest-get-type": "^28.0.2", - "pretty-format": "^28.1.3" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/jest-websocket-mock/node_modules/jest-get-type": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-28.0.2.tgz", - "integrity": "sha512-ioj2w9/DxSYHfOm5lJKCdcAmPJzQXmbM/Url3rhlghrPvT3tt+7a/+oXc9azkKmLvoiXjtV83bEWqi+vs5nlPA==", - "dev": true, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/jest-websocket-mock/node_modules/pretty-format": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-28.1.3.tgz", - "integrity": "sha512-8gFb/To0OmxHR9+ZTb14Df2vNxdGCX8g1xWGUTqUw5TiZvcQf5sHKObd5UcPyLLyowNwDAMTF3XWOG1B6mxl1Q==", - "dev": true, - "dependencies": { - "@jest/schemas": "^28.1.3", - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/jose": { - "version": "4.14.4", - "resolved": "https://registry.npmjs.org/jose/-/jose-4.14.4.tgz", - "integrity": "sha512-j8GhLiKmUAh+dsFXlX1aJCbt5KMibuKb+d7j1JaOJG6s2UjX1PQlW+OKB/sD4a/5ZYF4RcmYmLSndOoU3Lt/3g==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/panva" - } - }, - "node_modules/js-md4": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/js-md4/-/js-md4-0.3.2.tgz", - "integrity": "sha512-/GDnfQYsltsjRswQhN9fhv3EMw2sCpUdrdxyWDOUK7eyD++r3gRhzgiQgc/x4MAv2i1iuQ4lxO5mvqM3vj4bwA==", - "dev": true - }, - "node_modules/js-sha512": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/js-sha512/-/js-sha512-0.8.0.tgz", - "integrity": "sha512-PWsmefG6Jkodqt+ePTvBZCSMFgN7Clckjd0O7su3I0+BW2QWUTJNzjktHsztGLhncP2h8mcF9V9Y2Ha59pAViQ==", - "dev": true - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, - "node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==", - "dev": true - }, - "node_modules/jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "dev": true, - "bin": { - "jsesc": "bin/jsesc" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true - }, - "node_modules/json-schema": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", - "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", - "dev": true - }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", - "dev": true - }, - "node_modules/json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", - "dev": true - }, - "node_modules/json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "dev": true, - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", - "dev": true, - "dependencies": { - "universalify": "^2.0.0" - }, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/jsprim": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-2.0.2.tgz", - "integrity": "sha512-gqXddjPqQ6G40VdnI6T6yObEC+pDNvyP95wdQhkWkg7crHH3km5qP1FsOXEkzEQwnz6gz5qGTn1c2Y52wP3OyQ==", - "dev": true, - "engines": [ - "node >=0.6.0" - ], - "dependencies": { - "assert-plus": "1.0.0", - "extsprintf": "1.3.0", - "json-schema": "0.4.0", - "verror": "1.10.0" - } - }, - "node_modules/kleur": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", - "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/leven": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", - "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/lines-and-columns": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "dev": true - }, - "node_modules/liquid-json": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/liquid-json/-/liquid-json-0.3.1.tgz", - "integrity": "sha512-wUayTU8MS827Dam6MxgD72Ui+KOSF+u/eIqpatOtjnvgJ0+mnDq33uC2M7J0tPK+upe/DpUAuK4JUU89iBoNKQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true - }, - "node_modules/lodash.get": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", - "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==", - "deprecated": "This package is deprecated. Use the optional chaining (?.) operator instead." - }, - "node_modules/lodash.isequal": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", - "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==", - "deprecated": "This package is deprecated. Use require('node:util').isDeepStrictEqual instead." - }, - "node_modules/lodash.memoize": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", - "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", - "dev": true - }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true - }, - "node_modules/lodash.mergewith": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz", - "integrity": "sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ==" - }, - "node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dev": true, - "dependencies": { - "semver": "^6.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/make-dir/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/make-error": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true - }, - "node_modules/makeerror": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", - "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", - "dev": true, - "dependencies": { - "tmpl": "1.0.5" - } - }, - "node_modules/media-typer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/merge-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" - }, - "node_modules/merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true - }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/methods": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", - "dev": true, - "dependencies": { - "braces": "^3.0.2", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", - "bin": { - "mime": "cli.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-format": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/mime-format/-/mime-format-2.0.1.tgz", - "integrity": "sha512-XxU3ngPbEnrYnNbIX+lYSaYg0M01v6p2ntd2YaFksTu0vayaw5OJvbdRyWs07EYRlLED5qadUZ+xo+XhOvFhwg==", - "dev": true, - "dependencies": { - "charset": "^1.0.0" - } - }, - "node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/mimic-response": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz", - "integrity": "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/minimalistic-assert": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", - "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", - "dev": true - }, - "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/minimist": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", - "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", - "dev": true - }, - "node_modules/mkdirp": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-3.0.1.tgz", - "integrity": "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==", - "dev": true, - "bin": { - "mkdirp": "dist/cjs/src/bin.js" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/mkdirp-classic": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", - "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", - "dev": true - }, - "node_modules/mock-socket": { - "version": "9.1.5", - "resolved": "https://registry.npmjs.org/mock-socket/-/mock-socket-9.1.5.tgz", - "integrity": "sha512-3DeNIcsQixWHHKk6NdoBhWI4t1VMj5/HzfnI1rE/pLl5qKx7+gd4DNA07ehTaZ6MoUU053si6Hd+YtiM/tQZfg==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/morgan": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.10.0.tgz", - "integrity": "sha512-AbegBVI4sh6El+1gNwvD5YIck7nSA36weD7xvIxG4in80j/UoK8AEGaWnnz8v1GxonMCltmlNs5ZKbGvl9b1XQ==", - "dependencies": { - "basic-auth": "~2.0.1", - "debug": "2.6.9", - "depd": "~2.0.0", - "on-finished": "~2.3.0", - "on-headers": "~1.0.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/morgan/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/morgan/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - }, - "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, - "node_modules/multer": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/multer/-/multer-2.1.1.tgz", - "integrity": "sha512-mo+QTzKlx8R7E5ylSXxWzGoXoZbOsRMpyitcht8By2KHvMbf3tjwosZ/Mu/XYU6UuJ3VZnODIrak5ZrPiPyB6A==", - "dependencies": { - "append-field": "^1.0.0", - "busboy": "^1.6.0", - "concat-stream": "^2.0.0", - "type-is": "^1.6.18" - }, - "engines": { - "node": ">= 10.16.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/multistream": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/multistream/-/multistream-4.1.0.tgz", - "integrity": "sha512-J1XDiAmmNpRCBfIWJv+n0ymC4ABcf/Pl+5YvC5B/D2f/2+8PtHvCNxMPKiQcZyi922Hq69J2YOpb1pTywfifyw==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "once": "^1.4.0", - "readable-stream": "^3.6.0" - } - }, - "node_modules/multistream/node_modules/readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "dev": true, - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/napi-build-utils": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz", - "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==", - "dev": true - }, - "node_modules/natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", - "dev": true - }, - "node_modules/negotiator": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", - "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/neo-async": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", - "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", - "dev": true - }, - "node_modules/newman": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/newman/-/newman-6.0.0.tgz", - "integrity": "sha512-QaANQC5b6ga348MezIVRI9ZmMs+cg3MdYIp0tSEauH2tmWOAR9+cghNsFJNjU9JPui3jJp1ALC7pQq6g3Jqpxw==", - "dev": true, - "dependencies": { - "@postman/tough-cookie": "4.1.3-postman.1", - "async": "3.2.4", - "chardet": "1.6.0", - "cli-progress": "3.12.0", - "cli-table3": "0.6.3", - "colors": "1.4.0", - "commander": "11.0.0", - "csv-parse": "4.16.3", - "filesize": "10.0.12", - "liquid-json": "0.3.1", - "lodash": "4.17.21", - "mkdirp": "3.0.1", - "postman-collection": "4.2.1", - "postman-collection-transformer": "4.1.7", - "postman-request": "2.88.1-postman.33", - "postman-runtime": "7.33.0", - "pretty-ms": "7.0.1", - "semver": "7.5.4", - "serialised-error": "1.1.3", - "word-wrap": "1.2.5", - "xmlbuilder": "15.1.1" - }, - "bin": { - "newman": "bin/newman.js" - }, - "engines": { - "node": ">=16" - } - }, - "node_modules/node-abi": { - "version": "2.30.1", - "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.30.1.tgz", - "integrity": "sha512-/2D0wOQPgaUWzVSVgRMx+trKJRC2UG4SUc4oCJoXx9Uxjtp0Vy3/kt7zcbxHF8+Z/pK3UloLWzBISg72brfy1w==", - "dev": true, - "dependencies": { - "semver": "^5.4.1" - } - }, - "node_modules/node-abi/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true, - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/node-fetch": { - "version": "2.6.7", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", - "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", - "dev": true, - "dependencies": { - "whatwg-url": "^5.0.0" - }, - "engines": { - "node": "4.x || >=6.0.0" - }, - "peerDependencies": { - "encoding": "^0.1.0" - }, - "peerDependenciesMeta": { - "encoding": { - "optional": true - } - } - }, - "node_modules/node-int64": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", - "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", - "dev": true - }, - "node_modules/node-oauth1": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/node-oauth1/-/node-oauth1-1.3.0.tgz", - "integrity": "sha512-0yggixNfrA1KcBwvh/Hy2xAS1Wfs9dcg6TdFf2zN7gilcAigMdrtZ4ybrBSXBgLvGDw9V1p2MRnGBMq7XjTWLg==", - "dev": true - }, - "node_modules/node-releases": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.5.tgz", - "integrity": "sha512-U9h1NLROZTq9uE1SNffn6WuPDg8icmi3ns4rEl/oTfIle4iLjTliCzgTsbaIFMq/Xn078/lfY/BL0GWZ+psK4Q==", - "dev": true - }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "dev": true, - "dependencies": { - "path-key": "^3.0.0" - }, - "engines": { - "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==", - "dev": true, - "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/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==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/oauth-sign": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", - "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-hash": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-1.3.1.tgz", - "integrity": "sha512-OSuu/pU4ENM9kmREg0BdNrUDIl1heYa4mBZacJc+vVWz4GtAwu7jO8s4AIt2aGRUTqxykpWzI3Oqnsm13tTMDA==", - "dev": true, - "engines": { - "node": ">= 0.10.0" - } - }, - "node_modules/object-inspect": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", - "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/on-finished": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", - "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", - "dependencies": { - "ee-first": "1.1.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/on-headers": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", - "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dev": true, - "dependencies": { - "mimic-fn": "^2.1.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/openapi-types": { - "version": "12.1.3", - "resolved": "https://registry.npmjs.org/openapi-types/-/openapi-types-12.1.3.tgz", - "integrity": "sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw==", - "peer": true - }, - "node_modules/optionator": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", - "dev": true, - "dependencies": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.3" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/p-is-promise": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-3.0.0.tgz", - "integrity": "sha512-Wo8VsW4IRQSKVXsJCn7TomUaVtyfjVDn3nUP7kE967BQk0CwFpdbZs0X0uk5sW9mkBa9eNM7hCMaG93WUAwxYQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/parse-ms": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/parse-ms/-/parse-ms-2.1.0.tgz", - "integrity": "sha512-kHt7kzLoS9VBZfUsiKjv43mr91ea+U05EyKkEtqp7vNbHxmaVuEqN7XxeEVnGrMtYOAxGrDElSi96K7EgO1zCA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true - }, - "node_modules/path-to-regexp": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" - }, - "node_modules/path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/performance-now": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==", - "dev": true - }, - "node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", - "dev": true - }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/pirates": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz", - "integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==", - "dev": true, - "engines": { - "node": ">= 6" - } - }, - "node_modules/pkg": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/pkg/-/pkg-5.8.0.tgz", - "integrity": "sha512-8h9PUDYFi+LOMLbIyGRdP21g08mAtHidSpofSrf8LWhxUWGHymaRzcopEGiynB5EhQmZUKM6PQ9kCImV2TpdjQ==", - "dev": true, - "dependencies": { - "@babel/generator": "7.18.2", - "@babel/parser": "7.18.4", - "@babel/types": "7.18.4", - "chalk": "^4.1.2", - "fs-extra": "^9.1.0", - "globby": "^11.1.0", - "into-stream": "^6.0.0", - "is-core-module": "2.9.0", - "minimist": "^1.2.6", - "multistream": "^4.1.0", - "pkg-fetch": "3.4.2", - "prebuild-install": "6.1.4", - "resolve": "^1.22.0", - "stream-meter": "^1.0.4" - }, - "bin": { - "pkg": "lib-es5/bin.js" - }, - "peerDependencies": { - "node-notifier": ">=9.0.1" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "node_modules/pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "dev": true, - "dependencies": { - "find-up": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/pkg-fetch": { - "version": "3.4.2", - "resolved": "https://registry.npmjs.org/pkg-fetch/-/pkg-fetch-3.4.2.tgz", - "integrity": "sha512-0+uijmzYcnhC0hStDjm/cl2VYdrmVVBpe7Q8k9YBojxmR5tG8mvR9/nooQq3QSXiQqORDVOTY3XqMEqJVIzkHA==", - "dev": true, - "dependencies": { - "chalk": "^4.1.2", - "fs-extra": "^9.1.0", - "https-proxy-agent": "^5.0.0", - "node-fetch": "^2.6.6", - "progress": "^2.0.3", - "semver": "^7.3.5", - "tar-fs": "^2.1.1", - "yargs": "^16.2.0" - }, - "bin": { - "pkg-fetch": "lib-es5/bin.js" - } - }, - "node_modules/pkg-fetch/node_modules/yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", - "dev": true, - "dependencies": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/pkg-fetch/node_modules/yargs-parser": { - "version": "20.2.9", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/postman-collection": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/postman-collection/-/postman-collection-4.2.1.tgz", - "integrity": "sha512-DFLt3/yu8+ldtOTIzmBUctoupKJBOVK4NZO0t68K2lIir9smQg7OdQTBjOXYy+PDh7u0pSDvD66tm93eBHEPHA==", - "dev": true, - "dependencies": { - "@faker-js/faker": "5.5.3", - "file-type": "3.9.0", - "http-reasons": "0.1.0", - "iconv-lite": "0.6.3", - "liquid-json": "0.3.1", - "lodash": "4.17.21", - "mime-format": "2.0.1", - "mime-types": "2.1.35", - "postman-url-encoder": "3.0.5", - "semver": "7.5.4", - "uuid": "8.3.2" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/postman-collection-transformer": { - "version": "4.1.7", - "resolved": "https://registry.npmjs.org/postman-collection-transformer/-/postman-collection-transformer-4.1.7.tgz", - "integrity": "sha512-SxJkm/LnlFZs2splUBnS4jQFicgBptghpm4voHtNnaum3Ad64E2MHLV4fJhv58dVUmFwdSwdQUN3m2q0iLecnQ==", - "dev": true, - "dependencies": { - "commander": "8.3.0", - "inherits": "2.0.4", - "lodash": "4.17.21", - "semver": "7.5.4", - "strip-json-comments": "3.1.1" - }, - "bin": { - "postman-collection-transformer": "bin/transform-collection.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/postman-collection-transformer/node_modules/commander": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", - "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", - "dev": true, - "engines": { - "node": ">= 12" - } - }, - "node_modules/postman-collection/node_modules/iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "dev": true, - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/postman-collection/node_modules/uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "dev": true, - "bin": { - "uuid": "dist/bin/uuid" - } - }, - "node_modules/postman-request": { - "version": "2.88.1-postman.33", - "resolved": "https://registry.npmjs.org/postman-request/-/postman-request-2.88.1-postman.33.tgz", - "integrity": "sha512-uL9sCML4gPH6Z4hreDWbeinKU0p0Ke261nU7OvII95NU22HN6Dk7T/SaVPaj6T4TsQqGKIFw6/woLZnH7ugFNA==", - "dev": true, - "dependencies": { - "@postman/form-data": "~3.1.1", - "@postman/tough-cookie": "~4.1.3-postman.1", - "@postman/tunnel-agent": "^0.6.3", - "aws-sign2": "~0.7.0", - "aws4": "^1.12.0", - "brotli": "^1.3.3", - "caseless": "~0.12.0", - "combined-stream": "~1.0.6", - "extend": "~3.0.2", - "forever-agent": "~0.6.1", - "har-validator": "~5.1.3", - "http-signature": "~1.3.1", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "^2.1.35", - "oauth-sign": "~0.9.0", - "performance-now": "^2.1.0", - "qs": "~6.5.3", - "safe-buffer": "^5.1.2", - "stream-length": "^1.0.2", - "uuid": "^8.3.2" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/postman-request/node_modules/qs": { - "version": "6.5.3", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", - "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==", - "dev": true, - "engines": { - "node": ">=0.6" - } - }, - "node_modules/postman-request/node_modules/uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "dev": true, - "bin": { - "uuid": "dist/bin/uuid" - } - }, - "node_modules/postman-runtime": { - "version": "7.33.0", - "resolved": "https://registry.npmjs.org/postman-runtime/-/postman-runtime-7.33.0.tgz", - "integrity": "sha512-cYCb+5Y12FwZU/T3gOj2SKiOz38pisVLc0tdppb+ZlG7iqn5aLgxghJwhjG62pZCV6uixKiQX1hNdLSk9a9Xtw==", - "dev": true, - "dependencies": { - "@postman/tough-cookie": "4.1.3-postman.1", - "async": "3.2.4", - "aws4": "1.12.0", - "handlebars": "4.7.8", - "httpntlm": "1.8.13", - "jose": "4.14.4", - "js-sha512": "0.8.0", - "lodash": "4.17.21", - "mime-types": "2.1.35", - "node-oauth1": "1.3.0", - "performance-now": "2.1.0", - "postman-collection": "4.2.0", - "postman-request": "2.88.1-postman.33", - "postman-sandbox": "4.2.7", - "postman-url-encoder": "3.0.5", - "serialised-error": "1.1.3", - "strip-json-comments": "3.1.1", - "uuid": "8.3.2" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/postman-runtime/node_modules/iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "dev": true, - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/postman-runtime/node_modules/postman-collection": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/postman-collection/-/postman-collection-4.2.0.tgz", - "integrity": "sha512-tvOLgN1h6Kab6dt43PmBoV5kYO/YUta3x0C2QqfmbzmHZe47VTpZ/+gIkGlbNhjKNPUUub5X6ehxYKoaTYdy1w==", - "dev": true, - "dependencies": { - "@faker-js/faker": "5.5.3", - "file-type": "3.9.0", - "http-reasons": "0.1.0", - "iconv-lite": "0.6.3", - "liquid-json": "0.3.1", - "lodash": "4.17.21", - "mime-format": "2.0.1", - "mime-types": "2.1.35", - "postman-url-encoder": "3.0.5", - "semver": "7.5.4", - "uuid": "8.3.2" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/postman-runtime/node_modules/uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "dev": true, - "bin": { - "uuid": "dist/bin/uuid" - } - }, - "node_modules/postman-sandbox": { - "version": "4.2.7", - "resolved": "https://registry.npmjs.org/postman-sandbox/-/postman-sandbox-4.2.7.tgz", - "integrity": "sha512-/EcCrKnb/o+9iLS4u+H76E0kBomJFjPptVjoDiq1uZ7Es/4aTv0MAX+0aoDxdDO+0h9sl8vy65uKQwyjN7AOaw==", - "dev": true, - "dependencies": { - "lodash": "4.17.21", - "postman-collection": "4.2.0", - "teleport-javascript": "1.0.0", - "uvm": "2.1.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/postman-sandbox/node_modules/iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "dev": true, - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/postman-sandbox/node_modules/postman-collection": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/postman-collection/-/postman-collection-4.2.0.tgz", - "integrity": "sha512-tvOLgN1h6Kab6dt43PmBoV5kYO/YUta3x0C2QqfmbzmHZe47VTpZ/+gIkGlbNhjKNPUUub5X6ehxYKoaTYdy1w==", - "dev": true, - "dependencies": { - "@faker-js/faker": "5.5.3", - "file-type": "3.9.0", - "http-reasons": "0.1.0", - "iconv-lite": "0.6.3", - "liquid-json": "0.3.1", - "lodash": "4.17.21", - "mime-format": "2.0.1", - "mime-types": "2.1.35", - "postman-url-encoder": "3.0.5", - "semver": "7.5.4", - "uuid": "8.3.2" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/postman-sandbox/node_modules/uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "dev": true, - "bin": { - "uuid": "dist/bin/uuid" - } - }, - "node_modules/postman-url-encoder": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/postman-url-encoder/-/postman-url-encoder-3.0.5.tgz", - "integrity": "sha512-jOrdVvzUXBC7C+9gkIkpDJ3HIxOHTIqjpQ4C1EMt1ZGeMvSEpbFCKq23DEfgsj46vMnDgyQf+1ZLp2Wm+bKSsA==", - "dev": true, - "dependencies": { - "punycode": "^2.1.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/prebuild-install": { - "version": "6.1.4", - "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-6.1.4.tgz", - "integrity": "sha512-Z4vpywnK1lBg+zdPCVCsKq0xO66eEV9rWo2zrROGGiRS4JtueBOdlB1FnY8lcy7JsUud/Q3ijUxyWN26Ika0vQ==", - "dev": true, - "dependencies": { - "detect-libc": "^1.0.3", - "expand-template": "^2.0.3", - "github-from-package": "0.0.0", - "minimist": "^1.2.3", - "mkdirp-classic": "^0.5.3", - "napi-build-utils": "^1.0.1", - "node-abi": "^2.21.0", - "npmlog": "^4.0.1", - "pump": "^3.0.0", - "rc": "^1.2.7", - "simple-get": "^3.0.3", - "tar-fs": "^2.0.0", - "tunnel-agent": "^0.6.0" - }, - "bin": { - "prebuild-install": "bin.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/pretty-format": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.0.2.tgz", - "integrity": "sha512-wp3CdtUa3cSJVFn3Miu5a1+pxc1iPIQTenOAn+x5erXeN1+ryTcLesV5pbK/rlW5EKwp27x38MoYfNGaNXDDhg==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.0.0", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/pretty-format/node_modules/@jest/schemas": { - "version": "29.0.0", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.0.0.tgz", - "integrity": "sha512-3Ab5HgYIIAnS0HjqJHQYZS+zXc4tUmTmBH3z83ajI6afXp8X3ZtdLX+nXx+I7LNkJD7uN9LAVhgnjDgZa2z0kA==", - "dev": true, - "dependencies": { - "@sinclair/typebox": "^0.24.1" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/pretty-format/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/pretty-ms": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/pretty-ms/-/pretty-ms-7.0.1.tgz", - "integrity": "sha512-973driJZvxiGOQ5ONsFhOF/DtzPMOMtgC11kCpUrPGMTgqp2q/1gwzCquocrN33is0VZ5GFHXZYMM9l6h67v2Q==", - "dev": true, - "dependencies": { - "parse-ms": "^2.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", - "dev": true - }, - "node_modules/progress": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/prompts": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", - "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", - "dev": true, - "dependencies": { - "kleur": "^3.0.3", - "sisteransi": "^1.0.5" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/proxy-addr": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", - "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", - "dependencies": { - "forwarded": "0.2.0", - "ipaddr.js": "1.9.1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/psl": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", - "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==", - "dev": true - }, - "node_modules/pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dev": true, - "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "node_modules/punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/qs": { - "version": "6.10.3", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.3.tgz", - "integrity": "sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ==", - "dependencies": { - "side-channel": "^1.0.4" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/querystringify": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", - "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", - "dev": true - }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/range-parser": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/raw-body": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", - "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", - "dependencies": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/rc": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", - "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", - "dev": true, - "dependencies": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - }, - "bin": { - "rc": "cli.js" - } - }, - "node_modules/rc/node_modules/strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/react-is": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", - "dev": true - }, - "node_modules/readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", - "dev": true, - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/regexpp": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", - "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - } - }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/requires-port": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", - "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", - "dev": true - }, - "node_modules/resolve": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", - "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", - "dev": true, - "dependencies": { - "is-core-module": "^2.8.1", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/resolve-cwd": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", - "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", - "dev": true, - "dependencies": { - "resolve-from": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/resolve-cwd/node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/resolve.exports": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-1.1.0.tgz", - "integrity": "sha512-J1l+Zxxp4XK3LUDZ9m60LRJF/mAe4z6a4xyabPHk7pvK5t35dACV32iIjJDFeWZFfZlO29w6SZ67knR0tHzJtQ==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true, - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, - "node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" - }, - "node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/send": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", - "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", - "dependencies": { - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "mime": "1.6.0", - "ms": "2.1.3", - "on-finished": "2.4.1", - "range-parser": "~1.2.1", - "statuses": "2.0.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/send/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/send/node_modules/debug/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - }, - "node_modules/send/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" - }, - "node_modules/send/node_modules/on-finished": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", - "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", - "dependencies": { - "ee-first": "1.1.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/serialised-error": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/serialised-error/-/serialised-error-1.1.3.tgz", - "integrity": "sha512-vybp3GItaR1ZtO2nxZZo8eOo7fnVaNtP3XE2vJKgzkKR2bagCkdJ1EpYYhEMd3qu/80DwQk9KjsNSxE3fXWq0g==", - "dev": true, - "dependencies": { - "object-hash": "^1.1.2", - "stack-trace": "0.0.9", - "uuid": "^3.0.0" - } - }, - "node_modules/serialised-error/node_modules/uuid": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", - "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", - "dev": true, - "bin": { - "uuid": "bin/uuid" - } - }, - "node_modules/serve-static": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", - "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", - "dependencies": { - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "parseurl": "~1.3.3", - "send": "0.18.0" - }, - "engines": { - "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": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", - "dev": true - }, - "node_modules/setprototypeof": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", - "dependencies": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true - }, - "node_modules/simple-concat": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", - "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/simple-get": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.1.tgz", - "integrity": "sha512-CQ5LTKGfCpvE1K0n2us+kuMPbk/q0EKl82s4aheV9oXjFEz6W/Y7oQFVJuU6QG77hRT4Ghb5RURteF5vnWjupA==", - "dev": true, - "dependencies": { - "decompress-response": "^4.2.0", - "once": "^1.3.1", - "simple-concat": "^1.0.0" - } - }, - "node_modules/sisteransi": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", - "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", - "dev": true - }, - "node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/source-map-support": { - "version": "0.5.13", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", - "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", - "dev": true, - "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "node_modules/sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", - "dev": true - }, - "node_modules/sshpk": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.18.0.tgz", - "integrity": "sha512-2p2KJZTSqQ/I3+HX42EpYOa2l3f8Erv8MWKsy2I9uf4wA7yFIkXRffYdsx86y6z4vHtV8u7g+pPlr8/4ouAxsQ==", - "dev": true, - "dependencies": { - "asn1": "~0.2.3", - "assert-plus": "^1.0.0", - "bcrypt-pbkdf": "^1.0.0", - "dashdash": "^1.12.0", - "ecc-jsbn": "~0.1.1", - "getpass": "^0.1.1", - "jsbn": "~0.1.0", - "safer-buffer": "^2.0.2", - "tweetnacl": "~0.14.0" - }, - "bin": { - "sshpk-conv": "bin/sshpk-conv", - "sshpk-sign": "bin/sshpk-sign", - "sshpk-verify": "bin/sshpk-verify" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/stack-trace": { - "version": "0.0.9", - "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.9.tgz", - "integrity": "sha512-vjUc6sfgtgY0dxCdnc40mK6Oftjo9+2K8H/NG81TMhgL392FtiPA9tn9RLyTxXmTLPJPjF3VyzFp6bsWFLisMQ==", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/stack-utils": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.5.tgz", - "integrity": "sha512-xrQcmYhOsn/1kX+Vraq+7j4oE2j/6BFscZ0etmYg81xuM8Gq0022Pxb8+IqgOFUIaxHs0KaSb7T1+OegiNrNFA==", - "dev": true, - "dependencies": { - "escape-string-regexp": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/stack-utils/node_modules/escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/stream-length": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/stream-length/-/stream-length-1.0.2.tgz", - "integrity": "sha512-aI+qKFiwoDV4rsXiS7WRoCt+v2RX1nUj17+KJC5r2gfh5xoSJIfP6Y3Do/HtvesFcTSWthIuJ3l1cvKQY/+nZg==", - "dev": true, - "dependencies": { - "bluebird": "^2.6.2" - } - }, - "node_modules/stream-meter": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/stream-meter/-/stream-meter-1.0.4.tgz", - "integrity": "sha1-Uq+Vql6nYKJJFxZwTb/5D3Ov3R0=", - "dev": true, - "dependencies": { - "readable-stream": "^2.1.4" - } - }, - "node_modules/streamsearch": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", - "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/string-length": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", - "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", - "dev": true, - "dependencies": { - "char-regex": "^1.0.2", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "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==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-bom": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", - "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/supports-hyperlinks": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.3.0.tgz", - "integrity": "sha512-RpsAZlpWcDwOPQA22aCH4J0t7L8JmAvsCxfOSEwm7cQs3LshN36QaTkwd70DnBOXDWGssw2eUoc8CaRWT0XunA==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0", - "supports-color": "^7.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/swagger-jsdoc": { - "version": "6.2.8", - "resolved": "https://registry.npmjs.org/swagger-jsdoc/-/swagger-jsdoc-6.2.8.tgz", - "integrity": "sha512-VPvil1+JRpmJ55CgAtn8DIcpBs0bL5L3q5bVQvF4tAW/k/9JYSj7dCpaYCAv5rufe0vcCbBRQXGvzpkWjvLklQ==", - "dependencies": { - "commander": "6.2.0", - "doctrine": "3.0.0", - "glob": "7.1.6", - "lodash.mergewith": "^4.6.2", - "swagger-parser": "^10.0.3", - "yaml": "2.0.0-1" - }, - "bin": { - "swagger-jsdoc": "bin/swagger-jsdoc.js" - }, - "engines": { - "node": ">=12.0.0" - } - }, - "node_modules/swagger-jsdoc/node_modules/commander": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.0.tgz", - "integrity": "sha512-zP4jEKbe8SHzKJYQmq8Y9gYjtO/POJLgIdKgV7B9qNmABVFVc+ctqSX6iXh4mCpJfRBOabiZ2YKPg8ciDw6C+Q==", - "engines": { - "node": ">= 6" - } - }, - "node_modules/swagger-jsdoc/node_modules/glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", - "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/swagger-parser": { - "version": "10.0.3", - "resolved": "https://registry.npmjs.org/swagger-parser/-/swagger-parser-10.0.3.tgz", - "integrity": "sha512-nF7oMeL4KypldrQhac8RyHerJeGPD1p2xDh900GPvc+Nk7nWP6jX2FcC7WmkinMoAmoO774+AFXcWsW8gMWEIg==", - "dependencies": { - "@apidevtools/swagger-parser": "10.0.3" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/swagger-ui-dist": { - "version": "5.32.0", - "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-5.32.0.tgz", - "integrity": "sha512-nKZB0OuDvacB0s/lC2gbge+RigYvGRGpLLMWMFxaTUwfM+CfndVk9Th2IaTinqXiz6Mn26GK2zriCpv6/+5m3Q==", - "dependencies": { - "@scarf/scarf": "=1.4.0" - } - }, - "node_modules/swagger-ui-express": { - "version": "4.6.3", - "resolved": "https://registry.npmjs.org/swagger-ui-express/-/swagger-ui-express-4.6.3.tgz", - "integrity": "sha512-CDje4PndhTD2HkgyKH3pab+LKspDeB/NhPN2OF1j+piYIamQqBYwAXWESOT1Yju2xFg51bRW9sUng2WxDjzArw==", - "dependencies": { - "swagger-ui-dist": ">=4.11.0" - }, - "engines": { - "node": ">= v0.10.32" - }, - "peerDependencies": { - "express": ">=4.0.0 || >=5.0.0-beta" - } - }, - "node_modules/tar-fs": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", - "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", - "dev": true, - "dependencies": { - "chownr": "^1.1.1", - "mkdirp-classic": "^0.5.2", - "pump": "^3.0.0", - "tar-stream": "^2.1.4" - } - }, - "node_modules/tar-stream": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", - "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", - "dev": true, - "dependencies": { - "bl": "^4.0.3", - "end-of-stream": "^1.4.1", - "fs-constants": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.1.1" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/tar-stream/node_modules/readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "dev": true, - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/teleport-javascript": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/teleport-javascript/-/teleport-javascript-1.0.0.tgz", - "integrity": "sha512-j1llvWVFyEn/6XIFDfX5LAU43DXe0GCt3NfXDwJ8XpRRMkS+i50SAkonAONBy+vxwPFBd50MFU8a2uj8R/ccLg==", - "dev": true - }, - "node_modules/terminal-link": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-2.1.1.tgz", - "integrity": "sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==", - "dev": true, - "dependencies": { - "ansi-escapes": "^4.2.1", - "supports-hyperlinks": "^2.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/test-exclude": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", - "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", - "dev": true, - "dependencies": { - "@istanbuljs/schema": "^0.1.2", - "glob": "^7.1.4", - "minimatch": "^3.0.4" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", - "dev": true - }, - "node_modules/tmpl": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", - "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", - "dev": true - }, - "node_modules/to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/toidentifier": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", - "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", - "engines": { - "node": ">=0.6" - } - }, - "node_modules/tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", - "dev": true - }, - "node_modules/ts-jest": { - "version": "29.1.1", - "resolved": "https://registry.npmmirror.com/ts-jest/-/ts-jest-29.1.1.tgz", - "integrity": "sha512-D6xjnnbP17cC85nliwGiL+tpoKN0StpgE0TeOjXQTU6MVCfsB4v7aW05CgQ/1OywGb0x/oy9hHFnN+sczTiRaA==", - "dev": true, - "dependencies": { - "bs-logger": "0.x", - "fast-json-stable-stringify": "2.x", - "jest-util": "^29.0.0", - "json5": "^2.2.3", - "lodash.memoize": "4.x", - "make-error": "1.x", - "semver": "^7.5.3", - "yargs-parser": "^21.0.1" - }, - "bin": { - "ts-jest": "cli.js" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "@babel/core": ">=7.0.0-beta.0 <8", - "@jest/types": "^29.0.0", - "babel-jest": "^29.0.0", - "jest": "^29.0.0", - "typescript": ">=4.3 <6" - }, - "peerDependenciesMeta": { - "@babel/core": { - "optional": true - }, - "@jest/types": { - "optional": true - }, - "babel-jest": { - "optional": true - }, - "esbuild": { - "optional": true - } - } - }, - "node_modules/ts-node": { - "version": "10.9.1", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", - "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", - "dev": true, - "dependencies": { - "@cspotcode/source-map-support": "^0.8.0", - "@tsconfig/node10": "^1.0.7", - "@tsconfig/node12": "^1.0.7", - "@tsconfig/node14": "^1.0.0", - "@tsconfig/node16": "^1.0.2", - "acorn": "^8.4.1", - "acorn-walk": "^8.1.1", - "arg": "^4.1.0", - "create-require": "^1.1.0", - "diff": "^4.0.1", - "make-error": "^1.1.1", - "v8-compile-cache-lib": "^3.0.1", - "yn": "3.1.1" - }, - "bin": { - "ts-node": "dist/bin.js", - "ts-node-cwd": "dist/bin-cwd.js", - "ts-node-esm": "dist/bin-esm.js", - "ts-node-script": "dist/bin-script.js", - "ts-node-transpile-only": "dist/bin-transpile.js", - "ts-script": "dist/bin-script-deprecated.js" - }, - "peerDependencies": { - "@swc/core": ">=1.2.50", - "@swc/wasm": ">=1.2.50", - "@types/node": "*", - "typescript": ">=2.7" - }, - "peerDependenciesMeta": { - "@swc/core": { - "optional": true - }, - "@swc/wasm": { - "optional": true - } - } - }, - "node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - }, - "node_modules/tsutils": { - "version": "3.21.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", - "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", - "dev": true, - "dependencies": { - "tslib": "^1.8.1" - }, - "engines": { - "node": ">= 6" - }, - "peerDependencies": { - "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" - } - }, - "node_modules/tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", - "dev": true, - "dependencies": { - "safe-buffer": "^5.0.1" - }, - "engines": { - "node": "*" - } - }, - "node_modules/tweetnacl": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==", - "dev": true - }, - "node_modules/type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/type-detect": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/type-is": { - "version": "1.6.18", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", - "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", - "dependencies": { - "media-typer": "0.3.0", - "mime-types": "~2.1.24" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/typedarray": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==" - }, - "node_modules/typescript": { - "version": "4.8.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.2.tgz", - "integrity": "sha512-C0I1UsrrDHo2fYI5oaCGbSejwX4ch+9Y5jTQELvovfmFkK3HHSZJB8MSJcWLmCUBzQBchCrZ9rMRV6GuNrvGtw==", - "dev": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=4.2.0" - } - }, - "node_modules/uglify-js": { - "version": "3.17.4", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.4.tgz", - "integrity": "sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==", - "dev": true, - "optional": true, - "bin": { - "uglifyjs": "bin/uglifyjs" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/underscore": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.12.1.tgz", - "integrity": "sha512-hEQt0+ZLDVUMhebKxL4x1BTtDY7bavVofhZ9KZ4aI26X9SRaE+Y3m83XUL1UP2jn8ynjndwCCpEHdUG+9pP1Tw==", - "dev": true - }, - "node_modules/universalify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", - "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", - "dev": true, - "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/url-parse": { - "version": "1.5.10", - "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", - "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", - "dev": true, - "dependencies": { - "querystringify": "^2.1.1", - "requires-port": "^1.0.0" - } - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" - }, - "node_modules/utils-merge": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/uuid": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz", - "integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==", - "bin": { - "uuid": "dist/bin/uuid" - } - }, - "node_modules/uvm": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/uvm/-/uvm-2.1.1.tgz", - "integrity": "sha512-BZ5w8adTpNNr+zczOBRpaX/hH8UPKAf7fmCnidrcsqt3bn8KT9bDIfuS7hgRU9RXgiN01su2pwysBONY6w8W5w==", - "dev": true, - "dependencies": { - "flatted": "3.2.6" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/v8-compile-cache-lib": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", - "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", - "dev": true - }, - "node_modules/v8-to-istanbul": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.0.1.tgz", - "integrity": "sha512-74Y4LqY74kLE6IFyIjPtkSTWzUZmj8tdHT9Ii/26dvQ6K9Dl2NbEfj0XgU2sHCtKgt5VupqhlO/5aWuqS+IY1w==", - "dev": true, - "dependencies": { - "@jridgewell/trace-mapping": "^0.3.12", - "@types/istanbul-lib-coverage": "^2.0.1", - "convert-source-map": "^1.6.0" - }, - "engines": { - "node": ">=10.12.0" - } - }, - "node_modules/validator": { - "version": "13.15.26", - "resolved": "https://registry.npmjs.org/validator/-/validator-13.15.26.tgz", - "integrity": "sha512-spH26xU080ydGggxRyR1Yhcbgx+j3y5jbNXk/8L+iRvdIEQ4uTRH2Sgf2dokud6Q4oAtsbNvJ1Ft+9xmm6IZcA==", - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/vary": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/verror": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", - "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==", - "dev": true, - "engines": [ - "node >=0.6.0" - ], - "dependencies": { - "assert-plus": "^1.0.0", - "core-util-is": "1.0.2", - "extsprintf": "^1.2.0" - } - }, - "node_modules/verror/node_modules/core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==", - "dev": true - }, - "node_modules/walker": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", - "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", - "dev": true, - "dependencies": { - "makeerror": "1.0.12" - } - }, - "node_modules/webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", - "dev": true - }, - "node_modules/whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", - "dev": true, - "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "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==", - "dev": true, - "dependencies": { - "string-width": "^1.0.2 || 2 || 3 || 4" - } - }, - "node_modules/word-wrap": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", - "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/wordwrap": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", - "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", - "dev": true - }, - "node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" - }, - "node_modules/write-file-atomic": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.1.tgz", - "integrity": "sha512-nSKUxgAbyioruk6hU87QzVbY279oYT6uiwgDoujth2ju4mJ+TZau7SQBhtbTmUyuNYTuXnSyRn66FV0+eCgcrQ==", - "dev": true, - "dependencies": { - "imurmurhash": "^0.1.4", - "signal-exit": "^3.0.7" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16" - } - }, - "node_modules/ws": { - "version": "8.8.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.8.1.tgz", - "integrity": "sha512-bGy2JzvzkPowEJV++hF07hAD6niYSr0JzBNo/J29WsB57A2r7Wlc1UFcTR9IzrPvuNVO4B8LGqF8qcpsVOhJCA==", - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "node_modules/xmlbuilder": { - "version": "15.1.1", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-15.1.1.tgz", - "integrity": "sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==", - "dev": true, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/yaml": { - "version": "2.0.0-1", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.0.0-1.tgz", - "integrity": "sha512-W7h5dEhywMKenDJh2iX/LABkbFnBxasD27oyXWDS/feDsxiw0dD5ncXdYXgkvAsXIY2MpW/ZKkr9IU30DBdMNQ==", - "engines": { - "node": ">= 6" - } - }, - "node_modules/yargs": { - "version": "17.5.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.5.1.tgz", - "integrity": "sha512-t6YAJcxDkNX7NFYiVtKvWUz8l+PaKTLiL63mJYWR2GnHq2gjEWISzsLp9wg3aY36dY1j+gfIEL3pIF+XlJJfbA==", - "dev": true, - "dependencies": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "dev": true, - "engines": { - "node": ">=12" - } - }, - "node_modules/yn": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", - "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/z-schema": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/z-schema/-/z-schema-5.0.5.tgz", - "integrity": "sha512-D7eujBWkLa3p2sIpJA0d1pr7es+a7m0vFAnZLlCEKq/Ij2k0MLi9Br2UPxoxdYystm5K1yeBGzub0FlYUEWj2Q==", - "dependencies": { - "lodash.get": "^4.4.2", - "lodash.isequal": "^4.5.0", - "validator": "^13.7.0" - }, - "bin": { - "z-schema": "bin/z-schema" - }, - "engines": { - "node": ">=8.0.0" - }, - "optionalDependencies": { - "commander": "^9.4.1" - } - }, - "node_modules/z-schema/node_modules/commander": { - "version": "9.5.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz", - "integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==", - "optional": true, - "engines": { - "node": "^12.20.0 || >=14" - } - } - }, - "dependencies": { - "@ampproject/remapping": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", - "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", - "dev": true, - "requires": { - "@jridgewell/gen-mapping": "^0.1.0", - "@jridgewell/trace-mapping": "^0.3.9" - } - }, - "@apidevtools/json-schema-ref-parser": { - "version": "9.1.2", - "resolved": "https://registry.npmjs.org/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-9.1.2.tgz", - "integrity": "sha512-r1w81DpR+KyRWd3f+rk6TNqMgedmAxZP5v5KWlXQWlgMUUtyEJch0DKEci1SorPMiSeM8XPl7MZ3miJ60JIpQg==", - "requires": { - "@jsdevtools/ono": "^7.1.3", - "@types/json-schema": "^7.0.6", - "call-me-maybe": "^1.0.1", - "js-yaml": "^4.1.0" - } - }, - "@apidevtools/openapi-schemas": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@apidevtools/openapi-schemas/-/openapi-schemas-2.1.0.tgz", - "integrity": "sha512-Zc1AlqrJlX3SlpupFGpiLi2EbteyP7fXmUOGup6/DnkRgjP9bgMM/ag+n91rsv0U1Gpz0H3VILA/o3bW7Ua6BQ==" - }, - "@apidevtools/swagger-methods": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@apidevtools/swagger-methods/-/swagger-methods-3.0.2.tgz", - "integrity": "sha512-QAkD5kK2b1WfjDS/UQn/qQkbwF31uqRjPTrsCs5ZG9BQGAkjwvqGFjjPqAuzac/IYzpPtRzjCP1WrTuAIjMrXg==" - }, - "@apidevtools/swagger-parser": { - "version": "10.0.3", - "resolved": "https://registry.npmjs.org/@apidevtools/swagger-parser/-/swagger-parser-10.0.3.tgz", - "integrity": "sha512-sNiLY51vZOmSPFZA5TF35KZ2HbgYklQnTSDnkghamzLb3EkNtcQnrBQEj5AOCxHpTtXpqMCRM1CrmV2rG6nw4g==", - "requires": { - "@apidevtools/json-schema-ref-parser": "^9.0.6", - "@apidevtools/openapi-schemas": "^2.0.4", - "@apidevtools/swagger-methods": "^3.0.2", - "@jsdevtools/ono": "^7.1.3", - "call-me-maybe": "^1.0.1", - "z-schema": "^5.0.1" - } - }, - "@babel/code-frame": { - "version": "7.22.13", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", - "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", - "dev": true, - "requires": { - "@babel/highlight": "^7.22.13", - "chalk": "^2.4.2" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "@babel/compat-data": { - "version": "7.17.10", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.17.10.tgz", - "integrity": "sha512-GZt/TCsG70Ms19gfZO1tM4CVnXsPgEPBCpJu+Qz3L0LUDsY5nZqFZglIoPC1kIYOtNBZlrnFT+klg12vFGZXrw==", - "dev": true - }, - "@babel/core": { - "version": "7.18.2", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.18.2.tgz", - "integrity": "sha512-A8pri1YJiC5UnkdrWcmfZTJTV85b4UXTAfImGmCfYmax4TR9Cw8sDS0MOk++Gp2mE/BefVJ5nwy5yzqNJbP/DQ==", - "dev": true, - "requires": { - "@ampproject/remapping": "^2.1.0", - "@babel/code-frame": "^7.16.7", - "@babel/generator": "^7.18.2", - "@babel/helper-compilation-targets": "^7.18.2", - "@babel/helper-module-transforms": "^7.18.0", - "@babel/helpers": "^7.18.2", - "@babel/parser": "^7.18.0", - "@babel/template": "^7.16.7", - "@babel/traverse": "^7.18.2", - "@babel/types": "^7.18.2", - "convert-source-map": "^1.7.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.1", - "semver": "^6.3.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } - } - }, - "@babel/generator": { - "version": "7.18.2", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.18.2.tgz", - "integrity": "sha512-W1lG5vUwFvfMd8HVXqdfbuG7RuaSrTCCD8cl8fP8wOivdbtbIg2Db3IWUcgvfxKbbn6ZBGYRW/Zk1MIwK49mgw==", - "dev": true, - "requires": { - "@babel/types": "^7.18.2", - "@jridgewell/gen-mapping": "^0.3.0", - "jsesc": "^2.5.1" - }, - "dependencies": { - "@jridgewell/gen-mapping": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.1.tgz", - "integrity": "sha512-GcHwniMlA2z+WFPWuY8lp3fsza0I8xPFMWL5+n8LYyP6PSvPrXf4+n8stDHZY2DM0zy9sVkRDy1jDI4XGzYVqg==", - "dev": true, - "requires": { - "@jridgewell/set-array": "^1.0.0", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" - } - } - } - }, - "@babel/helper-compilation-targets": { - "version": "7.18.2", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.18.2.tgz", - "integrity": "sha512-s1jnPotJS9uQnzFtiZVBUxe67CuBa679oWFHpxYYnTpRL/1ffhyX44R9uYiXoa/pLXcY9H2moJta0iaanlk/rQ==", - "dev": true, - "requires": { - "@babel/compat-data": "^7.17.10", - "@babel/helper-validator-option": "^7.16.7", - "browserslist": "^4.20.2", - "semver": "^6.3.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } - } - }, - "@babel/helper-environment-visitor": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", - "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", - "dev": true - }, - "@babel/helper-function-name": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", - "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", - "dev": true, - "requires": { - "@babel/template": "^7.22.15", - "@babel/types": "^7.23.0" - }, - "dependencies": { - "@babel/types": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz", - "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==", - "dev": true, - "requires": { - "@babel/helper-string-parser": "^7.22.5", - "@babel/helper-validator-identifier": "^7.22.20", - "to-fast-properties": "^2.0.0" - } - } - } - }, - "@babel/helper-hoist-variables": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", - "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", - "dev": true, - "requires": { - "@babel/types": "^7.22.5" - }, - "dependencies": { - "@babel/types": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz", - "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==", - "dev": true, - "requires": { - "@babel/helper-string-parser": "^7.22.5", - "@babel/helper-validator-identifier": "^7.22.20", - "to-fast-properties": "^2.0.0" - } - } - } - }, - "@babel/helper-module-imports": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz", - "integrity": "sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg==", - "dev": true, - "requires": { - "@babel/types": "^7.16.7" - } - }, - "@babel/helper-module-transforms": { - "version": "7.18.0", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.18.0.tgz", - "integrity": "sha512-kclUYSUBIjlvnzN2++K9f2qzYKFgjmnmjwL4zlmU5f8ZtzgWe8s0rUPSTGy2HmK4P8T52MQsS+HTQAgZd3dMEA==", - "dev": true, - "requires": { - "@babel/helper-environment-visitor": "^7.16.7", - "@babel/helper-module-imports": "^7.16.7", - "@babel/helper-simple-access": "^7.17.7", - "@babel/helper-split-export-declaration": "^7.16.7", - "@babel/helper-validator-identifier": "^7.16.7", - "@babel/template": "^7.16.7", - "@babel/traverse": "^7.18.0", - "@babel/types": "^7.18.0" - } - }, - "@babel/helper-plugin-utils": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.19.0.tgz", - "integrity": "sha512-40Ryx7I8mT+0gaNxm8JGTZFUITNqdLAgdg0hXzeVZxVD6nFsdhQvip6v8dqkRHzsz1VFpFAaOCHNn0vKBL7Czw==", - "dev": true - }, - "@babel/helper-simple-access": { - "version": "7.18.2", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.18.2.tgz", - "integrity": "sha512-7LIrjYzndorDY88MycupkpQLKS1AFfsVRm2k/9PtKScSy5tZq0McZTj+DiMRynboZfIqOKvo03pmhTaUgiD6fQ==", - "dev": true, - "requires": { - "@babel/types": "^7.18.2" - } - }, - "@babel/helper-split-export-declaration": { - "version": "7.22.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", - "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", - "dev": true, - "requires": { - "@babel/types": "^7.22.5" - }, - "dependencies": { - "@babel/types": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz", - "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==", - "dev": true, - "requires": { - "@babel/helper-string-parser": "^7.22.5", - "@babel/helper-validator-identifier": "^7.22.20", - "to-fast-properties": "^2.0.0" - } - } - } - }, - "@babel/helper-string-parser": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz", - "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==", - "dev": true - }, - "@babel/helper-validator-identifier": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", - "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", - "dev": true - }, - "@babel/helper-validator-option": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.16.7.tgz", - "integrity": "sha512-TRtenOuRUVo9oIQGPC5G9DgK4743cdxvtOw0weQNpZXaS16SCBi5MNjZF8vba3ETURjZpTbVn7Vvcf2eAwFozQ==", - "dev": true - }, - "@babel/helpers": { - "version": "7.18.2", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.18.2.tgz", - "integrity": "sha512-j+d+u5xT5utcQSzrh9p+PaJX94h++KN+ng9b9WEJq7pkUPAd61FGqhjuUEdfknb3E/uDBb7ruwEeKkIxNJPIrg==", - "dev": true, - "requires": { - "@babel/template": "^7.16.7", - "@babel/traverse": "^7.18.2", - "@babel/types": "^7.18.2" - } - }, - "@babel/highlight": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz", - "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.22.20", - "chalk": "^2.4.2", - "js-tokens": "^4.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "@babel/parser": { - "version": "7.18.4", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.18.4.tgz", - "integrity": "sha512-FDge0dFazETFcxGw/EXzOkN8uJp0PC7Qbm+Pe9T+av2zlBpOgunFHkQPPn+eRuClU73JF+98D531UgayY89tow==", - "dev": true - }, - "@babel/plugin-syntax-async-generators": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", - "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-bigint": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", - "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-class-properties": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", - "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.12.13" - } - }, - "@babel/plugin-syntax-import-meta": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", - "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-syntax-json-strings": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", - "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-jsx": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.18.6.tgz", - "integrity": "sha512-6mmljtAedFGTWu2p/8WIORGwy+61PLgOMPOdazc7YoJ9ZCWUyFy3A6CpPkRKLKD1ToAesxX8KGEViAiLo9N+7Q==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.18.6" - } - }, - "@babel/plugin-syntax-logical-assignment-operators": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", - "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-syntax-nullish-coalescing-operator": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", - "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-numeric-separator": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", - "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-syntax-object-rest-spread": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", - "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-optional-catch-binding": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", - "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-optional-chaining": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", - "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-top-level-await": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", - "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.14.5" - } - }, - "@babel/plugin-syntax-typescript": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.18.6.tgz", - "integrity": "sha512-mAWAuq4rvOepWCBid55JuRNvpTNf2UGVgoz4JV0fXEKolsVZDzsa4NqCef758WZJj/GDu0gVGItjKFiClTAmZA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.18.6" - } - }, - "@babel/template": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", - "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.22.13", - "@babel/parser": "^7.22.15", - "@babel/types": "^7.22.15" - }, - "dependencies": { - "@babel/parser": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz", - "integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==", - "dev": true - }, - "@babel/types": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz", - "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==", - "dev": true, - "requires": { - "@babel/helper-string-parser": "^7.22.5", - "@babel/helper-validator-identifier": "^7.22.20", - "to-fast-properties": "^2.0.0" - } - } - } - }, - "@babel/traverse": { - "version": "7.23.2", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz", - "integrity": "sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.22.13", - "@babel/generator": "^7.23.0", - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-function-name": "^7.23.0", - "@babel/helper-hoist-variables": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/parser": "^7.23.0", - "@babel/types": "^7.23.0", - "debug": "^4.1.0", - "globals": "^11.1.0" - }, - "dependencies": { - "@babel/generator": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz", - "integrity": "sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==", - "dev": true, - "requires": { - "@babel/types": "^7.23.0", - "@jridgewell/gen-mapping": "^0.3.2", - "@jridgewell/trace-mapping": "^0.3.17", - "jsesc": "^2.5.1" - } - }, - "@babel/parser": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz", - "integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==", - "dev": true - }, - "@babel/types": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz", - "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==", - "dev": true, - "requires": { - "@babel/helper-string-parser": "^7.22.5", - "@babel/helper-validator-identifier": "^7.22.20", - "to-fast-properties": "^2.0.0" - } - }, - "@jridgewell/gen-mapping": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", - "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", - "dev": true, - "requires": { - "@jridgewell/set-array": "^1.0.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" - } - }, - "globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true - } - } - }, - "@babel/types": { - "version": "7.18.4", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.18.4.tgz", - "integrity": "sha512-ThN1mBcMq5pG/Vm2IcBmPPfyPXbd8S02rS+OBIDENdufvqC7Z/jHPCv9IcP01277aKtDI8g/2XysBN4hA8niiw==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.16.7", - "to-fast-properties": "^2.0.0" - } - }, - "@bcoe/v8-coverage": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", - "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", - "dev": true - }, - "@colors/colors": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", - "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", - "dev": true, - "optional": true - }, - "@cspotcode/source-map-support": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", - "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", - "dev": true, - "requires": { - "@jridgewell/trace-mapping": "0.3.9" - }, - "dependencies": { - "@jridgewell/trace-mapping": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", - "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", - "dev": true, - "requires": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" - } - } - } - }, - "@eslint/eslintrc": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.1.tgz", - "integrity": "sha512-OhSY22oQQdw3zgPOOwdoj01l/Dzl1Z+xyUP33tkSN+aqyEhymJCcPHyXt+ylW8FSe0TfRC2VG+ROQOapD0aZSQ==", - "dev": true, - "requires": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.4.0", - "globals": "^13.15.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - } - }, - "@faker-js/faker": { - "version": "5.5.3", - "resolved": "https://registry.npmjs.org/@faker-js/faker/-/faker-5.5.3.tgz", - "integrity": "sha512-R11tGE6yIFwqpaIqcfkcg7AICXzFg14+5h5v0TfF/9+RMDL6jhzCy/pxHVOfbALGdtVYdt6JdR21tuxEgl34dw==", - "dev": true - }, - "@humanwhocodes/config-array": { - "version": "0.10.4", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.10.4.tgz", - "integrity": "sha512-mXAIHxZT3Vcpg83opl1wGlVZ9xydbfZO3r5YfRSH6Gpp2J/PfdBP0wbDa2sO6/qRbcalpoevVyW6A/fI6LfeMw==", - "dev": true, - "requires": { - "@humanwhocodes/object-schema": "^1.2.1", - "debug": "^4.1.1", - "minimatch": "^3.0.4" - } - }, - "@humanwhocodes/gitignore-to-minimatch": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@humanwhocodes/gitignore-to-minimatch/-/gitignore-to-minimatch-1.0.2.tgz", - "integrity": "sha512-rSqmMJDdLFUsyxR6FMtD00nfQKKLFb1kv+qBbOVKqErvloEIJLo5bDTJTQNTYgeyp78JsA7u/NPi5jT1GR/MuA==", - "dev": true - }, - "@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "dev": true - }, - "@humanwhocodes/object-schema": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", - "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", - "dev": true - }, - "@istanbuljs/load-nyc-config": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", - "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", - "dev": true, - "requires": { - "camelcase": "^5.3.1", - "find-up": "^4.1.0", - "get-package-type": "^0.1.0", - "js-yaml": "^3.13.1", - "resolve-from": "^5.0.0" - }, - "dependencies": { - "argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "requires": { - "sprintf-js": "~1.0.2" - } - }, - "js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "dev": true, - "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - } - }, - "resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true - } - } - }, - "@istanbuljs/schema": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", - "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", - "dev": true - }, - "@jest-mock/express": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@jest-mock/express/-/express-2.0.1.tgz", - "integrity": "sha512-DvW4WMGoNBEOGx1XRCe8yZyQ7ju5dWmBN57H0zPio7AqQo27QawI+o30f9xVdLnS0bAF2wbmQQfS61LxL/t8bQ==", - "dev": true, - "requires": { - "@types/express": "^4.17.13" - } - }, - "@jest/console": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.0.2.tgz", - "integrity": "sha512-Fv02ijyhF4D/Wb3DvZO3iBJQz5DnzpJEIDBDbvje8Em099N889tNMUnBw7SalmSuOI+NflNG40RA1iK71kImPw==", - "dev": true, - "requires": { - "@jest/types": "^29.0.2", - "@types/node": "*", - "chalk": "^4.0.0", - "jest-message-util": "^29.0.2", - "jest-util": "^29.0.2", - "slash": "^3.0.0" - } - }, - "@jest/core": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.0.2.tgz", - "integrity": "sha512-imP5M6cdpHEOkmcuFYZuM5cTG1DAF7ZlVNCq1+F7kbqme2Jcl+Kh4M78hihM76DJHNkurbv4UVOnejGxBKEmww==", - "dev": true, - "requires": { - "@jest/console": "^29.0.2", - "@jest/reporters": "^29.0.2", - "@jest/test-result": "^29.0.2", - "@jest/transform": "^29.0.2", - "@jest/types": "^29.0.2", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.9", - "jest-changed-files": "^29.0.0", - "jest-config": "^29.0.2", - "jest-haste-map": "^29.0.2", - "jest-message-util": "^29.0.2", - "jest-regex-util": "^29.0.0", - "jest-resolve": "^29.0.2", - "jest-resolve-dependencies": "^29.0.2", - "jest-runner": "^29.0.2", - "jest-runtime": "^29.0.2", - "jest-snapshot": "^29.0.2", - "jest-util": "^29.0.2", - "jest-validate": "^29.0.2", - "jest-watcher": "^29.0.2", - "micromatch": "^4.0.4", - "pretty-format": "^29.0.2", - "slash": "^3.0.0", - "strip-ansi": "^6.0.0" - }, - "dependencies": { - "@jest/transform": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.0.2.tgz", - "integrity": "sha512-lajVQx2AnsR+Pa17q2zR7eikz2PkPs1+g/qPbZkqQATeS/s6eT55H+yHcsLfuI/0YQ/4VSBepSu3bOX+44q0aA==", - "dev": true, - "requires": { - "@babel/core": "^7.11.6", - "@jest/types": "^29.0.2", - "@jridgewell/trace-mapping": "^0.3.15", - "babel-plugin-istanbul": "^6.1.1", - "chalk": "^4.0.0", - "convert-source-map": "^1.4.0", - "fast-json-stable-stringify": "^2.1.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.0.2", - "jest-regex-util": "^29.0.0", - "jest-util": "^29.0.2", - "micromatch": "^4.0.4", - "pirates": "^4.0.4", - "slash": "^3.0.0", - "write-file-atomic": "^4.0.1" - } - }, - "jest-haste-map": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.0.2.tgz", - "integrity": "sha512-SOorh2ysQ0fe8gsF4gaUDhoMIWAvi2hXOkwThEO48qT3JqA8GLAUieQcIvdSEd6M0scRDe1PVmKc5tXR3Z0U0A==", - "dev": true, - "requires": { - "@jest/types": "^29.0.2", - "@types/graceful-fs": "^4.1.3", - "@types/node": "*", - "anymatch": "^3.0.3", - "fb-watchman": "^2.0.0", - "fsevents": "^2.3.2", - "graceful-fs": "^4.2.9", - "jest-regex-util": "^29.0.0", - "jest-util": "^29.0.2", - "jest-worker": "^29.0.2", - "micromatch": "^4.0.4", - "walker": "^1.0.8" - } - }, - "jest-regex-util": { - "version": "29.0.0", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.0.0.tgz", - "integrity": "sha512-BV7VW7Sy0fInHWN93MMPtlClweYv2qrSCwfeFWmpribGZtQPWNvRSq9XOVgOEjU1iBGRKXUZil0o2AH7Iy9Lug==", - "dev": true - }, - "jest-worker": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.0.2.tgz", - "integrity": "sha512-EyvBlYcvd2pg28yg5A3OODQnqK9LI1kitnGUZUG5/NYIeaRgewtYBKB5wlr7oXj8zPCkzev7EmnTCsrXK7V+Xw==", - "dev": true, - "requires": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - } - }, - "supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "@jest/environment": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.0.2.tgz", - "integrity": "sha512-Yf+EYaLOrVCgts/aTS5nGznU4prZUPa5k9S63Yct8YSOKj2jkdS17hHSUKhk5jxDFMyCy1PXknypDw7vfgc/mA==", - "dev": true, - "requires": { - "@jest/fake-timers": "^29.0.2", - "@jest/types": "^29.0.2", - "@types/node": "*", - "jest-mock": "^29.0.2" - } - }, - "@jest/expect": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.0.2.tgz", - "integrity": "sha512-y/3geZ92p2/zovBm/F+ZjXUJ3thvT9IRzD6igqaWskFE2aR0idD+N/p5Lj/ZautEox/9RwEc6nqergebeh72uQ==", - "dev": true, - "requires": { - "expect": "^29.0.2", - "jest-snapshot": "^29.0.2" - } - }, - "@jest/expect-utils": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.0.2.tgz", - "integrity": "sha512-+wcQF9khXKvAEi8VwROnCWWmHfsJYCZAs5dmuMlJBKk57S6ZN2/FQMIlo01F29fJyT8kV/xblE7g3vkIdTLOjw==", - "dev": true, - "requires": { - "jest-get-type": "^29.0.0" - } - }, - "@jest/fake-timers": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.0.2.tgz", - "integrity": "sha512-2JhQeWU28fvmM5r33lxg6BxxkTKaVXs6KMaJ6eXSM8ml/MaWkt2BvbIO8G9KWAJFMdBXWbn+2h9OK1/s5urKZA==", - "dev": true, - "requires": { - "@jest/types": "^29.0.2", - "@sinonjs/fake-timers": "^9.1.2", - "@types/node": "*", - "jest-message-util": "^29.0.2", - "jest-mock": "^29.0.2", - "jest-util": "^29.0.2" - } - }, - "@jest/globals": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.0.2.tgz", - "integrity": "sha512-4hcooSNJCVXuTu07/VJwCWW6HTnjLtQdqlcGisK6JST7z2ixa8emw4SkYsOk7j36WRc2ZUEydlUePnOIOTCNXg==", - "dev": true, - "requires": { - "@jest/environment": "^29.0.2", - "@jest/expect": "^29.0.2", - "@jest/types": "^29.0.2", - "jest-mock": "^29.0.2" - } - }, - "@jest/reporters": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.0.2.tgz", - "integrity": "sha512-Kr41qejRQHHkCgWHC9YwSe7D5xivqP4XML+PvgwsnRFaykKdNflDUb4+xLXySOU+O/bPkVdFpGzUpVNSJChCrw==", - "dev": true, - "requires": { - "@bcoe/v8-coverage": "^0.2.3", - "@jest/console": "^29.0.2", - "@jest/test-result": "^29.0.2", - "@jest/transform": "^29.0.2", - "@jest/types": "^29.0.2", - "@jridgewell/trace-mapping": "^0.3.15", - "@types/node": "*", - "chalk": "^4.0.0", - "collect-v8-coverage": "^1.0.0", - "exit": "^0.1.2", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "istanbul-lib-coverage": "^3.0.0", - "istanbul-lib-instrument": "^5.1.0", - "istanbul-lib-report": "^3.0.0", - "istanbul-lib-source-maps": "^4.0.0", - "istanbul-reports": "^3.1.3", - "jest-message-util": "^29.0.2", - "jest-util": "^29.0.2", - "jest-worker": "^29.0.2", - "slash": "^3.0.0", - "string-length": "^4.0.1", - "strip-ansi": "^6.0.0", - "terminal-link": "^2.0.0", - "v8-to-istanbul": "^9.0.1" - }, - "dependencies": { - "@jest/transform": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.0.2.tgz", - "integrity": "sha512-lajVQx2AnsR+Pa17q2zR7eikz2PkPs1+g/qPbZkqQATeS/s6eT55H+yHcsLfuI/0YQ/4VSBepSu3bOX+44q0aA==", - "dev": true, - "requires": { - "@babel/core": "^7.11.6", - "@jest/types": "^29.0.2", - "@jridgewell/trace-mapping": "^0.3.15", - "babel-plugin-istanbul": "^6.1.1", - "chalk": "^4.0.0", - "convert-source-map": "^1.4.0", - "fast-json-stable-stringify": "^2.1.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.0.2", - "jest-regex-util": "^29.0.0", - "jest-util": "^29.0.2", - "micromatch": "^4.0.4", - "pirates": "^4.0.4", - "slash": "^3.0.0", - "write-file-atomic": "^4.0.1" - } - }, - "jest-haste-map": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.0.2.tgz", - "integrity": "sha512-SOorh2ysQ0fe8gsF4gaUDhoMIWAvi2hXOkwThEO48qT3JqA8GLAUieQcIvdSEd6M0scRDe1PVmKc5tXR3Z0U0A==", - "dev": true, - "requires": { - "@jest/types": "^29.0.2", - "@types/graceful-fs": "^4.1.3", - "@types/node": "*", - "anymatch": "^3.0.3", - "fb-watchman": "^2.0.0", - "fsevents": "^2.3.2", - "graceful-fs": "^4.2.9", - "jest-regex-util": "^29.0.0", - "jest-util": "^29.0.2", - "jest-worker": "^29.0.2", - "micromatch": "^4.0.4", - "walker": "^1.0.8" - } - }, - "jest-regex-util": { - "version": "29.0.0", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.0.0.tgz", - "integrity": "sha512-BV7VW7Sy0fInHWN93MMPtlClweYv2qrSCwfeFWmpribGZtQPWNvRSq9XOVgOEjU1iBGRKXUZil0o2AH7Iy9Lug==", - "dev": true - }, - "jest-worker": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.0.2.tgz", - "integrity": "sha512-EyvBlYcvd2pg28yg5A3OODQnqK9LI1kitnGUZUG5/NYIeaRgewtYBKB5wlr7oXj8zPCkzev7EmnTCsrXK7V+Xw==", - "dev": true, - "requires": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - } - }, - "supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "@jest/schemas": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-28.1.3.tgz", - "integrity": "sha512-/l/VWsdt/aBXgjshLWOFyFt3IVdYypu5y2Wn2rOO1un6nkqIn8SLXzgIMYXFyYsRWDyF5EthmKJMIdJvk08grg==", - "dev": true, - "requires": { - "@sinclair/typebox": "^0.24.1" - } - }, - "@jest/source-map": { - "version": "29.0.0", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.0.0.tgz", - "integrity": "sha512-nOr+0EM8GiHf34mq2GcJyz/gYFyLQ2INDhAylrZJ9mMWoW21mLBfZa0BUVPPMxVYrLjeiRe2Z7kWXOGnS0TFhQ==", - "dev": true, - "requires": { - "@jridgewell/trace-mapping": "^0.3.15", - "callsites": "^3.0.0", - "graceful-fs": "^4.2.9" - } - }, - "@jest/test-result": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.0.2.tgz", - "integrity": "sha512-b5rDc0lLL6Kx73LyCx6370k9uZ8o5UKdCpMS6Za3ke7H9y8PtAU305y6TeghpBmf2In8p/qqi3GpftgzijSsNw==", - "dev": true, - "requires": { - "@jest/console": "^29.0.2", - "@jest/types": "^29.0.2", - "@types/istanbul-lib-coverage": "^2.0.0", - "collect-v8-coverage": "^1.0.0" - } - }, - "@jest/test-sequencer": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.0.2.tgz", - "integrity": "sha512-fsyZqHBlXNMv5ZqjQwCuYa2pskXCO0DVxh5aaVCuAtwzHuYEGrhordyEncBLQNuCGQSYgElrEEmS+7wwFnnMKw==", - "dev": true, - "requires": { - "@jest/test-result": "^29.0.2", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.0.2", - "slash": "^3.0.0" - }, - "dependencies": { - "jest-haste-map": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.0.2.tgz", - "integrity": "sha512-SOorh2ysQ0fe8gsF4gaUDhoMIWAvi2hXOkwThEO48qT3JqA8GLAUieQcIvdSEd6M0scRDe1PVmKc5tXR3Z0U0A==", - "dev": true, - "requires": { - "@jest/types": "^29.0.2", - "@types/graceful-fs": "^4.1.3", - "@types/node": "*", - "anymatch": "^3.0.3", - "fb-watchman": "^2.0.0", - "fsevents": "^2.3.2", - "graceful-fs": "^4.2.9", - "jest-regex-util": "^29.0.0", - "jest-util": "^29.0.2", - "jest-worker": "^29.0.2", - "micromatch": "^4.0.4", - "walker": "^1.0.8" - } - }, - "jest-regex-util": { - "version": "29.0.0", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.0.0.tgz", - "integrity": "sha512-BV7VW7Sy0fInHWN93MMPtlClweYv2qrSCwfeFWmpribGZtQPWNvRSq9XOVgOEjU1iBGRKXUZil0o2AH7Iy9Lug==", - "dev": true - }, - "jest-worker": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.0.2.tgz", - "integrity": "sha512-EyvBlYcvd2pg28yg5A3OODQnqK9LI1kitnGUZUG5/NYIeaRgewtYBKB5wlr7oXj8zPCkzev7EmnTCsrXK7V+Xw==", - "dev": true, - "requires": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - } - }, - "supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "@jest/types": { - "version": "29.6.1", - "resolved": "https://registry.npmmirror.com/@jest/types/-/types-29.6.1.tgz", - "integrity": "sha512-tPKQNMPuXgvdOn2/Lg9HNfUvjYVGolt04Hp03f5hAk878uwOLikN+JzeLY0HcVgKgFl9Hs3EIqpu3WX27XNhnw==", - "dev": true, - "requires": { - "@jest/schemas": "^29.6.0", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "dependencies": { - "@jest/schemas": { - "version": "29.6.0", - "resolved": "https://registry.npmmirror.com/@jest/schemas/-/schemas-29.6.0.tgz", - "integrity": "sha512-rxLjXyJBTL4LQeJW3aKo0M/+GkCOXsO+8i9Iu7eDb6KwtP65ayoDsitrdPBtujxQ88k4wI2FNYfa6TOGwSn6cQ==", - "dev": true, - "requires": { - "@sinclair/typebox": "^0.27.8" - } - }, - "@sinclair/typebox": { - "version": "0.27.8", - "resolved": "https://registry.npmmirror.com/@sinclair/typebox/-/typebox-0.27.8.tgz", - "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", - "dev": true - } - } - }, - "@jridgewell/gen-mapping": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", - "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==", - "dev": true, - "requires": { - "@jridgewell/set-array": "^1.0.0", - "@jridgewell/sourcemap-codec": "^1.4.10" - } - }, - "@jridgewell/resolve-uri": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", - "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", - "dev": true - }, - "@jridgewell/set-array": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.1.tgz", - "integrity": "sha512-Ct5MqZkLGEXTVmQYbGtx9SVqD2fqwvdubdps5D3djjAkgkKwT918VNOz65pEHFaYTeWcukmJmH5SwsA9Tn2ObQ==", - "dev": true - }, - "@jridgewell/sourcemap-codec": { - "version": "1.4.15", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", - "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", - "dev": true - }, - "@jridgewell/trace-mapping": { - "version": "0.3.20", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz", - "integrity": "sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==", - "dev": true, - "requires": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, - "@jsdevtools/ono": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/@jsdevtools/ono/-/ono-7.1.3.tgz", - "integrity": "sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==" - }, - "@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "requires": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - } - }, - "@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true - }, - "@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "requires": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - } - }, - "@postman/form-data": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@postman/form-data/-/form-data-3.1.1.tgz", - "integrity": "sha512-vjh8Q2a8S6UCm/KKs31XFJqEEgmbjBmpPNVV2eVav6905wyFAwaUOBGA1NPBI4ERH9MMZc6w0umFgM6WbEPMdg==", - "dev": true, - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - } - }, - "@postman/tough-cookie": { - "version": "4.1.3-postman.1", - "resolved": "https://registry.npmjs.org/@postman/tough-cookie/-/tough-cookie-4.1.3-postman.1.tgz", - "integrity": "sha512-txpgUqZOnWYnUHZpHjkfb0IwVH4qJmyq77pPnJLlfhMtdCLMFTEeQHlzQiK906aaNCe4NEB5fGJHo9uzGbFMeA==", - "dev": true, - "requires": { - "psl": "^1.1.33", - "punycode": "^2.1.1", - "universalify": "^0.2.0", - "url-parse": "^1.5.3" - }, - "dependencies": { - "universalify": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", - "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", - "dev": true - } - } - }, - "@postman/tunnel-agent": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/@postman/tunnel-agent/-/tunnel-agent-0.6.3.tgz", - "integrity": "sha512-k57fzmAZ2PJGxfOA4SGR05ejorHbVAa/84Hxh/2nAztjNXc4ZjOm9NUIk6/Z6LCrBvJZqjRZbN8e/nROVUPVdg==", - "dev": true, - "requires": { - "safe-buffer": "^5.0.1" - } - }, - "@scarf/scarf": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@scarf/scarf/-/scarf-1.4.0.tgz", - "integrity": "sha512-xxeapPiUXdZAE3che6f3xogoJPeZgig6omHEy1rIY5WVsB3H2BHNnZH+gHG6x91SCWyQCzWGsuL2Hh3ClO5/qQ==" - }, - "@sinclair/typebox": { - "version": "0.24.35", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.35.tgz", - "integrity": "sha512-iN6ehuDndiTiDz2F+Orv/+oHJR+PrGv+38oghCddpsW4YEZl5qyLsWxSwYUWrKEOfjpGtXDFW6scJtjpzSLeSw==", - "dev": true - }, - "@sinonjs/commons": { - "version": "1.8.3", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz", - "integrity": "sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ==", - "dev": true, - "requires": { - "type-detect": "4.0.8" - } - }, - "@sinonjs/fake-timers": { - "version": "9.1.2", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-9.1.2.tgz", - "integrity": "sha512-BPS4ynJW/o92PUR4wgriz2Ud5gpST5vz6GQfMixEDK0Z8ZCUv2M7SkBLykH56T++Xs+8ln9zTGbOvNGIe02/jw==", - "dev": true, - "requires": { - "@sinonjs/commons": "^1.7.0" - } - }, - "@tsconfig/node10": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", - "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", - "dev": true - }, - "@tsconfig/node12": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", - "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", - "dev": true - }, - "@tsconfig/node14": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", - "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", - "dev": true - }, - "@tsconfig/node16": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz", - "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==", - "dev": true - }, - "@types/babel__core": { - "version": "7.1.19", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.19.tgz", - "integrity": "sha512-WEOTgRsbYkvA/KCsDwVEGkd7WAr1e3g31VHQ8zy5gul/V1qKullU/BU5I68X5v7V3GnB9eotmom4v5a5gjxorw==", - "dev": true, - "requires": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0", - "@types/babel__generator": "*", - "@types/babel__template": "*", - "@types/babel__traverse": "*" - } - }, - "@types/babel__generator": { - "version": "7.6.4", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.4.tgz", - "integrity": "sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==", - "dev": true, - "requires": { - "@babel/types": "^7.0.0" - } - }, - "@types/babel__template": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz", - "integrity": "sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==", - "dev": true, - "requires": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0" - } - }, - "@types/babel__traverse": { - "version": "7.17.1", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.17.1.tgz", - "integrity": "sha512-kVzjari1s2YVi77D3w1yuvohV2idweYXMCDzqBiVNN63TcDWrIlTVOYpqVrvbbyOE/IyzBoTKF0fdnLPEORFxA==", - "dev": true, - "requires": { - "@babel/types": "^7.3.0" - } - }, - "@types/body-parser": { - "version": "1.19.1", - "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.1.tgz", - "integrity": "sha512-a6bTJ21vFOGIkwM0kzh9Yr89ziVxq4vYH2fQ6N8AeipEzai/cFK6aGMArIkUeIdRIgpwQa+2bXiLuUJCpSf2Cg==", - "requires": { - "@types/connect": "*", - "@types/node": "*" - } - }, - "@types/connect": { - "version": "3.4.35", - "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", - "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==", - "requires": { - "@types/node": "*" - } - }, - "@types/express": { - "version": "4.17.13", - "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.13.tgz", - "integrity": "sha512-6bSZTPaTIACxn48l50SR+axgrqm6qXFIxrdAKaG6PaJk3+zuUr35hBlgT7vOmJcum+OEaIBLtHV/qloEAFITeA==", - "requires": { - "@types/body-parser": "*", - "@types/express-serve-static-core": "^4.17.18", - "@types/qs": "*", - "@types/serve-static": "*" - } - }, - "@types/express-serve-static-core": { - "version": "4.17.24", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.24.tgz", - "integrity": "sha512-3UJuW+Qxhzwjq3xhwXm2onQcFHn76frIYVbTu+kn24LFxI+dEhdfISDFovPB8VpEgW8oQCTpRuCe+0zJxB7NEA==", - "requires": { - "@types/node": "*", - "@types/qs": "*", - "@types/range-parser": "*" - } - }, - "@types/graceful-fs": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz", - "integrity": "sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, - "@types/istanbul-lib-coverage": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz", - "integrity": "sha512-sz7iLqvVUg1gIedBOvlkxPlc8/uVzyS5OwGz1cKjXzkl3FpL3al0crU8YGU1WoHkxn0Wxbw5tyi6hvzJKNzFsw==", - "dev": true - }, - "@types/istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "*" - } - }, - "@types/istanbul-reports": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", - "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", - "dev": true, - "requires": { - "@types/istanbul-lib-report": "*" - } - }, - "@types/jest": { - "version": "29.5.3", - "resolved": "https://registry.npmmirror.com/@types/jest/-/jest-29.5.3.tgz", - "integrity": "sha512-1Nq7YrO/vJE/FYnqYyw0FS8LdrjExSgIiHyKg7xPpn+yi8Q4huZryKnkJatN1ZRH89Kw2v33/8ZMB7DuZeSLlA==", - "dev": true, - "requires": { - "expect": "^29.0.0", - "pretty-format": "^29.0.0" - } - }, - "@types/json-schema": { - "version": "7.0.11", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", - "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==" - }, - "@types/mime": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", - "integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==" - }, - "@types/morgan": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/@types/morgan/-/morgan-1.9.3.tgz", - "integrity": "sha512-BiLcfVqGBZCyNCnCH3F4o2GmDLrpy0HeBVnNlyZG4fo88ZiE9SoiBe3C+2ezuwbjlEyT+PDZ17//TAlRxAn75Q==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, - "@types/node": { - "version": "18.7.15", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.7.15.tgz", - "integrity": "sha512-XnjpaI8Bgc3eBag2Aw4t2Uj/49lLBSStHWfqKvIuXD7FIrZyMLWp8KuAFHAqxMZYTF9l08N1ctUn9YNybZJVmQ==" - }, - "@types/prettier": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.0.tgz", - "integrity": "sha512-RI1L7N4JnW5gQw2spvL7Sllfuf1SaHdrZpCHiBlCXjIlufi1SMNnbu2teze3/QE67Fg2tBlH7W+mi4hVNk4p0A==", - "dev": true - }, - "@types/qs": { - "version": "6.9.7", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", - "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==" - }, - "@types/range-parser": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz", - "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==" - }, - "@types/serve-static": { - "version": "1.13.10", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.10.tgz", - "integrity": "sha512-nCkHGI4w7ZgAdNkrEu0bv+4xNV/XDqW+DydknebMOQwkpDGx8G+HTlj7R7ABI8i8nKxVw0wtKPi1D+lPOkh4YQ==", - "requires": { - "@types/mime": "^1", - "@types/node": "*" - } - }, - "@types/stack-utils": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", - "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", - "dev": true - }, - "@types/swagger-jsdoc": { - "version": "6.0.4", - "resolved": "https://registry.npmjs.org/@types/swagger-jsdoc/-/swagger-jsdoc-6.0.4.tgz", - "integrity": "sha512-W+Xw5epcOZrF/AooUM/PccNMSAFOKWZA5dasNyMujTwsBkU74njSJBpvCCJhHAJ95XRMzQrrW844Btu0uoetwQ==", - "dev": true - }, - "@types/swagger-ui-express": { - "version": "4.1.8", - "resolved": "https://registry.npmjs.org/@types/swagger-ui-express/-/swagger-ui-express-4.1.8.tgz", - "integrity": "sha512-AhZV8/EIreHFmBV5wAs0gzJUNq9JbbSXgJLQubCC0jtIo6prnI9MIRRxnU4MZX9RB9yXxF1V4R7jtLl/Wcj31g==", - "dev": true, - "requires": { - "@types/express": "*", - "@types/serve-static": "*" - } - }, - "@types/ws": { - "version": "8.5.3", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.3.tgz", - "integrity": "sha512-6YOoWjruKj1uLf3INHH7D3qTXwFfEsg1kf3c0uDdSBJwfa/llkwIjrAGV7j7mVgGNbzTQ3HiHKKDXl6bJPD97w==", - "requires": { - "@types/node": "*" - } - }, - "@types/yargs": { - "version": "17.0.12", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.12.tgz", - "integrity": "sha512-Nz4MPhecOFArtm81gFQvQqdV7XYCrWKx5uUt6GNHredFHn1i2mtWqXTON7EPXMtNi1qjtjEM/VCHDhcHsAMLXQ==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - }, - "@types/yargs-parser": { - "version": "20.2.1", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-20.2.1.tgz", - "integrity": "sha512-7tFImggNeNBVMsn0vLrpn1H1uPrUBdnARPTpZoitY37ZrdJREzf7I16tMrlK3hen349gr1NYh8CmZQa7CTG6Aw==", - "dev": true - }, - "@typescript-eslint/eslint-plugin": { - "version": "5.36.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.36.2.tgz", - "integrity": "sha512-OwwR8LRwSnI98tdc2z7mJYgY60gf7I9ZfGjN5EjCwwns9bdTuQfAXcsjSB2wSQ/TVNYSGKf4kzVXbNGaZvwiXw==", - "dev": true, - "requires": { - "@typescript-eslint/scope-manager": "5.36.2", - "@typescript-eslint/type-utils": "5.36.2", - "@typescript-eslint/utils": "5.36.2", - "debug": "^4.3.4", - "functional-red-black-tree": "^1.0.1", - "ignore": "^5.2.0", - "regexpp": "^3.2.0", - "semver": "^7.3.7", - "tsutils": "^3.21.0" - } - }, - "@typescript-eslint/parser": { - "version": "5.36.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.36.2.tgz", - "integrity": "sha512-qS/Kb0yzy8sR0idFspI9Z6+t7mqk/oRjnAYfewG+VN73opAUvmYL3oPIMmgOX6CnQS6gmVIXGshlb5RY/R22pA==", - "dev": true, - "requires": { - "@typescript-eslint/scope-manager": "5.36.2", - "@typescript-eslint/types": "5.36.2", - "@typescript-eslint/typescript-estree": "5.36.2", - "debug": "^4.3.4" - } - }, - "@typescript-eslint/scope-manager": { - "version": "5.36.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.36.2.tgz", - "integrity": "sha512-cNNP51L8SkIFSfce8B1NSUBTJTu2Ts4nWeWbFrdaqjmn9yKrAaJUBHkyTZc0cL06OFHpb+JZq5AUHROS398Orw==", - "dev": true, - "requires": { - "@typescript-eslint/types": "5.36.2", - "@typescript-eslint/visitor-keys": "5.36.2" - } - }, - "@typescript-eslint/type-utils": { - "version": "5.36.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.36.2.tgz", - "integrity": "sha512-rPQtS5rfijUWLouhy6UmyNquKDPhQjKsaKH0WnY6hl/07lasj8gPaH2UD8xWkePn6SC+jW2i9c2DZVDnL+Dokw==", - "dev": true, - "requires": { - "@typescript-eslint/typescript-estree": "5.36.2", - "@typescript-eslint/utils": "5.36.2", - "debug": "^4.3.4", - "tsutils": "^3.21.0" - } - }, - "@typescript-eslint/types": { - "version": "5.36.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.36.2.tgz", - "integrity": "sha512-9OJSvvwuF1L5eS2EQgFUbECb99F0mwq501w0H0EkYULkhFa19Qq7WFbycdw1PexAc929asupbZcgjVIe6OK/XQ==", - "dev": true - }, - "@typescript-eslint/typescript-estree": { - "version": "5.36.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.36.2.tgz", - "integrity": "sha512-8fyH+RfbKc0mTspfuEjlfqA4YywcwQK2Amcf6TDOwaRLg7Vwdu4bZzyvBZp4bjt1RRjQ5MDnOZahxMrt2l5v9w==", - "dev": true, - "requires": { - "@typescript-eslint/types": "5.36.2", - "@typescript-eslint/visitor-keys": "5.36.2", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "semver": "^7.3.7", - "tsutils": "^3.21.0" - } - }, - "@typescript-eslint/utils": { - "version": "5.36.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.36.2.tgz", - "integrity": "sha512-uNcopWonEITX96v9pefk9DC1bWMdkweeSsewJ6GeC7L6j2t0SJywisgkr9wUTtXk90fi2Eljj90HSHm3OGdGRg==", - "dev": true, - "requires": { - "@types/json-schema": "^7.0.9", - "@typescript-eslint/scope-manager": "5.36.2", - "@typescript-eslint/types": "5.36.2", - "@typescript-eslint/typescript-estree": "5.36.2", - "eslint-scope": "^5.1.1", - "eslint-utils": "^3.0.0" - } - }, - "@typescript-eslint/visitor-keys": { - "version": "5.36.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.36.2.tgz", - "integrity": "sha512-BtRvSR6dEdrNt7Net2/XDjbYKU5Ml6GqJgVfXT0CxTCJlnIqK7rAGreuWKMT2t8cFUT2Msv5oxw0GMRD7T5J7A==", - "dev": true, - "requires": { - "@typescript-eslint/types": "5.36.2", - "eslint-visitor-keys": "^3.3.0" - } - }, - "accepts": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", - "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", - "requires": { - "mime-types": "~2.1.34", - "negotiator": "0.6.3" - } - }, - "acorn": { - "version": "8.8.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz", - "integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==", - "dev": true - }, - "acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "requires": {} - }, - "acorn-walk": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", - "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", - "dev": true - }, - "agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "dev": true, - "requires": { - "debug": "4" - } - }, - "ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, - "ansi-escapes": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", - "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", - "dev": true, - "requires": { - "type-fest": "^0.21.3" - }, - "dependencies": { - "type-fest": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", - "dev": true - } - } - }, - "ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true - }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "anymatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", - "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", - "dev": true, - "requires": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - } - }, - "append-field": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz", - "integrity": "sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw==" - }, - "aproba": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", - "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", - "dev": true - }, - "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==", - "dev": true, - "requires": { - "delegates": "^1.0.0", - "readable-stream": "^2.0.6" - } - }, - "arg": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "dev": true - }, - "argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" - }, - "array-flatten": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" - }, - "array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true - }, - "asn1": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", - "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", - "dev": true, - "requires": { - "safer-buffer": "~2.1.0" - } - }, - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", - "dev": true - }, - "async": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz", - "integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==", - "dev": true - }, - "asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", - "dev": true - }, - "at-least-node": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", - "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", - "dev": true - }, - "aws-sign2": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==", - "dev": true - }, - "aws4": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.12.0.tgz", - "integrity": "sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg==", - "dev": true - }, - "babel-plugin-istanbul": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", - "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@istanbuljs/load-nyc-config": "^1.0.0", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-instrument": "^5.0.4", - "test-exclude": "^6.0.0" - } - }, - "babel-preset-current-node-syntax": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", - "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", - "dev": true, - "requires": { - "@babel/plugin-syntax-async-generators": "^7.8.4", - "@babel/plugin-syntax-bigint": "^7.8.3", - "@babel/plugin-syntax-class-properties": "^7.8.3", - "@babel/plugin-syntax-import-meta": "^7.8.3", - "@babel/plugin-syntax-json-strings": "^7.8.3", - "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.8.3", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", - "@babel/plugin-syntax-optional-chaining": "^7.8.3", - "@babel/plugin-syntax-top-level-await": "^7.8.3" - } - }, - "balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" - }, - "base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "dev": true - }, - "basic-auth": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz", - "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==", - "requires": { - "safe-buffer": "5.1.2" - } - }, - "bcrypt-pbkdf": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", - "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", - "dev": true, - "requires": { - "tweetnacl": "^0.14.3" - } - }, - "bl": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", - "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", - "dev": true, - "requires": { - "buffer": "^5.5.0", - "inherits": "^2.0.4", - "readable-stream": "^3.4.0" - }, - "dependencies": { - "readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "dev": true, - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - } - } - }, - "bluebird": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-2.11.0.tgz", - "integrity": "sha512-UfFSr22dmHPQqPP9XWHRhq+gWnHCYguQGkXQlbyPtW5qTnhFWA8/iXg765tH0cAjy7l/zPJ1aBTO0g5XgA7kvQ==", - "dev": true - }, - "body-parser": { - "version": "1.20.0", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.0.tgz", - "integrity": "sha512-DfJ+q6EPcGKZD1QWUjSpqp+Q7bDQTsQIF4zfUAtZ6qk+H/3/QRhg9CEp39ss+/T2vw0+HaidC0ecJj/DRLIaKg==", - "requires": { - "bytes": "3.1.2", - "content-type": "~1.0.4", - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "on-finished": "2.4.1", - "qs": "6.10.3", - "raw-body": "2.5.1", - "type-is": "~1.6.18", - "unpipe": "1.0.0" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - }, - "on-finished": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", - "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", - "requires": { - "ee-first": "1.1.1" - } - } - } - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "requires": { - "fill-range": "^7.0.1" - } - }, - "brotli": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/brotli/-/brotli-1.3.3.tgz", - "integrity": "sha512-oTKjJdShmDuGW94SyyaoQvAjf30dZaHnjJ8uAF+u2/vGJkJbJPJAT1gDiOJP5v1Zb6f9KEyW/1HpuaWIXtGHPg==", - "dev": true, - "requires": { - "base64-js": "^1.1.2" - } - }, - "browserslist": { - "version": "4.20.4", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.20.4.tgz", - "integrity": "sha512-ok1d+1WpnU24XYN7oC3QWgTyMhY/avPJ/r9T00xxvUOIparA/gc+UPUMaod3i+G6s+nI2nUb9xZ5k794uIwShw==", - "dev": true, - "requires": { - "caniuse-lite": "^1.0.30001349", - "electron-to-chromium": "^1.4.147", - "escalade": "^3.1.1", - "node-releases": "^2.0.5", - "picocolors": "^1.0.0" - } - }, - "bs-logger": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", - "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", - "dev": true, - "requires": { - "fast-json-stable-stringify": "2.x" - } - }, - "bser": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", - "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", - "dev": true, - "requires": { - "node-int64": "^0.4.0" - } - }, - "buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "dev": true, - "requires": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" - } - }, - "buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" - }, - "busboy": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", - "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", - "requires": { - "streamsearch": "^1.1.0" - } - }, - "bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==" - }, - "call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", - "requires": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" - } - }, - "call-me-maybe": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.2.tgz", - "integrity": "sha512-HpX65o1Hnr9HH25ojC1YGs7HCQLq0GCOibSaWER0eNpgJ/Z1MZv2mTc7+xh6WOPxbRVcmgbv4hGU+uSQ/2xFZQ==" - }, - "callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true - }, - "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true - }, - "caniuse-lite": { - "version": "1.0.30001349", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001349.tgz", - "integrity": "sha512-VFaWW3jeo6DLU5rwdiasosxhYSduJgSGil4cSyX3/85fbctlE58pXAkWyuRmVA0r2RxsOSVYUTZcySJ8WpbTxw==", - "dev": true - }, - "caseless": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==", - "dev": true - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "char-regex": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", - "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", - "dev": true - }, - "chardet": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/chardet/-/chardet-1.6.0.tgz", - "integrity": "sha512-+QOTw3otC4+FxdjK9RopGpNOglADbr4WPFi0SonkO99JbpkTPbMxmdm4NenhF5Zs+4gPXLI1+y2uazws5TMe8w==", - "dev": true - }, - "charset": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/charset/-/charset-1.0.1.tgz", - "integrity": "sha512-6dVyOOYjpfFcL1Y4qChrAoQLRHvj2ziyhcm0QJlhOcAhykL/k1kTUPbeo+87MNRTRdk2OIIsIXbuF3x2wi5EXg==", - "dev": true - }, - "chownr": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", - "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", - "dev": true - }, - "ci-info": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.3.1.tgz", - "integrity": "sha512-SXgeMX9VwDe7iFFaEWkA5AstuER9YKqy4EhHqr4DVqkwmD9rpVimkMKWHdjn30Ja45txyjhSn63lVX69eVCckg==", - "dev": true - }, - "cjs-module-lexer": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz", - "integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==", - "dev": true - }, - "cli-progress": { - "version": "3.12.0", - "resolved": "https://registry.npmjs.org/cli-progress/-/cli-progress-3.12.0.tgz", - "integrity": "sha512-tRkV3HJ1ASwm19THiiLIXLO7Im7wlTuKnvkYaTkyoAPefqjNg7W7DHKUlGRxy9vxDvbyCYQkQozvptuMkGCg8A==", - "dev": true, - "requires": { - "string-width": "^4.2.3" - } - }, - "cli-table3": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.3.tgz", - "integrity": "sha512-w5Jac5SykAeZJKntOxJCrm63Eg5/4dhMWIcuTbo9rpE+brgaSZo0RuNJZeOyMgsUdhDeojvgyQLmjI+K50ZGyg==", - "dev": true, - "requires": { - "@colors/colors": "1.5.0", - "string-width": "^4.2.0" - } - }, - "cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "dev": true, - "requires": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } - }, - "co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", - "dev": true - }, - "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==", - "dev": true - }, - "collect-v8-coverage": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz", - "integrity": "sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==", - "dev": true - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "colors": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", - "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", - "dev": true - }, - "combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dev": true, - "requires": { - "delayed-stream": "~1.0.0" - } - }, - "commander": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-11.0.0.tgz", - "integrity": "sha512-9HMlXtt/BNoYr8ooyjjNRdIilOTkVJXB+GhxMTtOKwk0R4j4lS4NpjuqmRxroBfnfTSHQIHQB7wryHhXarNjmQ==", - "dev": true - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" - }, - "concat-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-2.0.0.tgz", - "integrity": "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==", - "requires": { - "buffer-from": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.0.2", - "typedarray": "^0.0.6" - }, - "dependencies": { - "readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - } - } - }, - "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==", - "dev": true - }, - "content-disposition": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", - "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", - "requires": { - "safe-buffer": "5.2.1" - }, - "dependencies": { - "safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" - } - } - }, - "content-type": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", - "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" - }, - "convert-source-map": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", - "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.1" - } - }, - "cookie": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", - "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==" - }, - "cookie-signature": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" - }, - "core-util-is": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", - "dev": true - }, - "cors": { - "version": "2.8.5", - "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", - "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", - "requires": { - "object-assign": "^4", - "vary": "^1" - } - }, - "create-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", - "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "dev": true - }, - "cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "requires": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - } - }, - "csv-parse": { - "version": "4.16.3", - "resolved": "https://registry.npmjs.org/csv-parse/-/csv-parse-4.16.3.tgz", - "integrity": "sha512-cO1I/zmz4w2dcKHVvpCr7JVRu8/FymG5OEpmvsZYlccYolPBLoVGKUHgNoc4ZGkFeFlWGEDmMyBM+TTqRdW/wg==", - "dev": true - }, - "dashdash": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==", - "dev": true, - "requires": { - "assert-plus": "^1.0.0" - } - }, - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "requires": { - "ms": "2.1.2" - } - }, - "decompress-response": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-4.2.1.tgz", - "integrity": "sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==", - "dev": true, - "requires": { - "mimic-response": "^2.0.0" - } - }, - "dedent": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", - "integrity": "sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==", - "dev": true - }, - "deep-extend": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", - "dev": true - }, - "deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true - }, - "deepmerge": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", - "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", - "dev": true - }, - "delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "dev": true - }, - "delegates": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", - "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", - "dev": true - }, - "depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==" - }, - "des.js": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.1.0.tgz", - "integrity": "sha512-r17GxjhUCjSRy8aiJpr8/UadFIzMzJGexI3Nmz4ADi9LYSFx4gTBp80+NaX/YsXWWLhpZ7v/v/ubEc/bCNfKwg==", - "dev": true, - "requires": { - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0" - } - }, - "destroy": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", - "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==" - }, - "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==", - "dev": true - }, - "detect-newline": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", - "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", - "dev": true - }, - "diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true - }, - "diff-sequences": { - "version": "29.0.0", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.0.0.tgz", - "integrity": "sha512-7Qe/zd1wxSDL4D/X/FPjOMB+ZMDt71W94KYaq05I2l0oQqgXgs7s4ftYYmV38gBSrPz2vcygxfs1xn0FT+rKNA==", - "dev": true - }, - "dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, - "requires": { - "path-type": "^4.0.0" - } - }, - "doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "requires": { - "esutils": "^2.0.2" - } - }, - "ecc-jsbn": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", - "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==", - "dev": true, - "requires": { - "jsbn": "~0.1.0", - "safer-buffer": "^2.1.0" - } - }, - "ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" - }, - "electron-to-chromium": { - "version": "1.4.147", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.147.tgz", - "integrity": "sha512-czclPqxLMPqPMkahKcske4TaS5lcznsc26ByBlEFDU8grTBVK9C5W6K9I6oEEhm4Ai4jTihGnys90xY1yjXcRg==", - "dev": true - }, - "emittery": { - "version": "0.10.2", - "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.10.2.tgz", - "integrity": "sha512-aITqOwnLanpHLNXZJENbOgjUBeHocD+xsSJmNrjovKBW5HbSpW3d1pEls7GFQPUWXiwG9+0P4GtHfEqC/4M0Iw==", - "dev": true - }, - "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==", - "dev": true - }, - "encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==" - }, - "end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "dev": true, - "requires": { - "once": "^1.4.0" - } - }, - "error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, - "requires": { - "is-arrayish": "^0.2.1" - } - }, - "escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "dev": true - }, - "escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" - }, - "escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true - }, - "eslint": { - "version": "8.23.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.23.0.tgz", - "integrity": "sha512-pBG/XOn0MsJcKcTRLr27S5HpzQo4kLr+HjLQIyK4EiCsijDl/TB+h5uEuJU6bQ8Edvwz1XWOjpaP2qgnXGpTcA==", - "dev": true, - "requires": { - "@eslint/eslintrc": "^1.3.1", - "@humanwhocodes/config-array": "^0.10.4", - "@humanwhocodes/gitignore-to-minimatch": "^1.0.2", - "@humanwhocodes/module-importer": "^1.0.1", - "ajv": "^6.10.0", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.3.2", - "doctrine": "^3.0.0", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.1.1", - "eslint-utils": "^3.0.0", - "eslint-visitor-keys": "^3.3.0", - "espree": "^9.4.0", - "esquery": "^1.4.0", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "find-up": "^5.0.0", - "functional-red-black-tree": "^1.0.1", - "glob-parent": "^6.0.1", - "globals": "^13.15.0", - "globby": "^11.1.0", - "grapheme-splitter": "^1.0.4", - "ignore": "^5.2.0", - "import-fresh": "^3.0.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "js-yaml": "^4.1.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.1", - "regexpp": "^3.2.0", - "strip-ansi": "^6.0.1", - "strip-json-comments": "^3.1.0", - "text-table": "^0.2.0" - }, - "dependencies": { - "eslint-scope": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", - "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", - "dev": true, - "requires": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - } - }, - "estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true - }, - "find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "requires": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - } - }, - "locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "requires": { - "p-locate": "^5.0.0" - } - }, - "p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "requires": { - "yocto-queue": "^0.1.0" - } - }, - "p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "requires": { - "p-limit": "^3.0.2" - } - } - } - }, - "eslint-plugin-jest": { - "version": "27.0.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-27.0.1.tgz", - "integrity": "sha512-LosUsrkwVSs/8Z/I8Hqn5vWgTEsHrfIquDEKOsV8/cl+gbFR4tiRCE1AimEotsHjSC0Rx1tYm6vPhw8C3ktmmg==", - "dev": true, - "requires": { - "@typescript-eslint/utils": "^5.10.0" - } - }, - "eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dev": true, - "requires": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - } - }, - "eslint-utils": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", - "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", - "dev": true, - "requires": { - "eslint-visitor-keys": "^2.0.0" - }, - "dependencies": { - "eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", - "dev": true - } - } - }, - "eslint-visitor-keys": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", - "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", - "dev": true - }, - "espree": { - "version": "9.4.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.0.tgz", - "integrity": "sha512-DQmnRpLj7f6TgN/NYb0MTzJXL+vJF9h3pHy4JhCIs3zwcgez8xmGg3sXHcEO97BrmO2OSvCwMdfdlyl+E9KjOw==", - "dev": true, - "requires": { - "acorn": "^8.8.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.3.0" - } - }, - "esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true - }, - "esquery": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", - "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", - "dev": true, - "requires": { - "estraverse": "^5.1.0" - }, - "dependencies": { - "estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", - "dev": true - } - } - }, - "esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "requires": { - "estraverse": "^5.2.0" - }, - "dependencies": { - "estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true - } - } - }, - "estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true - }, - "esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==" - }, - "etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==" - }, - "execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", - "dev": true, - "requires": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" - } - }, - "exit": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", - "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", - "dev": true - }, - "expand-template": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", - "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", - "dev": true - }, - "expect": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/expect/-/expect-29.0.2.tgz", - "integrity": "sha512-JeJlAiLKn4aApT4pzUXBVxl3NaZidWIOdg//smaIlP9ZMBDkHZGFd9ubphUZP9pUyDEo7bC6M0IIZR51o75qQw==", - "dev": true, - "requires": { - "@jest/expect-utils": "^29.0.2", - "jest-get-type": "^29.0.0", - "jest-matcher-utils": "^29.0.2", - "jest-message-util": "^29.0.2", - "jest-util": "^29.0.2" - } - }, - "express": { - "version": "4.18.1", - "resolved": "https://registry.npmjs.org/express/-/express-4.18.1.tgz", - "integrity": "sha512-zZBcOX9TfehHQhtupq57OF8lFZ3UZi08Y97dwFCkD8p9d/d2Y3M+ykKcwaMDEL+4qyUolgBDX6AblpR3fL212Q==", - "requires": { - "accepts": "~1.3.8", - "array-flatten": "1.1.1", - "body-parser": "1.20.0", - "content-disposition": "0.5.4", - "content-type": "~1.0.4", - "cookie": "0.5.0", - "cookie-signature": "1.0.6", - "debug": "2.6.9", - "depd": "2.0.0", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "finalhandler": "1.2.0", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "merge-descriptors": "1.0.1", - "methods": "~1.1.2", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "path-to-regexp": "0.1.7", - "proxy-addr": "~2.0.7", - "qs": "6.10.3", - "range-parser": "~1.2.1", - "safe-buffer": "5.2.1", - "send": "0.18.0", - "serve-static": "1.15.0", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "type-is": "~1.6.18", - "utils-merge": "1.0.1", - "vary": "~1.1.2" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - }, - "on-finished": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", - "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", - "requires": { - "ee-first": "1.1.1" - } - }, - "safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" - } - } - }, - "extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", - "dev": true - }, - "extsprintf": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==", - "dev": true - }, - "fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true - }, - "fast-glob": { - "version": "3.2.11", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", - "integrity": "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==", - "dev": true, - "requires": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - }, - "dependencies": { - "glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "requires": { - "is-glob": "^4.0.1" - } - } - } - }, - "fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true - }, - "fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true - }, - "fastq": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", - "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", - "dev": true, - "requires": { - "reusify": "^1.0.4" - } - }, - "fb-watchman": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.1.tgz", - "integrity": "sha512-DkPJKQeY6kKwmuMretBhr7G6Vodr7bFwDYTXIkfG1gjvNpaxBTQV3PbXg6bR1c1UP4jPOX0jHUbbHANL9vRjVg==", - "dev": true, - "requires": { - "bser": "2.1.1" - } - }, - "file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", - "dev": true, - "requires": { - "flat-cache": "^3.0.4" - } - }, - "file-type": { - "version": "3.9.0", - "resolved": "https://registry.npmjs.org/file-type/-/file-type-3.9.0.tgz", - "integrity": "sha512-RLoqTXE8/vPmMuTI88DAzhMYC99I8BWv7zYP4A1puo5HIjEJ5EX48ighy4ZyKMG9EDXxBgW6e++cn7d1xuFghA==", - "dev": true - }, - "filesize": { - "version": "10.0.12", - "resolved": "https://registry.npmjs.org/filesize/-/filesize-10.0.12.tgz", - "integrity": "sha512-6RS9gDchbn+qWmtV2uSjo5vmKizgfCQeb5jKmqx8HyzA3MoLqqyQxN+QcjkGBJt7FjJ9qFce67Auyya5rRRbpw==", - "dev": true - }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "requires": { - "to-regex-range": "^5.0.1" - } - }, - "finalhandler": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", - "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", - "requires": { - "debug": "2.6.9", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "statuses": "2.0.1", - "unpipe": "~1.0.0" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - }, - "on-finished": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", - "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", - "requires": { - "ee-first": "1.1.1" - } - } - } - }, - "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, - "flat-cache": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", - "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", - "dev": true, - "requires": { - "flatted": "^3.1.0", - "rimraf": "^3.0.2" - } - }, - "flatted": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.6.tgz", - "integrity": "sha512-0sQoMh9s0BYsm+12Huy/rkKxVu4R1+r96YX5cG44rHV0pQ6iC3Q+mkoMFaGWObMFYQxCVT+ssG1ksneA2MI9KQ==", - "dev": true - }, - "forever-agent": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==", - "dev": true - }, - "forwarded": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", - "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==" - }, - "fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==" - }, - "from2": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", - "integrity": "sha512-OMcX/4IC/uqEPVgGeyfN22LJk6AZrMkRZHxcHBMBvHScDGgwTm2GT2Wkgtocyd3JfZffjj2kYUDXXII0Fk9W0g==", - "dev": true, - "requires": { - "inherits": "^2.0.1", - "readable-stream": "^2.0.0" - } - }, - "fs-constants": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", - "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", - "dev": true - }, - "fs-extra": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", - "dev": true, - "requires": { - "at-least-node": "^1.0.0", - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - } - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" - }, - "fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, - "optional": true - }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" - }, - "functional-red-black-tree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", - "dev": true - }, - "gauge": { - "version": "2.7.4", - "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", - "integrity": "sha512-14x4kjc6lkD3ltw589k0NrPD6cCNTD6CWoVUNpB85+DrtONoZn+Rug6xZU5RvSC4+TZPxA5AnBibQYAvZn41Hg==", - "dev": true, - "requires": { - "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" - }, - "dependencies": { - "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==", - "dev": true - }, - "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==", - "dev": true, - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "dev": true, - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true, - "requires": { - "ansi-regex": "^2.0.0" - } - } - } - }, - "gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true - }, - "get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true - }, - "get-intrinsic": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", - "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", - "requires": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1" - } - }, - "get-package-type": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", - "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", - "dev": true - }, - "get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "dev": true - }, - "getpass": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==", - "dev": true, - "requires": { - "assert-plus": "^1.0.0" - } - }, - "github-from-package": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", - "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==", - "dev": true - }, - "glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, - "requires": { - "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" - } - }, - "glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "requires": { - "is-glob": "^4.0.3" - } - }, - "globals": { - "version": "13.17.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.17.0.tgz", - "integrity": "sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw==", - "dev": true, - "requires": { - "type-fest": "^0.20.2" - } - }, - "globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "dev": true, - "requires": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - } - }, - "graceful-fs": { - "version": "4.2.10", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", - "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", - "dev": true - }, - "grapheme-splitter": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", - "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", - "dev": true - }, - "handlebars": { - "version": "4.7.8", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz", - "integrity": "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==", - "dev": true, - "requires": { - "minimist": "^1.2.5", - "neo-async": "^2.6.2", - "source-map": "^0.6.1", - "uglify-js": "^3.1.4", - "wordwrap": "^1.0.0" - } - }, - "har-schema": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==", - "dev": true - }, - "har-validator": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", - "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", - "dev": true, - "requires": { - "ajv": "^6.12.3", - "har-schema": "^2.0.0" - } - }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "requires": { - "function-bind": "^1.1.1" - } - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==" - }, - "has-unicode": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", - "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", - "dev": true - }, - "html-escaper": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", - "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", - "dev": true - }, - "http-errors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", - "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", - "requires": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" - } - }, - "http-reasons": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/http-reasons/-/http-reasons-0.1.0.tgz", - "integrity": "sha512-P6kYh0lKZ+y29T2Gqz+RlC9WBLhKe8kDmcJ+A+611jFfxdPsbMRQ5aNmFRM3lENqFkK+HTTL+tlQviAiv0AbLQ==", - "dev": true - }, - "http-signature": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.3.6.tgz", - "integrity": "sha512-3adrsD6zqo4GsTqtO7FyrejHNv+NgiIfAfv68+jVlFmSr9OGy7zrxONceFRLKvnnZA5jbxQBX1u9PpB6Wi32Gw==", - "dev": true, - "requires": { - "assert-plus": "^1.0.0", - "jsprim": "^2.0.2", - "sshpk": "^1.14.1" - } - }, - "httpntlm": { - "version": "1.8.13", - "resolved": "https://registry.npmjs.org/httpntlm/-/httpntlm-1.8.13.tgz", - "integrity": "sha512-2F2FDPiWT4rewPzNMg3uPhNkP3NExENlUGADRUDPQvuftuUTGW98nLZtGemCIW3G40VhWZYgkIDcQFAwZ3mf2Q==", - "dev": true, - "requires": { - "des.js": "^1.0.1", - "httpreq": ">=0.4.22", - "js-md4": "^0.3.2", - "underscore": "~1.12.1" - } - }, - "httpreq": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/httpreq/-/httpreq-1.1.1.tgz", - "integrity": "sha512-uhSZLPPD2VXXOSN8Cni3kIsoFHaU2pT/nySEU/fHr/ePbqHYr0jeiQRmUKLEirC09SFPsdMoA7LU7UXMd/w0Kw==", - "dev": true - }, - "https-proxy-agent": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", - "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", - "dev": true, - "requires": { - "agent-base": "6", - "debug": "4" - } - }, - "human-signals": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", - "dev": true - }, - "iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "requires": { - "safer-buffer": ">= 2.1.2 < 3" - } - }, - "ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "dev": true - }, - "ignore": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", - "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", - "dev": true - }, - "import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "requires": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - } - }, - "import-local": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", - "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", - "dev": true, - "requires": { - "pkg-dir": "^4.2.0", - "resolve-cwd": "^3.0.0" - } - }, - "imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", - "dev": true - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "dev": true - }, - "into-stream": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/into-stream/-/into-stream-6.0.0.tgz", - "integrity": "sha512-XHbaOAvP+uFKUFsOgoNPRjLkwB+I22JFPFe5OjTkQ0nwgj6+pSjb4NmB6VMxaPshLiOf+zcpOCBQuLwC1KHhZA==", - "dev": true, - "requires": { - "from2": "^2.3.0", - "p-is-promise": "^3.0.0" - } - }, - "ipaddr.js": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" - }, - "is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "dev": true - }, - "is-core-module": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.9.0.tgz", - "integrity": "sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A==", - "dev": true, - "requires": { - "has": "^1.0.3" - } - }, - "is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "dev": true - }, - "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==", - "dev": true - }, - "is-generator-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", - "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", - "dev": true - }, - "is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "requires": { - "is-extglob": "^2.1.1" - } - }, - "is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true - }, - "is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true - }, - "is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", - "dev": true - }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true - }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true - }, - "isstream": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==", - "dev": true - }, - "istanbul-lib-coverage": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", - "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", - "dev": true - }, - "istanbul-lib-instrument": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.0.tgz", - "integrity": "sha512-6Lthe1hqXHBNsqvgDzGO6l03XNeu3CrG4RqQ1KM9+l5+jNGpEJfIELx1NS3SEHmJQA8np/u+E4EPRKRiu6m19A==", - "dev": true, - "requires": { - "@babel/core": "^7.12.3", - "@babel/parser": "^7.14.7", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.2.0", - "semver": "^6.3.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } - } - }, - "istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", - "dev": true, - "requires": { - "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^3.0.0", - "supports-color": "^7.1.0" - } - }, - "istanbul-lib-source-maps": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", - "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", - "dev": true, - "requires": { - "debug": "^4.1.1", - "istanbul-lib-coverage": "^3.0.0", - "source-map": "^0.6.1" - } - }, - "istanbul-reports": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz", - "integrity": "sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==", - "dev": true, - "requires": { - "html-escaper": "^2.0.0", - "istanbul-lib-report": "^3.0.0" - } - }, - "jest": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/jest/-/jest-29.0.2.tgz", - "integrity": "sha512-enziNbNUmXTcTaTP/Uq5rV91r0Yqy2UKzLUIabxMpGm9YHz8qpbJhiRnNVNvm6vzWfzt/0o97NEHH8/3udoClA==", - "dev": true, - "requires": { - "@jest/core": "^29.0.2", - "@jest/types": "^29.0.2", - "import-local": "^3.0.2", - "jest-cli": "^29.0.2" - } - }, - "jest-changed-files": { - "version": "29.0.0", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.0.0.tgz", - "integrity": "sha512-28/iDMDrUpGoCitTURuDqUzWQoWmOmOKOFST1mi2lwh62X4BFf6khgH3uSuo1e49X/UDjuApAj3w0wLOex4VPQ==", - "dev": true, - "requires": { - "execa": "^5.0.0", - "p-limit": "^3.1.0" - }, - "dependencies": { - "p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "requires": { - "yocto-queue": "^0.1.0" - } - } - } - }, - "jest-circus": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.0.2.tgz", - "integrity": "sha512-YTPEsoE1P1X0bcyDQi3QIkpt2Wl9om9k2DQRuLFdS5x8VvAKSdYAVJufgvudhnKgM8WHvvAzhBE+1DRQB8x1CQ==", - "dev": true, - "requires": { - "@jest/environment": "^29.0.2", - "@jest/expect": "^29.0.2", - "@jest/test-result": "^29.0.2", - "@jest/types": "^29.0.2", - "@types/node": "*", - "chalk": "^4.0.0", - "co": "^4.6.0", - "dedent": "^0.7.0", - "is-generator-fn": "^2.0.0", - "jest-each": "^29.0.2", - "jest-matcher-utils": "^29.0.2", - "jest-message-util": "^29.0.2", - "jest-runtime": "^29.0.2", - "jest-snapshot": "^29.0.2", - "jest-util": "^29.0.2", - "p-limit": "^3.1.0", - "pretty-format": "^29.0.2", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" - }, - "dependencies": { - "p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "requires": { - "yocto-queue": "^0.1.0" - } - } - } - }, - "jest-cli": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.0.2.tgz", - "integrity": "sha512-tlf8b+4KcUbBGr25cywIi3+rbZ4+G+SiG8SvY552m9sRZbXPafdmQRyeVE/C/R8K+TiBAMrTIUmV2SlStRJ40g==", - "dev": true, - "requires": { - "@jest/core": "^29.0.2", - "@jest/test-result": "^29.0.2", - "@jest/types": "^29.0.2", - "chalk": "^4.0.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.9", - "import-local": "^3.0.2", - "jest-config": "^29.0.2", - "jest-util": "^29.0.2", - "jest-validate": "^29.0.2", - "prompts": "^2.0.1", - "yargs": "^17.3.1" - } - }, - "jest-config": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.0.2.tgz", - "integrity": "sha512-RU4gzeUNZAFktYVzDGimDxeYoaiTnH100jkYYZgldqFamaZukF0IqmFx8+QrzVeEWccYg10EEJT3ox1Dq5b74w==", - "dev": true, - "requires": { - "@babel/core": "^7.11.6", - "@jest/test-sequencer": "^29.0.2", - "@jest/types": "^29.0.2", - "babel-jest": "^29.0.2", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "deepmerge": "^4.2.2", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "jest-circus": "^29.0.2", - "jest-environment-node": "^29.0.2", - "jest-get-type": "^29.0.0", - "jest-regex-util": "^29.0.0", - "jest-resolve": "^29.0.2", - "jest-runner": "^29.0.2", - "jest-util": "^29.0.2", - "jest-validate": "^29.0.2", - "micromatch": "^4.0.4", - "parse-json": "^5.2.0", - "pretty-format": "^29.0.2", - "slash": "^3.0.0", - "strip-json-comments": "^3.1.1" - }, - "dependencies": { - "@jest/transform": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.0.2.tgz", - "integrity": "sha512-lajVQx2AnsR+Pa17q2zR7eikz2PkPs1+g/qPbZkqQATeS/s6eT55H+yHcsLfuI/0YQ/4VSBepSu3bOX+44q0aA==", - "dev": true, - "requires": { - "@babel/core": "^7.11.6", - "@jest/types": "^29.0.2", - "@jridgewell/trace-mapping": "^0.3.15", - "babel-plugin-istanbul": "^6.1.1", - "chalk": "^4.0.0", - "convert-source-map": "^1.4.0", - "fast-json-stable-stringify": "^2.1.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.0.2", - "jest-regex-util": "^29.0.0", - "jest-util": "^29.0.2", - "micromatch": "^4.0.4", - "pirates": "^4.0.4", - "slash": "^3.0.0", - "write-file-atomic": "^4.0.1" - } - }, - "babel-jest": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.0.2.tgz", - "integrity": "sha512-yTu4/WSi/HzarjQtrJSwV+/0maoNt+iP0DmpvFJdv9yY+5BuNle8TbheHzzcSWj5gIHfuhpbLYHWRDYhWKyeKQ==", - "dev": true, - "requires": { - "@jest/transform": "^29.0.2", - "@types/babel__core": "^7.1.14", - "babel-plugin-istanbul": "^6.1.1", - "babel-preset-jest": "^29.0.2", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "slash": "^3.0.0" - } - }, - "babel-plugin-jest-hoist": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.0.2.tgz", - "integrity": "sha512-eBr2ynAEFjcebVvu8Ktx580BD1QKCrBG1XwEUTXJe285p9HA/4hOhfWCFRQhTKSyBV0VzjhG7H91Eifz9s29hg==", - "dev": true, - "requires": { - "@babel/template": "^7.3.3", - "@babel/types": "^7.3.3", - "@types/babel__core": "^7.1.14", - "@types/babel__traverse": "^7.0.6" - } - }, - "babel-preset-jest": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.0.2.tgz", - "integrity": "sha512-BeVXp7rH5TK96ofyEnHjznjLMQ2nAeDJ+QzxKnHAAMs0RgrQsCywjAN8m4mOm5Di0pxU//3AoEeJJrerMH5UeA==", - "dev": true, - "requires": { - "babel-plugin-jest-hoist": "^29.0.2", - "babel-preset-current-node-syntax": "^1.0.0" - } - }, - "jest-haste-map": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.0.2.tgz", - "integrity": "sha512-SOorh2ysQ0fe8gsF4gaUDhoMIWAvi2hXOkwThEO48qT3JqA8GLAUieQcIvdSEd6M0scRDe1PVmKc5tXR3Z0U0A==", - "dev": true, - "requires": { - "@jest/types": "^29.0.2", - "@types/graceful-fs": "^4.1.3", - "@types/node": "*", - "anymatch": "^3.0.3", - "fb-watchman": "^2.0.0", - "fsevents": "^2.3.2", - "graceful-fs": "^4.2.9", - "jest-regex-util": "^29.0.0", - "jest-util": "^29.0.2", - "jest-worker": "^29.0.2", - "micromatch": "^4.0.4", - "walker": "^1.0.8" - } - }, - "jest-regex-util": { - "version": "29.0.0", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.0.0.tgz", - "integrity": "sha512-BV7VW7Sy0fInHWN93MMPtlClweYv2qrSCwfeFWmpribGZtQPWNvRSq9XOVgOEjU1iBGRKXUZil0o2AH7Iy9Lug==", - "dev": true - }, - "jest-worker": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.0.2.tgz", - "integrity": "sha512-EyvBlYcvd2pg28yg5A3OODQnqK9LI1kitnGUZUG5/NYIeaRgewtYBKB5wlr7oXj8zPCkzev7EmnTCsrXK7V+Xw==", - "dev": true, - "requires": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - } - }, - "supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "jest-diff": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.0.2.tgz", - "integrity": "sha512-b9l9970sa1rMXH1owp2Woprmy42qIwwll/htsw4Gf7+WuSp5bZxNhkKHDuCGKL+HoHn1KhcC+tNEeAPYBkD2Jg==", - "dev": true, - "requires": { - "chalk": "^4.0.0", - "diff-sequences": "^29.0.0", - "jest-get-type": "^29.0.0", - "pretty-format": "^29.0.2" - } - }, - "jest-docblock": { - "version": "29.0.0", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.0.0.tgz", - "integrity": "sha512-s5Kpra/kLzbqu9dEjov30kj1n4tfu3e7Pl8v+f8jOkeWNqM6Ds8jRaJfZow3ducoQUrf2Z4rs2N5S3zXnb83gw==", - "dev": true, - "requires": { - "detect-newline": "^3.0.0" - } - }, - "jest-each": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.0.2.tgz", - "integrity": "sha512-+sA9YjrJl35iCg0W0VCrgCVj+wGhDrrKQ+YAqJ/DHBC4gcDFAeePtRRhpJnX9gvOZ63G7gt52pwp2PesuSEx0Q==", - "dev": true, - "requires": { - "@jest/types": "^29.0.2", - "chalk": "^4.0.0", - "jest-get-type": "^29.0.0", - "jest-util": "^29.0.2", - "pretty-format": "^29.0.2" - } - }, - "jest-environment-node": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.0.2.tgz", - "integrity": "sha512-4Fv8GXVCToRlMzDO94gvA8iOzKxQ7rhAbs8L+j8GPyTxGuUiYkV+63LecGeVdVhsL2KXih1sKnoqmH6tp89J7Q==", - "dev": true, - "requires": { - "@jest/environment": "^29.0.2", - "@jest/fake-timers": "^29.0.2", - "@jest/types": "^29.0.2", - "@types/node": "*", - "jest-mock": "^29.0.2", - "jest-util": "^29.0.2" - } - }, - "jest-get-type": { - "version": "29.0.0", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.0.0.tgz", - "integrity": "sha512-83X19z/HuLKYXYHskZlBAShO7UfLFXu/vWajw9ZNJASN32li8yHMaVGAQqxFW1RCFOkB7cubaL6FaJVQqqJLSw==", - "dev": true - }, - "jest-leak-detector": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.0.2.tgz", - "integrity": "sha512-5f0493qDeAxjUldkBSQg5D1cLadRgZVyWpTQvfJeQwQUpHQInE21AyVHVv64M7P2Ue8Z5EZ4BAcoDS/dSPPgMw==", - "dev": true, - "requires": { - "jest-get-type": "^29.0.0", - "pretty-format": "^29.0.2" - } - }, - "jest-matcher-utils": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.0.2.tgz", - "integrity": "sha512-s62YkHFBfAx0JLA2QX1BlnCRFwHRobwAv2KP1+YhjzF6ZCbCVrf1sG8UJyn62ZUsDaQKpoo86XMTjkUyO5aWmQ==", - "dev": true, - "requires": { - "chalk": "^4.0.0", - "jest-diff": "^29.0.2", - "jest-get-type": "^29.0.0", - "pretty-format": "^29.0.2" - } - }, - "jest-message-util": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.0.2.tgz", - "integrity": "sha512-kcJAgms3ckJV0wUoLsAM40xAhY+pb9FVSZwicjFU9PFkaTNmqh9xd99/CzKse48wPM1ANUQKmp03/DpkY+lGrA==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.12.13", - "@jest/types": "^29.0.2", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "micromatch": "^4.0.4", - "pretty-format": "^29.0.2", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" - } - }, - "jest-mock": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.0.2.tgz", - "integrity": "sha512-giWXOIT23UCxHCN2VUfUJ0Q7SmiqQwfSFXlCaIhW5anITpNQ+3vuLPQdKt5wkuwM37GrbFyHIClce8AAK9ft9g==", - "dev": true, - "requires": { - "@jest/types": "^29.0.2", - "@types/node": "*" - } - }, - "jest-pnp-resolver": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz", - "integrity": "sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w==", - "dev": true, - "requires": {} - }, - "jest-resolve": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.0.2.tgz", - "integrity": "sha512-V3uLjSA+EHxLtjIDKTBXnY71hyx+8lusCqPXvqzkFO1uCGvVpjBfuOyp+KOLBNSuY61kM2jhepiMwt4eiJS+Vw==", - "dev": true, - "requires": { - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.0.2", - "jest-pnp-resolver": "^1.2.2", - "jest-util": "^29.0.2", - "jest-validate": "^29.0.2", - "resolve": "^1.20.0", - "resolve.exports": "^1.1.0", - "slash": "^3.0.0" - }, - "dependencies": { - "jest-haste-map": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.0.2.tgz", - "integrity": "sha512-SOorh2ysQ0fe8gsF4gaUDhoMIWAvi2hXOkwThEO48qT3JqA8GLAUieQcIvdSEd6M0scRDe1PVmKc5tXR3Z0U0A==", - "dev": true, - "requires": { - "@jest/types": "^29.0.2", - "@types/graceful-fs": "^4.1.3", - "@types/node": "*", - "anymatch": "^3.0.3", - "fb-watchman": "^2.0.0", - "fsevents": "^2.3.2", - "graceful-fs": "^4.2.9", - "jest-regex-util": "^29.0.0", - "jest-util": "^29.0.2", - "jest-worker": "^29.0.2", - "micromatch": "^4.0.4", - "walker": "^1.0.8" - } - }, - "jest-regex-util": { - "version": "29.0.0", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.0.0.tgz", - "integrity": "sha512-BV7VW7Sy0fInHWN93MMPtlClweYv2qrSCwfeFWmpribGZtQPWNvRSq9XOVgOEjU1iBGRKXUZil0o2AH7Iy9Lug==", - "dev": true - }, - "jest-worker": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.0.2.tgz", - "integrity": "sha512-EyvBlYcvd2pg28yg5A3OODQnqK9LI1kitnGUZUG5/NYIeaRgewtYBKB5wlr7oXj8zPCkzev7EmnTCsrXK7V+Xw==", - "dev": true, - "requires": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - } - }, - "supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "jest-resolve-dependencies": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.0.2.tgz", - "integrity": "sha512-fSAu6eIG7wtGdnPJUkVVdILGzYAP9Dj/4+zvC8BrGe8msaUMJ9JeygU0Hf9+Uor6/icbuuzQn5See1uajLnAqg==", - "dev": true, - "requires": { - "jest-regex-util": "^29.0.0", - "jest-snapshot": "^29.0.2" - }, - "dependencies": { - "jest-regex-util": { - "version": "29.0.0", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.0.0.tgz", - "integrity": "sha512-BV7VW7Sy0fInHWN93MMPtlClweYv2qrSCwfeFWmpribGZtQPWNvRSq9XOVgOEjU1iBGRKXUZil0o2AH7Iy9Lug==", - "dev": true - } - } - }, - "jest-runner": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.0.2.tgz", - "integrity": "sha512-+D82iPZejI8t+SfduOO1deahC/QgLFf8aJBO++Znz3l2ETtOMdM7K4ATsGWzCFnTGio5yHaRifg1Su5Ybza5Nw==", - "dev": true, - "requires": { - "@jest/console": "^29.0.2", - "@jest/environment": "^29.0.2", - "@jest/test-result": "^29.0.2", - "@jest/transform": "^29.0.2", - "@jest/types": "^29.0.2", - "@types/node": "*", - "chalk": "^4.0.0", - "emittery": "^0.10.2", - "graceful-fs": "^4.2.9", - "jest-docblock": "^29.0.0", - "jest-environment-node": "^29.0.2", - "jest-haste-map": "^29.0.2", - "jest-leak-detector": "^29.0.2", - "jest-message-util": "^29.0.2", - "jest-resolve": "^29.0.2", - "jest-runtime": "^29.0.2", - "jest-util": "^29.0.2", - "jest-watcher": "^29.0.2", - "jest-worker": "^29.0.2", - "p-limit": "^3.1.0", - "source-map-support": "0.5.13" - }, - "dependencies": { - "@jest/transform": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.0.2.tgz", - "integrity": "sha512-lajVQx2AnsR+Pa17q2zR7eikz2PkPs1+g/qPbZkqQATeS/s6eT55H+yHcsLfuI/0YQ/4VSBepSu3bOX+44q0aA==", - "dev": true, - "requires": { - "@babel/core": "^7.11.6", - "@jest/types": "^29.0.2", - "@jridgewell/trace-mapping": "^0.3.15", - "babel-plugin-istanbul": "^6.1.1", - "chalk": "^4.0.0", - "convert-source-map": "^1.4.0", - "fast-json-stable-stringify": "^2.1.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.0.2", - "jest-regex-util": "^29.0.0", - "jest-util": "^29.0.2", - "micromatch": "^4.0.4", - "pirates": "^4.0.4", - "slash": "^3.0.0", - "write-file-atomic": "^4.0.1" - } - }, - "jest-haste-map": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.0.2.tgz", - "integrity": "sha512-SOorh2ysQ0fe8gsF4gaUDhoMIWAvi2hXOkwThEO48qT3JqA8GLAUieQcIvdSEd6M0scRDe1PVmKc5tXR3Z0U0A==", - "dev": true, - "requires": { - "@jest/types": "^29.0.2", - "@types/graceful-fs": "^4.1.3", - "@types/node": "*", - "anymatch": "^3.0.3", - "fb-watchman": "^2.0.0", - "fsevents": "^2.3.2", - "graceful-fs": "^4.2.9", - "jest-regex-util": "^29.0.0", - "jest-util": "^29.0.2", - "jest-worker": "^29.0.2", - "micromatch": "^4.0.4", - "walker": "^1.0.8" - } - }, - "jest-regex-util": { - "version": "29.0.0", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.0.0.tgz", - "integrity": "sha512-BV7VW7Sy0fInHWN93MMPtlClweYv2qrSCwfeFWmpribGZtQPWNvRSq9XOVgOEjU1iBGRKXUZil0o2AH7Iy9Lug==", - "dev": true - }, - "jest-worker": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.0.2.tgz", - "integrity": "sha512-EyvBlYcvd2pg28yg5A3OODQnqK9LI1kitnGUZUG5/NYIeaRgewtYBKB5wlr7oXj8zPCkzev7EmnTCsrXK7V+Xw==", - "dev": true, - "requires": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - } - }, - "p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "requires": { - "yocto-queue": "^0.1.0" - } - }, - "supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "jest-runtime": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.0.2.tgz", - "integrity": "sha512-DO6F81LX4okOgjJLkLySv10E5YcV5NHUbY1ZqAUtofxdQE+q4hjH0P2gNsY8x3z3sqgw7O/+919SU4r18Fcuig==", - "dev": true, - "requires": { - "@jest/environment": "^29.0.2", - "@jest/fake-timers": "^29.0.2", - "@jest/globals": "^29.0.2", - "@jest/source-map": "^29.0.0", - "@jest/test-result": "^29.0.2", - "@jest/transform": "^29.0.2", - "@jest/types": "^29.0.2", - "@types/node": "*", - "chalk": "^4.0.0", - "cjs-module-lexer": "^1.0.0", - "collect-v8-coverage": "^1.0.0", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.0.2", - "jest-message-util": "^29.0.2", - "jest-mock": "^29.0.2", - "jest-regex-util": "^29.0.0", - "jest-resolve": "^29.0.2", - "jest-snapshot": "^29.0.2", - "jest-util": "^29.0.2", - "slash": "^3.0.0", - "strip-bom": "^4.0.0" - }, - "dependencies": { - "@jest/transform": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.0.2.tgz", - "integrity": "sha512-lajVQx2AnsR+Pa17q2zR7eikz2PkPs1+g/qPbZkqQATeS/s6eT55H+yHcsLfuI/0YQ/4VSBepSu3bOX+44q0aA==", - "dev": true, - "requires": { - "@babel/core": "^7.11.6", - "@jest/types": "^29.0.2", - "@jridgewell/trace-mapping": "^0.3.15", - "babel-plugin-istanbul": "^6.1.1", - "chalk": "^4.0.0", - "convert-source-map": "^1.4.0", - "fast-json-stable-stringify": "^2.1.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.0.2", - "jest-regex-util": "^29.0.0", - "jest-util": "^29.0.2", - "micromatch": "^4.0.4", - "pirates": "^4.0.4", - "slash": "^3.0.0", - "write-file-atomic": "^4.0.1" - } - }, - "jest-haste-map": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.0.2.tgz", - "integrity": "sha512-SOorh2ysQ0fe8gsF4gaUDhoMIWAvi2hXOkwThEO48qT3JqA8GLAUieQcIvdSEd6M0scRDe1PVmKc5tXR3Z0U0A==", - "dev": true, - "requires": { - "@jest/types": "^29.0.2", - "@types/graceful-fs": "^4.1.3", - "@types/node": "*", - "anymatch": "^3.0.3", - "fb-watchman": "^2.0.0", - "fsevents": "^2.3.2", - "graceful-fs": "^4.2.9", - "jest-regex-util": "^29.0.0", - "jest-util": "^29.0.2", - "jest-worker": "^29.0.2", - "micromatch": "^4.0.4", - "walker": "^1.0.8" - } - }, - "jest-regex-util": { - "version": "29.0.0", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.0.0.tgz", - "integrity": "sha512-BV7VW7Sy0fInHWN93MMPtlClweYv2qrSCwfeFWmpribGZtQPWNvRSq9XOVgOEjU1iBGRKXUZil0o2AH7Iy9Lug==", - "dev": true - }, - "jest-worker": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.0.2.tgz", - "integrity": "sha512-EyvBlYcvd2pg28yg5A3OODQnqK9LI1kitnGUZUG5/NYIeaRgewtYBKB5wlr7oXj8zPCkzev7EmnTCsrXK7V+Xw==", - "dev": true, - "requires": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - } - }, - "supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "jest-snapshot": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.0.2.tgz", - "integrity": "sha512-26C4PzGKaX5gkoKg8UzYGVy2HPVcTaROSkf0gwnHu3lGeTB7bAIJBovvVPZoiJ20IximJELQs/r8WSDRCuGX2A==", - "dev": true, - "requires": { - "@babel/core": "^7.11.6", - "@babel/generator": "^7.7.2", - "@babel/plugin-syntax-jsx": "^7.7.2", - "@babel/plugin-syntax-typescript": "^7.7.2", - "@babel/traverse": "^7.7.2", - "@babel/types": "^7.3.3", - "@jest/expect-utils": "^29.0.2", - "@jest/transform": "^29.0.2", - "@jest/types": "^29.0.2", - "@types/babel__traverse": "^7.0.6", - "@types/prettier": "^2.1.5", - "babel-preset-current-node-syntax": "^1.0.0", - "chalk": "^4.0.0", - "expect": "^29.0.2", - "graceful-fs": "^4.2.9", - "jest-diff": "^29.0.2", - "jest-get-type": "^29.0.0", - "jest-haste-map": "^29.0.2", - "jest-matcher-utils": "^29.0.2", - "jest-message-util": "^29.0.2", - "jest-util": "^29.0.2", - "natural-compare": "^1.4.0", - "pretty-format": "^29.0.2", - "semver": "^7.3.5" - }, - "dependencies": { - "@jest/transform": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.0.2.tgz", - "integrity": "sha512-lajVQx2AnsR+Pa17q2zR7eikz2PkPs1+g/qPbZkqQATeS/s6eT55H+yHcsLfuI/0YQ/4VSBepSu3bOX+44q0aA==", - "dev": true, - "requires": { - "@babel/core": "^7.11.6", - "@jest/types": "^29.0.2", - "@jridgewell/trace-mapping": "^0.3.15", - "babel-plugin-istanbul": "^6.1.1", - "chalk": "^4.0.0", - "convert-source-map": "^1.4.0", - "fast-json-stable-stringify": "^2.1.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.0.2", - "jest-regex-util": "^29.0.0", - "jest-util": "^29.0.2", - "micromatch": "^4.0.4", - "pirates": "^4.0.4", - "slash": "^3.0.0", - "write-file-atomic": "^4.0.1" - } - }, - "jest-haste-map": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.0.2.tgz", - "integrity": "sha512-SOorh2ysQ0fe8gsF4gaUDhoMIWAvi2hXOkwThEO48qT3JqA8GLAUieQcIvdSEd6M0scRDe1PVmKc5tXR3Z0U0A==", - "dev": true, - "requires": { - "@jest/types": "^29.0.2", - "@types/graceful-fs": "^4.1.3", - "@types/node": "*", - "anymatch": "^3.0.3", - "fb-watchman": "^2.0.0", - "fsevents": "^2.3.2", - "graceful-fs": "^4.2.9", - "jest-regex-util": "^29.0.0", - "jest-util": "^29.0.2", - "jest-worker": "^29.0.2", - "micromatch": "^4.0.4", - "walker": "^1.0.8" - } - }, - "jest-regex-util": { - "version": "29.0.0", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.0.0.tgz", - "integrity": "sha512-BV7VW7Sy0fInHWN93MMPtlClweYv2qrSCwfeFWmpribGZtQPWNvRSq9XOVgOEjU1iBGRKXUZil0o2AH7Iy9Lug==", - "dev": true - }, - "jest-worker": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.0.2.tgz", - "integrity": "sha512-EyvBlYcvd2pg28yg5A3OODQnqK9LI1kitnGUZUG5/NYIeaRgewtYBKB5wlr7oXj8zPCkzev7EmnTCsrXK7V+Xw==", - "dev": true, - "requires": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - } - }, - "supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "jest-util": { - "version": "29.6.2", - "resolved": "https://registry.npmmirror.com/jest-util/-/jest-util-29.6.2.tgz", - "integrity": "sha512-3eX1qb6L88lJNCFlEADKOkjpXJQyZRiavX1INZ4tRnrBVr2COd3RgcTLyUiEXMNBlDU/cgYq6taUS0fExrWW4w==", - "dev": true, - "requires": { - "@jest/types": "^29.6.1", - "@types/node": "*", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "graceful-fs": "^4.2.9", - "picomatch": "^2.2.3" - } - }, - "jest-validate": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.0.2.tgz", - "integrity": "sha512-AeRKm7cEucSy7tr54r3LhiGIXYvOILUwBM1S7jQkKs6YelwAlWKsmZGVrQR7uwsd31rBTnR5NQkODi1Z+6TKIQ==", - "dev": true, - "requires": { - "@jest/types": "^29.0.2", - "camelcase": "^6.2.0", - "chalk": "^4.0.0", - "jest-get-type": "^29.0.0", - "leven": "^3.1.0", - "pretty-format": "^29.0.2" - }, - "dependencies": { - "camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "dev": true - } - } - }, - "jest-watcher": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.0.2.tgz", - "integrity": "sha512-ds2bV0oyUdYoyrUTv4Ga5uptz4cEvmmP/JzqDyzZZanvrIn8ipxg5l3SDOAIiyuAx1VdHd2FBzeXPFO5KPH8vQ==", - "dev": true, - "requires": { - "@jest/test-result": "^29.0.2", - "@jest/types": "^29.0.2", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "emittery": "^0.10.2", - "jest-util": "^29.0.2", - "string-length": "^4.0.1" - } - }, - "jest-websocket-mock": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/jest-websocket-mock/-/jest-websocket-mock-2.4.0.tgz", - "integrity": "sha512-AOwyuRw6fgROXHxMOiTDl1/T4dh3fV4jDquha5N0csS/PNp742HeTZWPAuKppVRSQ8s3fUGgJHoyZT9JDO0hMA==", - "dev": true, - "requires": { - "jest-diff": "^28.0.2", - "mock-socket": "^9.1.0" - }, - "dependencies": { - "ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true - }, - "diff-sequences": { - "version": "28.1.1", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-28.1.1.tgz", - "integrity": "sha512-FU0iFaH/E23a+a718l8Qa/19bF9p06kgE0KipMOMadwa3SjnaElKzPaUC0vnibs6/B/9ni97s61mcejk8W1fQw==", - "dev": true - }, - "jest-diff": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-28.1.3.tgz", - "integrity": "sha512-8RqP1B/OXzjjTWkqMX67iqgwBVJRgCyKD3L9nq+6ZqJMdvjE8RgHktqZ6jNrkdMT+dJuYNI3rhQpxaz7drJHfw==", - "dev": true, - "requires": { - "chalk": "^4.0.0", - "diff-sequences": "^28.1.1", - "jest-get-type": "^28.0.2", - "pretty-format": "^28.1.3" - } - }, - "jest-get-type": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-28.0.2.tgz", - "integrity": "sha512-ioj2w9/DxSYHfOm5lJKCdcAmPJzQXmbM/Url3rhlghrPvT3tt+7a/+oXc9azkKmLvoiXjtV83bEWqi+vs5nlPA==", - "dev": true - }, - "pretty-format": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-28.1.3.tgz", - "integrity": "sha512-8gFb/To0OmxHR9+ZTb14Df2vNxdGCX8g1xWGUTqUw5TiZvcQf5sHKObd5UcPyLLyowNwDAMTF3XWOG1B6mxl1Q==", - "dev": true, - "requires": { - "@jest/schemas": "^28.1.3", - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - } - } - } - }, - "jose": { - "version": "4.14.4", - "resolved": "https://registry.npmjs.org/jose/-/jose-4.14.4.tgz", - "integrity": "sha512-j8GhLiKmUAh+dsFXlX1aJCbt5KMibuKb+d7j1JaOJG6s2UjX1PQlW+OKB/sD4a/5ZYF4RcmYmLSndOoU3Lt/3g==", - "dev": true - }, - "js-md4": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/js-md4/-/js-md4-0.3.2.tgz", - "integrity": "sha512-/GDnfQYsltsjRswQhN9fhv3EMw2sCpUdrdxyWDOUK7eyD++r3gRhzgiQgc/x4MAv2i1iuQ4lxO5mvqM3vj4bwA==", - "dev": true - }, - "js-sha512": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/js-sha512/-/js-sha512-0.8.0.tgz", - "integrity": "sha512-PWsmefG6Jkodqt+ePTvBZCSMFgN7Clckjd0O7su3I0+BW2QWUTJNzjktHsztGLhncP2h8mcF9V9Y2Ha59pAViQ==", - "dev": true - }, - "js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, - "js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "requires": { - "argparse": "^2.0.1" - } - }, - "jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==", - "dev": true - }, - "jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "dev": true - }, - "json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true - }, - "json-schema": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", - "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", - "dev": true - }, - "json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", - "dev": true - }, - "json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", - "dev": true - }, - "json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "dev": true - }, - "jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.6", - "universalify": "^2.0.0" - } - }, - "jsprim": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-2.0.2.tgz", - "integrity": "sha512-gqXddjPqQ6G40VdnI6T6yObEC+pDNvyP95wdQhkWkg7crHH3km5qP1FsOXEkzEQwnz6gz5qGTn1c2Y52wP3OyQ==", - "dev": true, - "requires": { - "assert-plus": "1.0.0", - "extsprintf": "1.3.0", - "json-schema": "0.4.0", - "verror": "1.10.0" - } - }, - "kleur": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", - "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", - "dev": true - }, - "leven": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", - "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", - "dev": true - }, - "levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "requires": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - } - }, - "lines-and-columns": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "dev": true - }, - "liquid-json": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/liquid-json/-/liquid-json-0.3.1.tgz", - "integrity": "sha512-wUayTU8MS827Dam6MxgD72Ui+KOSF+u/eIqpatOtjnvgJ0+mnDq33uC2M7J0tPK+upe/DpUAuK4JUU89iBoNKQ==", - "dev": true - }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "requires": { - "p-locate": "^4.1.0" - } - }, - "lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true - }, - "lodash.get": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", - "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==" - }, - "lodash.isequal": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", - "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==" - }, - "lodash.memoize": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", - "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", - "dev": true - }, - "lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true - }, - "lodash.mergewith": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz", - "integrity": "sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ==" - }, - "lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "requires": { - "yallist": "^4.0.0" - } - }, - "make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dev": true, - "requires": { - "semver": "^6.0.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } - } - }, - "make-error": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true - }, - "makeerror": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", - "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", - "dev": true, - "requires": { - "tmpl": "1.0.5" - } - }, - "media-typer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==" - }, - "merge-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" - }, - "merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true - }, - "merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true - }, - "methods": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" - }, - "micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", - "dev": true, - "requires": { - "braces": "^3.0.2", - "picomatch": "^2.3.1" - } - }, - "mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" - }, - "mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" - }, - "mime-format": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/mime-format/-/mime-format-2.0.1.tgz", - "integrity": "sha512-XxU3ngPbEnrYnNbIX+lYSaYg0M01v6p2ntd2YaFksTu0vayaw5OJvbdRyWs07EYRlLED5qadUZ+xo+XhOvFhwg==", - "dev": true, - "requires": { - "charset": "^1.0.0" - } - }, - "mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "requires": { - "mime-db": "1.52.0" - } - }, - "mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true - }, - "mimic-response": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz", - "integrity": "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==", - "dev": true - }, - "minimalistic-assert": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", - "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", - "dev": true - }, - "minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", - "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", - "dev": true - }, - "mkdirp": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-3.0.1.tgz", - "integrity": "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==", - "dev": true - }, - "mkdirp-classic": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", - "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", - "dev": true - }, - "mock-socket": { - "version": "9.1.5", - "resolved": "https://registry.npmjs.org/mock-socket/-/mock-socket-9.1.5.tgz", - "integrity": "sha512-3DeNIcsQixWHHKk6NdoBhWI4t1VMj5/HzfnI1rE/pLl5qKx7+gd4DNA07ehTaZ6MoUU053si6Hd+YtiM/tQZfg==", - "dev": true - }, - "morgan": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.10.0.tgz", - "integrity": "sha512-AbegBVI4sh6El+1gNwvD5YIck7nSA36weD7xvIxG4in80j/UoK8AEGaWnnz8v1GxonMCltmlNs5ZKbGvl9b1XQ==", - "requires": { - "basic-auth": "~2.0.1", - "debug": "2.6.9", - "depd": "~2.0.0", - "on-finished": "~2.3.0", - "on-headers": "~1.0.2" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - } - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, - "multer": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/multer/-/multer-2.1.1.tgz", - "integrity": "sha512-mo+QTzKlx8R7E5ylSXxWzGoXoZbOsRMpyitcht8By2KHvMbf3tjwosZ/Mu/XYU6UuJ3VZnODIrak5ZrPiPyB6A==", - "requires": { - "append-field": "^1.0.0", - "busboy": "^1.6.0", - "concat-stream": "^2.0.0", - "type-is": "^1.6.18" - } - }, - "multistream": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/multistream/-/multistream-4.1.0.tgz", - "integrity": "sha512-J1XDiAmmNpRCBfIWJv+n0ymC4ABcf/Pl+5YvC5B/D2f/2+8PtHvCNxMPKiQcZyi922Hq69J2YOpb1pTywfifyw==", - "dev": true, - "requires": { - "once": "^1.4.0", - "readable-stream": "^3.6.0" - }, - "dependencies": { - "readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "dev": true, - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - } - } - }, - "napi-build-utils": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz", - "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==", - "dev": true - }, - "natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", - "dev": true - }, - "negotiator": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", - "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==" - }, - "neo-async": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", - "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", - "dev": true - }, - "newman": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/newman/-/newman-6.0.0.tgz", - "integrity": "sha512-QaANQC5b6ga348MezIVRI9ZmMs+cg3MdYIp0tSEauH2tmWOAR9+cghNsFJNjU9JPui3jJp1ALC7pQq6g3Jqpxw==", - "dev": true, - "requires": { - "@postman/tough-cookie": "4.1.3-postman.1", - "async": "3.2.4", - "chardet": "1.6.0", - "cli-progress": "3.12.0", - "cli-table3": "0.6.3", - "colors": "1.4.0", - "commander": "11.0.0", - "csv-parse": "4.16.3", - "filesize": "10.0.12", - "liquid-json": "0.3.1", - "lodash": "4.17.21", - "mkdirp": "3.0.1", - "postman-collection": "4.2.1", - "postman-collection-transformer": "4.1.7", - "postman-request": "2.88.1-postman.33", - "postman-runtime": "7.33.0", - "pretty-ms": "7.0.1", - "semver": "7.5.4", - "serialised-error": "1.1.3", - "word-wrap": "1.2.5", - "xmlbuilder": "15.1.1" - } - }, - "node-abi": { - "version": "2.30.1", - "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.30.1.tgz", - "integrity": "sha512-/2D0wOQPgaUWzVSVgRMx+trKJRC2UG4SUc4oCJoXx9Uxjtp0Vy3/kt7zcbxHF8+Z/pK3UloLWzBISg72brfy1w==", - "dev": true, - "requires": { - "semver": "^5.4.1" - }, - "dependencies": { - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - } - } - }, - "node-fetch": { - "version": "2.6.7", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", - "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", - "dev": true, - "requires": { - "whatwg-url": "^5.0.0" - } - }, - "node-int64": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", - "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", - "dev": true - }, - "node-oauth1": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/node-oauth1/-/node-oauth1-1.3.0.tgz", - "integrity": "sha512-0yggixNfrA1KcBwvh/Hy2xAS1Wfs9dcg6TdFf2zN7gilcAigMdrtZ4ybrBSXBgLvGDw9V1p2MRnGBMq7XjTWLg==", - "dev": true - }, - "node-releases": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.5.tgz", - "integrity": "sha512-U9h1NLROZTq9uE1SNffn6WuPDg8icmi3ns4rEl/oTfIle4iLjTliCzgTsbaIFMq/Xn078/lfY/BL0GWZ+psK4Q==", - "dev": true - }, - "normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true - }, - "npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "dev": true, - "requires": { - "path-key": "^3.0.0" - } - }, - "npmlog": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", - "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", - "dev": true, - "requires": { - "are-we-there-yet": "~1.1.2", - "console-control-strings": "~1.1.0", - "gauge": "~2.7.3", - "set-blocking": "~2.0.0" - } - }, - "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==", - "dev": true - }, - "oauth-sign": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", - "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", - "dev": true - }, - "object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==" - }, - "object-hash": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-1.3.1.tgz", - "integrity": "sha512-OSuu/pU4ENM9kmREg0BdNrUDIl1heYa4mBZacJc+vVWz4GtAwu7jO8s4AIt2aGRUTqxykpWzI3Oqnsm13tTMDA==", - "dev": true - }, - "object-inspect": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", - "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==" - }, - "on-finished": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", - "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", - "requires": { - "ee-first": "1.1.1" - } - }, - "on-headers": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", - "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==" - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "requires": { - "wrappy": "1" - } - }, - "onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dev": true, - "requires": { - "mimic-fn": "^2.1.0" - } - }, - "openapi-types": { - "version": "12.1.3", - "resolved": "https://registry.npmjs.org/openapi-types/-/openapi-types-12.1.3.tgz", - "integrity": "sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw==", - "peer": true - }, - "optionator": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", - "dev": true, - "requires": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.3" - } - }, - "p-is-promise": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-3.0.0.tgz", - "integrity": "sha512-Wo8VsW4IRQSKVXsJCn7TomUaVtyfjVDn3nUP7kE967BQk0CwFpdbZs0X0uk5sW9mkBa9eNM7hCMaG93WUAwxYQ==", - "dev": true - }, - "p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "requires": { - "p-limit": "^2.2.0" - } - }, - "p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true - }, - "parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "requires": { - "callsites": "^3.0.0" - } - }, - "parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - } - }, - "parse-ms": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/parse-ms/-/parse-ms-2.1.0.tgz", - "integrity": "sha512-kHt7kzLoS9VBZfUsiKjv43mr91ea+U05EyKkEtqp7vNbHxmaVuEqN7XxeEVnGrMtYOAxGrDElSi96K7EgO1zCA==", - "dev": true - }, - "parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" - }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==" - }, - "path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true - }, - "path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true - }, - "path-to-regexp": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" - }, - "path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true - }, - "performance-now": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==", - "dev": true - }, - "picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", - "dev": true - }, - "picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true - }, - "pirates": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz", - "integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==", - "dev": true - }, - "pkg": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/pkg/-/pkg-5.8.0.tgz", - "integrity": "sha512-8h9PUDYFi+LOMLbIyGRdP21g08mAtHidSpofSrf8LWhxUWGHymaRzcopEGiynB5EhQmZUKM6PQ9kCImV2TpdjQ==", - "dev": true, - "requires": { - "@babel/generator": "7.18.2", - "@babel/parser": "7.18.4", - "@babel/types": "7.18.4", - "chalk": "^4.1.2", - "fs-extra": "^9.1.0", - "globby": "^11.1.0", - "into-stream": "^6.0.0", - "is-core-module": "2.9.0", - "minimist": "^1.2.6", - "multistream": "^4.1.0", - "pkg-fetch": "3.4.2", - "prebuild-install": "6.1.4", - "resolve": "^1.22.0", - "stream-meter": "^1.0.4" - } - }, - "pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "dev": true, - "requires": { - "find-up": "^4.0.0" - } - }, - "pkg-fetch": { - "version": "3.4.2", - "resolved": "https://registry.npmjs.org/pkg-fetch/-/pkg-fetch-3.4.2.tgz", - "integrity": "sha512-0+uijmzYcnhC0hStDjm/cl2VYdrmVVBpe7Q8k9YBojxmR5tG8mvR9/nooQq3QSXiQqORDVOTY3XqMEqJVIzkHA==", - "dev": true, - "requires": { - "chalk": "^4.1.2", - "fs-extra": "^9.1.0", - "https-proxy-agent": "^5.0.0", - "node-fetch": "^2.6.6", - "progress": "^2.0.3", - "semver": "^7.3.5", - "tar-fs": "^2.1.1", - "yargs": "^16.2.0" - }, - "dependencies": { - "yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", - "dev": true, - "requires": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" - } - }, - "yargs-parser": { - "version": "20.2.9", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", - "dev": true - } - } - }, - "postman-collection": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/postman-collection/-/postman-collection-4.2.1.tgz", - "integrity": "sha512-DFLt3/yu8+ldtOTIzmBUctoupKJBOVK4NZO0t68K2lIir9smQg7OdQTBjOXYy+PDh7u0pSDvD66tm93eBHEPHA==", - "dev": true, - "requires": { - "@faker-js/faker": "5.5.3", - "file-type": "3.9.0", - "http-reasons": "0.1.0", - "iconv-lite": "0.6.3", - "liquid-json": "0.3.1", - "lodash": "4.17.21", - "mime-format": "2.0.1", - "mime-types": "2.1.35", - "postman-url-encoder": "3.0.5", - "semver": "7.5.4", - "uuid": "8.3.2" - }, - "dependencies": { - "iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "dev": true, - "requires": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - } - }, - "uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "dev": true - } - } - }, - "postman-collection-transformer": { - "version": "4.1.7", - "resolved": "https://registry.npmjs.org/postman-collection-transformer/-/postman-collection-transformer-4.1.7.tgz", - "integrity": "sha512-SxJkm/LnlFZs2splUBnS4jQFicgBptghpm4voHtNnaum3Ad64E2MHLV4fJhv58dVUmFwdSwdQUN3m2q0iLecnQ==", - "dev": true, - "requires": { - "commander": "8.3.0", - "inherits": "2.0.4", - "lodash": "4.17.21", - "semver": "7.5.4", - "strip-json-comments": "3.1.1" - }, - "dependencies": { - "commander": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", - "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", - "dev": true - } - } - }, - "postman-request": { - "version": "2.88.1-postman.33", - "resolved": "https://registry.npmjs.org/postman-request/-/postman-request-2.88.1-postman.33.tgz", - "integrity": "sha512-uL9sCML4gPH6Z4hreDWbeinKU0p0Ke261nU7OvII95NU22HN6Dk7T/SaVPaj6T4TsQqGKIFw6/woLZnH7ugFNA==", - "dev": true, - "requires": { - "@postman/form-data": "~3.1.1", - "@postman/tough-cookie": "~4.1.3-postman.1", - "@postman/tunnel-agent": "^0.6.3", - "aws-sign2": "~0.7.0", - "aws4": "^1.12.0", - "brotli": "^1.3.3", - "caseless": "~0.12.0", - "combined-stream": "~1.0.6", - "extend": "~3.0.2", - "forever-agent": "~0.6.1", - "har-validator": "~5.1.3", - "http-signature": "~1.3.1", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "^2.1.35", - "oauth-sign": "~0.9.0", - "performance-now": "^2.1.0", - "qs": "~6.5.3", - "safe-buffer": "^5.1.2", - "stream-length": "^1.0.2", - "uuid": "^8.3.2" - }, - "dependencies": { - "qs": { - "version": "6.5.3", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", - "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==", - "dev": true - }, - "uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "dev": true - } - } - }, - "postman-runtime": { - "version": "7.33.0", - "resolved": "https://registry.npmjs.org/postman-runtime/-/postman-runtime-7.33.0.tgz", - "integrity": "sha512-cYCb+5Y12FwZU/T3gOj2SKiOz38pisVLc0tdppb+ZlG7iqn5aLgxghJwhjG62pZCV6uixKiQX1hNdLSk9a9Xtw==", - "dev": true, - "requires": { - "@postman/tough-cookie": "4.1.3-postman.1", - "async": "3.2.4", - "aws4": "1.12.0", - "handlebars": "4.7.8", - "httpntlm": "1.8.13", - "jose": "4.14.4", - "js-sha512": "0.8.0", - "lodash": "4.17.21", - "mime-types": "2.1.35", - "node-oauth1": "1.3.0", - "performance-now": "2.1.0", - "postman-collection": "4.2.0", - "postman-request": "2.88.1-postman.33", - "postman-sandbox": "4.2.7", - "postman-url-encoder": "3.0.5", - "serialised-error": "1.1.3", - "strip-json-comments": "3.1.1", - "uuid": "8.3.2" - }, - "dependencies": { - "iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "dev": true, - "requires": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - } - }, - "postman-collection": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/postman-collection/-/postman-collection-4.2.0.tgz", - "integrity": "sha512-tvOLgN1h6Kab6dt43PmBoV5kYO/YUta3x0C2QqfmbzmHZe47VTpZ/+gIkGlbNhjKNPUUub5X6ehxYKoaTYdy1w==", - "dev": true, - "requires": { - "@faker-js/faker": "5.5.3", - "file-type": "3.9.0", - "http-reasons": "0.1.0", - "iconv-lite": "0.6.3", - "liquid-json": "0.3.1", - "lodash": "4.17.21", - "mime-format": "2.0.1", - "mime-types": "2.1.35", - "postman-url-encoder": "3.0.5", - "semver": "7.5.4", - "uuid": "8.3.2" - } - }, - "uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "dev": true - } - } - }, - "postman-sandbox": { - "version": "4.2.7", - "resolved": "https://registry.npmjs.org/postman-sandbox/-/postman-sandbox-4.2.7.tgz", - "integrity": "sha512-/EcCrKnb/o+9iLS4u+H76E0kBomJFjPptVjoDiq1uZ7Es/4aTv0MAX+0aoDxdDO+0h9sl8vy65uKQwyjN7AOaw==", - "dev": true, - "requires": { - "lodash": "4.17.21", - "postman-collection": "4.2.0", - "teleport-javascript": "1.0.0", - "uvm": "2.1.1" - }, - "dependencies": { - "iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "dev": true, - "requires": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - } - }, - "postman-collection": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/postman-collection/-/postman-collection-4.2.0.tgz", - "integrity": "sha512-tvOLgN1h6Kab6dt43PmBoV5kYO/YUta3x0C2QqfmbzmHZe47VTpZ/+gIkGlbNhjKNPUUub5X6ehxYKoaTYdy1w==", - "dev": true, - "requires": { - "@faker-js/faker": "5.5.3", - "file-type": "3.9.0", - "http-reasons": "0.1.0", - "iconv-lite": "0.6.3", - "liquid-json": "0.3.1", - "lodash": "4.17.21", - "mime-format": "2.0.1", - "mime-types": "2.1.35", - "postman-url-encoder": "3.0.5", - "semver": "7.5.4", - "uuid": "8.3.2" - } - }, - "uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "dev": true - } - } - }, - "postman-url-encoder": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/postman-url-encoder/-/postman-url-encoder-3.0.5.tgz", - "integrity": "sha512-jOrdVvzUXBC7C+9gkIkpDJ3HIxOHTIqjpQ4C1EMt1ZGeMvSEpbFCKq23DEfgsj46vMnDgyQf+1ZLp2Wm+bKSsA==", - "dev": true, - "requires": { - "punycode": "^2.1.1" - } - }, - "prebuild-install": { - "version": "6.1.4", - "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-6.1.4.tgz", - "integrity": "sha512-Z4vpywnK1lBg+zdPCVCsKq0xO66eEV9rWo2zrROGGiRS4JtueBOdlB1FnY8lcy7JsUud/Q3ijUxyWN26Ika0vQ==", - "dev": true, - "requires": { - "detect-libc": "^1.0.3", - "expand-template": "^2.0.3", - "github-from-package": "0.0.0", - "minimist": "^1.2.3", - "mkdirp-classic": "^0.5.3", - "napi-build-utils": "^1.0.1", - "node-abi": "^2.21.0", - "npmlog": "^4.0.1", - "pump": "^3.0.0", - "rc": "^1.2.7", - "simple-get": "^3.0.3", - "tar-fs": "^2.0.0", - "tunnel-agent": "^0.6.0" - } - }, - "prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true - }, - "pretty-format": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.0.2.tgz", - "integrity": "sha512-wp3CdtUa3cSJVFn3Miu5a1+pxc1iPIQTenOAn+x5erXeN1+ryTcLesV5pbK/rlW5EKwp27x38MoYfNGaNXDDhg==", - "dev": true, - "requires": { - "@jest/schemas": "^29.0.0", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - }, - "dependencies": { - "@jest/schemas": { - "version": "29.0.0", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.0.0.tgz", - "integrity": "sha512-3Ab5HgYIIAnS0HjqJHQYZS+zXc4tUmTmBH3z83ajI6afXp8X3ZtdLX+nXx+I7LNkJD7uN9LAVhgnjDgZa2z0kA==", - "dev": true, - "requires": { - "@sinclair/typebox": "^0.24.1" - } - }, - "ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true - } - } - }, - "pretty-ms": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/pretty-ms/-/pretty-ms-7.0.1.tgz", - "integrity": "sha512-973driJZvxiGOQ5ONsFhOF/DtzPMOMtgC11kCpUrPGMTgqp2q/1gwzCquocrN33is0VZ5GFHXZYMM9l6h67v2Q==", - "dev": true, - "requires": { - "parse-ms": "^2.1.0" - } - }, - "process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", - "dev": true - }, - "progress": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", - "dev": true - }, - "prompts": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", - "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", - "dev": true, - "requires": { - "kleur": "^3.0.3", - "sisteransi": "^1.0.5" - } - }, - "proxy-addr": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", - "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", - "requires": { - "forwarded": "0.2.0", - "ipaddr.js": "1.9.1" - } - }, - "psl": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", - "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==", - "dev": true - }, - "pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dev": true, - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "dev": true - }, - "qs": { - "version": "6.10.3", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.3.tgz", - "integrity": "sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ==", - "requires": { - "side-channel": "^1.0.4" - } - }, - "querystringify": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", - "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", - "dev": true - }, - "queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true - }, - "range-parser": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" - }, - "raw-body": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", - "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", - "requires": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - } - }, - "rc": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", - "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", - "dev": true, - "requires": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - }, - "dependencies": { - "strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", - "dev": true - } - } - }, - "react-is": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", - "dev": true - }, - "readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "regexpp": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", - "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", - "dev": true - }, - "require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "dev": true - }, - "requires-port": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", - "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", - "dev": true - }, - "resolve": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", - "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", - "dev": true, - "requires": { - "is-core-module": "^2.8.1", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - } - }, - "resolve-cwd": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", - "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", - "dev": true, - "requires": { - "resolve-from": "^5.0.0" - }, - "dependencies": { - "resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true - } - } - }, - "resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true - }, - "resolve.exports": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-1.1.0.tgz", - "integrity": "sha512-J1l+Zxxp4XK3LUDZ9m60LRJF/mAe4z6a4xyabPHk7pvK5t35dACV32iIjJDFeWZFfZlO29w6SZ67knR0tHzJtQ==", - "dev": true - }, - "reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true - }, - "rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - }, - "run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "requires": { - "queue-microtask": "^1.2.2" - } - }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - }, - "safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" - }, - "semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - }, - "send": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", - "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", - "requires": { - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "mime": "1.6.0", - "ms": "2.1.3", - "on-finished": "2.4.1", - "range-parser": "~1.2.1", - "statuses": "2.0.1" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - }, - "dependencies": { - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - } - } - }, - "ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" - }, - "on-finished": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", - "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", - "requires": { - "ee-first": "1.1.1" - } - } - } - }, - "serialised-error": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/serialised-error/-/serialised-error-1.1.3.tgz", - "integrity": "sha512-vybp3GItaR1ZtO2nxZZo8eOo7fnVaNtP3XE2vJKgzkKR2bagCkdJ1EpYYhEMd3qu/80DwQk9KjsNSxE3fXWq0g==", - "dev": true, - "requires": { - "object-hash": "^1.1.2", - "stack-trace": "0.0.9", - "uuid": "^3.0.0" - }, - "dependencies": { - "uuid": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", - "dev": true - } - } - }, - "serve-static": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", - "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", - "requires": { - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "parseurl": "~1.3.3", - "send": "0.18.0" - } - }, - "set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", - "dev": true - }, - "setprototypeof": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" - }, - "shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "requires": { - "shebang-regex": "^3.0.0" - } - }, - "shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true - }, - "side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", - "requires": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" - } - }, - "signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true - }, - "simple-concat": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", - "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", - "dev": true - }, - "simple-get": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.1.tgz", - "integrity": "sha512-CQ5LTKGfCpvE1K0n2us+kuMPbk/q0EKl82s4aheV9oXjFEz6W/Y7oQFVJuU6QG77hRT4Ghb5RURteF5vnWjupA==", - "dev": true, - "requires": { - "decompress-response": "^4.2.0", - "once": "^1.3.1", - "simple-concat": "^1.0.0" - } - }, - "sisteransi": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", - "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", - "dev": true - }, - "slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - }, - "source-map-support": { - "version": "0.5.13", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", - "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", - "dev": true, - "requires": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", - "dev": true - }, - "sshpk": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.18.0.tgz", - "integrity": "sha512-2p2KJZTSqQ/I3+HX42EpYOa2l3f8Erv8MWKsy2I9uf4wA7yFIkXRffYdsx86y6z4vHtV8u7g+pPlr8/4ouAxsQ==", - "dev": true, - "requires": { - "asn1": "~0.2.3", - "assert-plus": "^1.0.0", - "bcrypt-pbkdf": "^1.0.0", - "dashdash": "^1.12.0", - "ecc-jsbn": "~0.1.1", - "getpass": "^0.1.1", - "jsbn": "~0.1.0", - "safer-buffer": "^2.0.2", - "tweetnacl": "~0.14.0" - } - }, - "stack-trace": { - "version": "0.0.9", - "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.9.tgz", - "integrity": "sha512-vjUc6sfgtgY0dxCdnc40mK6Oftjo9+2K8H/NG81TMhgL392FtiPA9tn9RLyTxXmTLPJPjF3VyzFp6bsWFLisMQ==", - "dev": true - }, - "stack-utils": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.5.tgz", - "integrity": "sha512-xrQcmYhOsn/1kX+Vraq+7j4oE2j/6BFscZ0etmYg81xuM8Gq0022Pxb8+IqgOFUIaxHs0KaSb7T1+OegiNrNFA==", - "dev": true, - "requires": { - "escape-string-regexp": "^2.0.0" - }, - "dependencies": { - "escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "dev": true - } - } - }, - "statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==" - }, - "stream-length": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/stream-length/-/stream-length-1.0.2.tgz", - "integrity": "sha512-aI+qKFiwoDV4rsXiS7WRoCt+v2RX1nUj17+KJC5r2gfh5xoSJIfP6Y3Do/HtvesFcTSWthIuJ3l1cvKQY/+nZg==", - "dev": true, - "requires": { - "bluebird": "^2.6.2" - } - }, - "stream-meter": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/stream-meter/-/stream-meter-1.0.4.tgz", - "integrity": "sha1-Uq+Vql6nYKJJFxZwTb/5D3Ov3R0=", - "dev": true, - "requires": { - "readable-stream": "^2.1.4" - } - }, - "streamsearch": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", - "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==" - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "requires": { - "safe-buffer": "~5.1.0" - } - }, - "string-length": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", - "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", - "dev": true, - "requires": { - "char-regex": "^1.0.2", - "strip-ansi": "^6.0.0" - } - }, - "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==", - "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - } - }, - "strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.1" - } - }, - "strip-bom": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", - "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", - "dev": true - }, - "strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", - "dev": true - }, - "strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - }, - "supports-hyperlinks": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.3.0.tgz", - "integrity": "sha512-RpsAZlpWcDwOPQA22aCH4J0t7L8JmAvsCxfOSEwm7cQs3LshN36QaTkwd70DnBOXDWGssw2eUoc8CaRWT0XunA==", - "dev": true, - "requires": { - "has-flag": "^4.0.0", - "supports-color": "^7.0.0" - } - }, - "supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true - }, - "swagger-jsdoc": { - "version": "6.2.8", - "resolved": "https://registry.npmjs.org/swagger-jsdoc/-/swagger-jsdoc-6.2.8.tgz", - "integrity": "sha512-VPvil1+JRpmJ55CgAtn8DIcpBs0bL5L3q5bVQvF4tAW/k/9JYSj7dCpaYCAv5rufe0vcCbBRQXGvzpkWjvLklQ==", - "requires": { - "commander": "6.2.0", - "doctrine": "3.0.0", - "glob": "7.1.6", - "lodash.mergewith": "^4.6.2", - "swagger-parser": "^10.0.3", - "yaml": "2.0.0-1" - }, - "dependencies": { - "commander": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.0.tgz", - "integrity": "sha512-zP4jEKbe8SHzKJYQmq8Y9gYjtO/POJLgIdKgV7B9qNmABVFVc+ctqSX6iXh4mCpJfRBOabiZ2YKPg8ciDw6C+Q==" - }, - "glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - } - } - }, - "swagger-parser": { - "version": "10.0.3", - "resolved": "https://registry.npmjs.org/swagger-parser/-/swagger-parser-10.0.3.tgz", - "integrity": "sha512-nF7oMeL4KypldrQhac8RyHerJeGPD1p2xDh900GPvc+Nk7nWP6jX2FcC7WmkinMoAmoO774+AFXcWsW8gMWEIg==", - "requires": { - "@apidevtools/swagger-parser": "10.0.3" - } - }, - "swagger-ui-dist": { - "version": "5.32.0", - "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-5.32.0.tgz", - "integrity": "sha512-nKZB0OuDvacB0s/lC2gbge+RigYvGRGpLLMWMFxaTUwfM+CfndVk9Th2IaTinqXiz6Mn26GK2zriCpv6/+5m3Q==", - "requires": { - "@scarf/scarf": "=1.4.0" - } - }, - "swagger-ui-express": { - "version": "4.6.3", - "resolved": "https://registry.npmjs.org/swagger-ui-express/-/swagger-ui-express-4.6.3.tgz", - "integrity": "sha512-CDje4PndhTD2HkgyKH3pab+LKspDeB/NhPN2OF1j+piYIamQqBYwAXWESOT1Yju2xFg51bRW9sUng2WxDjzArw==", - "requires": { - "swagger-ui-dist": ">=4.11.0" - } - }, - "tar-fs": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", - "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", - "dev": true, - "requires": { - "chownr": "^1.1.1", - "mkdirp-classic": "^0.5.2", - "pump": "^3.0.0", - "tar-stream": "^2.1.4" - } - }, - "tar-stream": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", - "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", - "dev": true, - "requires": { - "bl": "^4.0.3", - "end-of-stream": "^1.4.1", - "fs-constants": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.1.1" - }, - "dependencies": { - "readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "dev": true, - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - } - } - }, - "teleport-javascript": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/teleport-javascript/-/teleport-javascript-1.0.0.tgz", - "integrity": "sha512-j1llvWVFyEn/6XIFDfX5LAU43DXe0GCt3NfXDwJ8XpRRMkS+i50SAkonAONBy+vxwPFBd50MFU8a2uj8R/ccLg==", - "dev": true - }, - "terminal-link": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-2.1.1.tgz", - "integrity": "sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==", - "dev": true, - "requires": { - "ansi-escapes": "^4.2.1", - "supports-hyperlinks": "^2.0.0" - } - }, - "test-exclude": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", - "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", - "dev": true, - "requires": { - "@istanbuljs/schema": "^0.1.2", - "glob": "^7.1.4", - "minimatch": "^3.0.4" - } - }, - "text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", - "dev": true - }, - "tmpl": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", - "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", - "dev": true - }, - "to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", - "dev": true - }, - "to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "requires": { - "is-number": "^7.0.0" - } - }, - "toidentifier": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", - "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==" - }, - "tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", - "dev": true - }, - "ts-jest": { - "version": "29.1.1", - "resolved": "https://registry.npmmirror.com/ts-jest/-/ts-jest-29.1.1.tgz", - "integrity": "sha512-D6xjnnbP17cC85nliwGiL+tpoKN0StpgE0TeOjXQTU6MVCfsB4v7aW05CgQ/1OywGb0x/oy9hHFnN+sczTiRaA==", - "dev": true, - "requires": { - "bs-logger": "0.x", - "fast-json-stable-stringify": "2.x", - "jest-util": "^29.0.0", - "json5": "^2.2.3", - "lodash.memoize": "4.x", - "make-error": "1.x", - "semver": "^7.5.3", - "yargs-parser": "^21.0.1" - } - }, - "ts-node": { - "version": "10.9.1", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", - "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", - "dev": true, - "requires": { - "@cspotcode/source-map-support": "^0.8.0", - "@tsconfig/node10": "^1.0.7", - "@tsconfig/node12": "^1.0.7", - "@tsconfig/node14": "^1.0.0", - "@tsconfig/node16": "^1.0.2", - "acorn": "^8.4.1", - "acorn-walk": "^8.1.1", - "arg": "^4.1.0", - "create-require": "^1.1.0", - "diff": "^4.0.1", - "make-error": "^1.1.1", - "v8-compile-cache-lib": "^3.0.1", - "yn": "3.1.1" - } - }, - "tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - }, - "tsutils": { - "version": "3.21.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", - "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", - "dev": true, - "requires": { - "tslib": "^1.8.1" - } - }, - "tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", - "dev": true, - "requires": { - "safe-buffer": "^5.0.1" - } - }, - "tweetnacl": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==", - "dev": true - }, - "type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "requires": { - "prelude-ls": "^1.2.1" - } - }, - "type-detect": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", - "dev": true - }, - "type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true - }, - "type-is": { - "version": "1.6.18", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", - "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", - "requires": { - "media-typer": "0.3.0", - "mime-types": "~2.1.24" - } - }, - "typedarray": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==" - }, - "typescript": { - "version": "4.8.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.2.tgz", - "integrity": "sha512-C0I1UsrrDHo2fYI5oaCGbSejwX4ch+9Y5jTQELvovfmFkK3HHSZJB8MSJcWLmCUBzQBchCrZ9rMRV6GuNrvGtw==", - "dev": true - }, - "uglify-js": { - "version": "3.17.4", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.4.tgz", - "integrity": "sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==", - "dev": true, - "optional": true - }, - "underscore": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.12.1.tgz", - "integrity": "sha512-hEQt0+ZLDVUMhebKxL4x1BTtDY7bavVofhZ9KZ4aI26X9SRaE+Y3m83XUL1UP2jn8ynjndwCCpEHdUG+9pP1Tw==", - "dev": true - }, - "universalify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", - "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", - "dev": true - }, - "unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" - }, - "uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "requires": { - "punycode": "^2.1.0" - } - }, - "url-parse": { - "version": "1.5.10", - "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", - "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", - "dev": true, - "requires": { - "querystringify": "^2.1.1", - "requires-port": "^1.0.0" - } - }, - "util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" - }, - "utils-merge": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" - }, - "uuid": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz", - "integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==" - }, - "uvm": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/uvm/-/uvm-2.1.1.tgz", - "integrity": "sha512-BZ5w8adTpNNr+zczOBRpaX/hH8UPKAf7fmCnidrcsqt3bn8KT9bDIfuS7hgRU9RXgiN01su2pwysBONY6w8W5w==", - "dev": true, - "requires": { - "flatted": "3.2.6" - } - }, - "v8-compile-cache-lib": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", - "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", - "dev": true - }, - "v8-to-istanbul": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.0.1.tgz", - "integrity": "sha512-74Y4LqY74kLE6IFyIjPtkSTWzUZmj8tdHT9Ii/26dvQ6K9Dl2NbEfj0XgU2sHCtKgt5VupqhlO/5aWuqS+IY1w==", - "dev": true, - "requires": { - "@jridgewell/trace-mapping": "^0.3.12", - "@types/istanbul-lib-coverage": "^2.0.1", - "convert-source-map": "^1.6.0" - } - }, - "validator": { - "version": "13.15.26", - "resolved": "https://registry.npmjs.org/validator/-/validator-13.15.26.tgz", - "integrity": "sha512-spH26xU080ydGggxRyR1Yhcbgx+j3y5jbNXk/8L+iRvdIEQ4uTRH2Sgf2dokud6Q4oAtsbNvJ1Ft+9xmm6IZcA==" - }, - "vary": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" - }, - "verror": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", - "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==", - "dev": true, - "requires": { - "assert-plus": "^1.0.0", - "core-util-is": "1.0.2", - "extsprintf": "^1.2.0" - }, - "dependencies": { - "core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==", - "dev": true - } - } - }, - "walker": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", - "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", - "dev": true, - "requires": { - "makeerror": "1.0.12" - } - }, - "webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", - "dev": true - }, - "whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", - "dev": true, - "requires": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - }, - "which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - }, - "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==", - "dev": true, - "requires": { - "string-width": "^1.0.2 || 2 || 3 || 4" - } - }, - "word-wrap": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", - "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", - "dev": true - }, - "wordwrap": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", - "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", - "dev": true - }, - "wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "requires": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - } - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" - }, - "write-file-atomic": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.1.tgz", - "integrity": "sha512-nSKUxgAbyioruk6hU87QzVbY279oYT6uiwgDoujth2ju4mJ+TZau7SQBhtbTmUyuNYTuXnSyRn66FV0+eCgcrQ==", - "dev": true, - "requires": { - "imurmurhash": "^0.1.4", - "signal-exit": "^3.0.7" - } - }, - "ws": { - "version": "8.8.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.8.1.tgz", - "integrity": "sha512-bGy2JzvzkPowEJV++hF07hAD6niYSr0JzBNo/J29WsB57A2r7Wlc1UFcTR9IzrPvuNVO4B8LGqF8qcpsVOhJCA==", - "requires": {} - }, - "xmlbuilder": { - "version": "15.1.1", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-15.1.1.tgz", - "integrity": "sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==", - "dev": true - }, - "y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true - }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "yaml": { - "version": "2.0.0-1", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.0.0-1.tgz", - "integrity": "sha512-W7h5dEhywMKenDJh2iX/LABkbFnBxasD27oyXWDS/feDsxiw0dD5ncXdYXgkvAsXIY2MpW/ZKkr9IU30DBdMNQ==" - }, - "yargs": { - "version": "17.5.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.5.1.tgz", - "integrity": "sha512-t6YAJcxDkNX7NFYiVtKvWUz8l+PaKTLiL63mJYWR2GnHq2gjEWISzsLp9wg3aY36dY1j+gfIEL3pIF+XlJJfbA==", - "dev": true, - "requires": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.0.0" - } - }, - "yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "dev": true - }, - "yn": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", - "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "dev": true - }, - "yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true - }, - "z-schema": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/z-schema/-/z-schema-5.0.5.tgz", - "integrity": "sha512-D7eujBWkLa3p2sIpJA0d1pr7es+a7m0vFAnZLlCEKq/Ij2k0MLi9Br2UPxoxdYystm5K1yeBGzub0FlYUEWj2Q==", - "requires": { - "commander": "^9.4.1", - "lodash.get": "^4.4.2", - "lodash.isequal": "^4.5.0", - "validator": "^13.7.0" - }, - "dependencies": { - "commander": { - "version": "9.5.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz", - "integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==", - "optional": true - } - } - } - } -} diff --git a/WebApp/package.json b/WebApp/package.json deleted file mode 100644 index 31864d7..0000000 --- a/WebApp/package.json +++ /dev/null @@ -1,59 +0,0 @@ -{ - "name": "webserver", - "version": "3.1.0", - "private": true, - "scripts": { - "build": "tsc -p tsconfig.build.json", - "test": "jest --colors test/*.ts", - "newman": "newman run test/renderstreaming.postman_collection.json", - "start": "node ./build/index.js -s -p 8080 -m private -k ./server.key -c ./server.cert", - "dev": "ts-node ./src/index.ts -s -p 8080 -m private", - "lint": "eslint src/**/*.ts test/**/*.ts", - "pack": "pkg ." - }, - "dependencies": { - "@types/express": "^4.17.13", - "@types/node": "^18.7.15", - "@types/ws": "^8.5.3", - "cors": "^2.8.5", - "debug": "~4.3.4", - "express": "~4.18.1", - "morgan": "^1.10.0", - "multer": "^2.1.1", - "swagger-jsdoc": "^6.2.1", - "swagger-ui-express": "^4.5.0", - "uuid": "^9.0.0", - "ws": "^8.8.1" - }, - "devDependencies": { - "@jest-mock/express": "^2.0.1", - "@types/jest": "^29.0.2", - "@types/morgan": "^1.9.3", - "@types/swagger-jsdoc": "^6.0.1", - "@types/swagger-ui-express": "^4.1.3", - "@typescript-eslint/eslint-plugin": "^5.36.2", - "@typescript-eslint/parser": "^5.36.2", - "eslint": "^8.23.0", - "eslint-plugin-jest": "^27.0.1", - "jest": "^29.0.2", - "jest-websocket-mock": "^2.4.0", - "mock-socket": "^9.1.5", - "newman": "^6.0.0", - "pkg": "^5.8.0", - "ts-jest": "^29.0.2", - "ts-node": "^10.9.1", - "typescript": "^4.8.2" - }, - "bin": { - "webserver": "build/index.js" - }, - "pkg": { - "assets": [ - "client/public/**/*", - "client/src/**/*" - ], - "targets": [ - "node10" - ] - } -} diff --git a/WebApp/run.bat b/WebApp/run.bat deleted file mode 100644 index 36fb672..0000000 --- a/WebApp/run.bat +++ /dev/null @@ -1,16 +0,0 @@ -@echo off -pushd %~dp0 -call npm run build -call npm run start -popd -pause - -node ./build/index.js -s -p 8080 -m private -k ./server.key -c ./server.cert -l dev - - -// 通话测试代码 -const caller = { - name: "Sarah Chen", - avatar: "https://images.unsplash.com/photo-1494790108377-be9c29b29330?w=100&h=100&fit=crop" -}; -window.showCallRequest(caller); diff --git a/WebApp/server.cert b/WebApp/server.cert deleted file mode 100644 index 9c2963a..0000000 --- a/WebApp/server.cert +++ /dev/null @@ -1,22 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDkzCCAnugAwIBAgIUUSy8jVg4AA8orKk80GBpbe+YMDIwDQYJKoZIhvcNAQEL -BQAwcjELMAkGA1UEBhMCQ0gxCzAJBgNVBAgMAlpKMQswCQYDVQQHDAJIWjEOMAwG -A1UECgwFU1RBUlkxCzAJBgNVBAsMAktGMQswCQYDVQQDDAJaWjEfMB0GCSqGSIb3 -DQEJARYQODM0MjA3MTcyQHFxLmNvbTAeFw0yNjAyMjcwODExMTVaFw0yNzAyMjcw -ODExMTVaMHIxCzAJBgNVBAYTAkNIMQswCQYDVQQIDAJaSjELMAkGA1UEBwwCSFox -DjAMBgNVBAoMBVNUQVJZMQswCQYDVQQLDAJLRjELMAkGA1UEAwwCWloxHzAdBgkq -hkiG9w0BCQEWEDgzNDIwNzE3MkBxcS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IB -DwAwggEKAoIBAQC68fDdstoTwmXca0EG28xQ8s2cp24Mr9rPUyPMsbtJiDtOf4uD -/mUqybl0YNeAIWm7jhwOaxAidl1Y6+J8o6FEX+EGu1qgldP0wV9C/OqpedBMULpt -X7BkkAYsHpa3WmV8AZC3B61xng/jVyEj1rLrzMn+2yoC/VZEH41jE9wGPvL3qL5J -80Ssxmly4NEwygxtr8cXbhm2+UFudevvtW5QAOBbzeAt2mEPfRZNA4NMYkao/9vQ -MZpYEYnY2hO9KxYaHXoQ0rebt/vXJgrndNn3sMCuwePWCIFnQM3lNV6y+bAX833G -i0eYYWAlQ7PzKDDh8oK1IYrZF9ebSojc1r41AgMBAAGjITAfMB0GA1UdDgQWBBQO -SK56uQTrNF7UeNyrBdbCihh2YTANBgkqhkiG9w0BAQsFAAOCAQEAOpfrvwjhqGsT -lCpA2ntDC0AI++Vm2FDFBc4TpY3ZJFTj/PJ3sB4Dbh4KB57Nafwdpe4Clp4TVB9y -H5v4EQemMgtswGzByrAjSIsbN41kYFobJBi9bHLIERO7OhAQRkmeqJAuWx978SB1 -lm2AUhd7+Y3lDoCpaqSXB8bPqrigpjfGhwhZTE6PLBBjIc79rbXsJUL02Xguwb+P -Ertnm5TY62xEz7NamwVwAAy8wvVxxKftkqo2UEQJ0WIs20cJMtZRkbzHPAwFCXRY -Hov1YCto5Yr4kxWwXrLuOcaRp1hvp3jBCeIRjeQ0oDb9uwbaQPmkmjIzKehVFT+B -cB/Vf5yjmA== ------END CERTIFICATE----- diff --git a/WebApp/server.key b/WebApp/server.key deleted file mode 100644 index 9a69299..0000000 --- a/WebApp/server.key +++ /dev/null @@ -1,28 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC68fDdstoTwmXc -a0EG28xQ8s2cp24Mr9rPUyPMsbtJiDtOf4uD/mUqybl0YNeAIWm7jhwOaxAidl1Y -6+J8o6FEX+EGu1qgldP0wV9C/OqpedBMULptX7BkkAYsHpa3WmV8AZC3B61xng/j -VyEj1rLrzMn+2yoC/VZEH41jE9wGPvL3qL5J80Ssxmly4NEwygxtr8cXbhm2+UFu -devvtW5QAOBbzeAt2mEPfRZNA4NMYkao/9vQMZpYEYnY2hO9KxYaHXoQ0rebt/vX -JgrndNn3sMCuwePWCIFnQM3lNV6y+bAX833Gi0eYYWAlQ7PzKDDh8oK1IYrZF9eb -Sojc1r41AgMBAAECggEALMiiQr3ie6rNc4r3CjFT5g1wX6eFV8E16gY49IOcQe6C -hJjN34otCp3GEWDUpzN57I4L3xFbTWItFQz3FhQt4R8V3WK7AG68Fq1PSJEllwFh -OrL5IhPzAfg1nlKamORtHNKULCCI9oeetz+rZvY7KP1HY4f1rb8qMAod+P7sLctz -9fYfpIRGYRU8TjZK+VvL47lQor4227CXWucveOHDh4rbQ2RSklzyqfG13q2QosiM -C+BaV7U3RmFt9vBagQApFRJitspysIDt+l+9crywyXvUJ73FBcdywHempKctzHAX -cipXA4503gSm/2Em7s3xSJSu4xLq07xfcAlOj/bNUQKBgQDvNcgzgdfpxowbwDdj -YQLL4QP+dyqZo9brPAZSUR3vXiFf0ETPSmkEfrAorI230okjSdmYXDF2IY9YmOdD -G/VS9ziNQ5EOHQlO/Z79ZsJGlEvW7dgigym/QmlSQtXQJLlZMHFcmcOFNhxOwEVU -4efZpcBxS8OW6kGDp6KrjT/AsQKBgQDIEQqU0ukyCfCoyLXC6xUWvZgE4C+EAYyH -XBOi5YG7n2D6nJs8Sr66n9pdAsH+6mruzWqS6UbAMcjegMvbV1AJurQbvWJQrlSg -Krcx7CsIIuXlMvAkj6nXQemuxechNsRz1+DheziEOMVOYN6vCF3ZXmoMCNnX5G5E -tx6sI8xWxQKBgBujRyJMWjn0arO6HawpxTzxHpkEA7QErgw3vzM7lA3X/lsnoQui -OUf/qzLH3QfkF1wwaCemX0Ca2AkQgYfLbyjKz4niyJus1yp9OyVj/gZRlAGdMV+r -b+NdNPYAKtwFojSf2DkuutxlSBgBNwF7qGIJOJbefhatsiwX7j+L7lXBAoGBAK++ -2I63X4ZHWRLLjW92VoYtcjcGQHczbSES72TvOzF35hcALxWdi0IhXg7Kd2PYxKqV -5AK9zRrUIOHkPi+l2XdSfRjJGm5JVamFHHxMO9jf3xeh0XYshUPEcOTIkCqLE7O3 -daJdPd5YiGo7iiIztU1XNMzxkXum/H58ZgNNRxkJAoGBAKyf60tE6tYj/R+uG7pY -YqSQAFelAp5ayzW2UR/gF8deM9MOSpAxzYL286OnWQ4UJOzSC5pVsfo7gx90en3F -38e2cgYjaP3VpL3U5+jm4cvMNKk1fOBaLqEH6UZD+66YmF7jag8CKnvhz83lN1w0 -FSbqtfFjjtVUwD0yqPUWwpsi ------END PRIVATE KEY----- diff --git a/WebApp/src/class/answer.ts b/WebApp/src/class/answer.ts deleted file mode 100644 index 1de32df..0000000 --- a/WebApp/src/class/answer.ts +++ /dev/null @@ -1,8 +0,0 @@ -export default class Answer { - sdp: string; - datetime: number; - constructor(sdp: string, datetime: number) { - this.sdp = sdp; - this.datetime = datetime; - } -} \ No newline at end of file diff --git a/WebApp/src/class/candidate.ts b/WebApp/src/class/candidate.ts deleted file mode 100644 index 84c047c..0000000 --- a/WebApp/src/class/candidate.ts +++ /dev/null @@ -1,12 +0,0 @@ -export default class Candidate { - candidate: string; - sdpMLineIndex: number; - sdpMid: string; - datetime: number; - constructor(candidate: string, sdpMLineIndex: number, sdpMid: string, datetime: number) { - this.candidate = candidate; - this.sdpMLineIndex = sdpMLineIndex; - this.sdpMid = sdpMid; - this.datetime = datetime; - } -} \ No newline at end of file diff --git a/WebApp/src/class/httphandler.ts b/WebApp/src/class/httphandler.ts deleted file mode 100644 index c5b65b0..0000000 --- a/WebApp/src/class/httphandler.ts +++ /dev/null @@ -1,1128 +0,0 @@ -/** - * HTTP处理器 - * 负责处理HTTP请求,管理会话和连接,处理信令消息 - */ -import { Request, Response } from 'express'; -import Offer from './offer'; -import Answer from './answer'; -import Candidate from './candidate'; -import { v4 as uuid } from 'uuid'; -import { onGetAllConnectionIds } from './websockethandler'; -/** - * 断开连接记录类 - * 用于记录断开连接的信息 - */ -class Disconnection { - id: string; // 连接ID - datetime: number; // 断开连接的时间戳 - - /** - * 构造函数 - * @param id 连接ID - * @param datetime 断开连接的时间戳 - */ - constructor(id: string, datetime: number) { - this.id = id; - this.datetime = datetime; - } -} - -// 会话超时时间(毫秒) -const TimeoutRequestedTime = 10000; // 10sec - -// 是否为私有模式 -let isPrivate: boolean; - -/** - * 客户端会话映射 - * 键: 会话ID - * 值: 该会话的连接ID集合 - */ -const clients: Map> = new Map>(); - -/** - * 会话最后请求时间映射 - * 键: 会话ID - * 值: 最后请求的时间戳 - */ -const lastRequestedTime: Map = new Map(); - -/** - * 连接对映射 - * 键: 连接ID - * 值: [会话ID1, 会话ID2] - */ -const connectionPair: Map = new Map(); // key = connectionId - -/** - * 会话的offer映射 - * 键: 会话ID - * 值: 该会话的连接ID到Offer对象的映射 - */ -const offers: Map> = new Map>(); // key = sessionId - -/** - * 会话的answer映射 - * 键: 会话ID - * 值: 该会话的连接ID到Answer对象的映射 - */ -const answers: Map> = new Map>(); // key = sessionId - -/** - * 会话的candidate映射 - * 键: 会话ID - * 值: 该会话的连接ID到Candidate数组的映射 - */ -const candidates: Map> = new Map>(); // key = sessionId - -/** - * 会话的断开连接记录映射 - * 键: 会话ID - * 值: 该会话的Disconnection对象数组 - */ -const disconnections: Map = new Map(); // key = sessionId - -/** - * 获取或创建会话的连接ID集合 - * @param sessionId 会话ID - * @returns 连接ID的Set集合 - */ -function getOrCreateConnectionIds(sessionId: string): Set { - let connectionIds = null; - // 检查会话是否已存在 - if (!clients.has(sessionId)) { - // 如果不存在,创建新的连接ID集合 - connectionIds = new Set(); - // 将新的连接ID集合与会话关联 - clients.set(sessionId, connectionIds); - } - // 获取会话的连接ID集合 - connectionIds = clients.get(sessionId); - // 返回连接ID集合 - return connectionIds; -} - -/** - * 重置处理器状态 - * @param mode 通信模式(public或private) - */ -function reset(mode: string): void { - // 设置是否为私有模式 - isPrivate = mode == "private"; - // 清空所有映射 - clients.clear(); - connectionPair.clear(); - offers.clear(); - answers.clear(); - candidates.clear(); - disconnections.clear(); -} - -/** - * 检查会话ID是否有效 - * @param req Express请求对象 - * @param res Express响应对象 - * @param next 下一个中间件函数 - */ -function checkSessionId(req: Request, res: Response, next): void { - // 如果是根路径,直接通过 - if (req.url === '/') { - next(); - return; - } - // 从请求头获取会话ID - const id: string = req.header('session-id'); - // 检查会话是否存在 - if (!clients.has(id)) { - res.sendStatus(404); - return; - } - // 更新会话的最后请求时间 - lastRequestedTime.set(id, Date.now()); - // 继续处理请求 - next(); -} - -/** - * 删除连接 - * @param sessionId 会话ID - * @param connectionId 连接ID - * @param datetime 时间戳 - */ -function _deleteConnection(sessionId:string, connectionId:string, datetime:number) { - // 从会话的连接ID集合中删除连接ID - clients.get(sessionId).delete(connectionId); - - // 处理私有模式 - if(isPrivate) { - if (connectionPair.has(connectionId)) { - const pair = connectionPair.get(connectionId); - // 找到另一个会话ID - const otherSessionId = pair[0] == sessionId ? pair[1] : pair[0]; - if (otherSessionId) { - if (clients.has(otherSessionId)) { - // 从另一个会话的连接ID集合中删除连接ID - clients.get(otherSessionId).delete(connectionId); - // 向另一个会话的断开连接记录中添加记录 - const array1 = disconnections.get(otherSessionId); - array1.push(new Disconnection(connectionId, datetime)); - } - } - } - } else { - // 公共模式:向所有其他会话的断开连接记录中添加记录 - disconnections.forEach((array, id) => { - if (id == sessionId) - return; - array.push(new Disconnection(connectionId, datetime)); - }); - } - - // 从连接对映射中删除 - connectionPair.delete(connectionId); - // 从会话的offer映射中删除 - offers.get(sessionId).delete(connectionId); - // 从会话的answer映射中删除 - answers.get(sessionId).delete(connectionId); - // 从会话的candidate映射中删除 - candidates.get(sessionId).delete(connectionId); - - // 向当前会话的断开连接记录中添加记录 - const array2 = disconnections.get(sessionId); - array2.push(new Disconnection(connectionId, datetime)); -} - -/** - * 删除会话 - * @param sessionId 会话ID - */ -function _deleteSession(sessionId: string) { - // 如果会话存在,删除其所有连接 - if(clients.has(sessionId)) { - for(const connectionId of Array.from(clients.get(sessionId))) { - _deleteConnection(sessionId, connectionId, Date.now()); - } - } - // 从所有映射中删除会话 - offers.delete(sessionId); - answers.delete(sessionId); - candidates.delete(sessionId); - clients.delete(sessionId); - disconnections.delete(sessionId); -} - -/** - * 检查超时会话 - */ -function _checkForTimedOutSessions(): void { - // 遍历所有会话 - for (const sessionId of Array.from(clients.keys())) - { - // 如果会话没有最后请求时间,跳过 - if(!lastRequestedTime.has(sessionId)) - continue; - // 如果会话未超时,跳过 - if(lastRequestedTime.get(sessionId) > Date.now() - TimeoutRequestedTime) - continue; - // 删除超时会话 - _deleteSession(sessionId); - console.log(`deleted sessionId:${sessionId} by timeout.`); - } -} - -/** - * 获取会话的连接ID列表 - * @param sessionId 会话ID - * @returns 连接ID数组 - */ -function _getConnection(sessionId: string): string[] { - // 检查超时会话 - _checkForTimedOutSessions(); - // 返回会话的连接ID集合的数组形式 - return Array.from(clients.get(sessionId)); -} - -/** - * 获取会话的断开连接记录 - * @param sessionId 会话ID - * @param fromTime 起始时间戳 - * @returns 断开连接记录数组 - */ -function _getDisconnection(sessionId: string, fromTime: number): Disconnection[] { - // 检查超时会话 - _checkForTimedOutSessions(); - let arrayDisconnections: Disconnection[] = []; - // 如果断开连接记录存在,获取该会话的断开连接记录 - if (disconnections.size != 0 && disconnections.has(sessionId)) { - arrayDisconnections = disconnections.get(sessionId); - } - - // 如果指定了起始时间,过滤出时间戳大于等于起始时间的记录 - if (fromTime > 0) { - arrayDisconnections = arrayDisconnections.filter((v) => v.datetime >= fromTime); - } - return arrayDisconnections; -} - -/** - * 获取会话的offer列表 - * @param sessionId 会话ID - * @param fromTime 起始时间戳 - * @returns [连接ID, Offer]数组 - */ -function _getOffer(sessionId: string, fromTime: number): [string, Offer][] { - let arrayOffers: [string, Offer][] = []; - - // 如果offer映射不为空 - if (offers.size != 0) { - // 处理私有模式 - if (isPrivate) { - // 如果会话存在offer记录,获取该会话的offer列表 - if (offers.has(sessionId)) { - arrayOffers = Array.from(offers.get(sessionId)); - } - } else { - // 公共模式:获取所有其他会话的offer列表 - const otherSessionMap = Array.from(offers).filter(x => x[0] != sessionId); - arrayOffers = [].concat(...Array.from(otherSessionMap, x => Array.from(x[1], y => [y[0], y[1]]))); - } - } - - // 如果指定了起始时间,过滤出时间戳大于等于起始时间的offer - if (fromTime > 0) { - arrayOffers = arrayOffers.filter((v) => v[1].datetime >= fromTime); - } - return arrayOffers; -} - -/** - * 获取会话的answer列表 - * @param sessionId 会话ID - * @param fromTime 起始时间戳 - * @returns [连接ID, Answer]数组 - */ -function _getAnswer(sessionId: string, fromTime: number): [string, Answer][] { - let arrayAnswers: [string, Answer][] = []; - - // 如果answer映射不为空且会话存在answer记录,获取该会话的answer列表 - if (answers.size != 0 && answers.has(sessionId)) { - arrayAnswers = Array.from(answers.get(sessionId)); - } - - // 如果指定了起始时间,过滤出时间戳大于等于起始时间的answer - if (fromTime > 0) { - arrayAnswers = arrayAnswers.filter((v) => v[1].datetime >= fromTime); - } - return arrayAnswers; -} - -/** - * 获取会话的candidate列表 - * @param sessionId 会话ID - * @param fromTime 起始时间戳 - * @returns [连接ID, Candidate]数组 - */ -function _getCandidate(sessionId: string, fromTime: number): [string, Candidate][] { - // 获取会话的连接ID列表 - const connectionIds = Array.from(clients.get(sessionId)); - const arr: [string, Candidate][] = []; - // 遍历每个连接ID - for (const connectionId of connectionIds) { - // 获取连接对 - const pair = connectionPair.get(connectionId); - if (pair == null) { - continue; - } - // 找到另一个会话ID - const otherSessionId = sessionId === pair[0] ? pair[1] : pair[0]; - // 如果另一个会话不存在candidate记录或该连接ID不存在candidate记录,跳过 - if (!candidates.get(otherSessionId) || !candidates.get(otherSessionId).get(connectionId)) { - continue; - } - // 获取该连接ID的candidate列表,并过滤出时间戳大于等于起始时间的candidate - const arrayCandidates = candidates.get(otherSessionId).get(connectionId) - .filter((v) => v.datetime >= fromTime); - // 如果没有符合条件的candidate,跳过 - if (arrayCandidates.length === 0) { - continue; - } - // 将符合条件的candidate添加到结果数组中 - for (const candidate of arrayCandidates) { - arr.push([connectionId, candidate]); - } - } - return arr; -} - -/** - * @swagger - * /signaling/answer: - * get: - * summary: 获取answer列表 - * description: 获取当前会话的answer信令消息列表 - * security: - * - sessionAuth: [] - * parameters: - * - in: query - * name: fromtime - * schema: - * type: number - * description: 起始时间戳,用于过滤消息 - * responses: - * 200: - * description: 成功获取answer列表 - * content: - * application/json: - * schema: - * type: object - * properties: - * answers: - * type: array - * items: - * type: object - * properties: - * connectionId: - * type: string - * description: 连接ID - * sdp: - * type: string - * description: SDP描述 - * type: - * type: string - * description: 消息类型 - * datetime: - * type: number - * description: 时间戳 - */ -function getAnswer(req: Request, res: Response): void { - // 从请求查询参数中获取`fromtime`参数 - const fromTime: number = req.query.fromtime ? Number(req.query.fromtime) : 0; - // 从请求头获取会话ID - const sessionId: string = req.header('session-id'); - // 获取会话的answer列表 - const answers: [string, Answer][] = _getAnswer(sessionId, fromTime); - // 返回JSON响应,包含answer列表 - res.json({ answers: answers.map((v) => ({ connectionId: v[0], sdp: v[1].sdp, type: "answer", datetime: v[1].datetime })) }); -} - -/** - * @swagger - * /signaling/connection: - * get: - * summary: 获取连接列表 - * description: 获取当前会话的连接列表 - * security: - * - sessionAuth: [] - * responses: - * 200: - * description: 成功获取连接列表 - * content: - * application/json: - * schema: - * type: object - * properties: - * connections: - * type: array - * items: - * type: object - * properties: - * connectionId: - * type: string - * description: 连接ID - * type: - * type: string - * description: 消息类型 - * datetime: - * type: number - * description: 时间戳 - */ -function getConnection(req: Request, res: Response): void { - // 从请求头获取会话ID - const sessionId: string = req.header('session-id'); - // 获取会话的连接ID列表 - const connections = _getConnection(sessionId); - // 返回JSON响应,包含连接列表 - res.json({ connections: connections.map((v) => ({ connectionId: v, type: "connect", datetime: Date.now() })) }); -} - -/** - * @swagger - * /signaling/offer: - * get: - * summary: 获取offer列表 - * description: 获取当前会话的offer信令消息列表 - * security: - * - sessionAuth: [] - * parameters: - * - in: query - * name: fromtime - * schema: - * type: number - * description: 起始时间戳,用于过滤消息 - * responses: - * 200: - * description: 成功获取offer列表 - * content: - * application/json: - * schema: - * type: object - * properties: - * offers: - * type: array - * items: - * type: object - * properties: - * connectionId: - * type: string - * description: 连接ID - * sdp: - * type: string - * description: SDP描述 - * polite: - * type: boolean - * description: 是否为polite模式 - * type: - * type: string - * description: 消息类型 - * datetime: - * type: number - * description: 时间戳 - */ -function getOffer(req: Request, res: Response): void { - // 从请求查询参数中获取`fromtime`参数 - const fromTime: number = req.query.fromtime ? Number(req.query.fromtime) : 0; - // 从请求头获取会话ID - const sessionId: string = req.header('session-id'); - // 获取会话的offer列表 - const offers = _getOffer(sessionId, fromTime); - // 返回JSON响应,包含offer列表 - res.json({ offers: offers.map((v) => ({ connectionId: v[0], sdp: v[1].sdp, polite: v[1].polite, type: "offer", datetime: v[1].datetime })) }); -} - -/** - * @swagger - * /signaling/candidate: - * get: - * summary: 获取candidate列表 - * description: 获取当前会话的candidate信令消息列表 - * security: - * - sessionAuth: [] - * parameters: - * - in: query - * name: fromtime - * schema: - * type: number - * description: 起始时间戳,用于过滤消息 - * responses: - * 200: - * description: 成功获取candidate列表 - * content: - * application/json: - * schema: - * type: object - * properties: - * candidates: - * type: array - * items: - * type: object - * properties: - * connectionId: - * type: string - * description: 连接ID - * candidate: - * type: string - * description: ICE候选者信息 - * sdpMLineIndex: - * type: number - * description: SDP媒体行索引 - * sdpMid: - * type: string - * description: SDP媒体ID - * type: - * type: string - * description: 消息类型 - * datetime: - * type: number - * description: 时间戳 - */ -function getCandidate(req: Request, res: Response): void { - // 从请求查询参数中获取`fromtime`参数 - const fromTime: number = req.query.fromtime ? Number(req.query.fromtime) : 0; - // 从请求头获取会话ID - const sessionId: string = req.header('session-id'); - // 获取会话的candidate列表 - const candidates = _getCandidate(sessionId, fromTime); - // 返回JSON响应,包含candidate列表 - res.json({ candidates: candidates.map((v) => ({ connectionId: v[0], candidate: v[1].candidate, sdpMLineIndex: v[1].sdpMLineIndex, sdpMid: v[1].sdpMid, type: "candidate", datetime: v[1].datetime })) }); -} - -/** - * @swagger - * /signaling: - * get: - * summary: 获取所有信令消息 - * description: 获取当前会话的所有信令消息,包括连接、断开连接、offer、answer和candidate - * security: - * - sessionAuth: [] - * parameters: - * - in: query - * name: fromtime - * schema: - * type: number - * description: 起始时间戳,用于过滤消息 - * responses: - * 200: - * description: 成功获取所有信令消息 - * content: - * application/json: - * schema: - * type: object - * properties: - * messages: - * type: array - * items: - * type: object - * properties: - * connectionId: - * type: string - * description: 连接ID - * type: - * type: string - * description: 消息类型 - * datetime: - * type: number - * description: 时间戳 - * sdp: - * type: string - * description: SDP描述(仅offer和answer消息) - * polite: - * type: boolean - * description: 是否为polite模式(仅offer消息) - * candidate: - * type: string - * description: ICE候选者信息(仅candidate消息) - * sdpMLineIndex: - * type: number - * description: SDP媒体行索引(仅candidate消息) - * sdpMid: - * type: string - * description: SDP媒体ID(仅candidate消息) - * datetime: - * type: number - * description: 当前时间戳 - */ -function getAll(req: Request, res: Response): void { - // 从请求查询参数中获取`fromtime`参数 - const fromTime: number = req.query.fromtime ? Number(req.query.fromtime) : 0; - // 从请求头获取会话ID - const sessionId: string = req.header('session-id'); - // 获取各种信令消息 - const connections = _getConnection(sessionId); - const offers = _getOffer(sessionId, fromTime); - const answers: [string, Answer][] = _getAnswer(sessionId, fromTime); - const candidates: [string, Candidate][] = _getCandidate(sessionId, fromTime); - const disconnections: Disconnection[] = _getDisconnection(sessionId, fromTime); - const datetime = lastRequestedTime.get(sessionId); - - let array: any[] = []; - - // 合并所有信令消息 - array = array.concat(connections.map((v) => ({ connectionId: v, type: "connect", datetime: datetime }))); - array = array.concat(offers.map((v) => ({ connectionId: v[0], sdp: v[1].sdp, polite: v[1].polite, type: "offer", datetime: v[1].datetime }))); - array = array.concat(answers.map((v) => ({ connectionId: v[0], sdp: v[1].sdp, type: "answer", datetime: v[1].datetime }))); - array = array.concat(candidates.map((v) => ({ connectionId: v[0], candidate: v[1].candidate, sdpMLineIndex: v[1].sdpMLineIndex, sdpMid: v[1].sdpMid, type: "candidate", datetime: v[1].datetime }))); - array = array.concat(disconnections.map((v) => ({ connectionId: v.id, type: "disconnect", datetime: v.datetime }))); - - // 按时间戳排序 - array.sort((a, b) => a.datetime - b.datetime); - // 返回JSON响应,包含所有信令消息 - res.json({ messages: array, datetime: datetime }); -} - -/** - * @swagger - * /signaling: - * put: - * summary: 创建会话 - * description: 创建一个新的会话,并返回会话ID - * responses: - * 200: - * description: 成功创建会话 - * content: - * application/json: - * schema: - * type: object - * properties: - * sessionId: - * type: string - * description: 新创建的会话ID - */ -function createSession(sessionId: string, res: Response): void; -function createSession(req: Request, res: Response): void; - -function createSession(req: string | Request, res: Response): void { - // 确定会话ID - const sessionId: string = typeof req === "string" ? req : uuid(); - // 为会话创建各种映射 - clients.set(sessionId, new Set()); - offers.set(sessionId, new Map()); - answers.set(sessionId, new Map()); - candidates.set(sessionId, new Map()); - disconnections.set(sessionId, []); - // 返回JSON响应,包含会话ID - res.json({ sessionId: sessionId }); -} - -/** - * @swagger - * /signaling: - * delete: - * summary: 删除会话 - * description: 删除当前会话及其所有连接 - * security: - * - sessionAuth: [] - * responses: - * 200: - * description: 成功删除会话 - */ -function deleteSession(req: Request, res: Response): void { - // 从请求头获取会话ID - const id: string = req.header('session-id'); - // 删除会话 - _deleteSession(id); - // 返回200状态码表示请求处理成功 - res.sendStatus(200); -} - -/** - * @swagger - * /signaling/connection: - * put: - * summary: 创建连接 - * description: 创建一个新的连接,并返回连接信息 - * security: - * - sessionAuth: [] - * requestBody: - * required: true - * content: - * application/json: - * schema: - * type: object - * properties: - * connectionId: - * type: string - * description: 连接ID - * responses: - * 200: - * description: 成功创建连接 - * content: - * application/json: - * schema: - * type: object - * properties: - * connectionId: - * type: string - * description: 连接ID - * polite: - * type: boolean - * description: 是否为polite模式 - * type: - * type: string - * description: 消息类型 - * datetime: - * type: number - * description: 时间戳 - * 400: - * description: 请求参数错误 - */ -function createConnection(req: Request, res: Response): void { - // 从请求头获取会话ID - const sessionId: string = req.header('session-id'); - // 从请求体获取连接ID - const { connectionId } = req.body; - // 获取会话的最后请求时间 - const datetime = lastRequestedTime.get(sessionId); - - // 检查连接ID是否存在 - if (connectionId == null) { - res.status(400).send({ error: new Error(`connectionId is required`) }); - return; - } - let polite = true; - // 处理私有模式 - if (isPrivate) { - if (connectionPair.has(connectionId)) { - const pair = connectionPair.get(connectionId); - - // 检查连接ID是否已被使用 - if (pair[0] != null && pair[1] != null) { - const err = new Error(`${connectionId}: This connection id is already used.`); - console.log(err); - res.status(400).send({ error: err }); - return; - } else if (pair[0] != null) { - // 找到配对连接 - connectionPair.set(connectionId, [pair[0], sessionId]); - // 添加连接ID到另一个会话 - const map = getOrCreateConnectionIds(pair[0]); - map.add(connectionId); - } - } else { - // 创建新的连接对 - connectionPair.set(connectionId, [sessionId, null]); - polite = false; - } - } - - // 添加连接ID到当前会话 - const connectionIds = getOrCreateConnectionIds(sessionId); - connectionIds.add(connectionId); - // 返回JSON响应,包含连接信息 - res.json({ connectionId: connectionId, polite: polite, type: "connect", datetime: datetime }); -} - -/** - * @swagger - * /signaling/connection: - * delete: - * summary: 删除连接 - * description: 删除指定的连接 - * security: - * - sessionAuth: [] - * requestBody: - * required: true - * content: - * application/json: - * schema: - * type: object - * properties: - * connectionId: - * type: string - * description: 连接ID - * responses: - * 200: - * description: 成功删除连接 - * content: - * application/json: - * schema: - * type: object - * properties: - * connectionId: - * type: string - * description: 连接ID - */ -function deleteConnection(req: Request, res: Response): void { - // 从请求头获取会话ID - const sessionId: string = req.header('session-id'); - // 从请求体获取连接ID - const { connectionId } = req.body; - // 获取会话的最后请求时间 - const datetime = lastRequestedTime.get(sessionId); - - // 删除连接 - _deleteConnection(sessionId, connectionId, datetime); - - // 返回JSON响应,包含连接ID - res.json({ connectionId: connectionId }); -} - -/** - * @swagger - * /signaling/offer: - * post: - * summary: 发送offer信令 - * description: 发送offer信令消息 - * security: - * - sessionAuth: [] - * requestBody: - * required: true - * content: - * application/json: - * schema: - * type: object - * properties: - * connectionId: - * type: string - * description: 连接ID - * sdp: - * type: string - * description: SDP描述 - * responses: - * 200: - * description: 成功发送offer信令 - */ -function postOffer(req: Request, res: Response): void { - const sessionId: string = req.header('session-id'); - const { connectionId } = req.body; - const datetime = lastRequestedTime.get(sessionId); - let keySessionId = null; - let polite = false; - - if (isPrivate) { - if (connectionPair.has(connectionId)) { - const pair = connectionPair.get(connectionId); - keySessionId = pair[0] == sessionId ? pair[1] : pair[0]; - if (keySessionId != null) { - polite = true; - const map = offers.get(keySessionId); - map.set(connectionId, new Offer(req.body.sdp, datetime, polite)); - } - } - res.sendStatus(200); - return; - } - - if(!connectionPair.has(connectionId)) - { - connectionPair.set(connectionId, [sessionId, null]); - } - - keySessionId = sessionId; - const map = offers.get(keySessionId); - map.set(connectionId, new Offer(req.body.sdp, datetime, polite)); - - res.sendStatus(200); -} - -/** - * @swagger - * /signaling/answer: - * post: - * summary: 发送answer信令 - * description: 发送answer信令消息 - * security: - * - sessionAuth: [] - * requestBody: - * required: true - * content: - * application/json: - * schema: - * type: object - * properties: - * connectionId: - * type: string - * description: 连接ID - * sdp: - * type: string - * description: SDP描述 - * responses: - * 200: - * description: 成功发送answer信令 - */ -function postAnswer(req: Request, res: Response): void { - const sessionId: string = req.header('session-id'); - const { connectionId } = req.body; - const datetime = lastRequestedTime.get(sessionId); - const connectionIds = getOrCreateConnectionIds(sessionId); - connectionIds.add(connectionId); - - if (!connectionPair.has(connectionId)) { - res.sendStatus(200); - return; - } - - // add connectionPair - const pair = connectionPair.get(connectionId); - const otherSessionId = pair[0] == sessionId ? pair[1] : pair[0]; - if (!clients.has(otherSessionId)) { - // already deleted - res.sendStatus(200); - return; - } - - if (!isPrivate) { - connectionPair.set(connectionId, [otherSessionId, sessionId]); - } - - const map = answers.get(otherSessionId); - map.set(connectionId, new Answer(req.body.sdp, datetime)); - - // update datetime for candidates - const mapCandidates = candidates.get(otherSessionId); - if (mapCandidates) { - const arrayCandidates = mapCandidates.get(connectionId); - if (arrayCandidates) { - for (const candidate of arrayCandidates) { - candidate.datetime = datetime; - } - } - } - res.sendStatus(200); -} - -/** - * @swagger - * /signaling/candidate: - * post: - * summary: 发送candidate信令 - * description: 发送candidate信令消息 - * security: - * - sessionAuth: [] - * requestBody: - * required: true - * content: - * application/json: - * schema: - * type: object - * properties: - * connectionId: - * type: string - * description: 连接ID - * candidate: - * type: string - * description: ICE候选者信息 - * sdpMLineIndex: - * type: number - * description: SDP媒体行索引 - * sdpMid: - * type: string - * description: SDP媒体ID - * responses: - * 200: - * description: 成功发送candidate信令 - */ -function postCandidate(req: Request, res: Response): void { - const sessionId: string = req.header('session-id'); - const { connectionId } = req.body; - const datetime = lastRequestedTime.get(sessionId); - - const map = candidates.get(sessionId); - if (!map.has(connectionId)) { - map.set(connectionId, []); - } - const arr = map.get(connectionId); - const candidate = new Candidate(req.body.candidate, req.body.sdpMLineIndex, req.body.sdpMid, datetime); - arr.push(candidate); - res.sendStatus(200); -} -/** - * @swagger - * /signaling/rooms: - * get: - * summary: 获取房间和用户信息 - * description: 获取所有房间的信息,包括房间ID和链接的用户 - * security: - * - sessionAuth: [] - * responses: - * 200: - * description: 成功获取房间和用户信息 - * content: - * application/json: - * schema: - * type: object - * properties: - * rooms: - * type: array - * items: - * type: object - * properties: - * roomId: - * type: string - * description: 房间ID - * users: - * type: array - * items: - * type: object - * properties: - * sessionId: - * type: string - * description: 会话ID - * connected: - * type: boolean - * description: 连接状态 - * userCount: - * type: number - * description: 用户数量 - * totalRooms: - * type: number - * description: 总房间数 - */ -function onGetConnections(req: Request, res: Response): void { - - // 收集所有房间ID和链接用户信息 - const rooms = []; - - // 遍历所有连接对 - for (const [connectionId, pair] of Array.from(connectionPair.entries())) { - // 收集房间中的用户信息 - const users = []; - - // 添加第一个用户 - if (pair[0] && clients.has(pair[0])) { - users.push({ - sessionId: pair[0], - connected: true - }); - } - - // 添加第二个用户 - if (pair[1] && clients.has(pair[1])) { - users.push({ - sessionId: pair[1], - connected: true - }); - } - - // 添加房间信息 - rooms.push({ - roomId: connectionId, - users: users, - userCount: users.length - }); - } - - res.json({ rooms: rooms, totalRooms: rooms.length }); -} - -/** - * @swagger - * /signaling/connection-ids: - * get: - * summary: 获取所有连接ID - * description: 获取所有当前活跃的连接ID - * security: - * - sessionAuth: [] - * responses: - * 200: - * description: 成功获取连接ID列表 - * content: - * application/json: - * schema: - * type: object - * properties: - * connectionIds: - * type: array - * items: - * type: string - * description: 连接ID - * totalCount: - * type: number - * description: 总连接数 - */ -function getAllConnectionIds(req: Request, res: Response): void { - // 获取所有连接ID - const connectionIds = onGetAllConnectionIds(); - // 返回JSON响应,包含连接ID列表和总数量 - res.json({ connectionIds: connectionIds, totalCount: connectionIds.length }); -} -/** - * 导出HTTP处理器函数 - */ -export { - reset, // 重置处理器状态 - checkSessionId, // 检查会话ID是否有效 - getAll, // 获取所有信令消息 - getConnection, // 获取连接列表 - getOffer, // 获取offer列表 - getAnswer, // 获取answer列表 - getCandidate, // 获取candidate列表 - createSession, // 创建会话 - deleteSession, // 删除会话 - createConnection, // 创建连接 - deleteConnection, // 删除连接 - postOffer, // 处理offer信令消息 - postAnswer, // 处理answer信令消息 - postCandidate, // 处理candidate信令消息 - onGetConnections, // 获取房间和用户信息 - getAllConnectionIds // 获取所有连接ID -}; diff --git a/WebApp/src/class/offer.ts b/WebApp/src/class/offer.ts deleted file mode 100644 index 701ed6e..0000000 --- a/WebApp/src/class/offer.ts +++ /dev/null @@ -1,10 +0,0 @@ -export default class Offer { - sdp: string; - datetime: number; - polite: boolean; - constructor(sdp: string, datetime: number, polite: boolean) { - this.sdp = sdp; - this.datetime = datetime; - this.polite = polite; - } -} diff --git a/WebApp/src/class/options.ts b/WebApp/src/class/options.ts deleted file mode 100644 index 6648366..0000000 --- a/WebApp/src/class/options.ts +++ /dev/null @@ -1,9 +0,0 @@ -export default interface Options { - secure?: boolean; - port?: number; - keyfile?: string; - certfile?: string; - type?: string; - mode?: string; - logging?: string; -} diff --git a/WebApp/src/class/websockethandler.ts b/WebApp/src/class/websockethandler.ts deleted file mode 100644 index 4acb86a..0000000 --- a/WebApp/src/class/websockethandler.ts +++ /dev/null @@ -1,475 +0,0 @@ -/** - * WebSocket处理器 - * 负责管理WebSocket连接和信令消息处理 - */ -import Offer from './offer'; -import Answer from './answer'; -import Candidate from './candidate'; - -/** - * 是否为私有模式 - */ -let isPrivate: boolean; - -/** - * 客户端连接映射 - * 键: WebSocket实例 - * 值: 该WebSocket的连接ID集合 - */ -const clients: Map> = new Map>(); - -/** - * 连接组结构 - * host: 主机WebSocket实例(第一个连接的客户端) - * participants: 参与者WebSocket集合(后续连接的客户端) - */ -interface ConnectionGroup { - host: WebSocket; - participants: Set; -} - -/** - * 连接组映射 - * 键: connectionId - * 值: ConnectionGroup(1个host + 多个participants) - */ -const connectionGroup: Map = new Map(); - -/** - * 获取或创建WebSocket会话的连接ID集合 - * @param session WebSocket会话实例 - * @returns 连接ID的Set集合 - */ -function getOrCreateConnectionIds(session: WebSocket): Set { - let connectionIds = null; - // 检查客户端是否已存在 - if (!clients.has(session)) { - // 如果不存在,创建新的连接ID集合 - connectionIds = new Set(); - // 将新的连接ID集合与客户端关联 - clients.set(session, connectionIds); - } - // 获取客户端的连接ID集合 - connectionIds = clients.get(session); - // 返回连接ID集合 - return connectionIds; -} - -/** - * 重置处理器状态 - * @param mode 通信模式(public或private) - */ -function reset(mode: string): void { - // 设置是否为私有模式 - isPrivate = mode == "private"; -} - -/** - * 添加新的WebSocket连接 - * @param ws WebSocket连接实例 - */ -function add(ws: WebSocket): void { - // 为新连接创建空的连接ID集合 - const id = new Set(); - clients.set(ws, id); - // 记录添加WebSocket连接的日志 - console.log(`Add WebSocket: ${id}`); -} - -/** - * 判断WebSocket是否为指定连接组的host - * @param ws WebSocket连接实例 - * @param connectionId 连接ID - * @returns 是否为host - */ -function isHost(ws: WebSocket, connectionId: string): boolean { - const group = connectionGroup.get(connectionId); - return group != null && group.host === ws; -} - -/** - * 向连接组中除发送者外的所有成员发送消息 - * @param connectionId 连接ID - * @param senderWs 发送者WebSocket实例 - * @param message 要发送的消息对象 - */ -function broadcastToGroup(connectionId: string, senderWs: WebSocket, message: any): void { - const group = connectionGroup.get(connectionId); - if (!group) return; - // 如果发送者是host,转发给所有participants - if (senderWs === group.host) { - group.participants.forEach(participantWs => { - participantWs.send(JSON.stringify(message)); - }); - } else { - // 如果发送者是participant,转发给host - group.host.send(JSON.stringify(message)); - } -} - -/** - * 移除WebSocket连接 - * @param ws WebSocket连接实例 - */ -function remove(ws: WebSocket): void { - const connectionIds = clients.get(ws); - if (!connectionIds) return; - - connectionIds.forEach(connectionId => { - const group = connectionGroup.get(connectionId); - if (group) { - if (group.host === ws) { - group.participants.forEach(participantWs => { - participantWs.send(JSON.stringify({ type: "disconnect", connectionId: connectionId, reason: "host-left" })); - }); - connectionGroup.delete(connectionId); - } else { - group.participants.delete(ws); - // 包含participantId,让host能识别是哪个participant离开 - group.host.send(JSON.stringify({ type: "participant-left", connectionId: connectionId, participantId: (ws as any).participantId })); - } - } - console.log(`Remove connectionId: ${connectionId}`); - }); - - clients.delete(ws); -} - -/** - * 处理连接请求(1对多模式) - * 第一个连接的客户端成为host,后续连接的客户端成为participants - * @param ws WebSocket连接实例 - * @param connectionId 连接ID - */ -function onConnect(ws: WebSocket, connectionId: string): void { - let polite = true; - // 为每个WebSocket生成唯一的participantId - const participantId = (ws as any).participantId = (ws as any).participantId || `p_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`; - - if (isPrivate) { - if (connectionGroup.has(connectionId)) { - const group = connectionGroup.get(connectionId); - group.participants.add(ws); - console.log(`Participant ${participantId} joined connectionId: ${connectionId}, total participants: ${group.participants.size}`); - // 通知host有新participant加入 - group.host.send(JSON.stringify({ type: "participant-joined", connectionId: connectionId, participantId: participantId })); - } else { - connectionGroup.set(connectionId, { host: ws, participants: new Set() }); - polite = false; - console.log(`Host created connectionId: ${connectionId}`); - } - } - - const connectionIds = getOrCreateConnectionIds(ws); - connectionIds.add(connectionId); - const role = polite ? 'participant' : 'host'; - ws.send(JSON.stringify({ type: "connect", connectionId: connectionId, polite: polite, role: role, participantId: participantId })); -} - -/** - * 处理断开连接请求(1对多模式) - * @param ws WebSocket连接实例 - * @param connectionId 连接ID - */ -function onDisconnect(ws: WebSocket, connectionId: string): void { - // 获取连接的连接ID集合 - const connectionIds = clients.get(ws); - if (connectionIds) { - // 从集合中删除连接ID - connectionIds.delete(connectionId); - } - - // 处理连接组 - const group = connectionGroup.get(connectionId); - if (group) { - if (group.host === ws) { - // host断开连接,通知所有participants房间已关闭,并删除连接组 - group.participants.forEach(participantWs => { - participantWs.send(JSON.stringify({ type: "disconnect", connectionId: connectionId, reason: "host-left" })); - }); - connectionGroup.delete(connectionId); - console.log(`Host disconnected, room ${connectionId} deleted, notified ${group.participants.size} participants`); - } else { - // participant断开连接,从组中移除并通知host(使用participant-left类型,host不会关闭房间) - group.participants.delete(ws); - group.host.send(JSON.stringify({ type: "participant-left", connectionId: connectionId, participantId: (ws as any).participantId })); - console.log(`Participant left connectionId: ${connectionId}, remaining participants: ${group.participants.size}`); - } - } - - // 向当前连接发送断开连接消息 - ws.send(JSON.stringify({ type: "disconnect", connectionId: connectionId })); - //RemoveHeartbeat(ws); - // 记录断开连接的日志 - console.log(`Disconnect connectionId: ${connectionId}`); -} - -/** - * 处理offer信令(1对多模式) - * host的offer转发给所有participants,participant的offer转发给host - * @param ws WebSocket连接实例 - * @param message 消息数据 - */ -function onOffer(ws: WebSocket, message: any): void { - const connectionId = message.connectionId as string; - const newOffer = new Offer(message.sdp, Date.now(), false); - - if (isPrivate) { - if (connectionGroup.has(connectionId)) { - const group = connectionGroup.get(connectionId); - const senderParticipantId = (ws as any).participantId; - const targetParticipantId = message.participantId; - if (group.host === ws) { - // host发送offer给特定participant(多peer模式下按participantId路由) - newOffer.polite = true; - if (targetParticipantId) { - // 路由到指定participant - group.participants.forEach(participantWs => { - if ((participantWs as any).participantId === targetParticipantId) { - participantWs.send(JSON.stringify({ from: connectionId, to: "", type: "offer", data: newOffer, participantId: targetParticipantId })); - } - }); - } else { - // 兼容:无目标时广播给所有participants - group.participants.forEach(participantWs => { - const pid = (participantWs as any).participantId; - participantWs.send(JSON.stringify({ from: connectionId, to: "", type: "offer", data: newOffer, participantId: pid })); - }); - } - } else { - // participant发送offer给host,携带该participant的participantId - newOffer.polite = true; - group.host.send(JSON.stringify({ from: connectionId, to: "", type: "offer", data: newOffer, participantId: senderParticipantId })); - } - } - return; - } - - // 公共模式:创建新的连接组(如果不存在) - if (!connectionGroup.has(connectionId)) { - connectionGroup.set(connectionId, { host: ws, participants: new Set() }); - } - // 向所有其他客户端广播offer - clients.forEach((_v, k) => { - if (k == ws) { - return; - } - k.send(JSON.stringify({ from: connectionId, to: "", type: "offer", data: newOffer })); - }); -} - -/** - * 处理answer信令(1对多模式) - * participant的answer转发给host - * @param ws WebSocket连接实例 - * @param message 消息数据 - */ -function onAnswer(ws: WebSocket, message: any): void { - const connectionId = message.connectionId as string; - const connectionIds = getOrCreateConnectionIds(ws); - connectionIds.add(connectionId); - const newAnswer = new Answer(message.sdp, Date.now()); - - if (!connectionGroup.has(connectionId)) { - return; - } - - const group = connectionGroup.get(connectionId); - const senderParticipantId = (ws as any).participantId; - // 从answer消息中获取目标participantId(host回复时指定) - const targetParticipantId = message.participantId; - - if (group.host === ws) { - // host发送answer给特定participant - if (targetParticipantId) { - group.participants.forEach(participantWs => { - if ((participantWs as any).participantId === targetParticipantId) { - participantWs.send(JSON.stringify({ from: connectionId, to: "", type: "answer", data: newAnswer, participantId: targetParticipantId })); - } - }); - } else { - // 兼容:没有targetParticipantId时广播给所有participants - group.participants.forEach(participantWs => { - participantWs.send(JSON.stringify({ from: connectionId, to: "", type: "answer", data: newAnswer })); - }); - } - } else { - // participant发送answer给host,携带自己的participantId - group.host.send(JSON.stringify({ from: connectionId, to: "", type: "answer", data: newAnswer, participantId: senderParticipantId })); - } -} - -/** - * 处理candidate信令(1对多模式) - * host的candidate转发给所有participants,participant的candidate转发给host - * @param ws WebSocket连接实例 - * @param message 消息数据 - */ -function onCandidate(ws: WebSocket, message: any): void { - const connectionId = message.connectionId; - const candidate = new Candidate(message.candidate, message.sdpMLineIndex, message.sdpMid, Date.now()); - const senderParticipantId = (ws as any).participantId; - const targetParticipantId = message.participantId; - - if (isPrivate) { - if (connectionGroup.has(connectionId)) { - const group = connectionGroup.get(connectionId); - if (group.host === ws) { - // host发送candidate给特定participant - if (targetParticipantId) { - group.participants.forEach(participantWs => { - if ((participantWs as any).participantId === targetParticipantId) { - participantWs.send(JSON.stringify({ from: connectionId, to: "", type: "candidate", data: candidate, participantId: targetParticipantId })); - } - }); - } else { - group.participants.forEach(participantWs => { - participantWs.send(JSON.stringify({ from: connectionId, to: "", type: "candidate", data: candidate })); - }); - } - } else { - // participant发送candidate给host,携带自己的participantId - group.host.send(JSON.stringify({ from: connectionId, to: "", type: "candidate", data: candidate, participantId: senderParticipantId })); - } - } - return; - } -} - -function onCallConnectionId(ws: WebSocket, message: any): void { - // 获取连接ID - const connectionId = message.connectionId; - const clientId = message.clientId; - // 在1对多模式下,通知host有新的呼叫请求 - if (connectionGroup.has(connectionId)) { - const group = connectionGroup.get(connectionId); - if (group.host !== ws) { - // participant发起呼叫,通知host - group.host.send(JSON.stringify({ from: connectionId, to: "", type: "call-request", data: connectionId })); - } - } else { - // 兼容旧的广播方式 - clients.forEach((_v, k) => { - if (k === ws) { - return; - } - if (_v == clientId) { - k.send(JSON.stringify({ from: connectionId, to: "", type: "call-request", data: connectionId })); - } - }); - } -} - - -/** - * 处理广播消息请求(1对多模式) - * @param ws WebSocket连接实例 - * @param message 消息数据 - */ -function onBroadcast(ws: WebSocket, message: any): void { - const broadcastMessage = message.message; - const targetConnectionId = message.targetConnectionId; - - if (targetConnectionId) { - // 向指定连接组广播 - if (connectionGroup.has(targetConnectionId)) { - const group = connectionGroup.get(targetConnectionId); - // 向组内所有成员发送消息 - group.host.send(JSON.stringify({ - type: "broadcast", - message: broadcastMessage, - from: "server" - })); - group.participants.forEach(participantWs => { - participantWs.send(JSON.stringify({ - type: "broadcast", - message: broadcastMessage, - from: "server" - })); - }); - } - } else { - // 全局广播:向所有客户端发送消息 - clients.forEach((_v, k) => { - k.send(JSON.stringify({ - type: "broadcast", - message: broadcastMessage, - from: "server" - })); - }); - } -} - -function AddHeartbeat(ws: WebSocket, connectionId: string) { - // 初始化心跳检测 - (ws as any).lastActivity = Date.now(); - - // 设置心跳检测定时器,每30秒发送一次ping - (ws as any).heartbeatTimer = setInterval(() => { - const now = Date.now(); - // 检查上次活动时间,如果超过60秒没有活动,关闭连接 - if (now - (ws as any).lastActivity > 10000) { - console.log('WebSocket connection timeout, closing...'); - clearInterval((ws as any).heartbeatTimer); - //ws.close(); - onDisconnect(ws, connectionId); - } else { - // 发送ping消息 - ws.send(JSON.stringify({ from: connectionId, to: "", type: "on-message", data: { type: "ping"} })); - console.log('WebSocket connection heartbeat, lastActivity: ', (ws as any).lastActivity); - } - }, 3000); -} - -function RemoveHeartbeat(ws: WebSocket) { - // 清除心跳检测定时器 - if ((ws as any).heartbeatTimer) { - clearInterval((ws as any).heartbeatTimer); - } -} - -/** - * 处理获取所有连接ID的请求 - * @param ws WebSocket连接实例 - */ -function onGetAllConnectionIds(): string[] { - // 获取所有connectionId - const connectionIds = Array.from(connectionGroup.keys()); - return connectionIds; -} - -/** - * 处理chat-message信令(1对多模式) - * host的消息转发给所有participants,participant的消息转发给host - * @param ws WebSocket连接实例 - * @param message 消息数据 - */ -function onMessage(ws: WebSocket, message: any): void { - // 获取连接ID - const connectionId = message.connectionId; - const chatMessage = message.message; - const senderParticipantId = (ws as any).participantId; - if (connectionGroup.has(connectionId)) { - const group = connectionGroup.get(connectionId); - if (group.host === ws) { - // host发送消息,转发给所有participants - group.participants.forEach(participantWs => { - participantWs.send(JSON.stringify({ from: connectionId, to: "", type: "on-message", data: chatMessage })); - }); - } else { - // participant发送消息,转发给host(附带participantId)和其他participants - group.host.send(JSON.stringify({ from: connectionId, to: "", type: "on-message", data: chatMessage, participantId: senderParticipantId })); - // 同时转发给其他participants(排除发送者自身) - group.participants.forEach(participantWs => { - if (participantWs !== ws) { - participantWs.send(JSON.stringify({ from: connectionId, to: "", type: "on-message", data: chatMessage, participantId: senderParticipantId })); - } - }); - } - } -} - -/** - * 导出WebSocket处理器函数 - */ -export { reset, add, remove, onConnect, onDisconnect, onOffer, onAnswer, onCandidate, onCallConnectionId, onBroadcast, onGetAllConnectionIds, AddHeartbeat, RemoveHeartbeat, onMessage, isHost, broadcastToGroup, connectionGroup }; diff --git a/WebApp/src/index.ts b/WebApp/src/index.ts deleted file mode 100644 index 7e4b4cb..0000000 --- a/WebApp/src/index.ts +++ /dev/null @@ -1,107 +0,0 @@ -import { Command } from 'commander'; -import * as express from 'express'; -import * as https from 'https'; -import { Server } from 'http'; -import * as fs from 'fs'; -import * as os from 'os'; -import { createServer } from './server'; -import { AddressInfo } from 'net'; -import WSSignaling from './websocket'; -import Options from './class/options'; - -export class RenderStreaming { - public static run(argv: string[]): RenderStreaming { - const program = new Command(); - const readOptions = (): Options => { - // 确保argv是数组 - const args = Array.isArray(argv) ? argv : process.argv; - - program - .usage('[options] ') - .option('-p, --port ', 'Port to start the server on.', process.env.PORT || `80`) - .option('-s, --secure', 'Enable HTTPS (you need server.key and server.cert).', process.env.SECURE || true) - .option('-k, --keyfile ', 'https key file.', process.env.KEYFILE || 'server.key') - .option('-c, --certfile ', 'https cert file.', process.env.CERTFILE || 'server.cert') - .option('-t, --type ', 'Type of signaling protocol, Choose websocket or http.', process.env.TYPE || 'websocket') - .option('-m, --mode ', 'Choose Communication mode public or private.', process.env.MODE || 'public') - .option('-l, --logging ', 'Choose http logging type combined, dev, short, tiny or none.', process.env.LOGGING || 'dev') - .parse(args); - - const option = program.opts(); - return { - port: option.port, - secure: option.secure == undefined ? false : option.secure, - keyfile: option.keyfile, - certfile: option.certfile, - type: option.type == undefined ? 'websocket' : option.type, - mode: option.mode, - logging: option.logging, - }; - }; - const options = readOptions(); - return new RenderStreaming(options); - } - - public app: express.Application; - - public server?: Server; - - public options: Options; - - constructor(options: Options) { - this.options = options; - this.app = createServer(this.options); - if (this.options.secure) { - this.server = https.createServer({ - key: fs.readFileSync(options.keyfile), - cert: fs.readFileSync(options.certfile), - }, this.app).listen(this.options.port, () => { - const { port } = this.server.address() as AddressInfo; - const addresses = this.getIPAddress(); - for (const address of addresses) { - console.log(`https://${address}:${port}`); - } - }); - } else { - this.server = this.app.listen(this.options.port, () => { - const { port } = this.server.address() as AddressInfo; - const addresses = this.getIPAddress(); - for (const address of addresses) { - console.log(`http://${address}:${port}`); - } - }); - } - if (this.options.type == 'http') { - console.log(`Use http polling for signaling server.`); - } - else if(this.options.type != 'websocket') { - console.log(`signaling type should be set "websocket" or "http". ${this.options.type} is not supported.`); - console.log(`Changing signaling type to websocket.`); - this.options.type = 'websocket'; - } - if (this.options.type == 'websocket') { - console.log(`Use websocket for signaling server ws://${this.getIPAddress()[0]}`); - - //Start Websocket Signaling server - new WSSignaling(this.server, this.options.mode); - } - - console.log(`start as ${this.options.mode} mode`); - } - - getIPAddress(): string[] { - const interfaces = os.networkInterfaces(); - const addresses: string[] = []; - for (const k in interfaces) { - for (const k2 in interfaces[k]) { - const address = interfaces[k][k2]; - if (address.family === 'IPv4') { - addresses.push(address.address); - } - } - } - return addresses; - } -} - -RenderStreaming.run(process.argv); diff --git a/WebApp/src/log.ts b/WebApp/src/log.ts deleted file mode 100644 index 6268c02..0000000 --- a/WebApp/src/log.ts +++ /dev/null @@ -1,27 +0,0 @@ -const isDebug = true; - -export enum LogLevel { - info, - log, - warn, - error, -} - -export function log(level: LogLevel, ...args: any[]): void { - if (isDebug) { - switch (level) { - case LogLevel.log: - console.log(...args); - break; - case LogLevel.info: - console.info(...args); - break; - case LogLevel.warn: - console.warn(...args); - break; - case LogLevel.error: - console.error(...args); - break; - } - } -} diff --git a/WebApp/src/server.ts b/WebApp/src/server.ts deleted file mode 100644 index e2d6171..0000000 --- a/WebApp/src/server.ts +++ /dev/null @@ -1,89 +0,0 @@ -import * as express from 'express'; -import * as path from 'path'; -import * as fs from 'fs'; -import * as morgan from 'morgan'; -import signaling from './signaling'; -import { log, LogLevel } from './log'; -import Options from './class/options'; -import { reset as resetHandler }from './class/httphandler'; -import { initSwagger } from './swagger'; - -const cors = require('cors'); -const multer = require('multer'); - -export const createServer = (config: Options): express.Express => { - const app: express.Express = express(); - resetHandler(config.mode); - // logging http access - if (config.logging != "none") { - app.use(morgan(config.logging)); - } - // const signal = require('./signaling'); - app.use(cors({origin: '*'})); - app.use(express.urlencoded({ extended: true })); - app.use(express.json()); - app.get('/config', (req, res) => res.json({ useWebSocket: config.type == 'websocket', startupMode: config.mode, logging: config.logging })); - app.use('/signaling', signaling); - app.use(express.static(path.join(__dirname, '../client/public'))); - app.use('/module', express.static(path.join(__dirname, '../client/src'))); - app.get('/', (req, res) => { - const indexPagePath: string = path.join(__dirname, '../client/public/index.html'); - fs.access(indexPagePath, (err) => { - if (err) { - log(LogLevel.warn, `Can't find file ' ${indexPagePath}`); - res.status(404).send(`Can't find file ${indexPagePath}`); - } else { - res.sendFile(indexPagePath); - } - }); - }); - // 初始化Swagger - initSwagger(app, config); - - // 配置multer存储 - const storage = multer.diskStorage({ - destination: function (req: any, file: any, cb: (error: Error | null, destination: string) => void) { - // 确保上传目录存在 - const uploadDir = path.join(__dirname, '../client/public/uploads/avatars'); - if (!fs.existsSync(uploadDir)) { - fs.mkdirSync(uploadDir, { recursive: true }); - } - cb(null, uploadDir); - }, - filename: function (req: any, file: any, cb: (error: Error | null, filename: string) => void) { - // 临时使用原始文件名,稍后在API处理中重命名 - cb(null, file.originalname); - } - }); - - const upload = multer({ storage: storage }); - - // 头像上传API - app.post('/api/upload/avatar', upload.single('avatar'), (req: any, res: express.Response) => { - if (!req.file) { - return res.status(400).json({ success: false, message: 'No file uploaded' }); - } - - const userId = req.body.userId || 'unknown'; - const ext = path.extname(req.file.originalname); - const oldPath = req.file.path; - const newFilename = `${userId}${ext}`; - const newPath = path.join(path.dirname(oldPath), newFilename); - - // 重命名文件 - fs.rename(oldPath, newPath, (err) => { - if (err) { - console.error('Error renaming file:', err); - return res.status(500).json({ success: false, message: '文件重命名失败' }); - } - - const avatarUrl = `/uploads/avatars/${newFilename}`; - res.json({ success: true, avatarUrl: avatarUrl }); - }); - }); - - // 确保uploads目录可访问 - app.use('/uploads', express.static(path.join(__dirname, '../client/public/uploads'))); - - return app; -}; diff --git a/WebApp/src/signaling.ts b/WebApp/src/signaling.ts deleted file mode 100644 index c523e82..0000000 --- a/WebApp/src/signaling.ts +++ /dev/null @@ -1,24 +0,0 @@ -import * as express from 'express'; -import * as handler from'./class/httphandler'; - -const router: express.Router = express.Router(); - -// 不需要会话ID的路由 -router.get('/connection-ids', handler.getAllConnectionIds); - -// 需要会话ID的路由 -router.use(handler.checkSessionId); -router.get('/connection', handler.getConnection); -router.get('/offer', handler.getOffer); -router.get('/answer', handler.getAnswer); -router.get('/candidate', handler.getCandidate); -router.get('', handler.getAll); -router.put('', handler.createSession); -router.delete('', handler.deleteSession); -router.put('/connection', handler.createConnection); -router.delete('/connection', handler.deleteConnection); -router.post('/offer', handler.postOffer); -router.post('/answer', handler.postAnswer); -router.post('/candidate', handler.postCandidate); - -export default router; diff --git a/WebApp/src/swagger.ts b/WebApp/src/swagger.ts deleted file mode 100644 index 0f2e16e..0000000 --- a/WebApp/src/swagger.ts +++ /dev/null @@ -1,64 +0,0 @@ -/** - * Swagger配置文件 - * 用于设置API文档的基本信息和路由 - */ -import * as swaggerJSDoc from 'swagger-jsdoc'; -import * as swaggerUi from 'swagger-ui-express'; -import { Express } from 'express'; -import Options from './class/options'; - -/** - * 初始化Swagger - * @param app Express应用实例 - * @param config 配置选项 - */ -export const initSwagger = (app: Express, config: Options): void => { - // 根据配置生成服务器URL - const protocol = config.secure ? 'https' : 'http'; - const port = config.port || 8080; - const serverUrl = `${protocol}://localhost:${port}`; - - /** - * Swagger配置选项 - */ - const swaggerOptions = { - definition: { - openapi: '3.0.0', - info: { - title: 'WebRTC Signaling API', - version: '1.0.0', - description: 'WebRTC信令服务器API文档', - contact: { - name: 'WebRTC Team', - email: 'contact@webrtc.example.com' - } - }, - servers: [ - { - url: serverUrl, - description: '本地开发服务器' - } - ], - components: { - securitySchemes: { - sessionAuth: { - type: 'apiKey', - in: 'header', - name: 'session-id', - description: '会话ID' - } - } - }, - security: [ - { - sessionAuth: [] - } - ] - }, - apis: ['./src/class/httphandler.ts', './src/signaling.ts'] - }; - - const swaggerSpec = swaggerJSDoc(swaggerOptions); - app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerSpec)); - console.log(`Swagger文档已初始化,访问 ${serverUrl}/api-docs 查看`); -}; diff --git a/WebApp/src/websocket.ts b/WebApp/src/websocket.ts deleted file mode 100644 index f92285c..0000000 --- a/WebApp/src/websocket.ts +++ /dev/null @@ -1,116 +0,0 @@ -import * as websocket from "ws"; -import { Server } from 'http'; -import * as handler from "./class/websockethandler"; - -export default class WSSignaling { - server: Server; - wss: websocket.Server; - - /** - * 构造函数,初始化WebSocket信令服务器 - * @param server HTTP服务器实例 - * @param mode 通信模式(public或private) - */ - constructor(server: Server, mode: string) { - // 保存服务器实例 - this.server = server; - // 创建WebSocket服务器 - this.wss = new websocket.Server({ server }); - // 重置处理器,设置通信模式 - handler.reset(mode); - - /** - * 监听WebSocket连接事件 - * @param ws WebSocket连接实例 - */ - this.wss.on('connection', (ws: WebSocket) => { - // 添加新的WebSocket连接到处理器 - handler.add(ws); - //handler.AddHeartbeat(ws); - /** - * 监听连接关闭事件 - */ - ws.onclose = (): void => { - // 从处理器中移除关闭的连接 - handler.remove(ws); - //handler.RemoveHeartbeat(ws); - }; - - /** - * 监听消息事件 - * @param event 消息事件对象 - */ - ws.onmessage = (event: MessageEvent): void => { - // 消息类型说明: - // 1. connect, disconnect 消息格式: - // { type: "connect", connectionId: "连接ID" } - // { type: "disconnect", connectionId: "连接ID" } - // 2. offer, answer, candidate 消息格式: - // { - // type: "offer", - // data: { - // from: "发送方连接ID", - // to: "接收方连接ID", - // data: "信令数据" - // } - // } - // 3. broadcast 消息格式: - // { - // type: "broadcast", - // message: "广播消息内容", - // targetConnectionId: "目标连接ID(可选)" - // } - - // 解析消息数据 - const msg = JSON.parse(event.data); - // 检查消息是否有效 - if (!msg || !this) { - return; - } - - // 打印接收到的消息 - console.log(msg); - - // 根据消息类型处理 - switch (msg.type) { - case "connect": - handler.onConnect(ws, msg.connectionId); - break; - case "disconnect": - handler.onDisconnect(ws, msg.connectionId); - break; - case "offer": - if (msg.participantId !== undefined) msg.data.participantId = msg.participantId; - handler.onOffer(ws, msg.data); - break; - case "answer": - if (msg.participantId !== undefined) msg.data.participantId = msg.participantId; - handler.onAnswer(ws, msg.data); - break; - case "candidate": - if (msg.participantId !== undefined) msg.data.participantId = msg.participantId; - handler.onCandidate(ws, msg.data); - break; - case "ping": - ws.send(JSON.stringify({ type: "pong" })); - break; - case "pong": - (ws as any).lastActivity = Date.now(); - break; - case "broadcast": - handler.onBroadcast(ws, msg.data); - break; - case 'call-request': - handler.onCallConnectionId(ws, msg.data); - break; - case 'on-message': - if (msg.from) msg.data.connectionId = msg.from; - handler.onMessage(ws, msg.data); - break; - default: - break; - } - }; - }); - } -} diff --git a/WebApp/src/服务端接口与WebSocket消息类型.md b/WebApp/src/服务端接口与WebSocket消息类型.md deleted file mode 100644 index a25bc91..0000000 --- a/WebApp/src/服务端接口与WebSocket消息类型.md +++ /dev/null @@ -1,561 +0,0 @@ -# 服务端接口与 WebSocket 消息类型 - -## 一、HTTP REST API 接口 - -### 1.1 配置接口 - -**GET /config** -- **功能**: 获取服务器配置信息 -- **参数**: 无 -- **响应**: - ```json - { - "useWebSocket": boolean, - "startupMode": string, - "logging": string - } - ``` - -### 1.2 头像上传接口 - -**POST /api/upload/avatar** -- **功能**: 上传用户头像 -- **参数**: - - `userId` (body): 用户ID - - `avatar` (file): 头像文件 -- **响应**: - ```json - { - "success": boolean, - "avatarUrl": string, - "message": string - } - ``` - -### 1.3 会话管理接口 - -**GET /signaling/connection-ids** -- **功能**: 获取所有活跃的连接ID(无需会话认证) -- **响应**: - ```json - { - "connectionIds": string[], - "totalCount": number - } - ``` - -**PUT /signaling** -- **功能**: 创建新的会话,获取会话ID -- **参数**: 无 -- **响应**: - ```json - { - "sessionId": string - } - ``` - -**GET /signaling** -- **功能**: 获取当前会话的所有信令消息 -- **认证**: 需要在请求头 `Session-Id` 中提供会话ID -- **参数**: - - `fromtime` (query): 起始时间戳,用于增量拉取 -- **响应**: - ```json - { - "messages": [ - { - "connectionId": string, - "type": "connect|disconnect|offer|answer|candidate", - "datetime": number, - "sdp": string, - "polite": boolean, - "candidate": string, - "sdpMLineIndex": number, - "sdpMid": string - } - ], - "datetime": number - } - ``` - -**DELETE /signaling** -- **功能**: 删除当前会话及其所有连接 -- **认证**: 需要会话ID -- **响应**: 200 OK - -### 1.4 连接管理接口 - -**GET /signaling/connection** -- **功能**: 获取当前会话的连接列表 -- **认证**: 需要会话ID -- **响应**: - ```json - { - "connections": [ - { - "connectionId": string, - "type": "connect", - "datetime": number - } - ] - } - ``` - -**PUT /signaling/connection** -- **功能**: 创建新的连接 -- **认证**: 需要会话ID -- **请求体**: - ```json - { - "connectionId": string - } - ``` -- **响应**: - ```json - { - "connectionId": string, - "polite": boolean, - "type": "connect", - "datetime": number - } - ``` - -**DELETE /signaling/connection** -- **功能**: 删除指定的连接 -- **认证**: 需要会话ID -- **请求体**: - ```json - { - "connectionId": string - } - ``` -- **响应**: - ```json - { - "connectionId": string - } - ``` - -### 1.5 WebRTC 信令交换接口 - -**GET /signaling/offer** -- **功能**: 获取 offer 信令消息列表 -- **认证**: 需要会话ID -- **参数**: `fromtime` (query): 起始时间戳 -- **响应**: - ```json - { - "offers": [ - { - "connectionId": string, - "sdp": string, - "polite": boolean, - "type": "offer", - "datetime": number - } - ] - } - ``` - -**POST /signaling/offer** -- **功能**: 发送 offer 信令 -- **认证**: 需要会话ID -- **请求体**: - ```json - { - "connectionId": string, - "sdp": string - } - ``` -- **响应**: 200 OK - -**GET /signaling/answer** -- **功能**: 获取 answer 信令消息列表 -- **认证**: 需要会话ID -- **参数**: `fromtime` (query): 起始时间戳 -- **响应**: - ```json - { - "answers": [ - { - "connectionId": string, - "sdp": string, - "type": "answer", - "datetime": number - } - ] - } - ``` - -**POST /signaling/answer** -- **功能**: 发送 answer 信令 -- **认证**: 需要会话ID -- **请求体**: - ```json - { - "connectionId": string, - "sdp": string - } - ``` -- **响应**: 200 OK - -**GET /signaling/candidate** -- **功能**: 获取 ICE candidate 信令消息列表 -- **认证**: 需要会话ID -- **参数**: `fromtime` (query): 起始时间戳 -- **响应**: - ```json - { - "candidates": [ - { - "connectionId": string, - "candidate": string, - "sdpMLineIndex": number, - "sdpMid": string, - "type": "candidate", - "datetime": number - } - ] - } - ``` - -**POST /signaling/candidate** -- **功能**: 发送 ICE candidate 信令 -- **认证**: 需要会话ID -- **请求体**: - ```json - { - "connectionId": string, - "candidate": string, - "sdpMLineIndex": number, - "sdpMid": string - } - ``` -- **响应**: 200 OK - -### 1.6 房间信息接口 - -**GET /signaling/rooms** -- **功能**: 获取房间和用户信息 -- **认证**: 需要会话ID -- **响应**: - ```json - { - "rooms": [ - { - "roomId": string, - "users": [ - { - "sessionId": string, - "connected": boolean - } - ], - "userCount": number - } - ], - "totalRooms": number - } - ``` - ---- - -## 二、WebSocket 消息类型 - -### 2.1 连接生命周期消息 - -#### connect(连接建立) - -- **方向**: 客户端 → 服务端 → 客户端 -- **客户端发送**: - ```json - { - "type": "connect", - "connectionId": string - } - ``` -- **服务端响应**: - ```json - { - "type": "connect", - "connectionId": string, - "polite": boolean, - "role": "host|participant", - "participantId": string - } - ``` -- **说明**: 建立连接并协商 polite 标志以处理连接冲突。`polite=true` 表示后加入方(participant),`polite=false` 表示先加入方(host)。 - -#### disconnect(连接断开) - -- **方向**: 客户端 → 服务端 → 客户端 -- **客户端发送**: - ```json - { - "type": "disconnect", - "connectionId": string - } - ``` -- **服务端响应**: - ```json - { - "type": "disconnect", - "connectionId": string, - "reason": "normal|host-left" - } - ``` -- **说明**: 断开连接。当 host 离开时,reason 为 `host-left`。 - -#### participant-joined(参与者加入,仅私有模式) - -- **方向**: 服务端 → host 客户端 -- **格式**: - ```json - { - "type": "participant-joined", - "connectionId": string, - "participantId": string - } - ``` -- **说明**: 通知 host 有新的 participant 加入。 - -#### participant-left(参与者离开,仅私有模式) - -- **方向**: 服务端 → host 客户端 / 其他 participants -- **格式**: - ```json - { - "type": "participant-left", - "connectionId": string, - "participantId": string - } - ``` -- **说明**: 通知有 participant 离开房间。 - -### 2.2 WebRTC SDP 交换消息 - -#### offer - -- **方向**: 双向 -- **格式**: - ```json - { - "type": "offer", - "from": string, - "to": string, - "data": { - "sdp": string, - "connectionId": string, - "participantId": string - }, - "participantId": string - } - ``` -- **路由规则**: - - **私有模式**: Host → 所有/特定 Participant;Participant → Host - - **公共模式**: Peer → 所有其他 Peers - -#### answer - -- **方向**: 双向 -- **格式**: - ```json - { - "type": "answer", - "from": string, - "to": string, - "data": { - "sdp": string, - "connectionId": string, - "participantId": string - }, - "participantId": string - } - ``` -- **路由规则**: - - **私有模式**: Participant → Host;Host → 特定 Participant - - **公共模式**: Peer → 特定 Peer - -#### candidate - -- **方向**: 双向 -- **格式**: - ```json - { - "type": "candidate", - "from": string, - "to": string, - "data": { - "candidate": string, - "sdpMLineIndex": number, - "sdpMid": string, - "connectionId": string, - "participantId": string - }, - "participantId": string - } - ``` -- **路由规则**: 与 answer 消息相同。 - -### 2.3 心跳/控制消息 - -#### ping(服务端 → 客户端) - -- **格式**: - ```json - { - "from": string, - "to": string, - "type": "on-message", - "data": { - "type": "ping" - } - } - ``` -- **说明**: 服务端心跳检测(可选功能,默认未启用)。 - -#### pong(客户端 → 服务端) - -- **格式**: - ```json - { - "type": "pong" - } - ``` -- **说明**: 心跳应答。 - -### 2.4 自定义消息 - -#### on-message(通用消息传递) - -- **方向**: 双向 -- **格式**: - ```json - { - "type": "on-message", - "from": string, - "to": string, - "data": { - "message": string|object, - "connectionId": string, - "senderId": string, - "participantId": string - } - } - ``` -- **路由规则**: - - **私有模式**: Host ↔ 所有 Participants;Participant ↔ Host - - **公共模式**: Peer → Peer -- **说明**: 传输文本、数据或聊天消息。 - -#### broadcast(广播消息) - -- **客户端发送**: - ```json - { - "type": "broadcast", - "message": string|object, - "targetConnectionId": string - } - ``` -- **服务端转发**: - ```json - { - "type": "broadcast", - "message": string|object, - "from": "server" - } - ``` -- **说明**: 若指定 `targetConnectionId`,则广播给该连接组内的所有成员;否则广播给所有连接的客户端。 - -### 2.5 呼叫请求消息 - -#### call-request - -- **方向**: 客户端 → 服务端 → 客户端 -- **格式**: - ```json - { - "type": "call-request", - "data": string - } - ``` -- **路由规则**: - - **私有模式**: Participant → Server → Host - - **公共模式**: Peer → Server → 所有其他 Peers -- **说明**: 发起呼叫请求。 - ---- - -## 三、通信模式说明 - -### 3.1 公共模式(Public Mode) - -- 所有连接的客户端都可以相互通信 -- offer/answer/candidate 向所有其他客户端广播 - -### 3.2 私有模式(Private Mode) - -- 一个 connectionId 对应一个房间,包含 1 个 host 和多个 participants -- Host 是第一个加入 connectionId 的客户端(`polite=false`) -- Participants 是后续加入的客户端(`polite=true`) -- Host 发送的消息可单播给特定 participant 或广播给所有 participants -- Participant 发送的消息仅发送给 host -- 当 host 离开时,整个房间关闭,所有 participants 被断开连接 -- 当 participant 离开时,房间继续存在 - ---- - -## 四、会话与连接管理 - -### 4.1 会话(Session) - -- 每个客户端通过 `PUT /signaling` 创建一个唯一的会话 -- 会话ID通过 `Session-Id` 请求头在所有后续 HTTP 请求中传递 -- 会话管理超时:10 秒无请求则自动删除会话 -- 一个会话可以包含多个连接ID - -### 4.2 连接(Connection) - -- 连接ID由客户端生成和指定 -- 在 HTTP 模式下,连接对通过 connectionId 自动配对 -- 在 WebSocket 私有模式下,第一个连接是 host,后续连接是 participants -- 一个连接对在私有模式下支持 1 对多(1 host + N participants) - -### 4.3 Polite 标志 - -- 用于处理 WebRTC 连接冲突(双方同时发送 offer 的情况) -- `polite=true`:该端应放弃 offer,接收来自另一端的 offer -- `polite=false`:该端具有优先权,可以发送 offer -- 私有模式下:host → `polite=false`,participants → `polite=true` - ---- - -## 五、关键设计特性 - -1. **双协议支持**: 同时支持 HTTP 轮询和 WebSocket 两种信令协议 -2. **两种通信模式**: 公共模式(全连通)和私有模式(1 对多房间) -3. **Polite 机制**: 自动处理并发 offer 冲突 -4. **会话隔离**: 通过 Session-ID 在 HTTP 模式下隔离不同客户端的消息 -5. **心跳检测**: 可选的心跳机制防止连接超时 -6. **消息增量拉取**: HTTP GET 支持 fromtime 参数实现增量消息获取 -7. **头像上传**: 内置文件上传功能支持用户头像管理 -8. **API 文档**: 集成 Swagger 提供自动生成的 API 文档 - ---- - -## 六、源文件路径 - -| 文件 | 功能 | -|------|------| -| `src/index.ts` | 应用入口,配置和启动服务器 | -| `src/server.ts` | Express 服务器创建,中间件配置 | -| `src/signaling.ts` | HTTP REST 路由定义 | -| `src/websocket.ts` | WebSocket 服务器和消息路由 | -| `src/class/httphandler.ts` | HTTP 处理器,核心业务逻辑 | -| `src/class/websockethandler.ts` | WebSocket 处理器,消息分发逻辑 | -| `src/class/offer.ts` | Offer 类定义 | -| `src/class/answer.ts` | Answer 类定义 | -| `src/class/candidate.ts` | Candidate 类定义 | -| `src/class/options.ts` | 配置选项接口 | -| `src/swagger.ts` | Swagger API 文档配置 | -| `src/log.ts` | 日志工具 | diff --git a/WebApp/test/env_macos.postman_environment.json b/WebApp/test/env_macos.postman_environment.json deleted file mode 100644 index 8d32ec8..0000000 --- a/WebApp/test/env_macos.postman_environment.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "id": "0ff4f10b-de1b-4376-bf88-c51b03b4d25b", - "name": "env_macos", - "values": [ - { - "key": "url", - "value": "localhost:8080", - "enabled": true - } - ], - "_postman_variable_scope": "environment", - "_postman_exported_at": "2019-07-06T09:29:02.003Z", - "_postman_exported_using": "Postman/7.2.2" -} \ No newline at end of file diff --git a/WebApp/test/httphandler.test.ts b/WebApp/test/httphandler.test.ts deleted file mode 100644 index 615eb31..0000000 --- a/WebApp/test/httphandler.test.ts +++ /dev/null @@ -1,509 +0,0 @@ -import { getMockReq, getMockRes } from '@jest-mock/express'; -import * as httpHandler from '../src/class/httphandler'; - -const RetriesToForceTimeout = 11; // Waits a second each time, timeout is 10 sec for httphandler. - -describe('http signaling test in public mode', () => { - const sessionId = "abcd1234"; - const sessionId2 = "abcd5678"; - const sessionId3 = "abcd9101112"; - const connectionId = "12345"; - const connectionId2 = "67890"; - const testsdp = "test sdp"; - - const { res, next, mockClear } = getMockRes(); - const req = getMockReq({ header: jest.fn(() => sessionId) }); - const req2 = getMockReq({ header: jest.fn(() => sessionId2) }); - const req3 = getMockReq({ header: jest.fn(() => sessionId3) }); - - beforeAll(() => { - httpHandler.reset("public"); - }); - - beforeEach(() => { - mockClear(); - httpHandler.checkSessionId(req, res, next); - httpHandler.checkSessionId(req2, res, next); - }); - - test('throw check has session', async () => { - httpHandler.checkSessionId(req, res, next); - expect(res.sendStatus).toHaveBeenCalledWith(404); - expect(next).not.toHaveBeenCalled(); - }); - - test('create session', async () => { - await httpHandler.createSession(sessionId, res); - expect(res.json).toHaveBeenCalledWith({ sessionId: sessionId }); - }); - - test('create session2', async () => { - await httpHandler.createSession(sessionId2, res); - expect(res.json).toHaveBeenCalledWith({ sessionId: sessionId2 }); - }); - - test('create connection from session1', async () => { - const body = { connectionId: connectionId }; - req.body = body; - await httpHandler.createConnection(req, res); - expect(res.json).toHaveBeenCalledWith({ connectionId: connectionId, polite: true, datetime: expect.anything(), type: "connect" }); - }); - - test('create connection from session2', async () => { - const body = { connectionId: connectionId2 }; - req2.body = body; - await httpHandler.createConnection(req2, res); - expect(res.json).toHaveBeenCalledWith({ connectionId: connectionId2, polite: true, datetime: expect.anything(), type: "connect" }); - }); - - test('get connection from session1', async () => { - await httpHandler.getConnection(req, res); - const connect = { connectionId: connectionId, datetime: expect.anything(), type: "connect" }; - expect(res.json).toHaveBeenCalledWith({ connections: expect.arrayContaining([connect]) }); - }); - - test('get all from session1', async () => { - await httpHandler.getAll(req, res); - const connect = { connectionId: connectionId, datetime: expect.anything(), type: "connect" }; - expect(res.json).toHaveBeenCalledWith({ messages: expect.arrayContaining([connect]), datetime: expect.anything() }); - }); - - test('post offer from session1', async () => { - const body = { connectionId: connectionId, sdp: testsdp, datetime: expect.anything(), type: "offer" }; - req.body = body; - await httpHandler.postOffer(req, res); - expect(res.sendStatus).toHaveBeenCalledWith(200); - }); - - test('get offer from session1', async () => { - await httpHandler.getOffer(req, res); - expect(res.json).toHaveBeenCalledWith({ offers: [] }); - }); - - test('get offer from session2', async () => { - await httpHandler.getOffer(req2, res); - expect(res.json).toHaveBeenCalledWith({ offers: [{ connectionId: connectionId, sdp: testsdp, polite: false, datetime: expect.anything(), type: "offer" }] }); - }); - - test('post answer from session2', async () => { - const body = { connectionId: connectionId, sdp: testsdp }; - req2.body = body; - await httpHandler.postAnswer(req2, res); - expect(res.sendStatus).toHaveBeenCalledWith(200); - }); - - test('get answer from session1', async () => { - await httpHandler.getAnswer(req, res); - expect(res.json).toHaveBeenCalledWith({ answers: [{ connectionId: connectionId, sdp: testsdp, datetime: expect.anything(), type: "answer" }] }); - }); - - test('get answer from session2', async () => { - await httpHandler.getAnswer(req2, res); - expect(res.json).toHaveBeenCalledWith({ answers: [] }); - }); - - test('post candidate from sesson1', async () => { - const body = { connectionId: connectionId, candidate: "testcandidate", sdpMLineIndex: 0, sdpMid: 0 }; - req.body = body; - await httpHandler.postCandidate(req, res); - expect(res.sendStatus).toHaveBeenCalledWith(200); - }); - - test('get candidate from session1', async () => { - await httpHandler.getCandidate(req, res); - expect(res.json).toHaveBeenCalledWith({ candidates: [] }); - }); - - test('get candidate from session2', async () => { - await httpHandler.getCandidate(req2, res); - expect(res.json).toHaveBeenCalledWith({ candidates: [{ connectionId: connectionId, candidate: "testcandidate", sdpMLineIndex: 0, sdpMid: 0, type: "candidate", datetime: expect.anything() }] }); - }); - - test('delete connection from session2', async () => { - const body = { connectionId: connectionId }; - req2.body = body; - await httpHandler.deleteConnection(req2, res); - expect(res.json).toHaveBeenCalledWith({ connectionId: connectionId }); - }); - - test('disconnection get from session1', async () => { - await httpHandler.getAll(req, res); - const disconnect = { connectionId: connectionId, datetime: expect.anything(), type: "disconnect" }; - expect(res.json).toHaveBeenCalledWith({ messages: expect.arrayContaining([disconnect]), datetime: expect.anything() }); - }); - - test('delete connection from session1', async () => { - const body = { connectionId: connectionId }; - req.body = body; - await httpHandler.deleteConnection(req, res); - expect(res.json).toHaveBeenCalledWith({ connectionId: connectionId }); - }); - - test('delete session1', async () => { - const req = getMockReq({ header: jest.fn(() => sessionId) }); - await httpHandler.deleteSession(req, res); - expect(res.sendStatus).toHaveBeenCalledWith(200); - }); - - test('delete session2', async () => { - const req2 = getMockReq({ header: jest.fn(() => sessionId2) }); - await httpHandler.deleteSession(req2, res); - expect(res.sendStatus).toHaveBeenCalledWith(200); - }); - - test('disconnection get when session2 disconnects before session1 answer', async () => { - httpHandler.reset("public"); - - await httpHandler.createSession(sessionId, res); - await httpHandler.createSession(sessionId2, res); - - await httpHandler.getAll(req, res); - expect(res.json).toHaveBeenLastCalledWith({ messages: [], datetime: expect.anything() }); - - const connectBody = { connectionId: connectionId }; - req.body = connectBody; - await httpHandler.createConnection(req, res); - - const offerBody = { connectionId: connectionId, sdp: testsdp, datetime: expect.anything(), type: "offer" }; - req.body = offerBody; - await httpHandler.postOffer(req, res); - - const offer = { connectionId: connectionId, sdp: testsdp, datetime: expect.anything(), type: "offer", polite: false }; - await httpHandler.getAll(req, res); - expect(res.json).toHaveBeenLastCalledWith({ messages: expect.not.arrayContaining([offer]), datetime: expect.anything() }); - await httpHandler.getAll(req2, res); - expect(res.json).toHaveBeenLastCalledWith({ messages: expect.arrayContaining([offer]), datetime: expect.anything() }); - - const deleteBody = { connectionId: connectionId }; - req2.body = deleteBody; - await httpHandler.deleteConnection(req, res); - await httpHandler.deleteSession(req, res); - expect(res.sendStatus).toHaveBeenLastCalledWith(200); - - const answerBody = { connectionId: connectionId, sdp: testsdp }; - req2.body = answerBody; - await httpHandler.postAnswer(req2, res); - - const disconnect = { connectionId: connectionId, type: "disconnect", datetime: expect.anything() }; - await httpHandler.getAll(req2, res); - expect(res.json).toHaveBeenLastCalledWith({ messages: expect.arrayContaining([disconnect]), datetime: expect.anything() }); - - await httpHandler.deleteSession(req2, res); - }); - - test('Timed out session2 deleted after session1 resends offer', async () => { - httpHandler.reset("public"); - - await httpHandler.createSession(sessionId, res); - await httpHandler.createSession(sessionId2, res); - - req.url = ""; - req2.url = ""; - await httpHandler.checkSessionId(req, res, next); - await httpHandler.checkSessionId(req2, res, next); - - await httpHandler.getAll(req, res); - expect(res.json).toHaveBeenLastCalledWith({ messages: [], datetime: expect.anything() }); - - const connectBody = { connectionId: connectionId }; - req.body = connectBody; - await httpHandler.createConnection(req, res); - - const offerBody = { connectionId: connectionId, sdp: testsdp, datetime: expect.anything(), type: "offer" }; - req.body = offerBody; - await httpHandler.postOffer(req, res); - - const offer = { connectionId: connectionId, sdp: testsdp, datetime: expect.anything(), type: "offer", polite: false }; - await httpHandler.getAll(req, res); - expect(res.json).toHaveBeenLastCalledWith({ messages: expect.not.arrayContaining([offer]), datetime: expect.anything() }); - await httpHandler.getAll(req2, res); - expect(res.json).toHaveBeenLastCalledWith({ messages: expect.arrayContaining([offer]), datetime: expect.anything() }); - - const answerBody = { connectionId: connectionId, sdp: testsdp }; - req2.body = answerBody; - await httpHandler.postAnswer(req2, res); - - // resend offer after answer to simulate PeerCandidate entering into failed state - req.body = offerBody; - await httpHandler.postOffer(req, res); - - // Wait a second and then checkSession for only session1 to force timeout of session2. - for (let i = 0; i < RetriesToForceTimeout + 1; ++i) - { - await httpHandler.checkSessionId(req, res, next); - await new Promise(resolve => setTimeout(resolve, 1000)); - } - - // Get all for session1 to trigger cleaning up associated session that timed out. - await httpHandler.getAll(req, res); - - // Check that we do have session1 still - await httpHandler.checkSessionId(req, res, next); - expect(res.sendStatus).toHaveBeenLastCalledWith(200); - - // Check that we no longer have session2 - await httpHandler.checkSessionId(req2, res, next); - expect(res.sendStatus).toHaveBeenLastCalledWith(404); - - await httpHandler.deleteSession(req, res); - }, 16000); - -test('Timed out sessions are deleted when other sessions check', async () => { - httpHandler.reset("public"); - - await httpHandler.createSession(sessionId, res); - await httpHandler.createSession(sessionId2, res); - await httpHandler.createSession(sessionId3, res); - - req.url = ""; - req2.url = ""; - req3.url = ""; - await httpHandler.checkSessionId(req, res, next); - await httpHandler.checkSessionId(req2, res, next); - await httpHandler.checkSessionId(req3, res, next); - - await httpHandler.getAll(req, res); - expect(res.json).toHaveBeenLastCalledWith({ messages: [], datetime: expect.anything() }); - - const connectBody = { connectionId: connectionId }; - req.body = connectBody; - await httpHandler.createConnection(req, res); - - const offerBody = { connectionId: connectionId, sdp: testsdp, datetime: expect.anything(), type: "offer" }; - req.body = offerBody; - await httpHandler.postOffer(req, res); - - const offer = { connectionId: connectionId, sdp: testsdp, datetime: expect.anything(), type: "offer", polite: false }; - await httpHandler.getAll(req, res); - expect(res.json).toHaveBeenLastCalledWith({ messages: expect.not.arrayContaining([offer]), datetime: expect.anything() }); - await httpHandler.getAll(req2, res); - expect(res.json).toHaveBeenLastCalledWith({ messages: expect.arrayContaining([offer]), datetime: expect.anything() }); - - const answerBody = { connectionId: connectionId, sdp: testsdp }; - req2.body = answerBody; - await httpHandler.postAnswer(req2, res); - - // Wait a second and then checkSession for only session3 to force timeout of session1 & session2. - for (let i = 0; i < RetriesToForceTimeout + 1; ++i) - { - await httpHandler.checkSessionId(req3, res, next); - await new Promise(resolve => setTimeout(resolve, 1000)); - } - - // Get all for session3 to trigger cleaning up sessions that timed out. - await httpHandler.getAll(req3, res); - - // Check that we do have session3 still - await httpHandler.checkSessionId(req3, res, next); - expect(res.sendStatus).toHaveBeenLastCalledWith(200); - - // Check that we do have session1 still - await httpHandler.checkSessionId(req, res, next); - expect(res.sendStatus).toHaveBeenLastCalledWith(404); - - // Check that we no longer have session2 - await httpHandler.checkSessionId(req2, res, next); - expect(res.sendStatus).toHaveBeenLastCalledWith(404); - - await httpHandler.deleteSession(req3, res); -}, 16000); -}); - -describe('http signaling test in private mode', () => { - const sessionId = "abcd1234"; - const sessionId2 = "abcd5678"; - const connectionId = "12345"; - const testsdp = "test sdp"; - - const { res, next, mockClear } = getMockRes(); - const req = getMockReq({ header: jest.fn(() => sessionId) }); - const req2 = getMockReq({ header: jest.fn(() => sessionId2) }); - - beforeAll(() => { - httpHandler.reset("private"); - }); - - beforeEach(() => { - mockClear(); - - httpHandler.checkSessionId(req, res, next); - httpHandler.checkSessionId(req2, res, next); - }); - - test('throw check has session', async () => { - httpHandler.checkSessionId(req, res, next); - expect(res.sendStatus).toHaveBeenCalledWith(404); - expect(next).not.toHaveBeenCalled(); - }); - - test('create session', async () => { - await httpHandler.createSession(sessionId, res); - expect(res.json).toHaveBeenCalledWith({ sessionId: sessionId }); - }); - - test('create session2', async () => { - await httpHandler.createSession(sessionId2, res); - expect(res.json).toHaveBeenCalledWith({ sessionId: sessionId2 }); - }); - - test('create connection from session1', async () => { - const body = { connectionId: connectionId }; - req.body = body; - await httpHandler.createConnection(req, res); - expect(res.json).toHaveBeenCalledWith({ connectionId: connectionId, polite: false, datetime: expect.anything(), type: "connect" }); - }); - - test('create connection from session2', async () => { - const body = { connectionId: connectionId }; - req2.body = body; - await httpHandler.createConnection(req2, res); - expect(res.json).toHaveBeenCalledWith({ connectionId: connectionId, polite: true, datetime: expect.anything(), type: "connect" }); - }); - - test('response status 400 if connecctionId does not set', async () => { - const req3 = getMockReq({ header: jest.fn(() => sessionId) }); - await httpHandler.createConnection(req3, res); - expect(res.status).toHaveBeenCalledWith(400); - expect(res.send).toHaveBeenCalledWith({ error: new Error(`connectionId is required`) }); - }); - - test('response status 400 if aleady used connection', async () => { - const sessionId3 = "session3"; - await httpHandler.createSession(sessionId3, res); - const body = { connectionId: connectionId }; - const req3 = getMockReq({ header: jest.fn(() => sessionId3) }); - req3.body = body; - await httpHandler.createConnection(req3, res); - expect(res.status).toHaveBeenCalledWith(400); - expect(res.send).toHaveBeenCalledWith({ error: new Error(`${connectionId}: This connection id is already used.`) }); - }); - - test('not connection get from session1', async () => { - await httpHandler.getConnection(req, res); - expect(res.json).toHaveBeenCalledWith({ connections: [{ connectionId: connectionId, datetime: expect.anything(), type: "connect" }] }); - }); - - test('post offer from session1', async () => { - const body = { connectionId: connectionId, sdp: testsdp, datetime: expect.anything(), type: "offer" }; - req.body = body; - await httpHandler.postOffer(req, res); - expect(res.sendStatus).toHaveBeenCalledWith(200); - }); - - test('get offer from session1', async () => { - await httpHandler.getOffer(req, res); - expect(res.json).toHaveBeenCalledWith({ offers: [] }); - }); - - test('get offer from session2', async () => { - await httpHandler.getOffer(req2, res); - expect(res.json).toHaveBeenCalledWith({ offers: [{ connectionId: connectionId, sdp: testsdp, polite: true, datetime: expect.anything(), type: "offer" }] }); - }); - - test('post answer from session2', async () => { - const body = { connectionId: connectionId, sdp: testsdp }; - req2.body = body; - await httpHandler.postAnswer(req2, res); - expect(res.sendStatus).toHaveBeenCalledWith(200); - }); - - test('get answer from session1', async () => { - await httpHandler.getAnswer(req, res); - expect(res.json).toHaveBeenCalledWith({ answers: [{ connectionId: connectionId, sdp: testsdp, datetime: expect.anything(), type: "answer" }] }); - }); - - test('get answer from session2', async () => { - await httpHandler.getAnswer(req2, res); - expect(res.json).toHaveBeenCalledWith({ answers: [] }); - }); - - test('post candidate from sesson1', async () => { - const body = { connectionId: connectionId, candidate: "testcandidate", sdpMLineIndex: 0, sdpMid: 0 }; - req.body = body; - await httpHandler.postCandidate(req, res); - expect(res.sendStatus).toHaveBeenCalledWith(200); - }); - - test('get candidate from session1', async () => { - await httpHandler.getCandidate(req, res); - expect(res.json).toHaveBeenCalledWith({ candidates: [] }); - }); - - test('get candidate from session2', async () => { - await httpHandler.getCandidate(req2, res); - expect(res.json).toHaveBeenCalledWith({ candidates: [{ connectionId: connectionId, candidate: "testcandidate", sdpMLineIndex: 0, sdpMid: 0, type: "candidate", datetime: expect.anything() }] }); - }); - - test('delete connection from session2', async () => { - const body = { connectionId: connectionId }; - req2.body = body; - await httpHandler.deleteConnection(req2, res); - expect(res.json).toHaveBeenCalledWith({ connectionId: connectionId }); - }); - - test('get connection from session1', async () => { - await httpHandler.getConnection(req, res); - expect(res.json).toHaveBeenCalledWith({ connections: [] }); - }); - - test('delete connection from session1', async () => { - const body = { connectionId: connectionId }; - req.body = body; - await httpHandler.deleteConnection(req, res); - expect(res.json).toHaveBeenCalledWith({ connectionId: connectionId }); - }); - - test('delete session1', async () => { - const req = getMockReq({ header: jest.fn(() => sessionId) }); - await httpHandler.deleteSession(req, res); - expect(res.sendStatus).toHaveBeenCalledWith(200); - }); - - test('delete session2', async () => { - const req2 = getMockReq({ header: jest.fn(() => sessionId2) }); - await httpHandler.deleteSession(req2, res); - expect(res.sendStatus).toHaveBeenCalledWith(200); - }); - - test('disconnection get when session2 disconnects before session1 answer', async () => { - httpHandler.reset("private"); - - await httpHandler.createSession(sessionId, res); - await httpHandler.createSession(sessionId2, res); - - await httpHandler.getAll(req, res); - expect(res.json).toHaveBeenLastCalledWith({ messages: [], datetime: expect.anything() }); - - const connectBody = { connectionId: connectionId }; - req.body = connectBody; - await httpHandler.createConnection(req, res); - req2.body = connectBody; - await httpHandler.createConnection(req2, res); - - const offerBody = { connectionId: connectionId, sdp: testsdp, datetime: expect.anything(), type: "offer" }; - req.body = offerBody; - await httpHandler.postOffer(req, res); - - const offer = { connectionId: connectionId, sdp: testsdp, datetime: expect.anything(), type: "offer", polite: true }; - await httpHandler.getAll(req, res); - expect(res.json).toHaveBeenLastCalledWith({ messages: expect.not.arrayContaining([offer]), datetime: expect.anything() }); - await httpHandler.getAll(req2, res); - expect(res.json).toHaveBeenLastCalledWith({ messages: expect.arrayContaining([offer]), datetime: expect.anything() }); - - const deleteBody = { connectionId: connectionId }; - req2.body = deleteBody; - await httpHandler.deleteConnection(req, res); - await httpHandler.deleteSession(req, res); - expect(res.sendStatus).toHaveBeenLastCalledWith(200); - - const answerBody = { connectionId: connectionId, sdp: testsdp }; - req2.body = answerBody; - await httpHandler.postAnswer(req2, res); - - const disconnect = { connectionId: connectionId, type: "disconnect", datetime: expect.anything() }; - await httpHandler.getAll(req2, res); - expect(res.json).toHaveBeenLastCalledWith({ messages: expect.arrayContaining([disconnect]), datetime: expect.anything() }); - - await httpHandler.deleteSession(req2, res); - }); -}); diff --git a/WebApp/test/renderstreaming.postman_collection.json b/WebApp/test/renderstreaming.postman_collection.json deleted file mode 100644 index 96287cb..0000000 --- a/WebApp/test/renderstreaming.postman_collection.json +++ /dev/null @@ -1,1122 +0,0 @@ -{ - "info": { - "_postman_id": "81f69f19-4db2-4baa-8210-c4a72f326a47", - "name": "renderstreaming", - "description": "# Introduction\nWhat does your API do?\n\n# Overview\nThings that the developers should know about\n\n# Authentication\nWhat is the preferred way of using the API?\n\n# Error Codes\nWhat errors and status codes can a user expect?\n\n# Rate limit\nIs there a limit to the number of requests an user can send?", - "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", - "_exporter_id": "837833" - }, - "item": [ - { - "name": "Create Session1", - "event": [ - { - "listen": "test", - "script": { - "exec": [ - "pm.test(\"Status code is 200\", function () { pm.response.to.have.status(200); });", - "pm.test(\"The response has a valid JSON body\", function () {", - " pm.response.to.be.json;", - " var jsonData = pm.response.json();", - " pm.response.to.have.jsonBody(\"sessionId\");", - "});", - "pm.environment.set(\"session_Id\", pm.response.json().sessionId);" - ], - "type": "text/javascript" - } - } - ], - "request": { - "method": "PUT", - "header": [], - "body": { - "mode": "raw", - "raw": "" - }, - "url": { - "raw": "http://{{url}}/signaling", - "protocol": "http", - "host": [ - "{{url}}" - ], - "path": [ - "signaling" - ] - } - }, - "response": [] - }, - { - "name": "Create Session2", - "event": [ - { - "listen": "test", - "script": { - "exec": [ - "pm.test(\"Status code is 200\", function () { pm.response.to.have.status(200); });", - "pm.test(\"The response has a valid JSON body\", function () {", - " pm.response.to.be.json;", - " var jsonData = pm.response.json();", - " pm.response.to.have.jsonBody(\"sessionId\");", - "});", - "pm.environment.set(\"session_Id2\", pm.response.json().sessionId);" - ], - "type": "text/javascript" - } - } - ], - "request": { - "method": "PUT", - "header": [], - "body": { - "mode": "raw", - "raw": "" - }, - "url": { - "raw": "http://{{url}}/signaling", - "protocol": "http", - "host": [ - "{{url}}" - ], - "path": [ - "signaling" - ] - } - }, - "response": [] - }, - { - "name": "Create Connection", - "event": [ - { - "listen": "test", - "script": { - "exec": [ - "pm.test(\"Status code is 200\", function () { pm.response.to.have.status(200); });", - "pm.test(\"The response has a valid JSON body\", function () {", - " pm.response.to.be.json;", - " var jsonData = pm.response.json();", - " pm.response.to.have.jsonBody(\"connectionId\");", - " pm.response.to.have.jsonBody(\"polite\");", - " console.log(jsonData);", - " pm.expect(jsonData.polite).to.be.true;", - "});", - "pm.environment.set(\"connection_id\", JSON.stringify(pm.response.json().connectionId));" - ], - "type": "text/javascript" - } - } - ], - "request": { - "method": "PUT", - "header": [ - { - "key": "Content-Type", - "value": "application/json", - "type": "text" - }, - { - "key": "Session-Id", - "value": "{{session_Id}}", - "type": "text" - } - ], - "body": { - "mode": "raw", - "raw": "{\r\n\t\"connectionId\": \"b808d31f-e22b-4ee8-85fb-4c4b587f8065\"\r\n}" - }, - "url": { - "raw": "http://{{url}}/signaling/connection", - "protocol": "http", - "host": [ - "{{url}}" - ], - "path": [ - "signaling", - "connection" - ] - } - }, - "response": [] - }, - { - "name": "Post Offer from Session1", - "event": [ - { - "listen": "prerequest", - "script": { - "exec": [ - "" - ], - "type": "text/javascript" - } - }, - { - "listen": "test", - "script": { - "exec": [ - "pm.test(\"Status code is 200\", function () { pm.response.to.have.status(200); });", - "" - ], - "type": "text/javascript" - } - } - ], - "request": { - "method": "POST", - "header": [ - { - "key": "Content-Type", - "name": "Content-Type", - "value": "application/json", - "type": "text" - }, - { - "key": "Session-Id", - "value": "{{session_Id}}", - "type": "text" - } - ], - "body": { - "mode": "raw", - "raw": "{\t\n\t\"connectionId\": {{connection_id}},\n \"sdp\" : {{sdp}}\n}" - }, - "url": { - "raw": "http://{{url}}/signaling/offer", - "protocol": "http", - "host": [ - "{{url}}" - ], - "path": [ - "signaling", - "offer" - ] - } - }, - "response": [ - { - "name": "Default", - "originalRequest": { - "method": "POST", - "header": [], - "body": { - "mode": "raw", - "raw": "" - }, - "url": { - "raw": "offer", - "host": [ - "offer" - ] - } - }, - "code": 200, - "_postman_previewlanguage": "Text", - "header": [], - "cookie": [], - "body": "" - } - ] - }, - { - "name": "Post Answer from Session2", - "event": [ - { - "listen": "prerequest", - "script": { - "exec": [ - "" - ], - "type": "text/javascript" - } - }, - { - "listen": "test", - "script": { - "exec": [ - "pm.test(\"Status code is 200\", function () { pm.response.to.have.status(200); });" - ], - "type": "text/javascript" - } - } - ], - "request": { - "method": "POST", - "header": [ - { - "key": "Content-Type", - "name": "Content-Type", - "type": "text", - "value": "application/json" - }, - { - "key": "Session-Id", - "type": "text", - "value": "{{session_Id2}}" - } - ], - "body": { - "mode": "raw", - "raw": "{\n\t\"connectionId\": {{connection_id}},\n\t\"sdp\" : {{sdp}}\n}" - }, - "url": { - "raw": "http://{{url}}/signaling/answer", - "protocol": "http", - "host": [ - "{{url}}" - ], - "path": [ - "signaling", - "answer" - ] - } - }, - "response": [ - { - "name": "Default", - "originalRequest": { - "method": "POST", - "header": [], - "body": { - "mode": "raw", - "raw": "" - }, - "url": { - "raw": "offer", - "host": [ - "offer" - ] - } - }, - "code": 200, - "_postman_previewlanguage": "Text", - "header": [], - "cookie": [], - "body": "" - } - ] - }, - { - "name": "Post Candidate from Session1", - "event": [ - { - "listen": "test", - "script": { - "exec": [ - "pm.test(\"Status code is 200\", function () { pm.response.to.have.status(200); });" - ], - "type": "text/javascript" - } - } - ], - "request": { - "method": "POST", - "header": [ - { - "key": "Content-Type", - "name": "Content-Type", - "type": "text", - "value": "application/json" - }, - { - "key": "Session-Id", - "type": "text", - "value": "{{session_Id}}" - } - ], - "body": { - "mode": "raw", - "raw": "{\n\t\"connectionId\": {{connection_id}},\n\t\"candidate\" : {{candidate}}\n}" - }, - "url": { - "raw": "http://{{url}}/signaling/candidate", - "protocol": "http", - "host": [ - "{{url}}" - ], - "path": [ - "signaling", - "candidate" - ] - } - }, - "response": [ - { - "name": "Default", - "originalRequest": { - "method": "POST", - "header": [], - "body": { - "mode": "raw", - "raw": "" - }, - "url": { - "raw": "icecandidate", - "host": [ - "icecandidate" - ] - } - }, - "code": 200, - "_postman_previewlanguage": "Text", - "header": [], - "cookie": [], - "body": "" - } - ] - }, - { - "name": "Get Top index.html", - "event": [ - { - "listen": "test", - "script": { - "exec": [ - "pm.test(\"Status code is 200\", function () { pm.response.to.have.status(200); });" - ], - "type": "text/javascript" - } - } - ], - "request": { - "method": "GET", - "header": [], - "url": { - "raw": "http://{{url}}", - "protocol": "http", - "host": [ - "{{url}}" - ] - } - }, - "response": [] - }, - { - "name": "Get Connection", - "event": [ - { - "listen": "test", - "script": { - "exec": [ - "pm.test(\"Status code is 200\", function () { pm.response.to.have.status(200); });", - "pm.test(\"The response has a valid JSON body\", function () {", - " pm.response.to.be.json;", - " pm.response.to.have.jsonBody(\"connections\");", - " var jsonData = pm.response.json();", - " console.log(jsonData);", - " pm.expect(jsonData.connections.length).to.be.above(0);", - " var connection = jsonData.connections[0];", - " pm.expect(connection.connectionId).to.be.not.null;", - "});", - "" - ], - "type": "text/javascript" - } - } - ], - "request": { - "method": "GET", - "header": [ - { - "key": "Session-Id", - "type": "text", - "value": "{{session_Id}}" - } - ], - "url": { - "raw": "http://{{url}}/signaling/connection", - "protocol": "http", - "host": [ - "{{url}}" - ], - "path": [ - "signaling", - "connection" - ] - } - }, - "response": [] - }, - { - "name": "Get Offer to Session1", - "event": [ - { - "listen": "test", - "script": { - "exec": [ - "pm.test(\"Status code is 200\", function () { pm.response.to.have.status(200); });", - "pm.test(\"The response has a valid JSON body\", function () {", - " pm.response.to.be.json;", - " pm.response.to.have.jsonBody(\"offers\");", - " var jsonData = pm.response.json();", - " console.log(jsonData);", - " pm.expect(jsonData.offers.length).to.be.equal(0);", - "});", - "" - ], - "type": "text/javascript" - } - } - ], - "request": { - "method": "GET", - "header": [ - { - "key": "Session-Id", - "type": "text", - "value": "{{session_Id}}" - } - ], - "url": { - "raw": "http://{{url}}/signaling/offer", - "protocol": "http", - "host": [ - "{{url}}" - ], - "path": [ - "signaling", - "offer" - ] - } - }, - "response": [] - }, - { - "name": "Get Offer to Session2", - "event": [ - { - "listen": "test", - "script": { - "exec": [ - "pm.test(\"Status code is 200\", function () { pm.response.to.have.status(200); });", - "pm.test(\"The response has a valid JSON body\", function () {", - " pm.response.to.be.json;", - " pm.response.to.have.jsonBody(\"offers\");", - " var jsonData = pm.response.json();", - " console.log(jsonData);", - " pm.expect(jsonData.offers.length).to.be.above(0);", - " var offer = jsonData.offers[0];", - " pm.expect(offer.connectionId).to.be.not.null;", - " pm.expect(offer.sdp).to.be.not.null;", - " pm.expect(offer.polite).to.be.not.null;", - "});", - "" - ], - "type": "text/javascript" - } - } - ], - "request": { - "method": "GET", - "header": [ - { - "key": "Session-Id", - "type": "text", - "value": "{{session_Id2}}" - } - ], - "url": { - "raw": "http://{{url}}/signaling/offer", - "protocol": "http", - "host": [ - "{{url}}" - ], - "path": [ - "signaling", - "offer" - ] - } - }, - "response": [] - }, - { - "name": "Get Offer to Session1 fromtime={{datetime}}", - "event": [ - { - "listen": "test", - "script": { - "exec": [ - "pm.test(\"Status code is 200\", function () { pm.response.to.have.status(200); });", - "pm.test(\"The response has a valid JSON body\", function () {", - " pm.response.to.be.json;", - " pm.response.to.have.jsonBody(\"offers\");", - " var jsonData = pm.response.json();", - " console.log(jsonData);", - " pm.expect(jsonData.offers.length).to.be.equal(0);", - "});", - "" - ], - "type": "text/javascript" - } - }, - { - "listen": "prerequest", - "script": { - "exec": [ - "// datetime in the future", - "let datetime = Date.now() + 30;", - "pm.environment.set(\"datetime\", datetime);" - ], - "type": "text/javascript" - } - } - ], - "request": { - "method": "GET", - "header": [ - { - "key": "Session-Id", - "type": "text", - "value": "{{session_Id}}" - } - ], - "url": { - "raw": "http://{{url}}/signaling/offer?fromtime={{datetime}}", - "protocol": "http", - "host": [ - "{{url}}" - ], - "path": [ - "signaling", - "offer" - ], - "query": [ - { - "key": "fromtime", - "value": "{{datetime}}" - } - ] - } - }, - "response": [] - }, - { - "name": "Get Answer to Session1", - "event": [ - { - "listen": "test", - "script": { - "exec": [ - "pm.test(\"Status code is 200\", function () { pm.response.to.have.status(200); });", - "pm.test(\"The response has a valid JSON body\", function () {", - " pm.response.to.be.json;", - " pm.response.to.have.jsonBody(\"answers\");", - " var jsonData = pm.response.json();", - " console.log(jsonData);", - " pm.expect(jsonData.answers.length).to.be.above(0);", - " var answer = jsonData.answers[0];", - " pm.expect(answer.connectionId).to.be.not.null;", - " pm.expect(answer.sdp).to.be.not.null;", - "});", - "" - ], - "type": "text/javascript" - } - } - ], - "request": { - "method": "GET", - "header": [ - { - "key": "Session-Id", - "type": "text", - "value": "{{session_Id}}" - } - ], - "url": { - "raw": "http://{{url}}/signaling/answer", - "protocol": "http", - "host": [ - "{{url}}" - ], - "path": [ - "signaling", - "answer" - ] - } - }, - "response": [] - }, - { - "name": "Get Answer to Session2", - "event": [ - { - "listen": "test", - "script": { - "exec": [ - "pm.test(\"Status code is 200\", function () { pm.response.to.have.status(200); });", - "pm.test(\"The response has a valid JSON body\", function () {", - " pm.response.to.be.json;", - " pm.response.to.have.jsonBody(\"answers\");", - " var jsonData = pm.response.json();", - " console.log(jsonData);", - " pm.expect(jsonData.answers.length).to.be.equal(0);", - "});", - "" - ], - "type": "text/javascript" - } - } - ], - "request": { - "method": "GET", - "header": [ - { - "key": "Session-Id", - "type": "text", - "value": "{{session_Id2}}" - } - ], - "url": { - "raw": "http://{{url}}/signaling/answer", - "protocol": "http", - "host": [ - "{{url}}" - ], - "path": [ - "signaling", - "answer" - ] - } - }, - "response": [] - }, - { - "name": "Get Answer to Session1 fromtime={{datetime}}", - "event": [ - { - "listen": "test", - "script": { - "exec": [ - "pm.test(\"Status code is 200\", function () { pm.response.to.have.status(200); });", - "pm.test(\"The response has a valid JSON body\", function () {", - " pm.response.to.be.json;", - " pm.response.to.have.jsonBody(\"answers\");", - " var jsonData = pm.response.json();", - " console.log(jsonData);", - " pm.expect(jsonData.answers.length).to.be.equal(0);", - "});", - "" - ], - "type": "text/javascript" - } - }, - { - "listen": "prerequest", - "script": { - "exec": [ - "// datetime in the future", - "let datetime = Date.now() + 30;", - "pm.environment.set(\"datetime\", datetime);" - ], - "type": "text/javascript" - } - } - ], - "request": { - "method": "GET", - "header": [ - { - "key": "Session-Id", - "type": "text", - "value": "{{session_Id}}" - } - ], - "url": { - "raw": "http://{{url}}/signaling/answer?fromtime={{datetime}}", - "protocol": "http", - "host": [ - "{{url}}" - ], - "path": [ - "signaling", - "answer" - ], - "query": [ - { - "key": "fromtime", - "value": "{{datetime}}" - } - ] - } - }, - "response": [] - }, - { - "name": "Get Candidate to Session2", - "event": [ - { - "listen": "test", - "script": { - "exec": [ - "pm.test(\"Status code is 200\", function () { pm.response.to.have.status(200); });", - "pm.test(\"The response has a valid JSON body\", function () {", - " pm.response.to.be.json;", - " pm.response.to.have.jsonBody(\"candidates\");", - " var jsonData = pm.response.json();", - " console.log(jsonData);", - " pm.expect(jsonData.candidates.length).to.be.above(0);", - " pm.expect(jsonData.candidates[0].connectionId).to.not.equal(null);", - " pm.expect(jsonData.candidates[0].candidates).to.not.equal(null);", - "});", - "" - ], - "type": "text/javascript" - } - } - ], - "request": { - "method": "GET", - "header": [ - { - "key": "Session-Id", - "value": "{{session_Id2}}", - "type": "text" - } - ], - "url": { - "raw": "http://{{url}}/signaling/candidate", - "protocol": "http", - "host": [ - "{{url}}" - ], - "path": [ - "signaling", - "candidate" - ] - } - }, - "response": [] - }, - { - "name": "Get Candidate to Session1 fromtime={{datetime}}", - "event": [ - { - "listen": "test", - "script": { - "exec": [ - "pm.test(\"Status code is 200\", function () { pm.response.to.have.status(200); });", - "pm.test(\"The response has a valid JSON body\", function () {", - " pm.response.to.be.json;", - " pm.response.to.have.jsonBody(\"candidates\");", - " var jsonData = pm.response.json();", - " console.log(jsonData);", - " pm.expect(jsonData.candidates.length).to.be.equal(0);", - "});", - "" - ], - "type": "text/javascript" - } - }, - { - "listen": "prerequest", - "script": { - "exec": [ - "// datetime in the future", - "let datetime = Date.now() + 30;", - "pm.environment.set(\"datetime\", datetime);" - ], - "type": "text/javascript" - } - } - ], - "request": { - "method": "GET", - "header": [ - { - "key": "Session-Id", - "type": "text", - "value": "{{session_Id}}" - } - ], - "url": { - "raw": "http://{{url}}/signaling/candidate?fromtime={{datetime}}", - "protocol": "http", - "host": [ - "{{url}}" - ], - "path": [ - "signaling", - "candidate" - ], - "query": [ - { - "key": "fromtime", - "value": "{{datetime}}" - } - ] - } - }, - "response": [] - }, - { - "name": "Get All fromtime={{datetime}}", - "event": [ - { - "listen": "test", - "script": { - "exec": [ - "pm.test(\"Status code is 200\", function () { pm.response.to.have.status(200); });", - "pm.test(\"The response has a valid JSON body\", function () {", - " pm.response.to.be.json;", - " pm.response.to.have.jsonBody(\"messages\");", - " pm.response.to.have.jsonBody(\"datetime\");", - " var jsonData = pm.response.json();", - " console.log(jsonData);", - " pm.expect(jsonData.messages.length).to.be.above(0);", - "});", - "" - ], - "type": "text/javascript" - } - }, - { - "listen": "prerequest", - "script": { - "exec": [ - "// datetime in the future", - "let datetime = Date.now() + 30;", - "pm.environment.set(\"datetime\", datetime);" - ], - "type": "text/javascript" - } - } - ], - "request": { - "method": "GET", - "header": [ - { - "key": "Session-Id", - "type": "text", - "value": "{{session_Id}}" - } - ], - "url": { - "raw": "http://{{url}}/signaling?fromtime={{datetime}}", - "protocol": "http", - "host": [ - "{{url}}" - ], - "path": [ - "signaling" - ], - "query": [ - { - "key": "fromtime", - "value": "{{datetime}}" - } - ] - } - }, - "response": [] - }, - { - "name": "Get Config", - "event": [ - { - "listen": "test", - "script": { - "exec": [ - "pm.test(\"Status code is 200\", function () { pm.response.to.have.status(200); });", - "pm.test(\"The response has a valid JSON body\", function () {", - " pm.response.to.be.json;", - " var jsonData = pm.response.json();", - " console.log(jsonData);", - " pm.response.to.have.jsonBody(\"useWebSocket\");", - " pm.response.to.have.jsonBody(\"startupMode\");", - " pm.response.to.have.jsonBody(\"logging\");", - "});", - "" - ], - "type": "text/javascript" - } - } - ], - "request": { - "method": "GET", - "header": [], - "url": { - "raw": "http://{{url}}/config", - "protocol": "http", - "host": [ - "{{url}}" - ], - "path": [ - "config" - ] - } - }, - "response": [] - }, - { - "name": "Delete Connection", - "event": [ - { - "listen": "test", - "script": { - "exec": [ - "pm.test(\"Status code is 200\", function () { pm.response.to.have.status(200); });" - ], - "type": "text/javascript" - } - } - ], - "request": { - "method": "DELETE", - "header": [ - { - "key": "Content-Type", - "type": "text", - "value": "application/json" - }, - { - "key": "Session-Id", - "type": "text", - "value": "{{session_Id}}" - } - ], - "body": { - "mode": "raw", - "raw": "{\t\n\t\"connectionId\": {{connection_id}}\n}" - }, - "url": { - "raw": "http://{{url}}/signaling/connection", - "protocol": "http", - "host": [ - "{{url}}" - ], - "path": [ - "signaling", - "connection" - ] - } - }, - "response": [] - }, - { - "name": "Delete Session1", - "event": [ - { - "listen": "test", - "script": { - "exec": [ - "pm.test(\"Status code is 200\", function () { pm.response.to.have.status(200); });" - ], - "type": "text/javascript" - } - } - ], - "request": { - "method": "DELETE", - "header": [ - { - "key": "Session-Id", - "type": "text", - "value": "{{session_Id}}" - } - ], - "body": { - "mode": "raw", - "raw": "" - }, - "url": { - "raw": "http://{{url}}/signaling", - "protocol": "http", - "host": [ - "{{url}}" - ], - "path": [ - "signaling" - ] - } - }, - "response": [] - }, - { - "name": "Delete Session2", - "event": [ - { - "listen": "test", - "script": { - "exec": [ - "pm.test(\"Status code is 200\", function () { pm.response.to.have.status(200); });" - ], - "type": "text/javascript" - } - } - ], - "request": { - "method": "DELETE", - "header": [ - { - "key": "Session-Id", - "type": "text", - "value": "{{session_Id2}}" - } - ], - "body": { - "mode": "raw", - "raw": "" - }, - "url": { - "raw": "http://{{url}}/signaling", - "protocol": "http", - "host": [ - "{{url}}" - ], - "path": [ - "signaling" - ] - } - }, - "response": [] - } - ], - "event": [ - { - "listen": "prerequest", - "script": { - "type": "text/javascript", - "exec": [ - "" - ] - } - }, - { - "listen": "test", - "script": { - "type": "text/javascript", - "exec": [ - "" - ] - } - } - ], - "variable": [ - { - "key": "url", - "value": "localhost:8080", - "type": "string" - }, - { - "key": "session_Id", - "value": "", - "type": "string" - }, - { - "key": "sdp", - "value": "\"v=0\\r\\no=- 7060022371716902156 2 IN IP4 127.0.0.1\\r\\ns=-\\r\\nt=0 0\\r\\na=group:BUNDLE 0\\r\\na=msid-semantic: WMS 3fd630e8-9285-4f82-adbc-a7e31c334740\\r\\nm=audio 9 UDP\\/TLS\\/RTP\\/SAVPF 111 103 104 9 0 8 110 112 113 126\\r\\nc=IN IP4 0.0.0.0\\r\\na=rtcp:9 IN IP4 0.0.0.0\\r\\na=ice-ufrag:yOxE\\r\\na=ice-pwd:Ekoek1dl79NlWZS2dfmrW7Cr\\r\\na=ice-options:trickle\\r\\na=fingerprint:sha-256 02:F8:39:CE:EF:A7:77:B4:8D:56:8A:A1:C8:14:0C:1D:00:DF:99:14:ED:CE:05:4B:94:F9:EE:36:EE:4F:82:61\\r\\na=setup:actpass\\r\\na=mid:0\\r\\na=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level\\r\\na=extmap:2 http:\\/\\/www.ietf.org\\/id\\/draft-holmer-rmcat-transport-wide-cc-extensions-01\\r\\na=extmap:3 urn:ietf:params:rtp-hdrext:sdes:mid\\r\\na=extmap:4 urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id\\r\\na=extmap:5 urn:ietf:params:rtp-hdrext:sdes:repaired-rtp-stream-id\\r\\na=sendonly\\r\\na=msid:3fd630e8-9285-4f82-adbc-a7e31c334740 a573e4b8-b844-4ab9-b5b2-62c5bea85e9e\\r\\na=rtcp-mux\\r\\na=rtpmap:111 opus\\/48000\\/2\\r\\na=rtcp-fb:111 transport-cc\\r\\na=fmtp:111 minptime=10;useinbandfec=1\\r\\na=rtpmap:103 ISAC\\/16000\\r\\na=rtpmap:104 ISAC\\/32000\\r\\na=rtpmap:9 G722\\/8000\\r\\na=rtpmap:0 PCMU\\/8000\\r\\na=rtpmap:8 PCMA\\/8000\\r\\na=rtpmap:110 telephone-event\\/48000\\r\\na=rtpmap:112 telephone-event\\/32000\\r\\na=rtpmap:113 telephone-event\\/16000\\r\\na=rtpmap:126 telephone-event\\/8000\\r\\na=ssrc:2852212123 cname:GybrBKZh3U5xSqQq\\r\\na=ssrc:2852212123 msid:3fd630e8-9285-4f82-adbc-a7e31c334740 a573e4b8-b844-4ab9-b5b2-62c5bea85e9e\\r\\na=ssrc:2852212123 mslabel:3fd630e8-9285-4f82-adbc-a7e31c334740\\r\\na=ssrc:2852212123 label:a573e4b8-b844-4ab9-b5b2-62c5bea85e9e\\r\\n\"", - "type": "string" - }, - { - "key": "candidate", - "value": "\"\"", - "type": "string" - }, - { - "key": "connection_id", - "value": "", - "type": "string" - } - ] -} \ No newline at end of file diff --git a/WebApp/test/websockethandler.test.ts b/WebApp/test/websockethandler.test.ts deleted file mode 100644 index f1de627..0000000 --- a/WebApp/test/websockethandler.test.ts +++ /dev/null @@ -1,190 +0,0 @@ -import WS from "jest-websocket-mock"; -import Answer from "../src/class/answer"; -import Candidate from "../src/class/candidate"; -import Offer from "../src/class/offer"; -import * as wsHandler from '../src/class/websockethandler'; - -Date.now = jest.fn(() => 1482363367071); - -describe('websocket signaling test in public mode', () => { - let server: WS; - let client: WebSocket; - let client2: WebSocket; - const connectionId = "12345"; - const connectionId2 = "67890"; - const testsdp = "test sdp"; - - beforeAll(async () => { - wsHandler.reset("public"); - server = new WS("ws://localhost:1234", { jsonProtocol: true }); - client = new WebSocket("ws://localhost:1234"); - await server.connected; - client2 = new WebSocket("ws://localhost:1234"); - await server.connected; - }); - - afterAll(() => { - WS.clean(); - }); - - test('create session1', async () => { - expect(client).not.toBeNull(); - await wsHandler.add(client); - }); - - test('create session2', async () => { - expect(client2).not.toBeNull(); - await wsHandler.add(client2); - }); - - test('create connection from session1', async () => { - await wsHandler.onConnect(client, connectionId); - await expect(server).toReceiveMessage({ type: "connect", connectionId: connectionId, polite: true }); - expect(server).toHaveReceivedMessages([{ type: "connect", connectionId: connectionId, polite: true }]); - }); - - test('create connection from session2', async () => { - await wsHandler.onConnect(client2, connectionId2); - await expect(server).toReceiveMessage({ type: "connect", connectionId: connectionId2, polite: true }); - expect(server).toHaveReceivedMessages([{ type: "connect", connectionId: connectionId2, polite: true }]); - }); - - test('send offer from session1', async () => { - await wsHandler.onOffer(client, { connectionId: connectionId, sdp: testsdp }); - const receiveOffer = new Offer(testsdp, Date.now(), false); - await expect(server).toReceiveMessage({ from: connectionId, to: "", type: "offer", data: receiveOffer }); - expect(server).toHaveReceivedMessages([{ from: connectionId, to: "", type: "offer", data: receiveOffer }]); - }); - - test('send answer from session2', async () => { - await wsHandler.onAnswer(client2, { connectionId: connectionId, sdp: testsdp }); - const receiveAnswer = new Answer(testsdp, Date.now()); - await expect(server).toReceiveMessage({ from: connectionId, to: "", type: "answer", data: receiveAnswer }); - expect(server).toHaveReceivedMessages([{ from: connectionId, to: "", type: "answer", data: receiveAnswer }]); - }); - - test('send candidate from sesson1', async () => { - const msg = { connectionId: connectionId, candidate: "testcandidate", sdpMLineIndex: 0, sdpMid: "0" }; - await wsHandler.onCandidate(client, msg); - const receiveCandidate = new Candidate("testcandidate", 0, "0", Date.now()); - await expect(server).toReceiveMessage({ from: connectionId, to: "", type: "candidate", data: receiveCandidate }); - expect(server).toHaveReceivedMessages([{ from: connectionId, to: "", type: "candidate", data: receiveCandidate }]); - }); - - test('delete connection from session2', async () => { - await wsHandler.onDisconnect(client2, connectionId); - // disconnect send to client - await expect(server).toReceiveMessage({ type: "disconnect", connectionId: connectionId }); - // disconnect send to client2 - await expect(server).toReceiveMessage({ type: "disconnect", connectionId: connectionId }); - // server received total 2 disconnect messages - expect(server).toHaveReceivedMessages([{ type: "disconnect", connectionId: connectionId }, { type: "disconnect", connectionId: connectionId }]); - }); - - test('delete connection from session1', async () => { - await wsHandler.onDisconnect(client, connectionId); - await expect(server).toReceiveMessage({ type: "disconnect", connectionId: connectionId }); - expect(server).toHaveReceivedMessages([{ type: "disconnect", connectionId: connectionId }, { type: "disconnect", connectionId: connectionId }]); - }); - - test('delete session2', async () => { - expect(client).not.toBeNull(); - await wsHandler.remove(client2); - }); - - test('delete session1', async () => { - expect(client2).not.toBeNull(); - await wsHandler.remove(client); - }); -}); - -describe('websocket signaling test in private mode', () => { - let server: WS; - let client: WebSocket; - let client2: WebSocket; - const connectionId = "12345"; - const testsdp = "test sdp"; - - beforeAll(async () => { - wsHandler.reset("private"); - server = new WS("ws://localhost:1234", { jsonProtocol: true }); - client = new WebSocket("ws://localhost:1234"); - await server.connected; - client2 = new WebSocket("ws://localhost:1234"); - await server.connected; - }); - - afterAll(() => { - WS.clean(); - }); - - test('create session1', async () => { - expect(client).not.toBeNull(); - await wsHandler.add(client); - }); - - test('create session2', async () => { - expect(client2).not.toBeNull(); - await wsHandler.add(client2); - }); - - test('create connection from session1', async () => { - await wsHandler.onConnect(client, connectionId); - await expect(server).toReceiveMessage({ type: "connect", connectionId: connectionId, polite: false }); - expect(server).toHaveReceivedMessages([{ type: "connect", connectionId: connectionId, polite: false }]); - }); - - test('create connection from session2', async () => { - await wsHandler.onConnect(client2, connectionId); - await expect(server).toReceiveMessage({ type: "connect", connectionId: connectionId, polite: true }); - expect(server).toHaveReceivedMessages([{ type: "connect", connectionId: connectionId, polite: true }]); - }); - - test('send offer from session1', async () => { - await wsHandler.onOffer(client, { connectionId: connectionId, sdp: testsdp }); - const receiveOffer = new Offer(testsdp, Date.now(), true); - await expect(server).toReceiveMessage({ from: connectionId, to: "", type: "offer", data: receiveOffer }); - expect(server).toHaveReceivedMessages([{ from: connectionId, to: "", type: "offer", data: receiveOffer }]); - }); - - test('send answer from session2', async () => { - await wsHandler.onAnswer(client2, { connectionId: connectionId, sdp: testsdp }); - const receiveAnswer = new Answer(testsdp, Date.now()); - await expect(server).toReceiveMessage({ from: connectionId, to: "", type: "answer", data: receiveAnswer }); - expect(server).toHaveReceivedMessages([{ from: connectionId, to: "", type: "answer", data: receiveAnswer }]); - }); - - test('send candidate from sesson1', async () => { - const msg = { connectionId: connectionId, candidate: "testcandidate", sdpMLineIndex: 0, sdpMid: "0" }; - await wsHandler.onCandidate(client, msg); - const receiveCandidate = new Candidate("testcandidate", 0, "0", Date.now()); - await expect(server).toReceiveMessage({ from: connectionId, to: "", type: "candidate", data: receiveCandidate }); - expect(server).toHaveReceivedMessages([{ from: connectionId, to: "", type: "candidate", data: receiveCandidate }]); - }); - - test('delete connection from session2', async () => { - await wsHandler.onDisconnect(client2, connectionId); - // disconnect send to client - await expect(server).toReceiveMessage({ type: "disconnect", connectionId: connectionId }); - // disconnect send to client2 - await expect(server).toReceiveMessage({ type: "disconnect", connectionId: connectionId }); - // server received total 2 disconnect messages - expect(server).toHaveReceivedMessages([{ type: "disconnect", connectionId: connectionId }, { type: "disconnect", connectionId: connectionId }]); - }); - - test('delete connection from session1', async () => { - await wsHandler.onDisconnect(client, connectionId); - await expect(server).toReceiveMessage({ type: "disconnect", connectionId: connectionId }); - expect(server).toHaveReceivedMessages([{ type: "disconnect", connectionId: connectionId }, { type: "disconnect", connectionId: connectionId }]); - }); - - test('delete session2', async () => { - expect(client).not.toBeNull(); - await wsHandler.remove(client2); - }); - - test('delete session1', async () => { - expect(client2).not.toBeNull(); - await wsHandler.remove(client); - }); -}); diff --git a/WebApp/tsconfig.build.json b/WebApp/tsconfig.build.json deleted file mode 100644 index 0a79a80..0000000 --- a/WebApp/tsconfig.build.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "include": ["src/**/*"], - "extends": "./tsconfig.json" -} diff --git a/WebApp/tsconfig.json b/WebApp/tsconfig.json deleted file mode 100644 index 04a5fd9..0000000 --- a/WebApp/tsconfig.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "include": ["src/**/*", "test/**/*.ts"], - "exclude": ["node_modules", "**/*.spec.ts"], - "compilerOptions": { - "module": "commonjs", - "target": "es5", - "lib": ["dom","es5"], - "sourceMap": true, - "outDir":"build", - "rootDir":"src" - } -} diff --git a/WebApp/tsconfig.lint.json b/WebApp/tsconfig.lint.json deleted file mode 100644 index 87c8094..0000000 --- a/WebApp/tsconfig.lint.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "include": ["src/**/*", "test/**/*"], - "exclude": ["node_modules", "**/*.spec.ts"], - "compilerOptions": { - "module": "commonjs", - "target": "es5", - "lib": ["dom","es5"], - "sourceMap": false, - "outDir":"build", - "rootDir":"src" - } -} \ No newline at end of file diff --git a/WebApp/私有模式和公有模式区别.md b/WebApp/私有模式和公有模式区别.md deleted file mode 100644 index e55f2cc..0000000 --- a/WebApp/私有模式和公有模式区别.md +++ /dev/null @@ -1,514 +0,0 @@ -# WebRTC 信令模式说明:私有模式 vs 公有模式 - -## 📊 核心对比 - -| 特性 | **私有模式 (private)** | **公有模式 (public)** | -|------|----------------------|---------------------| -| **连接关系** | 1对多 (Host-Participants) | 多对多 (广播) | -| **角色分配** | 有明确的 host 和 participant 角色 | 所有客户端平等,无角色区分 | -| **信令路由** | 定向转发 (host ↔ participants) | 全局广播 (除发送者外所有人) | -| **连接组管理** | 使用 `connectionGroup` 管理 | 使用 `clients` 全局列表 | -| **适用场景** | 视频会议、主控-从控 | 直播、公开房间 | - ---- - -## 🔒 私有模式 (Private Mode) - -### 工作原理 - -``` -客户端A (Host) ←→ 服务器 ←→ 客户端B (Participant 1) - ←→ 客户端C (Participant 2) - ←→ 客户端D (Participant 3) -``` - -### 关键特性 - -#### 1. 角色分配机制 - -- **第一个**连接到服务器的客户端成为 **Host** -- **后续**连接的客户端成为 **Participants** -- 通过 `polite` 参数区分角色: - - `host`: `polite = false` - - `participant`: `polite = true` - -**代码实现** (`src/class/websockethandler.ts` 第 150-176 行): - -```typescript -function onConnect(ws: WebSocket, connectionId: string): void { - let polite = true; - - // 处理私有模式 - if (isPrivate) { - if (connectionGroup.has(connectionId)) { - const group = connectionGroup.get(connectionId); - // 已有host,新连接作为participant加入 - group.participants.add(ws); - console.log(`Participant joined connectionId: ${connectionId}, total participants: ${group.participants.size}`); - } else { - // 第一个连接成为host - connectionGroup.set(connectionId, { host: ws, participants: new Set() }); - polite = false; - console.log(`Host created connectionId: ${connectionId}`); - } - } - - // 发送连接成功消息(包含角色信息) - const role = polite ? 'participant' : 'host'; - ws.send(JSON.stringify({ type: "connect", connectionId: connectionId, polite: polite, role: role })); -} -``` - -#### 2. 信令转发规则 - -- **Host 发送** → 转发给**所有 participants** -- **Participant 发送** → 只转发给 **host** -- **Participants 之间不能直接通信** - -**代码实现** (`src/class/websockethandler.ts` 第 96-108 行): - -```typescript -function broadcastToGroup(connectionId: string, senderWs: WebSocket, message: any): void { - const group = connectionGroup.get(connectionId); - if (!group) return; - - // 如果发送者是host,转发给所有participants - if (senderWs === group.host) { - group.participants.forEach(participantWs => { - participantWs.send(JSON.stringify(message)); - }); - } else { - // 如果发送者是participant,转发给host - group.host.send(JSON.stringify(message)); - } -} -``` - -#### 3. Offer 信令处理 - -**代码实现** (`src/class/websockethandler.ts` 第 220-243 行): - -```typescript -function onOffer(ws: WebSocket, message: any): void { - const connectionId = message.connectionId as string; - const newOffer = new Offer(message.sdp, Date.now(), false); - - // 处理私有模式 - if (isPrivate) { - if (connectionGroup.has(connectionId)) { - const group = connectionGroup.get(connectionId); - if (group.host === ws) { - // host发送offer,转发给所有participants - newOffer.polite = true; - group.participants.forEach(participantWs => { - participantWs.send(JSON.stringify({ from: connectionId, to: "", type: "offer", data: newOffer })); - }); - } else { - // participant发送offer,转发给host - newOffer.polite = true; - group.host.send(JSON.stringify({ from: connectionId, to: "", type: "offer", data: newOffer })); - } - } - return; - } - // ... 公有模式处理 -} -``` - -#### 4. 断开连接处理 - -- **Host 断开** → 通知所有 participants,删除整个连接组 -- **Participant 断开** → 只通知 host,从 participants 中移除 - -**代码实现** (`src/class/websockethandler.ts` 第 114-142 行): - -```typescript -function remove(ws: WebSocket): void { - const connectionIds = clients.get(ws); - if (!connectionIds) return; - - connectionIds.forEach(connectionId => { - const group = connectionGroup.get(connectionId); - if (group) { - if (group.host === ws) { - // host断开连接,通知所有participants - group.participants.forEach(participantWs => { - participantWs.send(JSON.stringify({ type: "disconnect", connectionId: connectionId })); - }); - // 删除整个连接组 - connectionGroup.delete(connectionId); - } else { - // participant断开连接,从participants中移除并通知host - group.participants.delete(ws); - group.host.send(JSON.stringify({ type: "disconnect", connectionId: connectionId })); - } - } - console.log(`Remove connectionId: ${connectionId}`); - }); - - clients.delete(ws); -} -``` - -### 数据结构 - -```typescript -interface ConnectionGroup { - host: WebSocket; // 主机(第一个连接) - participants: Set; // 参与者集合(后续连接) -} - -const connectionGroup: Map = new Map(); -``` - -### 应用场景 - -- ✅ **视频会议** (1个主播 + 多个观众) -- ✅ **远程桌面控制** (1个主控 + 多个观察者) -- ✅ **直播互动** (主播与观众连麦) -- ✅ **教学系统** (教师 + 多个学生) -- ✅ **主从控制** (Unity 应用为主机,多个 Web 客户端为参与者) - ---- - -## 🌐 公有模式 (Public Mode) - -### 工作原理 - -``` -客户端A ←→ 服务器 ←→ 客户端B - ↕ (广播) ↕ -客户端C ←────────────→ 客户端D -``` - -### 关键特性 - -#### 1. 无角色区分 - -- 所有客户端地位平等 -- 没有 host/participant 的概念 -- `polite` 始终为 `true` - -#### 2. 全局广播机制 - -- 任何客户端发送的消息 → **广播给所有其他客户端** -- 支持 **多对多** 通信 -- 每个客户端既是发送者也是接收者 - -**代码实现** (`src/class/websockethandler.ts` 第 245-256 行): - -```typescript -function onOffer(ws: WebSocket, message: any): void { - const connectionId = message.connectionId as string; - const newOffer = new Offer(message.sdp, Date.now(), false); - - // ... 私有模式处理 - - // 公共模式:创建新的连接组(如果不存在) - if (!connectionGroup.has(connectionId)) { - connectionGroup.set(connectionId, { host: ws, participants: new Set() }); - } - - // 向所有其他客户端广播offer - clients.forEach((_v, k) => { - if (k == ws) { - return; // 跳过发送者 - } - k.send(JSON.stringify({ from: connectionId, to: "", type: "offer", data: newOffer })); - }); -} -``` - -#### 3. 对等通信 - -**消息流转示例**: -``` -A 发送消息 → B、C、D 都收到 -B 发送消息 → A、C、D 都收到 -C 发送消息 → A、B、D 都收到 -D 发送消息 → A、B、C 都收到 -``` - -### 应用场景 - -- ✅ **多人聊天室** (所有用户平等) -- ✅ **公开游戏房间** (多玩家对战) -- ✅ **协作编辑** (多人实时编辑) -- ✅ **广播直播** (单向推流,多人观看) -- ✅ **P2P 网状网络** (Full Mesh 拓扑) - ---- - -## 💻 启动方式 - -### 私有模式 - -```bash -# 使用 npm 脚本 -npm start -- -m private - -# 或直接运行 -node ./build/index.js -s -p 8080 -m private -k ./server.key -c ./server.cert - -# 开发模式 -npm run dev -- -m private -``` - -### 公有模式 - -```bash -# 使用 npm 脚本(默认模式) -npm start - -# 或明确指定 -npm start -- -m public - -# 或直接运行 -node ./build/index.js -s -p 8080 -m public -k ./server.key -c ./server.cert -``` - -### 参数说明 - -| 参数 | 说明 | 示例 | -|------|------|------| -| `-m` | 通信模式 | `-m private` 或 `-m public` | -| `-p` | 端口号 | `-p 8080` | -| `-s` | 启用 HTTPS | `-s` | -| `-k` | 密钥文件 | `-k ./server.key` | -| `-c` | 证书文件 | `-c ./server.cert` | -| `-t` | 信令类型 | `-t websocket` 或 `-t http` | - ---- - -## 📝 实际例子 - -### 私有模式示例 - -假设有 3 个客户端连接到同一个 `connectionId: "room1"`: - -**连接顺序**: -1. **客户端A** 先连接 → 成为 **Host** (`polite: false`) -2. **客户端B** 连接 → 成为 **Participant 1** (`polite: true`) -3. **客户端C** 连接 → 成为 **Participant 2** (`polite: true`) - -**消息流转**: -``` -A (Host) 发送消息 - → B 收到 - → C 收到 - -B (Participant) 发送消息 - → A 收到 - → C 收不到 ❌ - -C (Participant) 发送消息 - → A 收到 - → B 收不到 ❌ -``` - -**信令流程图**: -``` -B --[offer]--> 服务器 --[offer]--> A (Host) -A --[answer]--> 服务器 --[answer]--> B -A --[offer]--> 服务器 --[offer]--> C -C --[answer]--> 服务器 --[answer]--> A -``` - -### 公有模式示例 - -假设有 3 个客户端连接: - -**连接顺序**: -1. **客户端A** 连接 (`polite: true`) -2. **客户端B** 连接 (`polite: true`) -3. **客户端C** 连接 (`polite: true`) - -**消息流转**: -``` -A 发送消息 - → B 收到 ✅ - → C 收到 ✅ - -B 发送消息 - → A 收到 ✅ - → C 收到 ✅ - -C 发送消息 - → A 收到 ✅ - → B 收到 ✅ -``` - -**信令流程图**: -``` -A --[offer]--> 服务器 --[offer]--> B -A --[offer]--> 服务器 --[offer]--> C -B --[offer]--> 服务器 --[offer]--> A -B --[offer]--> 服务器 --[offer]--> C -C --[offer]--> 服务器 --[offer]--> A -C --[offer]--> 服务器 --[offer]--> B -``` - ---- - -## 🔍 代码中的模式判断 - -### 初始化模式 - -**`src/class/websockethandler.ts` 第 62-65 行**: - -```typescript -function reset(mode: string): void { - // 设置是否为私有模式 - isPrivate = mode == "private"; -} -``` - -### 模式判断逻辑 - -在各个信令处理函数中,通过 `isPrivate` 变量判断: - -```typescript -// Offer 处理 -if (isPrivate) { - // 私有模式逻辑:定向转发 -} else { - // 公有模式逻辑:全局广播 -} - -// Candidate 处理 -if (isPrivate) { - // 私有模式逻辑 - return; -} - -// Message 处理 -if (connectionGroup.has(connectionId)) { - const group = connectionGroup.get(connectionId); - if (group.host === ws) { - // host 发送 → 转发给 participants - } else { - // participant 发送 → 转发给 host - } -} -``` - ---- - -## 🎯 模式选择建议 - -### 选择私有模式的场景 - -- ✅ 需要明确的主从关系 -- ✅ 中心节点需要控制所有通信 -- ✅ 参与者之间不需要直接通信 -- ✅ 需要管理连接层级结构 -- ✅ 资源优化(减少不必要的 P2P 连接) - -### 选择公有模式的场景 - -- ✅ 所有参与者地位平等 -- ✅ 需要多对多通信 -- ✅ Full Mesh P2P 拓扑 -- ✅ 每个客户端都需要相互连接 -- ✅ 去中心化的应用场景 - ---- - -## 📊 性能对比 - -| 指标 | 私有模式 | 公有模式 | -|------|---------|---------| -| **连接数** | O(n) - 线性增长 | O(n²) - 平方增长 | -| **服务器负载** | 中等(需要路由转发) | 较低(主要是广播) | -| **客户端负载** | 较低(只与 host 建立连接) | 较高(需要与所有客户端建立连接) | -| **网络带宽** | 节省(定向传输) | 较高(广播传输) | -| **扩展性** | 好(适合大量 participants) | 受限(连接数随用户数平方增长) | - ---- - -## 🔧 测试方式 - -### 单元测试 - -项目中已包含完整的单元测试: - -**后端测试** (`test/websockethandler.test.ts`): - -```typescript -// 公有模式测试 -describe('websocket signaling test in public mode', () => { - beforeAll(async () => { - wsHandler.reset("public"); - // ... - }); -}); - -// 私有模式测试 -describe('websocket signaling test in private mode', () => { - beforeAll(async () => { - wsHandler.reset("private"); - // ... - }); -}); -``` - -**前端测试** (`client/test/signaling.test.js`): - -```javascript -// 公有模式测试 -describe.each([ - { mode: "mock" }, - { mode: "http" }, - { mode: "websocket" }, -])('signaling test in public mode', ({ mode }) => { - // ... -}); - -// 私有模式测试 -describe.each([ - { mode: "mock" }, - { mode: "http" }, - { mode: "websocket" }, -])('signaling test in private mode', ({ mode }) => { - // ... -}); -``` - -### 运行测试 - -```bash -# 运行后端测试 -npm test - -# 运行前端测试 -cd client -npm test -``` - ---- - -## 📚 相关文件 - -- **WebSocket 处理器**: `src/class/websockethandler.ts` -- **HTTP 处理器**: `src/class/httphandler.ts` -- **WebSocket 服务**: `src/websocket.ts` -- **前端信令**: `client/src/signaling.js` -- **主入口**: `src/index.ts` -- **后端测试**: `test/websockethandler.test.ts` -- **前端测试**: `client/test/signaling.test.js` - ---- - -## 💡 总结 - -| 模式 | 核心特点 | 最佳用途 | -|------|---------|---------| -| **私有模式** | 1对多、主从架构、定向转发 | 视频会议、远程控制、教学系统 | -| **公有模式** | 多对多、对等网络、全局广播 | 聊天室、多人游戏、协作编辑 | - -选择合适的模式取决于你的应用架构需求和通信拓扑结构。 - ---- - -**文档生成时间**: 2026-04-22 -**项目版本**: 3.1.0