runcloud 0.2.150 → 0.2.152

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/README.md CHANGED
@@ -80,8 +80,8 @@ runcloud ios logs <id> --tail 200 # read logs from this
80
80
  runcloud ios logs <id> --follow # follow new log entries
81
81
  runcloud ios delete <id> # release the session
82
82
 
83
- # Android also requires the Expo SDK profile used by the app; pools never substitute.
84
- runcloud android create --model pixel --expo-sdk-profile expo-57
83
+ # Android sessions use the available emulator pool.
84
+ runcloud android create --model pixel
85
85
  runcloud android swipe <id> 0.5 0.8 0.5 0.2 --duration 250
86
86
  runcloud android press-key <id> enter
87
87
  runcloud android accessibility-tree <id> --json
@@ -90,12 +90,6 @@ runcloud android mic inject <id> ./tone.wav --bundle-id com.example.Recorder
90
90
  runcloud android screenshot <id> --output android.png --json
91
91
  ```
92
92
 
93
- Use `--expo-sdk-profile expo-54` for Expo 54 projects and `expo-57` for Expo 57
94
- projects. `create`, `get`, `list`, and `mobile launch --json` expose the selected
95
- profile and immutable Expo Go APK, emulator image, toolchain, and profile
96
- digests. If that profile is full, the command returns
97
- `expo_profile_capacity_unavailable`; it does not lease the other pool.
98
-
99
93
  `open-url` accepts HTTPS URLs and application deep links on both platforms. Keep
100
94
  the complete target quoted so its URI delimiters stay in one argument:
101
95
 
@@ -314,13 +314,15 @@ function missingIosUsageDescriptions(root, appJson) {
314
314
  { name: 'camera', used: /expo-camera|CameraView|requestCameraPermissions/i, keys: ['NSCameraUsageDescription'] },
315
315
  { name: 'location', used: /expo-location|getCurrentPositionAsync|watchPositionAsync/i, keys: ['NSLocationWhenInUseUsageDescription', 'NSLocationAlwaysAndWhenInUseUsageDescription'] },
316
316
  { name: 'photos', used: /expo-image-picker|expo-media-library|MediaLibrary/i, keys: ['NSPhotoLibraryUsageDescription'] },
317
- { name: 'microphone', used: /expo-av|expo-audio|Audio\.|requestMicrophonePermissions/i, keys: ['NSMicrophoneUsageDescription'] },
317
+ { name: 'microphone', used: /expo-av|AudioRecorder|requestRecordingPermissionsAsync|requestMicrophonePermissions/i, keys: ['NSMicrophoneUsageDescription'] },
318
318
  ];
319
+ const pkg = readJson(path.join(root, 'package.json'));
320
+ const installed = new Set(['dependencies', 'devDependencies'].flatMap((field) => Object.keys(objectValue(getPath(pkg, [field])))));
319
321
  const missing = [];
320
322
  for (const check of checks) {
321
323
  if (!check.used.test(source))
322
324
  continue;
323
- if (!check.keys.some((key) => hasValue(infoPlist[key]))) {
325
+ if (!check.keys.some((key) => builtWithPurposeString(key, infoPlist, appJson, installed))) {
324
326
  missing.push(`ios ${check.name} usage description (${check.keys.join(' or ')})`);
325
327
  }
326
328
  }
@@ -333,6 +335,29 @@ function missingIosUsageDescriptions(root, appJson) {
333
335
  }
334
336
  return missing;
335
337
  }
338
+ const PLUGIN_PURPOSE_STRINGS = {
339
+ 'expo-camera': { auto: true, keys: { NSCameraUsageDescription: 'cameraPermission', NSMicrophoneUsageDescription: 'microphonePermission' } },
340
+ 'expo-image-picker': { auto: true, keys: { NSPhotoLibraryUsageDescription: 'photosPermission', NSCameraUsageDescription: 'cameraPermission', NSMicrophoneUsageDescription: 'microphonePermission' } },
341
+ 'expo-media-library': { auto: true, keys: { NSPhotoLibraryUsageDescription: 'photosPermission' } },
342
+ 'expo-av': { auto: true, keys: { NSMicrophoneUsageDescription: 'microphonePermission' } },
343
+ 'expo-location': { auto: true, keys: { NSLocationWhenInUseUsageDescription: 'locationWhenInUsePermission', NSLocationAlwaysAndWhenInUseUsageDescription: 'locationAlwaysAndWhenInUsePermission' } },
344
+ 'expo-audio': { auto: false, keys: { NSMicrophoneUsageDescription: 'microphonePermission' } },
345
+ };
346
+ function builtWithPurposeString(key, infoPlist, appJson, installed) {
347
+ let written = hasValue(infoPlist[key]);
348
+ for (const [name, plugin] of Object.entries(PLUGIN_PURPOSE_STRINGS)) {
349
+ const option = plugin.keys[key];
350
+ if (!option)
351
+ continue;
352
+ const listed = configPluginOptions(appJson, name);
353
+ if (!listed && !(plugin.auto && installed.has(name)))
354
+ continue;
355
+ if (listed?.[option] === false)
356
+ return false;
357
+ written = true;
358
+ }
359
+ return written;
360
+ }
336
361
  function configPluginOptions(appJson, name) {
337
362
  const plugins = getPath(appJson, ['expo', 'plugins']);
338
363
  if (!Array.isArray(plugins))
@@ -950,7 +950,6 @@ async function createSimulatorSession(platform, opts) {
950
950
  .filter((id) => typeof id === 'string' && id.length > 0),
951
951
  ];
952
952
  return await client().post(`/run-cloud/${platform}`, {
953
- ...(platform === 'android' ? { expoSdkProfile: opts.expoSdkProfile ?? 'expo-54' } : {}),
954
953
  ...(opts.orgId ? { orgId: opts.orgId } : {}),
955
954
  model: opts.model,
956
955
  region: opts.region,
@@ -1041,9 +1040,6 @@ function registerSimulatorCommands(program, platform) {
1041
1040
  .option('--rm', 'release the session when this command exits', false)
1042
1041
  .option('--json', 'output JSON', false)
1043
1042
  .addOption(new Option('--dev-host <host>', 'dev-only: target a specific simulator fleet host').hideHelp());
1044
- if (platform === 'android') {
1045
- createCommand.addOption(new Option('--expo-sdk-profile <profile>', 'preinstalled Expo Go version; omit when installing a custom APK').choices(['expo-54']));
1046
- }
1047
1043
  createCommand
1048
1044
  .action((opts) => action(async () => {
1049
1045
  print(await createSimulatorSession(platform, opts), opts);
@@ -1681,7 +1677,6 @@ export function registerRunCloud(program) {
1681
1677
  .option('--inactivity-timeout <duration>', 'idle timeout such as 60s, 3m, or none')
1682
1678
  .option('--hard-timeout <duration>', 'maximum lifetime such as 10m or 1h')
1683
1679
  .option('--codec <auto|mjpeg|webrtc>', 'viewer codec', 'auto')
1684
- .addOption(new Option('--expo-sdk-profile <profile>', 'preinstalled Expo Go version; omit when launching a custom APK').choices(['expo-54']))
1685
1680
  .option('--json', 'output JSON', false)
1686
1681
  .action((opts) => action(async () => {
1687
1682
  if (Boolean(opts.asset) === Boolean(opts.build)) {
@@ -1690,15 +1685,11 @@ export function registerRunCloud(program) {
1690
1685
  if (opts.platform !== 'ios' && opts.platform !== 'android') {
1691
1686
  throw new Error('--platform must be ios or android');
1692
1687
  }
1693
- if (opts.platform === 'ios' && opts.expoSdkProfile) {
1694
- throw new Error('--expo-sdk-profile is supported only when --platform android');
1695
- }
1696
1688
  print(await client().postWithHeaders('/run-cloud/mobile/launch', {
1697
1689
  ...(opts.asset ? { assetId: opts.asset } : { buildId: opts.build }),
1698
1690
  platform: opts.platform,
1699
1691
  ...(opts.orgId ? { orgId: opts.orgId } : {}),
1700
1692
  session: {
1701
- ...(opts.platform === 'android' ? { expoSdkProfile: opts.expoSdkProfile ?? 'expo-54' } : {}),
1702
1693
  ...(opts.model ? { model: opts.model } : {}),
1703
1694
  ...(opts.region ? { region: opts.region } : {}),
1704
1695
  ...(opts.displayName ? { displayName: opts.displayName } : {}),
package/dist/version.js CHANGED
@@ -1 +1 @@
1
- export const CLI_VERSION = '0.2.150';
1
+ export const CLI_VERSION = '0.2.152';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "runcloud",
3
- "version": "0.2.150",
3
+ "version": "0.2.152",
4
4
  "description": "Create and control run.cloud remote mobile simulators and cloud sandboxes",
5
5
  "license": "Apache-2.0",
6
6
  "keywords": [
Binary file
Binary file