@react-native-harness/platform-apple 1.0.0-alpha.18

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.
package/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Callstack
4
+ Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ of this software and associated documentation files (the "Software"), to deal
6
+ in the Software without restriction, including without limitation the rights
7
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ copies of the Software, and to permit persons to whom the Software is
9
+ furnished to do so, subject to the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be included in all
12
+ copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,99 @@
1
+ ![harness-banner](https://react-native-harness.dev/harness-banner.jpg)
2
+
3
+ [![mit licence][license-badge]][license]
4
+ [![npm downloads][npm-downloads-badge]][npm-downloads]
5
+ [![Chat][chat-badge]][chat]
6
+ [![PRs Welcome][prs-welcome-badge]][prs-welcome]
7
+
8
+ Apple platform for React Native Harness - enables testing on iOS simulators and physical devices.
9
+
10
+ ## Installation
11
+
12
+ ```bash
13
+ npm install @react-native-harness/platform-apple
14
+ # or
15
+ pnpm add @react-native-harness/platform-apple
16
+ # or
17
+ yarn add @react-native-harness/platform-apple
18
+ ```
19
+
20
+ ## Usage
21
+
22
+ Import the Apple platform functions in your `rn-harness.config.mjs`:
23
+
24
+ ```javascript
25
+ import {
26
+ applePlatform,
27
+ applePhysicalDevice,
28
+ appleSimulator,
29
+ } from '@react-native-harness/platform-apple';
30
+
31
+ const config = {
32
+ runners: [
33
+ applePlatform({
34
+ name: 'ios',
35
+ device: appleSimulator('iPhone 16 Pro Max', '18.0'),
36
+ bundleId: 'org.reactjs.native.example.YourApp',
37
+ }),
38
+ applePlatform({
39
+ name: 'iphone-device',
40
+ device: applePhysicalDevice('iPhone (Your Name)'),
41
+ bundleId: 'com.your.app',
42
+ }),
43
+ ],
44
+ // ... other config
45
+ };
46
+
47
+ export default config;
48
+ ```
49
+
50
+ ## API
51
+
52
+ ### `applePlatform(config)`
53
+
54
+ Creates an Apple platform runner configuration.
55
+
56
+ **Parameters:**
57
+
58
+ - `config.name` - Unique name for the runner
59
+ - `config.device` - Apple device configuration (simulator or physical)
60
+ - `config.bundleId` - iOS application bundle ID
61
+
62
+ ### `appleSimulator(deviceName, osVersion)`
63
+
64
+ Creates an iOS simulator device configuration.
65
+
66
+ **Parameters:**
67
+
68
+ - `deviceName` - Name of the iOS simulator (e.g., 'iPhone 16 Pro Max')
69
+ - `osVersion` - iOS version (e.g., '18.0')
70
+
71
+ ### `applePhysicalDevice(deviceName)`
72
+
73
+ Creates a physical Apple device configuration.
74
+
75
+ **Parameters:**
76
+
77
+ - `deviceName` - Name of the physical device (e.g., 'iPhone (Your Name)')
78
+
79
+ ## Requirements
80
+
81
+ - macOS with Xcode installed
82
+ - iOS Simulator or physical device connected
83
+ - React Native project configured for iOS
84
+
85
+ ## Made with ❤️ at Callstack
86
+
87
+ `react-native-harness` is an open source project and will always remain free to use. If you think it's cool, please star it 🌟. [Callstack][callstack-readme-with-love] is a group of React and React Native geeks, contact us at [hello@callstack.com](mailto:hello@callstack.com) if you need any help with these or just want to say hi!
88
+
89
+ Like the project? ⚛️ [Join the team](https://callstack.com/careers/?utm_campaign=Senior_RN&utm_source=github&utm_medium=readme) who does amazing stuff for clients and drives React Native Open Source! 🔥
90
+
91
+ [callstack-readme-with-love]: https://callstack.com/?utm_source=github.com&utm_medium=referral&utm_campaign=react-native-harness&utm_term=readme-with-love
92
+ [license-badge]: https://img.shields.io/npm/l/react-native-harness?style=for-the-badge
93
+ [license]: https://github.com/callstackincubator/react-native-harness/blob/main/LICENSE
94
+ [npm-downloads-badge]: https://img.shields.io/npm/dm/react-native-harness?style=for-the-badge
95
+ [npm-downloads]: https://www.npmjs.com/package/react-native-harness
96
+ [prs-welcome-badge]: https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=for-the-badge
97
+ [prs-welcome]: ./CONTRIBUTING.md
98
+ [chat-badge]: https://img.shields.io/discord/426714625279524876.svg?style=for-the-badge
99
+ [chat]: https://discord.gg/xgGt7KAjxv
@@ -0,0 +1,103 @@
1
+ import { z } from 'zod';
2
+ export declare const AppleSimulatorSchema: z.ZodObject<{
3
+ type: z.ZodLiteral<"simulator">;
4
+ name: z.ZodString;
5
+ systemVersion: z.ZodString;
6
+ }, "strip", z.ZodTypeAny, {
7
+ type: "simulator";
8
+ name: string;
9
+ systemVersion: string;
10
+ }, {
11
+ type: "simulator";
12
+ name: string;
13
+ systemVersion: string;
14
+ }>;
15
+ export declare const ApplePhysicalDeviceSchema: z.ZodObject<{
16
+ type: z.ZodLiteral<"physical">;
17
+ name: z.ZodString;
18
+ }, "strip", z.ZodTypeAny, {
19
+ type: "physical";
20
+ name: string;
21
+ }, {
22
+ type: "physical";
23
+ name: string;
24
+ }>;
25
+ export declare const AppleDeviceSchema: z.ZodDiscriminatedUnion<"type", [z.ZodObject<{
26
+ type: z.ZodLiteral<"simulator">;
27
+ name: z.ZodString;
28
+ systemVersion: z.ZodString;
29
+ }, "strip", z.ZodTypeAny, {
30
+ type: "simulator";
31
+ name: string;
32
+ systemVersion: string;
33
+ }, {
34
+ type: "simulator";
35
+ name: string;
36
+ systemVersion: string;
37
+ }>, z.ZodObject<{
38
+ type: z.ZodLiteral<"physical">;
39
+ name: z.ZodString;
40
+ }, "strip", z.ZodTypeAny, {
41
+ type: "physical";
42
+ name: string;
43
+ }, {
44
+ type: "physical";
45
+ name: string;
46
+ }>]>;
47
+ export declare const ApplePlatformConfigSchema: z.ZodObject<{
48
+ name: z.ZodString;
49
+ device: z.ZodDiscriminatedUnion<"type", [z.ZodObject<{
50
+ type: z.ZodLiteral<"simulator">;
51
+ name: z.ZodString;
52
+ systemVersion: z.ZodString;
53
+ }, "strip", z.ZodTypeAny, {
54
+ type: "simulator";
55
+ name: string;
56
+ systemVersion: string;
57
+ }, {
58
+ type: "simulator";
59
+ name: string;
60
+ systemVersion: string;
61
+ }>, z.ZodObject<{
62
+ type: z.ZodLiteral<"physical">;
63
+ name: z.ZodString;
64
+ }, "strip", z.ZodTypeAny, {
65
+ type: "physical";
66
+ name: string;
67
+ }, {
68
+ type: "physical";
69
+ name: string;
70
+ }>]>;
71
+ bundleId: z.ZodString;
72
+ }, "strip", z.ZodTypeAny, {
73
+ name: string;
74
+ device: {
75
+ type: "simulator";
76
+ name: string;
77
+ systemVersion: string;
78
+ } | {
79
+ type: "physical";
80
+ name: string;
81
+ };
82
+ bundleId: string;
83
+ }, {
84
+ name: string;
85
+ device: {
86
+ type: "simulator";
87
+ name: string;
88
+ systemVersion: string;
89
+ } | {
90
+ type: "physical";
91
+ name: string;
92
+ };
93
+ bundleId: string;
94
+ }>;
95
+ export type AppleSimulator = z.infer<typeof AppleSimulatorSchema>;
96
+ export type ApplePhysicalDevice = z.infer<typeof ApplePhysicalDeviceSchema>;
97
+ export type AppleDevice = z.infer<typeof AppleDeviceSchema>;
98
+ export type ApplePlatformConfig = z.infer<typeof ApplePlatformConfigSchema>;
99
+ export declare const isAppleDeviceSimulator: (device: AppleDevice) => device is AppleSimulator;
100
+ export declare const isAppleDevicePhysical: (device: AppleDevice) => device is ApplePhysicalDevice;
101
+ export declare function assertAppleDeviceSimulator(device: AppleDevice): asserts device is AppleSimulator;
102
+ export declare function assertAppleDevicePhysical(device: AppleDevice): asserts device is ApplePhysicalDevice;
103
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,eAAO,MAAM,oBAAoB;;;;;;;;;;;;EAI/B,CAAC;AAEH,eAAO,MAAM,yBAAyB;;;;;;;;;EAGpC,CAAC;AAEH,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;IAG5B,CAAC;AAEH,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAIpC,CAAC;AAEH,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAClE,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,yBAAyB,CAAC,CAAC;AAC5E,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAC5D,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,yBAAyB,CAAC,CAAC;AAE5E,eAAO,MAAM,sBAAsB,GACjC,QAAQ,WAAW,KAClB,MAAM,IAAI,cAEZ,CAAC;AAEF,eAAO,MAAM,qBAAqB,GAChC,QAAQ,WAAW,KAClB,MAAM,IAAI,mBAEZ,CAAC;AAEF,wBAAgB,0BAA0B,CACxC,MAAM,EAAE,WAAW,GAClB,OAAO,CAAC,MAAM,IAAI,cAAc,CAIlC;AAED,wBAAgB,yBAAyB,CACvC,MAAM,EAAE,WAAW,GAClB,OAAO,CAAC,MAAM,IAAI,mBAAmB,CAIvC"}
package/dist/config.js ADDED
@@ -0,0 +1,35 @@
1
+ import { z } from 'zod';
2
+ export const AppleSimulatorSchema = z.object({
3
+ type: z.literal('simulator'),
4
+ name: z.string().min(1, 'Name is required'),
5
+ systemVersion: z.string().min(1, 'System version is required'),
6
+ });
7
+ export const ApplePhysicalDeviceSchema = z.object({
8
+ type: z.literal('physical'),
9
+ name: z.string().min(1, 'Name is required'),
10
+ });
11
+ export const AppleDeviceSchema = z.discriminatedUnion('type', [
12
+ AppleSimulatorSchema,
13
+ ApplePhysicalDeviceSchema,
14
+ ]);
15
+ export const ApplePlatformConfigSchema = z.object({
16
+ name: z.string().min(1, 'Name is required'),
17
+ device: AppleDeviceSchema,
18
+ bundleId: z.string().min(1, 'Bundle ID is required'),
19
+ });
20
+ export const isAppleDeviceSimulator = (device) => {
21
+ return device.type === 'simulator';
22
+ };
23
+ export const isAppleDevicePhysical = (device) => {
24
+ return device.type === 'physical';
25
+ };
26
+ export function assertAppleDeviceSimulator(device) {
27
+ if (!isAppleDeviceSimulator(device)) {
28
+ throw new Error('Device is not a simulator');
29
+ }
30
+ }
31
+ export function assertAppleDevicePhysical(device) {
32
+ if (!isAppleDevicePhysical(device)) {
33
+ throw new Error('Device is not a physical device');
34
+ }
35
+ }
@@ -0,0 +1,6 @@
1
+ import { HarnessPlatform } from '@react-native-harness/platforms';
2
+ import type { AppleSimulator, ApplePhysicalDevice, ApplePlatformConfig } from './config.js';
3
+ export declare const appleSimulator: (name: string, systemVersion: string) => AppleSimulator;
4
+ export declare const applePhysicalDevice: (name: string) => ApplePhysicalDevice;
5
+ export declare const applePlatform: (config: ApplePlatformConfig) => HarnessPlatform;
6
+ //# sourceMappingURL=factory.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../src/factory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AAClE,OAAO,KAAK,EACV,cAAc,EACd,mBAAmB,EACnB,mBAAmB,EACpB,MAAM,aAAa,CAAC;AAOrB,eAAO,MAAM,cAAc,GACzB,MAAM,MAAM,EACZ,eAAe,MAAM,KACpB,cAID,CAAC;AAEH,eAAO,MAAM,mBAAmB,GAAI,MAAM,MAAM,KAAG,mBAGjD,CAAC;AAEH,eAAO,MAAM,aAAa,GACxB,QAAQ,mBAAmB,KAC1B,eAWD,CAAC"}
@@ -0,0 +1,21 @@
1
+ import { ApplePlatformConfigSchema, isAppleDeviceSimulator } from './config.js';
2
+ import { getApplePhysicalDevicePlatformInstance, getAppleSimulatorPlatformInstance, } from './instance.js';
3
+ export const appleSimulator = (name, systemVersion) => ({
4
+ type: 'simulator',
5
+ name,
6
+ systemVersion,
7
+ });
8
+ export const applePhysicalDevice = (name) => ({
9
+ type: 'physical',
10
+ name,
11
+ });
12
+ export const applePlatform = (config) => ({
13
+ name: config.name,
14
+ getInstance: async () => {
15
+ const parsedConfig = ApplePlatformConfigSchema.parse(config);
16
+ if (isAppleDeviceSimulator(parsedConfig.device)) {
17
+ return getAppleSimulatorPlatformInstance(parsedConfig);
18
+ }
19
+ return getApplePhysicalDevicePlatformInstance(parsedConfig);
20
+ },
21
+ });
@@ -0,0 +1,3 @@
1
+ export { applePlatform, appleSimulator, applePhysicalDevice, } from './factory.js';
2
+ export type { ApplePlatformConfig } from './config.js';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EACb,cAAc,EACd,mBAAmB,GACpB,MAAM,cAAc,CAAC;AACtB,YAAY,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1 @@
1
+ export { applePlatform, appleSimulator, applePhysicalDevice, } from './factory.js';
@@ -0,0 +1,5 @@
1
+ import { HarnessPlatformInstance } from '@react-native-harness/platforms';
2
+ import { ApplePlatformConfig } from './config.js';
3
+ export declare const getAppleSimulatorPlatformInstance: (config: ApplePlatformConfig) => Promise<HarnessPlatformInstance>;
4
+ export declare const getApplePhysicalDevicePlatformInstance: (config: ApplePlatformConfig) => Promise<HarnessPlatformInstance>;
5
+ //# sourceMappingURL=instance.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"instance.d.ts","sourceRoot":"","sources":["../src/instance.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,uBAAuB,EACxB,MAAM,iCAAiC,CAAC;AACzC,OAAO,EACL,mBAAmB,EAGpB,MAAM,aAAa,CAAC;AAKrB,eAAO,MAAM,iCAAiC,GAC5C,QAAQ,mBAAmB,KAC1B,OAAO,CAAC,uBAAuB,CAmDjC,CAAC;AAEF,eAAO,MAAM,sCAAsC,GACjD,QAAQ,mBAAmB,KAC1B,OAAO,CAAC,uBAAuB,CAiCjC,CAAC"}
@@ -0,0 +1,65 @@
1
+ import { AppNotInstalledError, DeviceNotFoundError, } from '@react-native-harness/platforms';
2
+ import { assertAppleDevicePhysical, assertAppleDeviceSimulator, } from './config.js';
3
+ import * as simctl from './xcrun/simctl.js';
4
+ import * as devicectl from './xcrun/devicectl.js';
5
+ import { getDeviceName } from './utils.js';
6
+ export const getAppleSimulatorPlatformInstance = async (config) => {
7
+ assertAppleDeviceSimulator(config.device);
8
+ const udid = await simctl.getSimulatorId(config.device.name, config.device.systemVersion);
9
+ if (!udid) {
10
+ throw new DeviceNotFoundError(getDeviceName(config.device));
11
+ }
12
+ const isInstalled = await simctl.isAppInstalled(udid, config.bundleId);
13
+ if (!isInstalled) {
14
+ throw new AppNotInstalledError(config.bundleId, getDeviceName(config.device));
15
+ }
16
+ const simulatorStatus = await simctl.getSimulatorStatus(udid);
17
+ if (simulatorStatus !== 'Booted') {
18
+ throw new Error('Simulator is not booted');
19
+ }
20
+ const isAvailable = await simctl.isAppInstalled(udid, config.bundleId);
21
+ if (!isAvailable) {
22
+ throw new AppNotInstalledError(config.bundleId, getDeviceName(config.device));
23
+ }
24
+ return {
25
+ startApp: async () => {
26
+ await simctl.startApp(udid, config.bundleId);
27
+ },
28
+ restartApp: async () => {
29
+ await simctl.stopApp(udid, config.bundleId);
30
+ await simctl.startApp(udid, config.bundleId);
31
+ },
32
+ stopApp: async () => {
33
+ await simctl.stopApp(udid, config.bundleId);
34
+ },
35
+ dispose: async () => {
36
+ await simctl.stopApp(udid, config.bundleId);
37
+ },
38
+ };
39
+ };
40
+ export const getApplePhysicalDevicePlatformInstance = async (config) => {
41
+ assertAppleDevicePhysical(config.device);
42
+ const deviceId = await devicectl.getDeviceId(config.device.name);
43
+ if (!deviceId) {
44
+ throw new DeviceNotFoundError(getDeviceName(config.device));
45
+ }
46
+ const isAvailable = await devicectl.isAppInstalled(deviceId, config.bundleId);
47
+ if (!isAvailable) {
48
+ throw new AppNotInstalledError(config.bundleId, getDeviceName(config.device));
49
+ }
50
+ return {
51
+ startApp: async () => {
52
+ await devicectl.startApp(deviceId, config.bundleId);
53
+ },
54
+ restartApp: async () => {
55
+ await devicectl.stopApp(deviceId, config.bundleId);
56
+ await devicectl.startApp(deviceId, config.bundleId);
57
+ },
58
+ stopApp: async () => {
59
+ await devicectl.stopApp(deviceId, config.bundleId);
60
+ },
61
+ dispose: async () => {
62
+ await devicectl.stopApp(deviceId, config.bundleId);
63
+ },
64
+ };
65
+ };
@@ -0,0 +1 @@
1
+ {"fileNames":["../../../node_modules/typescript/lib/lib.es5.d.ts","../../../node_modules/typescript/lib/lib.es2015.d.ts","../../../node_modules/typescript/lib/lib.es2016.d.ts","../../../node_modules/typescript/lib/lib.es2017.d.ts","../../../node_modules/typescript/lib/lib.es2018.d.ts","../../../node_modules/typescript/lib/lib.es2019.d.ts","../../../node_modules/typescript/lib/lib.es2020.d.ts","../../../node_modules/typescript/lib/lib.es2021.d.ts","../../../node_modules/typescript/lib/lib.es2022.d.ts","../../../node_modules/typescript/lib/lib.dom.d.ts","../../../node_modules/typescript/lib/lib.es2015.core.d.ts","../../../node_modules/typescript/lib/lib.es2015.collection.d.ts","../../../node_modules/typescript/lib/lib.es2015.generator.d.ts","../../../node_modules/typescript/lib/lib.es2015.iterable.d.ts","../../../node_modules/typescript/lib/lib.es2015.promise.d.ts","../../../node_modules/typescript/lib/lib.es2015.proxy.d.ts","../../../node_modules/typescript/lib/lib.es2015.reflect.d.ts","../../../node_modules/typescript/lib/lib.es2015.symbol.d.ts","../../../node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.ts","../../../node_modules/typescript/lib/lib.es2016.array.include.d.ts","../../../node_modules/typescript/lib/lib.es2016.intl.d.ts","../../../node_modules/typescript/lib/lib.es2017.arraybuffer.d.ts","../../../node_modules/typescript/lib/lib.es2017.date.d.ts","../../../node_modules/typescript/lib/lib.es2017.object.d.ts","../../../node_modules/typescript/lib/lib.es2017.sharedmemory.d.ts","../../../node_modules/typescript/lib/lib.es2017.string.d.ts","../../../node_modules/typescript/lib/lib.es2017.intl.d.ts","../../../node_modules/typescript/lib/lib.es2017.typedarrays.d.ts","../../../node_modules/typescript/lib/lib.es2018.asyncgenerator.d.ts","../../../node_modules/typescript/lib/lib.es2018.asynciterable.d.ts","../../../node_modules/typescript/lib/lib.es2018.intl.d.ts","../../../node_modules/typescript/lib/lib.es2018.promise.d.ts","../../../node_modules/typescript/lib/lib.es2018.regexp.d.ts","../../../node_modules/typescript/lib/lib.es2019.array.d.ts","../../../node_modules/typescript/lib/lib.es2019.object.d.ts","../../../node_modules/typescript/lib/lib.es2019.string.d.ts","../../../node_modules/typescript/lib/lib.es2019.symbol.d.ts","../../../node_modules/typescript/lib/lib.es2019.intl.d.ts","../../../node_modules/typescript/lib/lib.es2020.bigint.d.ts","../../../node_modules/typescript/lib/lib.es2020.date.d.ts","../../../node_modules/typescript/lib/lib.es2020.promise.d.ts","../../../node_modules/typescript/lib/lib.es2020.sharedmemory.d.ts","../../../node_modules/typescript/lib/lib.es2020.string.d.ts","../../../node_modules/typescript/lib/lib.es2020.symbol.wellknown.d.ts","../../../node_modules/typescript/lib/lib.es2020.intl.d.ts","../../../node_modules/typescript/lib/lib.es2020.number.d.ts","../../../node_modules/typescript/lib/lib.es2021.promise.d.ts","../../../node_modules/typescript/lib/lib.es2021.string.d.ts","../../../node_modules/typescript/lib/lib.es2021.weakref.d.ts","../../../node_modules/typescript/lib/lib.es2021.intl.d.ts","../../../node_modules/typescript/lib/lib.es2022.array.d.ts","../../../node_modules/typescript/lib/lib.es2022.error.d.ts","../../../node_modules/typescript/lib/lib.es2022.intl.d.ts","../../../node_modules/typescript/lib/lib.es2022.object.d.ts","../../../node_modules/typescript/lib/lib.es2022.string.d.ts","../../../node_modules/typescript/lib/lib.es2022.regexp.d.ts","../../../node_modules/typescript/lib/lib.esnext.intl.d.ts","../../../node_modules/typescript/lib/lib.decorators.d.ts","../../../node_modules/typescript/lib/lib.decorators.legacy.d.ts","../../../node_modules/tslib/tslib.d.ts","../../../node_modules/tslib/modules/index.d.ts","../../../node_modules/zod/dist/types/v3/helpers/typealiases.d.ts","../../../node_modules/zod/dist/types/v3/helpers/util.d.ts","../../../node_modules/zod/dist/types/v3/zoderror.d.ts","../../../node_modules/zod/dist/types/v3/locales/en.d.ts","../../../node_modules/zod/dist/types/v3/errors.d.ts","../../../node_modules/zod/dist/types/v3/helpers/parseutil.d.ts","../../../node_modules/zod/dist/types/v3/helpers/enumutil.d.ts","../../../node_modules/zod/dist/types/v3/helpers/errorutil.d.ts","../../../node_modules/zod/dist/types/v3/helpers/partialutil.d.ts","../../../node_modules/zod/dist/types/v3/standard-schema.d.ts","../../../node_modules/zod/dist/types/v3/types.d.ts","../../../node_modules/zod/dist/types/v3/external.d.ts","../../../node_modules/zod/dist/types/v3/index.d.ts","../../../node_modules/zod/dist/types/index.d.ts","../src/config.ts","../../platforms/dist/types.d.ts","../../platforms/dist/factory.d.ts","../../platforms/dist/errors.d.ts","../../platforms/dist/index.d.ts","../../tools/dist/abort.d.ts","../../../node_modules/picocolors/types.d.ts","../../../node_modules/picocolors/picocolors.d.ts","../../tools/dist/color.d.ts","../../tools/dist/logger.d.ts","../../../node_modules/@clack/core/dist/index.d.mts","../../../node_modules/@clack/prompts/dist/index.d.mts","../../tools/dist/prompts.d.ts","../../../node_modules/nano-spawn/source/index.d.ts","../../tools/dist/spawn.d.ts","../../tools/dist/react-native.d.ts","../../tools/dist/error.d.ts","../../tools/dist/index.d.ts","../src/xcrun/simctl.ts","../src/xcrun/devicectl.ts","../src/utils.ts","../src/instance.ts","../src/factory.ts","../src/index.ts","../../../node_modules/@types/node/assert.d.ts","../../../node_modules/@types/node/assert/strict.d.ts","../../../node_modules/@types/node/globals.d.ts","../../../node_modules/@types/node/async_hooks.d.ts","../../../node_modules/@types/node/buffer.d.ts","../../../node_modules/@types/node/child_process.d.ts","../../../node_modules/@types/node/cluster.d.ts","../../../node_modules/@types/node/console.d.ts","../../../node_modules/@types/node/constants.d.ts","../../../node_modules/@types/node/crypto.d.ts","../../../node_modules/@types/node/dgram.d.ts","../../../node_modules/@types/node/diagnostics_channel.d.ts","../../../node_modules/@types/node/dns.d.ts","../../../node_modules/@types/node/dns/promises.d.ts","../../../node_modules/@types/node/domain.d.ts","../../../node_modules/@types/node/dom-events.d.ts","../../../node_modules/@types/node/events.d.ts","../../../node_modules/@types/node/fs.d.ts","../../../node_modules/@types/node/fs/promises.d.ts","../../../node_modules/@types/node/http.d.ts","../../../node_modules/@types/node/http2.d.ts","../../../node_modules/@types/node/https.d.ts","../../../node_modules/@types/node/inspector.d.ts","../../../node_modules/@types/node/module.d.ts","../../../node_modules/@types/node/net.d.ts","../../../node_modules/@types/node/os.d.ts","../../../node_modules/@types/node/path.d.ts","../../../node_modules/@types/node/perf_hooks.d.ts","../../../node_modules/@types/node/process.d.ts","../../../node_modules/@types/node/punycode.d.ts","../../../node_modules/@types/node/querystring.d.ts","../../../node_modules/@types/node/readline.d.ts","../../../node_modules/@types/node/readline/promises.d.ts","../../../node_modules/@types/node/repl.d.ts","../../../node_modules/@types/node/stream.d.ts","../../../node_modules/@types/node/stream/promises.d.ts","../../../node_modules/@types/node/stream/consumers.d.ts","../../../node_modules/@types/node/stream/web.d.ts","../../../node_modules/@types/node/string_decoder.d.ts","../../../node_modules/@types/node/test.d.ts","../../../node_modules/@types/node/timers.d.ts","../../../node_modules/@types/node/timers/promises.d.ts","../../../node_modules/@types/node/tls.d.ts","../../../node_modules/@types/node/trace_events.d.ts","../../../node_modules/@types/node/tty.d.ts","../../../node_modules/@types/node/url.d.ts","../../../node_modules/@types/node/util.d.ts","../../../node_modules/@types/node/v8.d.ts","../../../node_modules/@types/node/vm.d.ts","../../../node_modules/@types/node/wasi.d.ts","../../../node_modules/@types/node/worker_threads.d.ts","../../../node_modules/@types/node/zlib.d.ts","../../../node_modules/@types/node/globals.global.d.ts","../../../node_modules/@types/node/index.d.ts"],"fileIdsList":[[131,134,146],[86,134,146],[100,146],[103,146],[104,109,137,146],[105,116,117,124,134,145,146],[105,106,116,124,146],[107,146],[108,109,117,125,146],[109,134,142,146],[110,112,116,124,146],[111,146],[112,113,146],[116,146],[114,116,146],[116,117,118,134,145,146],[116,117,118,131,134,137,146],[146,150],[146],[112,116,119,124,134,145,146],[116,117,119,120,124,134,142,145,146],[119,121,134,142,145,146],[100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152],[116,122,146],[123,145,146],[112,116,124,134,146],[125,146],[126,146],[103,127,146],[128,144,146,150],[129,146],[130,146],[116,131,132,146],[131,133,146,148],[104,116,134,135,136,137,146],[104,134,136,146],[134,135,146],[137,146],[138,146],[116,140,141,146],[140,141,146],[109,124,134,142,146],[143,146],[124,144,146],[104,119,130,145,146],[109,146],[134,146,147],[146,148],[146,149],[104,109,116,118,127,134,145,146,148,150],[134,146,151],[105,146],[82,146],[60,146],[74,146],[64,65,146],[62,63,64,66,67,72,146],[63,64,146],[72,146],[73,146],[64,146],[62,63,64,67,68,69,70,71,146],[62,63,74,146],[61,75,146],[61,76,80,97,146],[61,76,98,146],[61,76,80,94,95,96,146],[61,76,146],[61,93,109,117,125,126,146],[61,93,146],[77,146],[77,78,79,146],[83,146],[81,84,85,88,90,91,92,146],[87,146],[89,146]],"fileInfos":[{"version":"69684132aeb9b5642cbcd9e22dff7818ff0ee1aa831728af0ecf97d3364d5546","affectsGlobalScope":true,"impliedFormat":1},{"version":"45b7ab580deca34ae9729e97c13cfd999df04416a79116c3bfb483804f85ded4","impliedFormat":1},{"version":"3facaf05f0c5fc569c5649dd359892c98a85557e3e0c847964caeb67076f4d75","impliedFormat":1},{"version":"e44bb8bbac7f10ecc786703fe0a6a4b952189f908707980ba8f3c8975a760962","impliedFormat":1},{"version":"5e1c4c362065a6b95ff952c0eab010f04dcd2c3494e813b493ecfd4fcb9fc0d8","impliedFormat":1},{"version":"68d73b4a11549f9c0b7d352d10e91e5dca8faa3322bfb77b661839c42b1ddec7","impliedFormat":1},{"version":"5efce4fc3c29ea84e8928f97adec086e3dc876365e0982cc8479a07954a3efd4","impliedFormat":1},{"version":"feecb1be483ed332fad555aff858affd90a48ab19ba7272ee084704eb7167569","impliedFormat":1},{"version":"ee7bad0c15b58988daa84371e0b89d313b762ab83cb5b31b8a2d1162e8eb41c2","impliedFormat":1},{"version":"092c2bfe125ce69dbb1223c85d68d4d2397d7d8411867b5cc03cec902c233763","affectsGlobalScope":true,"impliedFormat":1},{"version":"c57796738e7f83dbc4b8e65132f11a377649c00dd3eee333f672b8f0a6bea671","affectsGlobalScope":true,"impliedFormat":1},{"version":"dc2df20b1bcdc8c2d34af4926e2c3ab15ffe1160a63e58b7e09833f616efff44","affectsGlobalScope":true,"impliedFormat":1},{"version":"515d0b7b9bea2e31ea4ec968e9edd2c39d3eebf4a2d5cbd04e88639819ae3b71","affectsGlobalScope":true,"impliedFormat":1},{"version":"0559b1f683ac7505ae451f9a96ce4c3c92bdc71411651ca6ddb0e88baaaad6a3","affectsGlobalScope":true,"impliedFormat":1},{"version":"0dc1e7ceda9b8b9b455c3a2d67b0412feab00bd2f66656cd8850e8831b08b537","affectsGlobalScope":true,"impliedFormat":1},{"version":"ce691fb9e5c64efb9547083e4a34091bcbe5bdb41027e310ebba8f7d96a98671","affectsGlobalScope":true,"impliedFormat":1},{"version":"8d697a2a929a5fcb38b7a65594020fcef05ec1630804a33748829c5ff53640d0","affectsGlobalScope":true,"impliedFormat":1},{"version":"4ff2a353abf8a80ee399af572debb8faab2d33ad38c4b4474cff7f26e7653b8d","affectsGlobalScope":true,"impliedFormat":1},{"version":"936e80ad36a2ee83fc3caf008e7c4c5afe45b3cf3d5c24408f039c1d47bdc1df","affectsGlobalScope":true,"impliedFormat":1},{"version":"d15bea3d62cbbdb9797079416b8ac375ae99162a7fba5de2c6c505446486ac0a","affectsGlobalScope":true,"impliedFormat":1},{"version":"68d18b664c9d32a7336a70235958b8997ebc1c3b8505f4f1ae2b7e7753b87618","affectsGlobalScope":true,"impliedFormat":1},{"version":"eb3d66c8327153d8fa7dd03f9c58d351107fe824c79e9b56b462935176cdf12a","affectsGlobalScope":true,"impliedFormat":1},{"version":"38f0219c9e23c915ef9790ab1d680440d95419ad264816fa15009a8851e79119","affectsGlobalScope":true,"impliedFormat":1},{"version":"69ab18c3b76cd9b1be3d188eaf8bba06112ebbe2f47f6c322b5105a6fbc45a2e","affectsGlobalScope":true,"impliedFormat":1},{"version":"fef8cfad2e2dc5f5b3d97a6f4f2e92848eb1b88e897bb7318cef0e2820bceaab","affectsGlobalScope":true,"impliedFormat":1},{"version":"2f11ff796926e0832f9ae148008138ad583bd181899ab7dd768a2666700b1893","affectsGlobalScope":true,"impliedFormat":1},{"version":"4de680d5bb41c17f7f68e0419412ca23c98d5749dcaaea1896172f06435891fc","affectsGlobalScope":true,"impliedFormat":1},{"version":"954296b30da6d508a104a3a0b5d96b76495c709785c1d11610908e63481ee667","affectsGlobalScope":true,"impliedFormat":1},{"version":"ac9538681b19688c8eae65811b329d3744af679e0bdfa5d842d0e32524c73e1c","affectsGlobalScope":true,"impliedFormat":1},{"version":"0a969edff4bd52585473d24995c5ef223f6652d6ef46193309b3921d65dd4376","affectsGlobalScope":true,"impliedFormat":1},{"version":"9e9fbd7030c440b33d021da145d3232984c8bb7916f277e8ffd3dc2e3eae2bdb","affectsGlobalScope":true,"impliedFormat":1},{"version":"811ec78f7fefcabbda4bfa93b3eb67d9ae166ef95f9bff989d964061cbf81a0c","affectsGlobalScope":true,"impliedFormat":1},{"version":"717937616a17072082152a2ef351cb51f98802fb4b2fdabd32399843875974ca","affectsGlobalScope":true,"impliedFormat":1},{"version":"d7e7d9b7b50e5f22c915b525acc5a49a7a6584cf8f62d0569e557c5cfc4b2ac2","affectsGlobalScope":true,"impliedFormat":1},{"version":"71c37f4c9543f31dfced6c7840e068c5a5aacb7b89111a4364b1d5276b852557","affectsGlobalScope":true,"impliedFormat":1},{"version":"576711e016cf4f1804676043e6a0a5414252560eb57de9faceee34d79798c850","affectsGlobalScope":true,"impliedFormat":1},{"version":"89c1b1281ba7b8a96efc676b11b264de7a8374c5ea1e6617f11880a13fc56dc6","affectsGlobalScope":true,"impliedFormat":1},{"version":"74f7fa2d027d5b33eb0471c8e82a6c87216223181ec31247c357a3e8e2fddc5b","affectsGlobalScope":true,"impliedFormat":1},{"version":"d6d7ae4d1f1f3772e2a3cde568ed08991a8ae34a080ff1151af28b7f798e22ca","affectsGlobalScope":true,"impliedFormat":1},{"version":"063600664504610fe3e99b717a1223f8b1900087fab0b4cad1496a114744f8df","affectsGlobalScope":true,"impliedFormat":1},{"version":"934019d7e3c81950f9a8426d093458b65d5aff2c7c1511233c0fd5b941e608ab","affectsGlobalScope":true,"impliedFormat":1},{"version":"52ada8e0b6e0482b728070b7639ee42e83a9b1c22d205992756fe020fd9f4a47","affectsGlobalScope":true,"impliedFormat":1},{"version":"3bdefe1bfd4d6dee0e26f928f93ccc128f1b64d5d501ff4a8cf3c6371200e5e6","affectsGlobalScope":true,"impliedFormat":1},{"version":"59fb2c069260b4ba00b5643b907ef5d5341b167e7d1dbf58dfd895658bda2867","affectsGlobalScope":true,"impliedFormat":1},{"version":"639e512c0dfc3fad96a84caad71b8834d66329a1f28dc95e3946c9b58176c73a","affectsGlobalScope":true,"impliedFormat":1},{"version":"368af93f74c9c932edd84c58883e736c9e3d53cec1fe24c0b0ff451f529ceab1","affectsGlobalScope":true,"impliedFormat":1},{"version":"af3dd424cf267428f30ccfc376f47a2c0114546b55c44d8c0f1d57d841e28d74","affectsGlobalScope":true,"impliedFormat":1},{"version":"995c005ab91a498455ea8dfb63aa9f83fa2ea793c3d8aa344be4a1678d06d399","affectsGlobalScope":true,"impliedFormat":1},{"version":"959d36cddf5e7d572a65045b876f2956c973a586da58e5d26cde519184fd9b8a","affectsGlobalScope":true,"impliedFormat":1},{"version":"965f36eae237dd74e6cca203a43e9ca801ce38824ead814728a2807b1910117d","affectsGlobalScope":true,"impliedFormat":1},{"version":"3925a6c820dcb1a06506c90b1577db1fdbf7705d65b62b99dce4be75c637e26b","affectsGlobalScope":true,"impliedFormat":1},{"version":"0a3d63ef2b853447ec4f749d3f368ce642264246e02911fcb1590d8c161b8005","affectsGlobalScope":true,"impliedFormat":1},{"version":"b5ce7a470bc3628408429040c4e3a53a27755022a32fd05e2cb694e7015386c7","affectsGlobalScope":true,"impliedFormat":1},{"version":"8444af78980e3b20b49324f4a16ba35024fef3ee069a0eb67616ea6ca821c47a","affectsGlobalScope":true,"impliedFormat":1},{"version":"3287d9d085fbd618c3971944b65b4be57859f5415f495b33a6adc994edd2f004","affectsGlobalScope":true,"impliedFormat":1},{"version":"b4b67b1a91182421f5df999988c690f14d813b9850b40acd06ed44691f6727ad","affectsGlobalScope":true,"impliedFormat":1},{"version":"811c71eee4aa0ac5f7adf713323a5c41b0cf6c4e17367a34fbce379e12bbf0a4","affectsGlobalScope":true,"impliedFormat":1},{"version":"8e7f8264d0fb4c5339605a15daadb037bf238c10b654bb3eee14208f860a32ea","affectsGlobalScope":true,"impliedFormat":1},{"version":"782dec38049b92d4e85c1585fbea5474a219c6984a35b004963b00beb1aab538","affectsGlobalScope":true,"impliedFormat":1},{"version":"a6a5253138c5432c68a1510c70fe78a644fe2e632111ba778e1978010d6edfec","impliedFormat":1},{"version":"b8f34dd1757f68e03262b1ca3ddfa668a855b872f8bdd5224d6f993a7b37dc2c","impliedFormat":99},{"version":"d3cfde44f8089768ebb08098c96d01ca260b88bccf238d55eee93f1c620ff5a5","impliedFormat":1},{"version":"293eadad9dead44c6fd1db6de552663c33f215c55a1bfa2802a1bceed88ff0ec","impliedFormat":1},{"version":"54f6ec6ea75acea6eb23635617252d249145edbc7bcd9d53f2d70280d2aef953","impliedFormat":1},{"version":"c25ce98cca43a3bfa885862044be0d59557be4ecd06989b2001a83dcf69620fd","impliedFormat":1},{"version":"8e71e53b02c152a38af6aec45e288cc65bede077b92b9b43b3cb54a37978bb33","impliedFormat":1},{"version":"754a9396b14ca3a4241591afb4edc644b293ccc8a3397f49be4dfd520c08acb3","impliedFormat":1},{"version":"f672c876c1a04a223cf2023b3d91e8a52bb1544c576b81bf64a8fec82be9969c","impliedFormat":1},{"version":"e4b03ddcf8563b1c0aee782a185286ed85a255ce8a30df8453aade2188bbc904","impliedFormat":1},{"version":"de2316e90fc6d379d83002f04ad9698bc1e5285b4d52779778f454dd12ce9f44","impliedFormat":1},{"version":"25b3f581e12ede11e5739f57a86e8668fbc0124f6649506def306cad2c59d262","impliedFormat":1},{"version":"2da997a01a6aa5c5c09de5d28f0f4407b597c5e1aecfd32f1815809c532650a2","impliedFormat":1},{"version":"5d26d2e47e2352def36f89a3e8bf8581da22b7f857e07ef3114cd52cf4813445","impliedFormat":1},{"version":"3db2efd285e7328d8014b54a7fce3f4861ebcdc655df40517092ed0050983617","impliedFormat":1},{"version":"d5d39a24c759df40480a4bfc0daffd364489702fdbcbdfc1711cde34f8739995","impliedFormat":1},{"version":"9c7dbfc3d2477afe16f56ebcc8a95e24aadd380c2facf9b9fecfce04e87b882e","signature":"277423b251fb375945b8dfcd5ba1a662eec1bd75b39c42a4bcb27912ae9158c7","impliedFormat":99},{"version":"e37270191d6e04dfa60d210394e75002e62398159beec672035a54c9d2827c40","impliedFormat":99},{"version":"fc61bab1427ed7f1e75aaff1d6893859f0ad5832db78e173c7e59abc4b3eebf2","impliedFormat":99},{"version":"742dbfad4257af069a16003c1a48a083697b6fe1c9902ba4a3a54bc08ce8db84","impliedFormat":99},{"version":"6e24348814b735daaa863c787ee558d05db2c9fe90447e97d474ba9f60dfb171","impliedFormat":99},{"version":"3e442c402123b264ccdf7123c1366e1473d9c39f5db69373e938284fc01c49ce","impliedFormat":99},{"version":"590595c1230ebb7c43ebac51b2b2da956a719b213355b4358e2a6b16a8b5936c","impliedFormat":1},{"version":"8c5f0739f00f89f89b03a1fe6658c6d78000d7ebd7f556f0f8d6908fa679de35","impliedFormat":1},{"version":"a15c0df1ac9b2a4d833490522614fc57ae97d70a07bf4964a4d6bb73f3f56399","impliedFormat":99},{"version":"e4cead4a8596a6f051c36ef184f5fb6f117232eefdc1f98ef9847c9efc2c8911","impliedFormat":99},{"version":"df7225806785ade68c6cf2b1cf3ba0d1c7fed1ee7605f34e37d4a901f1d29fd2","impliedFormat":99},{"version":"6bf8a7596880ff1b8f8fd52ee8de8000df00c0c98adacb0b0af0e6a3f16cabe6","impliedFormat":99},{"version":"8af66ec621033f41ccb2bcee775e883c2649fa0db71192fe863185b0281082a6","impliedFormat":99},{"version":"9d4af7bde3e345d3071b5fefbece2d3482971aae89ded50f302c8cb246e81581","impliedFormat":99},{"version":"f3eb748185038bca941a02994b1b0b5803c0a2ce818b8a7d72a24a6b814f5d3e","impliedFormat":99},{"version":"2ba26b5ab00dd3495eeb733cdb46d939a8eb755a395a91169158cdf962aff6c3","impliedFormat":99},{"version":"d6fe58ebff353af75db3986d9ab2b4b57258ad5af3f4b65cdb2100fd47df5425","impliedFormat":99},{"version":"299207f09ec026435d722d979effd6556f7facc6c16256c3c00f797648eed0cb","impliedFormat":99},{"version":"d71a9f0e67f6d98f158f056afca969fc359a241dbdfad6253d55b97d9f530348","signature":"24830d55a5964806840f3a1cef8679ac8ef0e13299edffcf93b73626230e3a97","impliedFormat":99},{"version":"c54595aaed14b999c35fd323fd8d676bb6c0a2d21b909081b8da26be5b1c1516","signature":"6be80d57374da8b7adc9ec6acb08c38699d16b76bda6953c9690018898c40350","impliedFormat":99},{"version":"09d484490fbff29868cd82b10519c45400814800569871ce27c6726e39d1094c","signature":"3ddf102e56cda9d977de594a122b1abed68821c38fd0b73bdb657f5063878177","impliedFormat":99},{"version":"662826451442fa53ec83cec3603b463d1e849135c4e5b50d882ddf363dd7b6ee","signature":"fde73bd38e0324f9613d97b0ca5370b48248f04e0a9f989b1de53176e3f97345","impliedFormat":99},{"version":"b454e6ba2403b80dd29c314e53017725ae2706b250d7b82de92cc177f290a00a","signature":"6a98ca8526c3518a75f3135d1fde19cd3839a3cb6c3e8404f3d282e83a606067","impliedFormat":99},{"version":"6e3f6aeec16f043afcb40227ec7a6bdd7f8f8a0b9d6196bddd8cfb1357a32ce6","signature":"7ebf46b10ce3196a4b117a4f59e33cf37fc84d9e99bbddcb2a69f89f143eca7b","impliedFormat":99},{"version":"7e771891adaa85b690266bc37bd6eb43bc57eecc4b54693ead36467e7369952a","impliedFormat":1},{"version":"a69c09dbea52352f479d3e7ac949fde3d17b195abe90b045d619f747b38d6d1a","impliedFormat":1},{"version":"f749812878fecfa53cfc13b36e5d35086fb6377983a9df44175da83ccc23af1f","affectsGlobalScope":true,"impliedFormat":1},{"version":"7d2e3fea24c712c99c03ad8f556abedbfe105f87f1be10b95dbd409d24bc05a3","impliedFormat":1},{"version":"211e3f15fbced4ab4be19f49ffa990b9ff20d749d33b65ff753be691e7616239","affectsGlobalScope":true,"impliedFormat":1},{"version":"3719525a8f6ab731e3dfd585d9f87df55ec7d50d461df84f74eb4d68bb165244","impliedFormat":1},{"version":"5a94487653355b56018122d92392beb2e5f4a6c63ba5cef83bbe1c99775ef713","impliedFormat":1},{"version":"d5135ad93b33adcce80b18f8065087934cdc1730d63db58562edcf017e1aad9b","affectsGlobalScope":true,"impliedFormat":1},{"version":"82408ed3e959ddc60d3e9904481b5a8dc16469928257af22a3f7d1a3bc7fd8c4","impliedFormat":1},{"version":"e596c9bb2f29a2699fdd4ae89139612652245192f67f45617c5a4b20832aaae9","impliedFormat":1},{"version":"bb9c4ffa5e6290c6980b63c815cdd1625876dadb2efaf77edbe82984be93e55e","impliedFormat":1},{"version":"1cdcfc1f624d6c08aa12c73935f6e13f095919cd99edf95752951796eb225729","impliedFormat":1},{"version":"4eaff3d8e10676fd7913d8c108890e71c688e1e7d52f6d1d55c39514f493dc47","impliedFormat":1},{"version":"14b5aa23c5d0ae1907bc696ac7b6915d88f7d85799cc0dc2dcf98fbce2c5a67c","impliedFormat":1},{"version":"5c439dafdc09abe4d6c260a96b822fa0ba5be7203c71a63ab1f1423cd9e838ea","impliedFormat":1},{"version":"6b526a5ec4a401ca7c26cfe6a48e641d8f30af76673bad3b06a1b4504594a960","affectsGlobalScope":true,"impliedFormat":1},{"version":"00dee7cdca8b8420c47ea4a31a34b8e8294013ebc4f463fd941e867e7bf05029","affectsGlobalScope":true,"impliedFormat":1},{"version":"3256f3cccd578f9e7fe3a28096c505634bebcee8afb738ffa99368e536ca3a0b","impliedFormat":1},{"version":"1c84b46267610a34028edfd0d035509341751262bac1062857f3c8df7aff7153","impliedFormat":1},{"version":"7f138842074d0a40681775af008c8452093b68c383c94de31759e853c6d06b5c","impliedFormat":1},{"version":"a3d541d303ee505053f5dcbf9fafb65cac3d5631037501cd616195863a6c5740","impliedFormat":1},{"version":"8d3c583a07e0c37e876908c2d5da575019f689df8d9fa4c081d99119d53dba22","impliedFormat":1},{"version":"2c828a5405191d006115ab34e191b8474bc6c86ffdc401d1a9864b1b6e088a58","impliedFormat":1},{"version":"e630e5528e899219ae319e83bef54bf3bcb91b01d76861ecf881e8e614b167f0","affectsGlobalScope":true,"impliedFormat":1},{"version":"bcebb922784739bdb34c18ee51095d25a92b560c78ccd2eaacd6bd00f7443d83","impliedFormat":1},{"version":"7ee6ed878c4528215c82b664fe0cfe80e8b4da6c0d4cc80869367868774db8b1","impliedFormat":1},{"version":"b0973c3cbcdc59b37bf477731d468696ecaf442593ec51bab497a613a580fe30","impliedFormat":1},{"version":"4989e92ba5b69b182d2caaea6295af52b7dc73a4f7a2e336a676722884e7139d","affectsGlobalScope":true,"impliedFormat":1},{"version":"0715e4cd28ad471b2a93f3e552ff51a3ae423417a01a10aa1d3bc7c6b95059d6","affectsGlobalScope":true,"impliedFormat":1},{"version":"5153a2fd150e46ce57bb3f8db1318d33f6ad3261ed70ceeff92281c0608c74a3","impliedFormat":1},{"version":"210d54cd652ec0fec8c8916e4af59bb341065576ecda039842f9ffb2e908507c","impliedFormat":1},{"version":"36b03690b628eab08703d63f04eaa89c5df202e5f1edf3989f13ad389cd2c091","impliedFormat":1},{"version":"0effadd232a20498b11308058e334d3339cc5bf8c4c858393e38d9d4c0013dcf","impliedFormat":1},{"version":"25846d43937c672bab7e8195f3d881f93495df712ee901860effc109918938cc","impliedFormat":1},{"version":"4f3fdeba4e28e21aa719c081b8dc8f91d47e12e773389b9d35679c08151c9d37","impliedFormat":1},{"version":"1b952304137851e45bc009785de89ada562d9376177c97e37702e39e60c2f1ff","impliedFormat":1},{"version":"69ee23dd0d215b09907ad30d23f88b7790c93329d1faf31d7835552a10cf7cbf","impliedFormat":1},{"version":"44b8b584a338b190a59f4f6929d072431950c7bd92ec2694821c11bce180c8a5","impliedFormat":1},{"version":"23b89798789dffbd437c0c423f5d02d11f9736aea73d6abf16db4f812ff36eda","impliedFormat":1},{"version":"f69ff39996a61a0dd10f4bce73272b52e8024a4d58b13ab32bf4712909d0a2b7","impliedFormat":1},{"version":"3c4ba1dd9b12ffa284b565063108f2f031d150ea15b8fafbdc17f5d2a07251f3","affectsGlobalScope":true,"impliedFormat":1},{"version":"e10177274a35a9d07c825615340b2fcde2f610f53f3fb40269fd196b4288dda6","impliedFormat":1},{"version":"1422cd9e705adcc09088fda85a900c2b70e3ad36ea85846f68bd1a884cdf4e2b","impliedFormat":1},{"version":"3c13ef48634e7b5012fcf7e8fce7496352c2d779a7201389ca96a2a81ee4314d","impliedFormat":1},{"version":"5d0a25ec910fa36595f85a67ac992d7a53dd4064a1ba6aea1c9f14ab73a023f2","impliedFormat":1},{"version":"a73ae8c0e62103bb9e21bb6538700881bf135b9a8b125b857ec68edfa0da4ed3","affectsGlobalScope":true,"impliedFormat":1},{"version":"e1c1b2fbe236bf7ee3e342eeae7e20efb8988a0ac7da1cbbfa2c1f66b76c3423","affectsGlobalScope":true,"impliedFormat":1},{"version":"868831cab82b65dfe1d68180e898af1f2101e89ba9b754d1db6fb8cc2fac1921","impliedFormat":1},{"version":"0fe8985a28f82c450a04a6edf1279d7181c0893f37da7d2a27f8efd4fd5edb03","impliedFormat":1},{"version":"e59a892d87e72733e2a9ca21611b9beb52977be2696c7ba4b216cbbb9a48f5aa","impliedFormat":1},{"version":"52120bb7e4583612225bdf08e7c12559548170f11e660d33a33623bae9bbdbba","affectsGlobalScope":true,"impliedFormat":1},{"version":"8a300fa9b698845a1f9c41ecbe2c5966634582a8e2020d51abcace9b55aa959e","impliedFormat":1},{"version":"ab9b9a36e5284fd8d3bf2f7d5fcbc60052f25f27e4d20954782099282c60d23e","affectsGlobalScope":true,"impliedFormat":1},{"version":"a6dd3dba8e665ac43d279e0fdf5219edda0eed69b5e9a5061f46cd6a65c4f7a1","impliedFormat":1}],"root":[76,[94,99]],"options":{"composite":true,"declarationMap":true,"emitDeclarationOnly":false,"importHelpers":true,"module":199,"noEmitOnError":true,"noFallthroughCasesInSwitch":true,"noImplicitOverride":true,"noImplicitReturns":true,"noUnusedLocals":true,"outDir":"./","rootDir":"../src","skipLibCheck":true,"strict":true,"target":9,"tsBuildInfoFile":"./tsconfig.lib.tsbuildinfo"},"referencedMap":[[86,1],[87,2],[100,3],[101,3],[103,4],[104,5],[105,6],[106,7],[107,8],[108,9],[109,10],[110,11],[111,12],[112,13],[113,13],[115,14],[114,15],[116,14],[117,16],[118,17],[102,18],[152,19],[119,20],[120,21],[121,22],[153,23],[122,24],[123,25],[124,26],[125,27],[126,28],[127,29],[128,30],[129,31],[130,32],[131,33],[132,33],[133,34],[134,35],[136,36],[135,37],[137,38],[138,39],[139,19],[140,40],[141,41],[142,42],[143,43],[144,44],[145,45],[146,46],[147,47],[148,48],[149,49],[150,50],[151,51],[89,52],[83,53],[82,19],[61,54],[60,19],[58,19],[59,19],[10,19],[12,19],[11,19],[2,19],[13,19],[14,19],[15,19],[16,19],[17,19],[18,19],[19,19],[20,19],[3,19],[21,19],[22,19],[4,19],[23,19],[27,19],[24,19],[25,19],[26,19],[28,19],[29,19],[30,19],[5,19],[31,19],[32,19],[33,19],[34,19],[6,19],[38,19],[35,19],[36,19],[37,19],[39,19],[7,19],[40,19],[45,19],[46,19],[41,19],[42,19],[43,19],[44,19],[8,19],[50,19],[47,19],[48,19],[49,19],[51,19],[9,19],[52,19],[53,19],[54,19],[56,19],[55,19],[1,19],[57,19],[75,55],[66,56],[73,57],[68,19],[69,19],[67,58],[70,59],[62,19],[63,19],[74,60],[65,61],[71,19],[72,62],[64,63],[76,64],[98,65],[99,66],[97,67],[96,68],[95,69],[94,70],[79,19],[78,71],[80,72],[77,19],[81,19],[84,73],[92,19],[93,74],[85,19],[88,75],[91,19],[90,76]],"latestChangedDtsFile":"./index.d.ts","version":"5.8.3"}
@@ -0,0 +1,3 @@
1
+ import { type AppleDevice } from './config.js';
2
+ export declare const getDeviceName: (device: AppleDevice) => string;
3
+ //# sourceMappingURL=utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAA0B,KAAK,WAAW,EAAE,MAAM,aAAa,CAAC;AAEvE,eAAO,MAAM,aAAa,GAAI,QAAQ,WAAW,KAAG,MAMnD,CAAC"}
package/dist/utils.js ADDED
@@ -0,0 +1,7 @@
1
+ import { isAppleDeviceSimulator } from './config.js';
2
+ export const getDeviceName = (device) => {
3
+ if (isAppleDeviceSimulator(device)) {
4
+ return `${device.name} (${device.systemVersion}) (simulator)`;
5
+ }
6
+ return `${device.name} (physical)`;
7
+ };
@@ -0,0 +1,32 @@
1
+ export declare const devicectl: <TOutput>(command: string, args: string[]) => Promise<TOutput>;
2
+ export type AppleDeviceInfo = {
3
+ identifier: string;
4
+ deviceProperties: {
5
+ name: string;
6
+ osVersionNumber: string;
7
+ };
8
+ hardwareProperties: {
9
+ marketingName: string;
10
+ productType: string;
11
+ udid: string;
12
+ };
13
+ };
14
+ export declare const listDevices: () => Promise<AppleDeviceInfo[]>;
15
+ export type AppleAppInfo = {
16
+ bundleIdentifier: string;
17
+ name: string;
18
+ version: string;
19
+ url: string;
20
+ };
21
+ export declare const listApps: (identifier: string) => Promise<AppleAppInfo[]>;
22
+ export declare const getAppInfo: (identifier: string, bundleId: string) => Promise<AppleAppInfo | null>;
23
+ export declare const isAppInstalled: (identifier: string, bundleId: string) => Promise<boolean>;
24
+ export declare const startApp: (identifier: string, bundleId: string) => Promise<void>;
25
+ export type AppleProcessInfo = {
26
+ executable: string;
27
+ processIdentifier: number;
28
+ };
29
+ export declare const getProcesses: (identifier: string) => Promise<AppleProcessInfo[]>;
30
+ export declare const stopApp: (identifier: string, bundleId: string) => Promise<void>;
31
+ export declare const getDeviceId: (name: string) => Promise<string | null>;
32
+ //# sourceMappingURL=devicectl.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"devicectl.d.ts","sourceRoot":"","sources":["../../src/xcrun/devicectl.ts"],"names":[],"mappings":"AAMA,eAAO,MAAM,SAAS,GAAU,OAAO,EACrC,SAAS,MAAM,EACf,MAAM,MAAM,EAAE,KACb,OAAO,CAAC,OAAO,CAejB,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,gBAAgB,EAAE;QAChB,IAAI,EAAE,MAAM,CAAC;QACb,eAAe,EAAE,MAAM,CAAC;KACzB,CAAC;IACF,kBAAkB,EAAE;QAClB,aAAa,EAAE,MAAM,CAAC;QACtB,WAAW,EAAE,MAAM,CAAC;QACpB,IAAI,EAAE,MAAM,CAAC;KACd,CAAC;CACH,CAAC;AAEF,eAAO,MAAM,WAAW,QAAa,OAAO,CAAC,eAAe,EAAE,CAK7D,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IACzB,gBAAgB,EAAE,MAAM,CAAC;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;CACb,CAAC;AAEF,eAAO,MAAM,QAAQ,GAAU,YAAY,MAAM,KAAG,OAAO,CAAC,YAAY,EAAE,CAQzE,CAAC;AAEF,eAAO,MAAM,UAAU,GACrB,YAAY,MAAM,EAClB,UAAU,MAAM,KACf,OAAO,CAAC,YAAY,GAAG,IAAI,CAW7B,CAAC;AAEF,eAAO,MAAM,cAAc,GACzB,YAAY,MAAM,EAClB,UAAU,MAAM,KACf,OAAO,CAAC,OAAO,CAGjB,CAAC;AAEF,eAAO,MAAM,QAAQ,GACnB,YAAY,MAAM,EAClB,UAAU,MAAM,KACf,OAAO,CAAC,IAAI,CAQd,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,iBAAiB,EAAE,MAAM,CAAC;CAC3B,CAAC;AAEF,eAAO,MAAM,YAAY,GACvB,YAAY,MAAM,KACjB,OAAO,CAAC,gBAAgB,EAAE,CAO5B,CAAC;AAEF,eAAO,MAAM,OAAO,GAClB,YAAY,MAAM,EAClB,UAAU,MAAM,KACf,OAAO,CAAC,IAAI,CAwBd,CAAC;AAEF,eAAO,MAAM,WAAW,GAAU,MAAM,MAAM,KAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAOrE,CAAC"}
@@ -0,0 +1,85 @@
1
+ import { spawn } from '@react-native-harness/tools';
2
+ import fs from 'node:fs';
3
+ import { tmpdir } from 'node:os';
4
+ import { join } from 'node:path';
5
+ import { randomUUID } from 'node:crypto';
6
+ export const devicectl = async (command, args) => {
7
+ const tempFile = join(tmpdir(), `devicectl-${randomUUID()}.json`);
8
+ await spawn('xcrun', [
9
+ 'devicectl',
10
+ command,
11
+ ...args,
12
+ '--json-output',
13
+ tempFile,
14
+ ]);
15
+ const output = fs.readFileSync(tempFile, 'utf8');
16
+ fs.unlinkSync(tempFile);
17
+ return JSON.parse(output).result;
18
+ };
19
+ export const listDevices = async () => {
20
+ const result = await devicectl('list', [
21
+ 'devices',
22
+ ]);
23
+ return result.devices;
24
+ };
25
+ export const listApps = async (identifier) => {
26
+ const result = await devicectl('device', [
27
+ 'info',
28
+ 'apps',
29
+ '--device',
30
+ identifier,
31
+ ]);
32
+ return result.apps;
33
+ };
34
+ export const getAppInfo = async (identifier, bundleId) => {
35
+ const result = await devicectl('device', [
36
+ 'info',
37
+ 'apps',
38
+ '--device',
39
+ identifier,
40
+ '--bundle-id',
41
+ bundleId,
42
+ ]);
43
+ return result.apps[0] ?? null;
44
+ };
45
+ export const isAppInstalled = async (identifier, bundleId) => {
46
+ const apps = await listApps(identifier);
47
+ return apps.some((app) => app.bundleIdentifier === bundleId);
48
+ };
49
+ export const startApp = async (identifier, bundleId) => {
50
+ await devicectl('device', [
51
+ 'process',
52
+ 'launch',
53
+ '--device',
54
+ identifier,
55
+ bundleId,
56
+ ]);
57
+ };
58
+ export const getProcesses = async (identifier) => {
59
+ const result = await devicectl('device', ['info', 'processes', '--device', identifier]);
60
+ return result.runningProcesses;
61
+ };
62
+ export const stopApp = async (identifier, bundleId) => {
63
+ const appInfo = await getAppInfo(identifier, bundleId);
64
+ if (!appInfo) {
65
+ return;
66
+ }
67
+ const processes = await getProcesses(identifier);
68
+ const process = processes.find((process) => process.executable.startsWith(appInfo.url));
69
+ if (!process) {
70
+ return;
71
+ }
72
+ await devicectl('device', [
73
+ 'process',
74
+ 'terminate',
75
+ '--device',
76
+ identifier,
77
+ '--pid',
78
+ process.processIdentifier.toString(),
79
+ ]);
80
+ };
81
+ export const getDeviceId = async (name) => {
82
+ const devices = await listDevices();
83
+ const device = devices.find((device) => device.deviceProperties.name === name);
84
+ return device?.identifier ?? null;
85
+ };
@@ -0,0 +1,23 @@
1
+ export type AppleAppInfo = {
2
+ Bundle: string;
3
+ CFBundleIdentifier: string;
4
+ CFBundleName: string;
5
+ CFBundleDisplayName: string;
6
+ Path: string;
7
+ };
8
+ export declare const getAppInfo: (udid: string, bundleId: string) => Promise<AppleAppInfo | null>;
9
+ export declare const isAppInstalled: (udid: string, bundleId: string) => Promise<boolean>;
10
+ export type AppleSimulatorState = 'Booted' | 'Booting' | 'Shutdown';
11
+ export type AppleSimulatorInfo = {
12
+ name: string;
13
+ udid: string;
14
+ state: AppleSimulatorState;
15
+ isAvailable: boolean;
16
+ runtime: string;
17
+ };
18
+ export declare const getSimulators: () => Promise<AppleSimulatorInfo[]>;
19
+ export declare const getSimulatorStatus: (udid: string) => Promise<AppleSimulatorState>;
20
+ export declare const startApp: (udid: string, bundleId: string) => Promise<void>;
21
+ export declare const stopApp: (udid: string, bundleId: string) => Promise<void>;
22
+ export declare const getSimulatorId: (name: string, systemVersion: string) => Promise<string | null>;
23
+ //# sourceMappingURL=simctl.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"simctl.d.ts","sourceRoot":"","sources":["../../src/xcrun/simctl.ts"],"names":[],"mappings":"AAWA,MAAM,MAAM,YAAY,GAAG;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,kBAAkB,EAAE,MAAM,CAAC;IAC3B,YAAY,EAAE,MAAM,CAAC;IACrB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,eAAO,MAAM,UAAU,GACrB,MAAM,MAAM,EACZ,UAAU,MAAM,KACf,OAAO,CAAC,YAAY,GAAG,IAAI,CAkB7B,CAAC;AAEF,eAAO,MAAM,cAAc,GACzB,MAAM,MAAM,EACZ,UAAU,MAAM,KACf,OAAO,CAAC,OAAO,CAGjB,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG,QAAQ,GAAG,SAAS,GAAG,UAAU,CAAC;AAEpE,MAAM,MAAM,kBAAkB,GAAG;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,mBAAmB,CAAC;IAC3B,WAAW,EAAE,OAAO,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,eAAO,MAAM,aAAa,QAAa,OAAO,CAAC,kBAAkB,EAAE,CAqBlE,CAAC;AAEF,eAAO,MAAM,kBAAkB,GAC7B,MAAM,MAAM,KACX,OAAO,CAAC,mBAAmB,CAS7B,CAAC;AAEF,eAAO,MAAM,QAAQ,GACnB,MAAM,MAAM,EACZ,UAAU,MAAM,KACf,OAAO,CAAC,IAAI,CAEd,CAAC;AAEF,eAAO,MAAM,OAAO,GAClB,MAAM,MAAM,EACZ,UAAU,MAAM,KACf,OAAO,CAAC,IAAI,CAEd,CAAC;AAEF,eAAO,MAAM,cAAc,GACzB,MAAM,MAAM,EACZ,eAAe,MAAM,KACpB,OAAO,CAAC,MAAM,GAAG,IAAI,CAQvB,CAAC"}
@@ -0,0 +1,62 @@
1
+ import { spawn, spawnAndForget } from '@react-native-harness/tools';
2
+ const plistToJson = async (plistOutput) => {
3
+ const { stdout: jsonOutput } = await spawn('plutil', ['-convert', 'json', '-o', '-', '-'], { stdin: { string: plistOutput } });
4
+ return JSON.parse(jsonOutput);
5
+ };
6
+ export const getAppInfo = async (udid, bundleId) => {
7
+ const { stdout: plistOutput } = await spawn('xcrun', [
8
+ 'simctl',
9
+ 'appinfo',
10
+ udid,
11
+ bundleId,
12
+ ]);
13
+ const json = await plistToJson(plistOutput);
14
+ // If there is only one entry, it means the app is not installed
15
+ const hasMoreThanOneEntry = Object.keys(json).length > 1;
16
+ if (!hasMoreThanOneEntry) {
17
+ return null;
18
+ }
19
+ return json;
20
+ };
21
+ export const isAppInstalled = async (udid, bundleId) => {
22
+ const appInfo = await getAppInfo(udid, bundleId);
23
+ return appInfo !== null;
24
+ };
25
+ export const getSimulators = async () => {
26
+ const { stdout } = await spawn('xcrun', [
27
+ 'simctl',
28
+ 'list',
29
+ 'devices',
30
+ '--json',
31
+ ]);
32
+ const runtimeDevices = JSON.parse(stdout).devices;
33
+ const simulators = [];
34
+ Object.entries(runtimeDevices).forEach(([runtime, devices]) => {
35
+ devices.forEach((device) => {
36
+ simulators.push({
37
+ ...device,
38
+ runtime,
39
+ });
40
+ });
41
+ });
42
+ return simulators;
43
+ };
44
+ export const getSimulatorStatus = async (udid) => {
45
+ const simulators = await getSimulators();
46
+ const simulator = simulators.find((s) => s.udid === udid);
47
+ if (!simulator) {
48
+ throw new Error(`Simulator with UDID ${udid} not found`);
49
+ }
50
+ return simulator.state;
51
+ };
52
+ export const startApp = async (udid, bundleId) => {
53
+ await spawn('xcrun', ['simctl', 'launch', udid, bundleId]);
54
+ };
55
+ export const stopApp = async (udid, bundleId) => {
56
+ await spawnAndForget('xcrun', ['simctl', 'terminate', udid, bundleId]);
57
+ };
58
+ export const getSimulatorId = async (name, systemVersion) => {
59
+ const simulators = await getSimulators();
60
+ const simulator = simulators.find((s) => s.name === name && s.runtime.endsWith(systemVersion.replaceAll('.', '-')));
61
+ return simulator?.udid ?? null;
62
+ };
@@ -0,0 +1,19 @@
1
+ import baseConfig from '../../eslint.config.mjs';
2
+
3
+ export default [
4
+ ...baseConfig,
5
+ {
6
+ files: ['**/*.json'],
7
+ rules: {
8
+ '@nx/dependency-checks': [
9
+ 'error',
10
+ {
11
+ ignoredFiles: ['{projectRoot}/eslint.config.{js,cjs,mjs,ts,cts,mts}'],
12
+ },
13
+ ],
14
+ },
15
+ languageOptions: {
16
+ parser: await import('jsonc-eslint-parser'),
17
+ },
18
+ },
19
+ ];
package/package.json ADDED
@@ -0,0 +1,25 @@
1
+ {
2
+ "name": "@react-native-harness/platform-apple",
3
+ "description": "Apple platform for React Native Harness",
4
+ "version": "1.0.0-alpha.18",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "module": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ "./package.json": "./package.json",
11
+ ".": {
12
+ "development": "./src/index.ts",
13
+ "types": "./dist/index.d.ts",
14
+ "import": "./dist/index.js",
15
+ "default": "./dist/index.js"
16
+ }
17
+ },
18
+ "dependencies": {
19
+ "zod": "^3.25.67",
20
+ "tslib": "^2.3.0",
21
+ "@react-native-harness/platforms": "1.0.0-alpha.18",
22
+ "@react-native-harness/tools": "1.0.0-alpha.18"
23
+ },
24
+ "license": "MIT"
25
+ }
package/src/config.ts ADDED
@@ -0,0 +1,56 @@
1
+ import { z } from 'zod';
2
+
3
+ export const AppleSimulatorSchema = z.object({
4
+ type: z.literal('simulator'),
5
+ name: z.string().min(1, 'Name is required'),
6
+ systemVersion: z.string().min(1, 'System version is required'),
7
+ });
8
+
9
+ export const ApplePhysicalDeviceSchema = z.object({
10
+ type: z.literal('physical'),
11
+ name: z.string().min(1, 'Name is required'),
12
+ });
13
+
14
+ export const AppleDeviceSchema = z.discriminatedUnion('type', [
15
+ AppleSimulatorSchema,
16
+ ApplePhysicalDeviceSchema,
17
+ ]);
18
+
19
+ export const ApplePlatformConfigSchema = z.object({
20
+ name: z.string().min(1, 'Name is required'),
21
+ device: AppleDeviceSchema,
22
+ bundleId: z.string().min(1, 'Bundle ID is required'),
23
+ });
24
+
25
+ export type AppleSimulator = z.infer<typeof AppleSimulatorSchema>;
26
+ export type ApplePhysicalDevice = z.infer<typeof ApplePhysicalDeviceSchema>;
27
+ export type AppleDevice = z.infer<typeof AppleDeviceSchema>;
28
+ export type ApplePlatformConfig = z.infer<typeof ApplePlatformConfigSchema>;
29
+
30
+ export const isAppleDeviceSimulator = (
31
+ device: AppleDevice
32
+ ): device is AppleSimulator => {
33
+ return device.type === 'simulator';
34
+ };
35
+
36
+ export const isAppleDevicePhysical = (
37
+ device: AppleDevice
38
+ ): device is ApplePhysicalDevice => {
39
+ return device.type === 'physical';
40
+ };
41
+
42
+ export function assertAppleDeviceSimulator(
43
+ device: AppleDevice
44
+ ): asserts device is AppleSimulator {
45
+ if (!isAppleDeviceSimulator(device)) {
46
+ throw new Error('Device is not a simulator');
47
+ }
48
+ }
49
+
50
+ export function assertAppleDevicePhysical(
51
+ device: AppleDevice
52
+ ): asserts device is ApplePhysicalDevice {
53
+ if (!isAppleDevicePhysical(device)) {
54
+ throw new Error('Device is not a physical device');
55
+ }
56
+ }
package/src/factory.ts ADDED
@@ -0,0 +1,40 @@
1
+ import { HarnessPlatform } from '@react-native-harness/platforms';
2
+ import type {
3
+ AppleSimulator,
4
+ ApplePhysicalDevice,
5
+ ApplePlatformConfig,
6
+ } from './config.js';
7
+ import { ApplePlatformConfigSchema, isAppleDeviceSimulator } from './config.js';
8
+ import {
9
+ getApplePhysicalDevicePlatformInstance,
10
+ getAppleSimulatorPlatformInstance,
11
+ } from './instance.js';
12
+
13
+ export const appleSimulator = (
14
+ name: string,
15
+ systemVersion: string
16
+ ): AppleSimulator => ({
17
+ type: 'simulator',
18
+ name,
19
+ systemVersion,
20
+ });
21
+
22
+ export const applePhysicalDevice = (name: string): ApplePhysicalDevice => ({
23
+ type: 'physical',
24
+ name,
25
+ });
26
+
27
+ export const applePlatform = (
28
+ config: ApplePlatformConfig
29
+ ): HarnessPlatform => ({
30
+ name: config.name,
31
+ getInstance: async () => {
32
+ const parsedConfig = ApplePlatformConfigSchema.parse(config);
33
+
34
+ if (isAppleDeviceSimulator(parsedConfig.device)) {
35
+ return getAppleSimulatorPlatformInstance(parsedConfig);
36
+ }
37
+
38
+ return getApplePhysicalDevicePlatformInstance(parsedConfig);
39
+ },
40
+ });
package/src/index.ts ADDED
@@ -0,0 +1,6 @@
1
+ export {
2
+ applePlatform,
3
+ appleSimulator,
4
+ applePhysicalDevice,
5
+ } from './factory.js';
6
+ export type { ApplePlatformConfig } from './config.js';
@@ -0,0 +1,105 @@
1
+ import {
2
+ AppNotInstalledError,
3
+ DeviceNotFoundError,
4
+ HarnessPlatformInstance,
5
+ } from '@react-native-harness/platforms';
6
+ import {
7
+ ApplePlatformConfig,
8
+ assertAppleDevicePhysical,
9
+ assertAppleDeviceSimulator,
10
+ } from './config.js';
11
+ import * as simctl from './xcrun/simctl.js';
12
+ import * as devicectl from './xcrun/devicectl.js';
13
+ import { getDeviceName } from './utils.js';
14
+
15
+ export const getAppleSimulatorPlatformInstance = async (
16
+ config: ApplePlatformConfig
17
+ ): Promise<HarnessPlatformInstance> => {
18
+ assertAppleDeviceSimulator(config.device);
19
+
20
+ const udid = await simctl.getSimulatorId(
21
+ config.device.name,
22
+ config.device.systemVersion
23
+ );
24
+
25
+ if (!udid) {
26
+ throw new DeviceNotFoundError(getDeviceName(config.device));
27
+ }
28
+
29
+ const isInstalled = await simctl.isAppInstalled(udid, config.bundleId);
30
+
31
+ if (!isInstalled) {
32
+ throw new AppNotInstalledError(
33
+ config.bundleId,
34
+ getDeviceName(config.device)
35
+ );
36
+ }
37
+
38
+ const simulatorStatus = await simctl.getSimulatorStatus(udid);
39
+
40
+ if (simulatorStatus !== 'Booted') {
41
+ throw new Error('Simulator is not booted');
42
+ }
43
+
44
+ const isAvailable = await simctl.isAppInstalled(udid, config.bundleId);
45
+
46
+ if (!isAvailable) {
47
+ throw new AppNotInstalledError(
48
+ config.bundleId,
49
+ getDeviceName(config.device)
50
+ );
51
+ }
52
+
53
+ return {
54
+ startApp: async () => {
55
+ await simctl.startApp(udid, config.bundleId);
56
+ },
57
+ restartApp: async () => {
58
+ await simctl.stopApp(udid, config.bundleId);
59
+ await simctl.startApp(udid, config.bundleId);
60
+ },
61
+ stopApp: async () => {
62
+ await simctl.stopApp(udid, config.bundleId);
63
+ },
64
+ dispose: async () => {
65
+ await simctl.stopApp(udid, config.bundleId);
66
+ },
67
+ };
68
+ };
69
+
70
+ export const getApplePhysicalDevicePlatformInstance = async (
71
+ config: ApplePlatformConfig
72
+ ): Promise<HarnessPlatformInstance> => {
73
+ assertAppleDevicePhysical(config.device);
74
+
75
+ const deviceId = await devicectl.getDeviceId(config.device.name);
76
+
77
+ if (!deviceId) {
78
+ throw new DeviceNotFoundError(getDeviceName(config.device));
79
+ }
80
+
81
+ const isAvailable = await devicectl.isAppInstalled(deviceId, config.bundleId);
82
+
83
+ if (!isAvailable) {
84
+ throw new AppNotInstalledError(
85
+ config.bundleId,
86
+ getDeviceName(config.device)
87
+ );
88
+ }
89
+
90
+ return {
91
+ startApp: async () => {
92
+ await devicectl.startApp(deviceId, config.bundleId);
93
+ },
94
+ restartApp: async () => {
95
+ await devicectl.stopApp(deviceId, config.bundleId);
96
+ await devicectl.startApp(deviceId, config.bundleId);
97
+ },
98
+ stopApp: async () => {
99
+ await devicectl.stopApp(deviceId, config.bundleId);
100
+ },
101
+ dispose: async () => {
102
+ await devicectl.stopApp(deviceId, config.bundleId);
103
+ },
104
+ };
105
+ };
package/src/utils.ts ADDED
@@ -0,0 +1,9 @@
1
+ import { isAppleDeviceSimulator, type AppleDevice } from './config.js';
2
+
3
+ export const getDeviceName = (device: AppleDevice): string => {
4
+ if (isAppleDeviceSimulator(device)) {
5
+ return `${device.name} (${device.systemVersion}) (simulator)`;
6
+ }
7
+
8
+ return `${device.name} (physical)`;
9
+ };
@@ -0,0 +1,153 @@
1
+ import { spawn } from '@react-native-harness/tools';
2
+ import fs from 'node:fs';
3
+ import { tmpdir } from 'node:os';
4
+ import { join } from 'node:path';
5
+ import { randomUUID } from 'node:crypto';
6
+
7
+ export const devicectl = async <TOutput>(
8
+ command: string,
9
+ args: string[]
10
+ ): Promise<TOutput> => {
11
+ const tempFile = join(tmpdir(), `devicectl-${randomUUID()}.json`);
12
+
13
+ await spawn('xcrun', [
14
+ 'devicectl',
15
+ command,
16
+ ...args,
17
+ '--json-output',
18
+ tempFile,
19
+ ]);
20
+
21
+ const output = fs.readFileSync(tempFile, 'utf8');
22
+ fs.unlinkSync(tempFile);
23
+
24
+ return JSON.parse(output).result;
25
+ };
26
+
27
+ export type AppleDeviceInfo = {
28
+ identifier: string;
29
+ deviceProperties: {
30
+ name: string;
31
+ osVersionNumber: string;
32
+ };
33
+ hardwareProperties: {
34
+ marketingName: string;
35
+ productType: string;
36
+ udid: string;
37
+ };
38
+ };
39
+
40
+ export const listDevices = async (): Promise<AppleDeviceInfo[]> => {
41
+ const result = await devicectl<{ devices: AppleDeviceInfo[] }>('list', [
42
+ 'devices',
43
+ ]);
44
+ return result.devices;
45
+ };
46
+
47
+ export type AppleAppInfo = {
48
+ bundleIdentifier: string;
49
+ name: string;
50
+ version: string;
51
+ url: string;
52
+ };
53
+
54
+ export const listApps = async (identifier: string): Promise<AppleAppInfo[]> => {
55
+ const result = await devicectl<{ apps: AppleAppInfo[] }>('device', [
56
+ 'info',
57
+ 'apps',
58
+ '--device',
59
+ identifier,
60
+ ]);
61
+ return result.apps;
62
+ };
63
+
64
+ export const getAppInfo = async (
65
+ identifier: string,
66
+ bundleId: string
67
+ ): Promise<AppleAppInfo | null> => {
68
+ const result = await devicectl<{ apps: AppleAppInfo[] }>('device', [
69
+ 'info',
70
+ 'apps',
71
+ '--device',
72
+ identifier,
73
+ '--bundle-id',
74
+ bundleId,
75
+ ]);
76
+
77
+ return result.apps[0] ?? null;
78
+ };
79
+
80
+ export const isAppInstalled = async (
81
+ identifier: string,
82
+ bundleId: string
83
+ ): Promise<boolean> => {
84
+ const apps = await listApps(identifier);
85
+ return apps.some((app) => app.bundleIdentifier === bundleId);
86
+ };
87
+
88
+ export const startApp = async (
89
+ identifier: string,
90
+ bundleId: string
91
+ ): Promise<void> => {
92
+ await devicectl('device', [
93
+ 'process',
94
+ 'launch',
95
+ '--device',
96
+ identifier,
97
+ bundleId,
98
+ ]);
99
+ };
100
+
101
+ export type AppleProcessInfo = {
102
+ executable: string;
103
+ processIdentifier: number;
104
+ };
105
+
106
+ export const getProcesses = async (
107
+ identifier: string
108
+ ): Promise<AppleProcessInfo[]> => {
109
+ const result = await devicectl<{ runningProcesses: AppleProcessInfo[] }>(
110
+ 'device',
111
+ ['info', 'processes', '--device', identifier]
112
+ );
113
+
114
+ return result.runningProcesses;
115
+ };
116
+
117
+ export const stopApp = async (
118
+ identifier: string,
119
+ bundleId: string
120
+ ): Promise<void> => {
121
+ const appInfo = await getAppInfo(identifier, bundleId);
122
+
123
+ if (!appInfo) {
124
+ return;
125
+ }
126
+
127
+ const processes = await getProcesses(identifier);
128
+ const process = processes.find((process) =>
129
+ process.executable.startsWith(appInfo.url)
130
+ );
131
+
132
+ if (!process) {
133
+ return;
134
+ }
135
+
136
+ await devicectl('device', [
137
+ 'process',
138
+ 'terminate',
139
+ '--device',
140
+ identifier,
141
+ '--pid',
142
+ process.processIdentifier.toString(),
143
+ ]);
144
+ };
145
+
146
+ export const getDeviceId = async (name: string): Promise<string | null> => {
147
+ const devices = await listDevices();
148
+ const device = devices.find(
149
+ (device) => device.deviceProperties.name === name
150
+ );
151
+
152
+ return device?.identifier ?? null;
153
+ };
@@ -0,0 +1,122 @@
1
+ import { spawn, spawnAndForget } from '@react-native-harness/tools';
2
+
3
+ const plistToJson = async (plistOutput: string): Promise<any> => {
4
+ const { stdout: jsonOutput } = await spawn(
5
+ 'plutil',
6
+ ['-convert', 'json', '-o', '-', '-'],
7
+ { stdin: { string: plistOutput } }
8
+ );
9
+ return JSON.parse(jsonOutput);
10
+ };
11
+
12
+ export type AppleAppInfo = {
13
+ Bundle: string;
14
+ CFBundleIdentifier: string;
15
+ CFBundleName: string;
16
+ CFBundleDisplayName: string;
17
+ Path: string;
18
+ };
19
+
20
+ export const getAppInfo = async (
21
+ udid: string,
22
+ bundleId: string
23
+ ): Promise<AppleAppInfo | null> => {
24
+ const { stdout: plistOutput } = await spawn('xcrun', [
25
+ 'simctl',
26
+ 'appinfo',
27
+ udid,
28
+ bundleId,
29
+ ]);
30
+
31
+ const json = await plistToJson(plistOutput);
32
+
33
+ // If there is only one entry, it means the app is not installed
34
+ const hasMoreThanOneEntry = Object.keys(json).length > 1;
35
+
36
+ if (!hasMoreThanOneEntry) {
37
+ return null;
38
+ }
39
+
40
+ return json;
41
+ };
42
+
43
+ export const isAppInstalled = async (
44
+ udid: string,
45
+ bundleId: string
46
+ ): Promise<boolean> => {
47
+ const appInfo = await getAppInfo(udid, bundleId);
48
+ return appInfo !== null;
49
+ };
50
+
51
+ export type AppleSimulatorState = 'Booted' | 'Booting' | 'Shutdown';
52
+
53
+ export type AppleSimulatorInfo = {
54
+ name: string;
55
+ udid: string;
56
+ state: AppleSimulatorState;
57
+ isAvailable: boolean;
58
+ runtime: string;
59
+ };
60
+
61
+ export const getSimulators = async (): Promise<AppleSimulatorInfo[]> => {
62
+ const { stdout } = await spawn('xcrun', [
63
+ 'simctl',
64
+ 'list',
65
+ 'devices',
66
+ '--json',
67
+ ]);
68
+ const runtimeDevices: Record<string, AppleSimulatorInfo[]> =
69
+ JSON.parse(stdout).devices;
70
+ const simulators: AppleSimulatorInfo[] = [];
71
+
72
+ Object.entries(runtimeDevices).forEach(([runtime, devices]) => {
73
+ devices.forEach((device) => {
74
+ simulators.push({
75
+ ...device,
76
+ runtime,
77
+ });
78
+ });
79
+ });
80
+
81
+ return simulators;
82
+ };
83
+
84
+ export const getSimulatorStatus = async (
85
+ udid: string
86
+ ): Promise<AppleSimulatorState> => {
87
+ const simulators = await getSimulators();
88
+ const simulator = simulators.find((s) => s.udid === udid);
89
+
90
+ if (!simulator) {
91
+ throw new Error(`Simulator with UDID ${udid} not found`);
92
+ }
93
+
94
+ return simulator.state;
95
+ };
96
+
97
+ export const startApp = async (
98
+ udid: string,
99
+ bundleId: string
100
+ ): Promise<void> => {
101
+ await spawn('xcrun', ['simctl', 'launch', udid, bundleId]);
102
+ };
103
+
104
+ export const stopApp = async (
105
+ udid: string,
106
+ bundleId: string
107
+ ): Promise<void> => {
108
+ await spawnAndForget('xcrun', ['simctl', 'terminate', udid, bundleId]);
109
+ };
110
+
111
+ export const getSimulatorId = async (
112
+ name: string,
113
+ systemVersion: string
114
+ ): Promise<string | null> => {
115
+ const simulators = await getSimulators();
116
+ const simulator = simulators.find(
117
+ (s) =>
118
+ s.name === name && s.runtime.endsWith(systemVersion.replaceAll('.', '-'))
119
+ );
120
+
121
+ return simulator?.udid ?? null;
122
+ };
package/tsconfig.json ADDED
@@ -0,0 +1,16 @@
1
+ {
2
+ "extends": "../../tsconfig.base.json",
3
+ "files": [],
4
+ "include": [],
5
+ "references": [
6
+ {
7
+ "path": "../tools"
8
+ },
9
+ {
10
+ "path": "../platforms"
11
+ },
12
+ {
13
+ "path": "./tsconfig.lib.json"
14
+ }
15
+ ]
16
+ }
@@ -0,0 +1,22 @@
1
+ {
2
+ "extends": "../../tsconfig.base.json",
3
+ "compilerOptions": {
4
+ "baseUrl": ".",
5
+ "rootDir": "src",
6
+ "outDir": "dist",
7
+ "tsBuildInfoFile": "dist/tsconfig.lib.tsbuildinfo",
8
+ "emitDeclarationOnly": false,
9
+ "forceConsistentCasingInFileNames": true,
10
+ "types": ["node"],
11
+ "lib": ["DOM", "ES2022"]
12
+ },
13
+ "include": ["src/**/*.ts"],
14
+ "references": [
15
+ {
16
+ "path": "../tools/tsconfig.lib.json"
17
+ },
18
+ {
19
+ "path": "../platforms/tsconfig.lib.json"
20
+ }
21
+ ]
22
+ }