@midscene/android-playground 1.7.5-beta-20260421061704.0 → 1.7.5

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/dist/es/bin.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  import node_path from "node:path";
2
2
  import { createScrcpyPreviewDescriptor, definePlaygroundPlatform, launchPreparedPlaygroundPlatform } from "@midscene/playground";
3
3
  import { AndroidAgent, AndroidDevice, getConnectedDevicesWithDetails } from "@midscene/android";
4
- import { PLAYGROUND_SERVER_PORT, SCRCPY_PREVIEW_METADATA_TIMEOUT_MS, SCRCPY_PUSH_TIMEOUT_MS, SCRCPY_SERVER_PORT, SCRCPY_START_TIMEOUT_MS, SCRCPY_VIDEO_STREAM_TIMEOUT_MS } from "@midscene/shared/constants";
4
+ import { PLAYGROUND_SERVER_PORT, SCRCPY_ADB_CONNECT_TIMEOUT_MS, SCRCPY_PREVIEW_METADATA_TIMEOUT_MS, SCRCPY_PUSH_TIMEOUT_MS, SCRCPY_SERVER_PORT, SCRCPY_START_TIMEOUT_MS, SCRCPY_VIDEO_STREAM_TIMEOUT_MS } from "@midscene/shared/constants";
5
5
  import { findAvailablePort } from "@midscene/shared/node";
6
6
  import { exec } from "node:child_process";
7
7
  import { createReadStream } from "node:fs";
@@ -219,6 +219,10 @@ function isAllowedOrigin(origin) {
219
219
  return false;
220
220
  }
221
221
  }
