@appium/coresim 1.0.0

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.
Files changed (138) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +66 -0
  3. package/binding.gyp +53 -0
  4. package/lib/src/commands/app.d.ts +88 -0
  5. package/lib/src/commands/app.d.ts.map +1 -0
  6. package/lib/src/commands/app.js +133 -0
  7. package/lib/src/commands/app.js.map +1 -0
  8. package/lib/src/commands/biometric.d.ts +33 -0
  9. package/lib/src/commands/biometric.d.ts.map +1 -0
  10. package/lib/src/commands/biometric.js +44 -0
  11. package/lib/src/commands/biometric.js.map +1 -0
  12. package/lib/src/commands/darwin-notification.d.ts +36 -0
  13. package/lib/src/commands/darwin-notification.d.ts.map +1 -0
  14. package/lib/src/commands/darwin-notification.js +35 -0
  15. package/lib/src/commands/darwin-notification.js.map +1 -0
  16. package/lib/src/commands/interaction.d.ts +48 -0
  17. package/lib/src/commands/interaction.d.ts.map +1 -0
  18. package/lib/src/commands/interaction.js +48 -0
  19. package/lib/src/commands/interaction.js.map +1 -0
  20. package/lib/src/commands/keychain.d.ts +25 -0
  21. package/lib/src/commands/keychain.d.ts.map +1 -0
  22. package/lib/src/commands/keychain.js +52 -0
  23. package/lib/src/commands/keychain.js.map +1 -0
  24. package/lib/src/commands/lifecycle.d.ts +101 -0
  25. package/lib/src/commands/lifecycle.d.ts.map +1 -0
  26. package/lib/src/commands/lifecycle.js +165 -0
  27. package/lib/src/commands/lifecycle.js.map +1 -0
  28. package/lib/src/commands/media.d.ts +28 -0
  29. package/lib/src/commands/media.d.ts.map +1 -0
  30. package/lib/src/commands/media.js +27 -0
  31. package/lib/src/commands/media.js.map +1 -0
  32. package/lib/src/commands/misc.d.ts +15 -0
  33. package/lib/src/commands/misc.d.ts.map +1 -0
  34. package/lib/src/commands/misc.js +12 -0
  35. package/lib/src/commands/misc.js.map +1 -0
  36. package/lib/src/commands/pasteboard.d.ts +24 -0
  37. package/lib/src/commands/pasteboard.d.ts.map +1 -0
  38. package/lib/src/commands/pasteboard.js +22 -0
  39. package/lib/src/commands/pasteboard.js.map +1 -0
  40. package/lib/src/commands/permissions.d.ts +48 -0
  41. package/lib/src/commands/permissions.d.ts.map +1 -0
  42. package/lib/src/commands/permissions.js +84 -0
  43. package/lib/src/commands/permissions.js.map +1 -0
  44. package/lib/src/commands/process.d.ts +16 -0
  45. package/lib/src/commands/process.d.ts.map +1 -0
  46. package/lib/src/commands/process.js +68 -0
  47. package/lib/src/commands/process.js.map +1 -0
  48. package/lib/src/commands/screenshot.d.ts +29 -0
  49. package/lib/src/commands/screenshot.d.ts.map +1 -0
  50. package/lib/src/commands/screenshot.js +30 -0
  51. package/lib/src/commands/screenshot.js.map +1 -0
  52. package/lib/src/commands/spawn.d.ts +48 -0
  53. package/lib/src/commands/spawn.d.ts.map +1 -0
  54. package/lib/src/commands/spawn.js +108 -0
  55. package/lib/src/commands/spawn.js.map +1 -0
  56. package/lib/src/commands/ui.d.ts +42 -0
  57. package/lib/src/commands/ui.d.ts.map +1 -0
  58. package/lib/src/commands/ui.js +44 -0
  59. package/lib/src/commands/ui.js.map +1 -0
  60. package/lib/src/commands/webinspector.d.ts +19 -0
  61. package/lib/src/commands/webinspector.d.ts.map +1 -0
  62. package/lib/src/commands/webinspector.js +16 -0
  63. package/lib/src/commands/webinspector.js.map +1 -0
  64. package/lib/src/errors.d.ts +51 -0
  65. package/lib/src/errors.d.ts.map +1 -0
  66. package/lib/src/errors.js +82 -0
  67. package/lib/src/errors.js.map +1 -0
  68. package/lib/src/index.d.ts +7 -0
  69. package/lib/src/index.d.ts.map +1 -0
  70. package/lib/src/index.js +5 -0
  71. package/lib/src/index.js.map +1 -0
  72. package/lib/src/native-simctl.d.ts +62 -0
  73. package/lib/src/native-simctl.d.ts.map +1 -0
  74. package/lib/src/native-simctl.js +221 -0
  75. package/lib/src/native-simctl.js.map +1 -0
  76. package/lib/src/types.d.ts +267 -0
  77. package/lib/src/types.d.ts.map +1 -0
  78. package/lib/src/types.js +29 -0
  79. package/lib/src/types.js.map +1 -0
  80. package/lib/src/utils/index.d.ts +3 -0
  81. package/lib/src/utils/index.d.ts.map +1 -0
  82. package/lib/src/utils/index.js +3 -0
  83. package/lib/src/utils/index.js.map +1 -0
  84. package/lib/src/utils/pkg-root.d.ts +6 -0
  85. package/lib/src/utils/pkg-root.d.ts.map +1 -0
  86. package/lib/src/utils/pkg-root.js +12 -0
  87. package/lib/src/utils/pkg-root.js.map +1 -0
  88. package/lib/src/utils/run-catching.d.ts +3 -0
  89. package/lib/src/utils/run-catching.d.ts.map +1 -0
  90. package/lib/src/utils/run-catching.js +11 -0
  91. package/lib/src/utils/run-catching.js.map +1 -0
  92. package/package.json +73 -0
  93. package/scripts/install.mjs +22 -0
  94. package/src/commands/app.ts +186 -0
  95. package/src/commands/biometric.ts +69 -0
  96. package/src/commands/darwin-notification.ts +51 -0
  97. package/src/commands/interaction.ts +74 -0
  98. package/src/commands/keychain.ts +63 -0
  99. package/src/commands/lifecycle.ts +210 -0
  100. package/src/commands/media.ts +38 -0
  101. package/src/commands/misc.ts +20 -0
  102. package/src/commands/pasteboard.ts +31 -0
  103. package/src/commands/permissions.ts +122 -0
  104. package/src/commands/process.ts +80 -0
  105. package/src/commands/screenshot.ts +46 -0
  106. package/src/commands/spawn.ts +133 -0
  107. package/src/commands/ui.ts +61 -0
  108. package/src/commands/webinspector.ts +23 -0
  109. package/src/coresim.mm +1066 -0
  110. package/src/errors.ts +93 -0
  111. package/src/index.ts +23 -0
  112. package/src/native/async_bridge.h +164 -0
  113. package/src/native/nserror_bridge.h +64 -0
  114. package/src/native/nserror_bridge.mm +30 -0
  115. package/src/native/objc_runtime.h +45 -0
  116. package/src/native/objc_runtime.mm +76 -0
  117. package/src/native/safe_dispatch.h +38 -0
  118. package/src/native/sim_device.h +143 -0
  119. package/src/native/sim_device.mm +355 -0
  120. package/src/native/sim_device_set.h +16 -0
  121. package/src/native/sim_device_set.mm +40 -0
  122. package/src/native/sim_pasteboard.h +16 -0
  123. package/src/native/sim_pasteboard.mm +295 -0
  124. package/src/native/sim_process.h +13 -0
  125. package/src/native/sim_process.mm +139 -0
  126. package/src/native/sim_screenshot.h +28 -0
  127. package/src/native/sim_screenshot.mm +226 -0
  128. package/src/native/sim_service_context.h +42 -0
  129. package/src/native/sim_service_context.mm +92 -0
  130. package/src/native/tcc_privacy.h +35 -0
  131. package/src/native/tcc_privacy.mm +256 -0
  132. package/src/native/value_bridge.h +18 -0
  133. package/src/native/value_bridge.mm +111 -0
  134. package/src/native-simctl.ts +288 -0
  135. package/src/types.ts +302 -0
  136. package/src/utils/index.ts +2 -0
  137. package/src/utils/pkg-root.ts +14 -0
  138. package/src/utils/run-catching.ts +10 -0
