@arenahito/droid-webscr 0.1.0 → 0.2.0
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/README.md +7 -7
- package/dist/bin.d.ts +5 -17
- package/dist/bin.js +258 -139
- package/dist/bin.js.map +1 -1
- package/package.json +8 -15
- package/web/assets/disconnected-phone-WRg-ns9U.png +0 -0
- package/web/assets/index-B3WqGQL0.js +10 -0
- package/web/assets/index-CxnoJHDV.css +2 -0
- package/web/index.html +13 -0
- package/dist/index.d.ts +0 -43
- package/dist/index.js +0 -15699
- package/dist/index.js.map +0 -1
- package/dist/main.d.ts +0 -22
- package/dist/main.js +0 -16208
- package/dist/main.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# droid-webscr
|
|
2
2
|
|
|
3
|
-
droid-webscr is a local Android screen streaming and control tool. It runs a
|
|
4
|
-
Node.js
|
|
5
|
-
and
|
|
3
|
+
droid-webscr is a local Android screen streaming and control tool. It runs a local
|
|
4
|
+
Node.js server on your machine, pushes a temporary Android-side server through ADB,
|
|
5
|
+
and serves a browser UI for viewing and controlling an authorized Android device.
|
|
6
6
|
|
|
7
7
|
The project is under active development. Expect CLI and protocol details to keep
|
|
8
8
|
moving until the first stable release.
|
|
@@ -44,21 +44,21 @@ droid-webscr
|
|
|
44
44
|
|
|
45
45
|
## Usage
|
|
46
46
|
|
|
47
|
-
Start the local
|
|
47
|
+
Start the local server and web UI:
|
|
48
48
|
|
|
49
49
|
```sh
|
|
50
50
|
droid-webscr
|
|
51
51
|
```
|
|
52
52
|
|
|
53
|
-
By default the
|
|
53
|
+
By default the integrated server listens on:
|
|
54
54
|
|
|
55
55
|
```text
|
|
56
56
|
http://127.0.0.1:7391
|
|
57
57
|
```
|
|
58
58
|
|
|
59
|
-
Open the
|
|
59
|
+
Open the printed URL, select an authorized device, and start a session. The session
|
|
60
60
|
streams the Android display into the browser and sends control frames back to the
|
|
61
|
-
device through the local
|
|
61
|
+
device through the local server.
|
|
62
62
|
|
|
63
63
|
The UI supports:
|
|
64
64
|
|
package/dist/bin.d.ts
CHANGED
|
@@ -1,19 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
declare function startPackagedRuntime(): Promise<{
|
|
3
|
+
close: () => Promise<void>;
|
|
4
|
+
readonly url: string;
|
|
5
|
+
}>;
|
|
5
6
|
|
|
6
|
-
|
|
7
|
-
stderr(value: string): void;
|
|
8
|
-
stdout(value: string): void;
|
|
9
|
-
}
|
|
10
|
-
interface CliRuntime {
|
|
11
|
-
readonly packageVersion?: string | undefined;
|
|
12
|
-
readonly startAgent?: (() => Promise<AgentRuntime>) | undefined;
|
|
13
|
-
readonly stderr?: ((value: string) => void) | undefined;
|
|
14
|
-
readonly stdout?: ((value: string) => void) | undefined;
|
|
15
|
-
}
|
|
16
|
-
declare function runCli(argv: readonly string[], runtime?: CliRuntime): Promise<number>;
|
|
17
|
-
declare function createCliHelp(): string;
|
|
18
|
-
|
|
19
|
-
export { type CliIo, type CliRuntime, createCliHelp, runCli };
|
|
7
|
+
export { startPackagedRuntime };
|
package/dist/bin.js
CHANGED
|
@@ -5,56 +5,64 @@ var __export = (target, all) => {
|
|
|
5
5
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
6
6
|
};
|
|
7
7
|
|
|
8
|
-
//
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
"
|
|
26
|
-
"
|
|
27
|
-
]
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
8
|
+
// src/bin.ts
|
|
9
|
+
import { dirname as dirname2 } from "path";
|
|
10
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
11
|
+
|
|
12
|
+
// ../agent/src/device-server/artifact.ts
|
|
13
|
+
import { access } from "fs/promises";
|
|
14
|
+
import { constants } from "fs";
|
|
15
|
+
import { dirname, join } from "path";
|
|
16
|
+
import { fileURLToPath } from "url";
|
|
17
|
+
var deviceServerArtifactFileName = "droid-webscr-server-android.jar";
|
|
18
|
+
var deviceServerArtifactRemotePath = "/data/local/tmp/droid-webscr-server.jar";
|
|
19
|
+
var defaultDeviceServerArtifact = {
|
|
20
|
+
localPath: `android/server/build/${deviceServerArtifactFileName}`,
|
|
21
|
+
remotePath: deviceServerArtifactRemotePath
|
|
22
|
+
};
|
|
23
|
+
async function resolveDeviceServerArtifact(moduleUrl = import.meta.url, startDirectory = dirname(fileURLToPath(moduleUrl))) {
|
|
24
|
+
const candidates = ancestorDirectories(startDirectory).flatMap((directory) => [
|
|
25
|
+
join(directory, "android", deviceServerArtifactFileName),
|
|
26
|
+
join(directory, "android", "server", "build", deviceServerArtifactFileName)
|
|
27
|
+
]);
|
|
28
|
+
const checks = await Promise.all(
|
|
29
|
+
candidates.map(async (candidate) => ({
|
|
30
|
+
candidate,
|
|
31
|
+
exists: await isReadableFile(candidate)
|
|
32
|
+
}))
|
|
33
|
+
);
|
|
34
|
+
for (const check2 of checks) {
|
|
35
|
+
if (check2.exists) {
|
|
36
|
+
return {
|
|
37
|
+
localPath: check2.candidate,
|
|
38
|
+
remotePath: deviceServerArtifactRemotePath
|
|
39
|
+
};
|
|
33
40
|
}
|
|
34
|
-
},
|
|
35
|
-
publishConfig: {
|
|
36
|
-
access: "public"
|
|
37
|
-
},
|
|
38
|
-
scripts: {
|
|
39
|
-
build: "tsup && node ../../tools/package-agent.mjs",
|
|
40
|
-
dev: "tsc -p tsconfig.build.json --watch",
|
|
41
|
-
lint: "oxlint --config ../../oxlint.json src",
|
|
42
|
-
test: "vitest run",
|
|
43
|
-
"type-check": "tsc -p tsconfig.json --noEmit"
|
|
44
|
-
},
|
|
45
|
-
dependencies: {
|
|
46
|
-
"@fastify/websocket": "11.2.0",
|
|
47
|
-
fastify: "5.8.5",
|
|
48
|
-
pino: "10.3.1"
|
|
49
|
-
},
|
|
50
|
-
devDependencies: {
|
|
51
|
-
"@droid-webscr/adb": "workspace:*",
|
|
52
|
-
"@droid-webscr/config": "workspace:*",
|
|
53
|
-
"@droid-webscr/protocol": "workspace:*",
|
|
54
|
-
"@droid-webscr/transport": "workspace:*",
|
|
55
|
-
"@types/ws": "8.18.1"
|
|
56
41
|
}
|
|
57
|
-
|
|
42
|
+
throw new Error(
|
|
43
|
+
`Android server artifact was not found. Run pnpm android:build before starting droid-webscr.`
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
function ancestorDirectories(startDirectory) {
|
|
47
|
+
const directories = [];
|
|
48
|
+
let current = startDirectory;
|
|
49
|
+
while (true) {
|
|
50
|
+
directories.push(current);
|
|
51
|
+
const parent = dirname(current);
|
|
52
|
+
if (parent === current) {
|
|
53
|
+
return directories;
|
|
54
|
+
}
|
|
55
|
+
current = parent;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
async function isReadableFile(path) {
|
|
59
|
+
try {
|
|
60
|
+
await access(path, constants.R_OK);
|
|
61
|
+
return true;
|
|
62
|
+
} catch {
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
58
66
|
|
|
59
67
|
// ../../packages/adb/src/provider.ts
|
|
60
68
|
import { Readable } from "stream";
|
|
@@ -14976,70 +14984,15 @@ function isLocalBind(host) {
|
|
|
14976
14984
|
return host === "127.0.0.1" || host === "localhost" || host === "::1";
|
|
14977
14985
|
}
|
|
14978
14986
|
|
|
14979
|
-
// src/runtime.ts
|
|
14987
|
+
// ../agent/src/runtime.ts
|
|
14980
14988
|
import { pathToFileURL } from "url";
|
|
14981
14989
|
|
|
14982
|
-
// src/device-server/
|
|
14983
|
-
import { access } from "fs/promises";
|
|
14984
|
-
import { constants } from "fs";
|
|
14985
|
-
import { dirname, join } from "path";
|
|
14986
|
-
import { fileURLToPath } from "url";
|
|
14987
|
-
var deviceServerArtifactFileName = "droid-webscr-server-android.jar";
|
|
14988
|
-
var deviceServerArtifactRemotePath = "/data/local/tmp/droid-webscr-server.jar";
|
|
14989
|
-
var defaultDeviceServerArtifact = {
|
|
14990
|
-
localPath: `android/server/build/${deviceServerArtifactFileName}`,
|
|
14991
|
-
remotePath: deviceServerArtifactRemotePath
|
|
14992
|
-
};
|
|
14993
|
-
async function resolveDeviceServerArtifact(moduleUrl = import.meta.url, startDirectory = dirname(fileURLToPath(moduleUrl))) {
|
|
14994
|
-
const candidates = ancestorDirectories(startDirectory).flatMap((directory) => [
|
|
14995
|
-
join(directory, "android", deviceServerArtifactFileName),
|
|
14996
|
-
join(directory, "android", "server", "build", deviceServerArtifactFileName)
|
|
14997
|
-
]);
|
|
14998
|
-
const checks = await Promise.all(
|
|
14999
|
-
candidates.map(async (candidate) => ({
|
|
15000
|
-
candidate,
|
|
15001
|
-
exists: await isReadableFile(candidate)
|
|
15002
|
-
}))
|
|
15003
|
-
);
|
|
15004
|
-
for (const check2 of checks) {
|
|
15005
|
-
if (check2.exists) {
|
|
15006
|
-
return {
|
|
15007
|
-
localPath: check2.candidate,
|
|
15008
|
-
remotePath: deviceServerArtifactRemotePath
|
|
15009
|
-
};
|
|
15010
|
-
}
|
|
15011
|
-
}
|
|
15012
|
-
throw new Error(
|
|
15013
|
-
`Android server artifact was not found. Run pnpm android:build before starting droid-webscr.`
|
|
15014
|
-
);
|
|
15015
|
-
}
|
|
15016
|
-
function ancestorDirectories(startDirectory) {
|
|
15017
|
-
const directories = [];
|
|
15018
|
-
let current = startDirectory;
|
|
15019
|
-
while (true) {
|
|
15020
|
-
directories.push(current);
|
|
15021
|
-
const parent = dirname(current);
|
|
15022
|
-
if (parent === current) {
|
|
15023
|
-
return directories;
|
|
15024
|
-
}
|
|
15025
|
-
current = parent;
|
|
15026
|
-
}
|
|
15027
|
-
}
|
|
15028
|
-
async function isReadableFile(path) {
|
|
15029
|
-
try {
|
|
15030
|
-
await access(path, constants.R_OK);
|
|
15031
|
-
return true;
|
|
15032
|
-
} catch {
|
|
15033
|
-
return false;
|
|
15034
|
-
}
|
|
15035
|
-
}
|
|
15036
|
-
|
|
15037
|
-
// src/device-server/deploy.ts
|
|
14990
|
+
// ../agent/src/device-server/deploy.ts
|
|
15038
14991
|
async function deployDeviceServer(session, artifact) {
|
|
15039
14992
|
await session.push(artifact.localPath, artifact.remotePath);
|
|
15040
14993
|
}
|
|
15041
14994
|
|
|
15042
|
-
// src/device-server/start.ts
|
|
14995
|
+
// ../agent/src/device-server/start.ts
|
|
15043
14996
|
var AdbDeviceServer = class {
|
|
15044
14997
|
constructor(adbProvider, artifact = defaultDeviceServerArtifact) {
|
|
15045
14998
|
this.adbProvider = adbProvider;
|
|
@@ -15197,8 +15150,9 @@ async function collectTextUntil(chunks, expected) {
|
|
|
15197
15150
|
return output + decoder.decode();
|
|
15198
15151
|
}
|
|
15199
15152
|
|
|
15200
|
-
// src/server/create-fastify-app.ts
|
|
15153
|
+
// ../agent/src/server/create-fastify-app.ts
|
|
15201
15154
|
import websocket from "@fastify/websocket";
|
|
15155
|
+
import middie from "@fastify/middie";
|
|
15202
15156
|
|
|
15203
15157
|
// ../../packages/protocol/src/streams.ts
|
|
15204
15158
|
var StreamId = /* @__PURE__ */ ((StreamId2) => {
|
|
@@ -15404,10 +15358,13 @@ function readPayloadLength(bytes) {
|
|
|
15404
15358
|
// ../../packages/transport/src/backpressure.ts
|
|
15405
15359
|
var VIDEO_KEYFRAME_FLAG = 1 << 0;
|
|
15406
15360
|
|
|
15407
|
-
// src/server/create-fastify-app.ts
|
|
15361
|
+
// ../agent/src/server/create-fastify-app.ts
|
|
15408
15362
|
import Fastify from "fastify";
|
|
15363
|
+
import { constants as constants2 } from "fs";
|
|
15364
|
+
import { access as access2, readFile } from "fs/promises";
|
|
15365
|
+
import { extname, join as join2, normalize, relative, sep } from "path";
|
|
15409
15366
|
|
|
15410
|
-
// src/security/origin.ts
|
|
15367
|
+
// ../agent/src/security/origin.ts
|
|
15411
15368
|
function isAllowedOrigin(origin, config2, requestHost) {
|
|
15412
15369
|
if (!origin) {
|
|
15413
15370
|
return true;
|
|
@@ -15417,9 +15374,6 @@ function isAllowedOrigin(origin, config2, requestHost) {
|
|
|
15417
15374
|
if (url2.protocol !== "http:") {
|
|
15418
15375
|
return false;
|
|
15419
15376
|
}
|
|
15420
|
-
if (requestHost !== void 0 && isLocalDevUiOrigin(url2) && isAllowedHost(requestHost, config2)) {
|
|
15421
|
-
return true;
|
|
15422
|
-
}
|
|
15423
15377
|
if (!isAllowedHost(url2.host, config2)) {
|
|
15424
15378
|
return false;
|
|
15425
15379
|
}
|
|
@@ -15462,9 +15416,6 @@ function isLocalHost(host) {
|
|
|
15462
15416
|
const normalized = normalizeHost(host);
|
|
15463
15417
|
return normalized === "127.0.0.1" || normalized === "localhost" || normalized === "::1";
|
|
15464
15418
|
}
|
|
15465
|
-
function isLocalDevUiOrigin(url2) {
|
|
15466
|
-
return url2.port === "5173" && isLocalHost(url2.host);
|
|
15467
|
-
}
|
|
15468
15419
|
function samePort(url2, host) {
|
|
15469
15420
|
return (url2.port || defaultPort(url2.protocol)) === (extractPort(host) || defaultPort(url2.protocol));
|
|
15470
15421
|
}
|
|
@@ -15483,7 +15434,7 @@ function extractPort(host) {
|
|
|
15483
15434
|
return parts.length === 2 ? parts[1] ?? "" : "";
|
|
15484
15435
|
}
|
|
15485
15436
|
|
|
15486
|
-
// src/security/session-token.ts
|
|
15437
|
+
// ../agent/src/security/session-token.ts
|
|
15487
15438
|
import { randomBytes } from "crypto";
|
|
15488
15439
|
function createSessionToken(sessionId, deviceSerial, nowMs, ttlMs, video) {
|
|
15489
15440
|
return {
|
|
@@ -15495,7 +15446,7 @@ function createSessionToken(sessionId, deviceSerial, nowMs, ttlMs, video) {
|
|
|
15495
15446
|
};
|
|
15496
15447
|
}
|
|
15497
15448
|
|
|
15498
|
-
// src/session/session-manager.ts
|
|
15449
|
+
// ../agent/src/session/session-manager.ts
|
|
15499
15450
|
var SessionManager = class {
|
|
15500
15451
|
constructor(adbProvider, now = () => Date.now(), ttlMs = 6e4) {
|
|
15501
15452
|
this.adbProvider = adbProvider;
|
|
@@ -15581,7 +15532,7 @@ var SessionManager = class {
|
|
|
15581
15532
|
}
|
|
15582
15533
|
};
|
|
15583
15534
|
|
|
15584
|
-
// src/security/auth.ts
|
|
15535
|
+
// ../agent/src/security/auth.ts
|
|
15585
15536
|
function validateAgentAuthHeader(authorization, config2) {
|
|
15586
15537
|
if (!config2.authToken) {
|
|
15587
15538
|
return true;
|
|
@@ -15590,7 +15541,7 @@ function validateAgentAuthHeader(authorization, config2) {
|
|
|
15590
15541
|
return values.some((value) => value === `Bearer ${config2.authToken}`);
|
|
15591
15542
|
}
|
|
15592
15543
|
|
|
15593
|
-
// src/server/routes.ts
|
|
15544
|
+
// ../agent/src/server/routes.ts
|
|
15594
15545
|
var noopUpdateRuntimeConfig = () => {
|
|
15595
15546
|
return;
|
|
15596
15547
|
};
|
|
@@ -15918,10 +15869,10 @@ function createShareUrl(bindHost, port) {
|
|
|
15918
15869
|
return `http://${host}:${port}`;
|
|
15919
15870
|
}
|
|
15920
15871
|
|
|
15921
|
-
// src/server/websocket.ts
|
|
15872
|
+
// ../agent/src/server/websocket.ts
|
|
15922
15873
|
var binaryWebSocketProtocol = "droid-webscr.v1";
|
|
15923
15874
|
|
|
15924
|
-
// src/server/create-fastify-app.ts
|
|
15875
|
+
// ../agent/src/server/create-fastify-app.ts
|
|
15925
15876
|
function createLoggerOptions(enabled) {
|
|
15926
15877
|
return enabled === false ? false : {
|
|
15927
15878
|
level: "info",
|
|
@@ -15936,6 +15887,12 @@ async function createFastifyApp(context) {
|
|
|
15936
15887
|
const app = Fastify({
|
|
15937
15888
|
logger: createLoggerOptions(context.logger)
|
|
15938
15889
|
});
|
|
15890
|
+
if (context.webUi?.devMiddleware) {
|
|
15891
|
+
await app.register(middie);
|
|
15892
|
+
app.use(
|
|
15893
|
+
context.webUi.devMiddleware
|
|
15894
|
+
);
|
|
15895
|
+
}
|
|
15939
15896
|
await app.register(websocket, {
|
|
15940
15897
|
options: {
|
|
15941
15898
|
handleProtocols: selectBinaryWebSocketProtocol
|
|
@@ -15978,6 +15935,7 @@ async function createFastifyApp(context) {
|
|
|
15978
15935
|
app.closeActiveDeviceSessions = closeActiveSessions;
|
|
15979
15936
|
app.addHook("preClose", async () => {
|
|
15980
15937
|
await closeActiveSessions({ waitForStartup: true });
|
|
15938
|
+
await context.webUi?.close?.();
|
|
15981
15939
|
});
|
|
15982
15940
|
app.addHook("onRequest", async (request, reply) => {
|
|
15983
15941
|
const origin = request.headers.origin;
|
|
@@ -16125,6 +16083,7 @@ async function createFastifyApp(context) {
|
|
|
16125
16083
|
});
|
|
16126
16084
|
}
|
|
16127
16085
|
);
|
|
16086
|
+
registerWebUiRoutes(app, context.webUi);
|
|
16128
16087
|
return app;
|
|
16129
16088
|
}
|
|
16130
16089
|
function selectBinaryWebSocketProtocol(protocols) {
|
|
@@ -16140,8 +16099,85 @@ function ignoreAsyncError2() {
|
|
|
16140
16099
|
function closeBrowserSocket(socket, code, reason) {
|
|
16141
16100
|
socket.close?.(code, reason);
|
|
16142
16101
|
}
|
|
16102
|
+
function registerWebUiRoutes(app, webUi) {
|
|
16103
|
+
if (!webUi) {
|
|
16104
|
+
return;
|
|
16105
|
+
}
|
|
16106
|
+
app.get("/*", async (request, reply) => {
|
|
16107
|
+
const path = request.url.split("?")[0] ?? "/";
|
|
16108
|
+
if (path.startsWith("/api/") || path === "/api" || path.startsWith("/ws/") || path === "/ws") {
|
|
16109
|
+
return reply.code(404).send({ error: "Not found" });
|
|
16110
|
+
}
|
|
16111
|
+
const file2 = await readWebUiFile(webUi, path);
|
|
16112
|
+
if (file2) {
|
|
16113
|
+
return reply.type(file2.contentType).send(file2.content);
|
|
16114
|
+
}
|
|
16115
|
+
if (webUi.renderIndex) {
|
|
16116
|
+
return reply.type("text/html; charset=utf-8").send(await webUi.renderIndex(request.url));
|
|
16117
|
+
}
|
|
16118
|
+
const index = await readWebUiFile(webUi, "/");
|
|
16119
|
+
if (index) {
|
|
16120
|
+
return reply.type(index.contentType).send(index.content);
|
|
16121
|
+
}
|
|
16122
|
+
return reply.code(404).send({ error: "Not found" });
|
|
16123
|
+
});
|
|
16124
|
+
}
|
|
16125
|
+
async function readWebUiFile(webUi, path) {
|
|
16126
|
+
const staticFile = webUi.staticFiles?.[path] ?? (path === "/" ? webUi.staticFiles?.["/"] : void 0);
|
|
16127
|
+
if (staticFile) {
|
|
16128
|
+
return staticFile;
|
|
16129
|
+
}
|
|
16130
|
+
if (!webUi.staticRoot) {
|
|
16131
|
+
return void 0;
|
|
16132
|
+
}
|
|
16133
|
+
const filePath = resolveStaticFilePath(webUi.staticRoot, path);
|
|
16134
|
+
if (!filePath || !await isReadableFile2(filePath)) {
|
|
16135
|
+
return void 0;
|
|
16136
|
+
}
|
|
16137
|
+
return {
|
|
16138
|
+
content: await readFile(filePath),
|
|
16139
|
+
contentType: contentTypeForPath(filePath)
|
|
16140
|
+
};
|
|
16141
|
+
}
|
|
16142
|
+
function resolveStaticFilePath(root, path) {
|
|
16143
|
+
const normalizedPath = path === "/" ? "/index.html" : path;
|
|
16144
|
+
const decodedPath = decodeURIComponent(normalizedPath);
|
|
16145
|
+
const relativePath = decodedPath.replace(/^\/+/, "");
|
|
16146
|
+
const resolvedPath = normalize(join2(root, relativePath));
|
|
16147
|
+
const relativeToRoot = relative(root, resolvedPath);
|
|
16148
|
+
if (relativeToRoot.startsWith("..") || relativeToRoot.includes(`..${sep}`)) {
|
|
16149
|
+
return void 0;
|
|
16150
|
+
}
|
|
16151
|
+
return resolvedPath;
|
|
16152
|
+
}
|
|
16153
|
+
async function isReadableFile2(path) {
|
|
16154
|
+
try {
|
|
16155
|
+
await access2(path, constants2.R_OK);
|
|
16156
|
+
return true;
|
|
16157
|
+
} catch {
|
|
16158
|
+
return false;
|
|
16159
|
+
}
|
|
16160
|
+
}
|
|
16161
|
+
function contentTypeForPath(path) {
|
|
16162
|
+
switch (extname(path)) {
|
|
16163
|
+
case ".css":
|
|
16164
|
+
return "text/css; charset=utf-8";
|
|
16165
|
+
case ".html":
|
|
16166
|
+
return "text/html; charset=utf-8";
|
|
16167
|
+
case ".js":
|
|
16168
|
+
return "text/javascript; charset=utf-8";
|
|
16169
|
+
case ".json":
|
|
16170
|
+
return "application/json; charset=utf-8";
|
|
16171
|
+
case ".svg":
|
|
16172
|
+
return "image/svg+xml";
|
|
16173
|
+
case ".wasm":
|
|
16174
|
+
return "application/wasm";
|
|
16175
|
+
default:
|
|
16176
|
+
return "application/octet-stream";
|
|
16177
|
+
}
|
|
16178
|
+
}
|
|
16143
16179
|
|
|
16144
|
-
// src/runtime.ts
|
|
16180
|
+
// ../agent/src/runtime.ts
|
|
16145
16181
|
async function startAgent(options = {}) {
|
|
16146
16182
|
const adbProvider = options.adbProvider ?? new SystemAdbProvider();
|
|
16147
16183
|
let runtimeConfig = options.config ?? defaultAgentConfig;
|
|
@@ -16157,7 +16193,8 @@ async function startAgent(options = {}) {
|
|
|
16157
16193
|
rebindRuntime,
|
|
16158
16194
|
updateRuntimeConfig: (nextConfig) => {
|
|
16159
16195
|
runtimeConfig = nextConfig;
|
|
16160
|
-
}
|
|
16196
|
+
},
|
|
16197
|
+
webUi: options.webUi
|
|
16161
16198
|
});
|
|
16162
16199
|
const applyRuntimeRebind = async (bindHost, port) => {
|
|
16163
16200
|
const previousApp = currentApp;
|
|
@@ -16202,9 +16239,17 @@ async function startAgent(options = {}) {
|
|
|
16202
16239
|
await currentApp?.close();
|
|
16203
16240
|
await Promise.all(closingPorts.values());
|
|
16204
16241
|
currentApp = void 0;
|
|
16242
|
+
},
|
|
16243
|
+
get url() {
|
|
16244
|
+
return createRuntimeUrl(runtimeConfig.bindHost, runtimeConfig.port);
|
|
16205
16245
|
}
|
|
16206
16246
|
};
|
|
16207
16247
|
}
|
|
16248
|
+
function createRuntimeUrl(bindHost, port) {
|
|
16249
|
+
const host = bindHost === "0.0.0.0" || bindHost === "::" ? "127.0.0.1" : bindHost;
|
|
16250
|
+
const formattedHost = host.includes(":") && !host.startsWith("[") ? `[${host}]` : host;
|
|
16251
|
+
return `http://${formattedHost}:${port}`;
|
|
16252
|
+
}
|
|
16208
16253
|
function isDirectRun(moduleUrl, argv) {
|
|
16209
16254
|
const entrypoint = argv[1];
|
|
16210
16255
|
return entrypoint !== void 0 && pathToFileURL(entrypoint).href === moduleUrl;
|
|
@@ -16246,41 +16291,89 @@ function ignoreAsyncError3() {
|
|
|
16246
16291
|
return void 0;
|
|
16247
16292
|
}
|
|
16248
16293
|
|
|
16249
|
-
//
|
|
16294
|
+
// package.json
|
|
16295
|
+
var package_default = {
|
|
16296
|
+
name: "@arenahito/droid-webscr",
|
|
16297
|
+
version: "0.2.0",
|
|
16298
|
+
private: false,
|
|
16299
|
+
license: "MIT",
|
|
16300
|
+
repository: {
|
|
16301
|
+
type: "git",
|
|
16302
|
+
url: "git+https://github.com/arenahito/droid-webscr.git",
|
|
16303
|
+
directory: "apps/cli"
|
|
16304
|
+
},
|
|
16305
|
+
bin: {
|
|
16306
|
+
"droid-webscr": "dist/bin.js"
|
|
16307
|
+
},
|
|
16308
|
+
files: [
|
|
16309
|
+
"dist",
|
|
16310
|
+
"web",
|
|
16311
|
+
"android",
|
|
16312
|
+
"README.md",
|
|
16313
|
+
"LICENSE"
|
|
16314
|
+
],
|
|
16315
|
+
type: "module",
|
|
16316
|
+
publishConfig: {
|
|
16317
|
+
access: "public"
|
|
16318
|
+
},
|
|
16319
|
+
scripts: {
|
|
16320
|
+
build: "tsup && node ../../tools/package-cli.mjs",
|
|
16321
|
+
"build:dev": "tsup --config tsup.dev.config.ts",
|
|
16322
|
+
lint: "oxlint --config ../../oxlint.json src",
|
|
16323
|
+
test: "vitest run",
|
|
16324
|
+
"type-check": "tsc -p tsconfig.json --noEmit"
|
|
16325
|
+
},
|
|
16326
|
+
dependencies: {
|
|
16327
|
+
"@droid-webscr/agent": "workspace:*",
|
|
16328
|
+
"@fastify/middie": "9.3.2",
|
|
16329
|
+
"@fastify/websocket": "11.2.0",
|
|
16330
|
+
fastify: "5.8.5",
|
|
16331
|
+
pino: "10.3.1"
|
|
16332
|
+
},
|
|
16333
|
+
devDependencies: {
|
|
16334
|
+
vite: "^8.0.16"
|
|
16335
|
+
}
|
|
16336
|
+
};
|
|
16337
|
+
|
|
16338
|
+
// src/cli.ts
|
|
16250
16339
|
async function runCli(argv, runtime = {}) {
|
|
16251
16340
|
const args = argv.slice(2);
|
|
16252
16341
|
const io = createCliIo(runtime);
|
|
16253
|
-
const packageVersion = runtime.packageVersion ?? package_default.version;
|
|
16254
|
-
const start = runtime.startAgent ?? startAgent;
|
|
16255
|
-
if (args.length === 0) {
|
|
16256
|
-
await start();
|
|
16257
|
-
return 0;
|
|
16258
|
-
}
|
|
16259
16342
|
if (args.length === 1 && (args[0] === "--help" || args[0] === "-h")) {
|
|
16260
16343
|
io.stdout(createCliHelp());
|
|
16261
16344
|
return 0;
|
|
16262
16345
|
}
|
|
16263
16346
|
if (args.length === 1 && (args[0] === "--version" || args[0] === "-v")) {
|
|
16264
|
-
io.stdout(`${packageVersion}
|
|
16347
|
+
io.stdout(`${runtime.packageVersion ?? "0.0.0"}
|
|
16265
16348
|
`);
|
|
16266
16349
|
return 0;
|
|
16267
16350
|
}
|
|
16268
|
-
|
|
16351
|
+
if (args.length > 0) {
|
|
16352
|
+
io.stderr(`Unknown option: ${args.join(" ")}
|
|
16269
16353
|
|
|
16270
16354
|
`);
|
|
16271
|
-
|
|
16272
|
-
|
|
16355
|
+
io.stderr(createCliHelp());
|
|
16356
|
+
return 1;
|
|
16357
|
+
}
|
|
16358
|
+
const startRuntime = runtime.startRuntime;
|
|
16359
|
+
if (!startRuntime) {
|
|
16360
|
+
throw new Error("No droid-webscr runtime was configured.");
|
|
16361
|
+
}
|
|
16362
|
+
const started = await startRuntime();
|
|
16363
|
+
io.stdout(`droid-webscr is running at ${started.url}
|
|
16364
|
+
`);
|
|
16365
|
+
return 0;
|
|
16273
16366
|
}
|
|
16274
16367
|
function createCliHelp() {
|
|
16275
16368
|
return `Usage: droid-webscr [options]
|
|
16276
16369
|
|
|
16277
|
-
Starts the
|
|
16370
|
+
Starts the integrated droid-webscr local server and web UI.
|
|
16278
16371
|
|
|
16279
16372
|
Options:
|
|
16280
16373
|
-h, --help Show this help text
|
|
16281
16374
|
-v, --version Show the package version
|
|
16282
16375
|
|
|
16283
|
-
The agent
|
|
16376
|
+
The web UI and agent API share http://127.0.0.1:7391 by default.
|
|
16284
16377
|
`;
|
|
16285
16378
|
}
|
|
16286
16379
|
function createCliIo(runtime) {
|
|
@@ -16289,8 +16382,35 @@ function createCliIo(runtime) {
|
|
|
16289
16382
|
stdout: runtime.stdout ?? ((value) => process.stdout.write(value))
|
|
16290
16383
|
};
|
|
16291
16384
|
}
|
|
16385
|
+
|
|
16386
|
+
// src/package-paths.ts
|
|
16387
|
+
import { join as join3 } from "path";
|
|
16388
|
+
var packagedAndroidArtifactFileName = "droid-webscr-server-android.jar";
|
|
16389
|
+
function resolvePackagedWebRoot(packageRoot2) {
|
|
16390
|
+
return join3(packageRoot2, "web");
|
|
16391
|
+
}
|
|
16392
|
+
function resolvePackagedAndroidArtifact(packageRoot2) {
|
|
16393
|
+
return {
|
|
16394
|
+
localPath: join3(packageRoot2, "android", packagedAndroidArtifactFileName),
|
|
16395
|
+
remotePath: deviceServerArtifactRemotePath
|
|
16396
|
+
};
|
|
16397
|
+
}
|
|
16398
|
+
|
|
16399
|
+
// src/bin.ts
|
|
16400
|
+
var packageRoot = dirname2(dirname2(fileURLToPath2(import.meta.url)));
|
|
16401
|
+
async function startPackagedRuntime() {
|
|
16402
|
+
return startAgent({
|
|
16403
|
+
deviceServerArtifact: resolvePackagedAndroidArtifact(packageRoot),
|
|
16404
|
+
webUi: {
|
|
16405
|
+
staticRoot: resolvePackagedWebRoot(packageRoot)
|
|
16406
|
+
}
|
|
16407
|
+
});
|
|
16408
|
+
}
|
|
16292
16409
|
if (isDirectRun(import.meta.url, process.argv)) {
|
|
16293
|
-
runCli(process.argv
|
|
16410
|
+
runCli(process.argv, {
|
|
16411
|
+
packageVersion: package_default.version,
|
|
16412
|
+
startRuntime: startPackagedRuntime
|
|
16413
|
+
}).then(
|
|
16294
16414
|
(exitCode) => {
|
|
16295
16415
|
process.exitCode = exitCode;
|
|
16296
16416
|
},
|
|
@@ -16301,7 +16421,6 @@ if (isDirectRun(import.meta.url, process.argv)) {
|
|
|
16301
16421
|
);
|
|
16302
16422
|
}
|
|
16303
16423
|
export {
|
|
16304
|
-
|
|
16305
|
-
runCli
|
|
16424
|
+
startPackagedRuntime
|
|
16306
16425
|
};
|
|
16307
16426
|
//# sourceMappingURL=bin.js.map
|