1+ import { AsyncLocalStorage } from 'node:async_hooks' ;
12import { AppError } from '../utils/errors.ts' ;
23import {
34 normalizePlatformSelector ,
@@ -28,6 +29,8 @@ type ResolveDeviceFlags = Pick<
2829 | 'androidDeviceAllowlist'
2930> ;
3031
32+ const resolveTargetDeviceCacheScope = new AsyncLocalStorage < Map < string , DeviceInfo > > ( ) ;
33+
3134type AppleDeviceSelector = {
3235 platform ?: Exclude < PlatformSelector , 'android' > ;
3336 target ?: DeviceTarget ;
@@ -98,9 +101,25 @@ export async function resolveTargetDevice(flags: ResolveDeviceFlags): Promise<De
98101 target : flags . target ,
99102 } ) ;
100103 const androidSerialAllowlist = resolveAndroidSerialAllowlist ( flags . androidDeviceAllowlist ) ;
104+ const cacheKey = buildResolveTargetDeviceCacheKey ( {
105+ flags,
106+ normalizedPlatform,
107+ iosSimulatorSetPath,
108+ androidSerialAllowlist,
109+ } ) ;
110+ const diagnosticData = {
111+ platform : normalizedPlatform ,
112+ target : flags . target ,
113+ cacheHit : false ,
114+ } ;
101115 return await withDiagnosticTimer (
102116 'resolve_target_device' ,
103117 async ( ) => {
118+ const cached = readResolveTargetDeviceCache ( cacheKey ) ;
119+ if ( cached ) {
120+ diagnosticData . cacheHit = true ;
121+ return cached ;
122+ }
104123 const selector = {
105124 platform : normalizedPlatform ,
106125 target : flags . target ,
@@ -117,20 +136,23 @@ export async function resolveTargetDevice(flags: ResolveDeviceFlags): Promise<De
117136
118137 if ( selector . platform === 'linux' ) {
119138 const devices = await listLinuxDevices ( ) ;
120- return await resolveDevice ( devices , selector ) ;
139+ return cacheResolvedTargetDevice ( cacheKey , await resolveDevice ( devices , selector ) ) ;
121140 }
122141
123142 if ( selector . platform === 'android' ) {
124143 await ensureAdb ( ) ;
125144 const devices = await listAndroidDevices ( { serialAllowlist : androidSerialAllowlist } ) ;
126- return await resolveDevice ( devices , selector ) ;
145+ return cacheResolvedTargetDevice ( cacheKey , await resolveDevice ( devices , selector ) ) ;
127146 }
128147
129148 if ( selector . platform ) {
130149 const devices = await listAppleDevices ( { simulatorSetPath : iosSimulatorSetPath } ) ;
131- return await resolveAppleDevice ( devices , selector as AppleDeviceSelector , {
132- simulatorSetPath : iosSimulatorSetPath ,
133- } ) ;
150+ return cacheResolvedTargetDevice (
151+ cacheKey ,
152+ await resolveAppleDevice ( devices , selector as AppleDeviceSelector , {
153+ simulatorSetPath : iosSimulatorSetPath ,
154+ } ) ,
155+ ) ;
134156 }
135157
136158 const devices : DeviceInfo [ ] = [ ] ;
@@ -145,11 +167,48 @@ export async function resolveTargetDevice(flags: ResolveDeviceFlags): Promise<De
145167 try {
146168 devices . push ( ...( await listLinuxDevices ( ) ) ) ;
147169 } catch { }
148- return await resolveDevice ( devices , selector , { simulatorSetPath : iosSimulatorSetPath } ) ;
149- } ,
150- {
151- platform : normalizedPlatform ,
152- target : flags . target ,
170+ return cacheResolvedTargetDevice (
171+ cacheKey ,
172+ await resolveDevice ( devices , selector , { simulatorSetPath : iosSimulatorSetPath } ) ,
173+ ) ;
153174 } ,
175+ diagnosticData ,
154176 ) ;
155177}
178+
179+ export async function withResolveTargetDeviceCacheScope < T > ( task : ( ) => Promise < T > ) : Promise < T > {
180+ if ( resolveTargetDeviceCacheScope . getStore ( ) ) return await task ( ) ;
181+ return await resolveTargetDeviceCacheScope . run ( new Map ( ) , task ) ;
182+ }
183+
184+ function readResolveTargetDeviceCache ( cacheKey : string ) : DeviceInfo | undefined {
185+ const cache = resolveTargetDeviceCacheScope . getStore ( ) ;
186+ const cached = cache ?. get ( cacheKey ) ;
187+ if ( ! cached ) return undefined ;
188+ return { ...cached } ;
189+ }
190+
191+ function cacheResolvedTargetDevice ( cacheKey : string , device : DeviceInfo ) : DeviceInfo {
192+ resolveTargetDeviceCacheScope . getStore ( ) ?. set ( cacheKey , { ...device } ) ;
193+ return device ;
194+ }
195+
196+ function buildResolveTargetDeviceCacheKey ( params : {
197+ flags : ResolveDeviceFlags ;
198+ normalizedPlatform ?: PlatformSelector ;
199+ iosSimulatorSetPath ?: string ;
200+ androidSerialAllowlist ?: ReadonlySet < string > ;
201+ } ) : string {
202+ const { flags, normalizedPlatform, iosSimulatorSetPath, androidSerialAllowlist } = params ;
203+ return JSON . stringify ( {
204+ platform : normalizedPlatform ,
205+ target : flags . target ,
206+ device : flags . device ,
207+ udid : flags . udid ,
208+ serial : flags . serial ,
209+ iosSimulatorSetPath,
210+ androidSerialAllowlist : androidSerialAllowlist
211+ ? Array . from ( androidSerialAllowlist ) . sort ( )
212+ : undefined ,
213+ } ) ;
214+ }
0 commit comments