@expo/cli 55.0.9 → 55.0.11

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 (43) hide show
  1. package/build/bin/cli +5 -1
  2. package/build/bin/cli.map +1 -1
  3. package/build/src/events/builder.js +6 -0
  4. package/build/src/events/builder.js.map +1 -0
  5. package/build/src/events/index.js +132 -0
  6. package/build/src/events/index.js.map +1 -0
  7. package/build/src/events/stream.js +303 -0
  8. package/build/src/events/stream.js.map +1 -0
  9. package/build/src/events/types.js +6 -0
  10. package/build/src/events/types.js.map +1 -0
  11. package/build/src/export/exportAssets.js +10 -9
  12. package/build/src/export/exportAssets.js.map +1 -1
  13. package/build/src/run/android/resolveGradlePropsAsync.js +22 -9
  14. package/build/src/run/android/resolveGradlePropsAsync.js.map +1 -1
  15. package/build/src/start/interface/interactiveActions.js +15 -13
  16. package/build/src/start/interface/interactiveActions.js.map +1 -1
  17. package/build/src/start/platforms/ios/devicectl.js +27 -5
  18. package/build/src/start/platforms/ios/devicectl.js.map +1 -1
  19. package/build/src/start/server/DevToolsPluginManager.js +10 -1
  20. package/build/src/start/server/DevToolsPluginManager.js.map +1 -1
  21. package/build/src/start/server/metro/MetroBundlerDevServer.js +27 -3
  22. package/build/src/start/server/metro/MetroBundlerDevServer.js.map +1 -1
  23. package/build/src/start/server/metro/MetroTerminalReporter.js +181 -79
  24. package/build/src/start/server/metro/MetroTerminalReporter.js.map +1 -1
  25. package/build/src/start/server/metro/instantiateMetro.js +53 -14
  26. package/build/src/start/server/metro/instantiateMetro.js.map +1 -1
  27. package/build/src/start/server/metro/metroErrorInterface.js +3 -5
  28. package/build/src/start/server/metro/metroErrorInterface.js.map +1 -1
  29. package/build/src/start/server/metro/runServer-fork.js +4 -1
  30. package/build/src/start/server/metro/runServer-fork.js.map +1 -1
  31. package/build/src/start/server/metro/withMetroMultiPlatform.js +1 -2
  32. package/build/src/start/server/metro/withMetroMultiPlatform.js.map +1 -1
  33. package/build/src/start/startAsync.js +4 -2
  34. package/build/src/start/startAsync.js.map +1 -1
  35. package/build/src/utils/env.js +3 -0
  36. package/build/src/utils/env.js.map +1 -1
  37. package/build/src/utils/interactive.js +2 -1
  38. package/build/src/utils/interactive.js.map +1 -1
  39. package/build/src/utils/nodeEnv.js +29 -2
  40. package/build/src/utils/nodeEnv.js.map +1 -1
  41. package/build/src/utils/telemetry/clients/FetchClient.js +1 -1
  42. package/build/src/utils/telemetry/utils/context.js +1 -1
  43. package/package.json +11 -12
@@ -26,16 +26,16 @@ function _fs() {
26
26
  };
27
27
  return data;
28
28
  }
