@expo/cli 54.0.8 → 54.1.0-canary-20250930-9dc59d3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/bin/cli +1 -1
- package/build/src/start/doctor/dependencies/getVersionedPackages.js +0 -4
- package/build/src/start/doctor/dependencies/getVersionedPackages.js.map +1 -1
- package/build/src/start/doctor/dependencies/validateDependenciesVersions.js +3 -0
- package/build/src/start/doctor/dependencies/validateDependenciesVersions.js.map +1 -1
- package/build/src/start/interface/cliExtensionMenuItemHandler.js +173 -0
- package/build/src/start/interface/cliExtensionMenuItemHandler.js.map +1 -0
- package/build/src/start/interface/createDevToolsMenuItems.js +159 -0
- package/build/src/start/interface/createDevToolsMenuItems.js.map +1 -0
- package/build/src/start/interface/interactiveActions.js +8 -12
- package/build/src/start/interface/interactiveActions.js.map +1 -1
- package/build/src/start/platforms/android/adb.js +1 -1
- package/build/src/start/platforms/android/adb.js.map +1 -1
- package/build/src/start/server/DevToolsPlugin.js +60 -0
- package/build/src/start/server/DevToolsPlugin.js.map +1 -0
- package/build/src/start/server/DevToolsPlugin.schema.js +79 -0
- package/build/src/start/server/DevToolsPlugin.schema.js.map +1 -0
- package/build/src/start/server/DevToolsPluginCliExtensionExecutor.js +119 -0
- package/build/src/start/server/DevToolsPluginCliExtensionExecutor.js.map +1 -0
- package/build/src/start/server/DevToolsPluginCliExtensionResults.js +61 -0
- package/build/src/start/server/DevToolsPluginCliExtensionResults.js.map +1 -0
- package/build/src/start/server/DevToolsPluginManager.js +4 -8
- package/build/src/start/server/DevToolsPluginManager.js.map +1 -1
- package/build/src/start/server/metro/MetroBundlerDevServer.js +125 -9
- package/build/src/start/server/metro/MetroBundlerDevServer.js.map +1 -1
- package/build/src/start/server/metro/createServerRouteMiddleware.js +6 -5
- package/build/src/start/server/metro/createServerRouteMiddleware.js.map +1 -1
- package/build/src/start/server/metro/router.js.map +1 -1
- package/build/src/start/server/middleware/DataLoaderModuleMiddleware.js +75 -0
- package/build/src/start/server/middleware/DataLoaderModuleMiddleware.js.map +1 -0
- package/build/src/utils/telemetry/clients/FetchClient.js +1 -1
- package/build/src/utils/telemetry/utils/context.js +1 -1
- package/package.json +20 -20
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/start/interface/interactiveActions.ts"],"sourcesContent":["import chalk from 'chalk';\n\nimport { BLT, printHelp, printItem, printQRCode, printUsage, StartOptions } from './commandsTable';\nimport * as Log from '../../log';\nimport { env } from '../../utils/env';\nimport { learnMore } from '../../utils/link';\nimport { openBrowserAsync } from '../../utils/open';\nimport { ExpoChoice, selectAsync } from '../../utils/prompts';\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 // 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 printQRCode(interstitialPageUrl ?? nativeRuntimeUrl);\n\n if (interstitialPageUrl) {\n Log.log(\n printItem(\n chalk`Choose an app to open your project at {underline ${interstitialPageUrl}}`\n )\n );\n }\n\n if (env.__EXPO_E2E_TEST) {\n // Print the URL to stdout for tests\n console.info(\n `[__EXPO_E2E_TEST:server] ${JSON.stringify({ url: devServer.getDevServerUrl() })}`\n );\n }\n\n Log.log(printItem(chalk`Metro waiting on {underline ${nativeRuntimeUrl}}`));\n if (options.devClient === false) {\n // TODO: if development build, change this message!\n Log.log(\n printItem('Scan the QR code above with Expo Go (Android) or the Camera app (iOS)')\n );\n } else {\n Log.log(\n printItem(\n 'Scan the QR code above to open the project in a development build. ' +\n learnMore('https://expo.fyi/start')\n )\n );\n }\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 waiting on {underline ${serverUrl}}`));\n Log.log(printItem(`Linking is disabled because the client scheme cannot be resolved.`));\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();\n Log.log(printItem(chalk`Web is waiting on {underline ${webUrl}}`));\n }\n }\n\n printUsage(options, { verbose: false });\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 const pluginMenuItems = (\n await this.devServerManager.devtoolsPluginManager.queryPluginsAsync()\n ).map((plugin) => ({\n title: chalk`Open {bold ${plugin.packageName}}`,\n value: `devtoolsPlugin:${plugin.packageName}`,\n action: async () => {\n const url = new URL(\n plugin.webpageEndpoint,\n this.devServerManager\n .getDefaultDevServer()\n .getUrlCreator()\n .constructUrl({ scheme: 'http' })\n );\n await openBrowserAsync(url.toString());\n },\n }));\n const menuItems = [...defaultMenuItems, ...pluginMenuItems];\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","getNativeDevServerPort","devServer","getDefaultDevServer","nativeRuntimeUrl","getNativeRuntimeUrl","interstitialPageUrl","getRedirectUrl","printQRCode","Log","log","printItem","chalk","env","__EXPO_E2E_TEST","console","info","JSON","stringify","url","getDevServerUrl","devClient","learnMore","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","pluginMenuItems","devtoolsPluginManager","queryPluginsAsync","map","plugin","packageName","action","URL","webpageEndpoint","getUrlCreator","constructUrl","scheme","openBrowserAsync","toString","menuItems","selectAsync","menuItem","find","item","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, printQRCode, printUsage, StartOptions } from './commandsTable';\nimport { createDevToolsMenuItems } from './createDevToolsMenuItems';\nimport * as Log from '../../log';\nimport { env } from '../../utils/env';\nimport { learnMore } from '../../utils/link';\nimport { openBrowserAsync } from '../../utils/open';\nimport { ExpoChoice, selectAsync } from '../../utils/prompts';\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 // 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 printQRCode(interstitialPageUrl ?? nativeRuntimeUrl);\n\n if (interstitialPageUrl) {\n Log.log(\n printItem(\n chalk`Choose an app to open your project at {underline ${interstitialPageUrl}}`\n )\n );\n }\n\n if (env.__EXPO_E2E_TEST) {\n // Print the URL to stdout for tests\n console.info(\n `[__EXPO_E2E_TEST:server] ${JSON.stringify({ url: devServer.getDevServerUrl() })}`\n );\n }\n\n Log.log(printItem(chalk`Metro waiting on {underline ${nativeRuntimeUrl}}`));\n if (options.devClient === false) {\n // TODO: if development build, change this message!\n Log.log(\n printItem('Scan the QR code above with Expo Go (Android) or the Camera app (iOS)')\n );\n } else {\n Log.log(\n printItem(\n 'Scan the QR code above to open the project in a development build. ' +\n learnMore('https://expo.fyi/start')\n )\n );\n }\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 waiting on {underline ${serverUrl}}`));\n Log.log(printItem(`Linking is disabled because the client scheme cannot be resolved.`));\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();\n Log.log(printItem(chalk`Web is waiting on {underline ${webUrl}}`));\n }\n }\n\n printUsage(options, { verbose: false });\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 Log.log();\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","getNativeDevServerPort","devServer","getDefaultDevServer","nativeRuntimeUrl","getNativeRuntimeUrl","interstitialPageUrl","getRedirectUrl","printQRCode","Log","log","printItem","chalk","env","__EXPO_E2E_TEST","console","info","JSON","stringify","url","getDevServerUrl","devClient","learnMore","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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"}
|
|
@@ -190,7 +190,7 @@ async function launchActivityAsync(device, { launchActivity, url }) {
|
|
|
190
190
|
return openAsync(adbArgs(device.pid, ...args));
|
|
191
191
|
}
|
|
192
192
|
async function openAppIdAsync(device, { applicationId }) {
|
|
193
|
-
return openAsync(adbArgs(device.pid, 'shell', 'monkey', '-p', applicationId, '-c', 'android.intent.category.LAUNCHER', '1'));
|
|
193
|
+
return openAsync(adbArgs(device.pid, 'shell', 'monkey', '--pct-syskeys', '0', '-p', applicationId, '-c', 'android.intent.category.LAUNCHER', '1'));
|
|
194
194
|
}
|
|
195
195
|
async function openUrlAsync(device, { url }) {
|
|
196
196
|
return openAsync(adbArgs(device.pid, 'shell', 'am', 'start', '-a', 'android.intent.action.VIEW', '-d', // ADB requires ampersands to be escaped.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../src/start/platforms/android/adb.ts"],"sourcesContent":["import chalk from 'chalk';\nimport os from 'os';\n\nimport { ADBServer } from './ADBServer';\nimport * as Log from '../../../log';\nimport { env } from '../../../utils/env';\nimport { CommandError } from '../../../utils/errors';\nimport { learnMore } from '../../../utils/link';\n\nconst debug = require('debug')('expo:start:platforms:android:adb') as typeof console.log;\n\nexport enum DeviceABI {\n // The arch specific android target platforms are soft-deprecated.\n // Instead of using TargetPlatform as a combination arch + platform\n // the code will be updated to carry arch information in [DarwinArch]\n // and [AndroidArch].\n arm = 'arm',\n arm64 = 'arm64',\n x64 = 'x64',\n x86 = 'x86',\n x8664 = 'x86_64',\n arm64v8a = 'arm64-v8a',\n armeabiV7a = 'armeabi-v7a',\n armeabi = 'armeabi',\n universal = 'universal',\n}\n\n/** Represents a connected Android device. */\nexport type Device = {\n /** Process ID. */\n pid?: string;\n /** Name of the device, also used as the ID for opening devices. */\n name: string;\n /** Is emulator or connected device. */\n type: 'emulator' | 'device';\n /** Is the device booted (emulator). */\n isBooted: boolean;\n /** Is device authorized for developing. https://expo.fyi/authorize-android-device */\n isAuthorized: boolean;\n /** The connection type to ADB, only available when `type: device` */\n connectionType?: 'USB' | 'Network';\n};\n\ntype DeviceContext = Pick<Device, 'pid'>;\n\ntype DeviceProperties = Record<string, string>;\n\nconst CANT_START_ACTIVITY_ERROR = 'Activity not started, unable to resolve Intent';\n// http://developer.android.com/ndk/guides/abis.html\nconst PROP_CPU_NAME = 'ro.product.cpu.abi';\n\nconst PROP_CPU_ABI_LIST_NAME = 'ro.product.cpu.abilist';\n\n// Can sometimes be null\n// http://developer.android.com/ndk/guides/abis.html\nconst PROP_BOOT_ANIMATION_STATE = 'init.svc.bootanim';\n\nlet _server: ADBServer | null;\n\n/** Return the lazily loaded ADB server instance. */\nexport function getServer() {\n _server ??= new ADBServer();\n return _server;\n}\n\n/** Logs an FYI message about authorizing your device. */\nexport function logUnauthorized(device: Device) {\n Log.warn(\n `\\nThis computer is not authorized for developing on ${chalk.bold(device.name)}. ${chalk.dim(\n learnMore('https://expo.fyi/authorize-android-device')\n )}`\n );\n}\n\n/** Returns true if the provided package name is installed on the provided Android device. */\nexport async function isPackageInstalledAsync(\n device: DeviceContext,\n androidPackage: string\n): Promise<boolean> {\n const packages = await getServer().runAsync(\n adbArgs(\n device.pid,\n 'shell',\n 'pm',\n 'list',\n 'packages',\n '--user',\n env.EXPO_ADB_USER,\n androidPackage\n )\n );\n\n const lines = packages.split(/\\r?\\n/);\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i].trim();\n if (line === `package:${androidPackage}`) {\n return true;\n }\n }\n return false;\n}\n\n/**\n * @param device.pid Process ID of the Android device to launch.\n * @param props.launchActivity Activity to launch `[application identifier]/.[main activity name]`, ex: `com.bacon.app/.MainActivity`\n * @param props.url Optional (dev client) URL to launch\n */\nexport async function launchActivityAsync(\n device: DeviceContext,\n {\n launchActivity,\n url,\n }: {\n launchActivity: string;\n url?: string;\n }\n) {\n const args: string[] = [\n 'shell',\n 'am',\n 'start',\n // FLAG_ACTIVITY_SINGLE_TOP -- If set, the activity will not be launched if it is already running at the top of the history stack.\n '-f',\n '0x20000000',\n // Activity to open first: com.bacon.app/.MainActivity\n '-n',\n launchActivity,\n ];\n\n if (url) {\n args.push('-d', url);\n }\n\n return openAsync(adbArgs(device.pid, ...args));\n}\n\n/**\n * @param device.pid Process ID of the Android device to launch.\n * @param props.applicationId package name to launch.\n */\nexport async function openAppIdAsync(\n device: DeviceContext,\n {\n applicationId,\n }: {\n applicationId: string;\n }\n) {\n return openAsync(\n adbArgs(\n device.pid,\n 'shell',\n 'monkey',\n '-p',\n applicationId,\n '-c',\n 'android.intent.category.LAUNCHER',\n '1'\n )\n );\n}\n\n/**\n * @param device.pid Process ID of the Android device to launch.\n * @param props.url URL to launch.\n */\nexport async function openUrlAsync(\n device: DeviceContext,\n {\n url,\n }: {\n url: string;\n }\n) {\n return openAsync(\n adbArgs(\n device.pid,\n 'shell',\n 'am',\n 'start',\n '-a',\n 'android.intent.action.VIEW',\n '-d',\n // ADB requires ampersands to be escaped.\n url.replace(/&/g, String.raw`\\&`)\n )\n );\n}\n\n/** Runs a generic command watches for common errors in order to throw with an expected code. */\nasync function openAsync(args: string[]): Promise<string> {\n const results = await getServer().runAsync(args);\n if (\n results.includes(CANT_START_ACTIVITY_ERROR) ||\n results.match(/Error: Activity class .* does not exist\\./g)\n ) {\n throw new CommandError('APP_NOT_INSTALLED', results.substring(results.indexOf('Error: ')));\n }\n return results;\n}\n\n/** Uninstall an app given its Android package name. */\nexport async function uninstallAsync(\n device: DeviceContext,\n { appId }: { appId: string }\n): Promise<string> {\n return await getServer().runAsync(\n adbArgs(device.pid, 'uninstall', '--user', env.EXPO_ADB_USER, appId)\n );\n}\n\n/** Get package info from an app based on its Android package name. */\nexport async function getPackageInfoAsync(\n device: DeviceContext,\n { appId }: { appId: string }\n): Promise<string> {\n return await getServer().runAsync(adbArgs(device.pid, 'shell', 'dumpsys', 'package', appId));\n}\n\n/** Install an app on a connected device. */\nexport async function installAsync(device: DeviceContext, { filePath }: { filePath: string }) {\n // TODO: Handle the `INSTALL_FAILED_INSUFFICIENT_STORAGE` error.\n return await getServer().runAsync(\n adbArgs(device.pid, 'install', '-r', '-d', '--user', env.EXPO_ADB_USER, filePath)\n );\n}\n\n/** Format ADB args with process ID. */\nexport function adbArgs(pid: Device['pid'], ...options: string[]): string[] {\n const args = [];\n if (pid) {\n args.push('-s', pid);\n }\n\n return args.concat(options);\n}\n\n// TODO: This is very expensive for some operations.\nexport async function getAttachedDevicesAsync(): Promise<Device[]> {\n const output = await getServer().runAsync(['devices', '-l']);\n\n const splitItems = output\n .trim()\n .replace(/\\n$/, '')\n .split(os.EOL)\n // Filter ADB trace logs from the output, e.g.\n // adb D 03-06 15:25:53 63677 4018815 adb_client.cpp:393] adb_query: host:devices-l\n // 03-04 12:29:44.557 16415 16415 D adb : commandline.cpp:1646 Using server socket: tcp:172.27.192.1:5037\n // 03-04 12:29:44.557 16415 16415 D adb : adb_client.cpp:160 _adb_connect: host:version\n .filter((line) => !line.match(/\\.cpp:[0-9]+/));\n\n // First line is `\"List of devices attached\"`, remove it\n // @ts-ignore: todo\n const attachedDevices: {\n props: string[];\n type: Device['type'];\n isAuthorized: Device['isAuthorized'];\n isBooted: Device['isBooted'];\n connectionType?: Device['connectionType'];\n }[] = splitItems\n .slice(1, splitItems.length)\n .map((line) => {\n // unauthorized: ['FA8251A00719', 'unauthorized', 'usb:338690048X', 'transport_id:5']\n // authorized: ['FA8251A00719', 'device', 'usb:336592896X', 'product:walleye', 'model:Pixel_2', 'device:walleye', 'transport_id:4']\n // emulator: ['emulator-5554', 'offline', 'transport_id:1']\n const props = line.split(' ').filter(Boolean);\n const type = line.includes('emulator') ? 'emulator' : 'device';\n\n let connectionType;\n if (type === 'device' && line.includes('usb:')) {\n connectionType = 'USB';\n } else if (type === 'device' && line.includes('_adb-tls-connect.')) {\n connectionType = 'Network';\n }\n\n const isBooted = type === 'emulator' || props[1] !== 'offline';\n const isAuthorized =\n connectionType === 'Network'\n ? line.includes('model:') // Network connected devices show `model:<name>` when authorized\n : props[1] !== 'unauthorized';\n\n return { props, type, isAuthorized, isBooted, connectionType };\n })\n .filter(({ props: [pid] }) => !!pid);\n\n const devicePromises = attachedDevices.map<Promise<Device>>(async (props) => {\n const {\n type,\n props: [pid, ...deviceInfo],\n isAuthorized,\n isBooted,\n } = props;\n\n let name: string | null = null;\n\n if (type === 'device') {\n if (isAuthorized) {\n // Possibly formatted like `model:Pixel_2`\n // Transform to `Pixel_2`\n const modelItem = deviceInfo.find((info) => info.includes('model:'));\n if (modelItem) {\n name = modelItem.replace('model:', '');\n }\n }\n // unauthorized devices don't have a name available to read\n if (!name) {\n // Device FA8251A00719\n name = `Device ${pid}`;\n }\n } else {\n // Given an emulator pid, get the emulator name which can be used to start the emulator later.\n name = (await getAdbNameForDeviceIdAsync({ pid })) ?? '';\n }\n\n return props.connectionType\n ? { pid, name, type, isAuthorized, isBooted, connectionType: props.connectionType }\n : { pid, name, type, isAuthorized, isBooted };\n });\n\n return Promise.all(devicePromises);\n}\n\n/**\n * Return the Emulator name for an emulator ID, this can be used to determine if an emulator is booted.\n *\n * @param device.pid a value like `emulator-5554` from `abd devices`\n */\nexport async function getAdbNameForDeviceIdAsync(device: DeviceContext): Promise<string | null> {\n const results = await getServer().runAsync(adbArgs(device.pid, 'emu', 'avd', 'name'));\n\n if (results.match(/could not connect to TCP port .*: Connection refused/)) {\n // Can also occur when the emulator does not exist.\n throw new CommandError('EMULATOR_NOT_FOUND', results);\n }\n\n return sanitizeAdbDeviceName(results) ?? null;\n}\n\nexport async function isDeviceBootedAsync({\n name,\n}: { name?: string } = {}): Promise<Device | null> {\n const devices = await getAttachedDevicesAsync();\n\n if (!name) {\n return devices[0] ?? null;\n }\n\n return devices.find((device) => device.name === name) ?? null;\n}\n\n/**\n * Returns true when a device's splash screen animation has stopped.\n * This can be used to detect when a device is fully booted and ready to use.\n *\n * @param pid\n */\nexport async function isBootAnimationCompleteAsync(pid?: string): Promise<boolean> {\n try {\n const props = await getPropertyDataForDeviceAsync({ pid }, PROP_BOOT_ANIMATION_STATE);\n return !!props[PROP_BOOT_ANIMATION_STATE].match(/stopped/);\n } catch {\n return false;\n }\n}\n\n/** Get a list of ABIs for the provided device. */\nexport async function getDeviceABIsAsync(\n device: Pick<Device, 'name' | 'pid'>\n): Promise<DeviceABI[]> {\n const cpuAbiList = (await getPropertyDataForDeviceAsync(device, PROP_CPU_ABI_LIST_NAME))[\n PROP_CPU_ABI_LIST_NAME\n ];\n\n if (cpuAbiList) {\n return cpuAbiList.trim().split(',') as DeviceABI[];\n }\n\n const abi = (await getPropertyDataForDeviceAsync(device, PROP_CPU_NAME))[\n PROP_CPU_NAME\n ] as DeviceABI;\n return [abi];\n}\n\nexport async function getPropertyDataForDeviceAsync(\n device: DeviceContext,\n prop?: string\n): Promise<DeviceProperties> {\n // @ts-ignore\n const propCommand = adbArgs(...[device.pid, 'shell', 'getprop', prop].filter(Boolean));\n try {\n // Prevent reading as UTF8.\n const results = await getServer().getFileOutputAsync(propCommand);\n // Like:\n // [wifi.direct.interface]: [p2p-dev-wlan0]\n // [wifi.interface]: [wlan0]\n\n if (prop) {\n debug(`Property data: (device pid: ${device.pid}, prop: ${prop}, data: ${results})`);\n return {\n [prop]: results,\n };\n }\n const props = parseAdbDeviceProperties(results);\n\n debug(`Parsed data:`, props);\n\n return props;\n } catch (error: any) {\n // TODO: Ensure error has message and not stderr\n throw new CommandError(`Failed to get properties for device (${device.pid}): ${error.message}`);\n }\n}\n\nfunction parseAdbDeviceProperties(devicePropertiesString: string) {\n const properties: DeviceProperties = {};\n const propertyExp = /\\[(.*?)\\]: \\[(.*?)\\]/gm;\n for (const match of devicePropertiesString.matchAll(propertyExp)) {\n properties[match[1]] = match[2];\n }\n return properties;\n}\n\n/**\n * Sanitize the ADB device name to only get the actual device name.\n * On Windows, we need to do \\r, \\n, and \\r\\n filtering to get the name.\n */\nexport function sanitizeAdbDeviceName(deviceName: string) {\n return deviceName\n .trim()\n .split(/[\\r\\n]+/)\n .shift();\n}\n"],"names":["DeviceABI","adbArgs","getAdbNameForDeviceIdAsync","getAttachedDevicesAsync","getDeviceABIsAsync","getPackageInfoAsync","getPropertyDataForDeviceAsync","getServer","installAsync","isBootAnimationCompleteAsync","isDeviceBootedAsync","isPackageInstalledAsync","launchActivityAsync","logUnauthorized","openAppIdAsync","openUrlAsync","sanitizeAdbDeviceName","uninstallAsync","debug","require","CANT_START_ACTIVITY_ERROR","PROP_CPU_NAME","PROP_CPU_ABI_LIST_NAME","PROP_BOOT_ANIMATION_STATE","_server","ADBServer","device","Log","warn","chalk","bold","name","dim","learnMore","androidPackage","packages","runAsync","pid","env","EXPO_ADB_USER","lines","split","i","length","line","trim","launchActivity","url","args","push","openAsync","applicationId","replace","String","raw","results","includes","match","CommandError","substring","indexOf","appId","filePath","options","concat","output","splitItems","os","EOL","filter","attachedDevices","slice","map","props","Boolean","type","connectionType","isBooted","isAuthorized","devicePromises","deviceInfo","modelItem","find","info","Promise","all","devices","cpuAbiList","abi","prop","propCommand","getFileOutputAsync","parseAdbDeviceProperties","error","message","devicePropertiesString","properties","propertyExp","matchAll","deviceName","shift"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../../../src/start/platforms/android/adb.ts"],"sourcesContent":["import chalk from 'chalk';\nimport os from 'os';\n\nimport { ADBServer } from './ADBServer';\nimport * as Log from '../../../log';\nimport { env } from '../../../utils/env';\nimport { CommandError } from '../../../utils/errors';\nimport { learnMore } from '../../../utils/link';\n\nconst debug = require('debug')('expo:start:platforms:android:adb') as typeof console.log;\n\nexport enum DeviceABI {\n // The arch specific android target platforms are soft-deprecated.\n // Instead of using TargetPlatform as a combination arch + platform\n // the code will be updated to carry arch information in [DarwinArch]\n // and [AndroidArch].\n arm = 'arm',\n arm64 = 'arm64',\n x64 = 'x64',\n x86 = 'x86',\n x8664 = 'x86_64',\n arm64v8a = 'arm64-v8a',\n armeabiV7a = 'armeabi-v7a',\n armeabi = 'armeabi',\n universal = 'universal',\n}\n\n/** Represents a connected Android device. */\nexport type Device = {\n /** Process ID. */\n pid?: string;\n /** Name of the device, also used as the ID for opening devices. */\n name: string;\n /** Is emulator or connected device. */\n type: 'emulator' | 'device';\n /** Is the device booted (emulator). */\n isBooted: boolean;\n /** Is device authorized for developing. https://expo.fyi/authorize-android-device */\n isAuthorized: boolean;\n /** The connection type to ADB, only available when `type: device` */\n connectionType?: 'USB' | 'Network';\n};\n\ntype DeviceContext = Pick<Device, 'pid'>;\n\ntype DeviceProperties = Record<string, string>;\n\nconst CANT_START_ACTIVITY_ERROR = 'Activity not started, unable to resolve Intent';\n// http://developer.android.com/ndk/guides/abis.html\nconst PROP_CPU_NAME = 'ro.product.cpu.abi';\n\nconst PROP_CPU_ABI_LIST_NAME = 'ro.product.cpu.abilist';\n\n// Can sometimes be null\n// http://developer.android.com/ndk/guides/abis.html\nconst PROP_BOOT_ANIMATION_STATE = 'init.svc.bootanim';\n\nlet _server: ADBServer | null;\n\n/** Return the lazily loaded ADB server instance. */\nexport function getServer() {\n _server ??= new ADBServer();\n return _server;\n}\n\n/** Logs an FYI message about authorizing your device. */\nexport function logUnauthorized(device: Device) {\n Log.warn(\n `\\nThis computer is not authorized for developing on ${chalk.bold(device.name)}. ${chalk.dim(\n learnMore('https://expo.fyi/authorize-android-device')\n )}`\n );\n}\n\n/** Returns true if the provided package name is installed on the provided Android device. */\nexport async function isPackageInstalledAsync(\n device: DeviceContext,\n androidPackage: string\n): Promise<boolean> {\n const packages = await getServer().runAsync(\n adbArgs(\n device.pid,\n 'shell',\n 'pm',\n 'list',\n 'packages',\n '--user',\n env.EXPO_ADB_USER,\n androidPackage\n )\n );\n\n const lines = packages.split(/\\r?\\n/);\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i].trim();\n if (line === `package:${androidPackage}`) {\n return true;\n }\n }\n return false;\n}\n\n/**\n * @param device.pid Process ID of the Android device to launch.\n * @param props.launchActivity Activity to launch `[application identifier]/.[main activity name]`, ex: `com.bacon.app/.MainActivity`\n * @param props.url Optional (dev client) URL to launch\n */\nexport async function launchActivityAsync(\n device: DeviceContext,\n {\n launchActivity,\n url,\n }: {\n launchActivity: string;\n url?: string;\n }\n) {\n const args: string[] = [\n 'shell',\n 'am',\n 'start',\n // FLAG_ACTIVITY_SINGLE_TOP -- If set, the activity will not be launched if it is already running at the top of the history stack.\n '-f',\n '0x20000000',\n // Activity to open first: com.bacon.app/.MainActivity\n '-n',\n launchActivity,\n ];\n\n if (url) {\n args.push('-d', url);\n }\n\n return openAsync(adbArgs(device.pid, ...args));\n}\n\n/**\n * @param device.pid Process ID of the Android device to launch.\n * @param props.applicationId package name to launch.\n */\nexport async function openAppIdAsync(\n device: DeviceContext,\n {\n applicationId,\n }: {\n applicationId: string;\n }\n) {\n return openAsync(\n adbArgs(\n device.pid,\n 'shell',\n 'monkey',\n '--pct-syskeys',\n '0',\n '-p',\n applicationId,\n '-c',\n 'android.intent.category.LAUNCHER',\n '1'\n )\n );\n}\n\n/**\n * @param device.pid Process ID of the Android device to launch.\n * @param props.url URL to launch.\n */\nexport async function openUrlAsync(\n device: DeviceContext,\n {\n url,\n }: {\n url: string;\n }\n) {\n return openAsync(\n adbArgs(\n device.pid,\n 'shell',\n 'am',\n 'start',\n '-a',\n 'android.intent.action.VIEW',\n '-d',\n // ADB requires ampersands to be escaped.\n url.replace(/&/g, String.raw`\\&`)\n )\n );\n}\n\n/** Runs a generic command watches for common errors in order to throw with an expected code. */\nasync function openAsync(args: string[]): Promise<string> {\n const results = await getServer().runAsync(args);\n if (\n results.includes(CANT_START_ACTIVITY_ERROR) ||\n results.match(/Error: Activity class .* does not exist\\./g)\n ) {\n throw new CommandError('APP_NOT_INSTALLED', results.substring(results.indexOf('Error: ')));\n }\n return results;\n}\n\n/** Uninstall an app given its Android package name. */\nexport async function uninstallAsync(\n device: DeviceContext,\n { appId }: { appId: string }\n): Promise<string> {\n return await getServer().runAsync(\n adbArgs(device.pid, 'uninstall', '--user', env.EXPO_ADB_USER, appId)\n );\n}\n\n/** Get package info from an app based on its Android package name. */\nexport async function getPackageInfoAsync(\n device: DeviceContext,\n { appId }: { appId: string }\n): Promise<string> {\n return await getServer().runAsync(adbArgs(device.pid, 'shell', 'dumpsys', 'package', appId));\n}\n\n/** Install an app on a connected device. */\nexport async function installAsync(device: DeviceContext, { filePath }: { filePath: string }) {\n // TODO: Handle the `INSTALL_FAILED_INSUFFICIENT_STORAGE` error.\n return await getServer().runAsync(\n adbArgs(device.pid, 'install', '-r', '-d', '--user', env.EXPO_ADB_USER, filePath)\n );\n}\n\n/** Format ADB args with process ID. */\nexport function adbArgs(pid: Device['pid'], ...options: string[]): string[] {\n const args = [];\n if (pid) {\n args.push('-s', pid);\n }\n\n return args.concat(options);\n}\n\n// TODO: This is very expensive for some operations.\nexport async function getAttachedDevicesAsync(): Promise<Device[]> {\n const output = await getServer().runAsync(['devices', '-l']);\n\n const splitItems = output\n .trim()\n .replace(/\\n$/, '')\n .split(os.EOL)\n // Filter ADB trace logs from the output, e.g.\n // adb D 03-06 15:25:53 63677 4018815 adb_client.cpp:393] adb_query: host:devices-l\n // 03-04 12:29:44.557 16415 16415 D adb : commandline.cpp:1646 Using server socket: tcp:172.27.192.1:5037\n // 03-04 12:29:44.557 16415 16415 D adb : adb_client.cpp:160 _adb_connect: host:version\n .filter((line) => !line.match(/\\.cpp:[0-9]+/));\n\n // First line is `\"List of devices attached\"`, remove it\n // @ts-ignore: todo\n const attachedDevices: {\n props: string[];\n type: Device['type'];\n isAuthorized: Device['isAuthorized'];\n isBooted: Device['isBooted'];\n connectionType?: Device['connectionType'];\n }[] = splitItems\n .slice(1, splitItems.length)\n .map((line) => {\n // unauthorized: ['FA8251A00719', 'unauthorized', 'usb:338690048X', 'transport_id:5']\n // authorized: ['FA8251A00719', 'device', 'usb:336592896X', 'product:walleye', 'model:Pixel_2', 'device:walleye', 'transport_id:4']\n // emulator: ['emulator-5554', 'offline', 'transport_id:1']\n const props = line.split(' ').filter(Boolean);\n const type = line.includes('emulator') ? 'emulator' : 'device';\n\n let connectionType;\n if (type === 'device' && line.includes('usb:')) {\n connectionType = 'USB';\n } else if (type === 'device' && line.includes('_adb-tls-connect.')) {\n connectionType = 'Network';\n }\n\n const isBooted = type === 'emulator' || props[1] !== 'offline';\n const isAuthorized =\n connectionType === 'Network'\n ? line.includes('model:') // Network connected devices show `model:<name>` when authorized\n : props[1] !== 'unauthorized';\n\n return { props, type, isAuthorized, isBooted, connectionType };\n })\n .filter(({ props: [pid] }) => !!pid);\n\n const devicePromises = attachedDevices.map<Promise<Device>>(async (props) => {\n const {\n type,\n props: [pid, ...deviceInfo],\n isAuthorized,\n isBooted,\n } = props;\n\n let name: string | null = null;\n\n if (type === 'device') {\n if (isAuthorized) {\n // Possibly formatted like `model:Pixel_2`\n // Transform to `Pixel_2`\n const modelItem = deviceInfo.find((info) => info.includes('model:'));\n if (modelItem) {\n name = modelItem.replace('model:', '');\n }\n }\n // unauthorized devices don't have a name available to read\n if (!name) {\n // Device FA8251A00719\n name = `Device ${pid}`;\n }\n } else {\n // Given an emulator pid, get the emulator name which can be used to start the emulator later.\n name = (await getAdbNameForDeviceIdAsync({ pid })) ?? '';\n }\n\n return props.connectionType\n ? { pid, name, type, isAuthorized, isBooted, connectionType: props.connectionType }\n : { pid, name, type, isAuthorized, isBooted };\n });\n\n return Promise.all(devicePromises);\n}\n\n/**\n * Return the Emulator name for an emulator ID, this can be used to determine if an emulator is booted.\n *\n * @param device.pid a value like `emulator-5554` from `abd devices`\n */\nexport async function getAdbNameForDeviceIdAsync(device: DeviceContext): Promise<string | null> {\n const results = await getServer().runAsync(adbArgs(device.pid, 'emu', 'avd', 'name'));\n\n if (results.match(/could not connect to TCP port .*: Connection refused/)) {\n // Can also occur when the emulator does not exist.\n throw new CommandError('EMULATOR_NOT_FOUND', results);\n }\n\n return sanitizeAdbDeviceName(results) ?? null;\n}\n\nexport async function isDeviceBootedAsync({\n name,\n}: { name?: string } = {}): Promise<Device | null> {\n const devices = await getAttachedDevicesAsync();\n\n if (!name) {\n return devices[0] ?? null;\n }\n\n return devices.find((device) => device.name === name) ?? null;\n}\n\n/**\n * Returns true when a device's splash screen animation has stopped.\n * This can be used to detect when a device is fully booted and ready to use.\n *\n * @param pid\n */\nexport async function isBootAnimationCompleteAsync(pid?: string): Promise<boolean> {\n try {\n const props = await getPropertyDataForDeviceAsync({ pid }, PROP_BOOT_ANIMATION_STATE);\n return !!props[PROP_BOOT_ANIMATION_STATE].match(/stopped/);\n } catch {\n return false;\n }\n}\n\n/** Get a list of ABIs for the provided device. */\nexport async function getDeviceABIsAsync(\n device: Pick<Device, 'name' | 'pid'>\n): Promise<DeviceABI[]> {\n const cpuAbiList = (await getPropertyDataForDeviceAsync(device, PROP_CPU_ABI_LIST_NAME))[\n PROP_CPU_ABI_LIST_NAME\n ];\n\n if (cpuAbiList) {\n return cpuAbiList.trim().split(',') as DeviceABI[];\n }\n\n const abi = (await getPropertyDataForDeviceAsync(device, PROP_CPU_NAME))[\n PROP_CPU_NAME\n ] as DeviceABI;\n return [abi];\n}\n\nexport async function getPropertyDataForDeviceAsync(\n device: DeviceContext,\n prop?: string\n): Promise<DeviceProperties> {\n // @ts-ignore\n const propCommand = adbArgs(...[device.pid, 'shell', 'getprop', prop].filter(Boolean));\n try {\n // Prevent reading as UTF8.\n const results = await getServer().getFileOutputAsync(propCommand);\n // Like:\n // [wifi.direct.interface]: [p2p-dev-wlan0]\n // [wifi.interface]: [wlan0]\n\n if (prop) {\n debug(`Property data: (device pid: ${device.pid}, prop: ${prop}, data: ${results})`);\n return {\n [prop]: results,\n };\n }\n const props = parseAdbDeviceProperties(results);\n\n debug(`Parsed data:`, props);\n\n return props;\n } catch (error: any) {\n // TODO: Ensure error has message and not stderr\n throw new CommandError(`Failed to get properties for device (${device.pid}): ${error.message}`);\n }\n}\n\nfunction parseAdbDeviceProperties(devicePropertiesString: string) {\n const properties: DeviceProperties = {};\n const propertyExp = /\\[(.*?)\\]: \\[(.*?)\\]/gm;\n for (const match of devicePropertiesString.matchAll(propertyExp)) {\n properties[match[1]] = match[2];\n }\n return properties;\n}\n\n/**\n * Sanitize the ADB device name to only get the actual device name.\n * On Windows, we need to do \\r, \\n, and \\r\\n filtering to get the name.\n */\nexport function sanitizeAdbDeviceName(deviceName: string) {\n return deviceName\n .trim()\n .split(/[\\r\\n]+/)\n .shift();\n}\n"],"names":["DeviceABI","adbArgs","getAdbNameForDeviceIdAsync","getAttachedDevicesAsync","getDeviceABIsAsync","getPackageInfoAsync","getPropertyDataForDeviceAsync","getServer","installAsync","isBootAnimationCompleteAsync","isDeviceBootedAsync","isPackageInstalledAsync","launchActivityAsync","logUnauthorized","openAppIdAsync","openUrlAsync","sanitizeAdbDeviceName","uninstallAsync","debug","require","CANT_START_ACTIVITY_ERROR","PROP_CPU_NAME","PROP_CPU_ABI_LIST_NAME","PROP_BOOT_ANIMATION_STATE","_server","ADBServer","device","Log","warn","chalk","bold","name","dim","learnMore","androidPackage","packages","runAsync","pid","env","EXPO_ADB_USER","lines","split","i","length","line","trim","launchActivity","url","args","push","openAsync","applicationId","replace","String","raw","results","includes","match","CommandError","substring","indexOf","appId","filePath","options","concat","output","splitItems","os","EOL","filter","attachedDevices","slice","map","props","Boolean","type","connectionType","isBooted","isAuthorized","devicePromises","deviceInfo","modelItem","find","info","Promise","all","devices","cpuAbiList","abi","prop","propCommand","getFileOutputAsync","parseAdbDeviceProperties","error","message","devicePropertiesString","properties","propertyExp","matchAll","deviceName","shift"],"mappings":"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"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
Object.defineProperty(exports, "DevToolsPlugin", {
|
|
6
|
+
enumerable: true,
|
|
7
|
+
get: function() {
|
|
8
|
+
return DevToolsPlugin;
|
|
9
|
+
}
|
|
10
|
+
});
|
|
11
|
+
const _DevToolsPluginschema = require("./DevToolsPlugin.schema");
|
|
12
|
+
const _DevToolsPluginCliExtensionExecutor = require("./DevToolsPluginCliExtensionExecutor");
|
|
13
|
+
const _DevToolsPluginManager = require("./DevToolsPluginManager");
|
|
14
|
+
class DevToolsPlugin {
|
|
15
|
+
constructor(plugin, projectRoot){
|
|
16
|
+
this.plugin = plugin;
|
|
17
|
+
this.projectRoot = projectRoot;
|
|
18
|
+
this._executor = undefined;
|
|
19
|
+
// Validate configuration schema
|
|
20
|
+
const result = _DevToolsPluginschema.PluginSchema.safeParse(plugin);
|
|
21
|
+
if (!result.success) {
|
|
22
|
+
throw new Error(`Invalid plugin configuration: ${result.error.message}`, {
|
|
23
|
+
cause: result.error
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
get packageName() {
|
|
28
|
+
return this.plugin.packageName;
|
|
29
|
+
}
|
|
30
|
+
get packageRoot() {
|
|
31
|
+
return this.plugin.packageRoot;
|
|
32
|
+
}
|
|
33
|
+
get webpageEndpoint() {
|
|
34
|
+
var _this_plugin, _this_plugin1;
|
|
35
|
+
return ((_this_plugin = this.plugin) == null ? void 0 : _this_plugin.webpageRoot) ? `${_DevToolsPluginManager.DevToolsPluginEndpoint}/${(_this_plugin1 = this.plugin) == null ? void 0 : _this_plugin1.packageName}` : undefined;
|
|
36
|
+
}
|
|
37
|
+
get webpageRoot() {
|
|
38
|
+
var _this_plugin;
|
|
39
|
+
return (_this_plugin = this.plugin) == null ? void 0 : _this_plugin.webpageRoot;
|
|
40
|
+
}
|
|
41
|
+
get description() {
|
|
42
|
+
var _this_plugin_cliExtensions;
|
|
43
|
+
return ((_this_plugin_cliExtensions = this.plugin.cliExtensions) == null ? void 0 : _this_plugin_cliExtensions.description) ?? '';
|
|
44
|
+
}
|
|
45
|
+
get cliExtensions() {
|
|
46
|
+
return this.plugin.cliExtensions;
|
|
47
|
+
}
|
|
48
|
+
get executor() {
|
|
49
|
+
var _this_plugin_cliExtensions;
|
|
50
|
+
if (!((_this_plugin_cliExtensions = this.plugin.cliExtensions) == null ? void 0 : _this_plugin_cliExtensions.entryPoint)) {
|
|
51
|
+
return undefined;
|
|
52
|
+
}
|
|
53
|
+
if (!this._executor) {
|
|
54
|
+
this._executor = new _DevToolsPluginCliExtensionExecutor.DevToolsPluginCliExtensionExecutor(this.plugin, this.projectRoot);
|
|
55
|
+
}
|
|
56
|
+
return this._executor;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
//# sourceMappingURL=DevToolsPlugin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../src/start/server/DevToolsPlugin.ts"],"sourcesContent":["import { DevToolsPluginInfo, PluginSchema } from './DevToolsPlugin.schema';\nimport { DevToolsPluginCliExtensionExecutor } from './DevToolsPluginCliExtensionExecutor';\nimport { DevToolsPluginEndpoint } from './DevToolsPluginManager';\nimport { Log } from '../../log';\n\n/**\n * Class that represents a DevTools plugin with CLI and/or web extensions\n *\n * Responsibilities:\n * - Validates plugin configuration against schema\n * - Provides access to plugin metadata (name, description\n * , endpoints)\n * - Manages CLI command execution via DevToolsPluginExecutor\n * - Lazily initializes executor when needed\n * - Constructs web endpoint URLs based on server configuration\n */\nexport class DevToolsPlugin {\n constructor(\n private plugin: DevToolsPluginInfo,\n public readonly projectRoot: string\n ) {\n // Validate configuration schema\n const result = PluginSchema.safeParse(plugin);\n if (!result.success) {\n throw new Error(`Invalid plugin configuration: ${result.error.message}`, {\n cause: result.error,\n });\n }\n }\n\n private _executor: DevToolsPluginCliExtensionExecutor | undefined = undefined;\n\n get packageName(): string {\n return this.plugin.packageName;\n }\n\n get packageRoot(): string {\n return this.plugin.packageRoot;\n }\n\n get webpageEndpoint(): string | undefined {\n return this.plugin?.webpageRoot\n ? `${DevToolsPluginEndpoint}/${this.plugin?.packageName}`\n : undefined;\n }\n\n get webpageRoot(): string | undefined {\n return this.plugin?.webpageRoot;\n }\n\n get description(): string {\n return this.plugin.cliExtensions?.description ?? '';\n }\n\n get cliExtensions(): DevToolsPluginInfo['cliExtensions'] {\n return this.plugin.cliExtensions;\n }\n\n get executor(): DevToolsPluginCliExtensionExecutor | undefined {\n if (!this.plugin.cliExtensions?.entryPoint) {\n return undefined;\n }\n\n if (!this._executor) {\n this._executor = new DevToolsPluginCliExtensionExecutor(this.plugin, this.projectRoot);\n }\n\n return this._executor;\n }\n}\n"],"names":["DevToolsPlugin","constructor","plugin","projectRoot","_executor","undefined","result","PluginSchema","safeParse","success","Error","error","message","cause","packageName","packageRoot","webpageEndpoint","webpageRoot","DevToolsPluginEndpoint","description","cliExtensions","executor","entryPoint","DevToolsPluginCliExtensionExecutor"],"mappings":";;;;+BAgBaA;;;eAAAA;;;sCAhBoC;oDACE;uCACZ;AAchC,MAAMA;IACXC,YACE,AAAQC,MAA0B,EAClC,AAAgBC,WAAmB,CACnC;aAFQD,SAAAA;aACQC,cAAAA;aAWVC,YAA4DC;QATlE,gCAAgC;QAChC,MAAMC,SAASC,kCAAY,CAACC,SAAS,CAACN;QACtC,IAAI,CAACI,OAAOG,OAAO,EAAE;YACnB,MAAM,IAAIC,MAAM,CAAC,8BAA8B,EAAEJ,OAAOK,KAAK,CAACC,OAAO,EAAE,EAAE;gBACvEC,OAAOP,OAAOK,KAAK;YACrB;QACF;IACF;IAIA,IAAIG,cAAsB;QACxB,OAAO,IAAI,CAACZ,MAAM,CAACY,WAAW;IAChC;IAEA,IAAIC,cAAsB;QACxB,OAAO,IAAI,CAACb,MAAM,CAACa,WAAW;IAChC;IAEA,IAAIC,kBAAsC;YACjC,cAC0B;QADjC,OAAO,EAAA,eAAA,IAAI,CAACd,MAAM,qBAAX,aAAae,WAAW,IAC3B,GAAGC,6CAAsB,CAAC,CAAC,GAAE,gBAAA,IAAI,CAAChB,MAAM,qBAAX,cAAaY,WAAW,EAAE,GACvDT;IACN;IAEA,IAAIY,cAAkC;YAC7B;QAAP,QAAO,eAAA,IAAI,CAACf,MAAM,qBAAX,aAAae,WAAW;IACjC;IAEA,IAAIE,cAAsB;YACjB;QAAP,OAAO,EAAA,6BAAA,IAAI,CAACjB,MAAM,CAACkB,aAAa,qBAAzB,2BAA2BD,WAAW,KAAI;IACnD;IAEA,IAAIC,gBAAqD;QACvD,OAAO,IAAI,CAAClB,MAAM,CAACkB,aAAa;IAClC;IAEA,IAAIC,WAA2D;YACxD;QAAL,IAAI,GAAC,6BAAA,IAAI,CAACnB,MAAM,CAACkB,aAAa,qBAAzB,2BAA2BE,UAAU,GAAE;YAC1C,OAAOjB;QACT;QAEA,IAAI,CAAC,IAAI,CAACD,SAAS,EAAE;YACnB,IAAI,CAACA,SAAS,GAAG,IAAImB,sEAAkC,CAAC,IAAI,CAACrB,MAAM,EAAE,IAAI,CAACC,WAAW;QACvF;QAEA,OAAO,IAAI,CAACC,SAAS;IACvB;AACF"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
function _export(target, all) {
|
|
6
|
+
for(var name in all)Object.defineProperty(target, name, {
|
|
7
|
+
enumerable: true,
|
|
8
|
+
get: all[name]
|
|
9
|
+
});
|
|
10
|
+
}
|
|
11
|
+
_export(exports, {
|
|
12
|
+
DevToolsPluginOutputSchema: function() {
|
|
13
|
+
return DevToolsPluginOutputSchema;
|
|
14
|
+
},
|
|
15
|
+
PluginSchema: function() {
|
|
16
|
+
return PluginSchema;
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
function _zod() {
|
|
20
|
+
const data = require("zod");
|
|
21
|
+
_zod = function() {
|
|
22
|
+
return data;
|
|
23
|
+
};
|
|
24
|
+
return data;
|
|
25
|
+
}
|
|
26
|
+
const CommandParameterSchema = _zod().z.object({
|
|
27
|
+
name: _zod().z.string().min(1),
|
|
28
|
+
type: _zod().z.enum([
|
|
29
|
+
'text',
|
|
30
|
+
'number',
|
|
31
|
+
'confirm'
|
|
32
|
+
]),
|
|
33
|
+
description: _zod().z.string().optional()
|
|
34
|
+
});
|
|
35
|
+
const CommandSchema = _zod().z.object({
|
|
36
|
+
name: _zod().z.string().min(1),
|
|
37
|
+
title: _zod().z.string().min(1),
|
|
38
|
+
environments: _zod().z.array(_zod().z.enum([
|
|
39
|
+
'cli',
|
|
40
|
+
'mcp'
|
|
41
|
+
])).readonly(),
|
|
42
|
+
parameters: _zod().z.array(CommandParameterSchema).optional()
|
|
43
|
+
});
|
|
44
|
+
const CliExtensionsSchema = _zod().z.object({
|
|
45
|
+
description: _zod().z.string(),
|
|
46
|
+
commands: _zod().z.array(CommandSchema).min(1),
|
|
47
|
+
entryPoint: _zod().z.string().min(1)
|
|
48
|
+
});
|
|
49
|
+
const PluginSchema = _zod().z.object({
|
|
50
|
+
packageName: _zod().z.string().min(1),
|
|
51
|
+
packageRoot: _zod().z.string().min(1),
|
|
52
|
+
webpageRoot: _zod().z.string().optional(),
|
|
53
|
+
cliExtensions: CliExtensionsSchema.optional()
|
|
54
|
+
});
|
|
55
|
+
const DevToolsPluginOutputLinesSchema = _zod().z.union([
|
|
56
|
+
_zod().z.object({
|
|
57
|
+
type: _zod().z.literal('text'),
|
|
58
|
+
text: _zod().z.string(),
|
|
59
|
+
url: _zod().z.string().optional(),
|
|
60
|
+
level: _zod().z.enum([
|
|
61
|
+
'info',
|
|
62
|
+
'warning',
|
|
63
|
+
'error'
|
|
64
|
+
])
|
|
65
|
+
}),
|
|
66
|
+
_zod().z.object({
|
|
67
|
+
type: _zod().z.literal('audio'),
|
|
68
|
+
url: _zod().z.string().url(),
|
|
69
|
+
text: _zod().z.string().optional()
|
|
70
|
+
}),
|
|
71
|
+
_zod().z.object({
|
|
72
|
+
type: _zod().z.literal('image'),
|
|
73
|
+
url: _zod().z.string().url(),
|
|
74
|
+
text: _zod().z.string().optional()
|
|
75
|
+
})
|
|
76
|
+
]);
|
|
77
|
+
const DevToolsPluginOutputSchema = _zod().z.array(DevToolsPluginOutputLinesSchema);
|
|
78
|
+
|
|
79
|
+
//# sourceMappingURL=DevToolsPlugin.schema.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../src/start/server/DevToolsPlugin.schema.ts"],"sourcesContent":["import { z } from 'zod';\n\nconst CommandParameterSchema = z.object({\n name: z.string().min(1),\n type: z.enum(['text', 'number', 'confirm']),\n description: z.string().optional(),\n});\n\nexport type DevToolsPluginCommandParameter = z.infer<typeof CommandParameterSchema>;\n\nconst CommandSchema = z.object({\n name: z.string().min(1),\n title: z.string().min(1),\n environments: z.array(z.enum(['cli', 'mcp'])).readonly(),\n parameters: z.array(CommandParameterSchema).optional(),\n});\n\nexport type DevToolsPluginCommand = z.infer<typeof CommandSchema>;\n\nexport type DevToolsPluginExecutorArguments = {\n command: string;\n metroServerOrigin: string;\n args?: Record<string, string | number | boolean> | undefined;\n onOutput?: (output: DevToolsPluginOutput) => void;\n};\n\nconst CliExtensionsSchema = z.object({\n description: z.string(),\n commands: z.array(CommandSchema).min(1),\n entryPoint: z.string().min(1),\n});\n\nexport type DevToolsPluginCliExtensions = z.infer<typeof CliExtensionsSchema>;\n\nexport const PluginSchema = z.object({\n packageName: z.string().min(1),\n packageRoot: z.string().min(1),\n webpageRoot: z.string().optional(),\n cliExtensions: CliExtensionsSchema.optional(),\n});\n\nexport type DevToolsPluginInfo = z.infer<typeof PluginSchema>;\n\nconst DevToolsPluginOutputLinesSchema = z.union([\n z.object({\n type: z.literal('text'),\n text: z.string(),\n url: z.string().optional(),\n level: z.enum(['info', 'warning', 'error']),\n }),\n z.object({\n type: z.literal('audio'),\n url: z.string().url(),\n text: z.string().optional(),\n }),\n z.object({\n type: z.literal('image'),\n url: z.string().url(),\n text: z.string().optional(),\n }),\n]);\n\nexport const DevToolsPluginOutputSchema = z.array(DevToolsPluginOutputLinesSchema);\n\nexport type DevToolsPluginOutput = z.infer<typeof DevToolsPluginOutputSchema>;\n"],"names":["DevToolsPluginOutputSchema","PluginSchema","CommandParameterSchema","z","object","name","string","min","type","enum","description","optional","CommandSchema","title","environments","array","readonly","parameters","CliExtensionsSchema","commands","entryPoint","packageName","packageRoot","webpageRoot","cliExtensions","DevToolsPluginOutputLinesSchema","union","literal","text","url","level"],"mappings":";;;;;;;;;;;IA8DaA,0BAA0B;eAA1BA;;IA5BAC,YAAY;eAAZA;;;;yBAlCK;;;;;;AAElB,MAAMC,yBAAyBC,QAAC,CAACC,MAAM,CAAC;IACtCC,MAAMF,QAAC,CAACG,MAAM,GAAGC,GAAG,CAAC;IACrBC,MAAML,QAAC,CAACM,IAAI,CAAC;QAAC;QAAQ;QAAU;KAAU;IAC1CC,aAAaP,QAAC,CAACG,MAAM,GAAGK,QAAQ;AAClC;AAIA,MAAMC,gBAAgBT,QAAC,CAACC,MAAM,CAAC;IAC7BC,MAAMF,QAAC,CAACG,MAAM,GAAGC,GAAG,CAAC;IACrBM,OAAOV,QAAC,CAACG,MAAM,GAAGC,GAAG,CAAC;IACtBO,cAAcX,QAAC,CAACY,KAAK,CAACZ,QAAC,CAACM,IAAI,CAAC;QAAC;QAAO;KAAM,GAAGO,QAAQ;IACtDC,YAAYd,QAAC,CAACY,KAAK,CAACb,wBAAwBS,QAAQ;AACtD;AAWA,MAAMO,sBAAsBf,QAAC,CAACC,MAAM,CAAC;IACnCM,aAAaP,QAAC,CAACG,MAAM;IACrBa,UAAUhB,QAAC,CAACY,KAAK,CAACH,eAAeL,GAAG,CAAC;IACrCa,YAAYjB,QAAC,CAACG,MAAM,GAAGC,GAAG,CAAC;AAC7B;AAIO,MAAMN,eAAeE,QAAC,CAACC,MAAM,CAAC;IACnCiB,aAAalB,QAAC,CAACG,MAAM,GAAGC,GAAG,CAAC;IAC5Be,aAAanB,QAAC,CAACG,MAAM,GAAGC,GAAG,CAAC;IAC5BgB,aAAapB,QAAC,CAACG,MAAM,GAAGK,QAAQ;IAChCa,eAAeN,oBAAoBP,QAAQ;AAC7C;AAIA,MAAMc,kCAAkCtB,QAAC,CAACuB,KAAK,CAAC;IAC9CvB,QAAC,CAACC,MAAM,CAAC;QACPI,MAAML,QAAC,CAACwB,OAAO,CAAC;QAChBC,MAAMzB,QAAC,CAACG,MAAM;QACduB,KAAK1B,QAAC,CAACG,MAAM,GAAGK,QAAQ;QACxBmB,OAAO3B,QAAC,CAACM,IAAI,CAAC;YAAC;YAAQ;YAAW;SAAQ;IAC5C;IACAN,QAAC,CAACC,MAAM,CAAC;QACPI,MAAML,QAAC,CAACwB,OAAO,CAAC;QAChBE,KAAK1B,QAAC,CAACG,MAAM,GAAGuB,GAAG;QACnBD,MAAMzB,QAAC,CAACG,MAAM,GAAGK,QAAQ;IAC3B;IACAR,QAAC,CAACC,MAAM,CAAC;QACPI,MAAML,QAAC,CAACwB,OAAO,CAAC;QAChBE,KAAK1B,QAAC,CAACG,MAAM,GAAGuB,GAAG;QACnBD,MAAMzB,QAAC,CAACG,MAAM,GAAGK,QAAQ;IAC3B;CACD;AAEM,MAAMX,6BAA6BG,QAAC,CAACY,KAAK,CAACU"}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
Object.defineProperty(exports, "DevToolsPluginCliExtensionExecutor", {
|
|
6
|
+
enumerable: true,
|
|
7
|
+
get: function() {
|
|
8
|
+
return DevToolsPluginCliExtensionExecutor;
|
|
9
|
+
}
|
|
10
|
+
});
|
|
11
|
+
function _child_process() {
|
|
12
|
+
const data = require("child_process");
|
|
13
|
+
_child_process = function() {
|
|
14
|
+
return data;
|
|
15
|
+
};
|
|
16
|
+
return data;
|
|
17
|
+
}
|
|
18
|
+
function _path() {
|
|
19
|
+
const data = /*#__PURE__*/ _interop_require_default(require("path"));
|
|
20
|
+
_path = function() {
|
|
21
|
+
return data;
|
|
22
|
+
};
|
|
23
|
+
return data;
|
|
24
|
+
}
|
|
25
|
+
const _DevToolsPluginCliExtensionResults = require("./DevToolsPluginCliExtensionResults");
|
|
26
|
+
function _interop_require_default(obj) {
|
|
27
|
+
return obj && obj.__esModule ? obj : {
|
|
28
|
+
default: obj
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
const DEFAULT_TIMEOUT_MS = 10000; // 10 seconds
|
|
32
|
+
class DevToolsPluginCliExtensionExecutor {
|
|
33
|
+
constructor(plugin, projectRoot, spawnFunc = _child_process().spawn, timeoutMs = DEFAULT_TIMEOUT_MS // Timeout for command execution
|
|
34
|
+
){
|
|
35
|
+
var _this_plugin_cliExtensions;
|
|
36
|
+
this.plugin = plugin;
|
|
37
|
+
this.projectRoot = projectRoot;
|
|
38
|
+
this.spawnFunc = spawnFunc;
|
|
39
|
+
this.timeoutMs = timeoutMs;
|
|
40
|
+
this.getCommandString = ({ command, args })=>{
|
|
41
|
+
return `node ${this.plugin.cliExtensions.entryPoint} ${command}${Object.keys(args ?? {}).length > 0 ? ' ' + JSON.stringify(args) : ''}`;
|
|
42
|
+
};
|
|
43
|
+
this.execute = async ({ command, args, metroServerOrigin, onOutput })=>{
|
|
44
|
+
this.validate({
|
|
45
|
+
command,
|
|
46
|
+
args
|
|
47
|
+
});
|
|
48
|
+
return new Promise(async (resolve)=>{
|
|
49
|
+
// Set up the command and its arguments
|
|
50
|
+
const tool = _path().default.join(this.plugin.packageRoot, this.plugin.cliExtensions.entryPoint);
|
|
51
|
+
const child = this.spawnFunc('node', [
|
|
52
|
+
tool,
|
|
53
|
+
command,
|
|
54
|
+
`'${JSON.stringify(args)}'`,
|
|
55
|
+
`'${metroServerOrigin}'`
|
|
56
|
+
], {
|
|
57
|
+
cwd: this.projectRoot,
|
|
58
|
+
env: {
|
|
59
|
+
...process.env
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
let finished = false;
|
|
63
|
+
const pluginResults = new _DevToolsPluginCliExtensionResults.DevToolsPluginCliExtensionResults(onOutput);
|
|
64
|
+
// Collect output/error data
|
|
65
|
+
child.stdout.on('data', (data)=>pluginResults.append(data.toString()));
|
|
66
|
+
child.stderr.on('data', (data)=>pluginResults.append(data.toString(), 'error'));
|
|
67
|
+
// Setup timeout
|
|
68
|
+
const timeout = setTimeout(()=>{
|
|
69
|
+
if (!finished) {
|
|
70
|
+
finished = true;
|
|
71
|
+
child.kill('SIGKILL');
|
|
72
|
+
pluginResults.append('Command timed out', 'error');
|
|
73
|
+
resolve(pluginResults.getOutput());
|
|
74
|
+
}
|
|
75
|
+
}, this.timeoutMs);
|
|
76
|
+
child.on('close', (code)=>{
|
|
77
|
+
if (finished) return;
|
|
78
|
+
clearTimeout(timeout);
|
|
79
|
+
finished = true;
|
|
80
|
+
pluginResults.exit(code);
|
|
81
|
+
resolve(pluginResults.getOutput());
|
|
82
|
+
});
|
|
83
|
+
child.on('error', (err)=>{
|
|
84
|
+
if (finished) return;
|
|
85
|
+
clearTimeout(timeout);
|
|
86
|
+
finished = true;
|
|
87
|
+
pluginResults.append(err.toString(), 'error');
|
|
88
|
+
resolve(pluginResults.getOutput());
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
};
|
|
92
|
+
// Validate that this is a plugin with cli extensions
|
|
93
|
+
if (!((_this_plugin_cliExtensions = this.plugin.cliExtensions) == null ? void 0 : _this_plugin_cliExtensions.entryPoint)) {
|
|
94
|
+
throw new Error(`Plugin ${this.plugin.packageName} has no CLI extensions`);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
validate({ command, args }) {
|
|
98
|
+
var _this_plugin_cliExtensions, _commandElement_parameters;
|
|
99
|
+
const commandElement = (_this_plugin_cliExtensions = this.plugin.cliExtensions) == null ? void 0 : _this_plugin_cliExtensions.commands.find((c)=>c.name === command);
|
|
100
|
+
if (!commandElement) {
|
|
101
|
+
throw new Error(`Command "${command}" not found in plugin ${this.plugin.packageName}`);
|
|
102
|
+
}
|
|
103
|
+
const paramLength = ((_commandElement_parameters = commandElement.parameters) == null ? void 0 : _commandElement_parameters.length) ?? 0;
|
|
104
|
+
const argsLength = Object.keys(args ?? {}).length;
|
|
105
|
+
if (paramLength !== argsLength) {
|
|
106
|
+
// Quick check to see if the lengths match
|
|
107
|
+
throw new Error(`Expected ${paramLength} parameter(s), but got ${argsLength} argument(s) for the command "${command}".`);
|
|
108
|
+
}
|
|
109
|
+
const argsKeys = Object.keys(args ?? {});
|
|
110
|
+
for (const param of commandElement.parameters ?? []){
|
|
111
|
+
const found = argsKeys.find((key)=>key === param.name);
|
|
112
|
+
if (!found) {
|
|
113
|
+
throw new Error(`Parameter "${param.name}" not found in command "${command}" of plugin ${this.plugin.packageName}`);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
//# sourceMappingURL=DevToolsPluginCliExtensionExecutor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../src/start/server/DevToolsPluginCliExtensionExecutor.ts"],"sourcesContent":["import { spawn } from 'child_process';\nimport path from 'path';\n\nimport {\n DevToolsPluginExecutorArguments,\n DevToolsPluginInfo,\n DevToolsPluginOutput,\n} from './DevToolsPlugin.schema';\nimport { DevToolsPluginCliExtensionResults } from './DevToolsPluginCliExtensionResults';\n\nconst DEFAULT_TIMEOUT_MS = 10_000; // 10 seconds\n\n/**\n * Class that executes CLI Extension commands for a given plugin\n *\n * ## Responsibilities:\n * - Verifies that requested commands exist and have correct parameters\n * - Validates that provided arguments match expected parameter schema\n * - Spawns and manages child processes for command execution\n * - Captures and streams stdout/stderr data from executed commands\n * - Manages process errors, timeouts, and unexpected failures\n * - Enforces execution time limits to prevent hanging processes\n * - Configures proper execution environment with color support\n * - Ensures proper cleanup of processes and timeouts\n * - Provides structured output with exit codes and error states\n */\nexport class DevToolsPluginCliExtensionExecutor {\n constructor(\n private plugin: DevToolsPluginInfo,\n private projectRoot: string,\n private spawnFunc: typeof spawn = spawn, // Used for injection when testing,\n private timeoutMs = DEFAULT_TIMEOUT_MS // Timeout for command execution\n ) {\n // Validate that this is a plugin with cli extensions\n if (!this.plugin.cliExtensions?.entryPoint) {\n throw new Error(`Plugin ${this.plugin.packageName} has no CLI extensions`);\n }\n }\n\n public validate({ command, args }: Omit<DevToolsPluginExecutorArguments, 'metroServerOrigin'>) {\n const commandElement = this.plugin.cliExtensions?.commands.find((c) => c.name === command);\n if (!commandElement) {\n throw new Error(`Command \"${command}\" not found in plugin ${this.plugin.packageName}`);\n }\n\n const paramLength = commandElement.parameters?.length ?? 0;\n const argsLength = Object.keys(args ?? {}).length;\n if (paramLength !== argsLength) {\n // Quick check to see if the lengths match\n throw new Error(\n `Expected ${paramLength} parameter(s), but got ${argsLength} argument(s) for the command \"${command}\".`\n );\n }\n\n const argsKeys = Object.keys(args ?? {});\n for (const param of commandElement.parameters ?? []) {\n const found = argsKeys.find((key) => key === param.name);\n if (!found) {\n throw new Error(\n `Parameter \"${param.name}\" not found in command \"${command}\" of plugin ${this.plugin.packageName}`\n );\n }\n }\n }\n\n /** this function is used for testing and showing the command in UI */\n public getCommandString = ({\n command,\n args,\n }: Omit<DevToolsPluginExecutorArguments, 'metroServerOrigin'>) => {\n return `node ${this.plugin.cliExtensions!.entryPoint} ${command}${Object.keys(args ?? {}).length > 0 ? ' ' + JSON.stringify(args) : ''}`;\n };\n\n public execute = async ({\n command,\n args,\n metroServerOrigin,\n onOutput,\n }: DevToolsPluginExecutorArguments): Promise<DevToolsPluginOutput> => {\n this.validate({ command, args });\n return new Promise<DevToolsPluginOutput>(async (resolve) => {\n // Set up the command and its arguments\n const tool = path.join(this.plugin.packageRoot, this.plugin.cliExtensions!.entryPoint);\n const child = this.spawnFunc(\n 'node',\n [tool, command, `'${JSON.stringify(args)}'`, `'${metroServerOrigin}'`],\n {\n cwd: this.projectRoot,\n env: { ...process.env },\n }\n );\n\n let finished = false;\n const pluginResults = new DevToolsPluginCliExtensionResults(onOutput);\n\n // Collect output/error data\n child.stdout.on('data', (data) => pluginResults.append(data.toString()));\n child.stderr.on('data', (data) => pluginResults.append(data.toString(), 'error'));\n\n // Setup timeout\n const timeout = setTimeout(() => {\n if (!finished) {\n finished = true;\n child.kill('SIGKILL');\n pluginResults.append('Command timed out', 'error');\n resolve(pluginResults.getOutput());\n }\n }, this.timeoutMs);\n\n child.on('close', (code: number) => {\n if (finished) return;\n clearTimeout(timeout);\n finished = true;\n pluginResults.exit(code);\n resolve(pluginResults.getOutput());\n });\n\n child.on('error', (err: Error) => {\n if (finished) return;\n clearTimeout(timeout);\n finished = true;\n pluginResults.append(err.toString(), 'error');\n resolve(pluginResults.getOutput());\n });\n });\n };\n}\n"],"names":["DevToolsPluginCliExtensionExecutor","DEFAULT_TIMEOUT_MS","constructor","plugin","projectRoot","spawnFunc","spawn","timeoutMs","getCommandString","command","args","cliExtensions","entryPoint","Object","keys","length","JSON","stringify","execute","metroServerOrigin","onOutput","validate","Promise","resolve","tool","path","join","packageRoot","child","cwd","env","process","finished","pluginResults","DevToolsPluginCliExtensionResults","stdout","on","data","append","toString","stderr","timeout","setTimeout","kill","getOutput","code","clearTimeout","exit","err","Error","packageName","commandElement","commands","find","c","name","paramLength","parameters","argsLength","argsKeys","param","found","key"],"mappings":"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"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
Object.defineProperty(exports, "DevToolsPluginCliExtensionResults", {
|
|
6
|
+
enumerable: true,
|
|
7
|
+
get: function() {
|
|
8
|
+
return DevToolsPluginCliExtensionResults;
|
|
9
|
+
}
|
|
10
|
+
});
|
|
11
|
+
const _DevToolsPluginschema = require("./DevToolsPlugin.schema");
|
|
12
|
+
class DevToolsPluginCliExtensionResults {
|
|
13
|
+
constructor(onOutput){
|
|
14
|
+
this.onOutput = onOutput;
|
|
15
|
+
this._output = [];
|
|
16
|
+
}
|
|
17
|
+
append(output, level = 'info') {
|
|
18
|
+
const results = this.parseOutputText(output, level);
|
|
19
|
+
this._output.push(...results);
|
|
20
|
+
this.onOutput == null ? void 0 : this.onOutput.call(this, results);
|
|
21
|
+
}
|
|
22
|
+
exit(code) {
|
|
23
|
+
if (code === 0) return;
|
|
24
|
+
this.append(`Process exited with code ${code}`, 'error');
|
|
25
|
+
}
|
|
26
|
+
getOutput() {
|
|
27
|
+
return this._output;
|
|
28
|
+
}
|
|
29
|
+
parseOutputText(txt, level = 'info') {
|
|
30
|
+
// Validate against schema
|
|
31
|
+
try {
|
|
32
|
+
const result = _DevToolsPluginschema.DevToolsPluginOutputSchema.safeParse(JSON.parse(txt));
|
|
33
|
+
if (!result.success) {
|
|
34
|
+
return [
|
|
35
|
+
{
|
|
36
|
+
type: 'text',
|
|
37
|
+
text: `Invalid JSON: ${result.error.issues.map((issue)=>issue.message).join(', ')}`,
|
|
38
|
+
level: 'error'
|
|
39
|
+
}
|
|
40
|
+
];
|
|
41
|
+
}
|
|
42
|
+
return result.data;
|
|
43
|
+
} catch {
|
|
44
|
+
// Not JSON, treat as plain text
|
|
45
|
+
const lines = txt.split('\n');
|
|
46
|
+
const results = [];
|
|
47
|
+
for (const line of lines){
|
|
48
|
+
if (line) {
|
|
49
|
+
results.push({
|
|
50
|
+
type: 'text',
|
|
51
|
+
text: line,
|
|
52
|
+
level
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return results;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
//# sourceMappingURL=DevToolsPluginCliExtensionResults.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../src/start/server/DevToolsPluginCliExtensionResults.ts"],"sourcesContent":["import z from 'zod';\n\nimport { DevToolsPluginOutput, DevToolsPluginOutputSchema } from './DevToolsPlugin.schema';\n\n/**\n * Class that collects and manages output from executed plugin commands\n *\n * Responsibilities:\n * - Collects output data from executed commands\n * - Parses and validates output data against expected schema\n * - Provides methods to append new output entries\n * - Handles exit codes and appends relevant messages\n * - Handles streaming of output via optional callback\n */\nexport class DevToolsPluginCliExtensionResults {\n constructor(private onOutput?: (output: DevToolsPluginOutput) => void) {}\n\n private _output: DevToolsPluginOutput = [];\n\n public append(output: string, level: 'info' | 'warning' | 'error' = 'info') {\n const results = this.parseOutputText(output, level);\n this._output.push(...results);\n this.onOutput?.(results);\n }\n\n public exit(code: number) {\n if (code === 0) return;\n this.append(`Process exited with code ${code}`, 'error');\n }\n\n public getOutput(): DevToolsPluginOutput {\n return this._output;\n }\n\n private parseOutputText(\n txt: string,\n level: 'info' | 'warning' | 'error' = 'info'\n ): DevToolsPluginOutput {\n // Validate against schema\n try {\n const result = DevToolsPluginOutputSchema.safeParse(JSON.parse(txt));\n if (!result.success) {\n return [\n {\n type: 'text',\n text: `Invalid JSON: ${result.error.issues.map((issue) => issue.message).join(', ')}`,\n level: 'error',\n },\n ];\n }\n return result.data;\n } catch {\n // Not JSON, treat as plain text\n const lines = txt.split('\\n');\n const results: DevToolsPluginOutput = [];\n for (const line of lines) {\n if (line) {\n results.push({ type: 'text', text: line, level });\n }\n }\n return results;\n }\n }\n}\n"],"names":["DevToolsPluginCliExtensionResults","constructor","onOutput","_output","append","output","level","results","parseOutputText","push","exit","code","getOutput","txt","result","DevToolsPluginOutputSchema","safeParse","JSON","parse","success","type","text","error","issues","map","issue","message","join","data","lines","split","line"],"mappings":";;;;+BAcaA;;;eAAAA;;;sCAZoD;AAY1D,MAAMA;IACXC,YAAY,AAAQC,QAAiD,CAAE;aAAnDA,WAAAA;aAEZC,UAAgC,EAAE;IAF8B;IAIjEC,OAAOC,MAAc,EAAEC,QAAsC,MAAM,EAAE;QAC1E,MAAMC,UAAU,IAAI,CAACC,eAAe,CAACH,QAAQC;QAC7C,IAAI,CAACH,OAAO,CAACM,IAAI,IAAIF;QACrB,IAAI,CAACL,QAAQ,oBAAb,IAAI,CAACA,QAAQ,MAAb,IAAI,EAAYK;IAClB;IAEOG,KAAKC,IAAY,EAAE;QACxB,IAAIA,SAAS,GAAG;QAChB,IAAI,CAACP,MAAM,CAAC,CAAC,yBAAyB,EAAEO,MAAM,EAAE;IAClD;IAEOC,YAAkC;QACvC,OAAO,IAAI,CAACT,OAAO;IACrB;IAEQK,gBACNK,GAAW,EACXP,QAAsC,MAAM,EACtB;QACtB,0BAA0B;QAC1B,IAAI;YACF,MAAMQ,SAASC,gDAA0B,CAACC,SAAS,CAACC,KAAKC,KAAK,CAACL;YAC/D,IAAI,CAACC,OAAOK,OAAO,EAAE;gBACnB,OAAO;oBACL;wBACEC,MAAM;wBACNC,MAAM,CAAC,cAAc,EAAEP,OAAOQ,KAAK,CAACC,MAAM,CAACC,GAAG,CAAC,CAACC,QAAUA,MAAMC,OAAO,EAAEC,IAAI,CAAC,OAAO;wBACrFrB,OAAO;oBACT;iBACD;YACH;YACA,OAAOQ,OAAOc,IAAI;QACpB,EAAE,OAAM;YACN,gCAAgC;YAChC,MAAMC,QAAQhB,IAAIiB,KAAK,CAAC;YACxB,MAAMvB,UAAgC,EAAE;YACxC,KAAK,MAAMwB,QAAQF,MAAO;gBACxB,IAAIE,MAAM;oBACRxB,QAAQE,IAAI,CAAC;wBAAEW,MAAM;wBAAQC,MAAMU;wBAAMzB;oBAAM;gBACjD;YACF;YACA,OAAOC;QACT;IACF;AACF"}
|
|
@@ -16,6 +16,7 @@ _export(exports, {
|
|
|
16
16
|
return DevToolsPluginManager;
|
|
17
17
|
}
|
|
18
18
|
});
|
|
19
|
+
const _DevToolsPlugin = require("./DevToolsPlugin");
|
|
19
20
|
const debug = require('debug')('expo:start:server:devtools');
|
|
20
21
|
const DevToolsPluginEndpoint = '/_expo/plugins';
|
|
21
22
|
class DevToolsPluginManager {
|
|
@@ -24,14 +25,9 @@ class DevToolsPluginManager {
|
|
|
24
25
|
this.plugins = null;
|
|
25
26
|
}
|
|
26
27
|
async queryPluginsAsync() {
|
|
27
|
-
if (this.plugins) {
|
|
28
|
-
|
|
28
|
+
if (!this.plugins) {
|
|
29
|
+
this.plugins = await this.queryAutolinkedPluginsAsync(this.projectRoot);
|
|
29
30
|
}
|
|
30
|
-
const plugins = (await this.queryAutolinkedPluginsAsync(this.projectRoot)).map((plugin)=>({
|
|
31
|
-
...plugin,
|
|
32
|
-
webpageEndpoint: `${DevToolsPluginEndpoint}/${plugin.packageName}`
|
|
33
|
-
}));
|
|
34
|
-
this.plugins = plugins;
|
|
35
31
|
return this.plugins;
|
|
36
32
|
}
|
|
37
33
|
async queryPluginWebpageRootAsync(pluginName) {
|
|
@@ -48,7 +44,7 @@ class DevToolsPluginManager {
|
|
|
48
44
|
const { resolveModuleAsync } = autolinking.getLinkingImplementationForPlatform('devtools');
|
|
49
45
|
const plugins = (await Promise.all(Object.values(revisions).map((revision)=>resolveModuleAsync(revision.name, revision)))).filter((maybePlugin)=>maybePlugin != null);
|
|
50
46
|
debug('Found autolinked plugins', plugins);
|
|
51
|
-
return plugins;
|
|
47
|
+
return plugins.map((pluginInfo)=>new _DevToolsPlugin.DevToolsPlugin(pluginInfo, this.projectRoot)).filter((p)=>p != null);
|
|
52
48
|
}
|
|
53
49
|
}
|
|
54
50
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/start/server/DevToolsPluginManager.ts"],"sourcesContent":["import type { ModuleDescriptorDevTools } from 'expo-modules-autolinking/exports';\n\nconst debug = require('debug')('expo:start:server:devtools');\n\nexport const DevToolsPluginEndpoint = '/_expo/plugins';\n\
|
|
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"}
|