(
_clientId: string,
msgType: DaemonMsgType,
body: Record<string, unknown>,
timeoutMs = 15_000,
)
| 304 | // ── Messages.ts direct-to-device calls ─────────────────────────────────── |
| 305 | |
| 306 | private async forwardAndWait( |
| 307 | _clientId: string, |
| 308 | msgType: DaemonMsgType, |
| 309 | body: Record<string, unknown>, |
| 310 | timeoutMs = 15_000, |
| 311 | ): Promise<Record<string, unknown>> { |
| 312 | const msgId = this.nextMsgId(); |
| 313 | const payloadString = JSON.stringify({ type: msgType, requestId: msgId, body }); |
| 314 | |
| 315 | const resultPromise = new Promise<Record<string, unknown>>((resolve, reject) => { |
| 316 | const timer = setTimeout(() => { |
| 317 | this.payloadListeners.delete(msgId); |
| 318 | reject(new Error('Timeout waiting for device response. Is the app running?')); |
| 319 | }, timeoutMs); |
| 320 | this.payloadListeners.set(msgId, { |
| 321 | resolve: (v) => { clearTimeout(timer); resolve(v); }, |
| 322 | reject: (e) => { clearTimeout(timer); reject(e); }, |
| 323 | }); |
| 324 | }); |
| 325 | |
| 326 | // Send as an event — the device processes payload_from_client events directly. |
| 327 | // It routes responses back as forward_client_payload requests (handled in dispatchMessage). |
| 328 | this.socket.write(encodePacket({ |
| 329 | event: { |
| 330 | payload_from_client: { |
| 331 | sender_client_id: DIRECT_CLIENT_ID, |
| 332 | payload_string: payloadString, |
| 333 | }, |
| 334 | }, |
| 335 | }), (err) => { |
| 336 | if (err) { |
| 337 | const listener = this.payloadListeners.get(msgId); |
| 338 | if (listener) { |
| 339 | this.payloadListeners.delete(msgId); |
| 340 | listener.reject(err); |
| 341 | } |
| 342 | } |
| 343 | }); |
| 344 | |
| 345 | return resultPromise; |
| 346 | } |
| 347 | |
| 348 | async listContexts(clientId: string): Promise<RemoteContext[]> { |
| 349 | const resp = await this.forwardAndWait(clientId, DaemonMsgType.LIST_CONTEXTS_REQUEST, {}); |
no test coverage detected