opendevbrowser 0.0.10 → 0.0.11
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 +150 -24
- package/dist/index.js +108 -2
- package/dist/index.js.map +1 -1
- package/dist/opendevbrowser.js +108 -2
- package/dist/opendevbrowser.js.map +1 -1
- package/extension/dist/popup.js +58 -11
- package/extension/dist/relay-settings.js +1 -0
- package/extension/manifest.json +1 -1
- package/package.json +2 -2
package/dist/opendevbrowser.js
CHANGED
|
@@ -2276,21 +2276,30 @@ function buildContinuityNudgeMessage(filePath) {
|
|
|
2276
2276
|
import { createServer } from "http";
|
|
2277
2277
|
import { timingSafeEqual } from "crypto";
|
|
2278
2278
|
import { WebSocket, WebSocketServer } from "ws";
|
|
2279
|
+
var DEFAULT_DISCOVERY_PORT = 8787;
|
|
2280
|
+
var CONFIG_PATH = "/config";
|
|
2281
|
+
var PAIR_PATH = "/pair";
|
|
2279
2282
|
var RelayServer = class _RelayServer {
|
|
2280
2283
|
running = false;
|
|
2281
2284
|
baseUrl = null;
|
|
2282
2285
|
port = null;
|
|
2283
2286
|
server = null;
|
|
2287
|
+
discoveryServer = null;
|
|
2284
2288
|
extensionWss = null;
|
|
2285
2289
|
cdpWss = null;
|
|
2286
2290
|
extensionSocket = null;
|
|
2287
2291
|
cdpSocket = null;
|
|
2288
2292
|
extensionInfo = null;
|
|
2289
2293
|
pairingToken = null;
|
|
2294
|
+
configuredDiscoveryPort;
|
|
2295
|
+
discoveryPort = null;
|
|
2290
2296
|
handshakeAttempts = /* @__PURE__ */ new Map();
|
|
2291
2297
|
cdpAllowlist = null;
|
|
2292
2298
|
static MAX_HANDSHAKE_ATTEMPTS = 5;
|
|
2293
2299
|
static RATE_LIMIT_WINDOW_MS = 6e4;
|
|
2300
|
+
constructor(options = {}) {
|
|
2301
|
+
this.configuredDiscoveryPort = options.discoveryPort ?? DEFAULT_DISCOVERY_PORT;
|
|
2302
|
+
}
|
|
2294
2303
|
async start(port = 8787) {
|
|
2295
2304
|
if (this.running && this.baseUrl && this.port !== null) {
|
|
2296
2305
|
return { url: this.baseUrl, port: this.port };
|
|
@@ -2335,7 +2344,15 @@ var RelayServer = class _RelayServer {
|
|
|
2335
2344
|
this.server.on("request", (request, response) => {
|
|
2336
2345
|
const pathname = new URL(request.url ?? "", "http://127.0.0.1").pathname;
|
|
2337
2346
|
const origin = request.headers.origin;
|
|
2338
|
-
if (pathname ===
|
|
2347
|
+
if (pathname === CONFIG_PATH && request.method === "OPTIONS") {
|
|
2348
|
+
this.handleConfigPreflight(origin, response);
|
|
2349
|
+
return;
|
|
2350
|
+
}
|
|
2351
|
+
if (pathname === CONFIG_PATH && request.method === "GET") {
|
|
2352
|
+
this.handleConfigRequest(origin, response);
|
|
2353
|
+
return;
|
|
2354
|
+
}
|
|
2355
|
+
if (pathname === PAIR_PATH && request.method === "OPTIONS") {
|
|
2339
2356
|
if (origin && origin.startsWith("chrome-extension://")) {
|
|
2340
2357
|
response.setHeader("Access-Control-Allow-Origin", origin);
|
|
2341
2358
|
response.setHeader("Access-Control-Allow-Methods", "GET, OPTIONS");
|
|
@@ -2345,7 +2362,7 @@ var RelayServer = class _RelayServer {
|
|
|
2345
2362
|
response.end();
|
|
2346
2363
|
return;
|
|
2347
2364
|
}
|
|
2348
|
-
if (pathname ===
|
|
2365
|
+
if (pathname === PAIR_PATH && request.method === "GET") {
|
|
2349
2366
|
const isLocalhost = !origin || origin.startsWith("chrome-extension://");
|
|
2350
2367
|
if (!isLocalhost) {
|
|
2351
2368
|
response.writeHead(403, { "Content-Type": "application/json" });
|
|
@@ -2405,6 +2422,13 @@ var RelayServer = class _RelayServer {
|
|
|
2405
2422
|
this.port = address.port;
|
|
2406
2423
|
this.baseUrl = `ws://127.0.0.1:${address.port}`;
|
|
2407
2424
|
this.running = true;
|
|
2425
|
+
try {
|
|
2426
|
+
await this.startDiscoveryServer();
|
|
2427
|
+
} catch (error) {
|
|
2428
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
2429
|
+
console.warn(`[opendevbrowser] Discovery server failed to start: ${message}`);
|
|
2430
|
+
this.stopDiscoveryServer();
|
|
2431
|
+
}
|
|
2408
2432
|
return { url: this.baseUrl, port: address.port };
|
|
2409
2433
|
}
|
|
2410
2434
|
stop() {
|
|
@@ -2412,6 +2436,7 @@ var RelayServer = class _RelayServer {
|
|
|
2412
2436
|
this.baseUrl = null;
|
|
2413
2437
|
this.port = null;
|
|
2414
2438
|
this.extensionInfo = null;
|
|
2439
|
+
this.stopDiscoveryServer();
|
|
2415
2440
|
if (this.extensionSocket) {
|
|
2416
2441
|
this.extensionSocket.close(1e3, "Relay stopped");
|
|
2417
2442
|
this.extensionSocket = null;
|
|
@@ -2440,6 +2465,12 @@ var RelayServer = class _RelayServer {
|
|
|
2440
2465
|
getCdpUrl() {
|
|
2441
2466
|
return this.baseUrl ? `${this.baseUrl}/cdp` : null;
|
|
2442
2467
|
}
|
|
2468
|
+
getDiscoveryPort() {
|
|
2469
|
+
if (this.port !== null && this.port === this.configuredDiscoveryPort) {
|
|
2470
|
+
return this.port;
|
|
2471
|
+
}
|
|
2472
|
+
return this.discoveryPort;
|
|
2473
|
+
}
|
|
2443
2474
|
setToken(token) {
|
|
2444
2475
|
const trimmed = typeof token === "string" ? token.trim() : "";
|
|
2445
2476
|
this.pairingToken = trimmed.length ? trimmed : null;
|
|
@@ -2460,6 +2491,81 @@ var RelayServer = class _RelayServer {
|
|
|
2460
2491
|
}
|
|
2461
2492
|
return false;
|
|
2462
2493
|
}
|
|
2494
|
+
isExtensionOrigin(origin) {
|
|
2495
|
+
return Boolean(origin && origin.startsWith("chrome-extension://"));
|
|
2496
|
+
}
|
|
2497
|
+
handleConfigPreflight(origin, response) {
|
|
2498
|
+
if (this.isExtensionOrigin(origin)) {
|
|
2499
|
+
response.setHeader("Access-Control-Allow-Origin", origin);
|
|
2500
|
+
response.setHeader("Access-Control-Allow-Methods", "GET, OPTIONS");
|
|
2501
|
+
response.setHeader("Access-Control-Allow-Headers", "Content-Type");
|
|
2502
|
+
}
|
|
2503
|
+
response.writeHead(204);
|
|
2504
|
+
response.end();
|
|
2505
|
+
}
|
|
2506
|
+
handleConfigRequest(origin, response) {
|
|
2507
|
+
if (!this.isExtensionOrigin(origin)) {
|
|
2508
|
+
response.writeHead(403, { "Content-Type": "application/json" });
|
|
2509
|
+
response.end(JSON.stringify({ error: "Forbidden: extension origin required" }));
|
|
2510
|
+
return;
|
|
2511
|
+
}
|
|
2512
|
+
if (origin) {
|
|
2513
|
+
response.setHeader("Access-Control-Allow-Origin", origin);
|
|
2514
|
+
}
|
|
2515
|
+
if (this.port === null) {
|
|
2516
|
+
response.writeHead(503, { "Content-Type": "application/json" });
|
|
2517
|
+
response.end(JSON.stringify({ error: "Relay not running" }));
|
|
2518
|
+
return;
|
|
2519
|
+
}
|
|
2520
|
+
response.writeHead(200, {
|
|
2521
|
+
"Content-Type": "application/json",
|
|
2522
|
+
"Cache-Control": "no-store"
|
|
2523
|
+
});
|
|
2524
|
+
response.end(JSON.stringify({
|
|
2525
|
+
relayPort: this.port,
|
|
2526
|
+
pairingRequired: Boolean(this.pairingToken)
|
|
2527
|
+
}));
|
|
2528
|
+
}
|
|
2529
|
+
async startDiscoveryServer() {
|
|
2530
|
+
if (this.port === null || this.discoveryServer) {
|
|
2531
|
+
return;
|
|
2532
|
+
}
|
|
2533
|
+
if (this.configuredDiscoveryPort > 0 && this.configuredDiscoveryPort === this.port) {
|
|
2534
|
+
return;
|
|
2535
|
+
}
|
|
2536
|
+
this.discoveryServer = createServer((request, response) => {
|
|
2537
|
+
const pathname = new URL(request.url ?? "", "http://127.0.0.1").pathname;
|
|
2538
|
+
const origin = request.headers.origin;
|
|
2539
|
+
if (pathname === CONFIG_PATH && request.method === "OPTIONS") {
|
|
2540
|
+
this.handleConfigPreflight(origin, response);
|
|
2541
|
+
return;
|
|
2542
|
+
}
|
|
2543
|
+
if (pathname === CONFIG_PATH && request.method === "GET") {
|
|
2544
|
+
this.handleConfigRequest(origin, response);
|
|
2545
|
+
return;
|
|
2546
|
+
}
|
|
2547
|
+
response.writeHead(404);
|
|
2548
|
+
response.end();
|
|
2549
|
+
});
|
|
2550
|
+
await new Promise((resolve, reject) => {
|
|
2551
|
+
this.discoveryServer?.once("error", reject);
|
|
2552
|
+
this.discoveryServer?.listen(this.configuredDiscoveryPort, "127.0.0.1", () => {
|
|
2553
|
+
resolve();
|
|
2554
|
+
});
|
|
2555
|
+
});
|
|
2556
|
+
const address = this.discoveryServer.address();
|
|
2557
|
+
if (!address) {
|
|
2558
|
+
throw new Error("Discovery server did not expose a port");
|
|
2559
|
+
}
|
|
2560
|
+
this.discoveryPort = address.port;
|
|
2561
|
+
}
|
|
2562
|
+
stopDiscoveryServer() {
|
|
2563
|
+
if (this.discoveryServer) {
|
|
2564
|
+
this.discoveryServer.close();
|
|
2565
|
+
this.discoveryServer = null;
|
|
2566
|
+
}
|
|
2567
|
+
this.discoveryPort = null;
|
|
2568
|
+
}
|
|
2463
2569
|
isRateLimited(ip) {
|
|
2464
2570
|
const now = Date.now();
|
|
2465
2571
|
const record = this.handshakeAttempts.get(ip);
|