222
+ function resolveRequestedDeviceId(options, currentDeviceId) {
223
+ const requestedDeviceId = 'string' == typeof options?.deviceId ? options.deviceId.trim() : '';
224
+ return requestedDeviceId || currentDeviceId || void 0;
225
+ }
222
226
  class ScrcpyServer {
223
227
  setupApiRoutes() {
224
228
  this.app.get('/api/devices', async (req, res)=>{
@@ -273,7 +277,7 @@ class ScrcpyServer {
273
277
  try {
274
278
  if (this.adbClient) debugPage('use existing adb client');
275
279
  else {
276
- await promiseExec('adb start-server');
280
+ await withTimeout(promiseExec('adb start-server'), SCRCPY_ADB_CONNECT_TIMEOUT_MS, `Timed out starting adb server after ${Math.round(SCRCPY_ADB_CONNECT_TIMEOUT_MS / 1000)}s`);
277
281
  debugPage('adb server started');
278
282
  debugPage('initialize adb client');
279
283
  this.adbClient = new AdbServerClient(new AdbServerNodeTcpConnector({
@@ -292,21 +296,21 @@ class ScrcpyServer {
292
296
  const { Adb } = await import("@yume-chan/adb");
293
297
  try {
294
298
  const client = await this.getAdbClient();
295
- if (!client) return null;
299
+ if (!client) throw new Error('Failed to initialize ADB client');
296
300
  const targetDeviceId = deviceId || this.currentDeviceId;
297
301
  if (targetDeviceId) {
298
302
  this.currentDeviceId = targetDeviceId;
299
- return new Adb(await client.createTransport({
303
+ return new Adb(await withTimeout(client.createTransport({
300
304
  serial: targetDeviceId
301
- }));
305
+ }), SCRCPY_ADB_CONNECT_TIMEOUT_MS, `Timed out connecting to Android device ${targetDeviceId} via ADB after ${Math.round(SCRCPY_ADB_CONNECT_TIMEOUT_MS / 1000)}s`));
302
306
  }
303
- const devices = await client.getDevices();
307
+ const devices = await withTimeout(client.getDevices(), SCRCPY_ADB_CONNECT_TIMEOUT_MS, `Timed out listing Android devices via ADB after ${Math.round(SCRCPY_ADB_CONNECT_TIMEOUT_MS / 1000)}s`);
304
308
  if (0 === devices.length) return null;
305
309
  this.currentDeviceId = devices[0].serial;
306
- return new Adb(await client.createTransport(devices[0]));
310
+ return new Adb(await withTimeout(client.createTransport(devices[0]), SCRCPY_ADB_CONNECT_TIMEOUT_MS, `Timed out connecting to Android device ${devices[0].serial} via ADB after ${Math.round(SCRCPY_ADB_CONNECT_TIMEOUT_MS / 1000)}s`));
307
311
  } catch (error) {
308
312
  console.error('failed to get adb client:', error);
309
- return null;
313
+ throw error;
310
314
  }
311
315
  }
312
316
  async startScrcpy(adb, options = {}, onProgress) {
@@ -366,7 +370,6 @@ class ScrcpyServer {
366
370
  });
367
371
  }
368
372
  };
369
- await sendDevicesList();
370
373
  socket.on('get-devices', async ()=>{
371
374
  debugPage('received client request to get devices list');
372
375
  await sendDevicesList();
@@ -394,12 +397,14 @@ class ScrcpyServer {
394
397
  });
395
398
  }
396
399
  });
397
- socket.on('connect-device', async (options)=>{
400
+ socket.on('connect-device', async (options = {})=>{
398
401
  const { ScrcpyVideoCodecId } = await import("@yume-chan/scrcpy");
399
402
  try {
400
403
  debugPage('received device connection request, options: %s, client id: %s', options, socket.id);
401
404
  emitPreviewStatus('connecting-device');
402
- adb = await this.getAdb(this.currentDeviceId || void 0);
405
+ const requestedDeviceId = resolveRequestedDeviceId(options, this.currentDeviceId);
406
+ if (requestedDeviceId) this.currentDeviceId = requestedDeviceId;
407
+ adb = await this.getAdb(requestedDeviceId);
403
408
  if (!adb) {
404
409
  console.error('no available device found');
405
410
  socket.emit('error', {
@@ -506,6 +511,7 @@ class ScrcpyServer {
506
511
  scrcpyClient = null;
507
512
  }
508
513
  });
514
+ sendDevicesList();
509
515
  });
510
516
  }
511
517
  async launch(port) {
package/dist/es/index.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  import node_path from "node:path";
2
2
  import { AndroidAgent, AndroidDevice, getConnectedDevicesWithDetails } from "@midscene/android";
3
3
  import { createScrcpyPreviewDescriptor, definePlaygroundPlatform } from "@midscene/playground";
4
- import { PLAYGROUND_SERVER_PORT, SCRCPY_PREVIEW_METADATA_TIMEOUT_MS, SCRCPY_PUSH_TIMEOUT_MS, SCRCPY_SERVER_PORT, SCRCPY_START_TIMEOUT_MS, SCRCPY_VIDEO_STREAM_TIMEOUT_MS } from "@midscene/shared/constants";
4
+ import { PLAYGROUND_SERVER_PORT, SCRCPY_ADB_CONNECT_TIMEOUT_MS, SCRCPY_PREVIEW_METADATA_TIMEOUT_MS, SCRCPY_PUSH_TIMEOUT_MS, SCRCPY_SERVER_PORT, SCRCPY_START_TIMEOUT_MS, SCRCPY_VIDEO_STREAM_TIMEOUT_MS } from "@midscene/shared/constants";
5
5
  import { findAvailablePort } from "@midscene/shared/node";
6
6
  import { exec } from "node:child_process";
7
7
  import { createReadStream } from "node:fs";
@@ -219,6 +219,10 @@ function isAllowedOrigin(origin) {
219
219
  return false;
220
220
  }
221
221
  }
222
+ function resolveRequestedDeviceId(options, currentDeviceId) {
223
+ const requestedDeviceId = 'string' == typeof options?.deviceId ? options.deviceId.trim() : '';
224
+ return requestedDeviceId || currentDeviceId || void 0;
225
+ }
222
226
  class ScrcpyServer {
223
227
  setupApiRoutes() {
224
228
  this.app.get('/api/devices', async (req, res)=>{
@@ -273,7 +277,7 @@ class ScrcpyServer {
273
277
  try {
274
278
  if (this.adbClient) debugPage('use existing adb client');
275
279
  else {
276
- await promiseExec('adb start-server');
280
+ await withTimeout(promiseExec('adb start-server'), SCRCPY_ADB_CONNECT_TIMEOUT_MS, `Timed out starting adb server after ${Math.round(SCRCPY_ADB_CONNECT_TIMEOUT_MS / 1000)}s`);
277
281
  debugPage('adb server started');
278
282
  debugPage('initialize adb client');
279
283
  this.adbClient = new AdbServerClient(new AdbServerNodeTcpConnector({
@@ -292,21 +296,21 @@ class ScrcpyServer {
292
296
  const { Adb } = await import("@yume-chan/adb");
293
297
  try {
294
298
  const client = await this.getAdbClient();
295
- if (!client) return null;
299
+ if (!client) throw new Error('Failed to initialize ADB client');
296
300
  const targetDeviceId = deviceId || this.currentDeviceId;
297
301
  if (targetDeviceId) {
298
302
  this.currentDeviceId = targetDeviceId;
299
- return new Adb(await client.createTransport({
303
+ return new Adb(await withTimeout(client.createTransport({
300
304
  serial: targetDeviceId
301
- }));
305
+ }), SCRCPY_ADB_CONNECT_TIMEOUT_MS, `Timed out connecting to Android device ${targetDeviceId} via ADB after ${Math.round(SCRCPY_ADB_CONNECT_TIMEOUT_MS / 1000)}s`));
302
306
  }
303
- const devices = await client.getDevices();
307
+ const devices = await withTimeout(client.getDevices(), SCRCPY_ADB_CONNECT_TIMEOUT_MS, `Timed out listing Android devices via ADB after ${Math.round(SCRCPY_ADB_CONNECT_TIMEOUT_MS / 1000)}s`);
304
308
  if (0 === devices.length) return null;
305
309
  this.currentDeviceId = devices[0].serial;
306
- return new Adb(await client.createTransport(devices[0]));
310
+ return new Adb(await withTimeout(client.createTransport(devices[0]), SCRCPY_ADB_CONNECT_TIMEOUT_MS, `Timed out connecting to Android device ${devices[0].serial} via ADB after ${Math.round(SCRCPY_ADB_CONNECT_TIMEOUT_MS / 1000)}s`));
307
311
  } catch (error) {
308
312
  console.error('failed to get adb client:', error);
309
- return null;
313
+ throw error;
310
314
  }
311
315
  }
312
316
  async startScrcpy(adb, options = {}, onProgress) {
@@ -366,7 +370,6 @@ class ScrcpyServer {
366
370
  });
367
371
  }
368
372
  };
369
- await sendDevicesList();
370
373
  socket.on('get-devices', async ()=>{
371
374
  debugPage('received client request to get devices list');
372
375
  await sendDevicesList();
@@ -394,12 +397,14 @@ class ScrcpyServer {
394
397
  });
395
398
  }
396
399
  });
397
- socket.on('connect-device', async (options)=>{
400
+ socket.on('connect-device', async (options = {})=>{
398
401
  const { ScrcpyVideoCodecId } = await import("@yume-chan/scrcpy");
399
402
  try {
400
403
  debugPage('received device connection request, options: %s, client id: %s', options, socket.id);
401
404
  emitPreviewStatus('connecting-device');
402
- adb = await this.getAdb(this.currentDeviceId || void 0);
405
+ const requestedDeviceId = resolveRequestedDeviceId(options, this.currentDeviceId);
406
+ if (requestedDeviceId) this.currentDeviceId = requestedDeviceId;
407
+ adb = await this.getAdb(requestedDeviceId);
403
408
  if (!adb) {
404
409
  console.error('no available device found');
405
410
  socket.emit('error', {
@@ -506,6 +511,7 @@ class ScrcpyServer {
506
511
  scrcpyClient = null;
507
512
  }
508
513
  });
514
+ sendDevicesList();
509
515
  });
510
516
  }
511
517
  async launch(port) {
package/dist/lib/bin.js CHANGED
@@ -245,6 +245,10 @@ function isAllowedOrigin(origin) {
245
245
  return false;
246
246
  }
247
247
  }
248
+ function resolveRequestedDeviceId(options, currentDeviceId) {
249
+ const requestedDeviceId = 'string' == typeof options?.deviceId ? options.deviceId.trim() : '';
250
+ return requestedDeviceId || currentDeviceId || void 0;
251
+ }
248
252
  class ScrcpyServer {
249
253
  setupApiRoutes() {
250
254
  this.app.get('/api/devices', async (req, res)=>{
@@ -299,7 +303,7 @@ class ScrcpyServer {
299
303
  try {
300
304
  if (this.adbClient) debugPage('use existing adb client');
301
305
  else {
302
- await promiseExec('adb start-server');
306
+ await withTimeout(promiseExec('adb start-server'), constants_namespaceObject.SCRCPY_ADB_CONNECT_TIMEOUT_MS, `Timed out starting adb server after ${Math.round(constants_namespaceObject.SCRCPY_ADB_CONNECT_TIMEOUT_MS / 1000)}s`);
303
307
  debugPage('adb server started');
304
308
  debugPage('initialize adb client');
305
309
  this.adbClient = new AdbServerClient(new AdbServerNodeTcpConnector({
@@ -318,21 +322,21 @@ class ScrcpyServer {
318
322
  const { Adb } = await import("@yume-chan/adb");
319
323
  try {
320
324
  const client = await this.getAdbClient();
321
- if (!client) return null;
325
+ if (!client) throw new Error('Failed to initialize ADB client');
322
326
  const targetDeviceId = deviceId || this.currentDeviceId;
323
327
  if (targetDeviceId) {
324
328
  this.currentDeviceId = targetDeviceId;
325
- return new Adb(await client.createTransport({
329
+ return new Adb(await withTimeout(client.createTransport({
326
330
  serial: targetDeviceId
327
- }));
331
+ }), constants_namespaceObject.SCRCPY_ADB_CONNECT_TIMEOUT_MS, `Timed out connecting to Android device ${targetDeviceId} via ADB after ${Math.round(constants_namespaceObject.SCRCPY_ADB_CONNECT_TIMEOUT_MS / 1000)}s`));
328
332
  }
329
- const devices = await client.getDevices();
333
+ const devices = await withTimeout(client.getDevices(), constants_namespaceObject.SCRCPY_ADB_CONNECT_TIMEOUT_MS, `Timed out listing Android devices via ADB after ${Math.round(constants_namespaceObject.SCRCPY_ADB_CONNECT_TIMEOUT_MS / 1000)}s`);
330
334
  if (0 === devices.length) return null;
331
335
  this.currentDeviceId = devices[0].serial;
332
- return new Adb(await client.createTransport(devices[0]));
336
+ return new Adb(await withTimeout(client.createTransport(devices[0]), constants_namespaceObject.SCRCPY_ADB_CONNECT_TIMEOUT_MS, `Timed out connecting to Android device ${devices[0].serial} via ADB after ${Math.round(constants_namespaceObject.SCRCPY_ADB_CONNECT_TIMEOUT_MS / 1000)}s`));
333
337
  } catch (error) {
334
338
  console.error('failed to get adb client:', error);
335
- return null;
339
+ throw error;
336
340
  }
337
341
  }
338
342
  async startScrcpy(adb, options = {}, onProgress) {
@@ -392,7 +396,6 @@ class ScrcpyServer {
392
396
  });
393
397
  }
394
398
  };
395
- await sendDevicesList();
396
399
  socket.on('get-devices', async ()=>{
397
400
  debugPage('received client request to get devices list');
398
401
  await sendDevicesList();
@@ -420,12 +423,14 @@ class ScrcpyServer {
420
423
  });
421
424
  }
422
425
  });
423
- socket.on('connect-device', async (options)=>{
426
+ socket.on('connect-device', async (options = {})=>{
424
427
  const { ScrcpyVideoCodecId } = await import("@yume-chan/scrcpy");
425
428
  try {
426
429
  debugPage('received device connection request, options: %s, client id: %s', options, socket.id);
427
430
  emitPreviewStatus('connecting-device');
428
- adb = await this.getAdb(this.currentDeviceId || void 0);
431
+ const requestedDeviceId = resolveRequestedDeviceId(options, this.currentDeviceId);
432
+ if (requestedDeviceId) this.currentDeviceId = requestedDeviceId;
433
+ adb = await this.getAdb(requestedDeviceId);
429
434
  if (!adb) {
430
435
  console.error('no available device found');
431
436
  socket.emit('error', {
@@ -532,6 +537,7 @@ class ScrcpyServer {
532
537
  scrcpyClient = null;
533
538
  }
534
539
  });
540
+ sendDevicesList();
535
541
  });
536
542
  }
537
543
  async launch(port) {
package/dist/lib/index.js CHANGED
@@ -260,6 +260,10 @@ function isAllowedOrigin(origin) {
260
260
  return false;
261
261
  }
262
262
  }
263
+ function resolveRequestedDeviceId(options, currentDeviceId) {
264
+ const requestedDeviceId = 'string' == typeof options?.deviceId ? options.deviceId.trim() : '';
265
+ return requestedDeviceId || currentDeviceId || void 0;
266
+ }
263
267
  class ScrcpyServer {
264
268
  setupApiRoutes() {
265
269
  this.app.get('/api/devices', async (req, res)=>{
@@ -314,7 +318,7 @@ class ScrcpyServer {
314
318
  try {
315
319
  if (this.adbClient) debugPage('use existing adb client');
316
320
  else {
317
- await promiseExec('adb start-server');
321
+ await withTimeout(promiseExec('adb start-server'), constants_namespaceObject.SCRCPY_ADB_CONNECT_TIMEOUT_MS, `Timed out starting adb server after ${Math.round(constants_namespaceObject.SCRCPY_ADB_CONNECT_TIMEOUT_MS / 1000)}s`);
318
322
  debugPage('adb server started');
319
323
  debugPage('initialize adb client');
320
324
  this.adbClient = new AdbServerClient(new AdbServerNodeTcpConnector({
@@ -333,21 +337,21 @@ class ScrcpyServer {
333
337
  const { Adb } = await import("@yume-chan/adb");
334
338
  try {
335
339
  const client = await this.getAdbClient();
336
- if (!client) return null;
340
+ if (!client) throw new Error('Failed to initialize ADB client');
337
341
  const targetDeviceId = deviceId || this.currentDeviceId;
338
342
  if (targetDeviceId) {
339
343
  this.currentDeviceId = targetDeviceId;
340
- return new Adb(await client.createTransport({
344
+ return new Adb(await withTimeout(client.createTransport({
341
345
  serial: targetDeviceId
342
- }));
346
+ }), constants_namespaceObject.SCRCPY_ADB_CONNECT_TIMEOUT_MS, `Timed out connecting to Android device ${targetDeviceId} via ADB after ${Math.round(constants_namespaceObject.SCRCPY_ADB_CONNECT_TIMEOUT_MS / 1000)}s`));
343
347
  }
344
- const devices = await client.getDevices();
348
+ const devices = await withTimeout(client.getDevices(), constants_namespaceObject.SCRCPY_ADB_CONNECT_TIMEOUT_MS, `Timed out listing Android devices via ADB after ${Math.round(constants_namespaceObject.SCRCPY_ADB_CONNECT_TIMEOUT_MS / 1000)}s`);
345
349
  if (0 === devices.length) return null;
346
350
  this.currentDeviceId = devices[0].serial;
347
- return new Adb(await client.createTransport(devices[0]));
351
+ return new Adb(await withTimeout(client.createTransport(devices[0]), constants_namespaceObject.SCRCPY_ADB_CONNECT_TIMEOUT_MS, `Timed out connecting to Android device ${devices[0].serial} via ADB after ${Math.round(constants_namespaceObject.SCRCPY_ADB_CONNECT_TIMEOUT_MS / 1000)}s`));
348
352
  } catch (error) {
349
353
  console.error('failed to get adb client:', error);
350
- return null;
354
+ throw error;
351
355
  }
352
356
  }
353
357
  async startScrcpy(adb, options = {}, onProgress) {
@@ -407,7 +411,6 @@ class ScrcpyServer {
407
411
  });
408
412
  }
409
413
  };
410
- await sendDevicesList();
411
414
  socket.on('get-devices', async ()=>{
412
415
  debugPage('received client request to get devices list');
413
416
  await sendDevicesList();
@@ -435,12 +438,14 @@ class ScrcpyServer {
435
438
  });
436
439
  }
437
440
  });
438
- socket.on('connect-device', async (options)=>{
441
+ socket.on('connect-device', async (options = {})=>{
439
442
  const { ScrcpyVideoCodecId } = await import("@yume-chan/scrcpy");
440
443
  try {
441
444
  debugPage('received device connection request, options: %s, client id: %s', options, socket.id);
442
445
  emitPreviewStatus('connecting-device');
443
- adb = await this.getAdb(this.currentDeviceId || void 0);
446
+ const requestedDeviceId = resolveRequestedDeviceId(options, this.currentDeviceId);
447
+ if (requestedDeviceId) this.currentDeviceId = requestedDeviceId;
448
+ adb = await this.getAdb(requestedDeviceId);
444
449
  if (!adb) {
445
450
  console.error('no available device found');
446
451
  socket.emit('error', {
@@ -547,6 +552,7 @@ class ScrcpyServer {
547
552
  scrcpyClient = null;
548
553
  }
549
554
  });
555
+ sendDevicesList();
550
556
  });
551
557
  }
552
558
  async launch(port) {
@@ -3,6 +3,11 @@ import type { AdbServerClient } from '@yume-chan/adb';
3
3
  import express from 'express';
4
4
  import { Server } from 'socket.io';
5
5
  export declare const debugPage: import("@midscene/shared/logger").DebugFunction;
6
+ export interface ScrcpyConnectDeviceRequest {
7
+ deviceId?: string;
8
+ maxSize?: number;
9
+ }
10
+ export declare function resolveRequestedDeviceId(options: ScrcpyConnectDeviceRequest | undefined, currentDeviceId: string | null): string | undefined;
6
11
  export default class ScrcpyServer {
7
12
  app: express.Application;
8
13
  httpServer: HttpServer;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@midscene/android-playground",
3
- "version": "1.7.5-beta-20260421061704.0",
3
+ "version": "1.7.5",
4
4
  "description": "Android playground for Midscene",
5
5
  "main": "./dist/lib/index.js",
6
6
  "types": "./dist/types/index.d.ts",
@@ -34,10 +34,10 @@
34
34
  "express": "^4.21.2",
35
35
  "open": "10.1.0",
36
36
  "socket.io": "^4.8.1",
37
- "@midscene/playground": "1.7.5-beta-20260421061704.0",
38
- "@midscene/shared": "1.7.5-beta-20260421061704.0",
39
- "@midscene/core": "1.7.5-beta-20260421061704.0",
40
- "@midscene/android": "1.7.5-beta-20260421061704.0"
37
+ "@midscene/android": "1.7.5",
38
+ "@midscene/core": "1.7.5",
39
+ "@midscene/playground": "1.7.5",
40
+ "@midscene/shared": "1.7.5"
41
41
  },
42
42
  "devDependencies": {
43
43
  "@rslib/core": "^0.18.3",
package/static/index.html CHANGED
@@ -1 +1 @@
1
- <!doctype html><html><head><title>Midscene Android Playground</title><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><script defer src="/static/js/lib-react.ed140d90.js"></script><script defer src="/static/js/883.91ca0de7.js"></script><script defer src="/static/js/index.827bfdbe.js"></script><link href="/static/css/index.dc500f18.css" rel="stylesheet"></head><body><div id="root"></div></body></html>
1
+ <!doctype html><html><head><title>Midscene Android Playground</title><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><script defer src="/static/js/lib-react.ed140d90.js"></script><script defer src="/static/js/883.91ca0de7.js"></script><script defer src="/static/js/index.860ebe39.js"></script><link href="/static/css/index.dc500f18.css" rel="stylesheet"></head><body><div id="root"></div></body></html>