@btraut/browser-bridge 0.13.0 → 0.13.2
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/CHANGELOG.md +17 -0
- package/dist/api.js +157 -39
- package/dist/api.js.map +3 -3
- package/dist/index.js +90 -39
- package/dist/index.js.map +3 -3
- package/extension/dist/background.js +92 -80
- package/extension/dist/background.js.map +3 -3
- package/extension/manifest.json +1 -1
- package/package.json +1 -1
- package/skills/browser-bridge/skill.json +1 -1
package/dist/index.js
CHANGED
|
@@ -28,6 +28,7 @@ var import_commander = require("commander");
|
|
|
28
28
|
|
|
29
29
|
// packages/shared/src/core-readiness.ts
|
|
30
30
|
var import_promises = require("node:timers/promises");
|
|
31
|
+
var import_node_net = require("node:net");
|
|
31
32
|
|
|
32
33
|
// packages/shared/src/logging.ts
|
|
33
34
|
var import_node_fs2 = require("node:fs");
|
|
@@ -604,6 +605,27 @@ var DEFAULT_HEALTH_RETRY_MS = 250;
|
|
|
604
605
|
var DEFAULT_HEALTH_ATTEMPTS = 20;
|
|
605
606
|
var DEFAULT_HEALTH_TIMEOUT_MS = 2e3;
|
|
606
607
|
var DEFAULT_HEALTH_BUDGET_MS = 15e3;
|
|
608
|
+
var DEFAULT_PORT_REACHABILITY_TIMEOUT_MS = 300;
|
|
609
|
+
var isPortReachableDefault = async (runtime) => {
|
|
610
|
+
return await new Promise((resolve4) => {
|
|
611
|
+
const socket = new import_node_net.Socket();
|
|
612
|
+
let settled = false;
|
|
613
|
+
const finish = (reachable) => {
|
|
614
|
+
if (settled) {
|
|
615
|
+
return;
|
|
616
|
+
}
|
|
617
|
+
settled = true;
|
|
618
|
+
socket.removeAllListeners();
|
|
619
|
+
socket.destroy();
|
|
620
|
+
resolve4(reachable);
|
|
621
|
+
};
|
|
622
|
+
socket.setTimeout(DEFAULT_PORT_REACHABILITY_TIMEOUT_MS);
|
|
623
|
+
socket.once("connect", () => finish(true));
|
|
624
|
+
socket.once("timeout", () => finish(false));
|
|
625
|
+
socket.once("error", () => finish(false));
|
|
626
|
+
socket.connect(runtime.port, runtime.host);
|
|
627
|
+
});
|
|
628
|
+
};
|
|
607
629
|
var resolveTimeoutMs = (timeoutMs) => {
|
|
608
630
|
const candidate = timeoutMs ?? (process.env.BROWSER_BRIDGE_CORE_TIMEOUT_MS ? Number.parseInt(process.env.BROWSER_BRIDGE_CORE_TIMEOUT_MS, 10) : process.env.BROWSER_VISION_CORE_TIMEOUT_MS ? Number.parseInt(process.env.BROWSER_VISION_CORE_TIMEOUT_MS, 10) : void 0);
|
|
609
631
|
if (candidate === void 0 || candidate === null) {
|
|
@@ -669,57 +691,71 @@ var createCoreReadinessController = (options = {}) => {
|
|
|
669
691
|
baseUrl = `http://${runtime.host}:${runtime.port}`;
|
|
670
692
|
};
|
|
671
693
|
const checkHealth = async () => {
|
|
672
|
-
|
|
673
|
-
const controller = new AbortController();
|
|
674
|
-
const timeout = setTimeout(() => controller.abort(), healthTimeoutMs);
|
|
694
|
+
for (const method of ["POST", "GET"]) {
|
|
675
695
|
try {
|
|
676
|
-
|
|
696
|
+
const controller = new AbortController();
|
|
697
|
+
const timeout = setTimeout(() => controller.abort(), healthTimeoutMs);
|
|
677
698
|
try {
|
|
678
|
-
response
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
699
|
+
let response;
|
|
700
|
+
try {
|
|
701
|
+
response = await fetchImpl(`${baseUrl}/health`, {
|
|
702
|
+
method,
|
|
703
|
+
signal: controller.signal
|
|
704
|
+
});
|
|
705
|
+
} catch (error) {
|
|
706
|
+
if (controller.signal.aborted || error instanceof Error && error.name === "AbortError") {
|
|
707
|
+
logger.warn(`${logPrefix}.health.timeout`, {
|
|
708
|
+
base_url: baseUrl,
|
|
709
|
+
method,
|
|
710
|
+
timeout_ms: healthTimeoutMs
|
|
711
|
+
});
|
|
712
|
+
continue;
|
|
713
|
+
}
|
|
714
|
+
logger.warn(`${logPrefix}.health.fetch_failed`, {
|
|
685
715
|
base_url: baseUrl,
|
|
686
|
-
|
|
716
|
+
method,
|
|
717
|
+
error
|
|
687
718
|
});
|
|
688
|
-
|
|
719
|
+
throw error;
|
|
720
|
+
}
|
|
721
|
+
if (!response.ok) {
|
|
722
|
+
logger.warn(`${logPrefix}.health.non_ok`, {
|
|
723
|
+
base_url: baseUrl,
|
|
724
|
+
method,
|
|
725
|
+
status: response.status
|
|
726
|
+
});
|
|
727
|
+
continue;
|
|
728
|
+
}
|
|
729
|
+
const data = await response.json().catch(() => null);
|
|
730
|
+
const ok = Boolean(data?.ok);
|
|
731
|
+
if (ok) {
|
|
732
|
+
if (method === "GET") {
|
|
733
|
+
logger.info(`${logPrefix}.health.compat_probe`, {
|
|
734
|
+
base_url: baseUrl,
|
|
735
|
+
method
|
|
736
|
+
});
|
|
737
|
+
}
|
|
738
|
+
return true;
|
|
689
739
|
}
|
|
690
|
-
logger.warn(`${logPrefix}.health.fetch_failed`, {
|
|
691
|
-
base_url: baseUrl,
|
|
692
|
-
error
|
|
693
|
-
});
|
|
694
|
-
throw error;
|
|
695
|
-
}
|
|
696
|
-
if (!response.ok) {
|
|
697
|
-
logger.warn(`${logPrefix}.health.non_ok`, {
|
|
698
|
-
base_url: baseUrl,
|
|
699
|
-
status: response.status
|
|
700
|
-
});
|
|
701
|
-
return false;
|
|
702
|
-
}
|
|
703
|
-
const data = await response.json().catch(() => null);
|
|
704
|
-
const ok = Boolean(data?.ok);
|
|
705
|
-
if (!ok) {
|
|
706
740
|
logger.warn(`${logPrefix}.health.not_ready`, {
|
|
707
|
-
base_url: baseUrl
|
|
741
|
+
base_url: baseUrl,
|
|
742
|
+
method
|
|
708
743
|
});
|
|
744
|
+
} finally {
|
|
745
|
+
clearTimeout(timeout);
|
|
709
746
|
}
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
747
|
+
} catch (error) {
|
|
748
|
+
logger.warn(`${logPrefix}.health.error`, {
|
|
749
|
+
base_url: baseUrl,
|
|
750
|
+
method,
|
|
751
|
+
error
|
|
752
|
+
});
|
|
713
753
|
}
|
|
714
|
-
} catch (error) {
|
|
715
|
-
logger.warn(`${logPrefix}.health.error`, {
|
|
716
|
-
base_url: baseUrl,
|
|
717
|
-
error
|
|
718
|
-
});
|
|
719
|
-
return false;
|
|
720
754
|
}
|
|
755
|
+
return false;
|
|
721
756
|
};
|
|
722
757
|
const ensureCoreRunning = async () => {
|
|
758
|
+
const portReachabilityCheck = options.portReachabilityCheck ?? isPortReachableDefault;
|
|
723
759
|
refreshRuntime();
|
|
724
760
|
if (await checkHealth()) {
|
|
725
761
|
logger.debug(`${logPrefix}.ensure_ready.already_running`, {
|
|
@@ -760,6 +796,21 @@ var createCoreReadinessController = (options = {}) => {
|
|
|
760
796
|
health_budget_ms: healthBudgetMs,
|
|
761
797
|
health_timeout_ms: healthTimeoutMs
|
|
762
798
|
});
|
|
799
|
+
let portOccupied = false;
|
|
800
|
+
try {
|
|
801
|
+
portOccupied = await portReachabilityCheck(runtime);
|
|
802
|
+
} catch (error) {
|
|
803
|
+
logger.warn(`${logPrefix}.ensure_ready.port_probe_failed`, {
|
|
804
|
+
host: runtime.host,
|
|
805
|
+
port: runtime.port,
|
|
806
|
+
error
|
|
807
|
+
});
|
|
808
|
+
}
|
|
809
|
+
if (portOccupied) {
|
|
810
|
+
throw new Error(
|
|
811
|
+
`Core daemon failed to start on ${runtime.host}:${runtime.port}. A process is already listening on this port but did not pass Browser Bridge health checks. Retry with --no-daemon to reuse it, or enable isolated mode (BROWSER_BRIDGE_ISOLATED_MODE=1) for per-worktree ports.`
|
|
812
|
+
);
|
|
813
|
+
}
|
|
763
814
|
throw new Error(
|
|
764
815
|
`Core daemon failed to start on ${runtime.host}:${runtime.port}.`
|
|
765
816
|
);
|