| 1239 | } |
| 1240 | |
| 1241 | async function withInvocationQueue<T>( |
| 1242 | sessionId: string, |
| 1243 | signal: AbortSignal, |
| 1244 | operation: () => Promise<T>, |
| 1245 | ): Promise<T> { |
| 1246 | const previous = invocationQueues.get(sessionId) ?? Promise.resolve(); |
| 1247 | let release!: () => void; |
| 1248 | const gate = new Promise<void>((resolve) => { |
| 1249 | release = resolve; |
| 1250 | }); |
| 1251 | const current = previous.then(() => gate); |
| 1252 | invocationQueues.set(sessionId, current); |
| 1253 | await previous; |
| 1254 | try { |
| 1255 | if (signal.aborted) throw new Error('aborted'); |
| 1256 | return await operation(); |
| 1257 | } finally { |
| 1258 | release(); |
| 1259 | if (invocationQueues.get(sessionId) === current) { |
| 1260 | invocationQueues.delete(sessionId); |
| 1261 | } |
| 1262 | } |
| 1263 | } |
| 1264 | |
| 1265 | function presentationScreenPoint(boundAction: CuaBoundAction | undefined): CuPoint | undefined { |
| 1266 | // An element action is aimed at an element, not at a coordinate, so it |