diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 0b64429..7d15d9e 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -30,7 +30,7 @@ jobs: dep: "brew update && brew install cocoapods xcodegen" cmd: "./scripts/build_mac_demo.sh" - os: windows-latest - cmd: ".\\scripts\\setup_windows.bat \"C:\\Program Files\\Microsoft Visual Studio\\2022\\Enterprise\\VC\\Tools\\MSVC\\14.43.34808\\bin\\Hostx64\\x64\\lib.exe\" && cd example\\winApp && msbuild winApp.vcxproj /t:Build /p:Configuration=Release /p:Platform=x64" + cmd: ".\\scripts\\setup_windows.bat \"C:\\Program Files\\Microsoft Visual Studio\\2022\\Enterprise\\VC\\Tools\\MSVC\\14.44.35207\\bin\\Hostx64\\x64\\lib.exe\" && cd example\\winApp && msbuild winApp.vcxproj /t:Build /p:Configuration=Release /p:Platform=x64" - os: macos-latest cmd: "./gradlew :example:webApp:jsBrowserDistribution" - os: ubuntu-latest diff --git a/README.md b/README.md index b7e4685..36c3379 100644 --- a/README.md +++ b/README.md @@ -71,14 +71,14 @@ Open the project (the repo root dir) in Android studio, and run the example.andr ### iOS ```bash -./scripts/setup_apple.sh +./scripts/setup_apple_demo.sh # open example/iosApp/iosApp.xcworkspace in Xcode, and run it. ``` ### macOS ```bash -./scripts/setup_apple.sh +./scripts/setup_apple_demo.sh # open example/macApp/macApp.xcworkspace in Xcode, and run it. ``` @@ -91,6 +91,8 @@ Open the project (the repo root dir) in Android studio, and run the example.andr ### Linux +On Linux machine with GUI support. + ```bash ./scripts/build_linux_demo.sh ./example/linuxApp/build/loopback @@ -99,7 +101,7 @@ Open the project (the repo root dir) in Android studio, and run the example.andr ### JS ```bash -./gradlew :example:webApp:jsBrowserRun +./gradlew :example:webApp:jsBrowserDevelopmentRun ``` ## Build WebRTC diff --git a/example/androidApp/src/main/java/com/piasy/kmp/webrtc/android/CallActivity.java b/example/androidApp/src/main/java/com/piasy/kmp/webrtc/android/CallActivity.java index 109b9e4..5b5282a 100644 --- a/example/androidApp/src/main/java/com/piasy/kmp/webrtc/android/CallActivity.java +++ b/example/androidApp/src/main/java/com/piasy/kmp/webrtc/android/CallActivity.java @@ -5,6 +5,7 @@ import android.os.Bundle; import android.os.Handler; import android.os.HandlerThread; +import android.text.TextUtils; import android.util.DisplayMetrics; import android.view.Gravity; import android.view.View; @@ -44,14 +45,7 @@ import static com.piasy.kmp.webrtc.AndroidPeerConnectionClientFactoryKt.createPeerConnectionClientFactory; import static com.piasy.kmp.webrtc.AndroidPeerConnectionClientFactoryKt.initializeWebRTC; -import static com.piasy.kmp.webrtc.android.HallActivity.EXTRA_AUDIO_ONLY; -import static com.piasy.kmp.webrtc.android.HallActivity.EXTRA_IS_PUBLISHER; -import static com.piasy.kmp.webrtc.android.HallActivity.EXTRA_RECORD_CALL; -import static com.piasy.kmp.webrtc.android.HallActivity.EXTRA_VIDEO_BITRATE; -import static com.piasy.kmp.webrtc.android.HallActivity.EXTRA_VIDEO_CODEC; -import static com.piasy.kmp.webrtc.android.HallActivity.EXTRA_VIDEO_FPS; -import static com.piasy.kmp.webrtc.android.HallActivity.EXTRA_VIDEO_HEIGHT; -import static com.piasy.kmp.webrtc.android.HallActivity.EXTRA_VIDEO_WIDTH; +import static com.piasy.kmp.webrtc.android.HallActivity.*; public class CallActivity extends AppCompatActivity implements PeerConnectionClientCallback, AudioMixer.MixerCallback { @@ -61,6 +55,7 @@ public class CallActivity extends AppCompatActivity implements PeerConnectionCli private static final boolean PAUSE_STREAMING = true; private boolean isPublisher; + private boolean singlePc; private boolean audioOnly; private int videoWidth; private int videoHeight; @@ -87,6 +82,7 @@ public class CallActivity extends AppCompatActivity implements PeerConnectionCli private EglBase eglBase; private PeerConnectionClientFactory pcClientFactory; private PeerConnectionClient pcClient; + private PeerConnectionClient recvPcClient; private AudioMixer mixer; private static int getSystemUiVisibility() { @@ -117,6 +113,7 @@ protected void onCreate(Bundle savedInstanceState) { isPublisher = intent.getBooleanExtra(EXTRA_IS_PUBLISHER, true); recording = intent.getBooleanExtra(EXTRA_RECORD_CALL, false); + singlePc = intent.getBooleanExtra(EXTRA_SINGLE_PC, false); audioOnly = intent.getBooleanExtra(EXTRA_AUDIO_ONLY, false); videoWidth = intent.getIntExtra(EXTRA_VIDEO_WIDTH, 640); @@ -300,11 +297,23 @@ public Unit invoke(Integer code, String msg) { // 5. create PcClient pcClient = pcClientFactory.createPeerConnectionClient( - "test", PeerConnectionClient.DIR_SEND_RECV, true, videoMaxBitrate, videoFps, this + "test", + singlePc ? PeerConnectionClient.DIR_SEND_RECV : PeerConnectionClient.DIR_SEND_ONLY, + true, videoMaxBitrate, videoFps, this ); + if (!singlePc) { + recvPcClient = pcClientFactory.createPeerConnectionClient( + "test-recv", + PeerConnectionClient.DIR_RECV_ONLY, + true, videoMaxBitrate, videoFps, this + ); + } // 6. create pc pcClient.createPeerConnection(Collections.emptyList()); + if (recvPcClient != null) { + recvPcClient.createPeerConnection(Collections.emptyList()); + } // 7. create offer pcClient.createOffer(); @@ -313,14 +322,28 @@ public Unit invoke(Integer code, String msg) { @Override public void onLocalDescription(@NotNull String peerUid, @NotNull SessionDescription sdp) { // 8. send offer to remote, get answer from remote, and set answer - SessionDescription answer = new SessionDescription(SessionDescription.ANSWER, sdp.getSdpDescription()); - pcClient.setRemoteDescription(answer); + if (singlePc || TextUtils.equals(peerUid, "test-recv")) { + SessionDescription answer = new SessionDescription(SessionDescription.ANSWER, sdp.getSdpDescription()); + pcClient.setRemoteDescription(answer); + } else if (TextUtils.equals(peerUid, "test")) { + SessionDescription offer = new SessionDescription(SessionDescription.OFFER, sdp.getSdpDescription()); + recvPcClient.setRemoteDescription(offer); + recvPcClient.createAnswer(); + } + } + + @Override + public void onSetRemoteSdpResult(@NotNull String peerUid, boolean success) { } @Override public void onIceCandidate(@NotNull String peerUid, @NotNull IceCandidate candidate) { // 9. send ice candidate to remote, get ice candidate from remote, add ice candidate - pcClient.addIceCandidate(candidate); + if (singlePc || TextUtils.equals(peerUid, "test-recv")) { + pcClient.addIceCandidate(candidate); + } else if (TextUtils.equals(peerUid, "test")) { + recvPcClient.addIceCandidate(candidate); + } } @Override @@ -329,7 +352,11 @@ public void onIceConnected(@NotNull String peerUid) { @Override public void run() { // 10. on ice connected, add renderer for remote stream - pcClient.addRemoteTrackRenderer(remoteRenderer); + if (singlePc) { + pcClient.addRemoteTrackRenderer(remoteRenderer); + } else { + recvPcClient.addRemoteTrackRenderer(remoteRenderer); + } } }); } @@ -343,6 +370,10 @@ private void disconnect() { if (pcClientFactory != null) { pcClientFactory.stopVideoCapture(); pcClient.close(); + if (recvPcClient != null) { + recvPcClient.close(); + recvPcClient = null; + } pcClientFactory.destroyPeerConnectionFactory(); pcClientFactory = null; pcClient = null; diff --git a/example/androidApp/src/main/java/com/piasy/kmp/webrtc/android/HallActivity.java b/example/androidApp/src/main/java/com/piasy/kmp/webrtc/android/HallActivity.java index 6c2ec05..eaa784b 100644 --- a/example/androidApp/src/main/java/com/piasy/kmp/webrtc/android/HallActivity.java +++ b/example/androidApp/src/main/java/com/piasy/kmp/webrtc/android/HallActivity.java @@ -19,6 +19,7 @@ public class HallActivity extends Activity { public static final String EXTRA_IS_PUBLISHER = "avconf.IS_PUBLISHER"; + public static final String EXTRA_SINGLE_PC = "avconf.SINGLE_PC"; public static final String EXTRA_AUDIO_ONLY = "avconf.AUDIO_ONLY"; public static final String EXTRA_RECORD_CALL = "avconf.RECORD_CALL"; public static final String EXTRA_VIDEO_WIDTH = "avconf.VIDEO_WIDTH"; @@ -35,6 +36,7 @@ public class HallActivity extends Activity { private String keyprefVideoBitrateValue; private CheckBox mRecording; + private CheckBox mSinglePc; private CheckBox mAudioOnly; private CheckBox mPublisher; private CheckBox mScreenShare; @@ -59,6 +61,7 @@ protected void onCreate(Bundle savedInstanceState) { tvVersion.setText("kmp-webrtc " + BuildConfig.VERSION_NAME); mRecording = findViewById(R.id.recording); + mSinglePc = findViewById(R.id.single_pc); mAudioOnly = findViewById(R.id.audio_only); mPublisher = findViewById(R.id.publisher); mScreenShare = findViewById(R.id.screen_share); @@ -84,7 +87,8 @@ public void onRequestPermissionsResult(final int requestCode, Manifest.permission.MODIFY_AUDIO_SETTINGS, Manifest.permission.BLUETOOTH, Manifest.permission.WRITE_EXTERNAL_STORAGE, - Manifest.permission.ACCESS_NETWORK_STATE + Manifest.permission.ACCESS_NETWORK_STATE, + Manifest.permission.BLUETOOTH_CONNECT, }) void checkPermission() { mGotPermission = true; @@ -145,6 +149,7 @@ private void startLoopback(Class activityClass) { // Start AppRTCMobile activity. Intent intent = new Intent(this, activityClass); intent.putExtra(EXTRA_IS_PUBLISHER, mPublisher.isChecked()); + intent.putExtra(EXTRA_SINGLE_PC, mSinglePc.isChecked()); intent.putExtra(EXTRA_AUDIO_ONLY, mAudioOnly.isChecked()); intent.putExtra(EXTRA_RECORD_CALL, mRecording.isChecked()); intent.putExtra(EXTRA_VIDEO_WIDTH, videoWidth); diff --git a/example/androidApp/src/main/res/layout/activity_hall.xml b/example/androidApp/src/main/res/layout/activity_hall.xml index 5ab75a9..c8f6345 100644 --- a/example/androidApp/src/main/res/layout/activity_hall.xml +++ b/example/androidApp/src/main/res/layout/activity_hall.xml @@ -32,11 +32,18 @@ + + diff --git a/example/iosApp/Podfile b/example/iosApp/Podfile index 1941d27..abb9edd 100644 --- a/example/iosApp/Podfile +++ b/example/iosApp/Podfile @@ -5,5 +5,4 @@ target 'iosApp' do platform :ios, '14.0' pod 'kmp_webrtc', :path => '../../kmp-webrtc/kmp_webrtc.podspec' pod 'WebRTC', :path => '../../libs/apple/WebRTC.podspec' - pod 'kmp_xlog', '~> 1.3.4' end diff --git a/example/iosApp/iosApp/ARDAppDelegate.h b/example/iosApp/iosApp/ARDAppDelegate.h index 623e859..72a2853 100644 --- a/example/iosApp/iosApp/ARDAppDelegate.h +++ b/example/iosApp/iosApp/ARDAppDelegate.h @@ -13,5 +13,5 @@ // The main application class of the AppRTCMobile iOS app demonstrating // interoperability between the Objective C implementation of PeerConnection // and the appr.tc demo webapp. -@interface ARDAppDelegate : NSObject +@interface ARDAppDelegate : UIResponder @end diff --git a/example/iosApp/iosApp/ARDAppDelegate.m b/example/iosApp/iosApp/ARDAppDelegate.m index 097ed14..a937e20 100644 --- a/example/iosApp/iosApp/ARDAppDelegate.m +++ b/example/iosApp/iosApp/ARDAppDelegate.m @@ -10,27 +10,28 @@ #import "ARDAppDelegate.h" -#import "HallViewController.h" +#import "SceneDelegate.h" -@implementation ARDAppDelegate { - UIWindow *_window; -} +@implementation ARDAppDelegate #pragma mark - UIApplicationDelegate methods -- (BOOL)application:(UIApplication *)application - didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { +- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { + // 这里可以保留你的全局初始化代码 + return YES; +} - _window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; - [_window makeKeyAndVisible]; - HallViewController *viewController = [[HallViewController alloc] init]; +#pragma mark - UISceneSession lifecycle (iOS 13+) - UINavigationController *root = - [[UINavigationController alloc] initWithRootViewController:viewController]; - root.navigationBar.translucent = NO; - _window.rootViewController = root; +- (UISceneConfiguration *)application:(UIApplication *)application configurationForConnectingSceneSession:(UISceneSession *)connectingSceneSession options:(UISceneConnectionOptions *)options { + // 当创建新场景时调用,返回一个场景配置对象 + UISceneConfiguration *configuration = [[UISceneConfiguration alloc] initWithName:@"Default Configuration" sessionRole:connectingSceneSession.role]; + configuration.delegateClass = [SceneDelegate class]; + return configuration; +} - return YES; +- (void)application:(UIApplication *)application didDiscardSceneSessions:(NSSet *)sceneSessions { + // 当用户丢弃场景会话时调用 } @end diff --git a/example/iosApp/iosApp/CallViewController.h b/example/iosApp/iosApp/CallViewController.h index 5a68ffb..49dbf7f 100644 --- a/example/iosApp/iosApp/CallViewController.h +++ b/example/iosApp/iosApp/CallViewController.h @@ -32,6 +32,7 @@ NS_ASSUME_NONNULL_BEGIN @interface CallViewController : UIViewController - (instancetype)initWithAudioOnly:(bool)audioOnly + singlePc:(bool)singlePc isLandscape:(bool)isLandscape; @end diff --git a/example/iosApp/iosApp/CallViewController.m b/example/iosApp/iosApp/CallViewController.m index 5095820..79bb52b 100644 --- a/example/iosApp/iosApp/CallViewController.m +++ b/example/iosApp/iosApp/CallViewController.m @@ -38,10 +38,12 @@ @interface CallViewController () _pcClient; + id _recvPcClient; NSTimer* _statsTimer; CFAudioMixer* _mixer; @@ -62,9 +64,11 @@ @implementation CallViewController { } - (instancetype)initWithAudioOnly:(bool)audioOnly + singlePc:(bool)singlePc isLandscape:(bool)isLandscape { if (self = [super init]) { _settingsModel = [[ARDSettingsModel alloc] init]; + _singlePc = singlePc; _isLandscape = isLandscape; } return self; @@ -224,7 +228,13 @@ - (void)hangup:(BOOL)dismissView { _statsTimer = nil; [_pcClientFactory stopVideoCapture]; [_pcClient close]; + if (_recvPcClient) { + [_recvPcClient close]; + _recvPcClient = nil; + } [_pcClientFactory destroyPeerConnectionFactory]; + _pcClient = nil; + _pcClientFactory = nil; if (dismissView) { [self dismissViewControllerAnimated:YES completion:nil]; @@ -369,15 +379,26 @@ - (void)startLoopback { // 5. create PcClient _pcClient = [_pcClientFactory createPeerConnectionClientPeerUid:@"test" - dir:0 - hasVideo:YES - videoMaxBitrateBps:[[_settingsModel currentMaxBitrateSettingFromStore] intValue] - videoMaxFrameRate:30 - callback:self]; + dir:0 + hasVideo:YES + videoMaxBitrateBps:[[_settingsModel currentMaxBitrateSettingFromStore] intValue] + videoMaxFrameRate:30 + callback:self]; + if (!_singlePc) { + _recvPcClient = [_pcClientFactory createPeerConnectionClientPeerUid:@"test-recv" + dir:0 + hasVideo:YES + videoMaxBitrateBps:[[_settingsModel currentMaxBitrateSettingFromStore] intValue] + videoMaxFrameRate:30 + callback:self]; + } // 6. create pc NSArray* iceServers = [NSArray array]; [_pcClient createPeerConnectionIceServers:iceServers]; + if (_recvPcClient) { + [_recvPcClient createPeerConnectionIceServers:iceServers]; + } // 7. create offer [_pcClient createOffer]; @@ -387,13 +408,24 @@ - (void)startLoopback { - (void)onLocalDescriptionPeerUid:(nonnull NSString *)peerUid sdp:(nonnull Kmp_webrtcSessionDescription *)sdp { // 8. send offer to remote, get answer from remote, and set answer - Kmp_webrtcSessionDescription* answer = [[Kmp_webrtcSessionDescription alloc] initWithType:3 sdpDescription:sdp.sdpDescription]; - [_pcClient setRemoteDescriptionSdp:answer]; + if (_singlePc || [@"test-recv" isEqualToString:peerUid]) { + Kmp_webrtcSessionDescription* answer = [[Kmp_webrtcSessionDescription alloc] initWithType:3 sdpDescription:sdp.sdpDescription]; + [_pcClient setRemoteDescriptionSdp:answer]; + } else if ([@"test" isEqualToString:peerUid]) { + Kmp_webrtcSessionDescription* offer = [[Kmp_webrtcSessionDescription alloc] initWithType:1 sdpDescription:sdp.sdpDescription]; + [_recvPcClient setRemoteDescriptionSdp:offer]; + [_recvPcClient createAnswer]; + } } - (void)onIceCandidatePeerUid:(nonnull NSString *)peerUid candidate:(nonnull Kmp_webrtcIceCandidate *)candidate { // 9. send ice candidate to remote, get ice candidate from remote, add ice candidate - [_pcClient addIceCandidateCandidate:candidate]; + if (_singlePc || [@"test-recv" isEqualToString:peerUid]) { + [_pcClient addIceCandidateCandidate:candidate]; + } else if ([@"test" isEqualToString:peerUid]) { + [_recvPcClient addIceCandidateCandidate:candidate]; + } + } - (void)onIceConnectedPeerUid:(nonnull NSString *)peerUid { @@ -405,7 +437,11 @@ - (void)onIceConnectedPeerUid:(nonnull NSString *)peerUid { return; } // 10. on ice connected, add renderer for remote stream - [sself->_pcClient addRemoteTrackRendererRenderer:sself->_remoteRenderer]; + if (sself->_singlePc) { + [sself->_pcClient addRemoteTrackRendererRenderer:sself->_remoteRenderer]; + } else { + [sself->_recvPcClient addRemoteTrackRendererRenderer:sself->_remoteRenderer]; + } [sself startGetStats]; }); @@ -429,6 +465,10 @@ - (void)onPeerConnectionStatsReadyPeerUid:(nonnull NSString *)peerUid report:(no - (void)onIceDisconnectedPeerUid:(nonnull NSString *)peerUid { } +- (void)onSetRemoteSdpResultPeerUid:(nonnull NSString *)peerUid success:(BOOL)success { + NSLog(@"XXPXX onSetRemoteSdpResultPeerUid %@", peerUid); +} + #pragma mark - CFAudioMixerDelegate - (void)onSsrcError:(int32_t)ssrc code:(int32_t)code { diff --git a/example/iosApp/iosApp/HallViewController.m b/example/iosApp/iosApp/HallViewController.m index 3b4d07c..96f97db 100644 --- a/example/iosApp/iosApp/HallViewController.m +++ b/example/iosApp/iosApp/HallViewController.m @@ -16,6 +16,7 @@ static NSString* const barButtonImageString = @"ic_settings_black_24dp.png"; @implementation HallViewController { + UISwitch* _singlePcSwitch; UISwitch* _audioOnlySwitch; } @@ -44,6 +45,17 @@ - (void)viewDidLoad { _audioOnlySwitch = [[UISwitch alloc] init]; [switchStackView addArrangedSubview:_audioOnlySwitch]; + UIStackView *switchStackView2 = [[UIStackView alloc] init]; + switchStackView2.axis = UILayoutConstraintAxisHorizontal; + switchStackView2.distribution = UIStackViewDistributionFillProportionally; + switchStackView2.spacing = 10; + UILabel *switchLabel2 = [[UILabel alloc] init]; + switchLabel2.text = @"Single pc"; + switchLabel2.font = [UIFont systemFontOfSize:20]; + [switchStackView2 addArrangedSubview:switchLabel2]; + _singlePcSwitch = [[UISwitch alloc] init]; + [switchStackView2 addArrangedSubview:_singlePcSwitch]; + UIButton* shareLog = [UIButton buttonWithType:UIButtonTypeSystem]; [shareLog setTitle:@"share log" forState:UIControlStateNormal]; [shareLog addTarget:self @@ -62,14 +74,15 @@ - (void)viewDidLoad { stackView.spacing = 10; [stackView addArrangedSubview:loopback]; + [stackView addArrangedSubview:switchStackView2]; [stackView addArrangedSubview:switchStackView]; [stackView addArrangedSubview:shareLog]; [stackView addArrangedSubview:version]; [self.view addSubview:stackView]; - // 使用 Auto Layout 约束 StackView 的位置和大小 + // use Auto Layout constrain StackView pos & size stackView.translatesAutoresizingMaskIntoConstraints = NO; - // 水平居中 + // center horizontal NSLayoutConstraint *centerXConstraint = [NSLayoutConstraint constraintWithItem:stackView attribute:NSLayoutAttributeCenterX @@ -78,7 +91,7 @@ - (void)viewDidLoad { attribute:NSLayoutAttributeCenterX multiplier:1.0 constant:0]; - // 距离顶部 50 + // top margin 50 NSLayoutConstraint *topConstraint = [NSLayoutConstraint constraintWithItem:stackView attribute:NSLayoutAttributeTop @@ -87,7 +100,7 @@ - (void)viewDidLoad { attribute:NSLayoutAttributeTop multiplier:1.0 constant:50]; - // 激活约束 + // activate constraints [NSLayoutConstraint activateConstraints:@[centerXConstraint, topConstraint]]; } @@ -144,7 +157,9 @@ - (void)onShareLog:(id)sender { } - (void)onLoopback:(id)sender { - CallViewController* viewController = [[CallViewController alloc] initWithAudioOnly:_audioOnlySwitch.isOn isLandscape:false]; + CallViewController* viewController = [[CallViewController alloc] initWithAudioOnly:_audioOnlySwitch.isOn + singlePc:_singlePcSwitch.isOn + isLandscape:false]; viewController.modalTransitionStyle = UIModalTransitionStyleCrossDissolve; [self presentViewController:viewController animated:YES completion:nil]; [[UIApplication sharedApplication] setIdleTimerDisabled:YES]; diff --git a/example/iosApp/iosApp/Info.plist b/example/iosApp/iosApp/Info.plist index 91aeb12..3e84f5e 100644 --- a/example/iosApp/iosApp/Info.plist +++ b/example/iosApp/iosApp/Info.plist @@ -38,6 +38,23 @@ CFBundleVersion 1.0 + UIApplicationSceneManifest + + UIApplicationSupportsMultipleScenes + + UISceneConfigurations + + UIWindowSceneSessionRoleApplication + + + UISceneConfigurationName + Default Configuration + UISceneDelegateClassName + SceneDelegate + + + + UIUserInterfaceStyle Light UIStatusBarTintParameters diff --git a/example/iosApp/iosApp/SceneDelegate.h b/example/iosApp/iosApp/SceneDelegate.h new file mode 100644 index 0000000..bb1f9b3 --- /dev/null +++ b/example/iosApp/iosApp/SceneDelegate.h @@ -0,0 +1,7 @@ +#import + +@interface SceneDelegate : UIResponder + +@property (strong, nonatomic) UIWindow *window; + +@end diff --git a/example/iosApp/iosApp/SceneDelegate.m b/example/iosApp/iosApp/SceneDelegate.m new file mode 100644 index 0000000..a674044 --- /dev/null +++ b/example/iosApp/iosApp/SceneDelegate.m @@ -0,0 +1,41 @@ +#import "SceneDelegate.h" +#import "HallViewController.h" + +@implementation SceneDelegate + +- (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions { + // 使用此方法选择性地配置并将给定的场景附加到UIWindow + if ([scene isKindOfClass:[UIWindowScene class]]) { + UIWindowScene *windowScene = (UIWindowScene *)scene; + self.window = [[UIWindow alloc] initWithWindowScene:windowScene]; + self.window.frame = windowScene.coordinateSpace.bounds; + + // 创建你的根视图控制器 + HallViewController *rootViewController = [[HallViewController alloc] init]; + self.window.rootViewController = rootViewController; + + [self.window makeKeyAndVisible]; + } +} + +- (void)sceneDidDisconnect:(UIScene *)scene { + // 当场景被释放时调用 +} + +- (void)sceneDidBecomeActive:(UIScene *)scene { + // 当场景从非活动状态转换为活动状态时调用 +} + +- (void)sceneWillResignActive:(UIScene *)scene { + // 当场景从活动状态转换为非活动状态时调用 +} + +- (void)sceneWillEnterForeground:(UIScene *)scene { + // 当场景从后台进入前台时调用 +} + +- (void)sceneDidEnterBackground:(UIScene *)scene { + // 当场景从前台进入后台时调用 +} + +@end diff --git a/example/macApp/Podfile b/example/macApp/Podfile index 2eed2bb..bc308ed 100644 --- a/example/macApp/Podfile +++ b/example/macApp/Podfile @@ -5,5 +5,4 @@ target 'macApp' do platform :osx, '11.0' pod 'kmp_webrtc', :path => '../../kmp-webrtc/kmp_webrtc.podspec' pod 'WebRTC', :path => '../../libs/apple/WebRTC.podspec' - pod 'kmp_xlog', '~> 1.3.4' end diff --git a/example/macApp/macApp/APPRTCViewController.m b/example/macApp/macApp/APPRTCViewController.m index 63694dd..5acf1b5 100644 --- a/example/macApp/macApp/APPRTCViewController.m +++ b/example/macApp/macApp/APPRTCViewController.m @@ -364,6 +364,9 @@ - (void)onPeerConnectionStatsReadyPeerUid:(nonnull NSString *)peerUid report:(no - (void)onIceDisconnectedPeerUid:(nonnull NSString *)peerUid { } +- (void)onSetRemoteSdpResultPeerUid:(nonnull NSString *)peerUid success:(BOOL)success { +} + #pragma mark - Private - (APPRTCMainView*)mainView { diff --git a/example/webApp/src/jsMain/kotlin/com/piasy/kmp/webrtc/web/WebApp.kt b/example/webApp/src/jsMain/kotlin/com/piasy/kmp/webrtc/web/WebApp.kt index fbf2916..368ebc0 100644 --- a/example/webApp/src/jsMain/kotlin/com/piasy/kmp/webrtc/web/WebApp.kt +++ b/example/webApp/src/jsMain/kotlin/com/piasy/kmp/webrtc/web/WebApp.kt @@ -57,11 +57,11 @@ fun startLoopback() { // 5. create PcClient localPcClient = pcClientFactory?.createPeerConnectionClient( - "test_local", PeerConnectionClientFactory.DIR_SEND_ONLY, true, + "test_local", PeerConnectionClient.DIR_SEND_ONLY, true, 800_000, 30, localPcClientCallback ) remotePcClient = pcClientFactory?.createPeerConnectionClient( - "test_remote", PeerConnectionClientFactory.DIR_RECV_ONLY, true, + "test_remote", PeerConnectionClient.DIR_RECV_ONLY, true, 800_000, 30, remotePcClientCallback ) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index e9edcd5..ffb596e 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,23 +1,29 @@ [versions] jvm = "17" iosDeploymentTarget = "14.0" -compileSdk = "35" +compileSdk = "36" minSdk = "21" -targetSdk = "35" -agp = "8.7.3" -kotlin = "2.1.0" +targetSdk = "36" +agp = "8.13.0" +kotlin = "2.2.20" +coroutine = "1.10.2" permissionsDispatcher = "4.9.2" +mockative = "3.0.1" +kmpXlog = "1.5.0" # also used in build.gradle [libraries] kotlin-stdlib-js = { module = "org.jetbrains.kotlin:kotlin-stdlib-js", version.ref = "kotlin" } -kotlinx-serialization-json = "org.jetbrains.kotlinx:kotlinx-serialization-json:1.8.0" -kmpXlog = "com.piasy:kmp-xlog:1.4.1" +kotlinx-serialization-json = "org.jetbrains.kotlinx:kotlinx-serialization-json:1.9.0" +kmpXlog = { module = "com.piasy:kmp-xlog", version.ref = "kmpXlog" } +kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "coroutine" } + +mockative = { module = "io.mockative:mockative", version.ref = "mockative" } kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test", version.ref = "kotlin" } -androidx-appcompat = "androidx.appcompat:appcompat:1.7.0" +androidx-appcompat = "androidx.appcompat:appcompat:1.7.1" permissionsDispatcher = { module = "com.github.permissions-dispatcher:permissionsdispatcher", version.ref = "permissionsDispatcher" } permissionsDispatcher-processor = { module = "com.github.permissions-dispatcher:permissionsdispatcher-processor", version.ref = "permissionsDispatcher" } -androidx-lifecycle = "androidx.lifecycle:lifecycle-runtime-ktx:2.8.7" +androidx-lifecycle = "androidx.lifecycle:lifecycle-runtime-ktx:2.9.4" [plugins] android-library = { id = "com.android.library", version.ref = "agp" } @@ -26,6 +32,11 @@ kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" } kotlinx-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" } compose-compiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" } kmp = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin" } -versions = "com.github.ben-manes.versions:0.51.0" -versionUpdate = "nl.littlerobots.version-catalog-update:0.8.5" -vanniktech-mavenPublish = "com.vanniktech.maven.publish:0.30.0" +# specify version will fail: The request for this plugin could not be satisfied because the plugin +# is already on the classpath with an unknown version +cocoapods = { id = "org.jetbrains.kotlin.native.cocoapods" } +versions = "com.github.ben-manes.versions:0.53.0" +versionUpdate = "nl.littlerobots.version-catalog-update:1.0.1" +vanniktech-mavenPublish = "com.vanniktech.maven.publish:0.34.0" +mockative = { id = "io.mockative", version.ref = "mockative" } +allopen = { id = "org.jetbrains.kotlin.plugin.allopen", version.ref = "kotlin" } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 993c6f9..84248d7 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ #Wed Nov 16 22:27:43 CST 2022 distributionBase=GRADLE_USER_HOME -distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.1.0-all.zip distributionPath=wrapper/dists zipStorePath=wrapper/dists zipStoreBase=GRADLE_USER_HOME diff --git a/kmp-webrtc/build.gradle.kts b/kmp-webrtc/build.gradle.kts index 935b129..4257c08 100644 --- a/kmp-webrtc/build.gradle.kts +++ b/kmp-webrtc/build.gradle.kts @@ -1,36 +1,23 @@ -import com.vanniktech.maven.publish.SonatypeHost - plugins { alias(libs.plugins.kmp) alias(libs.plugins.kotlinx.serialization) alias(libs.plugins.vanniktech.mavenPublish) alias(libs.plugins.android.library) - // alias will fail, see https://github.com/gradle/gradle/issues/20084 - id("org.jetbrains.kotlin.native.cocoapods") + alias(libs.plugins.cocoapods) + alias(libs.plugins.allopen) } version = Consts.releaseVersion group = Consts.releaseGroup +val projectRoot = project.rootProject.projectDir + kotlin { - val appleTargets = mapOf( - iosArm64() to "ios-arm64", - iosSimulatorArm64() to "ios-arm64_x86_64-simulator", - iosX64() to "ios-arm64_x86_64-simulator", - macosX64() to "macos-arm64_x86_64", - macosArm64() to "macos-arm64_x86_64", - ) - appleTargets.keys.forEach { - it.compilations.getByName("main").cinterops { - val webrtc by creating { - definitionFile.set(project.file("src/appleMain/cinterop/WebRTC.def")) - compilerOpts( - "-framework", "WebRTC", - "-F${project.rootProject.projectDir}/libs/apple/WebRTC.xcframework/${appleTargets[it]}" - ) - } - } - } + iosArm64() + iosSimulatorArm64() + iosX64() + macosX64() + macosArm64() cocoapods { summary = "KMP wrapper for WebRTC." @@ -43,6 +30,14 @@ kotlin { baseName = "kmp_webrtc" isStatic = true } + + pod("WebRTC") { + source = path(project.file("$projectRoot/libs/apple/")) + } + + pod("kmp_xlog") { + version = libs.versions.kmpXlog.get() + } } androidTarget { @@ -60,13 +55,13 @@ kotlin { val webrtc by creating { definitionFile.set(project.file("src/cppCommon/cinterop/WebRTC.def")) includeDirs { - allHeaders("${rootProject.projectDir}/libs/windows_linux/include") + allHeaders("$projectRoot/libs/windows_linux/include") } } } binaries { all { - linkerOpts.addAll(listOf("-L${rootProject.projectDir}/libs/windows/x64", "-lwin_pc_client.dll")) + linkerOpts.addAll(listOf("-L$projectRoot/libs/windows/x64", "-lwin_pc_client.dll")) //freeCompilerArgs = listOf("-Xadd-light-debug=enable") } sharedLib { @@ -80,13 +75,13 @@ kotlin { val webrtc by creating { definitionFile.set(project.file("src/cppCommon/cinterop/WebRTC.def")) includeDirs { - allHeaders("${rootProject.projectDir}/libs/windows_linux/include") + allHeaders("$projectRoot/libs/windows_linux/include") } } } binaries { all { - linkerOpts.addAll(listOf("-L${rootProject.projectDir}/libs/linux/x64", "-llinux_pc_client")) + linkerOpts.addAll(listOf("-L$projectRoot/libs/linux/x64", "-llinux_pc_client")) //freeCompilerArgs = listOf("-Xadd-light-debug=enable") } sharedLib { @@ -105,8 +100,10 @@ kotlin { commonMain { dependencies { + api(libs.kotlinx.coroutines.core) api(libs.kotlinx.serialization.json) api(libs.kmpXlog) + implementation(libs.mockative) } } commonTest { @@ -163,7 +160,7 @@ android { } mavenPublishing { - publishToMavenCentral(SonatypeHost.CENTRAL_PORTAL) + publishToMavenCentral() signAllPublications() @@ -195,3 +192,7 @@ mavenPublishing { } } } + +allOpen { + annotation("io.mockative.Mockable") +} diff --git a/kmp-webrtc/src/androidMain/kotlin/com/piasy/kmp/webrtc/AndroidPeerConnectionClient.kt b/kmp-webrtc/src/androidMain/kotlin/com/piasy/kmp/webrtc/AndroidPeerConnectionClient.kt index 898f03e..4e62ca7 100644 --- a/kmp-webrtc/src/androidMain/kotlin/com/piasy/kmp/webrtc/AndroidPeerConnectionClient.kt +++ b/kmp-webrtc/src/androidMain/kotlin/com/piasy/kmp/webrtc/AndroidPeerConnectionClient.kt @@ -20,38 +20,25 @@ import org.webrtc.VideoSink */ private class AndroidPeerConnectionClientCallback(private val callback: PeerConnectionClientCallback) : com.piasy.avconf.PeerConnectionClientCallback { - override fun onPreferCodecs( - peerUid: String, - sdp: String - ): String { - return callback.onPreferCodecs(peerUid, sdp) + override fun onPreferCodecs(peerUid: String, sdp: String) = callback.onPreferCodecs(peerUid, sdp) + + override fun onLocalDescription(peerUid: String, sdp: org.webrtc.SessionDescription) { + callback.onLocalDescription(peerUid, fromWebRTCSessionDescription(sdp)) } - override fun onLocalDescription( - peerUid: String, - sdp: org.webrtc.SessionDescription - ) { - return callback.onLocalDescription(peerUid, fromWebRTCSessionDescription(sdp)) + override fun onSetRemoteSdpResult(peerUid: String, success: Boolean) { + callback.onSetRemoteSdpResult(peerUid, success) } - override fun onIceCandidate( - peerUid: String, - candidate: org.webrtc.IceCandidate - ) { + override fun onIceCandidate(peerUid: String, candidate: org.webrtc.IceCandidate) { callback.onIceCandidate(peerUid, fromWebRTCIceCandidate(candidate)) } - override fun onIceCandidatesRemoved( - peerUid: String, - candidates: List - ) { + override fun onIceCandidatesRemoved(peerUid: String, candidates: List) { callback.onIceCandidatesRemoved(peerUid, fromWebRTCIceCandidates(candidates)) } - override fun onPeerConnectionStatsReady( - peerUid: String, - report: RTCStatsReport - ) { + override fun onPeerConnectionStatsReady(peerUid: String, report: RTCStatsReport) { callback.onPeerConnectionStatsReady(peerUid, fromWebRTCStatsReport(report)) } @@ -63,15 +50,12 @@ private class AndroidPeerConnectionClientCallback(private val callback: PeerConn callback.onIceDisconnected(peerUid) } - override fun onError( - peerUid: String, - code: Int - ) { + override fun onError(peerUid: String, code: Int) { callback.onError(peerUid, code) } } -class AndroidPeerConnectionClient( +internal class AndroidPeerConnectionClient( peerUid: String, private val dir: Int, needCaptureVideo: Boolean, @@ -101,11 +85,19 @@ class AndroidPeerConnectionClient( } override fun setAudioReceivingEnabled(enable: Boolean) { - realClient.setAudioReceivingEnabled(enable) + realClient.setAudioReceivingEnabled(null, enable) + } + + override fun setAudioReceivingEnabled(tid: String, enable: Boolean) { + realClient.setAudioReceivingEnabled(tid, enable) } override fun setVideoReceivingEnabled(enable: Boolean) { - realClient.setVideoReceivingEnabled(enable) + realClient.setVideoReceivingEnabled(null, enable) + } + + override fun setVideoReceivingEnabled(tid: String, enable: Boolean) { + realClient.setVideoReceivingEnabled(tid, enable) } override fun createOffer() { @@ -130,7 +122,19 @@ class AndroidPeerConnectionClient( override fun addRemoteTrackRenderer(renderer: Any) { if (renderer is VideoSink) { - realClient.addRemoteTrackRenderer(renderer) + realClient.addRemoteTrackRenderer(null, renderer) + } + } + + override fun addRemoteTrackRenderer(tid: String, renderer: Any) { + if (renderer is VideoSink) { + realClient.addRemoteTrackRenderer(tid, renderer) + } + } + + override fun removeRemoteTrackRenderer(tid: String, renderer: Any) { + if (renderer is VideoSink) { + realClient.removeRemoteTrackRenderer(tid, renderer) } } @@ -254,3 +258,7 @@ private fun fromStats(stats: org.webrtc.RTCStats): RtcStats { return RtcStats(stats.id, stats.type, stats.timestampUs.toLong(), members) } + +actual fun platformGetOfferForRtpCapabilities(block: (String) -> Unit) { + com.piasy.avconf.PeerConnectionClient.getOfferForRtpCapabilities(block) +} diff --git a/kmp-webrtc/src/androidMain/kotlin/com/piasy/kmp/webrtc/AndroidPeerConnectionClientFactory.kt b/kmp-webrtc/src/androidMain/kotlin/com/piasy/kmp/webrtc/AndroidPeerConnectionClientFactory.kt index 79b7ff1..b8f3445 100644 --- a/kmp-webrtc/src/androidMain/kotlin/com/piasy/kmp/webrtc/AndroidPeerConnectionClientFactory.kt +++ b/kmp-webrtc/src/androidMain/kotlin/com/piasy/kmp/webrtc/AndroidPeerConnectionClientFactory.kt @@ -19,7 +19,7 @@ import org.webrtc.audio.JavaAudioDeviceModule data class AndroidPrivateConfig( internal val lifecycle: Lifecycle, internal val rootEglBase: EglBase, - internal val options: PeerConnectionFactory.Options, + internal val options: PeerConnectionFactory.Options = PeerConnectionFactory.Options(), internal val enableH264HighProfile: Boolean = true, internal val mediaProjectionPermissionResultData: Intent? = null, internal val recordSamplesReadyCallback: JavaAudioDeviceModule.SamplesReadyCallback? = null, @@ -33,11 +33,11 @@ class AndroidPeerConnectionClientFactory( private val privateConfig: AndroidPrivateConfig, ) : PeerConnectionClientFactory(config, errorHandler, AndroidAudioDeviceManager(appContext, SpeakerphoneMode.AUTO)), DefaultLifecycleObserver { + init { privateConfig.lifecycle.addObserver(this) } - private val rootEglBase = EglBase.create() private var videoCapturer: VideoCapturer? = null private var videoCapturePaused = false @@ -69,7 +69,8 @@ class AndroidPeerConnectionClientFactory( peerUid: String, dir: Int, hasVideo: Boolean, videoMaxBitrateBps: Int, videoMaxFrameRate: Int, callback: PeerConnectionClientCallback - ) = AndroidPeerConnectionClient(peerUid, dir, hasVideo, videoMaxBitrateBps, videoMaxFrameRate, callback) + ): PeerConnectionClient = + AndroidPeerConnectionClient(peerUid, dir, hasVideo, videoMaxBitrateBps, videoMaxFrameRate, callback) override fun createLocalTracks() { val appContext = sAppContext ?: return @@ -79,7 +80,7 @@ class AndroidPeerConnectionClientFactory( errorHandler(ERR_VIDEO_CAPTURER_CREATE_FAIL, "") return } - com.piasy.avconf.PeerConnectionClient.createLocalTracks(appContext, rootEglBase, videoCapturer) + com.piasy.avconf.PeerConnectionClient.createLocalTracks(appContext, privateConfig.rootEglBase, videoCapturer) } override fun addLocalTrackRenderer(renderer: Any) { @@ -88,6 +89,12 @@ class AndroidPeerConnectionClientFactory( } } + override fun removeLocalTrackRenderer(renderer: Any) { + if (renderer is VideoSink) { + com.piasy.avconf.PeerConnectionClient.removeLocalTrackRenderer(renderer) + } + } + override fun startVideoCapture() { videoCapturer?.startCapture(config.videoCaptureWidth, config.videoCaptureHeight, config.videoCaptureFps) } @@ -240,7 +247,6 @@ actual fun initializeWebRTC(context: Any?, fieldTrials: String, debugLog: Boolea "$storagePath/webrtc/log", if (debugLog) Logging.LEVEL_DEBUG else Logging.LEVEL_INFO, "webrtc", - debugLog ) com.piasy.avconf.PeerConnectionClient.initialize( diff --git a/kmp-webrtc/src/androidMain/kotlin/com/piasy/kmp/webrtc/utils/PlatformInfo.android.kt b/kmp-webrtc/src/androidMain/kotlin/com/piasy/kmp/webrtc/utils/PlatformInfo.android.kt new file mode 100644 index 0000000..8566f57 --- /dev/null +++ b/kmp-webrtc/src/androidMain/kotlin/com/piasy/kmp/webrtc/utils/PlatformInfo.android.kt @@ -0,0 +1,11 @@ +package com.piasy.kmp.webrtc.utils + +import android.os.Build + +/** + * Created by Piasy{github.com/Piasy} on 2025-07-26. + */ + +actual fun platformModel(): String = Build.MODEL + +actual fun platformOsVersion(): String = Build.VERSION.RELEASE diff --git a/kmp-webrtc/src/androidMain/kotlin/com/piasy/kmp/webrtc/utils/VideoCodecUtils.android.kt b/kmp-webrtc/src/androidMain/kotlin/com/piasy/kmp/webrtc/utils/VideoCodecUtils.android.kt new file mode 100644 index 0000000..de5a7c5 --- /dev/null +++ b/kmp-webrtc/src/androidMain/kotlin/com/piasy/kmp/webrtc/utils/VideoCodecUtils.android.kt @@ -0,0 +1,14 @@ +package com.piasy.kmp.webrtc.utils + +/** + * Created by Piasy{github.com/Piasy} on 2025-07-18. + */ +internal actual fun platformIsSameH264Profile( + aParams: Map, + bParams: Map +) = com.piasy.avconf.utils.VideoCodecUtils.isSameH264Profile(aParams, bParams) + +internal actual fun platformH264GenerateProfileLevelIdForAnswer( + aParams: Map, + bParams: Map +) = com.piasy.avconf.utils.VideoCodecUtils.H264GenerateProfileLevelIdForAnswer(aParams, bParams) diff --git a/kmp-webrtc/src/appleMain/cinterop/WebRTC.def b/kmp-webrtc/src/appleMain/cinterop/WebRTC.def deleted file mode 100644 index e06feaf..0000000 --- a/kmp-webrtc/src/appleMain/cinterop/WebRTC.def +++ /dev/null @@ -1,3 +0,0 @@ -language = Objective-C -modules = WebRTC -package = WebRTC diff --git a/kmp-webrtc/src/appleMain/kotlin/com/piasy/kmp/webrtc/ObjCPeerConnectionClient.kt b/kmp-webrtc/src/appleMain/kotlin/com/piasy/kmp/webrtc/ObjCPeerConnectionClient.kt index 17e5246..8c3914b 100644 --- a/kmp-webrtc/src/appleMain/kotlin/com/piasy/kmp/webrtc/ObjCPeerConnectionClient.kt +++ b/kmp-webrtc/src/appleMain/kotlin/com/piasy/kmp/webrtc/ObjCPeerConnectionClient.kt @@ -1,9 +1,9 @@ package com.piasy.kmp.webrtc -import WebRTC.* -import WebRTC.RTCSdpType.RTCSdpTypeAnswer -import WebRTC.RTCSdpType.RTCSdpTypeOffer -import WebRTC.RTCSdpType.RTCSdpTypePrAnswer +import cocoapods.WebRTC.* +import cocoapods.WebRTC.RTCSdpType.RTCSdpTypeAnswer +import cocoapods.WebRTC.RTCSdpType.RTCSdpTypeOffer +import cocoapods.WebRTC.RTCSdpType.RTCSdpTypePrAnswer import com.piasy.kmp.webrtc.data.IceCandidate import com.piasy.kmp.webrtc.data.IceServer import com.piasy.kmp.webrtc.data.RtcStats @@ -19,38 +19,25 @@ private class ObjCPeerConnectionClientCallback(callback: PeerConnectionClientCal CFPeerConnectionClientDelegateProtocol, NSObject() { private val realCallback = WeakReference(callback) - override fun onPreferCodecs( - peerUid: String, - sdp: String - ): String { - return realCallback.get()?.onPreferCodecs(peerUid, sdp) ?: sdp - } + override fun onPreferCodecs(peerUid: String, sdp: String) = realCallback.get()?.onPreferCodecs(peerUid, sdp) ?: sdp - override fun onLocalDescription( - peerUid: String, - localSdp: RTCSessionDescription - ) { + override fun onLocalDescription(peerUid: String, localSdp: RTCSessionDescription) { realCallback.get()?.onLocalDescription(peerUid, fromWebRTCSessionDescription(localSdp)) } - override fun onIceCandidate( - peerUid: String, - candidate: RTCIceCandidate - ) { + override fun onSetRemoteSdpResult(peerUid: String, success: Boolean) { + realCallback.get()?.onSetRemoteSdpResult(peerUid, success) + } + + override fun onIceCandidate(peerUid: String, candidate: RTCIceCandidate) { realCallback.get()?.onIceCandidate(peerUid, fromWebRTCIceCandidate(candidate)) } - override fun onIceCandidatesRemoved( - peerUid: String, - candidates: List<*> - ) { + override fun onIceCandidatesRemoved(peerUid: String, candidates: List<*>) { realCallback.get()?.onIceCandidatesRemoved(peerUid, fromWebRTCIceCandidates(candidates)) } - override fun onPeerConnectionStatsReady( - peerUid: String, - report: RTCStatisticsReport - ) { + override fun onPeerConnectionStatsReady(peerUid: String, report: RTCStatisticsReport) { realCallback.get()?.onPeerConnectionStatsReady(peerUid, fromWebRTCStatsReport(report)) } @@ -62,15 +49,12 @@ private class ObjCPeerConnectionClientCallback(callback: PeerConnectionClientCal realCallback.get()?.onIceDisconnected(peerUid) } - override fun onError( - peerUid: String, - code: CFPeerConnectionError - ) { + override fun onError(peerUid: String, code: CFPeerConnectionError) { realCallback.get()?.onError(peerUid, code.toInt()) } } -class ObjCPeerConnectionClient( +internal class ObjCPeerConnectionClient( peerUid: String, private val dir: Int, needCaptureVideo: Boolean, @@ -100,11 +84,19 @@ class ObjCPeerConnectionClient( } override fun setAudioReceivingEnabled(enable: Boolean) { - realClient.setAudioReceivingEnabled(enable) + realClient.setAudioReceivingEnabled(null, enable) + } + + override fun setAudioReceivingEnabled(tid: String, enable: Boolean) { + realClient.setAudioReceivingEnabled(tid, enable) } override fun setVideoReceivingEnabled(enable: Boolean) { - realClient.setVideoReceivingEnabled(enable) + realClient.setVideoReceivingEnabled(null, enable) + } + + override fun setVideoReceivingEnabled(tid: String, enable: Boolean) { + realClient.setVideoReceivingEnabled(tid, enable) } override fun createOffer() { @@ -129,7 +121,19 @@ class ObjCPeerConnectionClient( override fun addRemoteTrackRenderer(renderer: Any) { if (renderer is RTCVideoRendererProtocol) { - realClient.addRemoteTrackRenderer(renderer) + realClient.addRemoteTrackRenderer(null, renderer) + } + } + + override fun addRemoteTrackRenderer(tid: String, renderer: Any) { + if (renderer is RTCVideoRendererProtocol) { + realClient.addRemoteTrackRenderer(tid, renderer) + } + } + + override fun removeRemoteTrackRenderer(tid: String, renderer: Any) { + if (renderer is RTCVideoRendererProtocol) { + realClient.removeRemoteTrackRenderer(tid, renderer) } } @@ -227,3 +231,9 @@ private fun fromStats(stats: RTCStatistics): RtcStats { return RtcStats(stats.id, stats.type, stats.timestamp_us.toLong(), members) } + +actual fun platformGetOfferForRtpCapabilities(block: (String) -> Unit) { + CFPeerConnectionClient.getOfferForRtpCapabilities { + block(it ?: "") + } +} diff --git a/kmp-webrtc/src/appleMain/kotlin/com/piasy/kmp/webrtc/ObjCPeerConnectionClientFactory.kt b/kmp-webrtc/src/appleMain/kotlin/com/piasy/kmp/webrtc/ObjCPeerConnectionClientFactory.kt index 2e4f03c..2a9bdf8 100644 --- a/kmp-webrtc/src/appleMain/kotlin/com/piasy/kmp/webrtc/ObjCPeerConnectionClientFactory.kt +++ b/kmp-webrtc/src/appleMain/kotlin/com/piasy/kmp/webrtc/ObjCPeerConnectionClientFactory.kt @@ -1,6 +1,6 @@ package com.piasy.kmp.webrtc -import WebRTC.* +import cocoapods.WebRTC.* import com.piasy.kmp.webrtc.utils.FieldTrial import com.piasy.kmp.xlog.Logging import com.piasy.kmp.xlog.initializeMarsXLog @@ -24,7 +24,8 @@ abstract class ObjCPeerConnectionClientFactory( peerUid: String, dir: Int, hasVideo: Boolean, videoMaxBitrateBps: Int, videoMaxFrameRate: Int, callback: PeerConnectionClientCallback - ) = ObjCPeerConnectionClient(peerUid, dir, hasVideo, videoMaxBitrateBps, videoMaxFrameRate, callback) + ): PeerConnectionClient = + ObjCPeerConnectionClient(peerUid, dir, hasVideo, videoMaxBitrateBps, videoMaxFrameRate, callback) override fun createLocalTracks() { // OWT requires video in SDP, so must have video track @@ -61,6 +62,12 @@ abstract class ObjCPeerConnectionClientFactory( } } + override fun removeLocalTrackRenderer(renderer: Any) { + if (renderer is RTCVideoRendererProtocol) { + CFPeerConnectionClient.removeLocalTrackRenderer(renderer) + } + } + override fun adaptVideoOutputFormat(width: Int, height: Int, fps: Int) { CFPeerConnectionClient.adaptVideoOutputFormat(width, height, fps) } @@ -83,7 +90,7 @@ actual fun initializeWebRTC(context: Any?, fieldTrials: String, debugLog: Boolea ) return true } - initializeMarsXLog(if (debugLog) Logging.LEVEL_DEBUG else Logging.LEVEL_INFO, "webrtc", debugLog) + initializeMarsXLog(if (debugLog) Logging.LEVEL_DEBUG else Logging.LEVEL_INFO, "webrtc") ObjCPeerConnectionClientFactory.logger.severity = if (debugLog) { RTCLoggingSeverity.RTCLoggingSeverityVerbose } else { diff --git a/kmp-webrtc/src/appleMain/kotlin/com/piasy/kmp/webrtc/utils/PlatformInfo.apple.kt b/kmp-webrtc/src/appleMain/kotlin/com/piasy/kmp/webrtc/utils/PlatformInfo.apple.kt new file mode 100644 index 0000000..6a82e39 --- /dev/null +++ b/kmp-webrtc/src/appleMain/kotlin/com/piasy/kmp/webrtc/utils/PlatformInfo.apple.kt @@ -0,0 +1,11 @@ +package com.piasy.kmp.webrtc.utils + +import cocoapods.WebRTC.CFUtils + +/** + * Created by Piasy{github.com/Piasy} on 2025-07-26. + */ + +actual fun platformModel(): String = CFUtils.modelName() ?: "Apple Unknown" + +actual fun platformOsVersion(): String = CFUtils.osVersion() ?: "Apple Unknown" diff --git a/kmp-webrtc/src/appleMain/kotlin/com/piasy/kmp/webrtc/utils/VideoCodecUtils.apple.kt b/kmp-webrtc/src/appleMain/kotlin/com/piasy/kmp/webrtc/utils/VideoCodecUtils.apple.kt new file mode 100644 index 0000000..ff238ff --- /dev/null +++ b/kmp-webrtc/src/appleMain/kotlin/com/piasy/kmp/webrtc/utils/VideoCodecUtils.apple.kt @@ -0,0 +1,18 @@ +@file:Suppress("UNCHECKED_CAST") + +package com.piasy.kmp.webrtc.utils + +import cocoapods.WebRTC.CFUtils + +/** + * Created by Piasy{github.com/Piasy} on 2025-07-18. + */ +internal actual fun platformIsSameH264Profile( + aParams: Map, + bParams: Map +): Boolean = CFUtils.isSameH264Profile(aParams as Map?, bParams as Map?) + +internal actual fun platformH264GenerateProfileLevelIdForAnswer( + aParams: Map, + bParams: Map +): String = CFUtils.H264GenerateProfileLevelIdForAnswer(aParams as Map?, bParams as Map?) ?: "" diff --git a/kmp-webrtc/src/commonMain/kotlin/com/piasy/kmp/webrtc/PeerConnectionClient.kt b/kmp-webrtc/src/commonMain/kotlin/com/piasy/kmp/webrtc/PeerConnectionClient.kt index a5fcd9c..924a953 100644 --- a/kmp-webrtc/src/commonMain/kotlin/com/piasy/kmp/webrtc/PeerConnectionClient.kt +++ b/kmp-webrtc/src/commonMain/kotlin/com/piasy/kmp/webrtc/PeerConnectionClient.kt @@ -4,6 +4,7 @@ import com.piasy.kmp.webrtc.data.IceCandidate import com.piasy.kmp.webrtc.data.IceServer import com.piasy.kmp.webrtc.data.RtcStatsReport import com.piasy.kmp.webrtc.data.SessionDescription +import kotlinx.coroutines.suspendCancellableCoroutine /** * Created by Piasy{github.com/Piasy} on 2019-11-26. @@ -19,8 +20,10 @@ interface PeerConnectionClient { fun setVideoSendingEnabled(enable: Boolean) fun setAudioReceivingEnabled(enable: Boolean) + fun setAudioReceivingEnabled(tid: String, enable: Boolean) fun setVideoReceivingEnabled(enable: Boolean) + fun setVideoReceivingEnabled(tid: String, enable: Boolean) fun createOffer() @@ -33,15 +36,14 @@ interface PeerConnectionClient { fun setRemoteDescription(sdp: SessionDescription) fun addRemoteTrackRenderer(renderer: Any) + fun addRemoteTrackRenderer(tid: String, renderer: Any) + fun removeRemoteTrackRenderer(tid: String, renderer: Any) fun send(): Boolean fun receive(): Boolean - fun startRecorder( - dir: Int, - path: String - ): Int + fun startRecorder(dir: Int, path: String): Int fun stopRecorder(dir: Int): Int @@ -97,43 +99,31 @@ interface PeerConnectionClient { else -> "UNKNOWN" } } + + suspend fun getOfferForRtpCapabilities(): String = suspendCancellableCoroutine { continuation -> + platformGetOfferForRtpCapabilities { continuation.resume(it) { _, _, _ -> } } + } } } interface PeerConnectionClientCallback { - fun onPreferCodecs( - peerUid: String, - sdp: String - ): String - - fun onLocalDescription( - peerUid: String, - sdp: SessionDescription - ) - - fun onIceCandidate( - peerUid: String, - candidate: IceCandidate - ) - - fun onIceCandidatesRemoved( - peerUid: String, - candidates: List - ) - - fun onPeerConnectionStatsReady( - peerUid: String, - report: RtcStatsReport - ) + fun onPreferCodecs(peerUid: String, sdp: String): String + + fun onLocalDescription(peerUid: String, sdp: SessionDescription) + + fun onSetRemoteSdpResult(peerUid: String, success: Boolean) {} + + fun onIceCandidate(peerUid: String, candidate: IceCandidate) + + fun onIceCandidatesRemoved(peerUid: String, candidates: List) + + fun onPeerConnectionStatsReady(peerUid: String, report: RtcStatsReport) fun onIceConnected(peerUid: String) fun onIceDisconnected(peerUid: String) - fun onError( - peerUid: String, - code: Int - ) + fun onError(peerUid: String, code: Int) companion object { const val ERR_NO_FACTORY = 1000 @@ -158,3 +148,5 @@ interface PeerConnectionClientCallback { } } } + +expect fun platformGetOfferForRtpCapabilities(block: (String) -> Unit) diff --git a/kmp-webrtc/src/commonMain/kotlin/com/piasy/kmp/webrtc/PeerConnectionClientFactory.kt b/kmp-webrtc/src/commonMain/kotlin/com/piasy/kmp/webrtc/PeerConnectionClientFactory.kt index b73ebb6..63acb92 100644 --- a/kmp-webrtc/src/commonMain/kotlin/com/piasy/kmp/webrtc/PeerConnectionClientFactory.kt +++ b/kmp-webrtc/src/commonMain/kotlin/com/piasy/kmp/webrtc/PeerConnectionClientFactory.kt @@ -1,6 +1,7 @@ package com.piasy.kmp.webrtc import com.piasy.kmp.xlog.Logging +import io.mockative.Mockable /** * Created by Piasy{github.com/Piasy} on 2025-02-16. @@ -10,6 +11,7 @@ abstract class PeerConnectionClientFactory( protected val errorHandler: (Int, String) -> Unit, private val audioDeviceManager: AudioDeviceManager, ) { + @Mockable data class Config( val videoCaptureImpl: Int, val videoCaptureWidth: Int, @@ -41,6 +43,7 @@ abstract class PeerConnectionClientFactory( abstract fun createLocalTracks() abstract fun addLocalTrackRenderer(renderer: Any) + abstract fun removeLocalTrackRenderer(renderer: Any) abstract fun startVideoCapture() abstract fun stopVideoCapture() @@ -59,22 +62,17 @@ abstract class PeerConnectionClientFactory( } protected fun logI(content: String) { - Logging.info("$TAG@${hashCode()}", content) + Logging.info(TAG, "@${hashCode()} $content") } protected fun logE(content: String) { - Logging.error("$TAG@${hashCode()}", content) + Logging.error(TAG, "@${hashCode()} $content") } companion object { internal const val TAG = "PCClientFactory" internal var sInitialized = false - const val DIR_SEND_RECV = 0 - const val DIR_SEND_ONLY = 1 - const val DIR_RECV_ONLY = 2 - const val DIR_INACTIVE = 3 - const val VIDEO_CODEC_VP8 = 1 const val VIDEO_CODEC_VP9 = 2 const val VIDEO_CODEC_H264_BASELINE = 3 diff --git a/kmp-webrtc/src/commonMain/kotlin/com/piasy/kmp/webrtc/utils/FieldTrial.kt b/kmp-webrtc/src/commonMain/kotlin/com/piasy/kmp/webrtc/utils/FieldTrial.kt index 7157184..bdbbc4d 100644 --- a/kmp-webrtc/src/commonMain/kotlin/com/piasy/kmp/webrtc/utils/FieldTrial.kt +++ b/kmp-webrtc/src/commonMain/kotlin/com/piasy/kmp/webrtc/utils/FieldTrial.kt @@ -6,7 +6,7 @@ package com.piasy.kmp.webrtc.utils internal object FieldTrial { fun fieldTrialsStringToMap(fieldTrials: String): Map { val map = HashMap() - if (fieldTrials.last() != '/') { + if (fieldTrials.isEmpty() || fieldTrials.last() != '/') { return map } val parts = fieldTrials.substring(0, fieldTrials.length - 1).split("/") diff --git a/kmp-webrtc/src/commonMain/kotlin/com/piasy/kmp/webrtc/utils/PlatformInfo.kt b/kmp-webrtc/src/commonMain/kotlin/com/piasy/kmp/webrtc/utils/PlatformInfo.kt new file mode 100644 index 0000000..6a46cb4 --- /dev/null +++ b/kmp-webrtc/src/commonMain/kotlin/com/piasy/kmp/webrtc/utils/PlatformInfo.kt @@ -0,0 +1,26 @@ +package com.piasy.kmp.webrtc.utils + +import com.piasy.kmp.xlog.Platform + +/** + * Created by Piasy{github.com/Piasy} on 2025-07-26. + */ +object PlatformInfo { + val name = when { + Platform.isJvm -> "android" + Platform.isIOS -> "ios" + Platform.isMAC -> "mac" + Platform.isWindows -> "windows" + Platform.isLinux -> "linux" + Platform.isJs -> "js" + else -> "unknown" + } + + val model = platformModel() + + val osVersion = platformOsVersion() +} + +expect fun platformModel(): String + +expect fun platformOsVersion(): String diff --git a/kmp-webrtc/src/commonMain/kotlin/com/piasy/kmp/webrtc/utils/SdpManipulator.kt b/kmp-webrtc/src/commonMain/kotlin/com/piasy/kmp/webrtc/utils/SdpManipulator.kt index d644dc6..02b287f 100644 --- a/kmp-webrtc/src/commonMain/kotlin/com/piasy/kmp/webrtc/utils/SdpManipulator.kt +++ b/kmp-webrtc/src/commonMain/kotlin/com/piasy/kmp/webrtc/utils/SdpManipulator.kt @@ -10,21 +10,19 @@ object SdpManipulator { !it.contains("urn:3gpp:video-orientation") } - fun preferCodecs( - sdp: String, - codecTypes: List, - video: Boolean - ): String { - val hasAv1x = sdp.contains("AV1X/") - val av1CodecName = if (hasAv1x) "AV1X" else "AV1" + fun preferCodecsByName(sdp: String, codecTypes: List, video: Boolean): String { + val preferredCodecs = ArrayList() + preferredCodecs.addAll(codecTypes) + return preferCodec(sdp, preferredCodecs, video) + } - val preferredCodecs = LinkedHashSet() + fun preferCodecsById(sdp: String, codecTypes: List, video: Boolean): String { + val av1CodecName = if (sdp.contains("AV1X/")) "AV1X" else "AV1" + + val preferredCodecs = ArrayList() for (codec in codecTypes) { preferredCodecs.add(codecName(codec, av1CodecName)) } - preferredCodecs.add("red") - preferredCodecs.add("ulpfec") - preferredCodecs.add("flexfec-03") return preferCodec(sdp, preferredCodecs, video) } @@ -33,10 +31,10 @@ object SdpManipulator { val lines = sdp.split("(\r\n|\n)".toRegex()) .dropLastWhile { it.isEmpty() } .filter(DISABLE_CVO_FILTER) - return joinString(lines.filter(DISABLE_CVO_FILTER), "\r\n", true) + return lines.filter(DISABLE_CVO_FILTER).joinToString("\r\n", postfix = "\r\n") } - private fun codecName(codec: Int, av1CodecName: String = "AV1") = when (codec) { + fun codecName(codec: Int, av1CodecName: String = "AV1") = when (codec) { PeerConnectionClientFactory.VIDEO_CODEC_VP8 -> "VP8" PeerConnectionClientFactory.VIDEO_CODEC_VP9 -> "VP9" PeerConnectionClientFactory.VIDEO_CODEC_H264_BASELINE, PeerConnectionClientFactory.VIDEO_CODEC_H264_HIGH_PROFILE -> "H264" @@ -45,12 +43,12 @@ object SdpManipulator { else -> "UNKNOWN" } - private fun preferCodec( - originalSdp: String, - preferredCodecs: LinkedHashSet, - video: Boolean - ): String { - val lines = originalSdp.split("(\r\n|\n)".toRegex()) + private fun preferCodec(sdp: String, preferredCodecs: ArrayList, video: Boolean): String { + preferredCodecs.add("red") + preferredCodecs.add("ulpfec") + preferredCodecs.add("flexfec-03") + + val lines = sdp.split("(\r\n|\n)".toRegex()) .dropLastWhile { it.isEmpty() } val newLines = ArrayList() @@ -109,13 +107,10 @@ object SdpManipulator { preferredPayloadTypes ) } - return joinString(newLines.filter(DISABLE_CVO_FILTER), "\r\n", true) + return newLines.filter(DISABLE_CVO_FILTER).joinToString("\r\n", postfix = "\r\n") } - private fun containsValue( - payloadTypes: HashMap>, - value: String - ): Boolean { + private fun containsValue(payloadTypes: HashMap>, value: String): Boolean { for (v in payloadTypes.values) { for (s in v) { if (s == value) { @@ -126,11 +121,7 @@ object SdpManipulator { return false } - private fun putEntry( - payloadTypes: HashMap>, - key: String, - value: String - ) { + private fun putEntry(payloadTypes: HashMap>, key: String, value: String) { var payload = payloadTypes[key] if (payload == null) { payload = ArrayList() @@ -141,7 +132,7 @@ object SdpManipulator { private fun changeMLine( mLine: String, - preferredCodecs: LinkedHashSet, + preferredCodecs: List, preferredPayloadTypes: HashMap> ): String { val oldMLineParts = mLine.split(" ") @@ -158,26 +149,6 @@ object SdpManipulator { if (rtxPayload != null) { newMLineParts.addAll(rtxPayload) } - return joinString(newMLineParts, " ", false) - } - - private fun joinString( - strings: List, - delimiter: String, - delimiterAtEnd: Boolean - ): String { - val iterator = strings.iterator() - if (!iterator.hasNext()) { - return "" - } - val builder = StringBuilder(iterator.next()) - while (iterator.hasNext()) { - builder.append(delimiter) - .append(iterator.next()) - } - if (delimiterAtEnd) { - builder.append(delimiter) - } - return builder.toString() + return newMLineParts.joinToString(" ") } } diff --git a/kmp-webrtc/src/commonMain/kotlin/com/piasy/kmp/webrtc/utils/VideoCodecUtils.kt b/kmp-webrtc/src/commonMain/kotlin/com/piasy/kmp/webrtc/utils/VideoCodecUtils.kt new file mode 100644 index 0000000..5f627fe --- /dev/null +++ b/kmp-webrtc/src/commonMain/kotlin/com/piasy/kmp/webrtc/utils/VideoCodecUtils.kt @@ -0,0 +1,24 @@ +package com.piasy.kmp.webrtc.utils + +/** + * Created by Piasy{github.com/Piasy} on 2025-07-18. + */ +object VideoCodecUtils { + fun isSameH264Profile(aParams: Map, bParams: Map) = + platformIsSameH264Profile(aParams, bParams) + + fun h264GenerateProfileLevelIdForAnswer( + aParams: Map, + bParams: Map + ) = platformH264GenerateProfileLevelIdForAnswer(aParams, bParams) +} + +internal expect fun platformIsSameH264Profile( + aParams: Map, + bParams: Map +): Boolean + +internal expect fun platformH264GenerateProfileLevelIdForAnswer( + aParams: Map, + bParams: Map +): String diff --git a/kmp-webrtc/src/commonTest/kotlin/com/piasy/kmp/webrtc/utils/FieldTrialTest.kt b/kmp-webrtc/src/commonTest/kotlin/com/piasy/kmp/webrtc/utils/FieldTrialTest.kt index 624a04e..87fe5f1 100644 --- a/kmp-webrtc/src/commonTest/kotlin/com/piasy/kmp/webrtc/utils/FieldTrialTest.kt +++ b/kmp-webrtc/src/commonTest/kotlin/com/piasy/kmp/webrtc/utils/FieldTrialTest.kt @@ -21,5 +21,10 @@ class FieldTrialTest { emptyMap(), FieldTrial.fieldTrialsStringToMap(str2) ) + + assertEquals( + emptyMap(), + FieldTrial.fieldTrialsStringToMap("") + ) } } diff --git a/kmp-webrtc/src/commonTest/kotlin/com/piasy/kmp/webrtc/utils/SdpManipulatorTest.kt b/kmp-webrtc/src/commonTest/kotlin/com/piasy/kmp/webrtc/utils/SdpManipulatorTest.kt index 27d6446..f21df2b 100644 --- a/kmp-webrtc/src/commonTest/kotlin/com/piasy/kmp/webrtc/utils/SdpManipulatorTest.kt +++ b/kmp-webrtc/src/commonTest/kotlin/com/piasy/kmp/webrtc/utils/SdpManipulatorTest.kt @@ -2,6 +2,7 @@ package com.piasy.kmp.webrtc.utils import com.piasy.kmp.webrtc.PeerConnectionClientFactory import kotlin.test.Test +import kotlin.test.assertFalse import kotlin.test.assertTrue /** @@ -14,7 +15,7 @@ internal class SdpManipulatorTest { val orgSdp = "v=0\r\no=- 3115672123855550998 2 IN IP4 127.0.0.1\r\ns=-\r\nt=0 0\r\na=group:BUNDLE 0 1\r\na=extmap-allow-mixed\r\na=msid-semantic: WMS\r\nm=audio 9 UDP/TLS/RTP/SAVPF 111 63 103 104 9 0 8 106 105 13 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:iNP9\r\na=ice-pwd:SS8UJE9t4rUv33Yh7/fuEILj\r\na=ice-options:trickle\r\na=fingerprint:sha-256 10:E4:9F:9D:10:50:BA:5B:C4:7A:C6:F2:70:CC:AF:5B:19:04:9F:D1:A7:F1:8B:B4:0B:61:00:FE:D4:6D:1C:2E\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.webrtc.org/experiments/rtp-hdrext/abs-send-time\r\na=extmap:3 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01\r\na=extmap:4 urn:ietf:params:rtp-hdrext:sdes:mid\r\na=recvonly\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:63 red/48000/2\r\na=fmtp:63 111/111\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:106 CN/32000\r\na=rtpmap:105 CN/16000\r\na=rtpmap:13 CN/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\nm=video 9 UDP/TLS/RTP/SAVPF 96 97 98 99 100 101 122 102 121 127 120 125 107 108 109 124 119 123 117 35 36 114 115 116 62 118 37\r\nc=IN IP4 0.0.0.0\r\na=rtcp:9 IN IP4 0.0.0.0\r\na=ice-ufrag:iNP9\r\na=ice-pwd:SS8UJE9t4rUv33Yh7/fuEILj\r\na=ice-options:trickle\r\na=fingerprint:sha-256 10:E4:9F:9D:10:50:BA:5B:C4:7A:C6:F2:70:CC:AF:5B:19:04:9F:D1:A7:F1:8B:B4:0B:61:00:FE:D4:6D:1C:2E\r\na=setup:actpass\r\na=mid:1\r\na=extmap:14 urn:ietf:params:rtp-hdrext:toffset\r\na=extmap:2 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time\r\na=extmap:13 urn:3gpp:video-orientation\r\na=extmap:3 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01\r\na=extmap:5 http://www.webrtc.org/experiments/rtp-hdrext/playout-delay\r\na=extmap:6 http://www.webrtc.org/experiments/rtp-hdrext/video-content-type\r\na=extmap:7 http://www.webrtc.org/experiments/rtp-hdrext/video-timing\r\na=extmap:8 http://www.webrtc.org/experiments/rtp-hdrext/color-space\r\na=extmap:4 urn:ietf:params:rtp-hdrext:sdes:mid\r\na=extmap:10 urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id\r\na=extmap:11 urn:ietf:params:rtp-hdrext:sdes:repaired-rtp-stream-id\r\na=recvonly\r\na=rtcp-mux\r\na=rtcp-rsize\r\na=rtpmap:96 VP8/90000\r\na=rtcp-fb:96 goog-remb\r\na=rtcp-fb:96 transport-cc\r\na=rtcp-fb:96 ccm fir\r\na=rtcp-fb:96 nack\r\na=rtcp-fb:96 nack pli\r\na=rtpmap:97 rtx/90000\r\na=fmtp:97 apt=96\r\na=rtpmap:98 VP9/90000\r\na=rtcp-fb:98 goog-remb\r\na=rtcp-fb:98 transport-cc\r\na=rtcp-fb:98 ccm fir\r\na=rtcp-fb:98 nack\r\na=rtcp-fb:98 nack pli\r\na=fmtp:98 profile-id=0\r\na=rtpmap:99 rtx/90000\r\na=fmtp:99 apt=98\r\na=rtpmap:100 VP9/90000\r\na=rtcp-fb:100 goog-remb\r\na=rtcp-fb:100 transport-cc\r\na=rtcp-fb:100 ccm fir\r\na=rtcp-fb:100 nack\r\na=rtcp-fb:100 nack pli\r\na=fmtp:100 profile-id=2\r\na=rtpmap:101 rtx/90000\r\na=fmtp:101 apt=100\r\na=rtpmap:122 VP9/90000\r\na=rtcp-fb:122 goog-remb\r\na=rtcp-fb:122 transport-cc\r\na=rtcp-fb:122 ccm fir\r\na=rtcp-fb:122 nack\r\na=rtcp-fb:122 nack pli\r\na=fmtp:122 profile-id=1\r\na=rtpmap:102 H264/90000\r\na=rtcp-fb:102 goog-remb\r\na=rtcp-fb:102 transport-cc\r\na=rtcp-fb:102 ccm fir\r\na=rtcp-fb:102 nack\r\na=rtcp-fb:102 nack pli\r\na=fmtp:102 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42001f\r\na=rtpmap:121 rtx/90000\r\na=fmtp:121 apt=102\r\na=rtpmap:127 H264/90000\r\na=rtcp-fb:127 goog-remb\r\na=rtcp-fb:127 transport-cc\r\na=rtcp-fb:127 ccm fir\r\na=rtcp-fb:127 nack\r\na=rtcp-fb:127 nack pli\r\na=fmtp:127 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42001f\r\na=rtpmap:120 rtx/90000\r\na=fmtp:120 apt=127\r\na=rtpmap:125 H264/90000\r\na=rtcp-fb:125 goog-remb\r\na=rtcp-fb:125 transport-cc\r\na=rtcp-fb:125 ccm fir\r\na=rtcp-fb:125 nack\r\na=rtcp-fb:125 nack pli\r\na=fmtp:125 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f\r\na=rtpmap:107 rtx/90000\r\na=fmtp:107 apt=125\r\na=rtpmap:108 H264/90000\r\na=rtcp-fb:108 goog-remb\r\na=rtcp-fb:108 transport-cc\r\na=rtcp-fb:108 ccm fir\r\na=rtcp-fb:108 nack\r\na=rtcp-fb:108 nack pli\r\na=fmtp:108 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42e01f\r\na=rtpmap:109 rtx/90000\r\na=fmtp:109 apt=108\r\na=rtpmap:124 H264/90000\r\na=rtcp-fb:124 goog-remb\r\na=rtcp-fb:124 transport-cc\r\na=rtcp-fb:124 ccm fir\r\na=rtcp-fb:124 nack\r\na=rtcp-fb:124 nack pli\r\na=fmtp:124 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=4d001f\r\na=rtpmap:119 rtx/90000\r\na=fmtp:119 apt=124\r\na=rtpmap:123 H264/90000\r\na=rtcp-fb:123 goog-remb\r\na=rtcp-fb:123 transport-cc\r\na=rtcp-fb:123 ccm fir\r\na=rtcp-fb:123 nack\r\na=rtcp-fb:123 nack pli\r\na=fmtp:123 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=4d001f\r\na=rtpmap:117 rtx/90000\r\na=fmtp:117 apt=123\r\na=rtpmap:35 AV1/90000\r\na=rtcp-fb:35 goog-remb\r\na=rtcp-fb:35 transport-cc\r\na=rtcp-fb:35 ccm fir\r\na=rtcp-fb:35 nack\r\na=rtcp-fb:35 nack pli\r\na=rtpmap:36 rtx/90000\r\na=fmtp:36 apt=35\r\na=rtpmap:114 H264/90000\r\na=rtcp-fb:114 goog-remb\r\na=rtcp-fb:114 transport-cc\r\na=rtcp-fb:114 ccm fir\r\na=rtcp-fb:114 nack\r\na=rtcp-fb:114 nack pli\r\na=fmtp:114 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=640032\r\na=rtpmap:115 rtx/90000\r\na=fmtp:115 apt=114\r\na=rtpmap:116 red/90000\r\na=rtpmap:62 rtx/90000\r\na=fmtp:62 apt=116\r\na=rtpmap:118 ulpfec/90000\r\na=rtpmap:37 flexfec-03/90000\r\na=rtcp-fb:37 goog-remb\r\na=rtcp-fb:37 transport-cc\r\na=fmtp:37 repair-window=10000000" val refinedSdp = - SdpManipulator.preferCodecs(orgSdp, listOf(PeerConnectionClientFactory.VIDEO_CODEC_H264_BASELINE), true) + SdpManipulator.preferCodecsById(orgSdp, listOf(PeerConnectionClientFactory.VIDEO_CODEC_H264_BASELINE), true) val lines = refinedSdp.split("(\r\n|\n)".toRegex()) .dropLastWhile { it.isEmpty() } @@ -29,6 +30,8 @@ internal class SdpManipulatorTest { assertTrue(false) } else { assertTrue(videoMLine.contains("37")) + assertFalse(videoMLine.contains("96")) + assertFalse(videoMLine.contains("122")) } } } diff --git a/kmp-webrtc/src/cppCommon/kotlin/com/piasy/kmp/webrtc/CppPeerConnectionClient.kt b/kmp-webrtc/src/cppCommon/kotlin/com/piasy/kmp/webrtc/CppPeerConnectionClient.kt index cbda78e..f7e0105 100644 --- a/kmp-webrtc/src/cppCommon/kotlin/com/piasy/kmp/webrtc/CppPeerConnectionClient.kt +++ b/kmp-webrtc/src/cppCommon/kotlin/com/piasy/kmp/webrtc/CppPeerConnectionClient.kt @@ -19,9 +19,7 @@ private fun freeKString(ptr: CPointer?) { } private fun pcClientCallbackOnPreferCodecs( - opaque: COpaquePointer?, - peerUidPtr: CPointer?, - sdpPtr: CPointer? + opaque: COpaquePointer?, peerUidPtr: CPointer?, sdpPtr: CPointer? ): CPointer? { if (opaque == null) { return null @@ -48,10 +46,7 @@ private fun pcClientCallbackOnPreferCodecs( } private fun pcClientCallbackOnLocalDescription( - opaque: COpaquePointer?, - peerUidPtr: CPointer?, - type: Int, - descriptionPtr: CPointer? + opaque: COpaquePointer?, peerUidPtr: CPointer?, type: Int, descriptionPtr: CPointer? ) { if (opaque == null) { return @@ -68,11 +63,8 @@ private fun pcClientCallbackOnLocalDescription( } private fun pcClientCallbackOnIceCandidate( - opaque: COpaquePointer?, - peerUidPtr: CPointer?, - sdpMidPtr: CPointer?, - sdpMlineIndex: Int, - sdpPtr: CPointer? + opaque: COpaquePointer?, peerUidPtr: CPointer?, sdpMidPtr: CPointer?, + sdpMlineIndex: Int, sdpPtr: CPointer? ) { if (opaque == null) { return @@ -90,9 +82,7 @@ private fun pcClientCallbackOnIceCandidate( } private fun pcClientCallbackOnPeerConnectionStatsReady( - opaque: COpaquePointer?, - peerUidPtr: CPointer?, - statsPtr: CPointer? + opaque: COpaquePointer?, peerUidPtr: CPointer?, statsPtr: CPointer? ) { if (opaque == null) { return @@ -114,8 +104,7 @@ private fun pcClientCallbackOnPeerConnectionStatsReady( } private fun pcClientCallbackOnIceConnected( - opaque: COpaquePointer?, - peerUidPtr: CPointer? + opaque: COpaquePointer?, peerUidPtr: CPointer? ) { if (opaque == null) { return @@ -128,8 +117,7 @@ private fun pcClientCallbackOnIceConnected( } private fun pcClientCallbackOnIceDisconnected( - opaque: COpaquePointer?, - peerUidPtr: CPointer? + opaque: COpaquePointer?, peerUidPtr: CPointer? ) { if (opaque == null) { return @@ -142,9 +130,7 @@ private fun pcClientCallbackOnIceDisconnected( } private fun pcClientCallbackOnError( - opaque: COpaquePointer?, - peerUidPtr: CPointer?, - code: Int + opaque: COpaquePointer?, peerUidPtr: CPointer?, code: Int ) { if (opaque == null) { return @@ -176,7 +162,7 @@ internal fun setPcClientLogCallback(severity: LogSeverity) { WebRTC.PCClientSetLogCallback(staticCFunction(::pcClientLogCallback), severity.ordinal) } -abstract class CppPeerConnectionClient( +internal abstract class CppPeerConnectionClient( peerUid: String, private val dir: Int, needCaptureVideo: Boolean, @@ -220,10 +206,18 @@ abstract class CppPeerConnectionClient( WebRTC.PCClientSetAudioReceivingEnabled(realClient, if (enable) 1 else 0) } + override fun setAudioReceivingEnabled(tid: String, enable: Boolean) { + //TODO("Not yet implemented") + } + override fun setVideoReceivingEnabled(enable: Boolean) { WebRTC.PCClientSetVideoReceivingEnabled(realClient, if (enable) 1 else 0) } + override fun setVideoReceivingEnabled(tid: String, enable: Boolean) { + //TODO("Not yet implemented") + } + override fun createOffer() { WebRTC.PCClientCreateOffer(realClient) } @@ -285,3 +279,7 @@ abstract class CppPeerConnectionClient( } } } + +actual fun platformGetOfferForRtpCapabilities(block: (String) -> Unit) { + // TODO +} diff --git a/kmp-webrtc/src/cppCommon/kotlin/com/piasy/kmp/webrtc/CppPeerConnectionClientFactory.kt b/kmp-webrtc/src/cppCommon/kotlin/com/piasy/kmp/webrtc/CppPeerConnectionClientFactory.kt index bc2f614..9a0f0f8 100644 --- a/kmp-webrtc/src/cppCommon/kotlin/com/piasy/kmp/webrtc/CppPeerConnectionClientFactory.kt +++ b/kmp-webrtc/src/cppCommon/kotlin/com/piasy/kmp/webrtc/CppPeerConnectionClientFactory.kt @@ -33,9 +33,6 @@ abstract class CppPeerConnectionClientFactory( protected abstract fun createVideoCapturer(): COpaquePointer? - override fun addLocalTrackRenderer(renderer: Any) { - } - override fun startVideoCapture() { logI("startVideoCapture $videoCapturer") if (videoCapturer != null) { @@ -71,7 +68,7 @@ actual fun initializeWebRTC(context: Any?, fieldTrials: String, debugLog: Boolea ) return true } - initializeMarsXLog(if (debugLog) Logging.LEVEL_DEBUG else Logging.LEVEL_INFO, "webrtc", debugLog) + initializeMarsXLog(if (debugLog) Logging.LEVEL_DEBUG else Logging.LEVEL_INFO, "webrtc") setPcClientLogCallback(if (debugLog) LogSeverity.Verbose else LogSeverity.Info) if (WebRTC.PCClientInitialize(fieldTrials) != 0) { return false diff --git a/kmp-webrtc/src/cppCommon/kotlin/com/piasy/kmp/webrtc/utils/CppUtils.kt b/kmp-webrtc/src/cppCommon/kotlin/com/piasy/kmp/webrtc/utils/CppUtils.kt index 6501aa4..99b9f43 100644 --- a/kmp-webrtc/src/cppCommon/kotlin/com/piasy/kmp/webrtc/utils/CppUtils.kt +++ b/kmp-webrtc/src/cppCommon/kotlin/com/piasy/kmp/webrtc/utils/CppUtils.kt @@ -2,7 +2,6 @@ package com.piasy.kmp.webrtc.utils import com.piasy.kmp.webrtc.CppPeerConnectionClient import com.piasy.kmp.webrtc.PeerConnectionClientCallback -import com.piasy.kmp.webrtc.PeerConnectionClientFactory import com.piasy.kmp.webrtc.data.IceCandidate import com.piasy.kmp.webrtc.data.IceServer import com.piasy.kmp.webrtc.data.RtcStatsReport @@ -28,7 +27,7 @@ fun logInfo(log: String) { } fun preferCodec(sdp: String, codec: Int): String { - return SdpManipulator.preferCodecs(sdp, listOf(codec), true) + return SdpManipulator.preferCodecsById(sdp, listOf(codec), true) } fun emptyIceServers() = emptyList() diff --git a/kmp-webrtc/src/cppCommon/kotlin/com/piasy/kmp/webrtc/utils/PlatformInfo.cpp.kt b/kmp-webrtc/src/cppCommon/kotlin/com/piasy/kmp/webrtc/utils/PlatformInfo.cpp.kt new file mode 100644 index 0000000..0dd1f82 --- /dev/null +++ b/kmp-webrtc/src/cppCommon/kotlin/com/piasy/kmp/webrtc/utils/PlatformInfo.cpp.kt @@ -0,0 +1,9 @@ +package com.piasy.kmp.webrtc.utils + +/** + * Created by Piasy{github.com/Piasy} on 2025-10-10. + */ + +actual fun platformModel(): String = "Cpp Unknown" + +actual fun platformOsVersion(): String = "Cpp Unknown" diff --git a/kmp-webrtc/src/cppCommon/kotlin/com/piasy/kmp/webrtc/utils/VideoCodecUtils.cpp.kt b/kmp-webrtc/src/cppCommon/kotlin/com/piasy/kmp/webrtc/utils/VideoCodecUtils.cpp.kt new file mode 100644 index 0000000..d731ff7 --- /dev/null +++ b/kmp-webrtc/src/cppCommon/kotlin/com/piasy/kmp/webrtc/utils/VideoCodecUtils.cpp.kt @@ -0,0 +1,14 @@ +package com.piasy.kmp.webrtc.utils + +/** + * Created by Piasy{github.com/Piasy} on 2025-10-10. + */ +internal actual fun platformIsSameH264Profile( + aParams: Map, + bParams: Map +): Boolean = false + +internal actual fun platformH264GenerateProfileLevelIdForAnswer( + aParams: Map, + bParams: Map +): String = "" diff --git a/kmp-webrtc/src/iosMain/kotlin/com/piasy/kmp/webrtc/IOSAudioDeviceManager.kt b/kmp-webrtc/src/iosMain/kotlin/com/piasy/kmp/webrtc/IOSAudioDeviceManager.kt index 9aabaff..1e48c72 100644 --- a/kmp-webrtc/src/iosMain/kotlin/com/piasy/kmp/webrtc/IOSAudioDeviceManager.kt +++ b/kmp-webrtc/src/iosMain/kotlin/com/piasy/kmp/webrtc/IOSAudioDeviceManager.kt @@ -1,6 +1,6 @@ package com.piasy.kmp.webrtc -import WebRTC.* +import cocoapods.WebRTC.* import com.piasy.kmp.webrtc.AudioDevice.BLUETOOTH import com.piasy.kmp.webrtc.AudioDevice.EARPIECE import com.piasy.kmp.webrtc.AudioDevice.NONE diff --git a/kmp-webrtc/src/iosMain/kotlin/com/piasy/kmp/webrtc/IOSPeerConnectionClientFactory.kt b/kmp-webrtc/src/iosMain/kotlin/com/piasy/kmp/webrtc/IOSPeerConnectionClientFactory.kt index cd9f246..83f4d82 100644 --- a/kmp-webrtc/src/iosMain/kotlin/com/piasy/kmp/webrtc/IOSPeerConnectionClientFactory.kt +++ b/kmp-webrtc/src/iosMain/kotlin/com/piasy/kmp/webrtc/IOSPeerConnectionClientFactory.kt @@ -1,6 +1,6 @@ package com.piasy.kmp.webrtc -import WebRTC.* +import cocoapods.WebRTC.* /** * Created by Piasy{github.com/Piasy} on 2019-12-02. diff --git a/kmp-webrtc/src/jsMain/kotlin/com/piasy/kmp/webrtc/JsPeerConnectionClient.kt b/kmp-webrtc/src/jsMain/kotlin/com/piasy/kmp/webrtc/JsPeerConnectionClient.kt index e91491c..bd4fb10 100644 --- a/kmp-webrtc/src/jsMain/kotlin/com/piasy/kmp/webrtc/JsPeerConnectionClient.kt +++ b/kmp-webrtc/src/jsMain/kotlin/com/piasy/kmp/webrtc/JsPeerConnectionClient.kt @@ -15,427 +15,443 @@ import kotlin.js.json /** * Created by Piasy{github.com/Piasy} on 2021-11-14. */ -class JsPeerConnectionClient( - private val peerUid: String, - private val dir: Int, - private val dummyVideoTrack: dynamic, - private val videoMaxBitrateBps: Int, - private val videoCaptureFps: Int, - private val callback: PeerConnectionClientCallback +internal class JsPeerConnectionClient( + private val peerUid: String, + private val dir: Int, + private val dummyVideoTrack: dynamic, + private val videoMaxBitrateBps: Int, + private val videoCaptureFps: Int, + private val callback: PeerConnectionClientCallback ) : PeerConnectionClient { - private var pc: RTCPeerConnection? = null - private var queuedCandidates: ArrayList? = ArrayList() + private var pc: RTCPeerConnection? = null + private var queuedCandidates: ArrayList? = ArrayList() - private var isInitiator = false - private var streamFulfilled = false - private var pendingCreateOffer = false - private var pendingCreateAnswer = false - private var usingDummyVideo = false + private var isInitiator = false + private var streamFulfilled = false + private var pendingCreateOffer = false + private var pendingCreateAnswer = false + private var usingDummyVideo = false - private var remoteStream: MediaStream? = null - private var remoteRenderer: HTMLVideoElement? = null + private var remoteStream: MediaStream? = null + private var remoteRenderer: HTMLVideoElement? = null - override fun createPeerConnection(iceServers: List) { - logI("createPeerConnection $iceServers") + override fun createPeerConnection(iceServers: List) { + logI("createPeerConnection $iceServers") - val config = json( - "iceServers" to iceServers.map { it.toJs() }.toTypedArray(), - ) - pc = RTCPeerConnection(config).apply { - // onsignalingstatechange = {} - // oniceconnectionstatechange = {} // oniceconnectionstatechange is legacy - onconnectionstatechange = { - when (this@JsPeerConnectionClient.pc?.iceConnectionState) { - "connected" -> callback.onIceConnected(peerUid) - "disconnected" -> callback.onIceDisconnected(peerUid) - "failed" -> callback.onError(peerUid, PeerConnectionClientCallback.ERR_ICE_FAIL) - } - } - // onicegatheringstatechange = {} - onicecandidate = { iceEvent -> - if (iceEvent.candidate != null) { - callback.onIceCandidate(peerUid, fromWebRTCIceCandidate(iceEvent.candidate)) + val config = json( + "iceServers" to iceServers.map { it.toJs() }.toTypedArray(), + ) + pc = RTCPeerConnection(config).apply { + // onsignalingstatechange = {} + // oniceconnectionstatechange = {} // oniceconnectionstatechange is legacy + onconnectionstatechange = { + when (this@JsPeerConnectionClient.pc?.iceConnectionState) { + "connected" -> callback.onIceConnected(peerUid) + "disconnected" -> callback.onIceDisconnected(peerUid) + "failed" -> callback.onError(peerUid, PeerConnectionClientCallback.ERR_ICE_FAIL) + } + } + // onicegatheringstatechange = {} + onicecandidate = { iceEvent -> + if (iceEvent.candidate != null) { + callback.onIceCandidate(peerUid, fromWebRTCIceCandidate(iceEvent.candidate)) + } + } + // ondatachannel = {} + // onnegotiationneeded = {} + ontrack = { + if (it.streams.isNotEmpty()) { + remoteStream = it.streams[0] + trySetRemoteRenderer() + } + } } - } - // ondatachannel = {} - // onnegotiationneeded = {} - ontrack = { - if (it.streams.isNotEmpty()) { - remoteStream = it.streams[0] - trySetRemoteRenderer() + + if (send()) { + logI("createPeerConnection wait for stream") + stream?.then { + logI( + "createPeerConnection stream fulfilled with ${it.getAudioTracks().size} " + + "audio tracks and ${it.getVideoTracks().size} video tracks" + ) + + streamFulfilled = true + for (track in it.getTracks()) { + pc?.addTrack(track, it) + } + + if (it.getVideoTracks().isEmpty()) { + logI("add dummy video track for audio only publisher") + it.addTrack(dummyVideoTrack) + pc?.addTrack(dummyVideoTrack, it) + usingDummyVideo = true + } + + if (pendingCreateOffer) { + logI("createPeerConnection create pending offer") + doCreateOffer() + } + + if (pendingCreateAnswer) { + logI("createPeerConnection create pending answer") + doCreateAnswer() + } + + logI("createPeerConnection success") + } + } else { + logI("createPeerConnection success") } - } } - if (send()) { - logI("createPeerConnection wait for stream") - stream?.then { - logI( - "createPeerConnection stream fulfilled with ${it.getAudioTracks().size} " + - "audio tracks and ${it.getVideoTracks().size} video tracks" - ) + override fun getStats() { + pc?.getStats()?.then { + val allStats = HashMap() + it.forEach { stats -> + val members = HashMap() + js("Object.keys(stats)").forEach { key -> + members.put(key.toString(), stats[key].toString()) + } + // don't cast with as, otherwise JS code will throw exception + val rtcStats = RtcStats( + stats.id.toString(), stats.type.toString(), stats.timestamp * 1000, members + ) + allStats[stats.id.toString()] = rtcStats + Unit + } - streamFulfilled = true - for (track in it.getTracks()) { - pc?.addTrack(track, it) + // don't cast with as, otherwise JS code will throw exception + val rtcStatsReport = RtcStatsReport(it.timestamp * 1000, allStats) + callback.onPeerConnectionStatsReady(peerUid, rtcStatsReport) } + } - if (it.getVideoTracks().isEmpty()) { - logI("add dummy video track for audio only publisher") - it.addTrack(dummyVideoTrack) - pc?.addTrack(dummyVideoTrack, it) - usingDummyVideo = true - } + override fun setAudioSendingEnabled(enable: Boolean) { + logI("setAudioSendingEnabled $enable") + toggleTrackMute(false, !enable) + } - if (pendingCreateOffer) { - logI("createPeerConnection create pending offer") - doCreateOffer() + override fun setVideoSendingEnabled(enable: Boolean) { + logI("setVideoSendingEnabled $enable") + if (enable && usingDummyVideo) { + window.navigator.mediaDevices.getUserMedia( + MediaStreamConstraints( + video = true, + audio = false + ) + ) + .then { + val tracks = it.getVideoTracks() + if (tracks.size == 1) { + stream?.then { it2 -> + it2.removeTrack(dummyVideoTrack) + it2.addTrack(tracks[0]) + localPreview?.srcObject = it2 + usingDummyVideo = false + + pc?.getSenders()?.forEach { it3 -> + if (it3.track?.kind == "video") { + it3.replaceTrack(tracks[0]) + } + } + } + } + } + } else { + toggleTrackMute(true, !enable) } + } - if (pendingCreateAnswer) { - logI("createPeerConnection create pending answer") - doCreateAnswer() - } + override fun setAudioReceivingEnabled(enable: Boolean) { + } - logI("createPeerConnection success") - } - } else { - logI("createPeerConnection success") + override fun setAudioReceivingEnabled(tid: String, enable: Boolean) { + //TODO("Not yet implemented") } - } - override fun getStats() { - pc?.getStats()?.then { - val allStats = HashMap() - it.forEach { stats -> - val members = HashMap() - js("Object.keys(stats)").forEach { key -> - members.put(key.toString(), stats[key].toString()) + override fun setVideoReceivingEnabled(enable: Boolean) { + } + + override fun setVideoReceivingEnabled(tid: String, enable: Boolean) { + //TODO("Not yet implemented") + } + + override fun createOffer() { + logI("createOffer") + + isInitiator = true + if (streamFulfilled || !send()) { + doCreateOffer() + } else { + logI("createOffer pending") + pendingCreateOffer = true + checkStreamTimeout() } - // don't cast with as, otherwise JS code will throw exception - val rtcStats = RtcStats( - stats.id.toString(), stats.type.toString(), stats.timestamp * 1000, members - ) - allStats[stats.id.toString()] = rtcStats - Unit - } - - // don't cast with as, otherwise JS code will throw exception - val rtcStatsReport = RtcStatsReport(it.timestamp * 1000, allStats) - callback.onPeerConnectionStatsReady(peerUid, rtcStatsReport) - } - } - - override fun setAudioSendingEnabled(enable: Boolean) { - logI("setAudioSendingEnabled $enable") - toggleTrackMute(false, !enable) - } - - override fun setVideoSendingEnabled(enable: Boolean) { - logI("setVideoSendingEnabled $enable") - if (enable && usingDummyVideo) { - window.navigator.mediaDevices.getUserMedia( - MediaStreamConstraints( - video = true, - audio = false - ) - ) - .then { - val tracks = it.getVideoTracks() - if (tracks.size == 1) { - stream?.then { it2 -> - it2.removeTrack(dummyVideoTrack) - it2.addTrack(tracks[0]) - localPreview?.srcObject = it2 - usingDummyVideo = false - - pc?.getSenders()?.forEach { it3 -> - if (it3.track?.kind == "video") { - it3.replaceTrack(tracks[0]) + } + + private fun checkStreamTimeout() { + window.setTimeout({ + if (!streamStarted) { + logE("open media stream timeout") + callback.onError(peerUid, PeerConnectionClientCallback.ERR_OPEN_MEDIA_STREAM_FAIL) + } + }, 3000) + } + + private fun doCreateOffer() { + pendingCreateOffer = false + + if (send()) { + pc?.createOffer(json()) + } else { + pc?.createOffer( + json( + "offerToReceiveAudio" to true, + "offerToReceiveVideo" to true + ) + ) + }?.then { setLocalDescription(it) } + } + + private fun setLocalDescription(sdp: RTCSessionDescription) { + logI("${sdp.type} created") + + val refinedSdp = callback.onPreferCodecs(peerUid, sdp.sdp) + pc?.setLocalDescription( + json( + "type" to sdp.type, + "sdp" to refinedSdp + ) + )?.then { + logI("set ${sdp.type} success") + + if (isInitiator) { + // For offering peer connection we first create offer and set + // local SDP, then after receiving answer set remote SDP. + if (pc?.remoteDescription == null) { + logI("Local SDP set successfully") + callback.onLocalDescription( + peerUid, SessionDescription(fromWebRTCSdpType(sdp.type), refinedSdp) + ) + doSetVideoMaxBitrate() + } else { + // We've just set remote description, so drain remote + // and send local ICE candidates. + logI("Remote SDP set successfully") + drainIceCandidate() + } + } else { + // For answering peer connection we set remote SDP and then + // create answer and set local SDP. + if (pc?.localDescription != null) { + // We've just set our local SDP so time to send it, drain + // remote and send local ICE candidates. + logI("Local SDP set successfully") + callback.onLocalDescription( + peerUid, SessionDescription(fromWebRTCSdpType(sdp.type), refinedSdp) + ) + doSetVideoMaxBitrate() + drainIceCandidate() + } else { + // We've just set remote SDP - do nothing for now - + // answer will be created soon. + logI("Remote SDP set successfully") } - } } - } } - } else { - toggleTrackMute(true, !enable) - } - } - - override fun setAudioReceivingEnabled(enable: Boolean) { - } - - override fun setVideoReceivingEnabled(enable: Boolean) { - } - - override fun createOffer() { - logI("createOffer") - - isInitiator = true - if (streamFulfilled || !send()) { - doCreateOffer() - } else { - logI("createOffer pending") - pendingCreateOffer = true - checkStreamTimeout() - } - } - - private fun checkStreamTimeout() { - window.setTimeout({ - if (!streamStarted) { - logE("open media stream timeout") - callback.onError(peerUid, PeerConnectionClientCallback.ERR_OPEN_MEDIA_STREAM_FAIL) - } - }, 3000) - } - - private fun doCreateOffer() { - pendingCreateOffer = false - - if (send()) { - pc?.createOffer(json()) - } else { - pc?.createOffer( - json( - "offerToReceiveAudio" to true, - "offerToReceiveVideo" to true - ) - ) - }?.then { setLocalDescription(it) } - } - - private fun setLocalDescription(sdp: RTCSessionDescription) { - logI("${sdp.type} created") - - val refinedSdp = callback.onPreferCodecs(peerUid, sdp.sdp) - pc?.setLocalDescription( - json( - "type" to sdp.type, - "sdp" to refinedSdp - ) - )?.then { - logI("set ${sdp.type} success") - - if (isInitiator) { - // For offering peer connection we first create offer and set - // local SDP, then after receiving answer set remote SDP. - if (pc?.remoteDescription == null) { - logI("Local SDP set successfully") - callback.onLocalDescription( - peerUid, SessionDescription(fromWebRTCSdpType(sdp.type), refinedSdp) - ) - doSetVideoMaxBitrate() + } + + override fun createAnswer() { + logI("createAnswer") + + isInitiator = false + if (streamFulfilled || !send()) { + doCreateAnswer() } else { - // We've just set remote description, so drain remote - // and send local ICE candidates. - logI("Remote SDP set successfully") - drainIceCandidate() + logI("createAnswer pending") + pendingCreateAnswer = true + checkStreamTimeout() } - } else { - // For answering peer connection we set remote SDP and then - // create answer and set local SDP. - if (pc?.localDescription != null) { - // We've just set our local SDP so time to send it, drain - // remote and send local ICE candidates. - logI("Local SDP set successfully") - callback.onLocalDescription( - peerUid, SessionDescription(fromWebRTCSdpType(sdp.type), refinedSdp) - ) - doSetVideoMaxBitrate() - drainIceCandidate() + } + + private fun doCreateAnswer() { + pendingCreateAnswer = false + + if (send()) { + pc?.createAnswer(json()) } else { - // We've just set remote SDP - do nothing for now - - // answer will be created soon. - logI("Remote SDP set successfully") - } - } + pc?.createAnswer( + json( + "offerToReceiveAudio" to true, + "offerToReceiveVideo" to true + ) + ) + }?.then { setLocalDescription(it) } } - } - override fun createAnswer() { - logI("createAnswer") + private fun doSetVideoMaxBitrate() { + val senders = pc?.getSenders() ?: return + for (sender in senders) { + val track = sender.track ?: continue + if (track.kind == "video") { + logI("doSetVideoMaxBitrate: found video sender") + val params = sender.getParameters() + if (params.encodings.isEmpty()) { + logE("doSetVideoMaxBitrate: RtpParameters are not ready") + return + } - isInitiator = false - if (streamFulfilled || !send()) { - doCreateAnswer() - } else { - logI("createAnswer pending") - pendingCreateAnswer = true - checkStreamTimeout() + for (encoding in params.encodings) { + encoding.maxBitrate = videoMaxBitrateBps * 1000 + encoding.maxFramerate = videoCaptureFps + } + sender.setParameters(params) + logI("doSetVideoMaxBitrate to $videoMaxBitrateBps") + } + } } - } - private fun doCreateAnswer() { - pendingCreateAnswer = false + override fun addIceCandidate(candidate: IceCandidate) { + logI("addIceCandidate $candidate") + if (queuedCandidates != null) { + queuedCandidates?.add(candidate) + } else { + doAddIceCandidate(candidate) + } + } - if (send()) { - pc?.createAnswer(json()) - } else { - pc?.createAnswer( - json( - "offerToReceiveAudio" to true, - "offerToReceiveVideo" to true + private fun doAddIceCandidate(candidate: IceCandidate) { + val jsCandidate = RTCIceCandidate( + json( + "sdpMid" to candidate.sdpMid, + "sdpMLineIndex" to candidate.sdpMLineIndex, + "candidate" to candidate.sdp + ) ) - ) - }?.then { setLocalDescription(it) } - } - - private fun doSetVideoMaxBitrate() { - val senders = pc?.getSenders() ?: return - for (sender in senders) { - val track = sender.track ?: continue - if (track.kind == "video") { - logI("doSetVideoMaxBitrate: found video sender") - val params = sender.getParameters() - if (params.encodings.isEmpty()) { - logE("doSetVideoMaxBitrate: RtpParameters are not ready") - return + pc?.addIceCandidate(jsCandidate) + } + + private fun drainIceCandidate() { + val candidates = queuedCandidates ?: return + queuedCandidates = null + for (candidate in candidates) { + doAddIceCandidate(candidate) + } + } + + override fun removeIceCandidates(candidates: List) { + // unsupported + } + + override fun setRemoteDescription(sdp: SessionDescription) { + logI("setRemoteDescription") + pc?.setRemoteDescription(toWebRTCSessionDescription(sdp))?.then { + if (isInitiator) { + drainIceCandidate() + } } + } - for (encoding in params.encodings) { - encoding.maxBitrate = videoMaxBitrateBps * 1000 - encoding.maxFramerate = videoCaptureFps + override fun addRemoteTrackRenderer(renderer: Any) { + if (renderer is HTMLVideoElement) { + remoteRenderer = renderer + trySetRemoteRenderer() } - sender.setParameters(params) - logI("doSetVideoMaxBitrate to $videoMaxBitrateBps") - } - } - } - - override fun addIceCandidate(candidate: IceCandidate) { - logI("addIceCandidate $candidate") - if (queuedCandidates != null) { - queuedCandidates?.add(candidate) - } else { - doAddIceCandidate(candidate) - } - } - - private fun doAddIceCandidate(candidate: IceCandidate) { - val jsCandidate = RTCIceCandidate( - json( - "sdpMid" to candidate.sdpMid, - "sdpMLineIndex" to candidate.sdpMLineIndex, - "candidate" to candidate.sdp - ) - ) - pc?.addIceCandidate(jsCandidate) - } - - private fun drainIceCandidate() { - val candidates = queuedCandidates ?: return - queuedCandidates = null - for (candidate in candidates) { - doAddIceCandidate(candidate) - } - } - - override fun removeIceCandidates(candidates: List) { - // unsupported - } - - override fun setRemoteDescription(sdp: SessionDescription) { - logI("setRemoteDescription") - pc?.setRemoteDescription(toWebRTCSessionDescription(sdp))?.then { - if (isInitiator) { - drainIceCandidate() - } - } - } - - override fun addRemoteTrackRenderer(renderer: Any) { - if (renderer is HTMLVideoElement) { - remoteRenderer = renderer - trySetRemoteRenderer() - } - } - - override fun send(): Boolean { - return PeerConnectionClient.dirSend(dir) - } - - override fun receive(): Boolean { - return PeerConnectionClient.dirRecv(dir) - } - - override fun startRecorder(dir: Int, path: String): Int { - logE("recorder not supported on Web") - return -1 - } - - override fun stopRecorder(dir: Int): Int { - logE("recorder not supported on Web") - return -1 - } - - override fun togglePauseStreaming(pause: Boolean) { - logE("pause streaming not supported on Web") - } - - override fun requestFir() { - logE("requestFir not supported on Web") - } - - override fun getRealClient(): Any { - return pc ?: false - } - - override fun close() { - logI("close") - pc?.close() - logI("close success") - } - - private fun trySetRemoteRenderer() { - val stream = remoteStream ?: return - val renderer = remoteRenderer ?: return - logI("setRemoteRenderer $renderer") - renderer.srcObject = stream - } - - private fun IceServer.toJs(): Json = json( - "urls" to urls, - "username" to username, - "credential" to password - ) - - private fun fromWebRTCSdpType(type: String) = when (type) { - "offer" -> SessionDescription.OFFER - "answer" -> SessionDescription.ANSWER - "pranswer" -> SessionDescription.PRANSWER - else -> SessionDescription.OFFER - } - - private fun toWebRTCSessionDescription(sdp: SessionDescription): dynamic { - val type = when (sdp.type) { - SessionDescription.OFFER -> "offer" - SessionDescription.ANSWER -> "answer" - SessionDescription.PRANSWER -> "pranswer" - else -> "offer" - } - return json( - "type" to type, - "sdp" to sdp.sdpDescription, + } + + override fun addRemoteTrackRenderer(tid: String, renderer: Any) { + //TODO("Not yet implemented") + } + + override fun removeRemoteTrackRenderer(tid: String, renderer: Any) { + //TODO("Not yet implemented") + } + + override fun send(): Boolean { + return PeerConnectionClient.dirSend(dir) + } + + override fun receive(): Boolean { + return PeerConnectionClient.dirRecv(dir) + } + + override fun startRecorder(dir: Int, path: String): Int { + logE("recorder not supported on Web") + return -1 + } + + override fun stopRecorder(dir: Int): Int { + logE("recorder not supported on Web") + return -1 + } + + override fun togglePauseStreaming(pause: Boolean) { + logE("pause streaming not supported on Web") + } + + override fun requestFir() { + logE("requestFir not supported on Web") + } + + override fun getRealClient(): Any { + return pc ?: false + } + + override fun close() { + logI("close") + pc?.close() + logI("close success") + } + + private fun trySetRemoteRenderer() { + val stream = remoteStream ?: return + val renderer = remoteRenderer ?: return + logI("setRemoteRenderer $renderer") + renderer.srcObject = stream + } + + private fun IceServer.toJs(): Json = json( + "urls" to urls, + "username" to username, + "credential" to password ) - } - private fun fromWebRTCIceCandidate(candidate: RTCIceCandidate) = IceCandidate( - candidate.sdpMid, candidate.sdpMLineIndex, candidate.candidate - ) + private fun fromWebRTCSdpType(type: String) = when (type) { + "offer" -> SessionDescription.OFFER + "answer" -> SessionDescription.ANSWER + "pranswer" -> SessionDescription.PRANSWER + else -> SessionDescription.OFFER + } - private fun logI(content: String) { - Logging.info("PeerConnectionClient@${hashCode()}", content) - } + private fun toWebRTCSessionDescription(sdp: SessionDescription): dynamic { + val type = when (sdp.type) { + SessionDescription.OFFER -> "offer" + SessionDescription.ANSWER -> "answer" + SessionDescription.PRANSWER -> "pranswer" + else -> "offer" + } + return json( + "type" to type, + "sdp" to sdp.sdpDescription, + ) + } + + private fun fromWebRTCIceCandidate(candidate: RTCIceCandidate) = IceCandidate( + candidate.sdpMid, candidate.sdpMLineIndex, candidate.candidate + ) - private fun logE(content: String) { - Logging.error("PeerConnectionClient@${hashCode()}", content) - } + private fun logI(content: String) { + Logging.info("PeerConnectionClient@${hashCode()}", content) + } + + private fun logE(content: String) { + Logging.error("PeerConnectionClient@${hashCode()}", content) + } - companion object { - private var stream: Promise? = null - private var localPreview: HTMLVideoElement? = null - private var streamStarted = false + companion object { + private var stream: Promise? = null + private var localPreview: HTMLVideoElement? = null + private var streamStarted = false // private var resolveAudioTrack: dynamic = null // private var resolveVideoTrack: dynamic = null // private val audioTrack = Promise { resolve: (MediaStreamTrack) -> Unit, _: (Throwable) -> Unit -> @@ -445,42 +461,51 @@ class JsPeerConnectionClient( // resolveVideoTrack = resolve // } - fun startLocalStream(needVideo: Boolean, needAudio: Boolean) { - streamStarted = false + fun startLocalStream(needVideo: Boolean, needAudio: Boolean) { + streamStarted = false - stream = - window.navigator.mediaDevices.getUserMedia(MediaStreamConstraints(needVideo, needAudio)) - stream?.then { - streamStarted = true - } - } + stream = + window.navigator.mediaDevices.getUserMedia(MediaStreamConstraints(needVideo, needAudio)) + stream?.then { + streamStarted = true + } + } - fun startLocalPreview(renderer: HTMLVideoElement) { - localPreview = renderer - stream?.then { - Logging.info("PeerConnectionClient", "startLocalPreview $renderer") - renderer.srcObject = it - } - } + fun startLocalPreview(renderer: HTMLVideoElement) { + localPreview = renderer + stream?.then { + Logging.info("PeerConnectionClient", "startLocalPreview $renderer") + renderer.srcObject = it + } + } - fun stopLocalStream() { - stream?.then { - for (track in it.getTracks()) { - if (track.readyState == MediaStreamTrackState.LIVE) { - track.stop() - } + fun stopLocalPreview(renderer: HTMLVideoElement) { + localPreview = null + renderer.srcObject = null } - } - } - fun toggleTrackMute(video: Boolean, mute: Boolean) { - stream?.then { - for (track in it.getTracks()) { - if ((track.kind == "video" && video) || (track.kind == "audio" && !video)) { - track.enabled = !mute - } + fun stopLocalStream() { + stream?.then { + for (track in it.getTracks()) { + if (track.readyState == MediaStreamTrackState.LIVE) { + track.stop() + } + } + } + } + + fun toggleTrackMute(video: Boolean, mute: Boolean) { + stream?.then { + for (track in it.getTracks()) { + if ((track.kind == "video" && video) || (track.kind == "audio" && !video)) { + track.enabled = !mute + } + } + } } - } } - } +} + +actual fun platformGetOfferForRtpCapabilities(block: (String) -> Unit) { + // TODO } diff --git a/kmp-webrtc/src/jsMain/kotlin/com/piasy/kmp/webrtc/JsPeerConnectionClientFactory.kt b/kmp-webrtc/src/jsMain/kotlin/com/piasy/kmp/webrtc/JsPeerConnectionClientFactory.kt index 21af0cc..fee60c5 100644 --- a/kmp-webrtc/src/jsMain/kotlin/com/piasy/kmp/webrtc/JsPeerConnectionClientFactory.kt +++ b/kmp-webrtc/src/jsMain/kotlin/com/piasy/kmp/webrtc/JsPeerConnectionClientFactory.kt @@ -20,9 +20,8 @@ class JsPeerConnectionClientFactory( peerUid: String, dir: Int, hasVideo: Boolean, videoMaxBitrateBps: Int, videoMaxFrameRate: Int, callback: PeerConnectionClientCallback - ) = JsPeerConnectionClient( - peerUid, dir, privateConfig.dummyVideoTrack, - videoMaxBitrateBps, videoMaxFrameRate, callback + ): PeerConnectionClient = JsPeerConnectionClient( + peerUid, dir, privateConfig.dummyVideoTrack, videoMaxBitrateBps, videoMaxFrameRate, callback ) override fun createLocalTracks() { @@ -35,6 +34,12 @@ class JsPeerConnectionClientFactory( } } + override fun removeLocalTrackRenderer(renderer: Any) { + if (renderer is HTMLVideoElement) { + JsPeerConnectionClient.stopLocalPreview(renderer) + } + } + override fun startVideoCapture() { } diff --git a/kmp-webrtc/src/jsMain/kotlin/com/piasy/kmp/webrtc/utils/PlatformInfo.js.kt b/kmp-webrtc/src/jsMain/kotlin/com/piasy/kmp/webrtc/utils/PlatformInfo.js.kt new file mode 100644 index 0000000..21676f6 --- /dev/null +++ b/kmp-webrtc/src/jsMain/kotlin/com/piasy/kmp/webrtc/utils/PlatformInfo.js.kt @@ -0,0 +1,9 @@ +package com.piasy.kmp.webrtc.utils + +/** + * Created by Piasy{github.com/Piasy} on 2025-10-10. + */ + +actual fun platformModel(): String = "Js Unknown" + +actual fun platformOsVersion(): String = "Js Unknown" diff --git a/kmp-webrtc/src/jsMain/kotlin/com/piasy/kmp/webrtc/utils/VideoCodecUtils.js.kt b/kmp-webrtc/src/jsMain/kotlin/com/piasy/kmp/webrtc/utils/VideoCodecUtils.js.kt new file mode 100644 index 0000000..d731ff7 --- /dev/null +++ b/kmp-webrtc/src/jsMain/kotlin/com/piasy/kmp/webrtc/utils/VideoCodecUtils.js.kt @@ -0,0 +1,14 @@ +package com.piasy.kmp.webrtc.utils + +/** + * Created by Piasy{github.com/Piasy} on 2025-10-10. + */ +internal actual fun platformIsSameH264Profile( + aParams: Map, + bParams: Map +): Boolean = false + +internal actual fun platformH264GenerateProfileLevelIdForAnswer( + aParams: Map, + bParams: Map +): String = "" diff --git a/kmp-webrtc/src/linuxMain/kotlin/com/piasy/kmp/webrtc/LinuxPeerConnectionClient.kt b/kmp-webrtc/src/linuxMain/kotlin/com/piasy/kmp/webrtc/LinuxPeerConnectionClient.kt index 6e39740..1cd5612 100644 --- a/kmp-webrtc/src/linuxMain/kotlin/com/piasy/kmp/webrtc/LinuxPeerConnectionClient.kt +++ b/kmp-webrtc/src/linuxMain/kotlin/com/piasy/kmp/webrtc/LinuxPeerConnectionClient.kt @@ -5,7 +5,7 @@ import kotlinx.cinterop.COpaquePointer /** * Created by Piasy{github.com/Piasy} on 2025-03-02. */ -class LinuxPeerConnectionClient( +internal class LinuxPeerConnectionClient( peerUid: String, dir: Int, needCaptureVideo: Boolean, @@ -19,4 +19,12 @@ class LinuxPeerConnectionClient( // WebRTC.PCClientAddRemoteRenderer(realClient, renderer) // } } + + override fun addRemoteTrackRenderer(tid: String, renderer: Any) { + //TODO("Not yet implemented") + } + + override fun removeRemoteTrackRenderer(tid: String, renderer: Any) { + //TODO("Not yet implemented") + } } diff --git a/kmp-webrtc/src/linuxMain/kotlin/com/piasy/kmp/webrtc/LinuxPeerConnectionClientFactory.kt b/kmp-webrtc/src/linuxMain/kotlin/com/piasy/kmp/webrtc/LinuxPeerConnectionClientFactory.kt index 243c2bd..7dbfdf5 100644 --- a/kmp-webrtc/src/linuxMain/kotlin/com/piasy/kmp/webrtc/LinuxPeerConnectionClientFactory.kt +++ b/kmp-webrtc/src/linuxMain/kotlin/com/piasy/kmp/webrtc/LinuxPeerConnectionClientFactory.kt @@ -24,12 +24,19 @@ class LinuxPeerConnectionClientFactory( peerUid: String, dir: Int, hasVideo: Boolean, videoMaxBitrateBps: Int, videoMaxFrameRate: Int, callback: PeerConnectionClientCallback - ) = LinuxPeerConnectionClient(peerUid, dir, hasVideo, videoMaxBitrateBps, videoMaxFrameRate, callback) + ): PeerConnectionClient = + LinuxPeerConnectionClient(peerUid, dir, hasVideo, videoMaxBitrateBps, videoMaxFrameRate, callback) override fun createVideoCapturer() = WebRTC.PCClientVideoCapturerCreate( config.videoCaptureImpl, config.videoCaptureWidth, config.videoCaptureHeight, config.videoCaptureFps, privateConfig.captureFilePath, privateConfig.captureDumpPath ) + + override fun addLocalTrackRenderer(renderer: Any) { + } + + override fun removeLocalTrackRenderer(renderer: Any) { + } } actual fun createPeerConnectionClientFactory( diff --git a/kmp-webrtc/src/macosMain/kotlin/com/piasy/kmp/webrtc/MacPeerConnectionClientFactory.kt b/kmp-webrtc/src/macosMain/kotlin/com/piasy/kmp/webrtc/MacPeerConnectionClientFactory.kt index 3a6807c..622ba74 100644 --- a/kmp-webrtc/src/macosMain/kotlin/com/piasy/kmp/webrtc/MacPeerConnectionClientFactory.kt +++ b/kmp-webrtc/src/macosMain/kotlin/com/piasy/kmp/webrtc/MacPeerConnectionClientFactory.kt @@ -1,6 +1,6 @@ package com.piasy.kmp.webrtc -import WebRTC.* +import cocoapods.WebRTC.* /** * Created by Piasy{github.com/Piasy} on 2025-02-27. diff --git a/kmp-webrtc/src/mingwMain/kotlin/com/piasy/kmp/webrtc/WinPeerConnectionClient.kt b/kmp-webrtc/src/mingwMain/kotlin/com/piasy/kmp/webrtc/WinPeerConnectionClient.kt index eaf95fc..a497c54 100644 --- a/kmp-webrtc/src/mingwMain/kotlin/com/piasy/kmp/webrtc/WinPeerConnectionClient.kt +++ b/kmp-webrtc/src/mingwMain/kotlin/com/piasy/kmp/webrtc/WinPeerConnectionClient.kt @@ -5,7 +5,7 @@ import kotlinx.cinterop.COpaquePointer /** * Created by Piasy{github.com/Piasy} on 2025-03-02. */ -class WinPeerConnectionClient( +internal class WinPeerConnectionClient( peerUid: String, dir: Int, needCaptureVideo: Boolean, @@ -19,4 +19,12 @@ class WinPeerConnectionClient( WebRTC.PCClientAddRemoteRenderer(realClient, renderer) } } + + override fun addRemoteTrackRenderer(tid: String, renderer: Any) { + //TODO("Not yet implemented") + } + + override fun removeRemoteTrackRenderer(tid: String, renderer: Any) { + //TODO("Not yet implemented") + } } diff --git a/kmp-webrtc/src/mingwMain/kotlin/com/piasy/kmp/webrtc/WinPeerConnectionClientFactory.kt b/kmp-webrtc/src/mingwMain/kotlin/com/piasy/kmp/webrtc/WinPeerConnectionClientFactory.kt index 8da0326..c01f1ee 100644 --- a/kmp-webrtc/src/mingwMain/kotlin/com/piasy/kmp/webrtc/WinPeerConnectionClientFactory.kt +++ b/kmp-webrtc/src/mingwMain/kotlin/com/piasy/kmp/webrtc/WinPeerConnectionClientFactory.kt @@ -19,12 +19,25 @@ class WinPeerConnectionClientFactory( peerUid: String, dir: Int, hasVideo: Boolean, videoMaxBitrateBps: Int, videoMaxFrameRate: Int, callback: PeerConnectionClientCallback - ) = WinPeerConnectionClient(peerUid, dir, hasVideo, videoMaxBitrateBps, videoMaxFrameRate, callback) + ): PeerConnectionClient = + WinPeerConnectionClient(peerUid, dir, hasVideo, videoMaxBitrateBps, videoMaxFrameRate, callback) override fun createVideoCapturer() = WebRTC.PCClientVideoCapturerCreate( config.videoCaptureImpl, config.videoCaptureWidth, config.videoCaptureHeight, config.videoCaptureFps, "", "" - ); + ) + + override fun addLocalTrackRenderer(renderer: Any) { + if (renderer is COpaquePointer) { + WebRTC.PCClientAddLocalRenderer(renderer) + } + } + + override fun removeLocalTrackRenderer(renderer: Any) { + if (renderer is COpaquePointer) { + WebRTC.PCClientRemoveLocalRenderer(renderer) + } + } } actual fun createPeerConnectionClientFactory( diff --git a/kotlin-js-store/yarn.lock b/kotlin-js-store/yarn.lock index 65ba2c4..b1d5581 100644 --- a/kotlin-js-store/yarn.lock +++ b/kotlin-js-store/yarn.lock @@ -7,10 +7,22 @@ resolved "https://registry.yarnpkg.com/@colors/colors/-/colors-1.5.0.tgz#bb504579c1cae923e6576a4f5da43d25f97bdbd9" integrity sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ== -"@discoveryjs/json-ext@^0.5.0": - version "0.5.7" - resolved "https://registry.yarnpkg.com/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz#1d572bfbbe14b7704e0ba0f39b74815b84870d70" - integrity sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw== +"@discoveryjs/json-ext@^0.6.1": + version "0.6.3" + resolved "https://registry.yarnpkg.com/@discoveryjs/json-ext/-/json-ext-0.6.3.tgz#f13c7c205915eb91ae54c557f5e92bddd8be0e83" + integrity sha512-4B4OijXeVNOPZlYA2oEwWOTkzyltLao+xbotHQeqN++Rv27Y6s818+n2Qkp8q+Fxhn0t/5lA5X1Mxktud8eayQ== + +"@isaacs/cliui@^8.0.2": + version "8.0.2" + resolved "https://registry.yarnpkg.com/@isaacs/cliui/-/cliui-8.0.2.tgz#b37667b7bc181c168782259bab42474fbf52b550" + integrity sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA== + dependencies: + string-width "^5.1.2" + string-width-cjs "npm:string-width@^4.2.0" + strip-ansi "^7.0.1" + strip-ansi-cjs "npm:strip-ansi@^6.0.1" + wrap-ansi "^8.1.0" + wrap-ansi-cjs "npm:wrap-ansi@^7.0.0" "@jridgewell/gen-mapping@^0.3.5": version "0.3.5" @@ -49,7 +61,7 @@ resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz#3188bcb273a414b0d215fd22a58540b989b9409a" integrity sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ== -"@jridgewell/trace-mapping@^0.3.20", "@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.25": +"@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.25": version "0.3.25" resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz#15f190e98895f3fc23276ee14bc76b675c2e50f0" integrity sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ== @@ -57,16 +69,60 @@ "@jridgewell/resolve-uri" "^3.1.0" "@jridgewell/sourcemap-codec" "^1.4.14" -"@js-joda/core@3.2.0": - version "3.2.0" - resolved "https://registry.yarnpkg.com/@js-joda/core/-/core-3.2.0.tgz#3e61e21b7b2b8a6be746df1335cf91d70db2a273" - integrity sha512-PMqgJ0sw5B7FKb2d5bWYIoxjri+QlW/Pys7+Rw82jSH0QN3rB05jZ/VrrsUdh1w4+i2kw9JOejXGq/KhDOX7Kg== +"@jsonjoy.com/base64@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@jsonjoy.com/base64/-/base64-1.1.2.tgz#cf8ea9dcb849b81c95f14fc0aaa151c6b54d2578" + integrity sha512-q6XAnWQDIMA3+FTiOYajoYqySkO+JSat0ytXGSuRdq9uXE7o92gzuQwQM14xaCRlBLGq3v5miDGC4vkVTn54xA== + +"@jsonjoy.com/buffers@^1.0.0", "@jsonjoy.com/buffers@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@jsonjoy.com/buffers/-/buffers-1.2.0.tgz#57b9bbc509055de80f22cf6b696ac7efd7554046" + integrity sha512-6RX+W5a+ZUY/c/7J5s5jK9UinLfJo5oWKh84fb4X0yK2q4WXEWUWZWuEMjvCb1YNUQhEAhUfr5scEGOH7jC4YQ== + +"@jsonjoy.com/codegen@^1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@jsonjoy.com/codegen/-/codegen-1.0.0.tgz#5c23f796c47675f166d23b948cdb889184b93207" + integrity sha512-E8Oy+08cmCf0EK/NMxpaJZmOxPqM+6iSe2S4nlSBrPZOORoDJILxtbSUEDKQyTamm/BVAhIGllOBNU79/dwf0g== + +"@jsonjoy.com/json-pack@^1.11.0": + version "1.20.0" + resolved "https://registry.yarnpkg.com/@jsonjoy.com/json-pack/-/json-pack-1.20.0.tgz#c59cbac0f3fcab0fa9fd5a36cd2b15d020b0bc0a" + integrity sha512-adcXFVorSQULtT4XDL0giRLr2EVGIcyWm6eQKZWTrRA4EEydGOY8QVQtL0PaITQpUyu+lOd/QOicw6vdy1v8QQ== + dependencies: + "@jsonjoy.com/base64" "^1.1.2" + "@jsonjoy.com/buffers" "^1.2.0" + "@jsonjoy.com/codegen" "^1.0.0" + "@jsonjoy.com/json-pointer" "^1.0.2" + "@jsonjoy.com/util" "^1.9.0" + hyperdyperid "^1.2.0" + thingies "^2.5.0" + +"@jsonjoy.com/json-pointer@^1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@jsonjoy.com/json-pointer/-/json-pointer-1.0.2.tgz#049cb530ac24e84cba08590c5e36b431c4843408" + integrity sha512-Fsn6wM2zlDzY1U+v4Nc8bo3bVqgfNTGcn6dMgs6FjrEnt4ZCe60o6ByKRjOGlI2gow0aE/Q41QOigdTqkyK5fg== + dependencies: + "@jsonjoy.com/codegen" "^1.0.0" + "@jsonjoy.com/util" "^1.9.0" + +"@jsonjoy.com/util@^1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@jsonjoy.com/util/-/util-1.9.0.tgz#7ee95586aed0a766b746cd8d8363e336c3c47c46" + integrity sha512-pLuQo+VPRnN8hfPqUTLTHk126wuYdXVxE6aDmjSeV4NCAgyxWbiOIeNJVtID3h1Vzpoi9m4jXezf73I6LgabgQ== + dependencies: + "@jsonjoy.com/buffers" "^1.0.0" + "@jsonjoy.com/codegen" "^1.0.0" "@leichtgewicht/ip-codec@^2.0.1": version "2.0.4" resolved "https://registry.yarnpkg.com/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz#b2ac626d6cb9c8718ab459166d4bb405b8ffa78b" integrity sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A== +"@pkgjs/parseargs@^0.11.0": + version "0.11.0" + resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33" + integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg== + "@socket.io/component-emitter@~3.1.0": version "3.1.0" resolved "https://registry.yarnpkg.com/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz#96116f2a912e0c02817345b3c10751069920d553" @@ -80,17 +136,17 @@ "@types/connect" "*" "@types/node" "*" -"@types/bonjour@^3.5.9": - version "3.5.10" - resolved "https://registry.yarnpkg.com/@types/bonjour/-/bonjour-3.5.10.tgz#0f6aadfe00ea414edc86f5d106357cda9701e275" - integrity sha512-p7ienRMiS41Nu2/igbJxxLDWrSZ0WxM8UQgCeO9KhoVF7cOVFkrKsiDr1EsJIla8vV3oEEjGcz11jc5yimhzZw== +"@types/bonjour@^3.5.13": + version "3.5.13" + resolved "https://registry.yarnpkg.com/@types/bonjour/-/bonjour-3.5.13.tgz#adf90ce1a105e81dd1f9c61fdc5afda1bfb92956" + integrity sha512-z9fJ5Im06zvUL548KvYNecEVlA7cVDkGUi6kZusb04mpyEFKCIZJvloCcmpmLaIahDpOQGHaHmG6imtPMmPXGQ== dependencies: "@types/node" "*" -"@types/connect-history-api-fallback@^1.3.5": - version "1.3.5" - resolved "https://registry.yarnpkg.com/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.3.5.tgz#d1f7a8a09d0ed5a57aee5ae9c18ab9b803205dae" - integrity sha512-h8QJa8xSb1WD4fpKBDcATDNGXghFj6/3GRWG6dhmRcu0RX1Ubasur2Uvx5aeEwlf0MwblEC2bMzzMQntxnw/Cw== +"@types/connect-history-api-fallback@^1.5.4": + version "1.5.4" + resolved "https://registry.yarnpkg.com/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.5.4.tgz#7de71645a103056b48ac3ce07b3520b819c1d5b3" + integrity sha512-n6Cr2xS1h4uAulPRdlw6Jl6s1oG8KrVilPN2yUITEs+K48EzMJJ3W1xy8K5eWuFvjp3R74AOIGSmp2UfBJ8HFw== dependencies: "@types/express-serve-static-core" "*" "@types/node" "*" @@ -114,10 +170,26 @@ dependencies: "@types/node" "*" -"@types/estree@^1.0.5": - version "1.0.6" - resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.6.tgz#628effeeae2064a1b4e79f78e81d87b7e5fc7b50" - integrity sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw== +"@types/eslint-scope@^3.7.7": + version "3.7.7" + resolved "https://registry.yarnpkg.com/@types/eslint-scope/-/eslint-scope-3.7.7.tgz#3108bd5f18b0cdb277c867b3dd449c9ed7079ac5" + integrity sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg== + dependencies: + "@types/eslint" "*" + "@types/estree" "*" + +"@types/eslint@*": + version "9.6.1" + resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-9.6.1.tgz#d5795ad732ce81715f27f75da913004a56751584" + integrity sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag== + dependencies: + "@types/estree" "*" + "@types/json-schema" "*" + +"@types/estree@*", "@types/estree@^1.0.8": + version "1.0.8" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.8.tgz#958b91c991b1867ced318bedea0e215ee050726e" + integrity sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w== "@types/express-serve-static-core@*", "@types/express-serve-static-core@^4.17.31": version "4.17.31" @@ -128,7 +200,17 @@ "@types/qs" "*" "@types/range-parser" "*" -"@types/express@*", "@types/express@^4.17.13": +"@types/express-serve-static-core@^4.17.21", "@types/express-serve-static-core@^4.17.33": + version "4.19.7" + resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.19.7.tgz#f1d306dcc03b1aafbfb6b4fe684cce8a31cffc10" + integrity sha512-FvPtiIf1LfhzsaIXhv/PHan/2FeQBbtBDtfX2QfvPxdUelMDEckK08SM6nqo1MIZY3RUlfA+HV8+hFUSio78qg== + dependencies: + "@types/node" "*" + "@types/qs" "*" + "@types/range-parser" "*" + "@types/send" "*" + +"@types/express@*": version "4.17.15" resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.15.tgz#9290e983ec8b054b65a5abccb610411953d417ff" integrity sha512-Yv0k4bXGOH+8a+7bELd2PqHQsuiANB+A8a4gnQrkRWzrkKlb6KHaVvyXhqs04sVW/OWlbPyYxRgYlIXLfrufMQ== @@ -138,6 +220,21 @@ "@types/qs" "*" "@types/serve-static" "*" +"@types/express@^4.17.21": + version "4.17.23" + resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.23.tgz#35af3193c640bfd4d7fe77191cd0ed411a433bef" + integrity sha512-Crp6WY9aTYP3qPi2wGDo9iUe/rceX01UMhnF1jmwDcKCFM6cx7YhGP/Mpr3y9AASpfHixIG0E6azCcL5OcDHsQ== + dependencies: + "@types/body-parser" "*" + "@types/express-serve-static-core" "^4.17.33" + "@types/qs" "*" + "@types/serve-static" "*" + +"@types/http-errors@*": + version "2.0.5" + resolved "https://registry.yarnpkg.com/@types/http-errors/-/http-errors-2.0.5.tgz#5b749ab2b16ba113423feb1a64a95dcd30398472" + integrity sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg== + "@types/http-proxy@^1.17.8": version "1.17.9" resolved "https://registry.yarnpkg.com/@types/http-proxy/-/http-proxy-1.17.9.tgz#7f0e7931343761efde1e2bf48c40f02f3f75705a" @@ -145,7 +242,12 @@ dependencies: "@types/node" "*" -"@types/json-schema@^7.0.8", "@types/json-schema@^7.0.9": +"@types/json-schema@*", "@types/json-schema@^7.0.15": + version "7.0.15" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841" + integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA== + +"@types/json-schema@^7.0.9": version "7.0.11" resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.11.tgz#d421b6c527a3037f7c84433fd2c4229e016863d3" integrity sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ== @@ -155,6 +257,11 @@ resolved "https://registry.yarnpkg.com/@types/mime/-/mime-3.0.1.tgz#5f8f2bca0a5863cb69bc0b0acd88c96cb1d4ae10" integrity sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA== +"@types/mime@^1": + version "1.3.5" + resolved "https://registry.yarnpkg.com/@types/mime/-/mime-1.3.5.tgz#1ef302e01cf7d2b5a0fa526790c9123bf1d06690" + integrity sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w== + "@types/node-forge@^1.3.0": version "1.3.11" resolved "https://registry.yarnpkg.com/@types/node-forge/-/node-forge-1.3.11.tgz#0972ea538ddb0f4d9c2fa0ec5db5724773a604da" @@ -177,19 +284,34 @@ resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.4.tgz#cd667bcfdd025213aafb7ca5915a932590acdcdc" integrity sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw== -"@types/retry@0.12.0": - version "0.12.0" - resolved "https://registry.yarnpkg.com/@types/retry/-/retry-0.12.0.tgz#2b35eccfcee7d38cd72ad99232fbd58bffb3c84d" - integrity sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA== +"@types/retry@0.12.2": + version "0.12.2" + resolved "https://registry.yarnpkg.com/@types/retry/-/retry-0.12.2.tgz#ed279a64fa438bb69f2480eda44937912bb7480a" + integrity sha512-XISRgDJ2Tc5q4TRqvgJtzsRkFYNJzZrhTdtMoGVBttwzzQJkPnS3WWTFc7kuDRoPtPakl+T+OfdEUjYJj7Jbow== -"@types/serve-index@^1.9.1": - version "1.9.1" - resolved "https://registry.yarnpkg.com/@types/serve-index/-/serve-index-1.9.1.tgz#1b5e85370a192c01ec6cec4735cf2917337a6278" - integrity sha512-d/Hs3nWDxNL2xAczmOVZNj92YZCS6RGxfBPjKzuu/XirCgXdpKEb88dYNbrYGint6IVWLNP+yonwVAuRC0T2Dg== +"@types/send@*": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@types/send/-/send-1.2.0.tgz#ae9dfa0e3ab0306d3c566182324a54c4be2fb45a" + integrity sha512-zBF6vZJn1IaMpg3xUF25VK3gd3l8zwE0ZLRX7dsQyQi+jp4E8mMDJNGDYnYse+bQhYwWERTxVwHpi3dMOq7RKQ== + dependencies: + "@types/node" "*" + +"@types/send@<1": + version "0.17.5" + resolved "https://registry.yarnpkg.com/@types/send/-/send-0.17.5.tgz#d991d4f2b16f2b1ef497131f00a9114290791e74" + integrity sha512-z6F2D3cOStZvuk2SaP6YrwkNO65iTZcwA2ZkSABegdkAh/lf+Aa/YQndZVfmEXT5vgAp6zv06VQ3ejSVjAny4w== + dependencies: + "@types/mime" "^1" + "@types/node" "*" + +"@types/serve-index@^1.9.4": + version "1.9.4" + resolved "https://registry.yarnpkg.com/@types/serve-index/-/serve-index-1.9.4.tgz#e6ae13d5053cb06ed36392110b4f9a49ac4ec898" + integrity sha512-qLpGZ/c2fhSs5gnYsQxtDEq3Oy8SXPClIXkW5ghvAvsNuVSA8k+gCONcUCS/UjLEYvYps+e8uBtfgXgvhwfNug== dependencies: "@types/express" "*" -"@types/serve-static@*", "@types/serve-static@^1.13.10": +"@types/serve-static@*": version "1.15.0" resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.15.0.tgz#c7930ff61afb334e121a9da780aac0d9b8f34155" integrity sha512-z5xyF6uh8CbjAu9760KDKsH2FcDxZ2tFCsA4HIMWE6IkiYMXfVoa+4f9KX+FN0ZLsaMw1WNG2ETLA6N+/YA+cg== @@ -197,21 +319,30 @@ "@types/mime" "*" "@types/node" "*" -"@types/sockjs@^0.3.33": - version "0.3.33" - resolved "https://registry.yarnpkg.com/@types/sockjs/-/sockjs-0.3.33.tgz#570d3a0b99ac995360e3136fd6045113b1bd236f" - integrity sha512-f0KEEe05NvUnat+boPTZ0dgaLZ4SfSouXUgv5noUiefG2ajgKjmETo9ZJyuqsl7dfl2aHlLJUiki6B4ZYldiiw== +"@types/serve-static@^1.15.5": + version "1.15.9" + resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.15.9.tgz#f9b08ab7dd8bbb076f06f5f983b683654fe0a025" + integrity sha512-dOTIuqpWLyl3BBXU3maNQsS4A3zuuoYRNIvYSxxhebPfXg2mzWQEPne/nlJ37yOse6uGgR386uTpdsx4D0QZWA== dependencies: + "@types/http-errors" "*" "@types/node" "*" + "@types/send" "<1" -"@types/ws@^8.5.5": - version "8.5.13" - resolved "https://registry.yarnpkg.com/@types/ws/-/ws-8.5.13.tgz#6414c280875e2691d0d1e080b05addbf5cb91e20" - integrity sha512-osM/gWBTPKgHV8XkTunnegTRIsvF6owmf5w+JtAfOw472dptdm0dlGv4xCt6GwQRcC2XVOvvRE/0bAoQcL2QkA== +"@types/sockjs@^0.3.36": + version "0.3.36" + resolved "https://registry.yarnpkg.com/@types/sockjs/-/sockjs-0.3.36.tgz#ce322cf07bcc119d4cbf7f88954f3a3bd0f67535" + integrity sha512-MK9V6NzAS1+Ud7JV9lJLFqW85VbC9dq3LmwZCuBe4wBDgKC0Kj/jd8Xl+nSviU+Qc3+m7umHHyHg//2KSa0a0Q== dependencies: "@types/node" "*" -"@webassemblyjs/ast@1.14.1", "@webassemblyjs/ast@^1.12.1": +"@types/ws@^8.5.10": + version "8.18.1" + resolved "https://registry.yarnpkg.com/@types/ws/-/ws-8.18.1.tgz#48464e4bf2ddfd17db13d845467f6070ffea4aa9" + integrity sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg== + dependencies: + "@types/node" "*" + +"@webassemblyjs/ast@1.14.1", "@webassemblyjs/ast@^1.14.1": version "1.14.1" resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.14.1.tgz#a9f6a07f2b03c95c8d38c4536a1fdfb521ff55b6" integrity sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ== @@ -277,7 +408,7 @@ resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.13.2.tgz#917a20e93f71ad5602966c2d685ae0c6c21f60f1" integrity sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ== -"@webassemblyjs/wasm-edit@^1.12.1": +"@webassemblyjs/wasm-edit@^1.14.1": version "1.14.1" resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.14.1.tgz#ac6689f502219b59198ddec42dcd496b1004d597" integrity sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ== @@ -312,7 +443,7 @@ "@webassemblyjs/wasm-gen" "1.14.1" "@webassemblyjs/wasm-parser" "1.14.1" -"@webassemblyjs/wasm-parser@1.14.1", "@webassemblyjs/wasm-parser@^1.12.1": +"@webassemblyjs/wasm-parser@1.14.1", "@webassemblyjs/wasm-parser@^1.14.1": version "1.14.1" resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.14.1.tgz#b3e13f1893605ca78b52c68e54cf6a865f90b9fb" integrity sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ== @@ -332,20 +463,20 @@ "@webassemblyjs/ast" "1.14.1" "@xtuc/long" "4.2.2" -"@webpack-cli/configtest@^2.1.1": - version "2.1.1" - resolved "https://registry.yarnpkg.com/@webpack-cli/configtest/-/configtest-2.1.1.tgz#3b2f852e91dac6e3b85fb2a314fb8bef46d94646" - integrity sha512-wy0mglZpDSiSS0XHrVR+BAdId2+yxPSoJW8fsna3ZpYSlufjvxnP4YbKTCBZnNIcGN4r6ZPXV55X4mYExOfLmw== +"@webpack-cli/configtest@^3.0.1": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@webpack-cli/configtest/-/configtest-3.0.1.tgz#76ac285b9658fa642ce238c276264589aa2b6b57" + integrity sha512-u8d0pJ5YFgneF/GuvEiDA61Tf1VDomHHYMjv/wc9XzYj7nopltpG96nXN5dJRstxZhcNpV1g+nT6CydO7pHbjA== -"@webpack-cli/info@^2.0.2": - version "2.0.2" - resolved "https://registry.yarnpkg.com/@webpack-cli/info/-/info-2.0.2.tgz#cc3fbf22efeb88ff62310cf885c5b09f44ae0fdd" - integrity sha512-zLHQdI/Qs1UyT5UBdWNqsARasIA+AaF8t+4u2aS2nEpBQh2mWIVb8qAklq0eUENnC5mOItrIB4LiS9xMtph18A== +"@webpack-cli/info@^3.0.1": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@webpack-cli/info/-/info-3.0.1.tgz#3cff37fabb7d4ecaab6a8a4757d3826cf5888c63" + integrity sha512-coEmDzc2u/ffMvuW9aCjoRzNSPDl/XLuhPdlFRpT9tZHmJ/039az33CE7uH+8s0uL1j5ZNtfdv0HkfaKRBGJsQ== -"@webpack-cli/serve@^2.0.5": - version "2.0.5" - resolved "https://registry.yarnpkg.com/@webpack-cli/serve/-/serve-2.0.5.tgz#325db42395cd49fe6c14057f9a900e427df8810e" - integrity sha512-lqaoKnRYBdo1UgDX8uF24AfGMifWK19TxPmM5FHc2vAGxrJ/qtyUyFBWoY1tISZdelsQ5fBcOusifo5o5wSJxQ== +"@webpack-cli/serve@^3.0.1": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@webpack-cli/serve/-/serve-3.0.1.tgz#bd8b1f824d57e30faa19eb78e4c0951056f72f00" + integrity sha512-sbgw03xQaCLiT6gcY/6u3qBDn01CWw/nbaXl3gTdTFuJJ75Gffv3E3DBpgvY2fkkrdS1fpjaXNOmJlnbtKauKg== "@xtuc/ieee754@^1.2.0": version "1.2.0" @@ -365,20 +496,15 @@ accepts@~1.3.4, accepts@~1.3.5, accepts@~1.3.8: mime-types "~2.1.34" negotiator "0.6.3" -acorn-import-attributes@^1.9.5: - version "1.9.5" - resolved "https://registry.yarnpkg.com/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz#7eb1557b1ba05ef18b5ed0ec67591bfab04688ef" - integrity sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ== - -acorn@^8.7.1: - version "8.8.2" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.2.tgz#1b2f25db02af965399b9776b0c2c391276d37c4a" - integrity sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw== +acorn-import-phases@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/acorn-import-phases/-/acorn-import-phases-1.0.4.tgz#16eb850ba99a056cb7cbfe872ffb8972e18c8bd7" + integrity sha512-wKmbr/DDiIXzEOiWrTTUcDm24kQ2vGfZQvM2fwg2vXqR5uW6aapr7ObPtj1th32b9u90/Pf4AItvdTh42fBmVQ== -acorn@^8.8.2: - version "8.14.0" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.14.0.tgz#063e2c70cac5fb4f6467f0b11152e04c682795b0" - integrity sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA== +acorn@^8.15.0: + version "8.15.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.15.0.tgz#a360898bc415edaac46c8241f6383975b930b816" + integrity sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg== ajv-formats@^2.1.1: version "2.1.1" @@ -387,28 +513,13 @@ ajv-formats@^2.1.1: dependencies: ajv "^8.0.0" -ajv-keywords@^3.5.2: - version "3.5.2" - resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz#31f29da5ab6e00d1c2d329acf7b5929614d5014d" - integrity sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ== - -ajv-keywords@^5.0.0: +ajv-keywords@^5.0.0, ajv-keywords@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-5.1.0.tgz#69d4d385a4733cdbeab44964a1170a88f87f0e16" integrity sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw== dependencies: fast-deep-equal "^3.1.3" -ajv@^6.12.5: - version "6.12.6" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" - integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== - 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" - ajv@^8.0.0, ajv@^8.8.0: version "8.11.2" resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.11.2.tgz#aecb20b50607acf2569b6382167b65a96008bb78" @@ -419,10 +530,15 @@ ajv@^8.0.0, ajv@^8.8.0: require-from-string "^2.0.2" uri-js "^4.2.2" -ansi-colors@^4.1.3: - version "4.1.3" - resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.3.tgz#37611340eb2243e70cc604cad35d63270d48781b" - integrity sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw== +ajv@^8.9.0: + version "8.17.1" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.17.1.tgz#37d9a5c776af6bc92d7f4f9510eba4c0a60d11a6" + integrity sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g== + dependencies: + fast-deep-equal "^3.1.3" + fast-uri "^3.0.1" + json-schema-traverse "^1.0.0" + require-from-string "^2.0.2" ansi-html-community@^0.0.8: version "0.0.8" @@ -434,6 +550,11 @@ ansi-regex@^5.0.1: resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== +ansi-regex@^6.0.1: + version "6.2.2" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-6.2.2.tgz#60216eea464d864597ce2832000738a0589650c1" + integrity sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg== + ansi-styles@^4.0.0, ansi-styles@^4.1.0: version "4.3.0" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" @@ -441,6 +562,11 @@ ansi-styles@^4.0.0, ansi-styles@^4.1.0: dependencies: color-convert "^2.0.1" +ansi-styles@^6.1.0: + version "6.2.3" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.2.3.tgz#c044d5dcc521a076413472597a1acb1f103c4041" + integrity sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg== + anymatch@~3.1.2: version "3.1.3" resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e" @@ -459,11 +585,6 @@ array-flatten@1.1.1: resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" integrity sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg== -array-flatten@^2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-2.1.2.tgz#24ef80a28c1a893617e2149b0c6d0d788293b099" - integrity sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ== - balanced-match@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" @@ -474,6 +595,11 @@ base64id@2.0.0, base64id@~2.0.0: resolved "https://registry.yarnpkg.com/base64id/-/base64id-2.0.0.tgz#2770ac6bc47d312af97a8bf9a634342e0cd25cb6" integrity sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog== +baseline-browser-mapping@^2.8.9: + version "2.8.15" + resolved "https://registry.yarnpkg.com/baseline-browser-mapping/-/baseline-browser-mapping-2.8.15.tgz#78d795047dcd878e29c0c0f7a916c782fb96e062" + integrity sha512-qsJ8/X+UypqxHXN75M7dF88jNK37dLBRW7LeUzCPz+TNs37G8cfWy9nWzS+LS//g600zrt2le9KuXt0rWfDz5Q== + batch@0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/batch/-/batch-0.6.1.tgz#dc34314f4e679318093fc760272525f94bf25c16" @@ -484,7 +610,25 @@ binary-extensions@^2.0.0: resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== -body-parser@1.20.1, body-parser@^1.19.0: +body-parser@1.20.3: + version "1.20.3" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.3.tgz#1953431221c6fb5cd63c4b36d53fab0928e548c6" + integrity sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g== + dependencies: + bytes "3.1.2" + content-type "~1.0.5" + 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.13.0" + raw-body "2.5.2" + type-is "~1.6.18" + unpipe "1.0.0" + +body-parser@^1.19.0: version "1.20.1" resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.1.tgz#b1812a8912c195cd371a3ee5e66faa2338a5c668" integrity sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw== @@ -502,13 +646,11 @@ body-parser@1.20.1, body-parser@^1.19.0: type-is "~1.6.18" unpipe "1.0.0" -bonjour-service@^1.0.11: - version "1.0.14" - resolved "https://registry.yarnpkg.com/bonjour-service/-/bonjour-service-1.0.14.tgz#c346f5bc84e87802d08f8d5a60b93f758e514ee7" - integrity sha512-HIMbgLnk1Vqvs6B4Wq5ep7mxvj9sGz5d1JJyDNSGNIdA/w2MCz6GTjWTdjqOJV1bEPj+6IkxDvWNFKEBxNt4kQ== +bonjour-service@^1.2.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/bonjour-service/-/bonjour-service-1.3.0.tgz#80d867430b5a0da64e82a8047fc1e355bdb71722" + integrity sha512-3YuAUiSkWykd+2Azjgyxei8OWf8thdn8AITIog2M4UICzoqfjlqr64WIjEXZllf/W6vK1goqleSR6brGomxQqA== dependencies: - array-flatten "^2.1.2" - dns-equal "^1.0.0" fast-deep-equal "^3.1.3" multicast-dns "^7.2.5" @@ -539,21 +681,29 @@ browser-stdout@^1.3.1: resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60" integrity sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw== -browserslist@^4.21.10: - version "4.24.2" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.24.2.tgz#f5845bc91069dbd55ee89faf9822e1d885d16580" - integrity sha512-ZIc+Q62revdMcqC6aChtW4jz3My3klmCO1fEmINZY/8J3EpBg5/A/D0AKmBveUh6pgoeycoMkVMko84tuYS+Gg== +browserslist@^4.24.0: + version "4.26.3" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.26.3.tgz#40fbfe2d1cd420281ce5b1caa8840049c79afb56" + integrity sha512-lAUU+02RFBuCKQPj/P6NgjlbCnLBMp4UtgTx7vNHd3XSIJF87s9a5rA3aH2yw3GS9DqZAUbOtZdCCiZeVRqt0w== dependencies: - caniuse-lite "^1.0.30001669" - electron-to-chromium "^1.5.41" - node-releases "^2.0.18" - update-browserslist-db "^1.1.1" + baseline-browser-mapping "^2.8.9" + caniuse-lite "^1.0.30001746" + electron-to-chromium "^1.5.227" + node-releases "^2.0.21" + update-browserslist-db "^1.1.3" buffer-from@^1.0.0: version "1.1.2" resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== +bundle-name@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/bundle-name/-/bundle-name-4.1.0.tgz#f3b96b34160d6431a19d7688135af7cfb8797889" + integrity sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q== + dependencies: + run-applescript "^7.0.0" + bytes@3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" @@ -564,6 +714,14 @@ bytes@3.1.2: resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5" integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg== +call-bind-apply-helpers@^1.0.1, call-bind-apply-helpers@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz#4b5428c222be985d79c3d82657479dbe0b59b2d6" + integrity sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ== + dependencies: + es-errors "^1.3.0" + function-bind "^1.1.2" + call-bind@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c" @@ -572,15 +730,23 @@ call-bind@^1.0.0: function-bind "^1.1.1" get-intrinsic "^1.0.2" +call-bound@^1.0.2: + version "1.0.4" + resolved "https://registry.yarnpkg.com/call-bound/-/call-bound-1.0.4.tgz#238de935d2a2a692928c538c7ccfa91067fd062a" + integrity sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg== + dependencies: + call-bind-apply-helpers "^1.0.2" + get-intrinsic "^1.3.0" + camelcase@^6.0.0: version "6.3.0" resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== -caniuse-lite@^1.0.30001669: - version "1.0.30001686" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001686.tgz#0e04b8d90de8753188e93c9989d56cb19d902670" - integrity sha512-Y7deg0Aergpa24M3qLC5xjNklnKnhsmSyR/V89dLZ1n0ucJIFNs7PgR2Yfa/Zf6W79SbBicgtGxZr2juHkEUIA== +caniuse-lite@^1.0.30001746: + version "1.0.30001749" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001749.tgz#21a43b923577932097fe32bcaabb6da7f4677632" + integrity sha512-0rw2fJOmLfnzCRbkm8EyHL8SvI2Apu5UbnQuTsJ0ClgrH8hcwFooJ1s5R0EP8o8aVrFu8++ae29Kt9/gZAZp/Q== chalk@^4.1.0: version "4.1.2" @@ -590,7 +756,7 @@ chalk@^4.1.0: ansi-styles "^4.1.0" supports-color "^7.1.0" -chokidar@^3.5.1, chokidar@^3.5.3: +chokidar@^3.5.1: version "3.5.3" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd" integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw== @@ -605,6 +771,28 @@ chokidar@^3.5.1, chokidar@^3.5.3: optionalDependencies: fsevents "~2.3.2" +chokidar@^3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.6.0.tgz#197c6cc669ef2a8dc5e7b4d97ee4e092c3eb0d5b" + integrity sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw== + dependencies: + anymatch "~3.1.2" + braces "~3.0.2" + glob-parent "~5.1.2" + is-binary-path "~2.1.0" + is-glob "~4.0.1" + normalize-path "~3.0.0" + readdirp "~3.6.0" + optionalDependencies: + fsevents "~2.3.2" + +chokidar@^4.0.1: + version "4.0.3" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-4.0.3.tgz#7be37a4c03c9aee1ecfe862a4a23b2c70c205d30" + integrity sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA== + dependencies: + readdirp "^4.0.1" + chrome-trace-event@^1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz#1015eced4741e15d06664a957dbbf50d041e26ac" @@ -619,6 +807,15 @@ cliui@^7.0.2: strip-ansi "^6.0.0" wrap-ansi "^7.0.0" +cliui@^8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-8.0.1.tgz#0c04b075db02cbfe60dc8e6cf2f5486b1a3608aa" + integrity sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.1" + wrap-ansi "^7.0.0" + clone-deep@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/clone-deep/-/clone-deep-4.0.1.tgz#c19fd9bdbbf85942b4fd979c84dcf7d5f07c2387" @@ -645,10 +842,10 @@ colorette@^2.0.10, colorette@^2.0.14: resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.19.tgz#cdf044f47ad41a0f4b56b3a0d5b4e6e1a2d5a798" integrity sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ== -commander@^10.0.1: - version "10.0.1" - resolved "https://registry.yarnpkg.com/commander/-/commander-10.0.1.tgz#881ee46b4f77d1c1dccc5823433aa39b022cbe06" - integrity sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug== +commander@^12.1.0: + version "12.1.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-12.1.0.tgz#01423b36f501259fdaac4d0e4d60c96c991585d3" + integrity sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA== commander@^2.20.0: version "2.20.3" @@ -707,15 +904,20 @@ content-type@~1.0.4: resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA== +content-type@~1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.5.tgz#8b773162656d1d1086784c8f23a54ce6d73d7918" + integrity sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA== + cookie-signature@1.0.6: version "1.0.6" resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" integrity sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ== -cookie@0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.5.0.tgz#d1f5d71adec6558c58f389987c366aa47e994f8b" - integrity sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw== +cookie@0.7.1: + version "0.7.1" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.7.1.tgz#2f73c42142d5d5cf71310a74fc4ae61670e5dbc9" + integrity sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w== cookie@~0.7.2: version "0.7.2" @@ -744,6 +946,15 @@ cross-spawn@^7.0.3: shebang-command "^2.0.0" which "^2.0.1" +cross-spawn@^7.0.6: + version "7.0.6" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.6.tgz#8a58fe78f00dcd70c370451759dfbfaf03e8ee9f" + integrity sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + custom-event@~1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/custom-event/-/custom-event-1.0.1.tgz#5d02a46850adf1b4a317946a3928fccb5bfd0425" @@ -780,17 +991,23 @@ decamelize@^4.0.0: resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-4.0.0.tgz#aa472d7bf660eb15f3494efd531cab7f2a709837" integrity sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ== -default-gateway@^6.0.3: - version "6.0.3" - resolved "https://registry.yarnpkg.com/default-gateway/-/default-gateway-6.0.3.tgz#819494c888053bdb743edbf343d6cdf7f2943a71" - integrity sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg== +default-browser-id@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/default-browser-id/-/default-browser-id-5.0.0.tgz#a1d98bf960c15082d8a3fa69e83150ccccc3af26" + integrity sha512-A6p/pu/6fyBcA1TRz/GqWYPViplrftcW2gZC9q79ngNCKAeR/X3gcEdXQHl4KNXV+3wgIJ1CPkJQ3IHM6lcsyA== + +default-browser@^5.2.1: + version "5.2.1" + resolved "https://registry.yarnpkg.com/default-browser/-/default-browser-5.2.1.tgz#7b7ba61204ff3e425b556869ae6d3e9d9f1712cf" + integrity sha512-WY/3TUME0x3KPYdRRxEJJvXRHV4PyPoUsxtZa78lwItwRQRHhd2U9xOscaT/YTf8uCXIAjeJOFBVEh/7FtD8Xg== dependencies: - execa "^5.0.0" + bundle-name "^4.1.0" + default-browser-id "^5.0.0" -define-lazy-prop@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz#3f7ae421129bcaaac9bc74905c98a0009ec9ee7f" - integrity sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og== +define-lazy-prop@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz#dbb19adfb746d7fc6d734a06b72f4a00d021255f" + integrity sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg== depd@2.0.0: version "2.0.0" @@ -817,15 +1034,10 @@ di@^0.0.1: resolved "https://registry.yarnpkg.com/di/-/di-0.0.1.tgz#806649326ceaa7caa3306d75d985ea2748ba913c" integrity sha512-uJaamHkagcZtHPqCIHZxnFrXlunQXgBOsZSUOWwFw31QJCAbyTBoHMW75YOTur5ZNx8pIeAKgf6GWIgaqqiLhA== -diff@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/diff/-/diff-5.2.0.tgz#26ded047cd1179b78b9537d5ef725503ce1ae531" - integrity sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A== - -dns-equal@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/dns-equal/-/dns-equal-1.0.0.tgz#b39e7f1da6eb0a75ba9c17324b34753c47e0654d" - integrity sha512-z+paD6YUQsk+AbGCEM4PrOXSss5gd66QfcVBFTKR/HpFL9jCqikS94HYwKww6fQyO7IxrIIyUu+g0Ka9tUS2Cg== +diff@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/diff/-/diff-7.0.0.tgz#3fb34d387cd76d803f6eebea67b921dab0182a9a" + integrity sha512-PJWHUb1RFevKCwaFA9RlG5tCd+FO5iRh9A8HEtkmBH2Li03iJriB6m6JIN4rGz3K3JLawI7/veA1xzRKP6ISBw== dns-packet@^5.2.2: version "5.4.0" @@ -844,26 +1056,50 @@ dom-serialize@^2.2.1: extend "^3.0.0" void-elements "^2.0.0" +dunder-proto@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/dunder-proto/-/dunder-proto-1.0.1.tgz#d7ae667e1dc83482f8b70fd0f6eefc50da30f58a" + integrity sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A== + dependencies: + call-bind-apply-helpers "^1.0.1" + es-errors "^1.3.0" + gopd "^1.2.0" + +eastasianwidth@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb" + integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA== + ee-first@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow== -electron-to-chromium@^1.5.41: - version "1.5.71" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.71.tgz#d8b5dba1e55b320f2f4e9b1ca80738f53fcfec2b" - integrity sha512-dB68l59BI75W1BUGVTAEJy45CEVuEGy9qPVVQ8pnHyHMn36PLPPoE1mjLH+lo9rKulO3HC2OhbACI/8tCqJBcA== +electron-to-chromium@^1.5.227: + version "1.5.234" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.234.tgz#d895b6dba84269f4e83b3a1149dcc55e27848c30" + integrity sha512-RXfEp2x+VRYn8jbKfQlRImzoJU01kyDvVPBmG39eU2iuRVhuS6vQNocB8J0/8GrIMLnPzgz4eW6WiRnJkTuNWg== emoji-regex@^8.0.0: version "8.0.0" resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== +emoji-regex@^9.2.2: + version "9.2.2" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72" + integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg== + encodeurl@~1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w== +encodeurl@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-2.0.0.tgz#7b8ea898077d7e409d3ac45474ea38eaf0857a58" + integrity sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg== + engine.io-parser@~5.2.1: version "5.2.3" resolved "https://registry.yarnpkg.com/engine.io-parser/-/engine.io-parser-5.2.3.tgz#00dc5b97b1f233a23c9398d0209504cf5f94d92f" @@ -885,10 +1121,10 @@ engine.io@~6.6.0: engine.io-parser "~5.2.1" ws "~8.17.1" -enhanced-resolve@^5.17.1: - version "5.17.1" - resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz#67bfbbcc2f81d511be77d686a90267ef7f898a15" - integrity sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg== +enhanced-resolve@^5.17.2: + version "5.18.3" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.18.3.tgz#9b5f4c5c076b8787c78fe540392ce76a88855b44" + integrity sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww== dependencies: graceful-fs "^4.2.4" tapable "^2.2.0" @@ -898,16 +1134,33 @@ ent@~2.2.0: resolved "https://registry.yarnpkg.com/ent/-/ent-2.2.0.tgz#e964219325a21d05f44466a2f686ed6ce5f5dd1d" integrity sha512-GHrMyVZQWvTIdDtpiEXdHZnFQKzeO09apj8Cbl4pKWy4i0Oprcq17usfDt5aO63swf0JOeMWjWQE/LzgSRuWpA== -envinfo@^7.7.3: - version "7.8.1" - resolved "https://registry.yarnpkg.com/envinfo/-/envinfo-7.8.1.tgz#06377e3e5f4d379fea7ac592d5ad8927e0c4d475" - integrity sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw== +envinfo@^7.14.0: + version "7.17.0" + resolved "https://registry.yarnpkg.com/envinfo/-/envinfo-7.17.0.tgz#4a9cb6fe0c91e27b5be5fcca61f681894f88db14" + integrity sha512-GpfViocsFM7viwClFgxK26OtjMlKN67GCR5v6ASFkotxtpBWd9d+vNy+AH7F2E1TUkMDZ8P/dDPZX71/NG8xnQ== + +es-define-property@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.1.tgz#983eb2f9a6724e9303f61addf011c72e09e0b0fa" + integrity sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g== + +es-errors@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f" + integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw== es-module-lexer@^1.2.1: version "1.5.4" resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-1.5.4.tgz#a8efec3a3da991e60efa6b633a7cad6ab8d26b78" integrity sha512-MVNK56NiMrOwitFB7cqDwq0CQutbw+0BvLshJSse0MUNU+y1FC3bUS/AQg7oUng+/wKrrki7JfmwtVHkVfPLlw== +es-object-atoms@^1.0.0, es-object-atoms@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/es-object-atoms/-/es-object-atoms-1.1.1.tgz#1c4f2c4837327597ce69d2ca190a7fdd172338c1" + integrity sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA== + dependencies: + es-errors "^1.3.0" + escalade@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" @@ -968,52 +1221,37 @@ events@^3.2.0: resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== -execa@^5.0.0: - version "5.1.1" - resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" - integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg== - 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" - -express@^4.17.3: - version "4.18.2" - resolved "https://registry.yarnpkg.com/express/-/express-4.18.2.tgz#3fabe08296e930c796c19e3c516979386ba9fd59" - integrity sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ== +express@^4.21.2: + version "4.21.2" + resolved "https://registry.yarnpkg.com/express/-/express-4.21.2.tgz#cf250e48362174ead6cea4a566abef0162c1ec32" + integrity sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA== dependencies: accepts "~1.3.8" array-flatten "1.1.1" - body-parser "1.20.1" + body-parser "1.20.3" content-disposition "0.5.4" content-type "~1.0.4" - cookie "0.5.0" + cookie "0.7.1" cookie-signature "1.0.6" debug "2.6.9" depd "2.0.0" - encodeurl "~1.0.2" + encodeurl "~2.0.0" escape-html "~1.0.3" etag "~1.8.1" - finalhandler "1.2.0" + finalhandler "1.3.1" fresh "0.5.2" http-errors "2.0.0" - merge-descriptors "1.0.1" + merge-descriptors "1.0.3" methods "~1.1.2" on-finished "2.4.1" parseurl "~1.3.3" - path-to-regexp "0.1.7" + path-to-regexp "0.1.12" proxy-addr "~2.0.7" - qs "6.11.0" + qs "6.13.0" range-parser "~1.2.1" safe-buffer "5.2.1" - send "0.18.0" - serve-static "1.15.0" + send "0.19.0" + serve-static "1.16.2" setprototypeof "1.2.0" statuses "2.0.1" type-is "~1.6.18" @@ -1030,10 +1268,10 @@ fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== -fast-json-stable-stringify@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" - integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== +fast-uri@^3.0.1: + version "3.1.0" + resolved "https://registry.yarnpkg.com/fast-uri/-/fast-uri-3.1.0.tgz#66eecff6c764c0df9b762e62ca7edcfb53b4edfa" + integrity sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA== fastest-levenshtein@^1.0.12: version "1.0.16" @@ -1067,13 +1305,13 @@ finalhandler@1.1.2: statuses "~1.5.0" unpipe "~1.0.0" -finalhandler@1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.2.0.tgz#7d23fe5731b207b4640e4fcd00aec1f9207a7b32" - integrity sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg== +finalhandler@1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.3.1.tgz#0c575f1d1d324ddd1da35ad7ece3df7d19088019" + integrity sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ== dependencies: debug "2.6.9" - encodeurl "~1.0.2" + encodeurl "~2.0.0" escape-html "~1.0.3" on-finished "2.4.1" parseurl "~1.3.3" @@ -1111,6 +1349,14 @@ follow-redirects@^1.0.0: resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.2.tgz#b460864144ba63f2681096f274c4e57026da2c13" integrity sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA== +foreground-child@^3.1.0: + version "3.3.1" + resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-3.3.1.tgz#32e8e9ed1b68a3497befb9ac2b6adf92a638576f" + integrity sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw== + dependencies: + cross-spawn "^7.0.6" + signal-exit "^4.0.1" + format-util@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/format-util/-/format-util-1.0.5.tgz#1ffb450c8a03e7bccffe40643180918cc297d271" @@ -1135,11 +1381,6 @@ fs-extra@^8.1.0: jsonfile "^4.0.0" universalify "^0.1.0" -fs-monkey@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/fs-monkey/-/fs-monkey-1.0.3.tgz#ae3ac92d53bb328efe0e9a1d9541f6ad8d48e2d3" - integrity sha512-cybjIfiiE+pTWicSCLFHSrXZ6EilF30oh91FDP9S2B051prEa7QWfrVTQm10/dDpswBDXZugPa1Ogu8Yh+HV0Q== - fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" @@ -1174,10 +1415,29 @@ get-intrinsic@^1.0.2: has "^1.0.3" has-symbols "^1.0.3" -get-stream@^6.0.0: - version "6.0.1" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" - integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== +get-intrinsic@^1.2.5, get-intrinsic@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.3.0.tgz#743f0e3b6964a93a5491ed1bffaae054d7f98d01" + integrity sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ== + dependencies: + call-bind-apply-helpers "^1.0.2" + es-define-property "^1.0.1" + es-errors "^1.3.0" + es-object-atoms "^1.1.1" + function-bind "^1.1.2" + get-proto "^1.0.1" + gopd "^1.2.0" + has-symbols "^1.1.0" + hasown "^2.0.2" + math-intrinsics "^1.1.0" + +get-proto@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/get-proto/-/get-proto-1.0.1.tgz#150b3f2743869ef3e851ec0c49d15b1d14d00ee1" + integrity sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g== + dependencies: + dunder-proto "^1.0.1" + es-object-atoms "^1.0.0" glob-parent@~5.1.2: version "5.1.2" @@ -1186,11 +1446,28 @@ glob-parent@~5.1.2: dependencies: is-glob "^4.0.1" +glob-to-regex.js@^1.0.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/glob-to-regex.js/-/glob-to-regex.js-1.2.0.tgz#2b323728271d133830850e32311f40766c5f6413" + integrity sha512-QMwlOQKU/IzqMUOAZWubUOT8Qft+Y0KQWnX9nK3ch0CJg0tTp4TvGZsTfudYKv2NzoQSyPcnA6TYeIQ3jGichQ== + glob-to-regexp@^0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz#c75297087c851b9a578bd217dd59a92f59fe546e" integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw== +glob@^10.4.5: + version "10.4.5" + resolved "https://registry.yarnpkg.com/glob/-/glob-10.4.5.tgz#f4d9f0b90ffdbab09c9d77f5f29b4262517b0956" + integrity sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg== + dependencies: + foreground-child "^3.1.0" + jackspeak "^3.1.2" + minimatch "^9.0.4" + minipass "^7.1.2" + package-json-from-dist "^1.0.0" + path-scurry "^1.11.1" + glob@^7.1.3, glob@^7.1.7: version "7.2.3" resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" @@ -1203,16 +1480,10 @@ glob@^7.1.3, glob@^7.1.7: once "^1.3.0" path-is-absolute "^1.0.0" -glob@^8.1.0: - version "8.1.0" - resolved "https://registry.yarnpkg.com/glob/-/glob-8.1.0.tgz#d388f656593ef708ee3e34640fdfb99a9fd1c33e" - integrity sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ== - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^5.0.1" - once "^1.3.0" +gopd@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.2.0.tgz#89f56b8217bdbc8802bd299df6d7f1081d7e51a1" + integrity sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg== graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.4, graceful-fs@^4.2.6: version "4.2.10" @@ -1239,6 +1510,11 @@ has-symbols@^1.0.3: resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== +has-symbols@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.1.0.tgz#fc9c6a783a084951d0b971fe1018de813707a338" + integrity sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ== + has@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" @@ -1268,11 +1544,6 @@ hpack.js@^2.1.6: readable-stream "^2.0.1" wbuf "^1.1.0" -html-entities@^2.3.2: - version "2.3.3" - resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-2.3.3.tgz#117d7626bece327fc8baace8868fa6f5ef856e46" - integrity sha512-DV5Ln36z34NNTDgnz0EWGBLZENelNAtkiFA4kyNOG2tDI6Mz1uSWiq1wAKdyjnJwyDiDO7Fa2SO1CTxPXL8VxA== - http-deceiver@^1.2.7: version "1.2.7" resolved "https://registry.yarnpkg.com/http-deceiver/-/http-deceiver-1.2.7.tgz#fa7168944ab9a519d337cb0bec7284dc3e723d87" @@ -1304,10 +1575,10 @@ http-parser-js@>=0.5.1: resolved "https://registry.yarnpkg.com/http-parser-js/-/http-parser-js-0.5.8.tgz#af23090d9ac4e24573de6f6aecc9d84a48bf20e3" integrity sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q== -http-proxy-middleware@^2.0.3: - version "2.0.6" - resolved "https://registry.yarnpkg.com/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz#e1a4dd6979572c7ab5a4e4b55095d1f32a74963f" - integrity sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw== +http-proxy-middleware@^2.0.9: + version "2.0.9" + resolved "https://registry.yarnpkg.com/http-proxy-middleware/-/http-proxy-middleware-2.0.9.tgz#e9e63d68afaa4eee3d147f39149ab84c0c2815ef" + integrity sha512-c1IyJYLYppU574+YI7R4QyX2ystMtVXZwIdzazUIPIJsHuWNd+mho2j+bKoHftndicGj9yh+xjd+l0yj7VeT1Q== dependencies: "@types/http-proxy" "^1.17.8" http-proxy "^1.18.1" @@ -1324,10 +1595,10 @@ http-proxy@^1.18.1: follow-redirects "^1.0.0" requires-port "^1.0.0" -human-signals@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" - integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== +hyperdyperid@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/hyperdyperid/-/hyperdyperid-1.2.0.tgz#59668d323ada92228d2a869d3e474d5a33b69e6b" + integrity sha512-Y93lCzHYgGWdrJ66yIktxiaGULYc6oGiABxhcO5AufBeOyoIdZF7bIfLaOrbM0iGIOXQQgxxRrFEnb+Y6w1n4A== iconv-lite@0.4.24: version "0.4.24" @@ -1379,10 +1650,10 @@ ipaddr.js@1.9.1: resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== -ipaddr.js@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-2.0.1.tgz#eca256a7a877e917aeb368b0a7497ddf42ef81c0" - integrity sha512-1qTgH9NG+IIJ4yfKs2e6Pp1bZg8wbDbKHT21HrLIeYBTRLgMYKnMTPAuI3Lcs61nfx5h1xlXnbJtH1kX5/d/ng== +ipaddr.js@^2.1.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-2.2.0.tgz#d33fa7bac284f4de7af949638c9d68157c6b92e8" + integrity sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA== is-binary-path@~2.1.0: version "2.1.0" @@ -1398,10 +1669,10 @@ is-core-module@^2.13.0: dependencies: hasown "^2.0.2" -is-docker@^2.0.0, is-docker@^2.1.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.2.1.tgz#33eeabe23cfe86f14bde4408a02c0cfb853acdaa" - integrity sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ== +is-docker@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-3.0.0.tgz#90093aa3106277d8a77a5910dbae71747e15a200" + integrity sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ== is-extglob@^2.1.1: version "2.1.1" @@ -1420,6 +1691,18 @@ is-glob@^4.0.1, is-glob@~4.0.1: dependencies: is-extglob "^2.1.1" +is-inside-container@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-inside-container/-/is-inside-container-1.0.0.tgz#e81fba699662eb31dbdaf26766a61d4814717ea4" + integrity sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA== + dependencies: + is-docker "^3.0.0" + +is-network-error@^1.0.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/is-network-error/-/is-network-error-1.3.0.tgz#2ce62cbca444abd506f8a900f39d20b898d37512" + integrity sha512-6oIwpsgRfnDiyEDLMay/GqCl3HoAtH5+RUKW29gYkL0QA+ipzpDLA16yQs7/RHCSu+BwgbJaOUqa4A99qNVQVw== + is-number@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" @@ -1442,22 +1725,17 @@ is-plain-object@^2.0.4: dependencies: isobject "^3.0.1" -is-stream@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" - integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== - is-unicode-supported@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7" integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw== -is-wsl@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-2.2.0.tgz#74a4c76e77ca9fd3f932f290c17ea326cd157271" - integrity sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww== +is-wsl@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-3.1.0.tgz#e1c657e39c10090afcbedec61720f6b924c3cbd2" + integrity sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw== dependencies: - is-docker "^2.0.0" + is-inside-container "^1.0.0" isarray@~1.0.0: version "1.0.0" @@ -1479,6 +1757,15 @@ isobject@^3.0.1: resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" integrity sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg== +jackspeak@^3.1.2: + version "3.4.3" + resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-3.4.3.tgz#8833a9d89ab4acde6188942bd1c53b6390ed5a8a" + integrity sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw== + dependencies: + "@isaacs/cliui" "^8.0.2" + optionalDependencies: + "@pkgjs/parseargs" "^0.11.0" + jest-worker@^27.4.5: version "27.5.1" resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-27.5.1.tgz#8d146f0900e8973b106b6f73cc1e9a8cb86f8db0" @@ -1500,11 +1787,6 @@ json-parse-even-better-errors@^2.3.1: resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== -json-schema-traverse@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" - integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== - json-schema-traverse@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2" @@ -1582,20 +1864,20 @@ kind-of@^6.0.2: resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== -kotlin-web-helpers@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/kotlin-web-helpers/-/kotlin-web-helpers-2.0.0.tgz#b112096b273c1e733e0b86560998235c09a19286" - integrity sha512-xkVGl60Ygn/zuLkDPx+oHj7jeLR7hCvoNF99nhwXMn8a3ApB4lLiC9pk4ol4NHPjyoCbvQctBqvzUcp8pkqyWw== +kotlin-web-helpers@2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/kotlin-web-helpers/-/kotlin-web-helpers-2.1.0.tgz#6cd4b0f0dc3baea163929c8638155b8d19c55a74" + integrity sha512-NAJhiNB84tnvJ5EQx7iER3GWw7rsTZkX9HVHZpe7E3dDBD/dhTzqgSwNU3MfQjniy2rB04bP24WM9Z32ntUWRg== dependencies: format-util "^1.0.5" -launch-editor@^2.6.0: - version "2.9.1" - resolved "https://registry.yarnpkg.com/launch-editor/-/launch-editor-2.9.1.tgz#253f173bd441e342d4344b4dae58291abb425047" - integrity sha512-Gcnl4Bd+hRO9P9icCP/RVVT2o8SFlPXofuCxvA2SaZuH45whSvf5p8x5oih5ftLiVhEI4sp5xDY+R+b3zJBh5w== +launch-editor@^2.6.1: + version "2.11.1" + resolved "https://registry.yarnpkg.com/launch-editor/-/launch-editor-2.11.1.tgz#61a0b7314a42fd84a6cbb564573d9e9ffcf3d72b" + integrity sha512-SEET7oNfgSaB6Ym0jufAdCeo3meJVeCaaDyzRygy0xsp2BFKCprcfHljTq4QkzTLUxEKkFK6OK4811YM2oSrRg== dependencies: - picocolors "^1.0.0" - shell-quote "^1.8.1" + picocolors "^1.1.1" + shell-quote "^1.8.3" loader-runner@^4.2.0: version "4.3.0" @@ -1640,22 +1922,37 @@ log4js@^6.4.1: rfdc "^1.3.0" streamroller "^3.1.3" +lru-cache@^10.2.0: + version "10.4.3" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.4.3.tgz#410fc8a17b70e598013df257c2446b7f3383f119" + integrity sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ== + +math-intrinsics@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/math-intrinsics/-/math-intrinsics-1.1.0.tgz#a0dd74be81e2aa5c2f27e65ce283605ee4e2b7f9" + integrity sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g== + media-typer@0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" integrity sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ== -memfs@^3.4.3: - version "3.4.12" - resolved "https://registry.yarnpkg.com/memfs/-/memfs-3.4.12.tgz#d00f8ad8dab132dc277c659dc85bfd14b07d03bd" - integrity sha512-BcjuQn6vfqP+k100e0E9m61Hyqa//Brp+I3f0OBmN0ATHlFA8vx3Lt8z57R3u2bPqe3WGDBC+nF72fTH7isyEw== +memfs@^4.43.1: + version "4.49.0" + resolved "https://registry.yarnpkg.com/memfs/-/memfs-4.49.0.tgz#bc35069570d41a31c62e31f1a6ec6057a8ea82f0" + integrity sha512-L9uC9vGuc4xFybbdOpRLoOAOq1YEBBsocCs5NVW32DfU+CZWWIn3OVF+lB8Gp4ttBVSMazwrTrjv8ussX/e3VQ== dependencies: - fs-monkey "^1.0.3" + "@jsonjoy.com/json-pack" "^1.11.0" + "@jsonjoy.com/util" "^1.9.0" + glob-to-regex.js "^1.0.1" + thingies "^2.5.0" + tree-dump "^1.0.3" + tslib "^2.0.0" -merge-descriptors@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" - integrity sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w== +merge-descriptors@1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.3.tgz#d80319a65f3c7935351e5cfdac8f9318504dbed5" + integrity sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ== merge-stream@^2.0.0: version "2.0.0" @@ -1680,13 +1977,25 @@ mime-db@1.52.0, "mime-db@>= 1.43.0 < 2": resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== -mime-types@^2.1.27, mime-types@^2.1.31, mime-types@~2.1.17, mime-types@~2.1.24, mime-types@~2.1.34: +mime-db@^1.54.0: + version "1.54.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.54.0.tgz#cddb3ee4f9c64530dff640236661d42cb6a314f5" + integrity sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ== + +mime-types@^2.1.27, mime-types@~2.1.17, mime-types@~2.1.24, mime-types@~2.1.34: version "2.1.35" resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== dependencies: mime-db "1.52.0" +mime-types@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-3.0.1.tgz#b1d94d6997a9b32fd69ebaed0db73de8acb519ce" + integrity sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA== + dependencies: + mime-db "^1.54.0" + mime@1.6.0: version "1.6.0" resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" @@ -1697,11 +2006,6 @@ mime@^2.5.2: resolved "https://registry.yarnpkg.com/mime/-/mime-2.6.0.tgz#a2a682a95cd4d0cb1d6257e28f83da7e35800367" integrity sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg== -mimic-fn@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" - integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== - minimalistic-assert@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" @@ -1714,14 +2018,7 @@ minimatch@^3.0.4, minimatch@^3.1.1: dependencies: brace-expansion "^1.1.7" -minimatch@^5.0.1, minimatch@^5.1.6: - version "5.1.6" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.1.6.tgz#1cfcb8cf5522ea69952cd2af95ae09477f122a96" - integrity sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g== - dependencies: - brace-expansion "^2.0.1" - -minimatch@^9.0.3: +minimatch@^9.0.3, minimatch@^9.0.4, minimatch@^9.0.5: version "9.0.5" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.5.tgz#d74f9dd6b57d83d8e98cfb82133b03978bc929e5" integrity sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow== @@ -1733,6 +2030,11 @@ minimist@^1.2.3, minimist@^1.2.6: resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.7.tgz#daa1c4d91f507390437c6a8bc01078e7000c4d18" integrity sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g== +"minipass@^5.0.0 || ^6.0.2 || ^7.0.0", minipass@^7.1.2: + version "7.1.2" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.1.2.tgz#93a9626ce5e5e66bd4db86849e7515e92340a707" + integrity sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw== + mkdirp@^0.5.5: version "0.5.6" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.6.tgz#7def03d2432dcae4ba1d611445c48396062255f6" @@ -1740,30 +2042,30 @@ mkdirp@^0.5.5: dependencies: minimist "^1.2.6" -mocha@10.7.3: - version "10.7.3" - resolved "https://registry.yarnpkg.com/mocha/-/mocha-10.7.3.tgz#ae32003cabbd52b59aece17846056a68eb4b0752" - integrity sha512-uQWxAu44wwiACGqjbPYmjo7Lg8sFrS3dQe7PP2FQI+woptP4vZXSMcfMyFL/e1yFEeEpV4RtyTpZROOKmxis+A== +mocha@11.7.1: + version "11.7.1" + resolved "https://registry.yarnpkg.com/mocha/-/mocha-11.7.1.tgz#91948fecd624fb4bd154ed260b7e1ad3910d7c7a" + integrity sha512-5EK+Cty6KheMS/YLPPMJC64g5V61gIR25KsRItHw6x4hEKT6Njp1n9LOlH4gpevuwMVS66SXaBBpg+RWZkza4A== dependencies: - ansi-colors "^4.1.3" browser-stdout "^1.3.1" - chokidar "^3.5.3" + chokidar "^4.0.1" debug "^4.3.5" - diff "^5.2.0" + diff "^7.0.0" escape-string-regexp "^4.0.0" find-up "^5.0.0" - glob "^8.1.0" + glob "^10.4.5" he "^1.2.0" js-yaml "^4.1.0" log-symbols "^4.1.0" - minimatch "^5.1.6" + minimatch "^9.0.5" ms "^2.1.3" + picocolors "^1.1.1" serialize-javascript "^6.0.2" strip-json-comments "^3.1.1" supports-color "^8.1.1" - workerpool "^6.5.1" - yargs "^16.2.0" - yargs-parser "^20.2.9" + workerpool "^9.2.0" + yargs "^17.7.2" + yargs-parser "^21.1.1" yargs-unparser "^2.0.0" ms@2.0.0: @@ -1804,28 +2106,26 @@ node-forge@^1: resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-1.3.1.tgz#be8da2af243b2417d5f646a770663a92b7e9ded3" integrity sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA== -node-releases@^2.0.18: - version "2.0.18" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.18.tgz#f010e8d35e2fe8d6b2944f03f70213ecedc4ca3f" - integrity sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g== +node-releases@^2.0.21: + version "2.0.23" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.23.tgz#2ecf3d7ba571ece05c67c77e5b7b1b6fb9e18cea" + integrity sha512-cCmFDMSm26S6tQSDpBCg/NR8NENrVPhAJSf+XbxBG4rPFaaonlEoE9wHQmun+cls499TQGSb7ZyPBRlzgKfpeg== normalize-path@^3.0.0, normalize-path@~3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== -npm-run-path@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" - integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== - dependencies: - path-key "^3.0.0" - object-assign@^4: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== +object-inspect@^1.13.3: + version "1.13.4" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.4.tgz#8375265e21bc20d0fa582c22e1b13485d6e00213" + integrity sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew== + object-inspect@^1.9.0: version "1.12.2" resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.2.tgz#c0641f26394532f28ab8d796ab954e43c009a8ea" @@ -1836,7 +2136,7 @@ obuf@^1.0.0, obuf@^1.1.2: resolved "https://registry.yarnpkg.com/obuf/-/obuf-1.1.2.tgz#09bea3343d41859ebd446292d11c9d4db619084e" integrity sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg== -on-finished@2.4.1: +on-finished@2.4.1, on-finished@^2.4.1: version "2.4.1" resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.4.1.tgz#58c8c44116e54845ad57f14ab10b03533184ac3f" integrity sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg== @@ -1862,21 +2162,15 @@ once@^1.3.0: dependencies: wrappy "1" -onetime@^5.1.2: - version "5.1.2" - resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" - integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== - dependencies: - mimic-fn "^2.1.0" - -open@^8.0.9: - version "8.4.0" - resolved "https://registry.yarnpkg.com/open/-/open-8.4.0.tgz#345321ae18f8138f82565a910fdc6b39e8c244f8" - integrity sha512-XgFPPM+B28FtCCgSb9I+s9szOC1vZRSwgWsRUA5ylIxRTgKozqjOCrVOqGsYABPYK5qnfqClxZTFBa8PKt2v6Q== +open@^10.0.3: + version "10.2.0" + resolved "https://registry.yarnpkg.com/open/-/open-10.2.0.tgz#b9d855be007620e80b6fb05fac98141fe62db73c" + integrity sha512-YgBpdJHPyQ2UE5x+hlSXcnejzAvD0b22U2OuAP+8OnlJT+PjWPxtgmGqKKc+RgTM63U9gN0YzrYc71R2WT/hTA== dependencies: - define-lazy-prop "^2.0.0" - is-docker "^2.1.1" - is-wsl "^2.2.0" + default-browser "^5.2.1" + define-lazy-prop "^3.0.0" + is-inside-container "^1.0.0" + wsl-utils "^0.1.0" p-limit@^2.2.0: version "2.3.0" @@ -1906,12 +2200,13 @@ p-locate@^5.0.0: dependencies: p-limit "^3.0.2" -p-retry@^4.5.0: - version "4.6.2" - resolved "https://registry.yarnpkg.com/p-retry/-/p-retry-4.6.2.tgz#9baae7184057edd4e17231cee04264106e092a16" - integrity sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ== +p-retry@^6.2.0: + version "6.2.1" + resolved "https://registry.yarnpkg.com/p-retry/-/p-retry-6.2.1.tgz#81828f8dc61c6ef5a800585491572cc9892703af" + integrity sha512-hEt02O4hUct5wtwg4H4KcWgDdm+l1bOaEy/hWzd8xtXB9BqxTWBBhb+2ImAtH4Cv4rPjV76xN3Zumqk3k3AhhQ== dependencies: - "@types/retry" "0.12.0" + "@types/retry" "0.12.2" + is-network-error "^1.0.0" retry "^0.13.1" p-try@^2.0.0: @@ -1919,6 +2214,11 @@ p-try@^2.0.0: resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== +package-json-from-dist@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz#4f1471a010827a86f94cfd9b0727e36d267de505" + integrity sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw== + parseurl@~1.3.2, parseurl@~1.3.3: version "1.3.3" resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" @@ -1934,7 +2234,7 @@ path-is-absolute@^1.0.0: resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== -path-key@^3.0.0, path-key@^3.1.0: +path-key@^3.1.0: version "3.1.1" resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== @@ -1944,17 +2244,20 @@ path-parse@^1.0.7: resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== -path-to-regexp@0.1.7: - version "0.1.7" - resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" - integrity sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ== +path-scurry@^1.11.1: + version "1.11.1" + resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-1.11.1.tgz#7960a668888594a0720b12a911d1a742ab9f11d2" + integrity sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA== + dependencies: + lru-cache "^10.2.0" + minipass "^5.0.0 || ^6.0.2 || ^7.0.0" -picocolors@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" - integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== +path-to-regexp@0.1.12: + version "0.1.12" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.12.tgz#d5e1a12e478a976d432ef3c58d534b9923164bb7" + integrity sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ== -picocolors@^1.1.0: +picocolors@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.1.tgz#3d321af3eab939b083c8f929a1d12cda81c26b6b" integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA== @@ -2001,6 +2304,13 @@ qs@6.11.0: dependencies: side-channel "^1.0.4" +qs@6.13.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.13.0.tgz#6ca3bd58439f7e245655798997787b0d88a51906" + integrity sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg== + dependencies: + side-channel "^1.0.6" + randombytes@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" @@ -2023,6 +2333,16 @@ raw-body@2.5.1: iconv-lite "0.4.24" unpipe "1.0.0" +raw-body@2.5.2: + version "2.5.2" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.2.tgz#99febd83b90e08975087e8f1f9419a149366b68a" + integrity sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA== + dependencies: + bytes "3.1.2" + http-errors "2.0.0" + iconv-lite "0.4.24" + unpipe "1.0.0" + readable-stream@^2.0.1: version "2.3.7" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" @@ -2045,6 +2365,11 @@ readable-stream@^3.0.6: string_decoder "^1.1.1" util-deprecate "^1.0.1" +readdirp@^4.0.1: + version "4.1.2" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-4.1.2.tgz#eb85801435fbf2a7ee58f19e0921b068fc69948d" + integrity sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg== + readdirp@~3.6.0: version "3.6.0" resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" @@ -2112,6 +2437,11 @@ rimraf@^3.0.0, rimraf@^3.0.2: dependencies: glob "^7.1.3" +run-applescript@^7.0.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/run-applescript/-/run-applescript-7.1.0.tgz#2e9e54c4664ec3106c5b5630e249d3d6595c4911" + integrity sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q== + safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: version "5.1.2" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" @@ -2127,24 +2457,6 @@ safe-buffer@5.2.1, safe-buffer@>=5.1.0, safe-buffer@^5.1.0, safe-buffer@~5.2.0: resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== -schema-utils@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-3.1.1.tgz#bc74c4b6b6995c1d88f76a8b77bea7219e0c8281" - integrity sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw== - dependencies: - "@types/json-schema" "^7.0.8" - ajv "^6.12.5" - ajv-keywords "^3.5.2" - -schema-utils@^3.2.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-3.3.0.tgz#f50a88877c3c01652a15b622ae9e9795df7a60fe" - integrity sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg== - dependencies: - "@types/json-schema" "^7.0.8" - ajv "^6.12.5" - ajv-keywords "^3.5.2" - schema-utils@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-4.0.0.tgz#60331e9e3ae78ec5d16353c467c34b3a0a1d3df7" @@ -2155,6 +2467,16 @@ schema-utils@^4.0.0: ajv-formats "^2.1.1" ajv-keywords "^5.0.0" +schema-utils@^4.2.0, schema-utils@^4.3.0, schema-utils@^4.3.2: + version "4.3.3" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-4.3.3.tgz#5b1850912fa31df90716963d45d9121fdfc09f46" + integrity sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA== + dependencies: + "@types/json-schema" "^7.0.9" + ajv "^8.9.0" + ajv-formats "^2.1.1" + ajv-keywords "^5.1.0" + sdp@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/sdp/-/sdp-3.2.0.tgz#8961420552b36663b4d13ddba6f478d1461896a5" @@ -2165,7 +2487,7 @@ select-hose@^2.0.0: resolved "https://registry.yarnpkg.com/select-hose/-/select-hose-2.0.0.tgz#625d8658f865af43ec962bfc376a37359a4994ca" integrity sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg== -selfsigned@^2.1.1: +selfsigned@^2.4.1: version "2.4.1" resolved "https://registry.yarnpkg.com/selfsigned/-/selfsigned-2.4.1.tgz#560d90565442a3ed35b674034cec4e95dceb4ae0" integrity sha512-th5B4L2U+eGLq1TVh7zNRGBapioSORUeymIydxgFpwww9d2qyKvtuPU2jJuHvYAwwqi2Y596QBL3eEqcPEYL8Q== @@ -2173,10 +2495,10 @@ selfsigned@^2.1.1: "@types/node-forge" "^1.3.0" node-forge "^1" -send@0.18.0: - version "0.18.0" - resolved "https://registry.yarnpkg.com/send/-/send-0.18.0.tgz#670167cc654b05f5aa4a767f9113bb371bc706be" - integrity sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg== +send@0.19.0: + version "0.19.0" + resolved "https://registry.yarnpkg.com/send/-/send-0.19.0.tgz#bbc5a388c8ea6c048967049dbeac0e4a3f09d7f8" + integrity sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw== dependencies: debug "2.6.9" depd "2.0.0" @@ -2192,7 +2514,7 @@ send@0.18.0: range-parser "~1.2.1" statuses "2.0.1" -serialize-javascript@^6.0.1, serialize-javascript@^6.0.2: +serialize-javascript@^6.0.2: version "6.0.2" resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.2.tgz#defa1e055c83bf6d59ea805d8da862254eb6a6c2" integrity sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g== @@ -2212,15 +2534,15 @@ serve-index@^1.9.1: mime-types "~2.1.17" parseurl "~1.3.2" -serve-static@1.15.0: - version "1.15.0" - resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.15.0.tgz#faaef08cffe0a1a62f60cad0c4e513cff0ac9540" - integrity sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g== +serve-static@1.16.2: + version "1.16.2" + resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.16.2.tgz#b6a5343da47f6bdd2673848bf45754941e803296" + integrity sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw== dependencies: - encodeurl "~1.0.2" + encodeurl "~2.0.0" escape-html "~1.0.3" parseurl "~1.3.3" - send "0.18.0" + send "0.19.0" setprototypeof@1.1.0: version "1.1.0" @@ -2251,10 +2573,39 @@ shebang-regex@^3.0.0: resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== -shell-quote@^1.8.1: - version "1.8.2" - resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.8.2.tgz#d2d83e057959d53ec261311e9e9b8f51dcb2934a" - integrity sha512-AzqKpGKjrj7EM6rKVQEPpB288oCfnrEIuyoT9cyF4nmGa7V8Zk6f7RRqYisX8X9m+Q7bd632aZW4ky7EhbQztA== +shell-quote@^1.8.3: + version "1.8.3" + resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.8.3.tgz#55e40ef33cf5c689902353a3d8cd1a6725f08b4b" + integrity sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw== + +side-channel-list@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/side-channel-list/-/side-channel-list-1.0.0.tgz#10cb5984263115d3b7a0e336591e290a830af8ad" + integrity sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA== + dependencies: + es-errors "^1.3.0" + object-inspect "^1.13.3" + +side-channel-map@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/side-channel-map/-/side-channel-map-1.0.1.tgz#d6bb6b37902c6fef5174e5f533fab4c732a26f42" + integrity sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA== + dependencies: + call-bound "^1.0.2" + es-errors "^1.3.0" + get-intrinsic "^1.2.5" + object-inspect "^1.13.3" + +side-channel-weakmap@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz#11dda19d5368e40ce9ec2bdc1fb0ecbc0790ecea" + integrity sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A== + dependencies: + call-bound "^1.0.2" + es-errors "^1.3.0" + get-intrinsic "^1.2.5" + object-inspect "^1.13.3" + side-channel-map "^1.0.1" side-channel@^1.0.4: version "1.0.4" @@ -2265,10 +2616,21 @@ side-channel@^1.0.4: get-intrinsic "^1.0.2" object-inspect "^1.9.0" -signal-exit@^3.0.3: - version "3.0.7" - resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" - integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== +side-channel@^1.0.6: + version "1.1.0" + resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.1.0.tgz#c3fcff9c4da932784873335ec9765fa94ff66bc9" + integrity sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw== + dependencies: + es-errors "^1.3.0" + object-inspect "^1.13.3" + side-channel-list "^1.0.0" + side-channel-map "^1.0.1" + side-channel-weakmap "^1.0.2" + +signal-exit@^4.0.1: + version "4.1.0" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04" + integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw== socket.io-adapter@~2.5.2: version "2.5.5" @@ -2376,7 +2738,7 @@ streamroller@^3.1.3: debug "^4.3.4" fs-extra "^8.1.0" -string-width@^4.1.0, string-width@^4.2.0: +"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -2385,6 +2747,15 @@ string-width@^4.1.0, string-width@^4.2.0: is-fullwidth-code-point "^3.0.0" strip-ansi "^6.0.1" +string-width@^5.0.1, string-width@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794" + integrity sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA== + dependencies: + eastasianwidth "^0.2.0" + emoji-regex "^9.2.2" + strip-ansi "^7.0.1" + string_decoder@^1.1.1: version "1.3.0" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" @@ -2399,17 +2770,19 @@ string_decoder@~1.1.1: dependencies: safe-buffer "~5.1.0" -strip-ansi@^6.0.0, strip-ansi@^6.0.1: +"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== dependencies: ansi-regex "^5.0.1" -strip-final-newline@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" - integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== +strip-ansi@^7.0.1: + version "7.1.2" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.2.tgz#132875abde678c7ea8d691533f2e7e22bb744dba" + integrity sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA== + dependencies: + ansi-regex "^6.0.1" strip-json-comments@^3.1.1: version "3.1.1" @@ -2440,27 +2813,32 @@ tapable@^2.1.1, tapable@^2.2.0: resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0" integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ== -terser-webpack-plugin@^5.3.10: - version "5.3.10" - resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-5.3.10.tgz#904f4c9193c6fd2a03f693a2150c62a92f40d199" - integrity sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w== +terser-webpack-plugin@^5.3.11: + version "5.3.14" + resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-5.3.14.tgz#9031d48e57ab27567f02ace85c7d690db66c3e06" + integrity sha512-vkZjpUjb6OMS7dhV+tILUW6BhpDR7P2L/aQSAv+Uwk+m8KATX9EccViHTJR2qDtACKPIYndLGCyl3FMo+r2LMw== dependencies: - "@jridgewell/trace-mapping" "^0.3.20" + "@jridgewell/trace-mapping" "^0.3.25" jest-worker "^27.4.5" - schema-utils "^3.1.1" - serialize-javascript "^6.0.1" - terser "^5.26.0" + schema-utils "^4.3.0" + serialize-javascript "^6.0.2" + terser "^5.31.1" -terser@^5.26.0: - version "5.37.0" - resolved "https://registry.yarnpkg.com/terser/-/terser-5.37.0.tgz#38aa66d1cfc43d0638fab54e43ff8a4f72a21ba3" - integrity sha512-B8wRRkmre4ERucLM/uXx4MOV5cbnOlVAqUst+1+iLKPI0dOgFO28f84ptoQt9HEI537PMzfYa/d+GEPKTRXmYA== +terser@^5.31.1: + version "5.44.0" + resolved "https://registry.yarnpkg.com/terser/-/terser-5.44.0.tgz#ebefb8e5b8579d93111bfdfc39d2cf63879f4a82" + integrity sha512-nIVck8DK+GM/0Frwd+nIhZ84pR/BX7rmXMfYwyg+Sri5oGVE99/E3KvXqpC2xHFxyqXyGHTKBSioxxplrO4I4w== dependencies: "@jridgewell/source-map" "^0.3.3" - acorn "^8.8.2" + acorn "^8.15.0" commander "^2.20.0" source-map-support "~0.5.20" +thingies@^2.5.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/thingies/-/thingies-2.5.0.tgz#5f7b882c933b85989f8466b528a6247a6881e04f" + integrity sha512-s+2Bwztg6PhWUD7XMfeYm5qliDdSiZm7M7n8KjTkIsm3l/2lgVRc2/Gx/v+ZX8lT4FMA+i8aQvhcWylldc+ZNw== + thunky@^1.0.2: version "1.1.0" resolved "https://registry.yarnpkg.com/thunky/-/thunky-1.1.0.tgz#5abaf714a9405db0504732bbccd2cedd9ef9537d" @@ -2485,6 +2863,16 @@ toidentifier@1.0.1: resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35" integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA== +tree-dump@^1.0.3: + version "1.1.0" + resolved "https://registry.yarnpkg.com/tree-dump/-/tree-dump-1.1.0.tgz#ab29129169dc46004414f5a9d4a3c6e89f13e8a4" + integrity sha512-rMuvhU4MCDbcbnleZTFezWsaZXRFemSqAM+7jPnzUl1fo9w3YEKOxAeui0fz3OI4EU4hf23iyA7uQRVko+UaBA== + +tslib@^2.0.0: + version "2.8.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f" + integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w== + type-is@~1.6.18: version "1.6.18" resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" @@ -2493,11 +2881,6 @@ type-is@~1.6.18: media-typer "0.3.0" mime-types "~2.1.24" -typescript@5.5.4: - version "5.5.4" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.5.4.tgz#d9852d6c82bad2d2eda4fd74a5762a8f5909e9ba" - integrity sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q== - ua-parser-js@^0.7.30: version "0.7.32" resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.32.tgz#cd8c639cdca949e30fa68c44b7813ef13e36d211" @@ -2513,13 +2896,13 @@ unpipe@1.0.0, unpipe@~1.0.0: resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ== -update-browserslist-db@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz#80846fba1d79e82547fb661f8d141e0945755fe5" - integrity sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A== +update-browserslist-db@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz#348377dd245216f9e7060ff50b15a1b740b75420" + integrity sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw== dependencies: escalade "^3.2.0" - picocolors "^1.1.0" + picocolors "^1.1.1" uri-js@^4.2.2: version "4.4.1" @@ -2568,71 +2951,70 @@ wbuf@^1.1.0, wbuf@^1.7.3: dependencies: minimalistic-assert "^1.0.0" -webpack-cli@5.1.4: - version "5.1.4" - resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-5.1.4.tgz#c8e046ba7eaae4911d7e71e2b25b776fcc35759b" - integrity sha512-pIDJHIEI9LR0yxHXQ+Qh95k2EvXpWzZ5l+d+jIo+RdSm9MiHfzazIxwwni/p7+x4eJZuvG1AJwgC4TNQ7NRgsg== +webpack-cli@6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-6.0.1.tgz#a1ce25da5ba077151afd73adfa12e208e5089207" + integrity sha512-MfwFQ6SfwinsUVi0rNJm7rHZ31GyTcpVE5pgVA3hwFRb7COD4TzjUUwhGWKfO50+xdc2MQPuEBBJoqIMGt3JDw== dependencies: - "@discoveryjs/json-ext" "^0.5.0" - "@webpack-cli/configtest" "^2.1.1" - "@webpack-cli/info" "^2.0.2" - "@webpack-cli/serve" "^2.0.5" + "@discoveryjs/json-ext" "^0.6.1" + "@webpack-cli/configtest" "^3.0.1" + "@webpack-cli/info" "^3.0.1" + "@webpack-cli/serve" "^3.0.1" colorette "^2.0.14" - commander "^10.0.1" + commander "^12.1.0" cross-spawn "^7.0.3" - envinfo "^7.7.3" + envinfo "^7.14.0" fastest-levenshtein "^1.0.12" import-local "^3.0.2" interpret "^3.1.1" rechoir "^0.8.0" - webpack-merge "^5.7.3" + webpack-merge "^6.0.1" -webpack-dev-middleware@^5.3.4: - version "5.3.4" - resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-5.3.4.tgz#eb7b39281cbce10e104eb2b8bf2b63fce49a3517" - integrity sha512-BVdTqhhs+0IfoeAf7EoH5WE+exCmqGerHfDM0IL096Px60Tq2Mn9MAbnaGUe6HiMa41KMCYF19gyzZmBcq/o4Q== +webpack-dev-middleware@^7.4.2: + version "7.4.5" + resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-7.4.5.tgz#d4e8720aa29cb03bc158084a94edb4594e3b7ac0" + integrity sha512-uxQ6YqGdE4hgDKNf7hUiPXOdtkXvBJXrfEGYSx7P7LC8hnUYGK70X6xQXUvXeNyBDDcsiQXpG2m3G9vxowaEuA== dependencies: colorette "^2.0.10" - memfs "^3.4.3" - mime-types "^2.1.31" + memfs "^4.43.1" + mime-types "^3.0.1" + on-finished "^2.4.1" range-parser "^1.2.1" schema-utils "^4.0.0" -webpack-dev-server@4.15.2: - version "4.15.2" - resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-4.15.2.tgz#9e0c70a42a012560860adb186986da1248333173" - integrity sha512-0XavAZbNJ5sDrCbkpWL8mia0o5WPOd2YGtxrEiZkBK9FjLppIUK2TgxK6qGD2P3hUXTJNNPVibrerKcx5WkR1g== - dependencies: - "@types/bonjour" "^3.5.9" - "@types/connect-history-api-fallback" "^1.3.5" - "@types/express" "^4.17.13" - "@types/serve-index" "^1.9.1" - "@types/serve-static" "^1.13.10" - "@types/sockjs" "^0.3.33" - "@types/ws" "^8.5.5" +webpack-dev-server@5.2.2: + version "5.2.2" + resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-5.2.2.tgz#96a143d50c58fef0c79107e61df911728d7ceb39" + integrity sha512-QcQ72gh8a+7JO63TAx/6XZf/CWhgMzu5m0QirvPfGvptOusAxG12w2+aua1Jkjr7hzaWDnJ2n6JFeexMHI+Zjg== + dependencies: + "@types/bonjour" "^3.5.13" + "@types/connect-history-api-fallback" "^1.5.4" + "@types/express" "^4.17.21" + "@types/express-serve-static-core" "^4.17.21" + "@types/serve-index" "^1.9.4" + "@types/serve-static" "^1.15.5" + "@types/sockjs" "^0.3.36" + "@types/ws" "^8.5.10" ansi-html-community "^0.0.8" - bonjour-service "^1.0.11" - chokidar "^3.5.3" + bonjour-service "^1.2.1" + chokidar "^3.6.0" colorette "^2.0.10" compression "^1.7.4" connect-history-api-fallback "^2.0.0" - default-gateway "^6.0.3" - express "^4.17.3" + express "^4.21.2" graceful-fs "^4.2.6" - html-entities "^2.3.2" - http-proxy-middleware "^2.0.3" - ipaddr.js "^2.0.1" - launch-editor "^2.6.0" - open "^8.0.9" - p-retry "^4.5.0" - rimraf "^3.0.2" - schema-utils "^4.0.0" - selfsigned "^2.1.1" + http-proxy-middleware "^2.0.9" + ipaddr.js "^2.1.0" + launch-editor "^2.6.1" + open "^10.0.3" + p-retry "^6.2.0" + schema-utils "^4.2.0" + selfsigned "^2.4.1" serve-index "^1.9.1" sockjs "^0.3.24" spdy "^4.0.2" - webpack-dev-middleware "^5.3.4" - ws "^8.13.0" + webpack-dev-middleware "^7.4.2" + ws "^8.18.0" webpack-merge@^4.1.5: version "4.2.2" @@ -2641,33 +3023,36 @@ webpack-merge@^4.1.5: dependencies: lodash "^4.17.15" -webpack-merge@^5.7.3: - version "5.8.0" - resolved "https://registry.yarnpkg.com/webpack-merge/-/webpack-merge-5.8.0.tgz#2b39dbf22af87776ad744c390223731d30a68f61" - integrity sha512-/SaI7xY0831XwP6kzuwhKWVKDP9t1QY1h65lAFLbZqMPIuYcD9QAW4u9STIbU9kaJbPBB/geU/gLr1wDjOhQ+Q== +webpack-merge@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/webpack-merge/-/webpack-merge-6.0.1.tgz#50c776868e080574725abc5869bd6e4ef0a16c6a" + integrity sha512-hXXvrjtx2PLYx4qruKl+kyRSLc52V+cCvMxRjmKwoA+CBbbF5GfIBtR6kCvl0fYGqTUPKB+1ktVmTHqMOzgCBg== dependencies: clone-deep "^4.0.1" - wildcard "^2.0.0" - -webpack-sources@^3.2.3: - version "3.2.3" - resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.2.3.tgz#2d4daab8451fd4b240cc27055ff6a0c2ccea0cde" - integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w== - -webpack@5.94.0: - version "5.94.0" - resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.94.0.tgz#77a6089c716e7ab90c1c67574a28da518a20970f" - integrity sha512-KcsGn50VT+06JH/iunZJedYGUJS5FGjow8wb9c0v5n1Om8O1g4L6LjtfxwlXIATopoQu+vOXXa7gYisWxCoPyg== - dependencies: - "@types/estree" "^1.0.5" - "@webassemblyjs/ast" "^1.12.1" - "@webassemblyjs/wasm-edit" "^1.12.1" - "@webassemblyjs/wasm-parser" "^1.12.1" - acorn "^8.7.1" - acorn-import-attributes "^1.9.5" - browserslist "^4.21.10" + flat "^5.0.2" + wildcard "^2.0.1" + +webpack-sources@^3.3.3: + version "3.3.3" + resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.3.3.tgz#d4bf7f9909675d7a070ff14d0ef2a4f3c982c723" + integrity sha512-yd1RBzSGanHkitROoPFd6qsrxt+oFhg/129YzheDGqeustzX0vTZJZsSsQjVQC4yzBQ56K55XU8gaNCtIzOnTg== + +webpack@5.100.2: + version "5.100.2" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.100.2.tgz#e2341facf9f7de1d702147c91bcb65b693adf9e8" + integrity sha512-QaNKAvGCDRh3wW1dsDjeMdDXwZm2vqq3zn6Pvq4rHOEOGSaUMgOOjG2Y9ZbIGzpfkJk9ZYTHpDqgDfeBDcnLaw== + dependencies: + "@types/eslint-scope" "^3.7.7" + "@types/estree" "^1.0.8" + "@types/json-schema" "^7.0.15" + "@webassemblyjs/ast" "^1.14.1" + "@webassemblyjs/wasm-edit" "^1.14.1" + "@webassemblyjs/wasm-parser" "^1.14.1" + acorn "^8.15.0" + acorn-import-phases "^1.0.3" + browserslist "^4.24.0" chrome-trace-event "^1.0.2" - enhanced-resolve "^5.17.1" + enhanced-resolve "^5.17.2" es-module-lexer "^1.2.1" eslint-scope "5.1.1" events "^3.2.0" @@ -2677,11 +3062,11 @@ webpack@5.94.0: loader-runner "^4.2.0" mime-types "^2.1.27" neo-async "^2.6.2" - schema-utils "^3.2.0" + schema-utils "^4.3.2" tapable "^2.1.1" - terser-webpack-plugin "^5.3.10" + terser-webpack-plugin "^5.3.11" watchpack "^2.4.1" - webpack-sources "^3.2.3" + webpack-sources "^3.3.3" webrtc-adapter@9.0.1: version "9.0.1" @@ -2718,17 +3103,17 @@ which@^2.0.1: dependencies: isexe "^2.0.0" -wildcard@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/wildcard/-/wildcard-2.0.0.tgz#a77d20e5200c6faaac979e4b3aadc7b3dd7f8fec" - integrity sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw== +wildcard@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/wildcard/-/wildcard-2.0.1.tgz#5ab10d02487198954836b6349f74fff961e10f67" + integrity sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ== -workerpool@^6.5.1: - version "6.5.1" - resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.5.1.tgz#060f73b39d0caf97c6db64da004cd01b4c099544" - integrity sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA== +workerpool@^9.2.0: + version "9.3.4" + resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-9.3.4.tgz#f6c92395b2141afd78e2a889e80cb338fe9fca41" + integrity sha512-TmPRQYYSAnnDiEB0P/Ytip7bFGvqnSU6I2BcuSw7Hx+JSg/DsUi5ebYfc8GYaSdpuvOcEs6dXxPurOYpe9QFwg== -wrap-ansi@^7.0.0: +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== @@ -2737,31 +3122,52 @@ wrap-ansi@^7.0.0: string-width "^4.1.0" strip-ansi "^6.0.0" +wrap-ansi@^8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214" + integrity sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ== + dependencies: + ansi-styles "^6.1.0" + string-width "^5.0.1" + strip-ansi "^7.0.1" + wrappy@1: version "1.0.2" resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== -ws@^8.13.0: - version "8.18.0" - resolved "https://registry.yarnpkg.com/ws/-/ws-8.18.0.tgz#0d7505a6eafe2b0e712d232b42279f53bc289bbc" - integrity sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw== +ws@^8.18.0: + version "8.18.3" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.18.3.tgz#b56b88abffde62791c639170400c93dcb0c95472" + integrity sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg== ws@~8.17.1: version "8.17.1" resolved "https://registry.yarnpkg.com/ws/-/ws-8.17.1.tgz#9293da530bb548febc95371d90f9c878727d919b" integrity sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ== +wsl-utils@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/wsl-utils/-/wsl-utils-0.1.0.tgz#8783d4df671d4d50365be2ee4c71917a0557baab" + integrity sha512-h3Fbisa2nKGPxCpm89Hk33lBLsnaGBvctQopaBSOW/uIs6FTe1ATyAnKFJrzVs9vpGdsTe73WF3V4lIsk4Gacw== + dependencies: + is-wsl "^3.1.0" + y18n@^5.0.5: version "5.0.8" resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== -yargs-parser@^20.2.2, yargs-parser@^20.2.9: +yargs-parser@^20.2.2: version "20.2.9" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== +yargs-parser@^21.1.1: + version "21.1.1" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35" + integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== + yargs-unparser@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/yargs-unparser/-/yargs-unparser-2.0.0.tgz#f131f9226911ae5d9ad38c432fe809366c2325eb" @@ -2772,7 +3178,7 @@ yargs-unparser@^2.0.0: flat "^5.0.2" is-plain-obj "^2.1.0" -yargs@^16.1.1, yargs@^16.2.0: +yargs@^16.1.1: version "16.2.0" resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== @@ -2785,6 +3191,19 @@ yargs@^16.1.1, yargs@^16.2.0: y18n "^5.0.5" yargs-parser "^20.2.2" +yargs@^17.7.2: + version "17.7.2" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.2.tgz#991df39aca675a192b816e1e0363f9d75d2aa269" + integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w== + dependencies: + cliui "^8.0.1" + 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.1.1" + yocto-queue@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" diff --git a/scripts/setup_apple_demo.sh b/scripts/setup_apple_demo.sh index f26e639..6448685 100755 --- a/scripts/setup_apple_demo.sh +++ b/scripts/setup_apple_demo.sh @@ -6,7 +6,7 @@ set -e pushd example/iosApp xcodegen -pod install +pod install --repo-update popd pushd example/macApp