@limrun/ui 0.5.0 → 0.5.1

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@limrun/ui",
3
- "version": "0.5.0",
3
+ "version": "0.5.1",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -68,6 +68,7 @@ export interface RemoteControlHandle {
68
68
  openUrl: (url: string) => void;
69
69
  sendKeyEvent: (event: ImperativeKeyboardEvent) => void;
70
70
  screenshot: () => Promise<ScreenshotData>;
71
+ terminateApp: (bundleId: string) => Promise<void>;
71
72
  }
72
73
 
73
74
  const debugLog = (...args: any[]) => {
@@ -193,6 +194,8 @@ export const RemoteControl = forwardRef<RemoteControlHandle, RemoteControlProps>
193
194
  Map<string, (value: ScreenshotData | PromiseLike<ScreenshotData>) => void>
194
195
  >(new Map());
195
196
  const pendingScreenshotRejectersRef = useRef<Map<string, (reason?: any) => void>>(new Map());
197
+ const pendingTerminateAppResolversRef = useRef<Map<string, () => void>>(new Map());
198
+ const pendingTerminateAppRejectersRef = useRef<Map<string, (reason?: any) => void>>(new Map());
196
199
 
197
200
  // Map to track active pointers for real touch/mouse single-finger events.
198
201
  // Key: pointerId (-1 for mouse, touch.identifier for touch), Value: { x: number, y: number }
@@ -1273,6 +1276,33 @@ export const RemoteControl = forwardRef<RemoteControlHandle, RemoteControlProps>
1273
1276
  pendingScreenshotResolversRef.current.delete(message.id);
1274
1277
  pendingScreenshotRejectersRef.current.delete(message.id);
1275
1278
  break;
1279
+ case 'terminateAppResult':
1280
+ if (typeof message.id !== 'string') {
1281
+ debugWarn('Received invalid terminateApp result message:', message);
1282
+ break;
1283
+ }
1284
+ if (typeof message.error === 'string') {
1285
+ const terminateRejecter = pendingTerminateAppRejectersRef.current.get(message.id);
1286
+ if (!terminateRejecter) {
1287
+ debugWarn(`Received terminateApp error for unknown or handled id: ${message.id}`);
1288
+ break;
1289
+ }
1290
+ debugWarn(`Received terminateApp error for id ${message.id}: ${message.error}`);
1291
+ terminateRejecter(new Error(message.error));
1292
+ pendingTerminateAppResolversRef.current.delete(message.id);
1293
+ pendingTerminateAppRejectersRef.current.delete(message.id);
1294
+ break;
1295
+ }
1296
+ const terminateResolver = pendingTerminateAppResolversRef.current.get(message.id);
1297
+ if (!terminateResolver) {
1298
+ debugWarn(`Received terminateApp result for unknown or handled id: ${message.id}`);
1299
+ break;
1300
+ }
1301
+ debugLog(`Received terminateApp success for id ${message.id}`);
1302
+ terminateResolver();
1303
+ pendingTerminateAppResolversRef.current.delete(message.id);
1304
+ pendingTerminateAppRejectersRef.current.delete(message.id);
1305
+ break;
1276
1306
  default:
1277
1307
  debugWarn(`Received unhandled message type: ${message.type}`, message);
1278
1308
  break;
@@ -1518,6 +1548,43 @@ export const RemoteControl = forwardRef<RemoteControlHandle, RemoteControlProps>
1518
1548
  }, 30000); // 30-second timeout
1519
1549
  });
1520
1550
  },
1551
+ terminateApp: (bundleId: string): Promise<void> => {
1552
+ return new Promise<void>((resolve, reject) => {
1553
+ if (!wsRef.current || wsRef.current.readyState !== WebSocket.OPEN) {
1554
+ debugWarn('WebSocket not open, cannot send terminateApp command.');
1555
+ return reject(new Error('WebSocket is not connected or connection is not open.'));
1556
+ }
1557
+ const id = `ui-term-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;
1558
+ const request = {
1559
+ type: 'terminateApp',
1560
+ id,
1561
+ bundleId,
1562
+ };
1563
+
1564
+ pendingTerminateAppResolversRef.current.set(id, resolve);
1565
+ pendingTerminateAppRejectersRef.current.set(id, reject);
1566
+
1567
+ debugLog('Sending terminateApp request:', request);
1568
+ try {
1569
+ wsRef.current.send(JSON.stringify(request));
1570
+ } catch (err) {
1571
+ debugWarn('Failed to send terminateApp request immediately:', err);
1572
+ pendingTerminateAppResolversRef.current.delete(id);
1573
+ pendingTerminateAppRejectersRef.current.delete(id);
1574
+ reject(err);
1575
+ return;
1576
+ }
1577
+
1578
+ setTimeout(() => {
1579
+ if (pendingTerminateAppResolversRef.current.has(id)) {
1580
+ debugWarn(`terminateApp request timed out for id ${id}`);
1581
+ pendingTerminateAppRejectersRef.current.get(id)?.(new Error('terminateApp request timed out'));
1582
+ pendingTerminateAppResolversRef.current.delete(id);
1583
+ pendingTerminateAppRejectersRef.current.delete(id);
1584
+ }
1585
+ }, 30000);
1586
+ });
1587
+ },
1521
1588
  }));
1522
1589
 
1523
1590
  // Show indicators when Alt is held and we have a valid hover point (null when outside)
package/src/index.ts CHANGED
@@ -1 +1,2 @@
1
1
  export { RemoteControl } from './components/remote-control';
2
+ export type { RemoteControlHandle } from './components/remote-control';