@expo/cli 54.1.0-canary-20251023-4c86f95 → 55.0.0-canary-20251118-8f7ee64
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/api/rest/cache/ResponseCache.js +3 -1
- package/build/src/api/rest/cache/ResponseCache.js.map +1 -1
- package/build/src/export/exportStaticAsync.js +30 -2
- package/build/src/export/exportStaticAsync.js.map +1 -1
- package/build/src/export/saveAssets.js +10 -0
- package/build/src/export/saveAssets.js.map +1 -1
- package/build/src/start/interface/commandsTable.js.map +1 -1
- package/build/src/start/interface/startInterface.js +3 -0
- package/build/src/start/interface/startInterface.js.map +1 -1
- package/build/src/start/platforms/android/AndroidDeviceManager.js +2 -7
- package/build/src/start/platforms/android/AndroidDeviceManager.js.map +1 -1
- package/build/src/start/platforms/android/adb.js +0 -6
- package/build/src/start/platforms/android/adb.js.map +1 -1
- package/build/src/start/server/MCP.js +15 -4
- package/build/src/start/server/MCP.js.map +1 -1
- package/build/src/start/server/metro/MetroBundlerDevServer.js +41 -36
- package/build/src/start/server/metro/MetroBundlerDevServer.js.map +1 -1
- package/build/src/start/server/metro/createServerComponentsMiddleware.js +16 -16
- package/build/src/start/server/metro/createServerComponentsMiddleware.js.map +1 -1
- package/build/src/start/server/metro/createServerRouteMiddleware.js +7 -29
- package/build/src/start/server/metro/createServerRouteMiddleware.js.map +1 -1
- package/build/src/start/server/metro/debugging/createDebugMiddleware.js +3 -1
- package/build/src/start/server/metro/debugging/createDebugMiddleware.js.map +1 -1
- package/build/src/start/server/metro/errors/FailedToResolveNativeOnlyModuleError.js +17 -0
- package/build/src/start/server/metro/errors/FailedToResolveNativeOnlyModuleError.js.map +1 -0
- package/build/src/start/server/metro/fetchRouterManifest.js.map +1 -1
- package/build/src/start/server/metro/instantiateMetro.js +14 -10
- package/build/src/start/server/metro/instantiateMetro.js.map +1 -1
- package/build/src/start/server/metro/resolveLoader.js +65 -0
- package/build/src/start/server/metro/resolveLoader.js.map +1 -0
- package/build/src/start/server/metro/withMetroMultiPlatform.js +25 -26
- package/build/src/start/server/metro/withMetroMultiPlatform.js.map +1 -1
- package/build/src/start/server/middleware/DataLoaderModuleMiddleware.js.map +1 -1
- package/build/src/start/server/middleware/inspector/CdpClient.js +2 -0
- package/build/src/start/server/middleware/inspector/CdpClient.js.map +1 -1
- package/build/src/start/server/type-generation/routes.js +3 -1
- package/build/src/start/server/type-generation/routes.js.map +1 -1
- package/build/src/start/startAsync.js +11 -8
- package/build/src/start/startAsync.js.map +1 -1
- package/build/src/utils/env.js +0 -3
- package/build/src/utils/env.js.map +1 -1
- package/build/src/utils/telemetry/clients/FetchClient.js +1 -1
- package/build/src/utils/telemetry/utils/context.js +1 -1
- package/package.json +21 -23
- package/static/template/[...rsc]+api.ts +1 -1
- package/build/src/start/server/metro/createExpoMetroResolver.js +0 -265
- package/build/src/start/server/metro/createExpoMetroResolver.js.map +0 -1
- package/build/src/start/server/metro/createJResolver.js +0 -201
- package/build/src/start/server/metro/createJResolver.js.map +0 -1
- package/build/src/start/server/metro/formatFileCandidates.js +0 -84
- package/build/src/start/server/metro/formatFileCandidates.js.map +0 -1
|
@@ -51,9 +51,6 @@ _export(exports, {
|
|
|
51
51
|
logUnauthorized: function() {
|
|
52
52
|
return logUnauthorized;
|
|
53
53
|
},
|
|
54
|
-
openAppIdAsync: function() {
|
|
55
|
-
return openAppIdAsync;
|
|
56
|
-
},
|
|
57
54
|
openUrlAsync: function() {
|
|
58
55
|
return openUrlAsync;
|
|
59
56
|
},
|
|
@@ -189,9 +186,6 @@ async function launchActivityAsync(device, { launchActivity, url }) {
|
|
|
189
186
|
}
|
|
190
187
|
return openAsync(adbArgs(device.pid, ...args));
|
|
191
188
|
}
|
|
192
|
-
async function openAppIdAsync(device, { applicationId }) {
|
|
193
|
-
return openAsync(adbArgs(device.pid, 'shell', 'monkey', '--pct-syskeys', '0', '-p', applicationId, '-c', 'android.intent.category.LAUNCHER', '1'));
|
|
194
|
-
}
|
|
195
189
|
async function openUrlAsync(device, { url }) {
|
|
196
190
|
return openAsync(adbArgs(device.pid, 'shell', 'am', 'start', '-a', 'android.intent.action.VIEW', '-d', // ADB requires ampersands to be escaped.
|
|
197
191
|
url.replace(/&/g, String.raw`\&`)));
|
|
@@ -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 '--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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"}
|
|
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.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","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","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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"}
|
|
@@ -18,6 +18,7 @@ function _resolvefrom() {
|
|
|
18
18
|
const _UserSettings = require("../../api/user/UserSettings");
|
|
19
19
|
const _log = require("../../log");
|
|
20
20
|
const _env = require("../../utils/env");
|
|
21
|
+
const _exit = require("../../utils/exit");
|
|
21
22
|
function _interop_require_default(obj) {
|
|
22
23
|
return obj && obj.__esModule ? obj : {
|
|
23
24
|
default: obj
|
|
@@ -25,7 +26,7 @@ function _interop_require_default(obj) {
|
|
|
25
26
|
}
|
|
26
27
|
const importESM = require('@expo/cli/add-module');
|
|
27
28
|
const debug = require('debug')('expo:start:server:mcp');
|
|
28
|
-
async function maybeCreateMCPServerAsync(projectRoot) {
|
|
29
|
+
async function maybeCreateMCPServerAsync({ projectRoot, devServerUrl }) {
|
|
29
30
|
const mcpServer = _env.env.EXPO_UNSTABLE_MCP_SERVER;
|
|
30
31
|
if (!mcpServer) {
|
|
31
32
|
return null;
|
|
@@ -52,11 +53,21 @@ async function maybeCreateMCPServerAsync(projectRoot) {
|
|
|
52
53
|
_log.Log.log(...message);
|
|
53
54
|
}
|
|
54
55
|
};
|
|
55
|
-
const
|
|
56
|
+
const serverProxy = new TunnelMcpServerProxy(mcpServerUrl, {
|
|
56
57
|
logger,
|
|
57
|
-
wsHeaders: createAuthHeaders()
|
|
58
|
+
wsHeaders: createAuthHeaders(),
|
|
59
|
+
projectRoot,
|
|
60
|
+
devServerUrl
|
|
58
61
|
});
|
|
59
|
-
addMcpCapabilities(
|
|
62
|
+
addMcpCapabilities(serverProxy, projectRoot);
|
|
63
|
+
const removeExitHook = (0, _exit.installExitHooks)(async ()=>{
|
|
64
|
+
await serverProxy.close();
|
|
65
|
+
});
|
|
66
|
+
const server = serverProxy;
|
|
67
|
+
server.closeAsync = async ()=>{
|
|
68
|
+
removeExitHook();
|
|
69
|
+
await serverProxy.close();
|
|
70
|
+
};
|
|
60
71
|
return server;
|
|
61
72
|
} catch (error) {
|
|
62
73
|
debug(`Error creating MCP tunnel: ${error}`);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/start/server/MCP.ts"],"sourcesContent":["import type {\n McpServerProxy,\n TunnelMcpServerProxy as TunnelMcpServerProxyType,\n} from '@expo/mcp-tunnel' with { 'resolution-mode': 'import' };\nimport resolveFrom from 'resolve-from';\n\nimport { getAccessToken, getSession } from '../../api/user/UserSettings';\nimport { Log } from '../../log';\nimport { env } from '../../utils/env';\n\nconst importESM = require('@expo/cli/add-module') as <T>(moduleName: string) => Promise<T>;\n\nconst debug = require('debug')('expo:start:server:mcp') as typeof console.log;\n\n/**\n * Create the MCP server\n */\nexport async function maybeCreateMCPServerAsync(\n projectRoot:
|
|
1
|
+
{"version":3,"sources":["../../../../src/start/server/MCP.ts"],"sourcesContent":["import type {\n McpServerProxy,\n TunnelMcpServerProxy as TunnelMcpServerProxyType,\n} from '@expo/mcp-tunnel' with { 'resolution-mode': 'import' };\nimport resolveFrom from 'resolve-from';\n\nimport { getAccessToken, getSession } from '../../api/user/UserSettings';\nimport { Log } from '../../log';\nimport { env } from '../../utils/env';\nimport { installExitHooks } from '../../utils/exit';\n\nconst importESM = require('@expo/cli/add-module') as <T>(moduleName: string) => Promise<T>;\n\nconst debug = require('debug')('expo:start:server:mcp') as typeof console.log;\n\n/**\n * The MCP server\n */\nexport type McpServer = Omit<McpServerProxy, 'close'> & {\n /**\n * Close the server\n */\n closeAsync: () => Promise<void>;\n};\n\n/**\n * Create the MCP server\n */\nexport async function maybeCreateMCPServerAsync({\n projectRoot,\n devServerUrl,\n}: {\n projectRoot: string;\n devServerUrl: string;\n}): Promise<McpServer | null> {\n const mcpServer = env.EXPO_UNSTABLE_MCP_SERVER;\n if (!mcpServer) {\n return null;\n }\n const mcpPackagePath = resolveFrom.silent(projectRoot, 'expo-mcp');\n if (!mcpPackagePath) {\n Log.error(\n 'Missing the `expo-mcp` package in the project. To enable the MCP integration, add the `expo-mcp` package to your project.'\n );\n return null;\n }\n\n const normalizedServer = /^([a-zA-Z][a-zA-Z\\d+\\-.]*):\\/\\//.test(mcpServer)\n ? mcpServer\n : `wss://${mcpServer}`;\n const mcpServerUrlObject = new URL(normalizedServer);\n const scheme = mcpServerUrlObject.protocol ?? 'wss:';\n const mcpServerUrl = `${scheme}//${mcpServerUrlObject.host}`;\n debug(`Creating MCP tunnel - server URL: ${mcpServerUrl}`);\n\n try {\n const { addMcpCapabilities } = await importESM<{\n addMcpCapabilities: (server: McpServerProxy, projectRoot: string) => void;\n }>(mcpPackagePath);\n const { TunnelMcpServerProxy } = await importESM<{\n TunnelMcpServerProxy: typeof TunnelMcpServerProxyType;\n }>('@expo/mcp-tunnel');\n\n const logger = {\n ...Log,\n debug(...message: any[]): void {\n debug(...message);\n },\n info(...message: any[]): void {\n Log.log(...message);\n },\n };\n const serverProxy: McpServerProxy = new TunnelMcpServerProxy(mcpServerUrl, {\n logger,\n wsHeaders: createAuthHeaders(),\n projectRoot,\n devServerUrl,\n });\n addMcpCapabilities(serverProxy, projectRoot);\n\n const removeExitHook = installExitHooks(async () => {\n await serverProxy.close();\n });\n const server = serverProxy as unknown as McpServer;\n server.closeAsync = async () => {\n removeExitHook();\n await serverProxy.close();\n };\n\n return server;\n } catch (error: unknown) {\n debug(`Error creating MCP tunnel: ${error}`);\n }\n return null;\n}\n\nfunction createAuthHeaders(): Record<string, string> {\n const token = getAccessToken();\n if (token) {\n return {\n authorization: `Bearer ${token}`,\n };\n }\n const sessionSecret = getSession()?.sessionSecret;\n if (sessionSecret) {\n return {\n 'expo-session': sessionSecret,\n };\n }\n return {};\n}\n"],"names":["maybeCreateMCPServerAsync","importESM","require","debug","projectRoot","devServerUrl","mcpServer","env","EXPO_UNSTABLE_MCP_SERVER","mcpPackagePath","resolveFrom","silent","Log","error","normalizedServer","test","mcpServerUrlObject","URL","scheme","protocol","mcpServerUrl","host","addMcpCapabilities","TunnelMcpServerProxy","logger","message","info","log","serverProxy","wsHeaders","createAuthHeaders","removeExitHook","installExitHooks","close","server","closeAsync","getSession","token","getAccessToken","authorization","sessionSecret"],"mappings":";;;;+BA4BsBA;;;eAAAA;;;;gEAxBE;;;;;;8BAEmB;qBACvB;qBACA;sBACa;;;;;;AAEjC,MAAMC,YAAYC,QAAQ;AAE1B,MAAMC,QAAQD,QAAQ,SAAS;AAexB,eAAeF,0BAA0B,EAC9CI,WAAW,EACXC,YAAY,EAIb;IACC,MAAMC,YAAYC,QAAG,CAACC,wBAAwB;IAC9C,IAAI,CAACF,WAAW;QACd,OAAO;IACT;IACA,MAAMG,iBAAiBC,sBAAW,CAACC,MAAM,CAACP,aAAa;IACvD,IAAI,CAACK,gBAAgB;QACnBG,QAAG,CAACC,KAAK,CACP;QAEF,OAAO;IACT;IAEA,MAAMC,mBAAmB,kCAAkCC,IAAI,CAACT,aAC5DA,YACA,CAAC,MAAM,EAAEA,WAAW;IACxB,MAAMU,qBAAqB,IAAIC,IAAIH;IACnC,MAAMI,SAASF,mBAAmBG,QAAQ,IAAI;IAC9C,MAAMC,eAAe,GAAGF,OAAO,EAAE,EAAEF,mBAAmBK,IAAI,EAAE;IAC5DlB,MAAM,CAAC,kCAAkC,EAAEiB,cAAc;IAEzD,IAAI;QACF,MAAM,EAAEE,kBAAkB,EAAE,GAAG,MAAMrB,UAElCQ;QACH,MAAM,EAAEc,oBAAoB,EAAE,GAAG,MAAMtB,UAEpC;QAEH,MAAMuB,SAAS;YACb,GAAGZ,QAAG;YACNT,OAAM,GAAGsB,OAAc;gBACrBtB,SAASsB;YACX;YACAC,MAAK,GAAGD,OAAc;gBACpBb,QAAG,CAACe,GAAG,IAAIF;YACb;QACF;QACA,MAAMG,cAA8B,IAAIL,qBAAqBH,cAAc;YACzEI;YACAK,WAAWC;YACX1B;YACAC;QACF;QACAiB,mBAAmBM,aAAaxB;QAEhC,MAAM2B,iBAAiBC,IAAAA,sBAAgB,EAAC;YACtC,MAAMJ,YAAYK,KAAK;QACzB;QACA,MAAMC,SAASN;QACfM,OAAOC,UAAU,GAAG;YAClBJ;YACA,MAAMH,YAAYK,KAAK;QACzB;QAEA,OAAOC;IACT,EAAE,OAAOrB,OAAgB;QACvBV,MAAM,CAAC,2BAA2B,EAAEU,OAAO;IAC7C;IACA,OAAO;AACT;AAEA,SAASiB;QAOeM;IANtB,MAAMC,QAAQC,IAAAA,4BAAc;IAC5B,IAAID,OAAO;QACT,OAAO;YACLE,eAAe,CAAC,OAAO,EAAEF,OAAO;QAClC;IACF;IACA,MAAMG,iBAAgBJ,cAAAA,IAAAA,wBAAU,wBAAVA,YAAcI,aAAa;IACjD,IAAIA,eAAe;QACjB,OAAO;YACL,gBAAgBA;QAClB;IACF;IACA,OAAO,CAAC;AACV"}
|
|
@@ -83,13 +83,6 @@ function _path() {
|
|
|
83
83
|
};
|
|
84
84
|
return data;
|
|
85
85
|
}
|
|
86
|
-
function _resolvefrom() {
|
|
87
|
-
const data = /*#__PURE__*/ _interop_require_default(require("resolve-from"));
|
|
88
|
-
_resolvefrom = function() {
|
|
89
|
-
return data;
|
|
90
|
-
};
|
|
91
|
-
return data;
|
|
92
|
-
}
|
|
93
86
|
const _createServerComponentsMiddleware = require("./createServerComponentsMiddleware");
|
|
94
87
|
const _createServerRouteMiddleware = require("./createServerRouteMiddleware");
|
|
95
88
|
const _fetchRouterManifest = require("./fetchRouterManifest");
|
|
@@ -106,6 +99,7 @@ const _filePath = require("../../../utils/filePath");
|
|
|
106
99
|
const _port = require("../../../utils/port");
|
|
107
100
|
const _BundlerDevServer = require("../BundlerDevServer");
|
|
108
101
|
const _getStaticRenderFunctions = require("../getStaticRenderFunctions");
|
|
102
|
+
const _resolveLoader = require("./resolveLoader");
|
|
109
103
|
const _ContextModuleSourceMapsMiddleware = require("../middleware/ContextModuleSourceMapsMiddleware");
|
|
110
104
|
const _CreateFileMiddleware = require("../middleware/CreateFileMiddleware");
|
|
111
105
|
const _DataLoaderModuleMiddleware = require("../middleware/DataLoaderModuleMiddleware");
|
|
@@ -246,7 +240,10 @@ class MetroBundlerDevServer extends _BundlerDevServer.BundlerDevServer {
|
|
|
246
240
|
debug('Adding RSC route to the manifest:', rscPath);
|
|
247
241
|
// NOTE: This might need to be sorted to the correct spot in the future.
|
|
248
242
|
manifest.apiRoutes.push({
|
|
249
|
-
|
|
243
|
+
// TODO(@kitten): This isn't great, we shouldn't be needing to rely on files like this
|
|
244
|
+
// It might even be better to make templating strings since that'd be type-checked, but currently,
|
|
245
|
+
// we rely on this being an entrypoint for Metro
|
|
246
|
+
file: require.resolve('@expo/cli/static/template/[...rsc]+api.ts'),
|
|
250
247
|
page: rscPath,
|
|
251
248
|
namedRegex: '^/_flight(?:/(?<rsc>.+?))?(?:/)?$',
|
|
252
249
|
routeKeys: {
|
|
@@ -324,6 +321,9 @@ class MetroBundlerDevServer extends _BundlerDevServer.BundlerDevServer {
|
|
|
324
321
|
* This function is invoked when exporting via `expo export`
|
|
325
322
|
*/ async getStaticRenderFunctionAsync() {
|
|
326
323
|
var _exp_extra, _exp_extra1;
|
|
324
|
+
const { routerRoot } = this.instanceMetroOptions;
|
|
325
|
+
(0, _assert().default)(routerRoot != null, 'The server must be started before calling getStaticRenderFunctionAsync.');
|
|
326
|
+
const appDir = _path().default.join(this.projectRoot, routerRoot);
|
|
327
327
|
const url = this.getDevServerUrlOrAssert();
|
|
328
328
|
const { getStaticContent, getManifest, getBuildTimeServerManifestAsync } = await this.ssrLoadModule('@expo/router-server/node/render.js', {
|
|
329
329
|
// This must always use the legacy rendering resolution (no `react-server`) because it leverages
|
|
@@ -342,8 +342,20 @@ class MetroBundlerDevServer extends _BundlerDevServer.BundlerDevServer {
|
|
|
342
342
|
...(_exp_extra1 = exp.extra) == null ? void 0 : _exp_extra1.router
|
|
343
343
|
}),
|
|
344
344
|
// Get route generating function
|
|
345
|
-
async
|
|
346
|
-
|
|
345
|
+
renderAsync: async (path, route, opts)=>{
|
|
346
|
+
const location = new URL(path, url);
|
|
347
|
+
return await getStaticContent(location, opts);
|
|
348
|
+
},
|
|
349
|
+
executeLoaderAsync: async (path, route)=>{
|
|
350
|
+
const location = new URL(path, url);
|
|
351
|
+
const resolvedLoaderRoute = (0, _resolveLoader.fromRuntimeManifestRoute)(location.pathname, route, {
|
|
352
|
+
serverManifest: (0, _fetchRouterManifest.inflateManifest)(serverManifest),
|
|
353
|
+
appDir
|
|
354
|
+
});
|
|
355
|
+
if (!resolvedLoaderRoute) {
|
|
356
|
+
return undefined;
|
|
357
|
+
}
|
|
358
|
+
return await this.executeServerDataLoaderAsync(location, resolvedLoaderRoute);
|
|
347
359
|
}
|
|
348
360
|
};
|
|
349
361
|
}
|
|
@@ -407,16 +419,19 @@ class MetroBundlerDevServer extends _BundlerDevServer.BundlerDevServer {
|
|
|
407
419
|
});
|
|
408
420
|
const location = new URL(pathname, this.getDevServerUrlOrAssert());
|
|
409
421
|
const useServerDataLoaders = (_exp_extra = exp.extra) == null ? void 0 : (_exp_extra_router = _exp_extra.router) == null ? void 0 : _exp_extra_router.unstable_useServerDataLoaders;
|
|
410
|
-
if (useServerDataLoaders) {
|
|
411
|
-
const data = await this.executeServerDataLoaderAsync(location, route);
|
|
412
|
-
return await getStaticContent(location, {
|
|
413
|
-
loader: {
|
|
414
|
-
data
|
|
415
|
-
}
|
|
416
|
-
});
|
|
417
|
-
} else {
|
|
422
|
+
if (!useServerDataLoaders) {
|
|
418
423
|
return await getStaticContent(location);
|
|
419
424
|
}
|
|
425
|
+
const resolvedLoaderRoute = (0, _resolveLoader.fromServerManifestRoute)(location.pathname, route);
|
|
426
|
+
if (!resolvedLoaderRoute) {
|
|
427
|
+
return await getStaticContent(location);
|
|
428
|
+
}
|
|
429
|
+
const data = await this.executeServerDataLoaderAsync(location, resolvedLoaderRoute);
|
|
430
|
+
return await getStaticContent(location, {
|
|
431
|
+
loader: {
|
|
432
|
+
data
|
|
433
|
+
}
|
|
434
|
+
});
|
|
420
435
|
};
|
|
421
436
|
const [{ artifacts: resources }, staticHtml] = await Promise.all([
|
|
422
437
|
this.getStaticResourcesAsync({
|
|
@@ -843,7 +858,11 @@ class MetroBundlerDevServer extends _BundlerDevServer.BundlerDevServer {
|
|
|
843
858
|
var _exp_extra_router1, _exp_extra2;
|
|
844
859
|
if ((_exp_extra2 = exp.extra) == null ? void 0 : (_exp_extra_router1 = _exp_extra2.router) == null ? void 0 : _exp_extra_router1.unstable_useServerDataLoaders) {
|
|
845
860
|
const loaderModuleMiddleware = new _DataLoaderModuleMiddleware.DataLoaderModuleMiddleware(this.projectRoot, appDir, async (location, route)=>{
|
|
846
|
-
|
|
861
|
+
const resolvedLoaderRoute = (0, _resolveLoader.fromServerManifestRoute)(location.pathname, route);
|
|
862
|
+
if (!resolvedLoaderRoute) {
|
|
863
|
+
return;
|
|
864
|
+
}
|
|
865
|
+
return this.executeServerDataLoaderAsync(location, resolvedLoaderRoute);
|
|
847
866
|
}, ()=>this.getDevServerUrlOrAssert());
|
|
848
867
|
// This MUST be before ServeStaticMiddleware so it doesn't treat the loader files as static assets
|
|
849
868
|
middleware.use(loaderModuleMiddleware.getHandler());
|
|
@@ -1178,27 +1197,13 @@ class MetroBundlerDevServer extends _BundlerDevServer.BundlerDevServer {
|
|
|
1178
1197
|
if (!unstable_useServerDataLoaders) {
|
|
1179
1198
|
throw new _errors.CommandError('LOADERS_NOT_ENABLED', 'Server data loaders are not enabled. Add `unstable_useServerDataLoaders` to your `expo-router` plugin config.');
|
|
1180
1199
|
}
|
|
1181
|
-
// If the route is unmatched, we can ignore it
|
|
1182
|
-
// TODO(@hassankhan): Is this the best way of determining the route is unmatched?
|
|
1183
|
-
if (route.page === '/+not-found') {
|
|
1184
|
-
return;
|
|
1185
|
-
}
|
|
1186
1200
|
const { routerRoot } = this.instanceMetroOptions;
|
|
1187
1201
|
(0, _assert().default)(routerRoot != null, 'The server must be started before calling executeRouteLoaderAsync.');
|
|
1188
1202
|
let loaderData;
|
|
1189
1203
|
try {
|
|
1190
|
-
debug(
|
|
1191
|
-
// TODO(@hassankhan): This should move to a util function
|
|
1192
|
-
const params = {};
|
|
1193
|
-
const match = route.namedRegex.exec(location.pathname);
|
|
1194
|
-
if (match == null ? void 0 : match.groups) {
|
|
1195
|
-
for (const [key, value] of Object.entries(match.groups)){
|
|
1196
|
-
const namedKey = route.routeKeys[key];
|
|
1197
|
-
params[namedKey] = value;
|
|
1198
|
-
}
|
|
1199
|
-
}
|
|
1200
|
-
let modulePath = route.file;
|
|
1204
|
+
debug(`Matched ${location.pathname} to file: ${route.file}`);
|
|
1201
1205
|
const appDir = _path().default.join(this.projectRoot, routerRoot);
|
|
1206
|
+
let modulePath = route.file;
|
|
1202
1207
|
modulePath = _path().default.isAbsolute(modulePath) ? modulePath : _path().default.join(appDir, modulePath);
|
|
1203
1208
|
modulePath = modulePath.replace(/\.(js|ts)x?$/, '');
|
|
1204
1209
|
debug('Using loader module path: ', modulePath);
|
|
@@ -1209,7 +1214,7 @@ class MetroBundlerDevServer extends _BundlerDevServer.BundlerDevServer {
|
|
|
1209
1214
|
// Register this module for loader HMR
|
|
1210
1215
|
this.setupLoaderHmr(modulePath);
|
|
1211
1216
|
loaderData = await routeModule.loader({
|
|
1212
|
-
params,
|
|
1217
|
+
params: route.params,
|
|
1213
1218
|
// NOTE(@hassankhan): The `request` object should only be available when using SSR
|
|
1214
1219
|
request: null
|
|
1215
1220
|
});
|