29
- function _minimatch() {
30
- const data = require("minimatch");
31
- _minimatch = function() {
29
+ function _path() {
30
+ const data = /*#__PURE__*/ _interop_require_default(require("path"));
31
+ _path = function() {
32
32
  return data;
33
33
  };
34
34
  return data;
35
35
  }
36
- function _path() {
37
- const data = /*#__PURE__*/ _interop_require_default(require("path"));
38
- _path = function() {
36
+ function _picomatch() {
37
+ const data = /*#__PURE__*/ _interop_require_default(require("picomatch"));
38
+ _picomatch = function() {
39
39
  return data;
40
40
  };
41
41
  return data;
@@ -132,8 +132,9 @@ function assetPatternsToBeBundled(exp) {
132
132
  // needed because android doesn't support assets that start with numbers.
133
133
  const fullPatterns = assetPatternsToBeBundled.map((p)=>_path().default.join(projectRoot, p));
134
134
  logPatterns(fullPatterns);
135
+ const matches = (0, _picomatch().default)(fullPatterns);
135
136
  const allBundledAssets = assets.map((asset)=>{
136
- const shouldBundle = shouldBundleAsset(asset, fullPatterns);
137
+ const shouldBundle = shouldBundleAsset(asset, matches);
137
138
  if (shouldBundle) {
138
139
  var _asset_files;
139
140
  debug(`${shouldBundle ? 'Include' : 'Exclude'} asset ${(_asset_files = asset.files) == null ? void 0 : _asset_files[0]}`);
@@ -158,10 +159,10 @@ function logPatterns(patterns) {
158
159
  _log.log('\nProcessing asset bundle patterns:');
159
160
  patterns.forEach((p)=>_log.log('- ' + p));
160
161
  }
161
- function shouldBundleAsset(asset, patterns) {
162
+ function shouldBundleAsset(asset, matcher) {
162
163
  var _asset_files;
163
164
  const file = (_asset_files = asset.files) == null ? void 0 : _asset_files[0];
164
- return !!('__packager_asset' in asset && asset.__packager_asset && file && patterns.some((pattern)=>(0, _minimatch().minimatch)(file, pattern)));
165
+ return !!('__packager_asset' in asset && asset.__packager_asset && file && matcher(file));
165
166
  }
166
167
  async function exportAssetsAsync(projectRoot, { exp, outputDir, bundles: { web, ...bundles }, baseUrl, files = new Map(), hostedNative }) {
167
168
  var _assets_;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/export/exportAssets.ts"],"sourcesContent":["import { ExpoConfig } from '@expo/config';\nimport fs from 'fs';\nimport { minimatch } from 'minimatch';\nimport path from 'path';\n\nimport { getAssetIdForLogGrouping, persistMetroAssetsAsync } from './persistMetroAssets';\nimport type { Asset, BundleAssetWithFileHashes, BundleOutput, ExportAssetMap } from './saveAssets';\nimport * as Log from '../log';\nimport { resolveGoogleServicesFile } from '../start/server/middleware/resolveAssets';\nimport { uniqBy } from '../utils/array';\n\nconst debug = require('debug')('expo:export:exportAssets') as typeof console.log;\n\nfunction mapAssetHashToAssetString(asset: Asset, hash: string) {\n return 'asset_' + hash + ('type' in asset && asset.type ? '.' + asset.type : '');\n}\n\nexport function assetPatternsToBeBundled(\n exp: ExpoConfig & { extra?: { updates?: { assetPatternsToBeBundled?: string[] } } }\n): string[] | undefined {\n // new location for this key\n if (exp.updates?.assetPatternsToBeBundled?.length) {\n return exp.updates.assetPatternsToBeBundled;\n }\n\n // old, untyped location for this key. we may want to change this to throw in a few SDK versions (deprecated as of SDK 52).\n if (exp.extra?.updates?.assetPatternsToBeBundled?.length) {\n return exp.extra.updates.assetPatternsToBeBundled;\n }\n\n return undefined;\n}\n\n/**\n * Given an asset and a set of strings representing the assets to be bundled, returns true if\n * the asset is part of the set to be bundled.\n * @param asset Asset object\n * @param bundledAssetsSet Set of strings\n * @returns true if the asset should be bundled\n */\nfunction assetShouldBeIncludedInExport(asset: Asset, bundledAssetsSet: Set<string> | undefined) {\n if (!bundledAssetsSet) {\n return true;\n }\n return (\n asset.fileHashes.filter((hash) => bundledAssetsSet.has(mapAssetHashToAssetString(asset, hash)))\n .length > 0\n );\n}\n\n/**\n * Computes a set of strings representing the assets to be bundled with an export, given an array of assets,\n * and a set of patterns to match\n * @param assets The asset array\n * @param assetPatternsToBeBundled An array of strings with glob patterns to match\n * @param projectRoot The project root\n * @returns A set of asset strings\n */\nfunction setOfAssetsToBeBundled(\n assets: Asset[],\n assetPatternsToBeBundled: string[],\n projectRoot: string\n): Set<string> | undefined {\n // Convert asset patterns to a list of asset strings that match them.\n // Assets strings are formatted as `asset_<hash>.<type>` and represent\n // the name that the file will have in the app bundle. The `asset_` prefix is\n // needed because android doesn't support assets that start with numbers.\n\n const fullPatterns: string[] = assetPatternsToBeBundled.map((p: string) =>\n path.join(projectRoot, p)\n );\n\n logPatterns(fullPatterns);\n\n const allBundledAssets = assets\n .map((asset) => {\n const shouldBundle = shouldBundleAsset(asset, fullPatterns);\n if (shouldBundle) {\n debug(`${shouldBundle ? 'Include' : 'Exclude'} asset ${asset.files?.[0]}`);\n return asset.fileHashes.map((hash) => mapAssetHashToAssetString(asset, hash));\n }\n return [];\n })\n .flat();\n\n // The assets returned by the RN packager has duplicates so make sure we\n // only bundle each once.\n return new Set(allBundledAssets);\n}\n\n/**\n * Resolves the assetBundlePatterns from the manifest and returns the set of assets to bundle.\n *\n * @modifies {exp}\n */\nexport function resolveAssetPatternsToBeBundled<T extends ExpoConfig>(\n projectRoot: string,\n exp: T,\n assets: Asset[]\n): Set<string> | undefined {\n const assetPatternsToBeBundledForConfig = assetPatternsToBeBundled(exp);\n if (!assetPatternsToBeBundledForConfig) {\n return undefined;\n }\n const bundledAssets = setOfAssetsToBeBundled(\n assets,\n assetPatternsToBeBundledForConfig,\n projectRoot\n );\n return bundledAssets;\n}\n\nfunction logPatterns(patterns: string[]) {\n // Only log the patterns in debug mode, if they aren't already defined in the app.json, then all files will be targeted.\n Log.log('\\nProcessing asset bundle patterns:');\n patterns.forEach((p) => Log.log('- ' + p));\n}\n\nfunction shouldBundleAsset(asset: Asset, patterns: string[]) {\n const file = asset.files?.[0];\n return !!(\n '__packager_asset' in asset &&\n asset.__packager_asset &&\n file &&\n patterns.some((pattern) => minimatch(file, pattern))\n );\n}\n\nexport async function exportAssetsAsync(\n projectRoot: string,\n {\n exp,\n outputDir,\n bundles: { web, ...bundles },\n baseUrl,\n files = new Map(),\n hostedNative,\n }: {\n exp: ExpoConfig;\n bundles: Partial<Record<string, BundleOutput>>;\n outputDir: string;\n baseUrl: string;\n files?: ExportAssetMap;\n hostedNative?: boolean;\n }\n): Promise<{\n exp: ExpoConfig;\n assets: BundleAssetWithFileHashes[];\n embeddedHashSet: Set<string>;\n files: ExportAssetMap;\n}> {\n const hostedAssets: BundleAssetWithFileHashes[] = web ? [...web.assets] : [];\n\n // If the native assets should be hosted like web, then we can add them to the hosted assets to export.\n if (hostedNative) {\n hostedAssets.push(...Object.values(bundles).flatMap((bundle) => bundle!.assets ?? []));\n }\n\n if (hostedAssets.length) {\n // Save assets like a typical bundler, preserving the file paths on web.\n // TODO: Update React Native Web to support loading files from asset hashes.\n await persistMetroAssetsAsync(projectRoot, hostedAssets, {\n files,\n platform: 'web',\n outputDirectory: outputDir,\n baseUrl,\n });\n }\n\n if (hostedNative) {\n // Add google services file if it exists\n await resolveGoogleServicesFile(projectRoot, exp);\n return { exp, assets: [], embeddedHashSet: new Set(), files };\n }\n\n const assets: BundleAssetWithFileHashes[] = uniqBy(\n Object.values(bundles).flatMap((bundle) => bundle!.assets),\n (asset) => asset.hash\n );\n\n let bundledAssetsSet: Set<string> | undefined = undefined;\n let filteredAssets = assets;\n const embeddedHashSet: Set<string> = new Set();\n\n if (assets[0]?.fileHashes) {\n debug(`Assets = ${JSON.stringify(assets, null, 2)}`);\n // Updates the manifest to reflect additional asset bundling + configs\n // Get only asset strings for assets we will save\n bundledAssetsSet = resolveAssetPatternsToBeBundled(projectRoot, exp, assets);\n if (bundledAssetsSet) {\n debug(`Bundled assets = ${JSON.stringify([...bundledAssetsSet], null, 2)}`);\n // Filter asset objects to only ones that include assetPatternsToBeBundled matches\n filteredAssets = assets.filter((asset) => {\n const shouldInclude = assetShouldBeIncludedInExport(asset, bundledAssetsSet);\n if (!shouldInclude) {\n embeddedHashSet.add(asset.hash);\n }\n return shouldInclude;\n });\n debug(`Filtered assets count = ${filteredAssets.length}`);\n }\n\n const hashes = new Set<string>();\n\n // Add assets to copy.\n filteredAssets.forEach((asset) => {\n const assetId = getAssetIdForLogGrouping(projectRoot, asset);\n\n asset.files.forEach((fp: string, index: number) => {\n const hash = asset.fileHashes[index];\n if (hashes.has(hash)) return;\n hashes.add(hash);\n files.set(path.join('assets', hash), {\n originFilename: path.relative(projectRoot, fp),\n contents: fs.readFileSync(fp),\n assetId,\n });\n });\n });\n }\n\n // Add google services file if it exists\n await resolveGoogleServicesFile(projectRoot, exp);\n\n return { exp, assets, embeddedHashSet, files };\n}\n"],"names":["assetPatternsToBeBundled","exportAssetsAsync","resolveAssetPatternsToBeBundled","debug","require","mapAssetHashToAssetString","asset","hash","type","exp","updates","length","extra","undefined","assetShouldBeIncludedInExport","bundledAssetsSet","fileHashes","filter","has","setOfAssetsToBeBundled","assets","projectRoot","fullPatterns","map","p","path","join","logPatterns","allBundledAssets","shouldBundle","shouldBundleAsset","files","flat","Set","assetPatternsToBeBundledForConfig","bundledAssets","patterns","Log","log","forEach","file","__packager_asset","some","pattern","minimatch","outputDir","bundles","web","baseUrl","Map","hostedNative","hostedAssets","push","Object","values","flatMap","bundle","persistMetroAssetsAsync","platform","outputDirectory","resolveGoogleServicesFile","embeddedHashSet","uniqBy","filteredAssets","JSON","stringify","shouldInclude","add","hashes","assetId","getAssetIdForLogGrouping","fp","index","set","originFilename","relative","contents","fs","readFileSync"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../src/export/exportAssets.ts"],"sourcesContent":["import { ExpoConfig } from '@expo/config';\nimport fs from 'fs';\nimport path from 'path';\nimport picomatch from 'picomatch';\n\nimport { getAssetIdForLogGrouping, persistMetroAssetsAsync } from './persistMetroAssets';\nimport type { Asset, BundleAssetWithFileHashes, BundleOutput, ExportAssetMap } from './saveAssets';\nimport * as Log from '../log';\nimport { resolveGoogleServicesFile } from '../start/server/middleware/resolveAssets';\nimport { uniqBy } from '../utils/array';\n\nconst debug = require('debug')('expo:export:exportAssets') as typeof console.log;\n\nfunction mapAssetHashToAssetString(asset: Asset, hash: string) {\n return 'asset_' + hash + ('type' in asset && asset.type ? '.' + asset.type : '');\n}\n\nexport function assetPatternsToBeBundled(\n exp: ExpoConfig & { extra?: { updates?: { assetPatternsToBeBundled?: string[] } } }\n): string[] | undefined {\n // new location for this key\n if (exp.updates?.assetPatternsToBeBundled?.length) {\n return exp.updates.assetPatternsToBeBundled;\n }\n\n // old, untyped location for this key. we may want to change this to throw in a few SDK versions (deprecated as of SDK 52).\n if (exp.extra?.updates?.assetPatternsToBeBundled?.length) {\n return exp.extra.updates.assetPatternsToBeBundled;\n }\n\n return undefined;\n}\n\n/**\n * Given an asset and a set of strings representing the assets to be bundled, returns true if\n * the asset is part of the set to be bundled.\n * @param asset Asset object\n * @param bundledAssetsSet Set of strings\n * @returns true if the asset should be bundled\n */\nfunction assetShouldBeIncludedInExport(asset: Asset, bundledAssetsSet: Set<string> | undefined) {\n if (!bundledAssetsSet) {\n return true;\n }\n return (\n asset.fileHashes.filter((hash) => bundledAssetsSet.has(mapAssetHashToAssetString(asset, hash)))\n .length > 0\n );\n}\n\n/**\n * Computes a set of strings representing the assets to be bundled with an export, given an array of assets,\n * and a set of patterns to match\n * @param assets The asset array\n * @param assetPatternsToBeBundled An array of strings with glob patterns to match\n * @param projectRoot The project root\n * @returns A set of asset strings\n */\nfunction setOfAssetsToBeBundled(\n assets: Asset[],\n assetPatternsToBeBundled: string[],\n projectRoot: string\n): Set<string> | undefined {\n // Convert asset patterns to a list of asset strings that match them.\n // Assets strings are formatted as `asset_<hash>.<type>` and represent\n // the name that the file will have in the app bundle. The `asset_` prefix is\n // needed because android doesn't support assets that start with numbers.\n\n const fullPatterns: string[] = assetPatternsToBeBundled.map((p: string) =>\n path.join(projectRoot, p)\n );\n\n logPatterns(fullPatterns);\n const matches = picomatch(fullPatterns);\n const allBundledAssets = assets\n .map((asset) => {\n const shouldBundle = shouldBundleAsset(asset, matches);\n if (shouldBundle) {\n debug(`${shouldBundle ? 'Include' : 'Exclude'} asset ${asset.files?.[0]}`);\n return asset.fileHashes.map((hash) => mapAssetHashToAssetString(asset, hash));\n }\n return [];\n })\n .flat();\n\n // The assets returned by the RN packager has duplicates so make sure we\n // only bundle each once.\n return new Set(allBundledAssets);\n}\n\n/**\n * Resolves the assetBundlePatterns from the manifest and returns the set of assets to bundle.\n *\n * @modifies {exp}\n */\nexport function resolveAssetPatternsToBeBundled<T extends ExpoConfig>(\n projectRoot: string,\n exp: T,\n assets: Asset[]\n): Set<string> | undefined {\n const assetPatternsToBeBundledForConfig = assetPatternsToBeBundled(exp);\n if (!assetPatternsToBeBundledForConfig) {\n return undefined;\n }\n const bundledAssets = setOfAssetsToBeBundled(\n assets,\n assetPatternsToBeBundledForConfig,\n projectRoot\n );\n return bundledAssets;\n}\n\nfunction logPatterns(patterns: string[]) {\n // Only log the patterns in debug mode, if they aren't already defined in the app.json, then all files will be targeted.\n Log.log('\\nProcessing asset bundle patterns:');\n patterns.forEach((p) => Log.log('- ' + p));\n}\n\nfunction shouldBundleAsset(asset: Asset, matcher: picomatch.Matcher) {\n const file = asset.files?.[0];\n return !!('__packager_asset' in asset && asset.__packager_asset && file && matcher(file));\n}\n\nexport async function exportAssetsAsync(\n projectRoot: string,\n {\n exp,\n outputDir,\n bundles: { web, ...bundles },\n baseUrl,\n files = new Map(),\n hostedNative,\n }: {\n exp: ExpoConfig;\n bundles: Partial<Record<string, BundleOutput>>;\n outputDir: string;\n baseUrl: string;\n files?: ExportAssetMap;\n hostedNative?: boolean;\n }\n): Promise<{\n exp: ExpoConfig;\n assets: BundleAssetWithFileHashes[];\n embeddedHashSet: Set<string>;\n files: ExportAssetMap;\n}> {\n const hostedAssets: BundleAssetWithFileHashes[] = web ? [...web.assets] : [];\n\n // If the native assets should be hosted like web, then we can add them to the hosted assets to export.\n if (hostedNative) {\n hostedAssets.push(...Object.values(bundles).flatMap((bundle) => bundle!.assets ?? []));\n }\n\n if (hostedAssets.length) {\n // Save assets like a typical bundler, preserving the file paths on web.\n // TODO: Update React Native Web to support loading files from asset hashes.\n await persistMetroAssetsAsync(projectRoot, hostedAssets, {\n files,\n platform: 'web',\n outputDirectory: outputDir,\n baseUrl,\n });\n }\n\n if (hostedNative) {\n // Add google services file if it exists\n await resolveGoogleServicesFile(projectRoot, exp);\n return { exp, assets: [], embeddedHashSet: new Set(), files };\n }\n\n const assets: BundleAssetWithFileHashes[] = uniqBy(\n Object.values(bundles).flatMap((bundle) => bundle!.assets),\n (asset) => asset.hash\n );\n\n let bundledAssetsSet: Set<string> | undefined = undefined;\n let filteredAssets = assets;\n const embeddedHashSet: Set<string> = new Set();\n\n if (assets[0]?.fileHashes) {\n debug(`Assets = ${JSON.stringify(assets, null, 2)}`);\n // Updates the manifest to reflect additional asset bundling + configs\n // Get only asset strings for assets we will save\n bundledAssetsSet = resolveAssetPatternsToBeBundled(projectRoot, exp, assets);\n if (bundledAssetsSet) {\n debug(`Bundled assets = ${JSON.stringify([...bundledAssetsSet], null, 2)}`);\n // Filter asset objects to only ones that include assetPatternsToBeBundled matches\n filteredAssets = assets.filter((asset) => {\n const shouldInclude = assetShouldBeIncludedInExport(asset, bundledAssetsSet);\n if (!shouldInclude) {\n embeddedHashSet.add(asset.hash);\n }\n return shouldInclude;\n });\n debug(`Filtered assets count = ${filteredAssets.length}`);\n }\n\n const hashes = new Set<string>();\n\n // Add assets to copy.\n filteredAssets.forEach((asset) => {\n const assetId = getAssetIdForLogGrouping(projectRoot, asset);\n\n asset.files.forEach((fp: string, index: number) => {\n const hash = asset.fileHashes[index];\n if (hashes.has(hash)) return;\n hashes.add(hash);\n files.set(path.join('assets', hash), {\n originFilename: path.relative(projectRoot, fp),\n contents: fs.readFileSync(fp),\n assetId,\n });\n });\n });\n }\n\n // Add google services file if it exists\n await resolveGoogleServicesFile(projectRoot, exp);\n\n return { exp, assets, embeddedHashSet, files };\n}\n"],"names":["assetPatternsToBeBundled","exportAssetsAsync","resolveAssetPatternsToBeBundled","debug","require","mapAssetHashToAssetString","asset","hash","type","exp","updates","length","extra","undefined","assetShouldBeIncludedInExport","bundledAssetsSet","fileHashes","filter","has","setOfAssetsToBeBundled","assets","projectRoot","fullPatterns","map","p","path","join","logPatterns","matches","picomatch","allBundledAssets","shouldBundle","shouldBundleAsset","files","flat","Set","assetPatternsToBeBundledForConfig","bundledAssets","patterns","Log","log","forEach","matcher","file","__packager_asset","outputDir","bundles","web","baseUrl","Map","hostedNative","hostedAssets","push","Object","values","flatMap","bundle","persistMetroAssetsAsync","platform","outputDirectory","resolveGoogleServicesFile","embeddedHashSet","uniqBy","filteredAssets","JSON","stringify","shouldInclude","add","hashes","assetId","getAssetIdForLogGrouping","fp","index","set","originFilename","relative","contents","fs","readFileSync"],"mappings":"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"}
@@ -40,25 +40,38 @@ async function resolveGradlePropsAsync(projectRoot, options, device) {
40
40
  // NOTE(EvanBacon): Why would this be different? Can we get the different name?
41
41
  const appName = 'app';
42
42
  const apkDirectory = _path().default.join(projectRoot, 'android', appName, 'build', 'outputs', 'apk');
43
- // buildDeveloperTrust -> buildtype: trust, flavors: build, developer
43
+ // buildDeveloperTrust -> buildtype: trust, flavors: buildDeveloper
44
44
  // developmentDebug -> buildType: debug, flavors: development
45
45
  // productionRelease -> buildType: release, flavors: production
46
- // This won't work for non-standard flavor names like "myFlavor" would be treated as "my", "flavor".
47
- const flavors = variant.split(/(?=[A-Z])/).map((v)=>v.toLowerCase());
48
- const buildType = flavors.pop() ?? 'debug';
49
- const apkVariantDirectory = _path().default.join(apkDirectory, ...flavors, buildType);
50
- const architectures = await getConnectedDeviceABIS(buildType, device, options.allArch);
46
+ // previewDebugOptimized -> buildType: debugOptimized, flavors: preview
47
+ const parts = variant.split(/(?=[A-Z])/);
48
+ // Special case: merge 'Optimized' suffix with preceding part, e.g. into 'debugOptimized'
49
+ let buildType = parts.pop() ?? 'debug';
50
+ if (parts.length > 0 && buildType === 'Optimized') {
51
+ buildType = parts.pop().toLowerCase() + buildType;
52
+ } else {
53
+ buildType = buildType.toLowerCase();
54
+ }
55
+ let apkVariantDirectory;
56
+ if (parts.length > 0) {
57
+ const flavorPath = parts[0].toLowerCase() + parts.slice(1).join('');
58
+ apkVariantDirectory = _path().default.join(apkDirectory, flavorPath, buildType);
59
+ } else {
60
+ apkVariantDirectory = _path().default.join(apkDirectory, buildType);
61
+ }
51
62
  return {
52
63
  appName,
53
64
  buildType,
54
- flavors,
65
+ flavors: parts.map((v)=>v.toLowerCase()),
55
66
  apkVariantDirectory,
56
- architectures
67
+ architectures: await getConnectedDeviceABIS(buildType, device, options.allArch)
57
68
  };
58
69
  }
59
70
  async function getConnectedDeviceABIS(buildType, device, allArch) {
60
71
  // Follow the same behavior as iOS, only enable this for debug builds
61
- if (allArch || buildType !== 'debug') {
72
+ // Support both 'debug' and 'debugOptimized' build types
73
+ const isDebugBuild = buildType === 'debug' || buildType === 'debugOptimized';
74
+ if (allArch || !isDebugBuild) {
62
75
  return '';
63
76
  }
64
77
  const abis = await (0, _adb.getDeviceABIsAsync)(device);
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/run/android/resolveGradlePropsAsync.ts"],"sourcesContent":["import path from 'path';\n\nimport { Device, getDeviceABIsAsync } from '../../start/platforms/android/adb';\nimport { CommandError } from '../../utils/errors';\n\n// Supported ABIs for Android. see https://developer.android.com/ndk/guides/abis\nconst VALID_ARCHITECTURES = ['armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64'];\n\nexport type GradleProps = {\n /** Directory for the APK based on the `variant`. */\n apkVariantDirectory: string;\n /** Name of the app, used in the `apkVariantDirectory`. */\n appName: string;\n /** Last section of the provided `variant`, indicates the starting directory of the file name for the output APK. E.g. \"debug\" or \"release\" */\n buildType: string;\n /** Used to assemble the APK, also included in the output APK filename. */\n flavors?: string[];\n /** Architectures to build for. */\n architectures?: string;\n};\n\nfunction assertVariant(variant?: string) {\n if (variant && typeof variant !== 'string') {\n throw new CommandError('BAD_ARGS', '--variant must be a string');\n }\n return variant ?? 'debug';\n}\n\nexport async function resolveGradlePropsAsync(\n projectRoot: string,\n options: { variant?: string; allArch?: boolean },\n device: Device\n): Promise<GradleProps> {\n const variant = assertVariant(options.variant);\n // NOTE(EvanBacon): Why would this be different? Can we get the different name?\n const appName = 'app';\n\n const apkDirectory = path.join(projectRoot, 'android', appName, 'build', 'outputs', 'apk');\n\n // buildDeveloperTrust -> buildtype: trust, flavors: build, developer\n // developmentDebug -> buildType: debug, flavors: development\n // productionRelease -> buildType: release, flavors: production\n // This won't work for non-standard flavor names like \"myFlavor\" would be treated as \"my\", \"flavor\".\n const flavors = variant.split(/(?=[A-Z])/).map((v) => v.toLowerCase());\n const buildType = flavors.pop() ?? 'debug';\n\n const apkVariantDirectory = path.join(apkDirectory, ...flavors, buildType);\n const architectures = await getConnectedDeviceABIS(buildType, device, options.allArch);\n\n return {\n appName,\n buildType,\n flavors,\n apkVariantDirectory,\n architectures,\n };\n}\n\nasync function getConnectedDeviceABIS(\n buildType: string,\n device: Device,\n allArch?: boolean\n): Promise<string> {\n // Follow the same behavior as iOS, only enable this for debug builds\n if (allArch || buildType !== 'debug') {\n return '';\n }\n\n const abis = await getDeviceABIsAsync(device);\n\n const validAbis = abis.filter((abi) => VALID_ARCHITECTURES.includes(abi));\n return validAbis.filter((abi, i, arr) => arr.indexOf(abi) === i).join(',');\n}\n"],"names":["resolveGradlePropsAsync","VALID_ARCHITECTURES","assertVariant","variant","CommandError","projectRoot","options","device","appName","apkDirectory","path","join","flavors","split","map","v","toLowerCase","buildType","pop","apkVariantDirectory","architectures","getConnectedDeviceABIS","allArch","abis","getDeviceABIsAsync","validAbis","filter","abi","includes","i","arr","indexOf"],"mappings":";;;;+BA4BsBA;;;eAAAA;;;;gEA5BL;;;;;;qBAE0B;wBACd;;;;;;AAE7B,gFAAgF;AAChF,MAAMC,sBAAsB;IAAC;IAAe;IAAa;IAAO;CAAS;AAezE,SAASC,cAAcC,OAAgB;IACrC,IAAIA,WAAW,OAAOA,YAAY,UAAU;QAC1C,MAAM,IAAIC,oBAAY,CAAC,YAAY;IACrC;IACA,OAAOD,WAAW;AACpB;AAEO,eAAeH,wBACpBK,WAAmB,EACnBC,OAAgD,EAChDC,MAAc;IAEd,MAAMJ,UAAUD,cAAcI,QAAQH,OAAO;IAC7C,+EAA+E;IAC/E,MAAMK,UAAU;IAEhB,MAAMC,eAAeC,eAAI,CAACC,IAAI,CAACN,aAAa,WAAWG,SAAS,SAAS,WAAW;IAEpF,qEAAqE;IACrE,6DAA6D;IAC7D,+DAA+D;IAC/D,oGAAoG;IACpG,MAAMI,UAAUT,QAAQU,KAAK,CAAC,aAAaC,GAAG,CAAC,CAACC,IAAMA,EAAEC,WAAW;IACnE,MAAMC,YAAYL,QAAQM,GAAG,MAAM;IAEnC,MAAMC,sBAAsBT,eAAI,CAACC,IAAI,CAACF,iBAAiBG,SAASK;IAChE,MAAMG,gBAAgB,MAAMC,uBAAuBJ,WAAWV,QAAQD,QAAQgB,OAAO;IAErF,OAAO;QACLd;QACAS;QACAL;QACAO;QACAC;IACF;AACF;AAEA,eAAeC,uBACbJ,SAAiB,EACjBV,MAAc,EACde,OAAiB;IAEjB,qEAAqE;IACrE,IAAIA,WAAWL,cAAc,SAAS;QACpC,OAAO;IACT;IAEA,MAAMM,OAAO,MAAMC,IAAAA,uBAAkB,EAACjB;IAEtC,MAAMkB,YAAYF,KAAKG,MAAM,CAAC,CAACC,MAAQ1B,oBAAoB2B,QAAQ,CAACD;IACpE,OAAOF,UAAUC,MAAM,CAAC,CAACC,KAAKE,GAAGC,MAAQA,IAAIC,OAAO,CAACJ,SAASE,GAAGlB,IAAI,CAAC;AACxE"}
1
+ {"version":3,"sources":["../../../../src/run/android/resolveGradlePropsAsync.ts"],"sourcesContent":["import path from 'path';\n\nimport { Device, getDeviceABIsAsync } from '../../start/platforms/android/adb';\nimport { CommandError } from '../../utils/errors';\n\n// Supported ABIs for Android. see https://developer.android.com/ndk/guides/abis\nconst VALID_ARCHITECTURES = ['armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64'];\n\nexport type GradleProps = {\n /** Directory for the APK based on the `variant`. */\n apkVariantDirectory: string;\n /** Name of the app, used in the `apkVariantDirectory`. */\n appName: string;\n /** Last section of the provided `variant`, indicates the starting directory of the file name for the output APK. E.g. \"debug\" or \"release\" */\n buildType: string;\n /** Used to assemble the APK, also included in the output APK filename. */\n flavors?: string[];\n /** Architectures to build for. */\n architectures?: string;\n};\n\nfunction assertVariant(variant?: string) {\n if (variant && typeof variant !== 'string') {\n throw new CommandError('BAD_ARGS', '--variant must be a string');\n }\n return variant ?? 'debug';\n}\n\nexport async function resolveGradlePropsAsync(\n projectRoot: string,\n options: { variant?: string; allArch?: boolean },\n device: Device\n): Promise<GradleProps> {\n const variant = assertVariant(options.variant);\n // NOTE(EvanBacon): Why would this be different? Can we get the different name?\n const appName = 'app';\n\n const apkDirectory = path.join(projectRoot, 'android', appName, 'build', 'outputs', 'apk');\n\n // buildDeveloperTrust -> buildtype: trust, flavors: buildDeveloper\n // developmentDebug -> buildType: debug, flavors: development\n // productionRelease -> buildType: release, flavors: production\n // previewDebugOptimized -> buildType: debugOptimized, flavors: preview\n const parts = variant.split(/(?=[A-Z])/);\n\n // Special case: merge 'Optimized' suffix with preceding part, e.g. into 'debugOptimized'\n let buildType = parts.pop() ?? 'debug';\n if (parts.length > 0 && buildType === 'Optimized') {\n buildType = parts.pop()!.toLowerCase() + buildType;\n } else {\n buildType = buildType.toLowerCase();\n }\n\n let apkVariantDirectory: string;\n if (parts.length > 0) {\n const flavorPath = parts[0].toLowerCase() + parts.slice(1).join('');\n apkVariantDirectory = path.join(apkDirectory, flavorPath, buildType);\n } else {\n apkVariantDirectory = path.join(apkDirectory, buildType);\n }\n\n return {\n appName,\n buildType,\n flavors: parts.map((v) => v.toLowerCase()),\n apkVariantDirectory,\n architectures: await getConnectedDeviceABIS(buildType, device, options.allArch),\n };\n}\n\nasync function getConnectedDeviceABIS(\n buildType: string,\n device: Device,\n allArch?: boolean\n): Promise<string> {\n // Follow the same behavior as iOS, only enable this for debug builds\n // Support both 'debug' and 'debugOptimized' build types\n const isDebugBuild = buildType === 'debug' || buildType === 'debugOptimized';\n if (allArch || !isDebugBuild) {\n return '';\n }\n\n const abis = await getDeviceABIsAsync(device);\n\n const validAbis = abis.filter((abi) => VALID_ARCHITECTURES.includes(abi));\n return validAbis.filter((abi, i, arr) => arr.indexOf(abi) === i).join(',');\n}\n"],"names":["resolveGradlePropsAsync","VALID_ARCHITECTURES","assertVariant","variant","CommandError","projectRoot","options","device","appName","apkDirectory","path","join","parts","split","buildType","pop","length","toLowerCase","apkVariantDirectory","flavorPath","slice","flavors","map","v","architectures","getConnectedDeviceABIS","allArch","isDebugBuild","abis","getDeviceABIsAsync","validAbis","filter","abi","includes","i","arr","indexOf"],"mappings":";;;;+BA4BsBA;;;eAAAA;;;;gEA5BL;;;;;;qBAE0B;wBACd;;;;;;AAE7B,gFAAgF;AAChF,MAAMC,sBAAsB;IAAC;IAAe;IAAa;IAAO;CAAS;AAezE,SAASC,cAAcC,OAAgB;IACrC,IAAIA,WAAW,OAAOA,YAAY,UAAU;QAC1C,MAAM,IAAIC,oBAAY,CAAC,YAAY;IACrC;IACA,OAAOD,WAAW;AACpB;AAEO,eAAeH,wBACpBK,WAAmB,EACnBC,OAAgD,EAChDC,MAAc;IAEd,MAAMJ,UAAUD,cAAcI,QAAQH,OAAO;IAC7C,+EAA+E;IAC/E,MAAMK,UAAU;IAEhB,MAAMC,eAAeC,eAAI,CAACC,IAAI,CAACN,aAAa,WAAWG,SAAS,SAAS,WAAW;IAEpF,mEAAmE;IACnE,6DAA6D;IAC7D,+DAA+D;IAC/D,uEAAuE;IACvE,MAAMI,QAAQT,QAAQU,KAAK,CAAC;IAE5B,yFAAyF;IACzF,IAAIC,YAAYF,MAAMG,GAAG,MAAM;IAC/B,IAAIH,MAAMI,MAAM,GAAG,KAAKF,cAAc,aAAa;QACjDA,YAAYF,MAAMG,GAAG,GAAIE,WAAW,KAAKH;IAC3C,OAAO;QACLA,YAAYA,UAAUG,WAAW;IACnC;IAEA,IAAIC;IACJ,IAAIN,MAAMI,MAAM,GAAG,GAAG;QACpB,MAAMG,aAAaP,KAAK,CAAC,EAAE,CAACK,WAAW,KAAKL,MAAMQ,KAAK,CAAC,GAAGT,IAAI,CAAC;QAChEO,sBAAsBR,eAAI,CAACC,IAAI,CAACF,cAAcU,YAAYL;IAC5D,OAAO;QACLI,sBAAsBR,eAAI,CAACC,IAAI,CAACF,cAAcK;IAChD;IAEA,OAAO;QACLN;QACAM;QACAO,SAAST,MAAMU,GAAG,CAAC,CAACC,IAAMA,EAAEN,WAAW;QACvCC;QACAM,eAAe,MAAMC,uBAAuBX,WAAWP,QAAQD,QAAQoB,OAAO;IAChF;AACF;AAEA,eAAeD,uBACbX,SAAiB,EACjBP,MAAc,EACdmB,OAAiB;IAEjB,qEAAqE;IACrE,wDAAwD;IACxD,MAAMC,eAAeb,cAAc,WAAWA,cAAc;IAC5D,IAAIY,WAAW,CAACC,cAAc;QAC5B,OAAO;IACT;IAEA,MAAMC,OAAO,MAAMC,IAAAA,uBAAkB,EAACtB;IAEtC,MAAMuB,YAAYF,KAAKG,MAAM,CAAC,CAACC,MAAQ/B,oBAAoBgC,QAAQ,CAACD;IACpE,OAAOF,UAAUC,MAAM,CAAC,CAACC,KAAKE,GAAGC,MAAQA,IAAIC,OAAO,CAACJ,SAASE,GAAGvB,IAAI,CAAC;AACxE"}
@@ -92,20 +92,22 @@ class DevServerManagerActions {
92
92
  })}`);
93
93
  rows--;
94
94
  }
95
- const qr = (0, _qr.printQRCode)(interstitialPageUrl ?? nativeRuntimeUrl);
96
- rows -= qr.lines;
97
- qr.print();
98
- let qrMessage = '';
99
- if (!options.devClient) {
100
- qrMessage = `Scan the QR code above to open in ${(0, _chalk().default)`{bold Expo Go}`}.`;
101
- } else {
102
- qrMessage = (0, _chalk().default)`Scan the QR code above to open in a {bold development build}.`;
103
- qrMessage += ` (${(0, _link.learnMore)('https://expo.fyi/start')})`;
95
+ if (!_env.env.EXPO_NO_QR_CODE) {
96
+ const qr = (0, _qr.printQRCode)(interstitialPageUrl ?? nativeRuntimeUrl);
97
+ rows -= qr.lines;
98
+ qr.print();
99
+ let qrMessage = '';
100
+ if (!options.devClient) {
101
+ qrMessage = `Scan the QR code above to open in ${(0, _chalk().default)`{bold Expo Go}`}.`;
102
+ } else {
103
+ qrMessage = (0, _chalk().default)`Scan the QR code above to open in a {bold development build}.`;
104
+ qrMessage += ` (${(0, _link.learnMore)('https://expo.fyi/start')})`;
105
+ }
106
+ rows--;
107
+ _log.log((0, _commandsTable.printItem)(qrMessage, {
108
+ dim: true
109
+ }));
104
110
  }
105
- rows--;
106
- _log.log((0, _commandsTable.printItem)(qrMessage, {
107
- dim: true
108
- }));
109
111
  if (interstitialPageUrl) {
110
112
  rows--;
111
113
  _log.log((0, _commandsTable.printItem)((0, _chalk().default)`Choose an app to open your project at {underline ${interstitialPageUrl}}`));
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/start/interface/interactiveActions.ts"],"sourcesContent":["import chalk from 'chalk';\n\nimport { BLT, printHelp, printItem, printUsage, StartOptions } from './commandsTable';\nimport { createDevToolsMenuItems } from './createDevToolsMenuItems';\nimport * as Log from '../../log';\nimport { env } from '../../utils/env';\nimport { learnMore } from '../../utils/link';\nimport { ExpoChoice, selectAsync } from '../../utils/prompts';\nimport { printQRCode } from '../../utils/qr';\nimport { DevServerManager } from '../server/DevServerManager';\nimport {\n openJsInspector,\n queryAllInspectorAppsAsync,\n promptInspectorAppAsync,\n} from '../server/middleware/inspector/JsInspector';\n\nconst debug = require('debug')('expo:start:interface:interactiveActions') as typeof console.log;\n\ninterface MoreToolMenuItem extends ExpoChoice<string> {\n action?: () => unknown;\n}\n\n/** Wraps the DevServerManager and adds an interface for user actions. */\nexport class DevServerManagerActions {\n constructor(\n private devServerManager: DevServerManager,\n private options: Pick<StartOptions, 'devClient' | 'platforms'>\n ) {}\n\n printDevServerInfo(\n options: Pick<StartOptions, 'devClient' | 'isWebSocketsEnabled' | 'platforms'>\n ) {\n // Keep track of approximately how much space we have to print our usage guide\n let rows = process.stdout.rows || Infinity;\n\n // If native dev server is running, print its URL.\n if (this.devServerManager.getNativeDevServerPort()) {\n const devServer = this.devServerManager.getDefaultDevServer();\n try {\n const nativeRuntimeUrl = devServer.getNativeRuntimeUrl()!;\n const interstitialPageUrl = devServer.getRedirectUrl();\n\n // Print the URL to stdout for tests\n if (env.__EXPO_E2E_TEST) {\n console.info(\n `[__EXPO_E2E_TEST:server] ${JSON.stringify({ url: devServer.getDevServerUrl() })}`\n );\n rows--;\n }\n\n const qr = printQRCode(interstitialPageUrl ?? nativeRuntimeUrl);\n rows -= qr.lines;\n qr.print();\n\n let qrMessage = '';\n if (!options.devClient) {\n qrMessage = `Scan the QR code above to open in ${chalk`{bold Expo Go}`}.`;\n } else {\n qrMessage = chalk`Scan the QR code above to open in a {bold development build}.`;\n qrMessage += ` (${learnMore('https://expo.fyi/start')})`;\n }\n rows--;\n Log.log(printItem(qrMessage, { dim: true }));\n\n if (interstitialPageUrl) {\n rows--;\n Log.log(\n printItem(\n chalk`Choose an app to open your project at {underline ${interstitialPageUrl}}`\n )\n );\n }\n\n rows--;\n Log.log(printItem(chalk`Metro: {underline ${nativeRuntimeUrl}}`));\n } catch (error) {\n console.log('err', error);\n // @ts-ignore: If there is no development build scheme, then skip the QR code.\n if (error.code !== 'NO_DEV_CLIENT_SCHEME') {\n throw error;\n } else {\n const serverUrl = devServer.getDevServerUrl();\n Log.log(printItem(chalk`Metro: {underline ${serverUrl}}`));\n Log.log(printItem(`Linking is disabled because the client scheme cannot be resolved.`));\n rows -= 2;\n }\n }\n }\n\n if (this.options.platforms?.includes('web')) {\n const webDevServer = this.devServerManager.getWebDevServer();\n const webUrl = webDevServer?.getDevServerUrl({ hostType: 'localhost' });\n if (webUrl) {\n Log.log(printItem(chalk`Web: {underline ${webUrl}}`));\n rows--;\n }\n }\n\n printUsage(options, { verbose: false, rows });\n printHelp();\n Log.log();\n }\n\n async openJsInspectorAsync() {\n try {\n const metroServerOrigin = this.devServerManager.getDefaultDevServer().getJsInspectorBaseUrl();\n const apps = await queryAllInspectorAppsAsync(metroServerOrigin);\n if (!apps.length) {\n return Log.warn(\n chalk`{bold Debug:} No compatible apps connected, React Native DevTools can only be used with Hermes. ${learnMore(\n 'https://docs.expo.dev/guides/using-hermes/'\n )}`\n );\n }\n\n const app = await promptInspectorAppAsync(apps);\n if (!app) {\n return Log.error(chalk`{bold Debug:} No inspectable device selected`);\n }\n\n if (!(await openJsInspector(metroServerOrigin, app))) {\n Log.warn(\n chalk`{bold Debug:} Failed to open the React Native DevTools, see debug logs for more info.`\n );\n }\n } catch (error: any) {\n // Handle aborting prompt\n if (error.code === 'ABORTED') return;\n\n Log.error('Failed to open the React Native DevTools.');\n Log.exception(error);\n }\n }\n\n reloadApp() {\n Log.log(`${BLT} Reloading apps`);\n // Send reload requests over the dev servers\n this.devServerManager.broadcastMessage('reload');\n }\n\n async openMoreToolsAsync() {\n // Options match: Chrome > View > Developer\n try {\n const defaultMenuItems: MoreToolMenuItem[] = [\n { title: 'Inspect elements', value: 'toggleElementInspector' },\n { title: 'Toggle performance monitor', value: 'togglePerformanceMonitor' },\n { title: 'Toggle developer menu', value: 'toggleDevMenu' },\n { title: 'Reload app', value: 'reload' },\n // TODO: Maybe a \"View Source\" option to open code.\n ];\n\n const defaultServerUrl = this.devServerManager\n .getDefaultDevServer()\n .getUrlCreator()\n .constructUrl({ scheme: 'http' });\n\n const metroServerOrigin = this.devServerManager.getDefaultDevServer().getJsInspectorBaseUrl();\n const plugins = await this.devServerManager.devtoolsPluginManager.queryPluginsAsync();\n\n const menuItems = [\n ...defaultMenuItems,\n ...createDevToolsMenuItems(plugins, defaultServerUrl, metroServerOrigin),\n ];\n\n const value = await selectAsync(chalk`Dev tools {dim (native only)}`, menuItems);\n const menuItem = menuItems.find((item) => item.value === value);\n if (menuItem?.action) {\n menuItem.action();\n } else if (menuItem?.value) {\n this.devServerManager.broadcastMessage('sendDevCommand', { name: menuItem.value });\n }\n } catch (error: any) {\n debug(error);\n // do nothing\n } finally {\n printHelp();\n }\n }\n\n toggleDevMenu() {\n Log.log(`${BLT} Toggling dev menu`);\n this.devServerManager.broadcastMessage('devMenu');\n }\n}\n"],"names":["DevServerManagerActions","debug","require","constructor","devServerManager","options","printDevServerInfo","rows","process","stdout","Infinity","getNativeDevServerPort","devServer","getDefaultDevServer","nativeRuntimeUrl","getNativeRuntimeUrl","interstitialPageUrl","getRedirectUrl","env","__EXPO_E2E_TEST","console","info","JSON","stringify","url","getDevServerUrl","qr","printQRCode","lines","print","qrMessage","devClient","chalk","learnMore","Log","log","printItem","dim","error","code","serverUrl","platforms","includes","webDevServer","getWebDevServer","webUrl","hostType","printUsage","verbose","printHelp","openJsInspectorAsync","metroServerOrigin","getJsInspectorBaseUrl","apps","queryAllInspectorAppsAsync","length","warn","app","promptInspectorAppAsync","openJsInspector","exception","reloadApp","BLT","broadcastMessage","openMoreToolsAsync","defaultMenuItems","title","value","defaultServerUrl","getUrlCreator","constructUrl","scheme","plugins","devtoolsPluginManager","queryPluginsAsync","menuItems","createDevToolsMenuItems","selectAsync","menuItem","find","item","action","name","toggleDevMenu"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../src/start/interface/interactiveActions.ts"],"sourcesContent":["import chalk from 'chalk';\n\nimport { BLT, printHelp, printItem, printUsage, StartOptions } from './commandsTable';\nimport { createDevToolsMenuItems } from './createDevToolsMenuItems';\nimport * as Log from '../../log';\nimport { env } from '../../utils/env';\nimport { learnMore } from '../../utils/link';\nimport { ExpoChoice, selectAsync } from '../../utils/prompts';\nimport { printQRCode } from '../../utils/qr';\nimport { DevServerManager } from '../server/DevServerManager';\nimport {\n openJsInspector,\n queryAllInspectorAppsAsync,\n promptInspectorAppAsync,\n} from '../server/middleware/inspector/JsInspector';\n\nconst debug = require('debug')('expo:start:interface:interactiveActions') as typeof console.log;\n\ninterface MoreToolMenuItem extends ExpoChoice<string> {\n action?: () => unknown;\n}\n\n/** Wraps the DevServerManager and adds an interface for user actions. */\nexport class DevServerManagerActions {\n constructor(\n private devServerManager: DevServerManager,\n private options: Pick<StartOptions, 'devClient' | 'platforms'>\n ) {}\n\n printDevServerInfo(\n options: Pick<StartOptions, 'devClient' | 'isWebSocketsEnabled' | 'platforms'>\n ) {\n // Keep track of approximately how much space we have to print our usage guide\n let rows = process.stdout.rows || Infinity;\n\n // If native dev server is running, print its URL.\n if (this.devServerManager.getNativeDevServerPort()) {\n const devServer = this.devServerManager.getDefaultDevServer();\n try {\n const nativeRuntimeUrl = devServer.getNativeRuntimeUrl()!;\n const interstitialPageUrl = devServer.getRedirectUrl();\n\n // Print the URL to stdout for tests\n if (env.__EXPO_E2E_TEST) {\n console.info(\n `[__EXPO_E2E_TEST:server] ${JSON.stringify({ url: devServer.getDevServerUrl() })}`\n );\n rows--;\n }\n\n if (!env.EXPO_NO_QR_CODE) {\n const qr = printQRCode(interstitialPageUrl ?? nativeRuntimeUrl);\n rows -= qr.lines;\n qr.print();\n\n let qrMessage = '';\n if (!options.devClient) {\n qrMessage = `Scan the QR code above to open in ${chalk`{bold Expo Go}`}.`;\n } else {\n qrMessage = chalk`Scan the QR code above to open in a {bold development build}.`;\n qrMessage += ` (${learnMore('https://expo.fyi/start')})`;\n }\n rows--;\n Log.log(printItem(qrMessage, { dim: true }));\n }\n\n if (interstitialPageUrl) {\n rows--;\n Log.log(\n printItem(\n chalk`Choose an app to open your project at {underline ${interstitialPageUrl}}`\n )\n );\n }\n\n rows--;\n Log.log(printItem(chalk`Metro: {underline ${nativeRuntimeUrl}}`));\n } catch (error) {\n console.log('err', error);\n // @ts-ignore: If there is no development build scheme, then skip the QR code.\n if (error.code !== 'NO_DEV_CLIENT_SCHEME') {\n throw error;\n } else {\n const serverUrl = devServer.getDevServerUrl();\n Log.log(printItem(chalk`Metro: {underline ${serverUrl}}`));\n Log.log(printItem(`Linking is disabled because the client scheme cannot be resolved.`));\n rows -= 2;\n }\n }\n }\n\n if (this.options.platforms?.includes('web')) {\n const webDevServer = this.devServerManager.getWebDevServer();\n const webUrl = webDevServer?.getDevServerUrl({ hostType: 'localhost' });\n if (webUrl) {\n Log.log(printItem(chalk`Web: {underline ${webUrl}}`));\n rows--;\n }\n }\n\n printUsage(options, { verbose: false, rows });\n printHelp();\n Log.log();\n }\n\n async openJsInspectorAsync() {\n try {\n const metroServerOrigin = this.devServerManager.getDefaultDevServer().getJsInspectorBaseUrl();\n const apps = await queryAllInspectorAppsAsync(metroServerOrigin);\n if (!apps.length) {\n return Log.warn(\n chalk`{bold Debug:} No compatible apps connected, React Native DevTools can only be used with Hermes. ${learnMore(\n 'https://docs.expo.dev/guides/using-hermes/'\n )}`\n );\n }\n\n const app = await promptInspectorAppAsync(apps);\n if (!app) {\n return Log.error(chalk`{bold Debug:} No inspectable device selected`);\n }\n\n if (!(await openJsInspector(metroServerOrigin, app))) {\n Log.warn(\n chalk`{bold Debug:} Failed to open the React Native DevTools, see debug logs for more info.`\n );\n }\n } catch (error: any) {\n // Handle aborting prompt\n if (error.code === 'ABORTED') return;\n\n Log.error('Failed to open the React Native DevTools.');\n Log.exception(error);\n }\n }\n\n reloadApp() {\n Log.log(`${BLT} Reloading apps`);\n // Send reload requests over the dev servers\n this.devServerManager.broadcastMessage('reload');\n }\n\n async openMoreToolsAsync() {\n // Options match: Chrome > View > Developer\n try {\n const defaultMenuItems: MoreToolMenuItem[] = [\n { title: 'Inspect elements', value: 'toggleElementInspector' },\n { title: 'Toggle performance monitor', value: 'togglePerformanceMonitor' },\n { title: 'Toggle developer menu', value: 'toggleDevMenu' },\n { title: 'Reload app', value: 'reload' },\n // TODO: Maybe a \"View Source\" option to open code.\n ];\n\n const defaultServerUrl = this.devServerManager\n .getDefaultDevServer()\n .getUrlCreator()\n .constructUrl({ scheme: 'http' });\n\n const metroServerOrigin = this.devServerManager.getDefaultDevServer().getJsInspectorBaseUrl();\n const plugins = await this.devServerManager.devtoolsPluginManager.queryPluginsAsync();\n\n const menuItems = [\n ...defaultMenuItems,\n ...createDevToolsMenuItems(plugins, defaultServerUrl, metroServerOrigin),\n ];\n\n const value = await selectAsync(chalk`Dev tools {dim (native only)}`, menuItems);\n const menuItem = menuItems.find((item) => item.value === value);\n if (menuItem?.action) {\n menuItem.action();\n } else if (menuItem?.value) {\n this.devServerManager.broadcastMessage('sendDevCommand', { name: menuItem.value });\n }\n } catch (error: any) {\n debug(error);\n // do nothing\n } finally {\n printHelp();\n }\n }\n\n toggleDevMenu() {\n Log.log(`${BLT} Toggling dev menu`);\n this.devServerManager.broadcastMessage('devMenu');\n }\n}\n"],"names":["DevServerManagerActions","debug","require","constructor","devServerManager","options","printDevServerInfo","rows","process","stdout","Infinity","getNativeDevServerPort","devServer","getDefaultDevServer","nativeRuntimeUrl","getNativeRuntimeUrl","interstitialPageUrl","getRedirectUrl","env","__EXPO_E2E_TEST","console","info","JSON","stringify","url","getDevServerUrl","EXPO_NO_QR_CODE","qr","printQRCode","lines","print","qrMessage","devClient","chalk","learnMore","Log","log","printItem","dim","error","code","serverUrl","platforms","includes","webDevServer","getWebDevServer","webUrl","hostType","printUsage","verbose","printHelp","openJsInspectorAsync","metroServerOrigin","getJsInspectorBaseUrl","apps","queryAllInspectorAppsAsync","length","warn","app","promptInspectorAppAsync","openJsInspector","exception","reloadApp","BLT","broadcastMessage","openMoreToolsAsync","defaultMenuItems","title","value","defaultServerUrl","getUrlCreator","constructUrl","scheme","plugins","devtoolsPluginManager","queryPluginsAsync","menuItems","createDevToolsMenuItems","selectAsync","menuItem","find","item","action","name","toggleDevMenu"],"mappings":"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"}
@@ -214,6 +214,25 @@ async function launchBinaryOnMacAsync(bundleId, appBinaryPath) {
214
214
  }
215
215
  }
216
216
  async function installAppWithDeviceCtlAsync(uuid, bundleIdOrAppPath, onProgress) {
217
+ const maxAttempts = 3;
218
+ for(let attempt = 1; attempt <= maxAttempts; attempt++){
219
+ try {
220
+ await installAppWithDeviceCtlInternalAsync(uuid, bundleIdOrAppPath, onProgress, attempt);
221
+ return;
222
+ } catch (error) {
223
+ if (error.code === 'detached') {
224
+ throw error;
225
+ }
226
+ const isTransientDisconnect = error.message && (error.message.includes('CoreDeviceError') || error.message.includes('0xFA0'));
227
+ if (!isTransientDisconnect || attempt === maxAttempts) {
228
+ throw error;
229
+ }
230
+ const backoffDelay = 500 + Math.pow(2, attempt - 1) * 500;
231
+ await new Promise((resolve)=>setTimeout(resolve, backoffDelay));
232
+ }
233
+ }
234
+ }
235
+ async function installAppWithDeviceCtlInternalAsync(uuid, bundleIdOrAppPath, onProgress, attempt) {
217
236
  // 𝝠 xcrun devicectl device install app --device 00001110-001111110110101A /Users/evanbacon/Library/Developer/Xcode/DerivedData/Router-hgbqaxzhrhkiftfweydvhgttadvn/Build/Products/Debug-iphoneos/Router.app --verbose
218
237
  return new Promise((resolve, reject)=>{
219
238
  const args = [
@@ -235,10 +254,11 @@ async function installAppWithDeviceCtlAsync(uuid, bundleIdOrAppPath, onProgress)
235
254
  return;
236
255
  }
237
256
  currentProgress = progress;
257
+ const statusPrefix = attempt > 1 ? `Installing (attempt ${attempt})` : 'Installing';
238
258
  onProgress({
239
259
  progress,
240
260
  isComplete: progress === 100,
241
- status: 'Installing'
261
+ status: statusPrefix
242
262
  });
243
263
  }
244
264
  childProcess.stdout.on('data', (data)=>{
@@ -259,13 +279,16 @@ async function installAppWithDeviceCtlAsync(uuid, bundleIdOrAppPath, onProgress)
259
279
  });
260
280
  debug('[stdout]:', strings);
261
281
  });
282
+ let stderrBuffer = '';
283
+ childProcess.stderr.on('data', (data)=>{
284
+ stderrBuffer += data.toString();
285
+ });
262
286
  childProcess.on('close', (code)=>{
263
287
  debug('[close]: ' + code);
264
288
  if (code === 0) {
265
289
  resolve();
266
290
  } else {
267
- const stderr = childProcess.stderr.read();
268
- const err = new Error(stderr);
291
+ const err = new Error(stderrBuffer || `Command failed with exit code ${code}`);
269
292
  err.code = code;
270
293
  detach(err);
271
294
  }
@@ -274,9 +297,8 @@ async function installAppWithDeviceCtlAsync(uuid, bundleIdOrAppPath, onProgress)
274
297
  off == null ? void 0 : off();
275
298
  if (childProcess) {
276
299
  return new Promise((resolve)=>{
277
- childProcess == null ? void 0 : childProcess.on('close', resolve);
300
+ childProcess == null ? void 0 : childProcess.on('close', ()=>resolve());
278
301
  childProcess == null ? void 0 : childProcess.kill();
279
- // childProcess = null;
280
302
  reject(err ?? new _errors.CommandError('detached'));
281
303
  });
282
304
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../src/start/platforms/ios/devicectl.ts"],"sourcesContent":["/**\n * Copyright © 2024 650 Industries.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\nimport JsonFile from '@expo/json-file';\nimport spawnAsync, { SpawnOptions, SpawnResult } from '@expo/spawn-async';\nimport chalk from 'chalk';\nimport { spawn, execSync } from 'child_process';\nimport fs from 'fs';\nimport assert from 'node:assert';\nimport { Ora } from 'ora';\nimport { EOL } from 'os';\nimport path from 'path';\n\nimport { xcrunAsync } from './xcrun';\nimport { getExpoHomeDirectory } from '../../../api/user/UserSettings';\nimport * as Log from '../../../log';\nimport { createTempFilePath } from '../../../utils/createTempPath';\nimport { CommandError } from '../../../utils/errors';\nimport { installExitHooks } from '../../../utils/exit';\nimport { isInteractive } from '../../../utils/interactive';\nimport { ora } from '../../../utils/ora';\nimport { confirmAsync } from '../../../utils/prompts';\n\nconst DEVICE_CTL_EXISTS_PATH = path.join(getExpoHomeDirectory(), 'devicectl-exists');\n\nconst debug = require('debug')('expo:devicectl') as typeof console.log;\n\ntype AnyEnum<T extends string = string> = T | (string & object);\n\ntype DeviceCtlDevice = {\n capabilities: DeviceCtlDeviceCapability[];\n connectionProperties: DeviceCtlConnectionProperties;\n deviceProperties: DeviceCtlDeviceProperties;\n hardwareProperties: DeviceCtlHardwareProperties;\n /** \"A1A1AAA1-0011-1AA1-11A1-10A1111AA11A\" */\n identifier: string;\n visibilityClass: AnyEnum<'default'>;\n};\n\ntype DeviceCtlHardwareProperties = {\n cpuType: DeviceCtlCpuType;\n deviceType: AnyEnum<'iPhone'>;\n /** 1114404411111111 */\n ecid: number;\n /** \"D74AP\" */\n hardwareModel: string;\n /** 512000000000 */\n internalStorageCapacity: number;\n /** true */\n isProductionFused: boolean;\n /** \"iPhone 14 Pro Max\" */\n marketingName: string;\n /** \"iOS\" */\n platform: AnyEnum<'iOS' | 'xrOS'>;\n /** \"iPhone15,3\" */\n productType: AnyEnum<'iPhone13,4' | 'iPhone15,3'>;\n reality: AnyEnum<'physical'>;\n /** \"X2X1CC1XXX\" */\n serialNumber: string;\n supportedCPUTypes: DeviceCtlCpuType[];\n /** [1] */\n supportedDeviceFamilies: number[];\n thinningProductType: AnyEnum<'iPhone15,3'>;\n /** \"00001110-001111110110101A\" */\n udid: string;\n};\n\ntype DeviceCtlDeviceProperties = {\n /** true */\n bootedFromSnapshot: boolean;\n /** \"com.apple.os.update-AD0CF111ACFF11A11111A76A3D1262AE42A3F56F305AF5AE1135393A7A14A7D1\" */\n bootedSnapshotName: string;\n /** false */\n ddiServicesAvailable: boolean;\n\n developerModeStatus: AnyEnum<'enabled'>;\n /** false */\n hasInternalOSBuild: boolean;\n /** \"Evan's phone\" */\n name: string;\n /** \"21E236\" */\n osBuildUpdate: string;\n /** \"17.4.1\" */\n osVersionNumber: string;\n /** false */\n rootFileSystemIsWritable: boolean;\n};\n\ntype DeviceCtlDeviceCapability =\n | {\n name: AnyEnum;\n featureIdentifier: AnyEnum;\n }\n | {\n featureIdentifier: 'com.apple.coredevice.feature.connectdevice';\n name: 'Connect to Device';\n }\n | {\n featureIdentifier: 'com.apple.coredevice.feature.unpairdevice';\n name: 'Unpair Device';\n }\n | {\n featureIdentifier: 'com.apple.coredevice.feature.acquireusageassertion';\n name: 'Acquire Usage Assertion';\n };\n\ntype DeviceCtlConnectionProperties = {\n authenticationType: AnyEnum<'manualPairing'>;\n isMobileDeviceOnly: boolean;\n /** \"2024-04-20T22:50:04.244Z\" */\n lastConnectionDate: string;\n pairingState: AnyEnum<'paired'>;\n /** [\"00001111-001111110110101A.coredevice.local\", \"A1A1AAA1-0011-1AA1-11A1-10A1111AA11A.coredevice.local\"] */\n potentialHostnames: string[];\n transportType: AnyEnum<'localNetwork' | 'wired'>;\n tunnelState: AnyEnum<'disconnected' | 'unavailable'>;\n tunnelTransportProtocol: AnyEnum<'tcp'>;\n};\n\ntype DeviceCtlCpuType = {\n name: AnyEnum<'arm64e' | 'arm64' | 'arm64_32'>;\n subType: number;\n /** 16777228 */\n type: number;\n};\n\n/** Run a `devicectl` command. */\nexport async function devicectlAsync(\n args: (string | undefined)[],\n options?: SpawnOptions\n): Promise<SpawnResult> {\n try {\n return await xcrunAsync(['devicectl', ...args], options);\n } catch (error: any) {\n if (error instanceof CommandError) {\n throw error;\n }\n if ('stderr' in error) {\n const errorCodes = getDeviceCtlErrorCodes(error.stderr);\n if (errorCodes.includes('Locked')) {\n throw new CommandError('APPLE_DEVICE_LOCKED', 'Device is locked, unlock and try again.');\n }\n }\n throw error;\n }\n}\n\nexport async function getConnectedAppleDevicesAsync() {\n if (!hasDevicectlEverBeenInstalled()) {\n debug('devicectl not found, skipping remote Apple devices.');\n return [];\n }\n\n const tmpPath = createTempFilePath();\n const devices = await devicectlAsync([\n 'list',\n 'devices',\n '--json-output',\n tmpPath,\n // Give two seconds before timing out: between 5 and 9223372036854775807\n '--timeout',\n '5',\n ]);\n debug(devices.stdout);\n const devicesJson = await JsonFile.readAsync(tmpPath);\n\n if (![2, 3].includes((devicesJson as any)?.info?.jsonVersion)) {\n Log.warn(\n 'Unexpected devicectl JSON version output from devicectl. Connecting to physical Apple devices may not work as expected.'\n );\n }\n\n assertDevicesJson(devicesJson);\n\n return devicesJson.result.devices as DeviceCtlDevice[];\n}\n\nfunction assertDevicesJson(\n results: any\n): asserts results is { result: { devices: DeviceCtlDevice[] } } {\n assert(\n results != null && 'result' in results && Array.isArray(results?.result?.devices),\n 'Malformed JSON output from devicectl: ' + JSON.stringify(results, null, 2)\n );\n}\n\nexport async function launchBinaryOnMacAsync(\n bundleId: string,\n appBinaryPath: string\n): Promise<void> {\n const args = ['-b', bundleId, appBinaryPath];\n try {\n await spawnAsync('open', args);\n } catch (error: any) {\n if ('code' in error) {\n if (error.code === 1) {\n throw new CommandError(\n 'MACOS_LAUNCH',\n 'Failed to launch the compatible binary on macOS: open ' +\n args.join(' ') +\n '\\n\\n' +\n error.message\n );\n }\n }\n throw error;\n }\n}\n\nasync function installAppWithDeviceCtlAsync(\n uuid: string,\n bundleIdOrAppPath: string,\n onProgress: (event: { status: string; isComplete: boolean; progress: number }) => void\n): Promise<void> {\n // 𝝠 xcrun devicectl device install app --device 00001110-001111110110101A /Users/evanbacon/Library/Developer/Xcode/DerivedData/Router-hgbqaxzhrhkiftfweydvhgttadvn/Build/Products/Debug-iphoneos/Router.app --verbose\n return new Promise((resolve, reject) => {\n const args: string[] = [\n 'devicectl',\n 'device',\n 'install',\n 'app',\n '--device',\n uuid,\n bundleIdOrAppPath,\n ];\n const childProcess = spawn('xcrun', args);\n debug('xcrun ' + args.join(' '));\n\n let currentProgress = 0;\n let hasStarted = false;\n\n function updateProgress(progress: number) {\n hasStarted = true;\n if (progress <= currentProgress) {\n return;\n }\n currentProgress = progress;\n onProgress({\n progress,\n isComplete: progress === 100,\n status: 'Installing',\n });\n }\n\n childProcess.stdout.on('data', (data: Buffer) => {\n // Sometimes more than one chunk comes at a time, here we split by system newline,\n // then trim and filter.\n const strings = data\n .toString()\n .split(EOL)\n .map((value) => value.trim());\n\n strings.forEach((str) => {\n // Match the progress percentage:\n // - '34%... 35%...' -> 34\n // - '31%...' -> 31\n // - 'Complete!' -> 100\n\n const match = str.match(/(\\d+)%\\.\\.\\./);\n if (match) {\n updateProgress(parseInt(match[1], 10));\n } else if (hasStarted) {\n updateProgress(100);\n }\n });\n\n debug('[stdout]:', strings);\n });\n\n childProcess.on('close', (code) => {\n debug('[close]: ' + code);\n if (code === 0) {\n resolve();\n } else {\n const stderr = childProcess.stderr.read();\n const err = new Error(stderr);\n (err as any).code = code;\n detach(err);\n }\n });\n\n const detach = async (err?: Error) => {\n off?.();\n if (childProcess) {\n return new Promise<void>((resolve) => {\n childProcess?.on('close', resolve);\n childProcess?.kill();\n // childProcess = null;\n reject(err ?? new CommandError('detached'));\n });\n }\n };\n\n const off = installExitHooks(() => detach());\n });\n}\n\nexport async function launchAppWithDeviceCtl(deviceId: string, bundleId: string) {\n await devicectlAsync(['device', 'process', 'launch', '--device', deviceId, bundleId]);\n}\n\n/** Find all error codes from the output log */\nfunction getDeviceCtlErrorCodes(log: string): string[] {\n return [...log.matchAll(/BSErrorCodeDescription\\s+=\\s+(.*)$/gim)].map(([_line, code]) => code);\n}\n\nlet hasEverBeenInstalled: boolean | undefined;\n\nexport function hasDevicectlEverBeenInstalled() {\n if (hasEverBeenInstalled) return hasEverBeenInstalled;\n // It doesn't appear possible for devicectl to ever be uninstalled. We can just check once and store this result forever\n // to prevent cold boots of devicectl from slowing down all invocations of `expo run ios`\n if (fs.existsSync(DEVICE_CTL_EXISTS_PATH)) {\n hasEverBeenInstalled = true;\n return true;\n }\n\n const isInstalled = isDevicectlInstalled();\n\n if (isInstalled) {\n fs.writeFileSync(DEVICE_CTL_EXISTS_PATH, '1');\n }\n hasEverBeenInstalled = isInstalled;\n return isInstalled;\n}\n\nfunction isDevicectlInstalled() {\n try {\n execSync('xcrun devicectl --version', { stdio: 'ignore' });\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Wraps the apple device method for installing and running an app,\n * adds indicator and retry loop for when the device is locked.\n */\nexport async function installAndLaunchAppAsync(props: {\n bundle: string;\n bundleIdentifier: string;\n udid: string;\n deviceName: string;\n}): Promise<void> {\n debug('Running on device:', props);\n const { bundle, bundleIdentifier, udid, deviceName } = props;\n let indicator: Ora | undefined;\n\n try {\n if (!indicator) {\n indicator = ora(`Connecting to: ${props.deviceName}`).start();\n }\n\n await installAppWithDeviceCtlAsync(\n udid,\n bundle,\n ({\n status,\n isComplete,\n progress,\n }: {\n status: string;\n isComplete: boolean;\n progress: number;\n }) => {\n if (!indicator) {\n indicator = ora(status).start();\n }\n indicator.text = `${chalk.bold(status)} ${progress}%`;\n if (isComplete) {\n indicator.succeed();\n }\n }\n );\n } catch (error: any) {\n if (indicator) {\n indicator.fail();\n }\n throw error;\n }\n\n async function launchAppOptionally() {\n try {\n await launchAppWithDeviceCtl(udid, bundleIdentifier);\n } catch (error: any) {\n if (indicator) {\n indicator.fail();\n }\n if (error.code === 'APPLE_DEVICE_LOCKED') {\n // Get the app name from the binary path.\n const appName = path.basename(bundle).split('.')[0] ?? 'app';\n if (\n isInteractive() &&\n (await confirmAsync({\n message: `Cannot launch ${appName} because the device is locked. Unlock ${deviceName} to continue...`,\n initial: true,\n }))\n ) {\n return launchAppOptionally();\n }\n throw new CommandError(\n `Cannot launch ${appName} on ${deviceName} because the device is locked.`\n );\n }\n throw error;\n }\n }\n\n await launchAppOptionally();\n}\n"],"names":["devicectlAsync","getConnectedAppleDevicesAsync","hasDevicectlEverBeenInstalled","installAndLaunchAppAsync","launchAppWithDeviceCtl","launchBinaryOnMacAsync","DEVICE_CTL_EXISTS_PATH","path","join","getExpoHomeDirectory","debug","require","args","options","xcrunAsync","error","CommandError","errorCodes","getDeviceCtlErrorCodes","stderr","includes","tmpPath","createTempFilePath","devices","stdout","devicesJson","JsonFile","readAsync","info","jsonVersion","Log","warn","assertDevicesJson","result","results","assert","Array","isArray","JSON","stringify","bundleId","appBinaryPath","spawnAsync","code","message","installAppWithDeviceCtlAsync","uuid","bundleIdOrAppPath","onProgress","Promise","resolve","reject","childProcess","spawn","currentProgress","hasStarted","updateProgress","progress","isComplete","status","on","data","strings","toString","split","EOL","map","value","trim","forEach","str","match","parseInt","read","err","Error","detach","off","kill","installExitHooks","deviceId","log","matchAll","_line","hasEverBeenInstalled","fs","existsSync","isInstalled","isDevicectlInstalled","writeFileSync","execSync","stdio","props","bundle","bundleIdentifier","udid","deviceName","indicator","ora","start","text","chalk","bold","succeed","fail","launchAppOptionally","appName","basename","isInteractive","confirmAsync","initial"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../src/start/platforms/ios/devicectl.ts"],"sourcesContent":["/**\n * Copyright © 2024 650 Industries.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\nimport JsonFile from '@expo/json-file';\nimport spawnAsync, { SpawnOptions, SpawnResult } from '@expo/spawn-async';\nimport chalk from 'chalk';\nimport { spawn, execSync } from 'child_process';\nimport fs from 'fs';\nimport assert from 'node:assert';\nimport { Ora } from 'ora';\nimport { EOL } from 'os';\nimport path from 'path';\n\nimport { xcrunAsync } from './xcrun';\nimport { getExpoHomeDirectory } from '../../../api/user/UserSettings';\nimport * as Log from '../../../log';\nimport { createTempFilePath } from '../../../utils/createTempPath';\nimport { CommandError } from '../../../utils/errors';\nimport { installExitHooks } from '../../../utils/exit';\nimport { isInteractive } from '../../../utils/interactive';\nimport { ora } from '../../../utils/ora';\nimport { confirmAsync } from '../../../utils/prompts';\n\nconst DEVICE_CTL_EXISTS_PATH = path.join(getExpoHomeDirectory(), 'devicectl-exists');\n\nconst debug = require('debug')('expo:devicectl') as typeof console.log;\n\ntype AnyEnum<T extends string = string> = T | (string & object);\n\ntype DeviceCtlDevice = {\n capabilities: DeviceCtlDeviceCapability[];\n connectionProperties: DeviceCtlConnectionProperties;\n deviceProperties: DeviceCtlDeviceProperties;\n hardwareProperties: DeviceCtlHardwareProperties;\n /** \"A1A1AAA1-0011-1AA1-11A1-10A1111AA11A\" */\n identifier: string;\n visibilityClass: AnyEnum<'default'>;\n};\n\ntype DeviceCtlHardwareProperties = {\n cpuType: DeviceCtlCpuType;\n deviceType: AnyEnum<'iPhone'>;\n /** 1114404411111111 */\n ecid: number;\n /** \"D74AP\" */\n hardwareModel: string;\n /** 512000000000 */\n internalStorageCapacity: number;\n /** true */\n isProductionFused: boolean;\n /** \"iPhone 14 Pro Max\" */\n marketingName: string;\n /** \"iOS\" */\n platform: AnyEnum<'iOS' | 'xrOS'>;\n /** \"iPhone15,3\" */\n productType: AnyEnum<'iPhone13,4' | 'iPhone15,3'>;\n reality: AnyEnum<'physical'>;\n /** \"X2X1CC1XXX\" */\n serialNumber: string;\n supportedCPUTypes: DeviceCtlCpuType[];\n /** [1] */\n supportedDeviceFamilies: number[];\n thinningProductType: AnyEnum<'iPhone15,3'>;\n /** \"00001110-001111110110101A\" */\n udid: string;\n};\n\ntype DeviceCtlDeviceProperties = {\n /** true */\n bootedFromSnapshot: boolean;\n /** \"com.apple.os.update-AD0CF111ACFF11A11111A76A3D1262AE42A3F56F305AF5AE1135393A7A14A7D1\" */\n bootedSnapshotName: string;\n /** false */\n ddiServicesAvailable: boolean;\n\n developerModeStatus: AnyEnum<'enabled'>;\n /** false */\n hasInternalOSBuild: boolean;\n /** \"Evan's phone\" */\n name: string;\n /** \"21E236\" */\n osBuildUpdate: string;\n /** \"17.4.1\" */\n osVersionNumber: string;\n /** false */\n rootFileSystemIsWritable: boolean;\n};\n\ntype DeviceCtlDeviceCapability =\n | {\n name: AnyEnum;\n featureIdentifier: AnyEnum;\n }\n | {\n featureIdentifier: 'com.apple.coredevice.feature.connectdevice';\n name: 'Connect to Device';\n }\n | {\n featureIdentifier: 'com.apple.coredevice.feature.unpairdevice';\n name: 'Unpair Device';\n }\n | {\n featureIdentifier: 'com.apple.coredevice.feature.acquireusageassertion';\n name: 'Acquire Usage Assertion';\n };\n\ntype DeviceCtlConnectionProperties = {\n authenticationType: AnyEnum<'manualPairing'>;\n isMobileDeviceOnly: boolean;\n /** \"2024-04-20T22:50:04.244Z\" */\n lastConnectionDate: string;\n pairingState: AnyEnum<'paired'>;\n /** [\"00001111-001111110110101A.coredevice.local\", \"A1A1AAA1-0011-1AA1-11A1-10A1111AA11A.coredevice.local\"] */\n potentialHostnames: string[];\n transportType: AnyEnum<'localNetwork' | 'wired'>;\n tunnelState: AnyEnum<'disconnected' | 'unavailable'>;\n tunnelTransportProtocol: AnyEnum<'tcp'>;\n};\n\ntype DeviceCtlCpuType = {\n name: AnyEnum<'arm64e' | 'arm64' | 'arm64_32'>;\n subType: number;\n /** 16777228 */\n type: number;\n};\n\n/** Run a `devicectl` command. */\nexport async function devicectlAsync(\n args: (string | undefined)[],\n options?: SpawnOptions\n): Promise<SpawnResult> {\n try {\n return await xcrunAsync(['devicectl', ...args], options);\n } catch (error: any) {\n if (error instanceof CommandError) {\n throw error;\n }\n if ('stderr' in error) {\n const errorCodes = getDeviceCtlErrorCodes(error.stderr);\n if (errorCodes.includes('Locked')) {\n throw new CommandError('APPLE_DEVICE_LOCKED', 'Device is locked, unlock and try again.');\n }\n }\n throw error;\n }\n}\n\nexport async function getConnectedAppleDevicesAsync() {\n if (!hasDevicectlEverBeenInstalled()) {\n debug('devicectl not found, skipping remote Apple devices.');\n return [];\n }\n\n const tmpPath = createTempFilePath();\n const devices = await devicectlAsync([\n 'list',\n 'devices',\n '--json-output',\n tmpPath,\n // Give two seconds before timing out: between 5 and 9223372036854775807\n '--timeout',\n '5',\n ]);\n debug(devices.stdout);\n const devicesJson = await JsonFile.readAsync(tmpPath);\n\n if (![2, 3].includes((devicesJson as any)?.info?.jsonVersion)) {\n Log.warn(\n 'Unexpected devicectl JSON version output from devicectl. Connecting to physical Apple devices may not work as expected.'\n );\n }\n\n assertDevicesJson(devicesJson);\n\n return devicesJson.result.devices as DeviceCtlDevice[];\n}\n\nfunction assertDevicesJson(\n results: any\n): asserts results is { result: { devices: DeviceCtlDevice[] } } {\n assert(\n results != null && 'result' in results && Array.isArray(results?.result?.devices),\n 'Malformed JSON output from devicectl: ' + JSON.stringify(results, null, 2)\n );\n}\n\nexport async function launchBinaryOnMacAsync(\n bundleId: string,\n appBinaryPath: string\n): Promise<void> {\n const args = ['-b', bundleId, appBinaryPath];\n try {\n await spawnAsync('open', args);\n } catch (error: any) {\n if ('code' in error) {\n if (error.code === 1) {\n throw new CommandError(\n 'MACOS_LAUNCH',\n 'Failed to launch the compatible binary on macOS: open ' +\n args.join(' ') +\n '\\n\\n' +\n error.message\n );\n }\n }\n throw error;\n }\n}\n\nasync function installAppWithDeviceCtlAsync(\n uuid: string,\n bundleIdOrAppPath: string,\n onProgress: (event: { status: string; isComplete: boolean; progress: number }) => void\n): Promise<void> {\n const maxAttempts = 3;\n for (let attempt = 1; attempt <= maxAttempts; attempt++) {\n try {\n await installAppWithDeviceCtlInternalAsync(uuid, bundleIdOrAppPath, onProgress, attempt);\n return;\n } catch (error: any) {\n if (error.code === 'detached') {\n throw error;\n }\n const isTransientDisconnect =\n error.message &&\n (error.message.includes('CoreDeviceError') || error.message.includes('0xFA0'));\n\n if (!isTransientDisconnect || attempt === maxAttempts) {\n throw error;\n }\n const backoffDelay = 500 + Math.pow(2, attempt - 1) * 500;\n await new Promise((resolve) => setTimeout(resolve, backoffDelay));\n }\n }\n}\n\nasync function installAppWithDeviceCtlInternalAsync(\n uuid: string,\n bundleIdOrAppPath: string,\n onProgress: (event: { status: string; isComplete: boolean; progress: number }) => void,\n attempt: number\n): Promise<void> {\n // 𝝠 xcrun devicectl device install app --device 00001110-001111110110101A /Users/evanbacon/Library/Developer/Xcode/DerivedData/Router-hgbqaxzhrhkiftfweydvhgttadvn/Build/Products/Debug-iphoneos/Router.app --verbose\n return new Promise((resolve, reject) => {\n const args: string[] = [\n 'devicectl',\n 'device',\n 'install',\n 'app',\n '--device',\n uuid,\n bundleIdOrAppPath,\n ];\n const childProcess = spawn('xcrun', args);\n debug('xcrun ' + args.join(' '));\n\n let currentProgress = 0;\n let hasStarted = false;\n\n function updateProgress(progress: number) {\n hasStarted = true;\n if (progress <= currentProgress) {\n return;\n }\n currentProgress = progress;\n const statusPrefix = attempt > 1 ? `Installing (attempt ${attempt})` : 'Installing';\n onProgress({\n progress,\n isComplete: progress === 100,\n status: statusPrefix,\n });\n }\n\n childProcess.stdout.on('data', (data: Buffer) => {\n // Sometimes more than one chunk comes at a time, here we split by system newline,\n // then trim and filter.\n const strings = data\n .toString()\n .split(EOL)\n .map((value) => value.trim());\n\n strings.forEach((str) => {\n // Match the progress percentage:\n // - '34%... 35%...' -> 34\n // - '31%...' -> 31\n // - 'Complete!' -> 100\n\n const match = str.match(/(\\d+)%\\.\\.\\./);\n if (match) {\n updateProgress(parseInt(match[1], 10));\n } else if (hasStarted) {\n updateProgress(100);\n }\n });\n\n debug('[stdout]:', strings);\n });\n\n let stderrBuffer = '';\n childProcess.stderr.on('data', (data: Buffer) => {\n stderrBuffer += data.toString();\n });\n\n childProcess.on('close', (code) => {\n debug('[close]: ' + code);\n if (code === 0) {\n resolve();\n } else {\n const err = new Error(stderrBuffer || `Command failed with exit code ${code}`);\n (err as any).code = code;\n detach(err);\n }\n });\n\n const detach = async (err?: Error) => {\n off?.();\n if (childProcess) {\n return new Promise<void>((resolve) => {\n childProcess?.on('close', () => resolve());\n childProcess?.kill();\n reject(err ?? new CommandError('detached'));\n });\n }\n };\n\n const off = installExitHooks(() => detach());\n });\n}\n\nexport async function launchAppWithDeviceCtl(deviceId: string, bundleId: string) {\n await devicectlAsync(['device', 'process', 'launch', '--device', deviceId, bundleId]);\n}\n\n/** Find all error codes from the output log */\nfunction getDeviceCtlErrorCodes(log: string): string[] {\n return [...log.matchAll(/BSErrorCodeDescription\\s+=\\s+(.*)$/gim)].map(([_line, code]) => code);\n}\n\nlet hasEverBeenInstalled: boolean | undefined;\n\nexport function hasDevicectlEverBeenInstalled() {\n if (hasEverBeenInstalled) return hasEverBeenInstalled;\n // It doesn't appear possible for devicectl to ever be uninstalled. We can just check once and store this result forever\n // to prevent cold boots of devicectl from slowing down all invocations of `expo run ios`\n if (fs.existsSync(DEVICE_CTL_EXISTS_PATH)) {\n hasEverBeenInstalled = true;\n return true;\n }\n\n const isInstalled = isDevicectlInstalled();\n\n if (isInstalled) {\n fs.writeFileSync(DEVICE_CTL_EXISTS_PATH, '1');\n }\n hasEverBeenInstalled = isInstalled;\n return isInstalled;\n}\n\nfunction isDevicectlInstalled() {\n try {\n execSync('xcrun devicectl --version', { stdio: 'ignore' });\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Wraps the apple device method for installing and running an app,\n * adds indicator and retry loop for when the device is locked.\n */\nexport async function installAndLaunchAppAsync(props: {\n bundle: string;\n bundleIdentifier: string;\n udid: string;\n deviceName: string;\n}): Promise<void> {\n debug('Running on device:', props);\n const { bundle, bundleIdentifier, udid, deviceName } = props;\n let indicator: Ora | undefined;\n\n try {\n if (!indicator) {\n indicator = ora(`Connecting to: ${props.deviceName}`).start();\n }\n\n await installAppWithDeviceCtlAsync(\n udid,\n bundle,\n ({\n status,\n isComplete,\n progress,\n }: {\n status: string;\n isComplete: boolean;\n progress: number;\n }) => {\n if (!indicator) {\n indicator = ora(status).start();\n }\n indicator.text = `${chalk.bold(status)} ${progress}%`;\n if (isComplete) {\n indicator.succeed();\n }\n }\n );\n } catch (error: any) {\n if (indicator) {\n indicator.fail();\n }\n throw error;\n }\n\n async function launchAppOptionally() {\n try {\n await launchAppWithDeviceCtl(udid, bundleIdentifier);\n } catch (error: any) {\n if (indicator) {\n indicator.fail();\n }\n if (error.code === 'APPLE_DEVICE_LOCKED') {\n // Get the app name from the binary path.\n const appName = path.basename(bundle).split('.')[0] ?? 'app';\n if (\n isInteractive() &&\n (await confirmAsync({\n message: `Cannot launch ${appName} because the device is locked. Unlock ${deviceName} to continue...`,\n initial: true,\n }))\n ) {\n return launchAppOptionally();\n }\n throw new CommandError(\n `Cannot launch ${appName} on ${deviceName} because the device is locked.`\n );\n }\n throw error;\n }\n }\n\n await launchAppOptionally();\n}\n"],"names":["devicectlAsync","getConnectedAppleDevicesAsync","hasDevicectlEverBeenInstalled","installAndLaunchAppAsync","launchAppWithDeviceCtl","launchBinaryOnMacAsync","DEVICE_CTL_EXISTS_PATH","path","join","getExpoHomeDirectory","debug","require","args","options","xcrunAsync","error","CommandError","errorCodes","getDeviceCtlErrorCodes","stderr","includes","tmpPath","createTempFilePath","devices","stdout","devicesJson","JsonFile","readAsync","info","jsonVersion","Log","warn","assertDevicesJson","result","results","assert","Array","isArray","JSON","stringify","bundleId","appBinaryPath","spawnAsync","code","message","installAppWithDeviceCtlAsync","uuid","bundleIdOrAppPath","onProgress","maxAttempts","attempt","installAppWithDeviceCtlInternalAsync","isTransientDisconnect","backoffDelay","Math","pow","Promise","resolve","setTimeout","reject","childProcess","spawn","currentProgress","hasStarted","updateProgress","progress","statusPrefix","isComplete","status","on","data","strings","toString","split","EOL","map","value","trim","forEach","str","match","parseInt","stderrBuffer","err","Error","detach","off","kill","installExitHooks","deviceId","log","matchAll","_line","hasEverBeenInstalled","fs","existsSync","isInstalled","isDevicectlInstalled","writeFileSync","execSync","stdio","props","bundle","bundleIdentifier","udid","deviceName","indicator","ora","start","text","chalk","bold","succeed","fail","launchAppOptionally","appName","basename","isInteractive","confirmAsync","initial"],"mappings":"AAAA;;;;;CAKC;;;;;;;;;;;IA8HqBA,cAAc;eAAdA;;IAoBAC,6BAA6B;eAA7BA;;IAiMNC,6BAA6B;eAA7BA;;IA+BMC,wBAAwB;eAAxBA;;IA1CAC,sBAAsB;eAAtBA;;IA/IAC,sBAAsB;eAAtBA;;;;gEAvLD;;;;;;;gEACiC;;;;;;;gEACpC;;;;;;;yBACc;;;;;;;gEACjB;;;;;;;gEACI;;;;;;;yBAEC;;;;;;;gEACH;;;;;;uBAEU;8BACU;6DAChB;gCACc;wBACN;sBACI;6BACH;qBACV;yBACS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAE7B,MAAMC,yBAAyBC,eAAI,CAACC,IAAI,CAACC,IAAAA,kCAAoB,KAAI;AAEjE,MAAMC,QAAQC,QAAQ,SAAS;AAsGxB,eAAeX,eACpBY,IAA4B,EAC5BC,OAAsB;IAEtB,IAAI;QACF,OAAO,MAAMC,IAAAA,iBAAU,EAAC;YAAC;eAAgBF;SAAK,EAAEC;IAClD,EAAE,OAAOE,OAAY;QACnB,IAAIA,iBAAiBC,oBAAY,EAAE;YACjC,MAAMD;QACR;QACA,IAAI,YAAYA,OAAO;YACrB,MAAME,aAAaC,uBAAuBH,MAAMI,MAAM;YACtD,IAAIF,WAAWG,QAAQ,CAAC,WAAW;gBACjC,MAAM,IAAIJ,oBAAY,CAAC,uBAAuB;YAChD;QACF;QACA,MAAMD;IACR;AACF;AAEO,eAAed;QAmBC;IAlBrB,IAAI,CAACC,iCAAiC;QACpCQ,MAAM;QACN,OAAO,EAAE;IACX;IAEA,MAAMW,UAAUC,IAAAA,kCAAkB;IAClC,MAAMC,UAAU,MAAMvB,eAAe;QACnC;QACA;QACA;QACAqB;QACA,wEAAwE;QACxE;QACA;KACD;IACDX,MAAMa,QAAQC,MAAM;IACpB,MAAMC,cAAc,MAAMC,mBAAQ,CAACC,SAAS,CAACN;IAE7C,IAAI,CAAC;QAAC;QAAG;KAAE,CAACD,QAAQ,CAAEK,gCAAD,oBAAA,AAACA,YAAqBG,IAAI,qBAA1B,kBAA4BC,WAAW,GAAG;QAC7DC,KAAIC,IAAI,CACN;IAEJ;IAEAC,kBAAkBP;IAElB,OAAOA,YAAYQ,MAAM,CAACV,OAAO;AACnC;AAEA,SAASS,kBACPE,OAAY;QAG8CA;IAD1DC,IAAAA,qBAAM,EACJD,WAAW,QAAQ,YAAYA,WAAWE,MAAMC,OAAO,CAACH,4BAAAA,kBAAAA,QAASD,MAAM,qBAAfC,gBAAiBX,OAAO,GAChF,2CAA2Ce,KAAKC,SAAS,CAACL,SAAS,MAAM;AAE7E;AAEO,eAAe7B,uBACpBmC,QAAgB,EAChBC,aAAqB;IAErB,MAAM7B,OAAO;QAAC;QAAM4B;QAAUC;KAAc;IAC5C,IAAI;QACF,MAAMC,IAAAA,qBAAU,EAAC,QAAQ9B;IAC3B,EAAE,OAAOG,OAAY;QACnB,IAAI,UAAUA,OAAO;YACnB,IAAIA,MAAM4B,IAAI,KAAK,GAAG;gBACpB,MAAM,IAAI3B,oBAAY,CACpB,gBACA,2DACEJ,KAAKJ,IAAI,CAAC,OACV,SACAO,MAAM6B,OAAO;YAEnB;QACF;QACA,MAAM7B;IACR;AACF;AAEA,eAAe8B,6BACbC,IAAY,EACZC,iBAAyB,EACzBC,UAAsF;IAEtF,MAAMC,cAAc;IACpB,IAAK,IAAIC,UAAU,GAAGA,WAAWD,aAAaC,UAAW;QACvD,IAAI;YACF,MAAMC,qCAAqCL,MAAMC,mBAAmBC,YAAYE;YAChF;QACF,EAAE,OAAOnC,OAAY;YACnB,IAAIA,MAAM4B,IAAI,KAAK,YAAY;gBAC7B,MAAM5B;YACR;YACA,MAAMqC,wBACJrC,MAAM6B,OAAO,IACZ7B,CAAAA,MAAM6B,OAAO,CAACxB,QAAQ,CAAC,sBAAsBL,MAAM6B,OAAO,CAACxB,QAAQ,CAAC,QAAO;YAE9E,IAAI,CAACgC,yBAAyBF,YAAYD,aAAa;gBACrD,MAAMlC;YACR;YACA,MAAMsC,eAAe,MAAMC,KAAKC,GAAG,CAAC,GAAGL,UAAU,KAAK;YACtD,MAAM,IAAIM,QAAQ,CAACC,UAAYC,WAAWD,SAASJ;QACrD;IACF;AACF;AAEA,eAAeF,qCACbL,IAAY,EACZC,iBAAyB,EACzBC,UAAsF,EACtFE,OAAe;IAEf,uNAAuN;IACvN,OAAO,IAAIM,QAAQ,CAACC,SAASE;QAC3B,MAAM/C,OAAiB;YACrB;YACA;YACA;YACA;YACA;YACAkC;YACAC;SACD;QACD,MAAMa,eAAeC,IAAAA,sBAAK,EAAC,SAASjD;QACpCF,MAAM,WAAWE,KAAKJ,IAAI,CAAC;QAE3B,IAAIsD,kBAAkB;QACtB,IAAIC,aAAa;QAEjB,SAASC,eAAeC,QAAgB;YACtCF,aAAa;YACb,IAAIE,YAAYH,iBAAiB;gBAC/B;YACF;YACAA,kBAAkBG;YAClB,MAAMC,eAAehB,UAAU,IAAI,CAAC,oBAAoB,EAAEA,QAAQ,CAAC,CAAC,GAAG;YACvEF,WAAW;gBACTiB;gBACAE,YAAYF,aAAa;gBACzBG,QAAQF;YACV;QACF;QAEAN,aAAapC,MAAM,CAAC6C,EAAE,CAAC,QAAQ,CAACC;YAC9B,kFAAkF;YAClF,wBAAwB;YACxB,MAAMC,UAAUD,KACbE,QAAQ,GACRC,KAAK,CAACC,SAAG,EACTC,GAAG,CAAC,CAACC,QAAUA,MAAMC,IAAI;YAE5BN,QAAQO,OAAO,CAAC,CAACC;gBACf,iCAAiC;gBACjC,0BAA0B;gBAC1B,mBAAmB;gBACnB,uBAAuB;gBAEvB,MAAMC,QAAQD,IAAIC,KAAK,CAAC;gBACxB,IAAIA,OAAO;oBACThB,eAAeiB,SAASD,KAAK,CAAC,EAAE,EAAE;gBACpC,OAAO,IAAIjB,YAAY;oBACrBC,eAAe;gBACjB;YACF;YAEAtD,MAAM,aAAa6D;QACrB;QAEA,IAAIW,eAAe;QACnBtB,aAAazC,MAAM,CAACkD,EAAE,CAAC,QAAQ,CAACC;YAC9BY,gBAAgBZ,KAAKE,QAAQ;QAC/B;QAEAZ,aAAaS,EAAE,CAAC,SAAS,CAAC1B;YACxBjC,MAAM,cAAciC;YACpB,IAAIA,SAAS,GAAG;gBACdc;YACF,OAAO;gBACL,MAAM0B,MAAM,IAAIC,MAAMF,gBAAgB,CAAC,8BAA8B,EAAEvC,MAAM;gBAC5EwC,IAAYxC,IAAI,GAAGA;gBACpB0C,OAAOF;YACT;QACF;QAEA,MAAME,SAAS,OAAOF;YACpBG,uBAAAA;YACA,IAAI1B,cAAc;gBAChB,OAAO,IAAIJ,QAAc,CAACC;oBACxBG,gCAAAA,aAAcS,EAAE,CAAC,SAAS,IAAMZ;oBAChCG,gCAAAA,aAAc2B,IAAI;oBAClB5B,OAAOwB,OAAO,IAAInE,oBAAY,CAAC;gBACjC;YACF;QACF;QAEA,MAAMsE,MAAME,IAAAA,sBAAgB,EAAC,IAAMH;IACrC;AACF;AAEO,eAAejF,uBAAuBqF,QAAgB,EAAEjD,QAAgB;IAC7E,MAAMxC,eAAe;QAAC;QAAU;QAAW;QAAU;QAAYyF;QAAUjD;KAAS;AACtF;AAEA,6CAA6C,GAC7C,SAAStB,uBAAuBwE,GAAW;IACzC,OAAO;WAAIA,IAAIC,QAAQ,CAAC;KAAyC,CAAChB,GAAG,CAAC,CAAC,CAACiB,OAAOjD,KAAK,GAAKA;AAC3F;AAEA,IAAIkD;AAEG,SAAS3F;IACd,IAAI2F,sBAAsB,OAAOA;IACjC,wHAAwH;IACxH,yFAAyF;IACzF,IAAIC,aAAE,CAACC,UAAU,CAACzF,yBAAyB;QACzCuF,uBAAuB;QACvB,OAAO;IACT;IAEA,MAAMG,cAAcC;IAEpB,IAAID,aAAa;QACfF,aAAE,CAACI,aAAa,CAAC5F,wBAAwB;IAC3C;IACAuF,uBAAuBG;IACvB,OAAOA;AACT;AAEA,SAASC;IACP,IAAI;QACFE,IAAAA,yBAAQ,EAAC,6BAA6B;YAAEC,OAAO;QAAS;QACxD,OAAO;IACT,EAAE,OAAM;QACN,OAAO;IACT;AACF;AAMO,eAAejG,yBAAyBkG,KAK9C;IACC3F,MAAM,sBAAsB2F;IAC5B,MAAM,EAAEC,MAAM,EAAEC,gBAAgB,EAAEC,IAAI,EAAEC,UAAU,EAAE,GAAGJ;IACvD,IAAIK;IAEJ,IAAI;QACF,IAAI,CAACA,WAAW;YACdA,YAAYC,IAAAA,QAAG,EAAC,CAAC,eAAe,EAAEN,MAAMI,UAAU,EAAE,EAAEG,KAAK;QAC7D;QAEA,MAAM/D,6BACJ2D,MACAF,QACA,CAAC,EACClC,MAAM,EACND,UAAU,EACVF,QAAQ,EAKT;YACC,IAAI,CAACyC,WAAW;gBACdA,YAAYC,IAAAA,QAAG,EAACvC,QAAQwC,KAAK;YAC/B;YACAF,UAAUG,IAAI,GAAG,GAAGC,gBAAK,CAACC,IAAI,CAAC3C,QAAQ,CAAC,EAAEH,SAAS,CAAC,CAAC;YACrD,IAAIE,YAAY;gBACduC,UAAUM,OAAO;YACnB;QACF;IAEJ,EAAE,OAAOjG,OAAY;QACnB,IAAI2F,WAAW;YACbA,UAAUO,IAAI;QAChB;QACA,MAAMlG;IACR;IAEA,eAAemG;QACb,IAAI;YACF,MAAM9G,uBAAuBoG,MAAMD;QACrC,EAAE,OAAOxF,OAAY;YACnB,IAAI2F,WAAW;gBACbA,UAAUO,IAAI;YAChB;YACA,IAAIlG,MAAM4B,IAAI,KAAK,uBAAuB;gBACxC,yCAAyC;gBACzC,MAAMwE,UAAU5G,eAAI,CAAC6G,QAAQ,CAACd,QAAQ7B,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI;gBACvD,IACE4C,IAAAA,0BAAa,OACZ,MAAMC,IAAAA,qBAAY,EAAC;oBAClB1E,SAAS,CAAC,cAAc,EAAEuE,QAAQ,sCAAsC,EAAEV,WAAW,eAAe,CAAC;oBACrGc,SAAS;gBACX,IACA;oBACA,OAAOL;gBACT;gBACA,MAAM,IAAIlG,oBAAY,CACpB,CAAC,cAAc,EAAEmG,QAAQ,IAAI,EAAEV,WAAW,8BAA8B,CAAC;YAE7E;YACA,MAAM1F;QACR;IACF;IAEA,MAAMmG;AACR"}
@@ -17,6 +17,7 @@ _export(exports, {
17
17
  }
18
18
  });
19
19
  const _DevToolsPlugin = require("./DevToolsPlugin");
20
+ const _log = require("../../log");
20
21
  const debug = require('debug')('expo:start:server:devtools');
21
22
  const DevToolsPluginEndpoint = '/_expo/plugins';
22
23
  class DevToolsPluginManager {
@@ -44,7 +45,15 @@ class DevToolsPluginManager {
44
45
  const { resolveModuleAsync } = autolinking.getLinkingImplementationForPlatform('devtools');
45
46
  const plugins = (await Promise.all(Object.values(revisions).map((revision)=>resolveModuleAsync(revision.name, revision)))).filter((maybePlugin)=>maybePlugin != null);
46
47
  debug('Found autolinked plugins', plugins);
47
- return plugins.map((pluginInfo)=>new _DevToolsPlugin.DevToolsPlugin(pluginInfo, this.projectRoot)).filter((p)=>p != null);
48
+ return plugins.map((pluginInfo)=>{
49
+ try {
50
+ return new _DevToolsPlugin.DevToolsPlugin(pluginInfo, this.projectRoot);
51
+ } catch (error) {
52
+ _log.Log.warn(`Skipping plugin "${pluginInfo.packageName}": ${error.message ?? 'invalid configuration'}`);
53
+ debug('Plugin validation error for %s: %O', pluginInfo.packageName, error);
54
+ return null;
55
+ }
56
+ }).filter((p)=>p != null);
48
57
  }
49
58
  }
50
59
 
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/start/server/DevToolsPluginManager.ts"],"sourcesContent":["import type { ModuleDescriptorDevTools } from 'expo-modules-autolinking/exports';\n\nimport { DevToolsPlugin } from './DevToolsPlugin';\nimport { Log } from '../../log';\n\nconst debug = require('debug')('expo:start:server:devtools');\n\nexport const DevToolsPluginEndpoint = '/_expo/plugins';\n\nexport default class DevToolsPluginManager {\n private plugins: DevToolsPlugin[] | null = null;\n\n constructor(private projectRoot: string) {}\n\n public async queryPluginsAsync(): Promise<DevToolsPlugin[]> {\n if (!this.plugins) {\n this.plugins = await this.queryAutolinkedPluginsAsync(this.projectRoot);\n }\n return this.plugins;\n }\n\n public async queryPluginWebpageRootAsync(pluginName: string): Promise<string | null> {\n const plugins = await this.queryPluginsAsync();\n const plugin = plugins.find((p) => p.packageName === pluginName);\n return plugin?.webpageRoot ?? null;\n }\n\n private async queryAutolinkedPluginsAsync(projectRoot: string): Promise<DevToolsPlugin[]> {\n const autolinking: typeof import('expo/internal/unstable-autolinking-exports') = require('expo/internal/unstable-autolinking-exports');\n const linker = autolinking.makeCachedDependenciesLinker({ projectRoot });\n const revisions = await autolinking.scanExpoModuleResolutionsForPlatform(linker, 'devtools');\n const { resolveModuleAsync } = autolinking.getLinkingImplementationForPlatform('devtools');\n const plugins: ModuleDescriptorDevTools[] = (\n await Promise.all(\n Object.values(revisions).map((revision) => resolveModuleAsync(revision.name, revision))\n )\n ).filter((maybePlugin) => maybePlugin != null);\n debug('Found autolinked plugins', plugins);\n return plugins\n .map((pluginInfo) => new DevToolsPlugin(pluginInfo, this.projectRoot))\n .filter((p) => p != null) as DevToolsPlugin[];\n }\n}\n"],"names":["DevToolsPluginEndpoint","DevToolsPluginManager","debug","require","constructor","projectRoot","plugins","queryPluginsAsync","queryAutolinkedPluginsAsync","queryPluginWebpageRootAsync","pluginName","plugin","find","p","packageName","webpageRoot","autolinking","linker","makeCachedDependenciesLinker","revisions","scanExpoModuleResolutionsForPlatform","resolveModuleAsync","getLinkingImplementationForPlatform","Promise","all","Object","values","map","revision","name","filter","maybePlugin","pluginInfo","DevToolsPlugin"],"mappings":";;;;;;;;;;;IAOaA,sBAAsB;eAAtBA;;IAEb,OAiCC;eAjCoBC;;;gCAPU;AAG/B,MAAMC,QAAQC,QAAQ,SAAS;AAExB,MAAMH,yBAAyB;AAEvB,MAAMC;IAGnBG,YAAY,AAAQC,WAAmB,CAAE;aAArBA,cAAAA;aAFZC,UAAmC;IAED;IAE1C,MAAaC,oBAA+C;QAC1D,IAAI,CAAC,IAAI,CAACD,OAAO,EAAE;YACjB,IAAI,CAACA,OAAO,GAAG,MAAM,IAAI,CAACE,2BAA2B,CAAC,IAAI,CAACH,WAAW;QACxE;QACA,OAAO,IAAI,CAACC,OAAO;IACrB;IAEA,MAAaG,4BAA4BC,UAAkB,EAA0B;QACnF,MAAMJ,UAAU,MAAM,IAAI,CAACC,iBAAiB;QAC5C,MAAMI,SAASL,QAAQM,IAAI,CAAC,CAACC,IAAMA,EAAEC,WAAW,KAAKJ;QACrD,OAAOC,CAAAA,0BAAAA,OAAQI,WAAW,KAAI;IAChC;IAEA,MAAcP,4BAA4BH,WAAmB,EAA6B;QACxF,MAAMW,cAA2Eb,QAAQ;QACzF,MAAMc,SAASD,YAAYE,4BAA4B,CAAC;YAAEb;QAAY;QACtE,MAAMc,YAAY,MAAMH,YAAYI,oCAAoC,CAACH,QAAQ;QACjF,MAAM,EAAEI,kBAAkB,EAAE,GAAGL,YAAYM,mCAAmC,CAAC;QAC/E,MAAMhB,UAAsC,AAC1C,CAAA,MAAMiB,QAAQC,GAAG,CACfC,OAAOC,MAAM,CAACP,WAAWQ,GAAG,CAAC,CAACC,WAAaP,mBAAmBO,SAASC,IAAI,EAAED,WAC/E,EACAE,MAAM,CAAC,CAACC,cAAgBA,eAAe;QACzC7B,MAAM,4BAA4BI;QAClC,OAAOA,QACJqB,GAAG,CAAC,CAACK,aAAe,IAAIC,8BAAc,CAACD,YAAY,IAAI,CAAC3B,WAAW,GACnEyB,MAAM,CAAC,CAACjB,IAAMA,KAAK;IACxB;AACF"}
1
+ {"version":3,"sources":["../../../../src/start/server/DevToolsPluginManager.ts"],"sourcesContent":["import type { ModuleDescriptorDevTools } from 'expo-modules-autolinking/exports';\n\nimport { DevToolsPlugin } from './DevToolsPlugin';\nimport { Log } from '../../log';\n\nconst debug = require('debug')('expo:start:server:devtools');\n\nexport const DevToolsPluginEndpoint = '/_expo/plugins';\n\nexport default class DevToolsPluginManager {\n private plugins: DevToolsPlugin[] | null = null;\n\n constructor(private projectRoot: string) {}\n\n public async queryPluginsAsync(): Promise<DevToolsPlugin[]> {\n if (!this.plugins) {\n this.plugins = await this.queryAutolinkedPluginsAsync(this.projectRoot);\n }\n return this.plugins;\n }\n\n public async queryPluginWebpageRootAsync(pluginName: string): Promise<string | null> {\n const plugins = await this.queryPluginsAsync();\n const plugin = plugins.find((p) => p.packageName === pluginName);\n return plugin?.webpageRoot ?? null;\n }\n\n private async queryAutolinkedPluginsAsync(projectRoot: string): Promise<DevToolsPlugin[]> {\n const autolinking: typeof import('expo/internal/unstable-autolinking-exports') = require('expo/internal/unstable-autolinking-exports');\n const linker = autolinking.makeCachedDependenciesLinker({ projectRoot });\n const revisions = await autolinking.scanExpoModuleResolutionsForPlatform(linker, 'devtools');\n const { resolveModuleAsync } = autolinking.getLinkingImplementationForPlatform('devtools');\n const plugins: ModuleDescriptorDevTools[] = (\n await Promise.all(\n Object.values(revisions).map((revision) => resolveModuleAsync(revision.name, revision))\n )\n ).filter((maybePlugin) => maybePlugin != null);\n debug('Found autolinked plugins', plugins);\n return plugins\n .map((pluginInfo) => {\n try {\n return new DevToolsPlugin(pluginInfo, this.projectRoot);\n } catch (error: any) {\n Log.warn(\n `Skipping plugin \"${pluginInfo.packageName}\": ${error.message ?? 'invalid configuration'}`\n );\n debug('Plugin validation error for %s: %O', pluginInfo.packageName, error);\n return null;\n }\n })\n .filter((p) => p != null) as DevToolsPlugin[];\n }\n}\n"],"names":["DevToolsPluginEndpoint","DevToolsPluginManager","debug","require","constructor","projectRoot","plugins","queryPluginsAsync","queryAutolinkedPluginsAsync","queryPluginWebpageRootAsync","pluginName","plugin","find","p","packageName","webpageRoot","autolinking","linker","makeCachedDependenciesLinker","revisions","scanExpoModuleResolutionsForPlatform","resolveModuleAsync","getLinkingImplementationForPlatform","Promise","all","Object","values","map","revision","name","filter","maybePlugin","pluginInfo","DevToolsPlugin","error","Log","warn","message"],"mappings":";;;;;;;;;;;IAOaA,sBAAsB;eAAtBA;;IAEb,OA2CC;eA3CoBC;;;gCAPU;qBACX;AAEpB,MAAMC,QAAQC,QAAQ,SAAS;AAExB,MAAMH,yBAAyB;AAEvB,MAAMC;IAGnBG,YAAY,AAAQC,WAAmB,CAAE;aAArBA,cAAAA;aAFZC,UAAmC;IAED;IAE1C,MAAaC,oBAA+C;QAC1D,IAAI,CAAC,IAAI,CAACD,OAAO,EAAE;YACjB,IAAI,CAACA,OAAO,GAAG,MAAM,IAAI,CAACE,2BAA2B,CAAC,IAAI,CAACH,WAAW;QACxE;QACA,OAAO,IAAI,CAACC,OAAO;IACrB;IAEA,MAAaG,4BAA4BC,UAAkB,EAA0B;QACnF,MAAMJ,UAAU,MAAM,IAAI,CAACC,iBAAiB;QAC5C,MAAMI,SAASL,QAAQM,IAAI,CAAC,CAACC,IAAMA,EAAEC,WAAW,KAAKJ;QACrD,OAAOC,CAAAA,0BAAAA,OAAQI,WAAW,KAAI;IAChC;IAEA,MAAcP,4BAA4BH,WAAmB,EAA6B;QACxF,MAAMW,cAA2Eb,QAAQ;QACzF,MAAMc,SAASD,YAAYE,4BAA4B,CAAC;YAAEb;QAAY;QACtE,MAAMc,YAAY,MAAMH,YAAYI,oCAAoC,CAACH,QAAQ;QACjF,MAAM,EAAEI,kBAAkB,EAAE,GAAGL,YAAYM,mCAAmC,CAAC;QAC/E,MAAMhB,UAAsC,AAC1C,CAAA,MAAMiB,QAAQC,GAAG,CACfC,OAAOC,MAAM,CAACP,WAAWQ,GAAG,CAAC,CAACC,WAAaP,mBAAmBO,SAASC,IAAI,EAAED,WAC/E,EACAE,MAAM,CAAC,CAACC,cAAgBA,eAAe;QACzC7B,MAAM,4BAA4BI;QAClC,OAAOA,QACJqB,GAAG,CAAC,CAACK;YACJ,IAAI;gBACF,OAAO,IAAIC,8BAAc,CAACD,YAAY,IAAI,CAAC3B,WAAW;YACxD,EAAE,OAAO6B,OAAY;gBACnBC,QAAG,CAACC,IAAI,CACN,CAAC,iBAAiB,EAAEJ,WAAWlB,WAAW,CAAC,GAAG,EAAEoB,MAAMG,OAAO,IAAI,yBAAyB;gBAE5FnC,MAAM,sCAAsC8B,WAAWlB,WAAW,EAAEoB;gBACpE,OAAO;YACT;QACF,GACCJ,MAAM,CAAC,CAACjB,IAAMA,KAAK;IACxB;AACF"}
@@ -7,10 +7,18 @@
7
7
  Object.defineProperty(exports, "__esModule", {
8
8
  value: true
9
9
  });
10
- Object.defineProperty(exports, "MetroBundlerDevServer", {
11
- enumerable: true,
12
- get: function() {
10
+ function _export(target, all) {
11
+ for(var name in all)Object.defineProperty(target, name, {
12
+ enumerable: true,
13
+ get: all[name]
14
+ });
15
+ }
16
+ _export(exports, {
17
+ MetroBundlerDevServer: function() {
13
18
  return MetroBundlerDevServer;
19
+ },
20
+ event: function() {
21
+ return event;
14
22
  }
15
23
  });
16
24
  function _config() {
@@ -92,6 +100,7 @@ const _metroWatchTypeScriptFiles = require("./metroWatchTypeScriptFiles");
92
100
  const _router = require("./router");
93
101
  const _serializeHtml = require("./serializeHtml");
94
102
  const _waitForMetroToObserveTypeScriptFile = require("./waitForMetroToObserveTypeScriptFile");
103
+ const _events = require("../../../events");
95
104
  const _log = require("../../../log");
96
105
  const _env = require("../../../utils/env");
97
106
  const _errors = require("../../../utils/errors");
@@ -163,6 +172,9 @@ function _interop_require_wildcard(obj, nodeInterop) {
163
172
  const debug = require('debug')('expo:start:server:metro');
164
173
  /** Default port to use for apps running in Expo Go. */ const EXPO_GO_METRO_PORT = 8081;
165
174
  /** Default port to use for apps that run in standard React Native projects or Expo Dev Clients. */ const DEV_CLIENT_METRO_PORT = 8081;
175
+ const event = (0, _events.events)('devserver', (t)=>[
176
+ t.event()
177
+ ]);
166
178
  class MetroBundlerDevServer extends _BundlerDevServer.BundlerDevServer {
167
179
  get name() {
168
180
  return 'metro';
@@ -844,6 +856,18 @@ class MetroBundlerDevServer extends _BundlerDevServer.BundlerDevServer {
844
856
  };
845
857
  // Required for symbolication:
846
858
  process.env.EXPO_DEV_SERVER_ORIGIN = `http://localhost:${options.port}`;
859
+ event('start', {
860
+ mode,
861
+ web: this.isTargetingWeb(),
862
+ baseUrl,
863
+ asyncRoutes,
864
+ routerRoot: event.path(appDir),
865
+ serverComponents: this.isReactServerComponentsEnabled,
866
+ serverActions: isReactServerActionsOnlyEnabled,
867
+ serverRendering: useServerRendering,
868
+ apiRoutes: hasApiRoutes,
869
+ exporting: !!options.isExporting
870
+ });
847
871
  const { metro, hmrServer, server, middleware, messageSocket } = await (0, _instantiateMetro.instantiateMetroAsync)(this, parsedOptions, {
848
872
  isExporting: !!options.isExporting,
849
873
  exp