serve-sim 0.1.46 → 0.1.47-beta.119.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -70,6 +70,7 @@ void SimCamLogSwallowedRuntimeError(NSString *via, id object, NSDictionary *user
70
70
  AVCaptureDeviceFormat *SimCamSharedFakeFormat(void);
71
71
  AVCaptureDevice *SimCamFakeDeviceForPosition(AVCaptureDevicePosition p);
72
72
  AVCaptureDeviceInput *SimCamFakeInputForPosition(AVCaptureDevicePosition p);
73
+ NSArray<AVCaptureInputPort *> *SimCamFakePortsForInput(AVCaptureInput *input);
73
74
 
74
75
  AVCaptureConnection *SimCamFakeConnectionForOutput(AVCaptureOutput *out);
75
76
  void SimCamSetOutputInput(AVCaptureOutput *out, AVCaptureInput *input);
@@ -317,8 +317,7 @@ static AVCaptureInputPort *SimCamFakeInputPortForInput(AVCaptureInput *input, AV
317
317
  - (AVCaptureOutput *)output { return _outputRef; }
318
318
  - (NSArray *)inputPorts {
319
319
  AVCaptureInput *input = SimCamOutputInput(_outputRef) ?: SimCamFakeInputForPosition(_position);
320
- AVCaptureInputPort *port = SimCamFakeInputPortForInput(input, _position);
321
- return port ? @[port] : @[];
320
+ return SimCamFakePortsForInput(input);
322
321
  }
323
322
  - (AVCaptureInput *)input { return SimCamOutputInput(_outputRef) ?: SimCamFakeInputForPosition(_position); }
324
323
  - (AVCaptureVideoPreviewLayer *)videoPreviewLayer { return nil; }
@@ -480,6 +479,12 @@ static AVCaptureInputPort *SimCamFakeInputPortForInput(AVCaptureInput *input, AV
480
479
  return port;
481
480
  }
482
481
 
482
+ NSArray<AVCaptureInputPort *> *SimCamFakePortsForInput(AVCaptureInput *input) {
483
+ if (!SimCamIsFakeInput(input)) return @[];
484
+ AVCaptureInputPort *port = SimCamFakeInputPortForInput(input, SimCamPositionOf(input));
485
+ return port ? @[port] : @[];
486
+ }
487
+
483
488
  #pragma mark - SimCamFakeInput marking
484
489
 
485
490
  static char kSimCamFakeInputKey;
@@ -190,7 +190,7 @@ static BOOL SwizzleInstanceMethod(Class cls, SEL orig, SEL swiz) {
190
190
  return [self simcam_device];
191
191
  }
192
192
  - (NSArray *)simcam_ports {
193
- if (SimCamIsFakeInput(self)) return @[];
193
+ if (SimCamIsFakeInput(self)) return SimCamFakePortsForInput(self);
194
194
  return [self simcam_ports];
195
195
  }
196
196
  @end
@@ -200,7 +200,10 @@ static BOOL SwizzleInstanceMethod(Class cls, SEL orig, SEL swiz) {
200
200
  static char kSimCamSessionRunningKey;
201
201
  static char kSimCamSessionInputsKey;
202
202
  static char kSimCamSessionOutputsKey;
203
+ static char kSimCamSessionConnectionsKey;
203
204
  static char kSimCamOutputAttachedToFakeSessionKey;
205
+ static char kSimCamOutputSessionKey;
206
+ static char kSimCamMaxPhotoDimensionsKey;
204
207
 
205
208
  static NSMutableArray *SimCamSessionTrackedInputs(AVCaptureSession *s) {
206
209
  NSMutableArray *arr = objc_getAssociatedObject(s, &kSimCamSessionInputsKey);
@@ -218,6 +221,14 @@ static NSMutableArray *SimCamSessionTrackedOutputs(AVCaptureSession *s) {
218
221
  }
219
222
  return arr;
220
223
  }
224
+ static NSMutableArray *SimCamSessionTrackedConnections(AVCaptureSession *s) {
225
+ NSMutableArray *arr = objc_getAssociatedObject(s, &kSimCamSessionConnectionsKey);
226
+ if (!arr) {
227
+ arr = [NSMutableArray new];
228
+ objc_setAssociatedObject(s, &kSimCamSessionConnectionsKey, arr, OBJC_ASSOCIATION_RETAIN);
229
+ }
230
+ return arr;
231
+ }
221
232
 
222
233
  static AVCaptureInput *SimCamFirstFakeInputForSession(AVCaptureSession *s) {
223
234
  for (AVCaptureInput *candidate in SimCamSessionTrackedInputs(s)) {
@@ -229,26 +240,95 @@ static AVCaptureInput *SimCamFirstFakeInputForSession(AVCaptureSession *s) {
229
240
  // Real AVFoundation only exposes output connections after an output has been
230
241
  // attached to a session. Keep this per-output so newly created outputs still
231
242
  // look disconnected during client-side session configuration checks.
232
- static void SimCamMarkOutputAttachedToFakeSession(AVCaptureSession *s, AVCaptureOutput *output) {
233
- if (!output) return;
234
- objc_setAssociatedObject(output, &kSimCamOutputAttachedToFakeSessionKey, @YES, OBJC_ASSOCIATION_RETAIN);
235
- SimCamSetOutputInput(output, SimCamFirstFakeInputForSession(s));
236
- }
237
243
  static void SimCamUnmarkOutputAttachedToFakeSession(AVCaptureOutput *output) {
238
244
  if (!output) return;
239
245
  objc_setAssociatedObject(output, &kSimCamOutputAttachedToFakeSessionKey, nil, OBJC_ASSOCIATION_RETAIN);
246
+ objc_setAssociatedObject(output, &kSimCamOutputSessionKey, nil, OBJC_ASSOCIATION_RETAIN);
247
+ objc_setAssociatedObject(output, &kSimCamMaxPhotoDimensionsKey, nil, OBJC_ASSOCIATION_RETAIN);
240
248
  SimCamSetOutputInput(output, nil);
241
249
  }
250
+ static void SimCamMarkOutputAttachedToFakeSession(AVCaptureSession *s, AVCaptureOutput *output) {
251
+ if (!output) return;
252
+ AVCaptureInput *input = SimCamFirstFakeInputForSession(s);
253
+ if (!input) {
254
+ SimCamUnmarkOutputAttachedToFakeSession(output);
255
+ return;
256
+ }
257
+ objc_setAssociatedObject(output, &kSimCamOutputAttachedToFakeSessionKey, @YES, OBJC_ASSOCIATION_RETAIN);
258
+ SimCamWeakRef *sessionRef = [SimCamWeakRef new];
259
+ sessionRef.target = s;
260
+ objc_setAssociatedObject(output, &kSimCamOutputSessionKey, sessionRef, OBJC_ASSOCIATION_RETAIN);
261
+ SimCamSetOutputInput(output, input);
262
+ }
242
263
  static BOOL SimCamOutputAttachedToFakeSession(AVCaptureOutput *output) {
243
264
  if (!output) return NO;
244
265
  return [objc_getAssociatedObject(output, &kSimCamOutputAttachedToFakeSessionKey) boolValue];
245
266
  }
246
267
  static void SimCamRefreshAttachedOutputInputsForSession(AVCaptureSession *s) {
247
- AVCaptureInput *input = SimCamFirstFakeInputForSession(s);
248
268
  for (AVCaptureOutput *output in SimCamSessionTrackedOutputs(s)) {
249
- if (SimCamOutputAttachedToFakeSession(output)) {
250
- SimCamSetOutputInput(output, input);
251
- }
269
+ SimCamMarkOutputAttachedToFakeSession(s, output);
270
+ }
271
+ }
272
+ static AVCaptureSession *SimCamFakeSessionForOutput(AVCaptureOutput *output) {
273
+ SimCamWeakRef *ref = objc_getAssociatedObject(output, &kSimCamOutputSessionKey);
274
+ return ref.target;
275
+ }
276
+ static BOOL SimCamConnectionUsesInput(AVCaptureConnection *connection, AVCaptureInput *input) {
277
+ for (AVCaptureInputPort *port in connection.inputPorts) {
278
+ if (port.input == input) return YES;
279
+ }
280
+ return NO;
281
+ }
282
+ static BOOL SimCamConnectionUsesFakeInput(AVCaptureConnection *connection) {
283
+ for (AVCaptureInputPort *port in connection.inputPorts) {
284
+ if (SimCamIsFakeInput(port.input)) return YES;
285
+ }
286
+ return NO;
287
+ }
288
+ static BOOL SimCamConnectionBelongsToSession(
289
+ AVCaptureConnection *connection,
290
+ AVCaptureSession *session
291
+ ) {
292
+ NSArray<AVCaptureInputPort *> *ports = connection.inputPorts;
293
+ if (ports.count == 0) return NO;
294
+ NSArray<AVCaptureInput *> *inputs = SimCamSessionTrackedInputs(session);
295
+ for (AVCaptureInputPort *port in ports) {
296
+ if (![inputs containsObject:port.input]) return NO;
297
+ }
298
+ AVCaptureOutput *output = connection.output;
299
+ return !output || [SimCamSessionTrackedOutputs(session) containsObject:output];
300
+ }
301
+ static NSArray<AVCaptureConnection *> *SimCamConnectionsForOutput(AVCaptureOutput *output) {
302
+ AVCaptureSession *session = SimCamFakeSessionForOutput(output);
303
+ if (!session) return @[];
304
+ NSMutableArray *result = [NSMutableArray new];
305
+ for (AVCaptureConnection *connection in SimCamSessionTrackedConnections(session)) {
306
+ if (connection.output == output) [result addObject:connection];
307
+ }
308
+ return [result copy];
309
+ }
310
+ static void SimCamRecordConnection(AVCaptureSession *session, AVCaptureConnection *connection) {
311
+ if (!connection) return;
312
+ NSMutableArray *connections = SimCamSessionTrackedConnections(session);
313
+ if (![connections containsObject:connection]) [connections addObject:connection];
314
+ }
315
+ static void SimCamRemoveConnectionsForOutput(AVCaptureSession *session, AVCaptureOutput *output) {
316
+ NSMutableArray *connections = SimCamSessionTrackedConnections(session);
317
+ for (AVCaptureConnection *connection in [connections copy]) {
318
+ if (connection.output == output) [connections removeObject:connection];
319
+ }
320
+ }
321
+ static void SimCamRemoveConnectionsForInput(AVCaptureSession *session, AVCaptureInput *input) {
322
+ NSMutableArray *connections = SimCamSessionTrackedConnections(session);
323
+ for (AVCaptureConnection *connection in [connections copy]) {
324
+ if (SimCamConnectionUsesInput(connection, input)) [connections removeObject:connection];
325
+ }
326
+ }
327
+ static void SimCamAddAutomaticConnections(AVCaptureSession *session) {
328
+ for (AVCaptureOutput *output in SimCamSessionTrackedOutputs(session)) {
329
+ if (!SimCamOutputAttachedToFakeSession(output)) continue;
330
+ if (SimCamConnectionsForOutput(output).count > 0) continue;
331
+ SimCamRecordConnection(session, SimCamFakeConnectionForOutput(output));
252
332
  }
253
333
  }
254
334
 
@@ -264,6 +344,7 @@ static void SimCamRefreshAttachedOutputInputsForSession(AVCaptureSession *s) {
264
344
  NSMutableArray *tracked = SimCamSessionTrackedInputs(self);
265
345
  if (![tracked containsObject:input]) [tracked addObject:input];
266
346
  SimCamRefreshAttachedOutputInputsForSession(self);
347
+ SimCamAddAutomaticConnections(self);
267
348
  simcam_log(@"addInput: fake input (%@) — tracked (count=%lu), skipping native add",
268
349
  p == AVCaptureDevicePositionBack ? @"back" : @"front",
269
350
  (unsigned long)tracked.count);
@@ -294,6 +375,7 @@ static void SimCamRefreshAttachedOutputInputsForSession(AVCaptureSession *s) {
294
375
  - (void)simcam_removeInput:(AVCaptureInput *)input {
295
376
  if (SimCamIsFakeInput(input)) {
296
377
  NSMutableArray *tracked = SimCamSessionTrackedInputs(self);
378
+ SimCamRemoveConnectionsForInput(self, input);
297
379
  [tracked removeObject:input];
298
380
  SimCamRefreshAttachedOutputInputsForSession(self);
299
381
  if (tracked.count == 0) SimCamMarkSessionUsingFakeCamera(self, NO);
@@ -305,10 +387,13 @@ static void SimCamRefreshAttachedOutputInputsForSession(AVCaptureSession *s) {
305
387
  }
306
388
  - (void)simcam_addOutput:(AVCaptureOutput *)output {
307
389
  SimCamSetPosition(output, SimCamPositionOf(self));
308
- SimCamMarkOutputAttachedToFakeSession(self, output);
309
390
  SimCamMarkCameraInUse();
310
391
  NSMutableArray *tracked = SimCamSessionTrackedOutputs(self);
311
392
  if (![tracked containsObject:output]) [tracked addObject:output];
393
+ SimCamMarkOutputAttachedToFakeSession(self, output);
394
+ if (SimCamOutputAttachedToFakeSession(output)) {
395
+ SimCamRecordConnection(self, SimCamFakeConnectionForOutput(output));
396
+ }
312
397
  simcam_log(@"addOutput: %@ (intercepted, tracked count=%lu, pos=%d)",
313
398
  NSStringFromClass([output class]),
314
399
  (unsigned long)tracked.count,
@@ -317,16 +402,17 @@ static void SimCamRefreshAttachedOutputInputsForSession(AVCaptureSession *s) {
317
402
  - (BOOL)simcam_canAddOutput:(AVCaptureOutput *)output { return YES; }
318
403
  - (void)simcam_addOutputWithNoConnections:(AVCaptureOutput *)output {
319
404
  SimCamSetPosition(output, SimCamPositionOf(self));
320
- SimCamMarkOutputAttachedToFakeSession(self, output);
321
405
  SimCamMarkCameraInUse();
322
406
  NSMutableArray *tracked = SimCamSessionTrackedOutputs(self);
323
407
  if (![tracked containsObject:output]) [tracked addObject:output];
408
+ SimCamMarkOutputAttachedToFakeSession(self, output);
324
409
  simcam_log(@"addOutputWithNoConnections: %@ (intercepted, tracked count=%lu, pos=%d)",
325
410
  NSStringFromClass([output class]),
326
411
  (unsigned long)tracked.count,
327
412
  (int)SimCamPositionOf(self));
328
413
  }
329
414
  - (void)simcam_removeOutput:(AVCaptureOutput *)output {
415
+ SimCamRemoveConnectionsForOutput(self, output);
330
416
  SimCamUnmarkOutputAttachedToFakeSession(output);
331
417
  NSMutableArray *tracked = SimCamSessionTrackedOutputs(self);
332
418
  [tracked removeObject:output];
@@ -344,9 +430,33 @@ static void SimCamRefreshAttachedOutputInputsForSession(AVCaptureSession *s) {
344
430
  simcam_log(@"commitConfiguration intercepted (session=%p, fakeInputs=%lu, fakeOutputs=%lu)",
345
431
  self, (unsigned long)inCount, (unsigned long)outCount);
346
432
  }
347
- - (BOOL)simcam_canAddConnection:(AVCaptureConnection *)c { (void)c; return YES; }
433
+ - (BOOL)simcam_canAddConnection:(AVCaptureConnection *)connection {
434
+ if (SimCamConnectionUsesFakeInput(connection)) {
435
+ return SimCamConnectionBelongsToSession(connection, self) &&
436
+ ![SimCamSessionTrackedConnections(self) containsObject:connection];
437
+ }
438
+ return [self simcam_canAddConnection:connection];
439
+ }
348
440
  - (void)simcam_addConnection:(AVCaptureConnection *)c {
349
- simcam_log(@"addConnection intercepted (session=%p, conn=%p)", self, c);
441
+ if (!SimCamConnectionUsesFakeInput(c)) {
442
+ [self simcam_addConnection:c];
443
+ return;
444
+ }
445
+ if (!SimCamConnectionBelongsToSession(c, self)) {
446
+ simcam_log(@"addConnection: rejected unowned fake connection (session=%p, conn=%p)", self, c);
447
+ return;
448
+ }
449
+ AVCaptureOutput *output = c.output;
450
+ SimCamRecordConnection(self, c);
451
+ simcam_log(@"addConnection: fake input (session=%p, conn=%p, output=%p)", self, c, output);
452
+ }
453
+ - (void)simcam_removeConnection:(AVCaptureConnection *)c {
454
+ if (!SimCamConnectionUsesFakeInput(c)) {
455
+ [self simcam_removeConnection:c];
456
+ return;
457
+ }
458
+ [SimCamSessionTrackedConnections(self) removeObject:c];
459
+ simcam_log(@"removeConnection: fake input (session=%p, conn=%p, output=%p)", self, c, c.output);
350
460
  }
351
461
  - (NSArray<AVCaptureInput *> *)simcam_inputs {
352
462
  NSMutableArray *tracked = objc_getAssociatedObject(self, &kSimCamSessionInputsKey);
@@ -371,14 +481,10 @@ static void SimCamRefreshAttachedOutputInputsForSession(AVCaptureSession *s) {
371
481
  return [merged copy];
372
482
  }
373
483
  - (NSArray<AVCaptureConnection *> *)simcam_connections {
374
- NSMutableArray *trackedOut = objc_getAssociatedObject(self, &kSimCamSessionOutputsKey);
484
+ NSMutableArray *tracked = objc_getAssociatedObject(self, &kSimCamSessionConnectionsKey);
375
485
  NSArray *native = [self simcam_connections];
376
- if (trackedOut.count == 0) return native ?: @[];
377
- NSMutableArray *merged = [NSMutableArray arrayWithCapacity:trackedOut.count + native.count];
378
- for (AVCaptureOutput *o in trackedOut) {
379
- AVCaptureConnection *c = SimCamFakeConnectionForOutput(o);
380
- if (c) [merged addObject:c];
381
- }
486
+ if (tracked.count == 0) return native ?: @[];
487
+ NSMutableArray *merged = [tracked mutableCopy];
382
488
  for (AVCaptureConnection *n in native) {
383
489
  if (![merged containsObject:n]) [merged addObject:n];
384
490
  }
@@ -478,17 +584,22 @@ static void SimCamRefreshAttachedOutputInputsForSession(AVCaptureSession *s) {
478
584
  if (real) return real;
479
585
  if (!SimCamOutputAttachedToFakeSession(self)) return nil;
480
586
  if (![mediaType isEqualToString:AVMediaTypeVideo]) return nil;
481
- AVCaptureConnection *fake = SimCamFakeConnectionForOutput(self);
482
- simcam_log(@"connectionWithMediaType:%@ → fake %p for %@ %p",
483
- mediaType, fake, NSStringFromClass([self class]), self);
484
- return fake;
587
+ AVCaptureConnection *connection = SimCamConnectionsForOutput(self).firstObject;
588
+ simcam_log(@"connectionWithMediaType:%@ → tracked %p for %@ %p",
589
+ mediaType, connection, NSStringFromClass([self class]), self);
590
+ return connection;
485
591
  }
486
592
  - (NSArray<AVCaptureConnection *> *)simcam_connections {
487
593
  NSArray *real = [self simcam_connections];
488
- if (real.count > 0) return real;
489
594
  if (!SimCamOutputAttachedToFakeSession(self)) return real ?: @[];
490
- AVCaptureConnection *fake = SimCamFakeConnectionForOutput(self);
491
- return fake ? @[fake] : @[];
595
+ NSArray *tracked = SimCamConnectionsForOutput(self);
596
+ if (tracked.count == 0) return real ?: @[];
597
+ if (real.count == 0) return tracked;
598
+ NSMutableArray *merged = [tracked mutableCopy];
599
+ for (AVCaptureConnection *connection in real) {
600
+ if (![merged containsObject:connection]) [merged addObject:connection];
601
+ }
602
+ return [merged copy];
492
603
  }
493
604
  @end
494
605
 
@@ -537,8 +648,33 @@ static void SimCamRefreshAttachedOutputInputsForSession(AVCaptureSession *s) {
537
648
  @interface AVCapturePhotoOutput (SimCam)
538
649
  @end
539
650
  @implementation AVCapturePhotoOutput (SimCam)
651
+ - (CMVideoDimensions)simcam_maxPhotoDimensions {
652
+ if (SimCamOutputAttachedToFakeSession(self)) {
653
+ NSValue *value = objc_getAssociatedObject(self, &kSimCamMaxPhotoDimensionsKey);
654
+ if (value) {
655
+ CMVideoDimensions dimensions = { 0, 0 };
656
+ [value getValue:&dimensions size:sizeof(dimensions)];
657
+ return dimensions;
658
+ }
659
+ }
660
+ return [self simcam_maxPhotoDimensions];
661
+ }
662
+ - (void)simcam_setMaxPhotoDimensions:(CMVideoDimensions)dimensions {
663
+ if (!SimCamOutputAttachedToFakeSession(self)) {
664
+ [self simcam_setMaxPhotoDimensions:dimensions];
665
+ return;
666
+ }
667
+ // AVFoundation validates this against private AVCaptureDeviceFormat state.
668
+ // Synthetic formats only have public state, so retain the value per output.
669
+ NSValue *value = [NSValue valueWithBytes:&dimensions objCType:@encode(CMVideoDimensions)];
670
+ objc_setAssociatedObject(self, &kSimCamMaxPhotoDimensionsKey, value, OBJC_ASSOCIATION_RETAIN);
671
+ }
540
672
  - (void)simcam_capturePhotoWithSettings:(AVCapturePhotoSettings *)settings
541
673
  delegate:(id<AVCapturePhotoCaptureDelegate>)delegate {
674
+ if (!SimCamOutputAttachedToFakeSession(self)) {
675
+ [self simcam_capturePhotoWithSettings:settings delegate:delegate];
676
+ return;
677
+ }
542
678
  if (!delegate) return;
543
679
  SimCamRegistry *reg = [SimCamRegistry shared];
544
680
  CVPixelBufferRef pb = [reg currentPixelBuffer];
@@ -581,11 +717,11 @@ static void SimCamRefreshAttachedOutputInputsForSession(AVCaptureSession *s) {
581
717
  (int)p, (int)mirror, (unsigned long)photo.fileDataRepresentation.length,
582
718
  resolved.photoDimensions.width, resolved.photoDimensions.height);
583
719
  AVCapturePhotoOutput *output = self;
584
- SEL selWillBegin = @selector(photoOutput:willBeginCaptureForResolvedSettings:);
585
- SEL selWillCapture = @selector(photoOutput:willCapturePhotoForResolvedSettings:);
586
- SEL selDidProcess = @selector(photoOutput:didFinishProcessingPhoto:error:);
587
- SEL selDidCapture = @selector(photoOutput:didCapturePhotoForResolvedSettings:);
588
- SEL selDidFinish = @selector(photoOutput:didFinishCaptureForResolvedSettings:error:);
720
+ SEL selWillBegin = @selector(captureOutput:willBeginCaptureForResolvedSettings:);
721
+ SEL selWillCapture = @selector(captureOutput:willCapturePhotoForResolvedSettings:);
722
+ SEL selDidProcess = @selector(captureOutput:didFinishProcessingPhoto:error:);
723
+ SEL selDidCapture = @selector(captureOutput:didCapturePhotoForResolvedSettings:);
724
+ SEL selDidFinish = @selector(captureOutput:didFinishCaptureForResolvedSettings:error:);
589
725
  dispatch_async(dispatch_get_main_queue(), ^{
590
726
  if ([delegate respondsToSelector:selWillBegin]) {
591
727
  ((void (*)(id, SEL, AVCapturePhotoOutput *, AVCaptureResolvedPhotoSettings *))
@@ -595,16 +731,16 @@ static void SimCamRefreshAttachedOutputInputsForSession(AVCaptureSession *s) {
595
731
  ((void (*)(id, SEL, AVCapturePhotoOutput *, AVCaptureResolvedPhotoSettings *))
596
732
  objc_msgSend)(delegate, selWillCapture, output, resolved);
597
733
  }
734
+ if ([delegate respondsToSelector:selDidCapture]) {
735
+ ((void (*)(id, SEL, AVCapturePhotoOutput *, AVCaptureResolvedPhotoSettings *))
736
+ objc_msgSend)(delegate, selDidCapture, output, resolved);
737
+ }
598
738
  BOOL delivered = NO;
599
739
  if ([delegate respondsToSelector:selDidProcess]) {
600
740
  ((void (*)(id, SEL, AVCapturePhotoOutput *, AVCapturePhoto *, NSError *))
601
741
  objc_msgSend)(delegate, selDidProcess, output, photo, (NSError *)nil);
602
742
  delivered = YES;
603
743
  }
604
- if ([delegate respondsToSelector:selDidCapture]) {
605
- ((void (*)(id, SEL, AVCapturePhotoOutput *, AVCaptureResolvedPhotoSettings *))
606
- objc_msgSend)(delegate, selDidCapture, output, resolved);
607
- }
608
744
  if ([delegate respondsToSelector:selDidFinish]) {
609
745
  ((void (*)(id, SEL, AVCapturePhotoOutput *, AVCaptureResolvedPhotoSettings *, NSError *))
610
746
  objc_msgSend)(delegate, selDidFinish, output, resolved, (NSError *)nil);
@@ -984,6 +1120,9 @@ void SimCamInstallSwizzles(void) {
984
1120
  SwizzleInstanceMethod(sess,
985
1121
  @selector(addConnection:),
986
1122
  @selector(simcam_addConnection:));
1123
+ SwizzleInstanceMethod(sess,
1124
+ @selector(removeConnection:),
1125
+ @selector(simcam_removeConnection:));
987
1126
  SwizzleInstanceMethod(sess,
988
1127
  @selector(canAddConnection:),
989
1128
  @selector(simcam_canAddConnection:));
@@ -1050,6 +1189,14 @@ void SimCamInstallSwizzles(void) {
1050
1189
  }
1051
1190
 
1052
1191
  Class photoOut = [AVCapturePhotoOutput class];
1192
+ if (@available(iOS 16.0, *)) {
1193
+ SwizzleInstanceMethod(photoOut,
1194
+ @selector(maxPhotoDimensions),
1195
+ @selector(simcam_maxPhotoDimensions));
1196
+ SwizzleInstanceMethod(photoOut,
1197
+ @selector(setMaxPhotoDimensions:),
1198
+ @selector(simcam_setMaxPhotoDimensions:));
1199
+ }
1053
1200
  SwizzleInstanceMethod(photoOut,
1054
1201
  @selector(capturePhotoWithSettings:delegate:),
1055
1202
  @selector(simcam_capturePhotoWithSettings:delegate:));
package/dist/serve-sim.js CHANGED
@@ -146,7 +146,7 @@ Usage:
146
146
  serve-sim permissions reset <permission|all> <bundle-id> [-d <udid|name>]
147
147
  serve-sim permissions list [bundle-id] [-d <udid|name>]
148
148
 
149
- Permissions: ${k8().join(", ")}`),process.exit(1);let Y=J.device?o(J.device):Q$();if(!Y)console.error("No booted simulator. Boot one or pass -d <udid|name>."),process.exit(1);if(J.verb==="list"){let G={udid:Y,bundleId:J.bundleId??null,tcc:RZ(Y,J.bundleId),location:UZ(Y,J.bundleId),notifications:FZ(Y,J.bundleId)};console.log(JSON.stringify(G,null,Q?0:2)),process.exit(0)}let X=J.bundleId;try{if(J.permission==="all")for(let G of k8())n6(Y,"reset",G,void 0,X);else n6(Y,J.verb,J.permission,J.value,X)}catch(G){console.error(G?.message??String(G)),process.exit(1)}if(Q)console.log(JSON.stringify({udid:Y,verb:J.verb,permission:J.permission,value:J.value??null,bundleId:X}));else{let G=J.value?` (${J.value})`:"";console.log(`\uD83D\uDD10 ${J.verb} ${J.permission}${G} for ${X} on ${Y}`)}process.exit(0)}l8();o8();function F7($,Q={}){let Z=new Date($.timestamp),J=Number.isNaN(Z.getTime())?$.timestamp:Z.toLocaleTimeString([],{hour:"2-digit",minute:"2-digit",second:"2-digit"}),Y=Q.deviceLabel??($.device?$.device.slice(0,8):null),X=$.status==="error"?" failed":"";return[J,Y,`${V1($)}${X?` (${X.trim()})`:""}`].filter(Boolean).join(" ")}function V1($){if($.kind==="tap"){let Q=i0($.details,"current")??i0($.details,"start");return Q?`Tap at ${a8(Q)}`:"Tap"}if($.kind==="drag"){let Q=i0($.details,"start"),Z=i0($.details,"current");if(Q&&Z)return`Drag from ${a8(Q)} to ${a8(Z)}`;return"Drag"}if($.kind==="key"){let Q=M1($.details,"key")??$.action??"key",Z=$.action==="down"?"down":$.action==="up"?"up":$.action;return Z?`Key ${Z} ${B7(Q)}`:`Key ${B7(Q)}`}if($.kind==="rotate"){let Q=$.action?T7($.action):"";return Q?`Rotate ${Q}`:"Rotate"}return R1($.msg??$.summary)}function i0($,Q){let Z=$?.[Q];if(!Z||typeof Z!=="object"||Array.isArray(Z))return null;let J=Z;return typeof J.x==="number"&&typeof J.y==="number"?{x:J.x,y:J.y}:null}function M1($,Q){let Z=$?.[Q];return typeof Z==="string"&&Z.length>0?Z:null}function a8($){return`${N7($.x)}, ${N7($.y)}`}function N7($){if(!Number.isFinite($))return"?";return(Math.round((H1($,0,1)+Number.EPSILON)*100)/100).toFixed(2)}function H1($,Q,Z){return Math.min(Z,Math.max(Q,$))}function R1($){return $.replace(/\b[a-z]+(?:_[a-z]+)+\b/g,T7)}function T7($){return $.replace(/[-_]+/g," ")}function B7($){return{MetaLeft:"Left Command",MetaRight:"Right Command",AltLeft:"Left Option",AltRight:"Right Option",ControlLeft:"Left Control",ControlRight:"Right Control",ShiftLeft:"Left Shift",ShiftRight:"Right Shift",ArrowLeft:"Left Arrow",ArrowRight:"Right Arrow",ArrowUp:"Up Arrow",ArrowDown:"Down Arrow"}[$]??$}var j7=["devices","tools","devtools"];function O7($){let Q=$.split(",").map((J)=>J.trim().toLowerCase()).filter(Boolean);if(Q.length===1&&Q[0]==="none")return[];if(Q.length===0||Q.includes("none"))throw Error("Expected 'none' or a comma-separated list of: devices, tools, devtools.");let Z=Q.filter((J)=>!j7.includes(J));if(Z.length>0)throw Error(`Unknown pane${Z.length===1?"":"s"}: ${Z.join(", ")}. Expected: ${j7.join(", ")}.`);return[...new Set(Q)]}function E7($){let Q=$.trim().toLowerCase();if(Q==="light"||Q==="dark")return Q;throw Error("Expected simulator theme: light or dark.")}s8();var C$=u0(import.meta.url);function LY(){return"0.1.46"}function T4(){if(!K$(W$))$6(W$,{recursive:!0})}function r($){if($)return sQ(V0($));for(let Q of b0()){let Z=sQ(Q);if(Z)return Z}return null}var _8={at:0,booted:null};function UY(){let $=Date.now();if(_8.booted&&$-_8.at<1000)return _8.booted;try{let Q=J$("xcrun simctl list devices booted -j",{encoding:"utf-8",stdio:["ignore","pipe","pipe"],timeout:3000}),Z=JSON.parse(Q),J=new Set;for(let Y of Object.values(Z.devices))for(let X of Y)if(X.state==="Booted")J.add(X.udid);return _8={at:$,booted:J},J}catch{return null}}function sQ($){try{if(!K$($))return V$("state file missing %s",$),null;let Q=JSON.parse(m$($,"utf-8"));try{process.kill(Q.pid,0)}catch{return V$("helper pid %d dead, removing stale state %s",Q.pid,$),g$($),null}let Z=UY();if(Z&&!Z.has(Q.device)){if(Q.pid===process.pid){V$("dropping own stale state for non-booted device %s",Q.device);try{g$($)}catch{}return null}V$("helper pid %d bound to non-booted device %s — killing stale helper",Q.pid,Q.device),console.error(`[serve-sim] Helper pid ${Q.pid} is bound to device ${Q.device} which is no longer booted — killing stale helper.`);try{process.kill(Q.pid,"SIGTERM")}catch{}try{g$($)}catch{}return null}return V$("state ok pid=%d device=%s port=%d",Q.pid,Q.device,Q.port),Q}catch(Q){return V$("readStateFile threw for %s: %o",$,Q),null}}function x0(){let $=[];for(let Q of b0()){let Z=sQ(Q);if(Z)$.push(Z)}return $}function _Y($){T4(),J6(V0($.device),JSON.stringify($,null,2)),V$("wrote state pid=%d device=%s port=%d",$.pid,$.device,$.port)}function c$($){if($){V$("clearState device=%s",$);try{g$(V0($))}catch{}}else{V$("clearState (all)");for(let Q of b0())try{g$(Q)}catch{}}}function Y6(){try{let $=J$("xcrun simctl list devices -j",{encoding:"utf-8"}),Q=JSON.parse($),Z=Object.keys(Q.devices).filter((J)=>/SimRuntime\.iOS-/i.test(J)).sort((J,Y)=>{let X=(J.match(/iOS-(\d+)-(\d+)/)??[]).slice(1).map(Number),G=(Y.match(/iOS-(\d+)-(\d+)/)??[]).slice(1).map(Number);return(G[0]??0)-(X[0]??0)||(G[1]??0)-(X[1]??0)});for(let J of Z){let X=(Q.devices[J]??[]).find((G)=>G.isAvailable!==!1&&/^iPhone\b/i.test(G.name));if(X)return{udid:X.udid,name:X.name}}}catch{}return null}function B4($){return j4().get($)??null}function j4(){let $=new Map;try{let Q=J$("xcrun simctl list devices -j",{encoding:"utf-8"}),Z=JSON.parse(Q);for(let J of Object.values(Z.devices))for(let Y of J)$.set(Y.udid,Y.name)}catch{}return $}function O4($){try{let Q=J$("xcrun simctl list devices -j",{encoding:"utf-8"}),Z=JSON.parse(Q);for(let J of Object.values(Z.devices))for(let Y of J)if(Y.udid===$)return Y.state==="Booted"}catch{}return!1}function eQ($){try{return process.kill($,0),!0}catch{return!1}}function E4($){try{process.kill($,"SIGTERM")}catch{return}let Q=Date.now()+500;while(Date.now()<Q)try{process.kill($,0),I$(25)}catch{return}try{process.kill($,"SIGKILL")}catch{}let Z=Date.now()+500;while(Date.now()<Z)try{process.kill($,0),I$(25)}catch{return}}function NY($){if(!O4($))try{J$(`xcrun simctl boot ${$}`,{encoding:"utf-8",stdio:"pipe"})}catch(Q){let Z=(Q.stderr??Q.message??"").toLowerCase();if(!Z.includes("booted")&&!Z.includes("current state"))throw Error(`Failed to boot device ${$}: ${Q.stderr||Q.message}`)}try{J$("open -ga Simulator",{encoding:"utf-8",stdio:"pipe",timeout:3000})}catch{}}function BY(){let $=RY();for(let Q of Object.values($))for(let Z of Q??[])if(Z.family==="IPv4"&&!Z.internal)return Z.address;return null}async function q4($){let Q=new Set(x0().map((Z)=>Z.port));for(let Z=$;Z<$+100;Z++){if(Q.has(Z))continue;if(await m6(Z))return Z}throw Error(`No available port found in range ${$}-${$+99}`)}async function FY($){NY($);try{VY("xcrun",s0($),{encoding:"utf-8",stdio:"pipe",timeout:60000})}catch(Q){if(!O4($))console.error(`Device ${$} failed to reach booted state: ${Q.stderr||Q.message}`),process.exit(1)}}function TY($){if(process.argv[0]&&/(^|\/)serve-sim$/.test(process.argv[0]))return{command:process.argv[0],args:$};return{command:process.argv[0],args:[process.argv[1],...$]}}async function jY($,Q=150000){let Z=Date.now();while(Date.now()-Z<Q){let J=r($);if(J)return J;await new Promise((Y)=>setTimeout(Y,200))}return null}async function A4($,Q,Z){i8("startHelper udid=%s port=%d detach=%s",$,Q,Z.detach);let J="127.0.0.1";T4(),c$($),p6(Q);let Y=M$(W$,`server-${$}.log`),X=Q6(Y,"w"),{command:G,args:V}=TY([$,"--port",String(Q),"--host",J]),W=F4(G,V,{detached:Z.detach,stdio:["ignore",X,X]});if(Z6(X),Z.detach)W.unref();let z=await jY($);if(!z){if(W.pid)E4(W.pid);let K="";try{K=m$(Y,"utf-8").trim()}catch{}console.error(K?`Preview server failed:
149
+ Permissions: ${k8().join(", ")}`),process.exit(1);let Y=J.device?o(J.device):Q$();if(!Y)console.error("No booted simulator. Boot one or pass -d <udid|name>."),process.exit(1);if(J.verb==="list"){let G={udid:Y,bundleId:J.bundleId??null,tcc:RZ(Y,J.bundleId),location:UZ(Y,J.bundleId),notifications:FZ(Y,J.bundleId)};console.log(JSON.stringify(G,null,Q?0:2)),process.exit(0)}let X=J.bundleId;try{if(J.permission==="all")for(let G of k8())n6(Y,"reset",G,void 0,X);else n6(Y,J.verb,J.permission,J.value,X)}catch(G){console.error(G?.message??String(G)),process.exit(1)}if(Q)console.log(JSON.stringify({udid:Y,verb:J.verb,permission:J.permission,value:J.value??null,bundleId:X}));else{let G=J.value?` (${J.value})`:"";console.log(`\uD83D\uDD10 ${J.verb} ${J.permission}${G} for ${X} on ${Y}`)}process.exit(0)}l8();o8();function F7($,Q={}){let Z=new Date($.timestamp),J=Number.isNaN(Z.getTime())?$.timestamp:Z.toLocaleTimeString([],{hour:"2-digit",minute:"2-digit",second:"2-digit"}),Y=Q.deviceLabel??($.device?$.device.slice(0,8):null),X=$.status==="error"?" failed":"";return[J,Y,`${V1($)}${X?` (${X.trim()})`:""}`].filter(Boolean).join(" ")}function V1($){if($.kind==="tap"){let Q=i0($.details,"current")??i0($.details,"start");return Q?`Tap at ${a8(Q)}`:"Tap"}if($.kind==="drag"){let Q=i0($.details,"start"),Z=i0($.details,"current");if(Q&&Z)return`Drag from ${a8(Q)} to ${a8(Z)}`;return"Drag"}if($.kind==="key"){let Q=M1($.details,"key")??$.action??"key",Z=$.action==="down"?"down":$.action==="up"?"up":$.action;return Z?`Key ${Z} ${B7(Q)}`:`Key ${B7(Q)}`}if($.kind==="rotate"){let Q=$.action?T7($.action):"";return Q?`Rotate ${Q}`:"Rotate"}return R1($.msg??$.summary)}function i0($,Q){let Z=$?.[Q];if(!Z||typeof Z!=="object"||Array.isArray(Z))return null;let J=Z;return typeof J.x==="number"&&typeof J.y==="number"?{x:J.x,y:J.y}:null}function M1($,Q){let Z=$?.[Q];return typeof Z==="string"&&Z.length>0?Z:null}function a8($){return`${N7($.x)}, ${N7($.y)}`}function N7($){if(!Number.isFinite($))return"?";return(Math.round((H1($,0,1)+Number.EPSILON)*100)/100).toFixed(2)}function H1($,Q,Z){return Math.min(Z,Math.max(Q,$))}function R1($){return $.replace(/\b[a-z]+(?:_[a-z]+)+\b/g,T7)}function T7($){return $.replace(/[-_]+/g," ")}function B7($){return{MetaLeft:"Left Command",MetaRight:"Right Command",AltLeft:"Left Option",AltRight:"Right Option",ControlLeft:"Left Control",ControlRight:"Right Control",ShiftLeft:"Left Shift",ShiftRight:"Right Shift",ArrowLeft:"Left Arrow",ArrowRight:"Right Arrow",ArrowUp:"Up Arrow",ArrowDown:"Down Arrow"}[$]??$}var j7=["devices","tools","devtools"];function O7($){let Q=$.split(",").map((J)=>J.trim().toLowerCase()).filter(Boolean);if(Q.length===1&&Q[0]==="none")return[];if(Q.length===0||Q.includes("none"))throw Error("Expected 'none' or a comma-separated list of: devices, tools, devtools.");let Z=Q.filter((J)=>!j7.includes(J));if(Z.length>0)throw Error(`Unknown pane${Z.length===1?"":"s"}: ${Z.join(", ")}. Expected: ${j7.join(", ")}.`);return[...new Set(Q)]}function E7($){let Q=$.trim().toLowerCase();if(Q==="light"||Q==="dark")return Q;throw Error("Expected simulator theme: light or dark.")}s8();var C$=u0(import.meta.url);function LY(){return"0.1.47-beta.119.1"}function T4(){if(!K$(W$))$6(W$,{recursive:!0})}function r($){if($)return sQ(V0($));for(let Q of b0()){let Z=sQ(Q);if(Z)return Z}return null}var _8={at:0,booted:null};function UY(){let $=Date.now();if(_8.booted&&$-_8.at<1000)return _8.booted;try{let Q=J$("xcrun simctl list devices booted -j",{encoding:"utf-8",stdio:["ignore","pipe","pipe"],timeout:3000}),Z=JSON.parse(Q),J=new Set;for(let Y of Object.values(Z.devices))for(let X of Y)if(X.state==="Booted")J.add(X.udid);return _8={at:$,booted:J},J}catch{return null}}function sQ($){try{if(!K$($))return V$("state file missing %s",$),null;let Q=JSON.parse(m$($,"utf-8"));try{process.kill(Q.pid,0)}catch{return V$("helper pid %d dead, removing stale state %s",Q.pid,$),g$($),null}let Z=UY();if(Z&&!Z.has(Q.device)){if(Q.pid===process.pid){V$("dropping own stale state for non-booted device %s",Q.device);try{g$($)}catch{}return null}V$("helper pid %d bound to non-booted device %s — killing stale helper",Q.pid,Q.device),console.error(`[serve-sim] Helper pid ${Q.pid} is bound to device ${Q.device} which is no longer booted — killing stale helper.`);try{process.kill(Q.pid,"SIGTERM")}catch{}try{g$($)}catch{}return null}return V$("state ok pid=%d device=%s port=%d",Q.pid,Q.device,Q.port),Q}catch(Q){return V$("readStateFile threw for %s: %o",$,Q),null}}function x0(){let $=[];for(let Q of b0()){let Z=sQ(Q);if(Z)$.push(Z)}return $}function _Y($){T4(),J6(V0($.device),JSON.stringify($,null,2)),V$("wrote state pid=%d device=%s port=%d",$.pid,$.device,$.port)}function c$($){if($){V$("clearState device=%s",$);try{g$(V0($))}catch{}}else{V$("clearState (all)");for(let Q of b0())try{g$(Q)}catch{}}}function Y6(){try{let $=J$("xcrun simctl list devices -j",{encoding:"utf-8"}),Q=JSON.parse($),Z=Object.keys(Q.devices).filter((J)=>/SimRuntime\.iOS-/i.test(J)).sort((J,Y)=>{let X=(J.match(/iOS-(\d+)-(\d+)/)??[]).slice(1).map(Number),G=(Y.match(/iOS-(\d+)-(\d+)/)??[]).slice(1).map(Number);return(G[0]??0)-(X[0]??0)||(G[1]??0)-(X[1]??0)});for(let J of Z){let X=(Q.devices[J]??[]).find((G)=>G.isAvailable!==!1&&/^iPhone\b/i.test(G.name));if(X)return{udid:X.udid,name:X.name}}}catch{}return null}function B4($){return j4().get($)??null}function j4(){let $=new Map;try{let Q=J$("xcrun simctl list devices -j",{encoding:"utf-8"}),Z=JSON.parse(Q);for(let J of Object.values(Z.devices))for(let Y of J)$.set(Y.udid,Y.name)}catch{}return $}function O4($){try{let Q=J$("xcrun simctl list devices -j",{encoding:"utf-8"}),Z=JSON.parse(Q);for(let J of Object.values(Z.devices))for(let Y of J)if(Y.udid===$)return Y.state==="Booted"}catch{}return!1}function eQ($){try{return process.kill($,0),!0}catch{return!1}}function E4($){try{process.kill($,"SIGTERM")}catch{return}let Q=Date.now()+500;while(Date.now()<Q)try{process.kill($,0),I$(25)}catch{return}try{process.kill($,"SIGKILL")}catch{}let Z=Date.now()+500;while(Date.now()<Z)try{process.kill($,0),I$(25)}catch{return}}function NY($){if(!O4($))try{J$(`xcrun simctl boot ${$}`,{encoding:"utf-8",stdio:"pipe"})}catch(Q){let Z=(Q.stderr??Q.message??"").toLowerCase();if(!Z.includes("booted")&&!Z.includes("current state"))throw Error(`Failed to boot device ${$}: ${Q.stderr||Q.message}`)}try{J$("open -ga Simulator",{encoding:"utf-8",stdio:"pipe",timeout:3000})}catch{}}function BY(){let $=RY();for(let Q of Object.values($))for(let Z of Q??[])if(Z.family==="IPv4"&&!Z.internal)return Z.address;return null}async function q4($){let Q=new Set(x0().map((Z)=>Z.port));for(let Z=$;Z<$+100;Z++){if(Q.has(Z))continue;if(await m6(Z))return Z}throw Error(`No available port found in range ${$}-${$+99}`)}async function FY($){NY($);try{VY("xcrun",s0($),{encoding:"utf-8",stdio:"pipe",timeout:60000})}catch(Q){if(!O4($))console.error(`Device ${$} failed to reach booted state: ${Q.stderr||Q.message}`),process.exit(1)}}function TY($){if(process.argv[0]&&/(^|\/)serve-sim$/.test(process.argv[0]))return{command:process.argv[0],args:$};return{command:process.argv[0],args:[process.argv[1],...$]}}async function jY($,Q=150000){let Z=Date.now();while(Date.now()-Z<Q){let J=r($);if(J)return J;await new Promise((Y)=>setTimeout(Y,200))}return null}async function A4($,Q,Z){i8("startHelper udid=%s port=%d detach=%s",$,Q,Z.detach);let J="127.0.0.1";T4(),c$($),p6(Q);let Y=M$(W$,`server-${$}.log`),X=Q6(Y,"w"),{command:G,args:V}=TY([$,"--port",String(Q),"--host",J]),W=F4(G,V,{detached:Z.detach,stdio:["ignore",X,X]});if(Z6(X),Z.detach)W.unref();let z=await jY($);if(!z){if(W.pid)E4(W.pid);let K="";try{K=m$(Y,"utf-8").trim()}catch{}console.error(K?`Preview server failed:
150
150
  ${K}`:"Preview server failed to start"),process.exit(1)}return Z.detach?{pid:z.pid}:{pid:z.pid,child:W}}async function OY($,Q,Z){n8("follow devices=%o startPort=%d",$,Q);let J=$.length>0?$.map(o):(()=>{let z=Q$();if(z)return[z];let K=Y6();if(!K)console.error("No device specified and no available iOS simulator found."),process.exit(1);if(!Z)console.log(`No booted simulator — booting ${K.name}...`);return[K.udid]})(),Y=new Map,X=[],G=Q;for(let z of J){let K=r(z);if(K){if(!Z){let T=B4(z)??z;if(J.length>1)console.log(`
151
151
  ==> ${T} (${z}) <==`);console.log(` Already running on port ${K.port}`),console.log(` Stream: ${K.streamUrl}`),console.log(` WebSocket: ${K.wsUrl}`)}X.push(K);continue}G=await q4(G);let{child:R}=await A4(z,G,{detach:!1});if(R)Y.set(z,R);let H=r(z)??i$(z,G,"/","127.0.0.1");if(X.push(H),!Z){let T=B4(z)??z;if(J.length>1)console.log(`
152
152
  ==> ${T} (${z}) <==`);console.log(` Stream: ${H.streamUrl}`),console.log(` WebSocket: ${H.wsUrl}`),console.log(` Port: ${G}`)}G++}if(X.length===1){let z=X[0];console.log(JSON.stringify({url:z.url,streamUrl:z.streamUrl,wsUrl:z.wsUrl,port:z.port,device:z.device}))}else console.log(JSON.stringify({devices:X.map((z)=>({url:z.url,streamUrl:z.streamUrl,wsUrl:z.wsUrl,port:z.port,device:z.device}))}));if(Y.size===0)return;let V=!1,W=(z)=>{if(V)return;if(V=!0,!Z)console.log(`
@@ -202,5 +202,5 @@ Examples:
202
202
  serve-sim --list Show all running streams
203
203
  serve-sim --kill Stop all streams`).action(async($,Q)=>{if(Q.list!==void 0){AY(typeof Q.list==="string"?Q.list:void 0);return}if(Q.kill!==void 0){DY(typeof Q.kill==="string"?Q.kill:void 0);return}let Z=Q.port;if(Q.detach){let J=await EY($,Z??3100);qY(J)}else if(Q.preview===!1)await OY($,Z??3100,!!Q.quiet);else{let J=Q.panes!==void 0||Q.fit?{...Q.panes!==void 0?{panes:Q.panes}:{},...Q.fit?{fit:!0}:{}}:void 0;await oY(Z??3200,$,Z!==void 0,Q.host,Q.codec,J,Q.theme)}});var P$=["-d, --device <udid>","Target a specific simulator (udid or name)"];Y$.command("gesture").description("Send a touch gesture").argument("<json>",`Gesture JSON, e.g. '{"type":"begin","x":0.5,"y":0.5}'`).option(...P$).action(($,Q)=>xY($,Q.device));Y$.command("tap").description("Tap at normalized 0..1 coords").argument("<x>","X coord, normalized 0..1").argument("<y>","Y coord, normalized 0..1").option(...P$).action(($,Q,Z)=>wY($,Q,Z.device));Y$.command("button").description("Send a hardware button press").argument("[name]","Button name","home").option(...P$).action(($,Q)=>fY($,Q.device));Y$.command("type").description("Type text (US keyboard only)").argument("[text...]","Text to type").option(...P$).option("--stdin","Read text from stdin").option("--file <path>","Read text from a file").action(($,Q)=>kY($,{device:Q.device,stdin:Q.stdin,file:Q.file}));Y$.command("rotate").description("Set device orientation (portrait|portrait_upside_down|landscape_left|landscape_right)").argument("<orientation>").option(...P$).action(($,Q)=>SY($,Q.device));Y$.command("ca-debug").description("Toggle a CoreAnimation debug render flag (blended|copies|misaligned|offscreen|slow-animations)").argument("<option>").argument("<state>","on|off").option(...P$).action(($,Q,Z)=>bY($,Q,Z.device));Y$.command("memory-warning").description("Simulate a memory warning on the device").option(...P$).action(($)=>vY($.device));Y$.command("event-log").description("Show recent simulator events").option(...P$).option("-j, --json","Print JSON").option("-n, --limit <count>","Maximum number of events").action(($)=>CY($.device,{json:$.json,limit:$.limit}));Y$.command("camera").description("Inject a synthetic camera feed and launch an app (see `camera --help`)").allowUnknownOption(!0).helpOption(!1).argument("[args...]").action(($)=>nY($));Y$.command("permissions").description("Manage app permissions (see `permissions` with no args for usage)").allowUnknownOption(!0).helpOption(!1).argument("[args...]").action(($)=>e6($));Y$.command("ui").description("Get or set simulator-wide UI options (see `ui --help`)").allowUnknownOption(!0).helpOption(!1).argument("[args...]").action(($)=>G7($));await Y$.parseAsync(process.argv);
204
204
 
205
- //# debugId=7B79CB4FDEDE753464756E2164756E21
205
+ //# debugId=4B851EADC630E3CD64756E2164756E21
206
206
  //# sourceMappingURL=serve-sim.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "serve-sim",
3
- "version": "0.1.46",
3
+ "version": "0.1.47-beta.119.1",
4
4
  "type": "module",
5
5
  "author": {
6
6
  "name": "Evan Bacon",