@@ -0,0 +1,15 @@
1
+ import type { NativeSimctl } from '../native-simctl.js';
2
+ declare module '../native-simctl.js' {
3
+ interface NativeSimctl {
4
+ shake(udid: string): Promise<void>;
5
+ }
6
+ }
7
+ /**
8
+ * Simulates a shake gesture (e.g. to trigger "Shake to Undo" or a shake-triggered debug menu) —
9
+ * the same Darwin notification (see darwin-notification.ts) Simulator.app's own Device > Shake
10
+ * menu item posts.
11
+ *
12
+ * @param udid — UDID of the target device
13
+ */
14
+ export declare function shake(this: NativeSimctl, udid: string): Promise<void>;
15
+ //# sourceMappingURL=misc.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"misc.d.ts","sourceRoot":"","sources":["../../../src/commands/misc.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,qBAAqB,CAAC;AAEtD,OAAO,QAAQ,qBAAqB,CAAC;IACnC,UAAU,YAAY;QACpB,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;KACpC;CACF;AAID;;;;;;GAMG;AACH,wBAAsB,KAAK,CAAC,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAE3E"}
@@ -0,0 +1,12 @@
1
+ const SHAKE_NOTIFICATION_NAME = 'com.apple.UIKit.SimulatorShake';
2
+ /**
3
+ * Simulates a shake gesture (e.g. to trigger "Shake to Undo" or a shake-triggered debug menu) —
4
+ * the same Darwin notification (see darwin-notification.ts) Simulator.app's own Device > Shake
5
+ * menu item posts.
6
+ *
7
+ * @param udid — UDID of the target device
8
+ */
9
+ export async function shake(udid) {
10
+ await this.postDarwinNotification(udid, SHAKE_NOTIFICATION_NAME);
11
+ }
12
+ //# sourceMappingURL=misc.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"misc.js","sourceRoot":"","sources":["../../../src/commands/misc.ts"],"names":[],"mappings":"AAQA,MAAM,uBAAuB,GAAG,gCAAgC,CAAC;AAEjE;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,KAAK,CAAqB,IAAY;IAC1D,MAAM,IAAI,CAAC,sBAAsB,CAAC,IAAI,EAAE,uBAAuB,CAAC,CAAC;AACnE,CAAC"}
@@ -0,0 +1,24 @@
1
+ import type { NativeSimctl } from '../native-simctl.js';
2
+ declare module '../native-simctl.js' {
3
+ interface NativeSimctl {
4
+ getPasteboard(udid: string): Promise<string>;
5
+ setPasteboard(udid: string, content: string): Promise<void>;
6
+ }
7
+ }
8
+ /**
9
+ * Reads the device's current pasteboard content — the native equivalent of `simctl pbpaste`
10
+ * (see native/sim_pasteboard.mm for which private CoreSimulator API this uses). Rejects with
11
+ * `NativeSimUnavailableError` if neither is present.
12
+ *
13
+ * @param udid — UDID of the device to read from; must be booted
14
+ * @returns the pasteboard's string content, or `""` if it holds no string-typed content
15
+ */
16
+ export declare function getPasteboard(this: NativeSimctl, udid: string): Promise<string>;
17
+ /**
18
+ * Sets the device's pasteboard content — the native equivalent of `simctl pbcopy`.
19
+ *
20
+ * @param udid — UDID of the target device; must be booted
21
+ * @param content — string content to set
22
+ */
23
+ export declare function setPasteboard(this: NativeSimctl, udid: string, content: string): Promise<void>;
24
+ //# sourceMappingURL=pasteboard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pasteboard.d.ts","sourceRoot":"","sources":["../../../src/commands/pasteboard.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,qBAAqB,CAAC;AAGtD,OAAO,QAAQ,qBAAqB,CAAC;IACnC,UAAU,YAAY;QACpB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;QAC7C,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;KAC7D;CACF;AAED;;;;;;;GAOG;AACH,wBAAsB,aAAa,CAAC,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAErF;AAED;;;;;GAKG;AACH,wBAAsB,aAAa,CAAC,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAEpG"}
@@ -0,0 +1,22 @@
1
+ import { runCatchingAsync } from '../utils/index.js';
2
+ /**
3
+ * Reads the device's current pasteboard content — the native equivalent of `simctl pbpaste`
4
+ * (see native/sim_pasteboard.mm for which private CoreSimulator API this uses). Rejects with
5
+ * `NativeSimUnavailableError` if neither is present.
6
+ *
7
+ * @param udid — UDID of the device to read from; must be booted
8
+ * @returns the pasteboard's string content, or `""` if it holds no string-typed content
9
+ */
10
+ export async function getPasteboard(udid) {
11
+ return runCatchingAsync(async () => (await this._findDevice(udid)).getPasteboard());
12
+ }
13
+ /**
14
+ * Sets the device's pasteboard content — the native equivalent of `simctl pbcopy`.
15
+ *
16
+ * @param udid — UDID of the target device; must be booted
17
+ * @param content — string content to set
18
+ */
19
+ export async function setPasteboard(udid, content) {
20
+ return runCatchingAsync(async () => (await this._findDevice(udid)).setPasteboard(content));
21
+ }
22
+ //# sourceMappingURL=pasteboard.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pasteboard.js","sourceRoot":"","sources":["../../../src/commands/pasteboard.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,gBAAgB,EAAC,MAAM,mBAAmB,CAAC;AASnD;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAqB,IAAY;IAClE,OAAO,gBAAgB,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,MAAM,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,aAAa,EAAE,CAAC,CAAC;AACtF,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAqB,IAAY,EAAE,OAAe;IACnF,OAAO,gBAAgB,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,MAAM,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,CAAC;AAC7F,CAAC"}
@@ -0,0 +1,48 @@
1
+ import type { NativeSimctl } from '../native-simctl.js';
2
+ import type { SimPermissionService, SimPermissionStatus } from '../types.js';
3
+ declare module '../native-simctl.js' {
4
+ interface NativeSimctl {
5
+ grantPermission(udid: string, service: SimPermissionService, bundleId: string): Promise<void>;
6
+ revokePermission(udid: string, service: SimPermissionService, bundleId: string): Promise<void>;
7
+ resetPermission(udid: string, service: SimPermissionService, bundleId: string): Promise<void>;
8
+ getPermission(udid: string, service: SimPermissionService, bundleId: string): Promise<SimPermissionStatus>;
9
+ }
10
+ }
11
+ /**
12
+ * Grants a privacy permission to the given app on the given device, by writing directly to the
13
+ * simulator's own TCC (privacy) database — see CLAUDE.md for why this bypasses CoreSimulator's own
14
+ * privacy API.
15
+ *
16
+ * @param udid — UDID of the target device
17
+ * @param service — permission to grant, e.g. `"camera"`, `"contacts"`, `"photos"`
18
+ * @param bundleId — bundle identifier of the app the permission applies to
19
+ */
20
+ export declare function grantPermission(this: NativeSimctl, udid: string, service: SimPermissionService, bundleId: string): Promise<void>;
21
+ /**
22
+ * Revokes a previously granted privacy permission from the given app.
23
+ *
24
+ * @param udid — UDID of the target device
25
+ * @param service — permission to revoke (see {@link grantPermission})
26
+ * @param bundleId — bundle identifier of the app the permission applies to
27
+ */
28
+ export declare function revokePermission(this: NativeSimctl, udid: string, service: SimPermissionService, bundleId: string): Promise<void>;
29
+ /**
30
+ * Resets a privacy permission for the given app to its default (unprompted) state.
31
+ *
32
+ * @param udid — UDID of the target device
33
+ * @param service — permission to reset (see {@link grantPermission})
34
+ * @param bundleId — bundle identifier of the app the permission applies to
35
+ */
36
+ export declare function resetPermission(this: NativeSimctl, udid: string, service: SimPermissionService, bundleId: string): Promise<void>;
37
+ /**
38
+ * Reads a privacy permission's current status directly from the simulator's own TCC database —
39
+ * there's no CoreSimulator getter for this, only the setters {@link grantPermission}/
40
+ * {@link revokePermission}/{@link resetPermission} write to (see CLAUDE.md).
41
+ *
42
+ * @param udid — UDID of the device to read from
43
+ * @param service — permission to check (see {@link grantPermission})
44
+ * @param bundleId — bundle identifier of the app the permission applies to
45
+ * @returns `'unset'` if the app has never been prompted/decided for this permission
46
+ */
47
+ export declare function getPermission(this: NativeSimctl, udid: string, service: SimPermissionService, bundleId: string): Promise<SimPermissionStatus>;
48
+ //# sourceMappingURL=permissions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"permissions.d.ts","sourceRoot":"","sources":["../../../src/commands/permissions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,qBAAqB,CAAC;AACtD,OAAO,KAAK,EAAC,oBAAoB,EAAE,mBAAmB,EAAC,MAAM,aAAa,CAAC;AAG3E,OAAO,QAAQ,qBAAqB,CAAC;IACnC,UAAU,YAAY;QACpB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,oBAAoB,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;QAC9F,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,oBAAoB,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;QAC/F,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,oBAAoB,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;QAC9F,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,oBAAoB,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAAC;KAC5G;CACF;AAED;;;;;;;;GAQG;AACH,wBAAsB,eAAe,CACnC,IAAI,EAAE,YAAY,EAClB,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,oBAAoB,EAC7B,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,IAAI,CAAC,CAKf;AAED;;;;;;GAMG;AACH,wBAAsB,gBAAgB,CACpC,IAAI,EAAE,YAAY,EAClB,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,oBAAoB,EAC7B,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,IAAI,CAAC,CAKf;AAED;;;;;;GAMG;AACH,wBAAsB,eAAe,CACnC,IAAI,EAAE,YAAY,EAClB,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,oBAAoB,EAC7B,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,IAAI,CAAC,CAKf;AAED;;;;;;;;;GASG;AACH,wBAAsB,aAAa,CACjC,IAAI,EAAE,YAAY,EAClB,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,oBAAoB,EAC7B,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,mBAAmB,CAAC,CAK9B"}
@@ -0,0 +1,84 @@
1
+ import { runCatchingAsync } from '../utils/index.js';
2
+ /**
3
+ * Grants a privacy permission to the given app on the given device, by writing directly to the
4
+ * simulator's own TCC (privacy) database — see CLAUDE.md for why this bypasses CoreSimulator's own
5
+ * privacy API.
6
+ *
7
+ * @param udid — UDID of the target device
8
+ * @param service — permission to grant, e.g. `"camera"`, `"contacts"`, `"photos"`
9
+ * @param bundleId — bundle identifier of the app the permission applies to
10
+ */
11
+ export async function grantPermission(udid, service, bundleId) {
12
+ return runCatchingAsync(async () => {
13
+ const tccIdentifier = toTCCIdentifier(service);
14
+ return (await this._findDevice(udid)).grantPermission(tccIdentifier, bundleId);
15
+ });
16
+ }
17
+ /**
18
+ * Revokes a previously granted privacy permission from the given app.
19
+ *
20
+ * @param udid — UDID of the target device
21
+ * @param service — permission to revoke (see {@link grantPermission})
22
+ * @param bundleId — bundle identifier of the app the permission applies to
23
+ */
24
+ export async function revokePermission(udid, service, bundleId) {
25
+ return runCatchingAsync(async () => {
26
+ const tccIdentifier = toTCCIdentifier(service);
27
+ return (await this._findDevice(udid)).revokePermission(tccIdentifier, bundleId);
28
+ });
29
+ }
30
+ /**
31
+ * Resets a privacy permission for the given app to its default (unprompted) state.
32
+ *
33
+ * @param udid — UDID of the target device
34
+ * @param service — permission to reset (see {@link grantPermission})
35
+ * @param bundleId — bundle identifier of the app the permission applies to
36
+ */
37
+ export async function resetPermission(udid, service, bundleId) {
38
+ return runCatchingAsync(async () => {
39
+ const tccIdentifier = toTCCIdentifier(service);
40
+ return (await this._findDevice(udid)).resetPermission(tccIdentifier, bundleId);
41
+ });
42
+ }
43
+ /**
44
+ * Reads a privacy permission's current status directly from the simulator's own TCC database —
45
+ * there's no CoreSimulator getter for this, only the setters {@link grantPermission}/
46
+ * {@link revokePermission}/{@link resetPermission} write to (see CLAUDE.md).
47
+ *
48
+ * @param udid — UDID of the device to read from
49
+ * @param service — permission to check (see {@link grantPermission})
50
+ * @param bundleId — bundle identifier of the app the permission applies to
51
+ * @returns `'unset'` if the app has never been prompted/decided for this permission
52
+ */
53
+ export async function getPermission(udid, service, bundleId) {
54
+ return runCatchingAsync(async () => {
55
+ const tccIdentifier = toTCCIdentifier(service);
56
+ return (await this._findDevice(udid)).getPermission(tccIdentifier, bundleId);
57
+ });
58
+ }
59
+ // Maps a friendly service name to the internal TCC service identifier its row in the simulator's
60
+ // own TCC.db is keyed on (see native/tcc_privacy.h). `location` is deliberately absent: it isn't a
61
+ // plain TCC row (CoreLocation simulation has its own subsystem), so it isn't supported by this
62
+ // TCC.db-based implementation.
63
+ const SERVICE_TO_TCC_IDENTIFIER = {
64
+ calendar: 'kTCCServiceCalendar',
65
+ camera: 'kTCCServiceCamera',
66
+ contacts: 'kTCCServiceAddressBook',
67
+ health: 'kTCCServiceMSO',
68
+ homekit: 'kTCCServiceWillow',
69
+ medialibrary: 'kTCCServiceMediaLibrary',
70
+ microphone: 'kTCCServiceMicrophone',
71
+ motion: 'kTCCServiceMotion',
72
+ photos: 'kTCCServicePhotos',
73
+ reminders: 'kTCCServiceReminders',
74
+ siri: 'kTCCServiceSiri',
75
+ speech: 'kTCCServiceSpeechRecognition',
76
+ };
77
+ function toTCCIdentifier(service) {
78
+ const identifier = SERVICE_TO_TCC_IDENTIFIER[service];
79
+ if (!identifier) {
80
+ throw new Error(`'${service}' is not a supported permission. Supported: ${Object.keys(SERVICE_TO_TCC_IDENTIFIER).join(', ')}`);
81
+ }
82
+ return identifier;
83
+ }
84
+ //# sourceMappingURL=permissions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"permissions.js","sourceRoot":"","sources":["../../../src/commands/permissions.ts"],"names":[],"mappings":"AAEA,OAAO,EAAC,gBAAgB,EAAC,MAAM,mBAAmB,CAAC;AAWnD;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CAEnC,IAAY,EACZ,OAA6B,EAC7B,QAAgB;IAEhB,OAAO,gBAAgB,CAAC,KAAK,IAAI,EAAE;QACjC,MAAM,aAAa,GAAG,eAAe,CAAC,OAAO,CAAC,CAAC;QAC/C,OAAO,CAAC,MAAM,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,eAAe,CAAC,aAAa,EAAE,QAAQ,CAAC,CAAC;IACjF,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAEpC,IAAY,EACZ,OAA6B,EAC7B,QAAgB;IAEhB,OAAO,gBAAgB,CAAC,KAAK,IAAI,EAAE;QACjC,MAAM,aAAa,GAAG,eAAe,CAAC,OAAO,CAAC,CAAC;QAC/C,OAAO,CAAC,MAAM,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,gBAAgB,CAAC,aAAa,EAAE,QAAQ,CAAC,CAAC;IAClF,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CAEnC,IAAY,EACZ,OAA6B,EAC7B,QAAgB;IAEhB,OAAO,gBAAgB,CAAC,KAAK,IAAI,EAAE;QACjC,MAAM,aAAa,GAAG,eAAe,CAAC,OAAO,CAAC,CAAC;QAC/C,OAAO,CAAC,MAAM,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,eAAe,CAAC,aAAa,EAAE,QAAQ,CAAC,CAAC;IACjF,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAEjC,IAAY,EACZ,OAA6B,EAC7B,QAAgB;IAEhB,OAAO,gBAAgB,CAAC,KAAK,IAAI,EAAE;QACjC,MAAM,aAAa,GAAG,eAAe,CAAC,OAAO,CAAC,CAAC;QAC/C,OAAO,CAAC,MAAM,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,aAAa,CAAC,aAAa,EAAE,QAAQ,CAAC,CAAC;IAC/E,CAAC,CAAC,CAAC;AACL,CAAC;AAED,iGAAiG;AACjG,mGAAmG;AACnG,+FAA+F;AAC/F,+BAA+B;AAC/B,MAAM,yBAAyB,GAAyC;IACtE,QAAQ,EAAE,qBAAqB;IAC/B,MAAM,EAAE,mBAAmB;IAC3B,QAAQ,EAAE,wBAAwB;IAClC,MAAM,EAAE,gBAAgB;IACxB,OAAO,EAAE,mBAAmB;IAC5B,YAAY,EAAE,yBAAyB;IACvC,UAAU,EAAE,uBAAuB;IACnC,MAAM,EAAE,mBAAmB;IAC3B,MAAM,EAAE,mBAAmB;IAC3B,SAAS,EAAE,sBAAsB;IACjC,IAAI,EAAE,iBAAiB;IACvB,MAAM,EAAE,8BAA8B;CACvC,CAAC;AAEF,SAAS,eAAe,CAAC,OAA6B;IACpD,MAAM,UAAU,GAAG,yBAAyB,CAAC,OAAO,CAAC,CAAC;IACtD,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,MAAM,IAAI,KAAK,CACb,IAAI,OAAO,+CAA+C,MAAM,CAAC,IAAI,CAAC,yBAAyB,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAC9G,CAAC;IACJ,CAAC;IACD,OAAO,UAAU,CAAC;AACpB,CAAC"}
@@ -0,0 +1,16 @@
1
+ import type { NativeSimctl } from '../native-simctl.js';
2
+ import type { SimProcessInfo } from '../types.js';
3
+ declare module '../native-simctl.js' {
4
+ interface NativeSimctl {
5
+ listProcesses(udid: string): Promise<SimProcessInfo[]>;
6
+ }
7
+ }
8
+ /**
9
+ * Lists currently-running processes/launchd jobs on the given (booted) device, by spawning
10
+ * `launchctl list` inside it and parsing its `PID / Status / Label` output. A `-` PID column
11
+ * (registered but not running) is dropped; an app process's `name` is its bundle identifier.
12
+ *
13
+ * @param udid — UDID of the device to inspect; must be booted
14
+ */
15
+ export declare function listProcesses(this: NativeSimctl, udid: string): Promise<SimProcessInfo[]>;
16
+ //# sourceMappingURL=process.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"process.d.ts","sourceRoot":"","sources":["../../../src/commands/process.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,qBAAqB,CAAC;AACtD,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,aAAa,CAAC;AAGhD,OAAO,QAAQ,qBAAqB,CAAC;IACnC,UAAU,YAAY;QACpB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC,CAAC;KACxD;CACF;AAED;;;;;;GAMG;AACH,wBAAsB,aAAa,CAAC,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC,CA8C/F"}
@@ -0,0 +1,68 @@
1
+ import { once } from 'node:events';
2
+ import { runCatchingAsync } from '../utils/index.js';
3
+ /**
4
+ * Lists currently-running processes/launchd jobs on the given (booted) device, by spawning
5
+ * `launchctl list` inside it and parsing its `PID / Status / Label` output. A `-` PID column
6
+ * (registered but not running) is dropped; an app process's `name` is its bundle identifier.
7
+ *
8
+ * @param udid — UDID of the device to inspect; must be booted
9
+ */
10
+ export async function listProcesses(udid) {
11
+ return runCatchingAsync(async () => {
12
+ const device = await this._findDevice(udid);
13
+ // The guest runtime ships its own launchctl, distinct from the host's /bin/launchctl (see
14
+ // CLAUDE.md) — spawn() takes a literal path, so resolve it via RuntimeRoot ourselves.
15
+ const launchctlPath = `${device.runtimeRootPath()}/bin/launchctl`;
16
+ const proc = await this.spawnProcess(udid, launchctlPath, { arguments: [launchctlPath, 'list'] });
17
+ let stdout = '';
18
+ let stderr = '';
19
+ proc.stdout.on('data', (chunk) => {
20
+ stdout += chunk;
21
+ });
22
+ proc.stderr.on('data', (chunk) => {
23
+ stderr += chunk;
24
+ });
25
+ // stdout/stderr are plain net.Sockets over raw fds — an unhandled 'error' on either would
26
+ // crash the whole process, not just reject this promise, so race it in as a real rejection.
27
+ const streamError = Promise.race([once(proc.stdout, 'error'), once(proc.stderr, 'error')]).then(([err]) => {
28
+ throw err;
29
+ });
30
+ // 'exit' can fire before the stdout stream has finished delivering its buffered data (see
31
+ // spawnProcess's own integration test) — wait for both before parsing.
32
+ const [[code, signal]] = await Promise.race([
33
+ Promise.all([once(proc, 'exit'), once(proc.stdout, 'end')]),
34
+ streamError,
35
+ ]);
36
+ if (code !== 0) {
37
+ const reason = signal ? `signal ${signal}` : `exit code ${code}`;
38
+ throw new Error(`'launchctl list' failed with ${reason}${stderr.trim() ? `: ${stderr.trim()}` : ''}`);
39
+ }
40
+ const result = [];
41
+ for (const line of stdout.split('\n')) {
42
+ const trimmedLine = line.trim();
43
+ if (!trimmedLine) {
44
+ continue;
45
+ }
46
+ const [pidText, , label] = trimmedLine.split(/\s+/);
47
+ const pid = Number.parseInt(pidText, 10);
48
+ if (!pid || !label) {
49
+ continue;
50
+ }
51
+ result.push({ pid, group: extractGroup(label), name: extractName(label) });
52
+ }
53
+ return result;
54
+ });
55
+ }
56
+ function extractGroup(label) {
57
+ const colonIdx = label.indexOf(':');
58
+ return colonIdx >= 0 ? label.slice(0, colonIdx) : null;
59
+ }
60
+ function extractName(label) {
61
+ let name = label.includes(':') ? label.slice(label.indexOf(':') + 1) : label;
62
+ const bracketIdx = name.indexOf('[');
63
+ if (bracketIdx >= 0) {
64
+ name = name.slice(0, bracketIdx);
65
+ }
66
+ return name;
67
+ }
68
+ //# sourceMappingURL=process.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"process.js","sourceRoot":"","sources":["../../../src/commands/process.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ import type { NativeSimctl } from '../native-simctl.js';
2
+ import type { ScreenshotOptions, SimDisplayInfo } from '../types.js';
3
+ declare module '../native-simctl.js' {
4
+ interface NativeSimctl {
5
+ getScreenshot(udid: string, options?: ScreenshotOptions): Promise<Buffer>;
6
+ getDisplays(udid: string): Promise<SimDisplayInfo[]>;
7
+ }
8
+ }
9
+ /**
10
+ * Captures a device display as an image — the native equivalent of `simctl io <udid> screenshot`
11
+ * (see native/sim_screenshot.mm for how this reads the framebuffer directly, with no temp file or
12
+ * subprocess). Rejects if the resolved display has no renderable surface yet (e.g. not booted), or
13
+ * if `options.displayId` doesn't match any display from {@link getDisplays}.
14
+ *
15
+ * @param udid — UDID of the device to capture; must be booted
16
+ * @param options — `format` (defaults to `'png'`), `displayId` (defaults to the primary display),
17
+ * and `quality` (JPEG only, 0-100 percent)
18
+ * @returns image data encoded as `options.format`
19
+ */
20
+ export declare function getScreenshot(this: NativeSimctl, udid: string, options?: ScreenshotOptions): Promise<Buffer>;
21
+ /**
22
+ * Lists the device's renderable displays — the same information `simctl io <udid> enumerate`
23
+ * reports for its own `--display` selection. Most devices report exactly one (the primary
24
+ * display); a device with a secondary display (e.g. tvOS's TVOut) reports more than one.
25
+ *
26
+ * @param udid — UDID of the device to inspect; must be booted
27
+ */
28
+ export declare function getDisplays(this: NativeSimctl, udid: string): Promise<SimDisplayInfo[]>;
29
+ //# sourceMappingURL=screenshot.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"screenshot.d.ts","sourceRoot":"","sources":["../../../src/commands/screenshot.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,qBAAqB,CAAC;AACtD,OAAO,KAAK,EAAC,iBAAiB,EAAE,cAAc,EAAC,MAAM,aAAa,CAAC;AAGnE,OAAO,QAAQ,qBAAqB,CAAC;IACnC,UAAU,YAAY;QACpB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,iBAAiB,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;QAC1E,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC,CAAC;KACtD;CACF;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,aAAa,CACjC,IAAI,EAAE,YAAY,EAClB,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE,iBAAsB,GAC9B,OAAO,CAAC,MAAM,CAAC,CAQjB;AAED;;;;;;GAMG;AACH,wBAAsB,WAAW,CAAC,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC,CAE7F"}
@@ -0,0 +1,30 @@
1
+ import { runCatchingAsync } from '../utils/index.js';
2
+ /**
3
+ * Captures a device display as an image — the native equivalent of `simctl io <udid> screenshot`
4
+ * (see native/sim_screenshot.mm for how this reads the framebuffer directly, with no temp file or
5
+ * subprocess). Rejects if the resolved display has no renderable surface yet (e.g. not booted), or
6
+ * if `options.displayId` doesn't match any display from {@link getDisplays}.
7
+ *
8
+ * @param udid — UDID of the device to capture; must be booted
9
+ * @param options — `format` (defaults to `'png'`), `displayId` (defaults to the primary display),
10
+ * and `quality` (JPEG only, 0-100 percent)
11
+ * @returns image data encoded as `options.format`
12
+ */
13
+ export async function getScreenshot(udid, options = {}) {
14
+ if (options.quality !== undefined &&
15
+ (!Number.isFinite(options.quality) || options.quality < 0 || options.quality > 100)) {
16
+ throw new RangeError(`quality must be a number between 0 and 100, got ${options.quality}`);
17
+ }
18
+ return runCatchingAsync(async () => (await this._findDevice(udid)).screenshot(options));
19
+ }
20
+ /**
21
+ * Lists the device's renderable displays — the same information `simctl io <udid> enumerate`
22
+ * reports for its own `--display` selection. Most devices report exactly one (the primary
23
+ * display); a device with a secondary display (e.g. tvOS's TVOut) reports more than one.
24
+ *
25
+ * @param udid — UDID of the device to inspect; must be booted
26
+ */
27
+ export async function getDisplays(udid) {
28
+ return runCatchingAsync(async () => (await this._findDevice(udid)).getDisplays());
29
+ }
30
+ //# sourceMappingURL=screenshot.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"screenshot.js","sourceRoot":"","sources":["../../../src/commands/screenshot.ts"],"names":[],"mappings":"AAEA,OAAO,EAAC,gBAAgB,EAAC,MAAM,mBAAmB,CAAC;AASnD;;;;;;;;;;GAUG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAEjC,IAAY,EACZ,UAA6B,EAAE;IAE/B,IACE,OAAO,CAAC,OAAO,KAAK,SAAS;QAC7B,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,OAAO,CAAC,OAAO,GAAG,CAAC,IAAI,OAAO,CAAC,OAAO,GAAG,GAAG,CAAC,EACnF,CAAC;QACD,MAAM,IAAI,UAAU,CAAC,mDAAmD,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;IAC7F,CAAC;IACD,OAAO,gBAAgB,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,MAAM,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC;AAC1F,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAAqB,IAAY;IAChE,OAAO,gBAAgB,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,MAAM,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC;AACpF,CAAC"}
@@ -0,0 +1,48 @@
1
+ import { EventEmitter } from 'node:events';
2
+ import { Socket } from 'node:net';
3
+ import type { NativeSimctl } from '../native-simctl.js';
4
+ import type { SpawnOptions } from '../types.js';
5
+ declare module '../native-simctl.js' {
6
+ interface NativeSimctl {
7
+ spawnProcess(udid: string, path: string, options?: SpawnOptions): Promise<SpawnedProcess>;
8
+ }
9
+ }
10
+ interface SpawnedProcessEvents {
11
+ exit: [code: number | null, signal: NodeJS.Signals | null];
12
+ }
13
+ /**
14
+ * A process spawned on a simulator device via `NativeSimctl.spawnProcess`. The simulator shares
15
+ * the host kernel and filesystem, so `pid` is a real host OS process id — {@link kill} just calls
16
+ * Node's own `process.kill()`, no native call needed. `stdout`/`stderr` stream live output as the
17
+ * process runs; `'exit'` fires exactly once, with a decoded `(code, signal)` pair mirroring
18
+ * `child_process.ChildProcess`'s own semantics (exactly one of the two is non-null).
19
+ */
20
+ export declare class SpawnedProcess extends EventEmitter<SpawnedProcessEvents> {
21
+ readonly pid: number;
22
+ readonly stdout: Socket;
23
+ readonly stderr: Socket;
24
+ exitCode: number | null;
25
+ signalCode: NodeJS.Signals | null;
26
+ constructor(pid: number, stdoutFd: number, stderrFd: number);
27
+ /** Whether the process has neither exited nor been killed yet. */
28
+ get running(): boolean;
29
+ /**
30
+ * Sends a signal to the process — a thin wrapper over `process.kill()`. A no-op returning
31
+ * `false` once exit has already been observed, rather than risking `process.kill()` throwing
32
+ * `ESRCH` on an already-reaped pid or, worse, hitting an unrelated process if the pid has since
33
+ * been recycled by the OS.
34
+ */
35
+ kill(signal?: NodeJS.Signals | number): boolean;
36
+ }
37
+ /**
38
+ * Native equivalent of `simctl spawn`. Streams live stdout/stderr and eventually reports an
39
+ * exit code/signal — see {@link SpawnedProcess}.
40
+ *
41
+ * @param udid — UDID of the target device
42
+ * @param path — path to the executable to spawn; not auto-prepended to `options.arguments`
43
+ * @param options — see {@link SpawnOptions}
44
+ * @returns a handle to the spawned process
45
+ */
46
+ export declare function spawnProcess(this: NativeSimctl, udid: string, path: string, options?: SpawnOptions): Promise<SpawnedProcess>;
47
+ export {};
48
+ //# sourceMappingURL=spawn.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spawn.d.ts","sourceRoot":"","sources":["../../../src/commands/spawn.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,YAAY,EAAC,MAAM,aAAa,CAAC;AACzC,OAAO,EAAC,MAAM,EAAC,MAAM,UAAU,CAAC;AAGhC,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,qBAAqB,CAAC;AACtD,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,aAAa,CAAC;AAG9C,OAAO,QAAQ,qBAAqB,CAAC;IACnC,UAAU,YAAY;QACpB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;KAC3F;CACF;AAYD,UAAU,oBAAoB;IAC5B,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,OAAO,GAAG,IAAI,CAAC,CAAC;CAC5D;AAED;;;;;;GAMG;AACH,qBAAa,cAAe,SAAQ,YAAY,CAAC,oBAAoB,CAAC;IAOlE,QAAQ,CAAC,GAAG,EAAE,MAAM;IANtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAQ;IAC/B,UAAU,EAAE,MAAM,CAAC,OAAO,GAAG,IAAI,CAAQ;gBAG9B,GAAG,EAAE,MAAM,EACpB,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM;IAiBlB,kEAAkE;IAClE,IAAI,OAAO,IAAI,OAAO,CAErB;IAED;;;;;OAKG;IACH,IAAI,CAAC,MAAM,GAAE,MAAM,CAAC,OAAO,GAAG,MAAkB,GAAG,OAAO;CAa3D;AAED;;;;;;;;GAQG;AACH,wBAAsB,YAAY,CAChC,IAAI,EAAE,YAAY,EAClB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE,YAAiB,GACzB,OAAO,CAAC,cAAc,CAAC,CA+BzB"}
@@ -0,0 +1,108 @@
1
+ import { EventEmitter } from 'node:events';
2
+ import { Socket } from 'node:net';
3
+ import { constants as osConstants } from 'node:os';
4
+ import { runCatchingAsync } from '../utils/index.js';
5
+ // Some signal numbers have more than one name (e.g. SIGABRT/SIGIOT are both 6) — built with a
6
+ // for-of rather than Object.fromEntries so the *first* name Node lists for a number wins instead
7
+ // of whichever happens to be last, which would otherwise make an aborted process unpredictably
8
+ // report as the obscure historical alias (confirmed: this reversed Object.fromEntries reported a
9
+ // real SIGABRT as 'SIGIOT').
10
+ const SIGNAL_NAME_BY_NUMBER = {};
11
+ for (const [name, num] of Object.entries(osConstants.signals)) {
12
+ SIGNAL_NAME_BY_NUMBER[num] ??= name;
13
+ }
14
+ /**
15
+ * A process spawned on a simulator device via `NativeSimctl.spawnProcess`. The simulator shares
16
+ * the host kernel and filesystem, so `pid` is a real host OS process id — {@link kill} just calls
17
+ * Node's own `process.kill()`, no native call needed. `stdout`/`stderr` stream live output as the
18
+ * process runs; `'exit'` fires exactly once, with a decoded `(code, signal)` pair mirroring
19
+ * `child_process.ChildProcess`'s own semantics (exactly one of the two is non-null).
20
+ */
21
+ export class SpawnedProcess extends EventEmitter {
22
+ pid;
23
+ stdout;
24
+ stderr;
25
+ exitCode = null;
26
+ signalCode = null;
27
+ constructor(pid, stdoutFd, stderrFd) {
28
+ super();
29
+ this.pid = pid;
30
+ // `net.Socket` (not `fs.createReadStream`) deliberately: these fds are blocking NSPipe read
31
+ // ends, and fs's reads always run as blocking syscalls on the shared libuv threadpool (default
32
+ // size 4) regardless of the fd's actual type — a single quiet process's idle stdout+stderr
33
+ // reads permanently occupy 2 of those 4 workers until output or EOF arrives, and two quiet
34
+ // processes exhaust the pool entirely, stalling unrelated fs work *and* this addon's own
35
+ // AsyncWorkers (confirmed empirically: an unrelated fs.readFile took 8+ seconds instead of
36
+ // ~1ms while two quiet spawned processes' output was being read this way). A pipe fd is
37
+ // recognized by libuv as a named-pipe handle regardless of whether it's an anonymous pipe(2),
38
+ // so wrapping it in a Socket gets real event-driven (kqueue/epoll) I/O instead, exactly like
39
+ // Node's own child_process does for a child's stdio pipes.
40
+ this.stdout = new Socket({ fd: stdoutFd, readable: true, writable: false });
41
+ this.stderr = new Socket({ fd: stderrFd, readable: true, writable: false });
42
+ }
43
+ /** Whether the process has neither exited nor been killed yet. */
44
+ get running() {
45
+ return this.exitCode === null && this.signalCode === null;
46
+ }
47
+ /**
48
+ * Sends a signal to the process — a thin wrapper over `process.kill()`. A no-op returning
49
+ * `false` once exit has already been observed, rather than risking `process.kill()` throwing
50
+ * `ESRCH` on an already-reaped pid or, worse, hitting an unrelated process if the pid has since
51
+ * been recycled by the OS.
52
+ */
53
+ kill(signal = 'SIGTERM') {
54
+ if (!this.running) {
55
+ return false;
56
+ }
57
+ return process.kill(this.pid, signal);
58
+ }
59
+ /** @internal Invoked once by NativeSimctl when the native termination callback fires. */
60
+ _handleExit(code, signal) {
61
+ this.exitCode = code;
62
+ this.signalCode = signal === null ? null : (SIGNAL_NAME_BY_NUMBER[signal] ?? null);
63
+ this.emit('exit', this.exitCode, this.signalCode);
64
+ }
65
+ }
66
+ /**
67
+ * Native equivalent of `simctl spawn`. Streams live stdout/stderr and eventually reports an
68
+ * exit code/signal — see {@link SpawnedProcess}.
69
+ *
70
+ * @param udid — UDID of the target device
71
+ * @param path — path to the executable to spawn; not auto-prepended to `options.arguments`
72
+ * @param options — see {@link SpawnOptions}
73
+ * @returns a handle to the spawned process
74
+ */
75
+ export async function spawnProcess(udid, path, options = {}) {
76
+ return runCatchingAsync(async () => {
77
+ const device = await this._findDevice(udid);
78
+ // The native termination callback (delivered via a ThreadSafeFunction/GCD path) and
79
+ // device.spawn()'s own promise resolution (an AsyncWorker completion) are independent async
80
+ // signals with no guaranteed relative order — a process that exits almost immediately can have
81
+ // its termination callback fire before the promise below resolves and `proc` exists. Buffer the
82
+ // exit args in that case and deliver them once the handle is constructed, rather than assuming
83
+ // the callback always arrives second.
84
+ let proc;
85
+ let pendingExit;
86
+ const { pid, stdoutFd, stderrFd } = await device.spawn(path, options, (code, signal) => {
87
+ if (proc) {
88
+ proc._handleExit(code, signal);
89
+ }
90
+ else {
91
+ pendingExit = [code, signal];
92
+ }
93
+ });
94
+ proc = new SpawnedProcess(pid, stdoutFd, stderrFd);
95
+ if (pendingExit) {
96
+ // Delivering this synchronously would emit 'exit' before spawnProcess()'s own promise has
97
+ // even resolved — a caller doing `const proc = await sim.spawnProcess(...); proc.on('exit', ...)`
98
+ // would never see it, since its listener can't be attached until after that await returns.
99
+ // setImmediate defers past both promise-resolution microtasks and any synchronous listener
100
+ // setup that runs right after them, guaranteeing the listener is attached first.
101
+ const exitArgs = pendingExit;
102
+ const deliverTo = proc;
103
+ setImmediate(() => deliverTo._handleExit(...exitArgs));
104
+ }
105
+ return proc;
106
+ });
107
+ }
108
+ //# sourceMappingURL=spawn.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spawn.js","sourceRoot":"","sources":["../../../src/commands/spawn.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,42 @@
1
+ import type { NativeSimctl } from '../native-simctl.js';
2
+ declare module '../native-simctl.js' {
3
+ interface NativeSimctl {
4
+ getAppearance(udid: string): Promise<number>;
5
+ setAppearance(udid: string, style: number): Promise<void>;
6
+ getIncreaseContrast(udid: string): Promise<number>;
7
+ setIncreaseContrast(udid: string, enabled: boolean): Promise<void>;
8
+ getContentSize(udid: string): Promise<number>;
9
+ setContentSize(udid: string, category: number): Promise<void>;
10
+ }
11
+ }
12
+ /**
13
+ * @param udid — UDID of the device to read from
14
+ * @returns the device's current UI appearance style, as a raw `UIUserInterfaceStyle` value
15
+ */
16
+ export declare function getAppearance(this: NativeSimctl, udid: string): Promise<number>;
17
+ /**
18
+ * @param udid — UDID of the target device
19
+ * @param style — a raw `UIUserInterfaceStyle` value to apply
20
+ */
21
+ export declare function setAppearance(this: NativeSimctl, udid: string, style: number): Promise<void>;
22
+ /**
23
+ * @param udid — UDID of the device to read from
24
+ * @returns the device's current Increase Contrast accessibility setting
25
+ */
26
+ export declare function getIncreaseContrast(this: NativeSimctl, udid: string): Promise<number>;
27
+ /**
28
+ * @param udid — UDID of the target device
29
+ * @param enabled — whether Increase Contrast should be enabled
30
+ */
31
+ export declare function setIncreaseContrast(this: NativeSimctl, udid: string, enabled: boolean): Promise<void>;
32
+ /**
33
+ * @param udid — UDID of the device to read from
34
+ * @returns the device's current Dynamic Type content size category
35
+ */
36
+ export declare function getContentSize(this: NativeSimctl, udid: string): Promise<number>;
37
+ /**
38
+ * @param udid — UDID of the target device
39
+ * @param category — the Dynamic Type content size category to apply
40
+ */
41
+ export declare function setContentSize(this: NativeSimctl, udid: string, category: number): Promise<void>;
42
+ //# sourceMappingURL=ui.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ui.d.ts","sourceRoot":"","sources":["../../../src/commands/ui.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,qBAAqB,CAAC;AAGtD,OAAO,QAAQ,qBAAqB,CAAC;IACnC,UAAU,YAAY;QACpB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;QAC7C,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;QAC1D,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;QACnD,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;QACnE,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;QAC9C,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;KAC/D;CACF;AAED;;;GAGG;AACH,wBAAsB,aAAa,CAAC,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAErF;AAED;;;GAGG;AACH,wBAAsB,aAAa,CAAC,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAElG;AAED;;;GAGG;AACH,wBAAsB,mBAAmB,CAAC,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAE3F;AAED;;;GAGG;AACH,wBAAsB,mBAAmB,CAAC,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAE3G;AAED;;;GAGG;AACH,wBAAsB,cAAc,CAAC,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAEtF;AAED;;;GAGG;AACH,wBAAsB,cAAc,CAAC,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAEtG"}