@anybrowser/cli 0.0.0-stage → 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/LICENSE +21 -0
- package/README.md +78 -2
- package/dist/allowedSites.js +164 -0
- package/dist/allowedSites.js.map +1 -0
- package/dist/blockLedger.js +111 -0
- package/dist/blockLedger.js.map +1 -0
- package/dist/browser.js +1096 -0
- package/dist/browser.js.map +1 -0
- package/dist/browserDetect.js +53 -0
- package/dist/browserDetect.js.map +1 -0
- package/dist/cli.js +366 -0
- package/dist/cli.js.map +1 -0
- package/dist/connect.js +260 -0
- package/dist/connect.js.map +1 -0
- package/dist/daemon.js +487 -0
- package/dist/daemon.js.map +1 -0
- package/dist/hello.js +62 -0
- package/dist/hello.js.map +1 -0
- package/dist/idle.js +84 -0
- package/dist/idle.js.map +1 -0
- package/dist/install.js +63 -0
- package/dist/install.js.map +1 -0
- package/dist/paths.js +36 -0
- package/dist/paths.js.map +1 -0
- package/dist/profile.js +273 -0
- package/dist/profile.js.map +1 -0
- package/dist/proxy.js +41 -0
- package/dist/proxy.js.map +1 -0
- package/dist/siteProxy.js +354 -0
- package/dist/siteProxy.js.map +1 -0
- package/dist/transport.js +85 -0
- package/dist/transport.js.map +1 -0
- package/dist/version.js +18 -0
- package/dist/version.js.map +1 -0
- package/package.json +50 -4
- package/skills/anybrowser/SKILL.md +42 -0
package/dist/connect.js
ADDED
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
import { chmodSync, existsSync, closeSync, mkdirSync, openSync, readFileSync, statSync, unlinkSync, writeSync, } from "node:fs";
|
|
3
|
+
import { createConnection } from "node:net";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
import { formatHelloLine } from "./hello.js";
|
|
6
|
+
import { assertSocketPathFits } from "./paths.js";
|
|
7
|
+
const DEFAULT_SPAWN_WAIT_MS = 10000;
|
|
8
|
+
/**
|
|
9
|
+
* How long `ensureDaemon` waits to connect to (or spawn and connect to) the
|
|
10
|
+
* daemon before giving up, configurable for tests. Mirrors
|
|
11
|
+
* `ANYBROWSER_STOP_WAIT_MS` in cli.ts. Invalid values (non-numeric, zero,
|
|
12
|
+
* negative) fall back to the default.
|
|
13
|
+
*/
|
|
14
|
+
function spawnWaitMs(env = process.env) {
|
|
15
|
+
const raw = env["ANYBROWSER_SPAWN_WAIT_MS"];
|
|
16
|
+
if (raw === undefined || raw.trim() === "") {
|
|
17
|
+
return DEFAULT_SPAWN_WAIT_MS;
|
|
18
|
+
}
|
|
19
|
+
const parsed = Number(raw);
|
|
20
|
+
return Number.isFinite(parsed) && parsed > 0 ? parsed : DEFAULT_SPAWN_WAIT_MS;
|
|
21
|
+
}
|
|
22
|
+
/** Lock is considered stale once it is this old, regardless of its contents. */
|
|
23
|
+
const LOCK_MAX_AGE_MS = 15000;
|
|
24
|
+
/** Lock is considered stale if it's empty/unreadable and at least this old. */
|
|
25
|
+
const LOCK_EMPTY_GRACE_MS = 2000;
|
|
26
|
+
function delay(ms) {
|
|
27
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
28
|
+
}
|
|
29
|
+
function pollIntervalMs() {
|
|
30
|
+
return 50 + Math.floor(Math.random() * 50);
|
|
31
|
+
}
|
|
32
|
+
/** Tries once to connect to the daemon socket. Resolves null instead of throwing on any failure. */
|
|
33
|
+
export function connectOnce(socketPath) {
|
|
34
|
+
return new Promise((resolve) => {
|
|
35
|
+
const socket = createConnection(socketPath);
|
|
36
|
+
const onConnect = () => {
|
|
37
|
+
cleanup();
|
|
38
|
+
resolve(socket);
|
|
39
|
+
};
|
|
40
|
+
const onError = () => {
|
|
41
|
+
cleanup();
|
|
42
|
+
socket.destroy();
|
|
43
|
+
resolve(null);
|
|
44
|
+
};
|
|
45
|
+
const cleanup = () => {
|
|
46
|
+
socket.off("connect", onConnect);
|
|
47
|
+
socket.off("error", onError);
|
|
48
|
+
};
|
|
49
|
+
socket.once("connect", onConnect);
|
|
50
|
+
socket.once("error", onError);
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
function tryCreateLockFile(lockPath) {
|
|
54
|
+
let fd;
|
|
55
|
+
try {
|
|
56
|
+
fd = openSync(lockPath, "wx");
|
|
57
|
+
}
|
|
58
|
+
catch (error) {
|
|
59
|
+
if (error.code === "EEXIST") {
|
|
60
|
+
return "busy";
|
|
61
|
+
}
|
|
62
|
+
throw error;
|
|
63
|
+
}
|
|
64
|
+
try {
|
|
65
|
+
writeSync(fd, String(process.pid));
|
|
66
|
+
}
|
|
67
|
+
finally {
|
|
68
|
+
closeSync(fd);
|
|
69
|
+
}
|
|
70
|
+
return "acquired";
|
|
71
|
+
}
|
|
72
|
+
function removeLockFile(lockPath) {
|
|
73
|
+
try {
|
|
74
|
+
unlinkSync(lockPath);
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
// best effort: nothing useful to do if it's already gone or unremovable
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
/** Whether the spawn lock at `lockPath` looks abandoned and safe to remove. */
|
|
81
|
+
function isLockStale(lockPath) {
|
|
82
|
+
let stat;
|
|
83
|
+
try {
|
|
84
|
+
stat = statSync(lockPath);
|
|
85
|
+
}
|
|
86
|
+
catch {
|
|
87
|
+
return false; // gone already; nothing to clean up
|
|
88
|
+
}
|
|
89
|
+
const ageMs = Date.now() - stat.mtimeMs;
|
|
90
|
+
if (ageMs > LOCK_MAX_AGE_MS) {
|
|
91
|
+
return true;
|
|
92
|
+
}
|
|
93
|
+
let content;
|
|
94
|
+
try {
|
|
95
|
+
content = readFileSync(lockPath, "utf8");
|
|
96
|
+
}
|
|
97
|
+
catch {
|
|
98
|
+
return ageMs > LOCK_EMPTY_GRACE_MS;
|
|
99
|
+
}
|
|
100
|
+
const trimmed = content.trim();
|
|
101
|
+
if (trimmed.length === 0) {
|
|
102
|
+
return ageMs > LOCK_EMPTY_GRACE_MS;
|
|
103
|
+
}
|
|
104
|
+
const pid = Number(trimmed);
|
|
105
|
+
if (!Number.isInteger(pid)) {
|
|
106
|
+
return ageMs > LOCK_EMPTY_GRACE_MS;
|
|
107
|
+
}
|
|
108
|
+
try {
|
|
109
|
+
process.kill(pid, 0);
|
|
110
|
+
return false; // still alive
|
|
111
|
+
}
|
|
112
|
+
catch (error) {
|
|
113
|
+
return error.code === "ESRCH";
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
async function spawnDaemonProcess(paths) {
|
|
117
|
+
const cliPath = fileURLToPath(new URL("./cli.js", import.meta.url));
|
|
118
|
+
const logFd = openSync(paths.log, "a");
|
|
119
|
+
try {
|
|
120
|
+
const child = spawn(process.execPath, [cliPath, "daemon"], {
|
|
121
|
+
detached: true,
|
|
122
|
+
stdio: ["ignore", logFd, logFd],
|
|
123
|
+
});
|
|
124
|
+
child.unref();
|
|
125
|
+
}
|
|
126
|
+
finally {
|
|
127
|
+
closeSync(logFd);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
function displayLogPath(paths, env = process.env) {
|
|
131
|
+
if (env["ANYBROWSER_HOME"]?.trim()) {
|
|
132
|
+
return paths.log;
|
|
133
|
+
}
|
|
134
|
+
return "~/.anybrowser/daemon.log";
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Returns a socket connected to the daemon, spawning it first if nothing is
|
|
138
|
+
* listening yet. Safe to call concurrently from many processes: exactly one
|
|
139
|
+
* spawns the daemon (via an O_EXCL lock file), the rest wait for it.
|
|
140
|
+
*/
|
|
141
|
+
export async function ensureDaemon(paths, deadlineMs = spawnWaitMs()) {
|
|
142
|
+
assertSocketPathFits(paths.socket);
|
|
143
|
+
// First run: the state directory (e.g. ~/.anybrowser) may not exist yet.
|
|
144
|
+
// Create it before anything below needs to open the lock or log file
|
|
145
|
+
// inside it.
|
|
146
|
+
mkdirSync(paths.home, { recursive: true, mode: 0o700 });
|
|
147
|
+
chmodSync(paths.home, 0o700);
|
|
148
|
+
const deadline = Date.now() + deadlineMs;
|
|
149
|
+
for (;;) {
|
|
150
|
+
const connected = await connectOnce(paths.socket);
|
|
151
|
+
if (connected) {
|
|
152
|
+
return connected;
|
|
153
|
+
}
|
|
154
|
+
if (Date.now() >= deadline) {
|
|
155
|
+
break;
|
|
156
|
+
}
|
|
157
|
+
const lockAttempt = tryCreateLockFile(paths.lock);
|
|
158
|
+
if (lockAttempt === "acquired") {
|
|
159
|
+
try {
|
|
160
|
+
await spawnDaemonProcess(paths);
|
|
161
|
+
while (Date.now() < deadline) {
|
|
162
|
+
const socket = await connectOnce(paths.socket);
|
|
163
|
+
if (socket) {
|
|
164
|
+
return socket;
|
|
165
|
+
}
|
|
166
|
+
await delay(pollIntervalMs());
|
|
167
|
+
}
|
|
168
|
+
break;
|
|
169
|
+
}
|
|
170
|
+
finally {
|
|
171
|
+
removeLockFile(paths.lock);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
// Someone else holds the lock: wait for them, but reclaim a stale lock.
|
|
175
|
+
let staleDetected = false;
|
|
176
|
+
while (Date.now() < deadline) {
|
|
177
|
+
const socket = await connectOnce(paths.socket);
|
|
178
|
+
if (socket) {
|
|
179
|
+
return socket;
|
|
180
|
+
}
|
|
181
|
+
if (isLockStale(paths.lock)) {
|
|
182
|
+
removeLockFile(paths.lock);
|
|
183
|
+
staleDetected = true;
|
|
184
|
+
break;
|
|
185
|
+
}
|
|
186
|
+
await delay(pollIntervalMs());
|
|
187
|
+
}
|
|
188
|
+
if (!staleDetected) {
|
|
189
|
+
break;
|
|
190
|
+
}
|
|
191
|
+
// loop back around and try to acquire the lock ourselves
|
|
192
|
+
}
|
|
193
|
+
throw new Error(`anyb: could not connect to or start the daemon within ${deadlineMs}ms. ` +
|
|
194
|
+
`Check the log at ${displayLogPath(paths)}`);
|
|
195
|
+
}
|
|
196
|
+
const REPLACE_WAIT_MS = 5000;
|
|
197
|
+
/** Reads one newline-terminated line from `socket`; null if it ends first or `timeoutMs` passes. */
|
|
198
|
+
function readReplyLine(socket, timeoutMs) {
|
|
199
|
+
return new Promise((resolve) => {
|
|
200
|
+
let buffered = "";
|
|
201
|
+
const finish = (value) => {
|
|
202
|
+
clearTimeout(timer);
|
|
203
|
+
socket.off("data", onData);
|
|
204
|
+
socket.off("close", onEnd);
|
|
205
|
+
socket.off("error", onEnd);
|
|
206
|
+
resolve(value);
|
|
207
|
+
};
|
|
208
|
+
const onData = (chunk) => {
|
|
209
|
+
buffered += chunk.toString("utf8");
|
|
210
|
+
const newline = buffered.indexOf("\n");
|
|
211
|
+
if (newline !== -1)
|
|
212
|
+
finish(buffered.slice(0, newline));
|
|
213
|
+
};
|
|
214
|
+
const onEnd = () => finish(null);
|
|
215
|
+
const timer = setTimeout(() => finish(null), timeoutMs);
|
|
216
|
+
socket.on("data", onData);
|
|
217
|
+
socket.on("close", onEnd);
|
|
218
|
+
socket.on("error", onEnd);
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Version handshake (docs/DESIGN.md decision 17). If a daemon is running
|
|
223
|
+
* with a different version than `version` and no session is using it, asks
|
|
224
|
+
* it to stop and waits (bounded) for its socket file to disappear, so the
|
|
225
|
+
* normal spawn path then starts a daemon of the new version. A daemon that
|
|
226
|
+
* still has sessions is left alone: it retires itself once they are gone.
|
|
227
|
+
* Never throws and never writes to stdout.
|
|
228
|
+
*/
|
|
229
|
+
export async function replaceStaleDaemon(paths, version) {
|
|
230
|
+
const probe = await connectOnce(paths.socket);
|
|
231
|
+
if (!probe)
|
|
232
|
+
return;
|
|
233
|
+
probe.on("error", () => { });
|
|
234
|
+
probe.write(formatHelloLine("status", version));
|
|
235
|
+
const line = await readReplyLine(probe, REPLACE_WAIT_MS);
|
|
236
|
+
probe.destroy();
|
|
237
|
+
if (line === null)
|
|
238
|
+
return;
|
|
239
|
+
let status;
|
|
240
|
+
try {
|
|
241
|
+
status = JSON.parse(line);
|
|
242
|
+
}
|
|
243
|
+
catch {
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
if (status.version === version || status.sessions > 0)
|
|
247
|
+
return;
|
|
248
|
+
const stopper = await connectOnce(paths.socket);
|
|
249
|
+
if (!stopper)
|
|
250
|
+
return;
|
|
251
|
+
stopper.on("error", () => { });
|
|
252
|
+
stopper.write(formatHelloLine("stop", version));
|
|
253
|
+
await readReplyLine(stopper, REPLACE_WAIT_MS);
|
|
254
|
+
stopper.destroy();
|
|
255
|
+
const deadline = Date.now() + REPLACE_WAIT_MS;
|
|
256
|
+
while (existsSync(paths.socket) && Date.now() < deadline) {
|
|
257
|
+
await delay(50);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
//# sourceMappingURL=connect.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"connect.js","sourceRoot":"","sources":["../src/connect.ts"],"names":[],"mappings":"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"}
|