@owloops/browserbird 1.0.2 → 1.0.3
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/bin/browserbird +7 -1
- package/dist/db-BsYEYsul.mjs +1011 -0
- package/dist/index.mjs +4748 -0
- package/package.json +6 -3
- package/src/channel/blocks.ts +0 -485
- package/src/channel/coalesce.ts +0 -79
- package/src/channel/commands.ts +0 -216
- package/src/channel/handler.ts +0 -272
- package/src/channel/slack.ts +0 -573
- package/src/channel/types.ts +0 -59
- package/src/cli/banner.ts +0 -10
- package/src/cli/birds.ts +0 -396
- package/src/cli/config.ts +0 -77
- package/src/cli/doctor.ts +0 -63
- package/src/cli/index.ts +0 -5
- package/src/cli/jobs.ts +0 -166
- package/src/cli/logs.ts +0 -67
- package/src/cli/run.ts +0 -148
- package/src/cli/sessions.ts +0 -158
- package/src/cli/style.ts +0 -19
- package/src/config.ts +0 -291
- package/src/core/logger.ts +0 -78
- package/src/core/redact.ts +0 -75
- package/src/core/types.ts +0 -83
- package/src/core/uid.ts +0 -26
- package/src/core/utils.ts +0 -137
- package/src/cron/parse.ts +0 -146
- package/src/cron/scheduler.ts +0 -242
- package/src/daemon.ts +0 -169
- package/src/db/auth.ts +0 -49
- package/src/db/birds.ts +0 -357
- package/src/db/core.ts +0 -377
- package/src/db/index.ts +0 -10
- package/src/db/jobs.ts +0 -289
- package/src/db/logs.ts +0 -64
- package/src/db/messages.ts +0 -79
- package/src/db/path.ts +0 -30
- package/src/db/sessions.ts +0 -165
- package/src/jobs.ts +0 -140
- package/src/provider/claude.test.ts +0 -95
- package/src/provider/claude.ts +0 -196
- package/src/provider/opencode.test.ts +0 -169
- package/src/provider/opencode.ts +0 -248
- package/src/provider/session.ts +0 -65
- package/src/provider/spawn.ts +0 -173
- package/src/provider/stream.ts +0 -67
- package/src/provider/types.ts +0 -24
- package/src/server/auth.ts +0 -135
- package/src/server/health.ts +0 -87
- package/src/server/http.ts +0 -132
- package/src/server/index.ts +0 -6
- package/src/server/lifecycle.ts +0 -135
- package/src/server/routes.ts +0 -1199
- package/src/server/sse.ts +0 -54
- package/src/server/static.ts +0 -45
- package/src/server/vnc-proxy.ts +0 -75
package/src/server/sse.ts
DELETED
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
/** @fileoverview Server-Sent Events: connection management and broadcasting. */
|
|
2
|
-
|
|
3
|
-
import type { IncomingMessage, ServerResponse } from 'node:http';
|
|
4
|
-
import type { Config } from '../core/types.ts';
|
|
5
|
-
import type { WebServerDeps } from './http.ts';
|
|
6
|
-
import { checkAuth } from './http.ts';
|
|
7
|
-
import { buildStatusPayload } from './routes.ts';
|
|
8
|
-
|
|
9
|
-
const sseConnections = new Set<ServerResponse>();
|
|
10
|
-
|
|
11
|
-
export function handleSSE(
|
|
12
|
-
getConfig: () => Config,
|
|
13
|
-
startedAt: number,
|
|
14
|
-
getDeps: () => WebServerDeps,
|
|
15
|
-
req: IncomingMessage,
|
|
16
|
-
res: ServerResponse,
|
|
17
|
-
): void {
|
|
18
|
-
if (!checkAuth(req, res, true)) return;
|
|
19
|
-
|
|
20
|
-
res.writeHead(200, {
|
|
21
|
-
'Content-Type': 'text/event-stream; charset=utf-8',
|
|
22
|
-
'Cache-Control': 'no-cache, no-transform',
|
|
23
|
-
Connection: 'keep-alive',
|
|
24
|
-
'X-Accel-Buffering': 'no',
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
sseConnections.add(res);
|
|
28
|
-
|
|
29
|
-
const send = () => {
|
|
30
|
-
const data = JSON.stringify(buildStatusPayload(getConfig, startedAt, getDeps));
|
|
31
|
-
res.write(`event: status\ndata: ${data}\n\n`);
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
send();
|
|
35
|
-
const timer = setInterval(send, 5000);
|
|
36
|
-
req.on('close', () => {
|
|
37
|
-
clearInterval(timer);
|
|
38
|
-
sseConnections.delete(res);
|
|
39
|
-
});
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
export function broadcastSSE(event: string, data: unknown): void {
|
|
43
|
-
const payload = `event: ${event}\ndata: ${JSON.stringify(data)}\n\n`;
|
|
44
|
-
for (const res of sseConnections) {
|
|
45
|
-
if (!res.destroyed) res.write(payload);
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
export function closeAllSSE(): void {
|
|
50
|
-
for (const res of sseConnections) {
|
|
51
|
-
res.end();
|
|
52
|
-
}
|
|
53
|
-
sseConnections.clear();
|
|
54
|
-
}
|
package/src/server/static.ts
DELETED
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
/** @fileoverview Static file serving for the web UI. */
|
|
2
|
-
|
|
3
|
-
import type { ServerResponse } from 'node:http';
|
|
4
|
-
import { readFileSync, existsSync } from 'node:fs';
|
|
5
|
-
import { join, extname } from 'node:path';
|
|
6
|
-
import { fileURLToPath } from 'node:url';
|
|
7
|
-
import { dirname } from 'node:path';
|
|
8
|
-
import { MIME_TYPES } from './http.ts';
|
|
9
|
-
|
|
10
|
-
const WEB_DIR = join(dirname(fileURLToPath(import.meta.url)), '..', '..', 'web', 'dist');
|
|
11
|
-
|
|
12
|
-
export function serveStatic(res: ServerResponse, urlPath: string): void {
|
|
13
|
-
if (!existsSync(WEB_DIR)) {
|
|
14
|
-
res.writeHead(503, { 'Content-Type': 'text/plain' });
|
|
15
|
-
res.end('Web UI not built');
|
|
16
|
-
return;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
if (urlPath === '/' || urlPath === '') urlPath = '/index.html';
|
|
20
|
-
|
|
21
|
-
const filePath = join(WEB_DIR, urlPath);
|
|
22
|
-
|
|
23
|
-
if (!filePath.startsWith(WEB_DIR)) {
|
|
24
|
-
res.writeHead(403);
|
|
25
|
-
res.end('Forbidden');
|
|
26
|
-
return;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
try {
|
|
30
|
-
const content = readFileSync(filePath);
|
|
31
|
-
const ext = extname(filePath);
|
|
32
|
-
const contentType = MIME_TYPES[ext] ?? 'application/octet-stream';
|
|
33
|
-
res.writeHead(200, { 'Content-Type': contentType });
|
|
34
|
-
res.end(content);
|
|
35
|
-
} catch {
|
|
36
|
-
try {
|
|
37
|
-
const indexContent = readFileSync(join(WEB_DIR, 'index.html'));
|
|
38
|
-
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
|
|
39
|
-
res.end(indexContent);
|
|
40
|
-
} catch {
|
|
41
|
-
res.writeHead(404);
|
|
42
|
-
res.end('Not found');
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
}
|
package/src/server/vnc-proxy.ts
DELETED
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
/** @fileoverview WebSocket proxy for VNC: tunnels browser connections to upstream noVNC. */
|
|
2
|
-
|
|
3
|
-
import { connect } from 'node:net';
|
|
4
|
-
import type { IncomingMessage } from 'node:http';
|
|
5
|
-
import type { Duplex } from 'node:stream';
|
|
6
|
-
import type { Config } from '../core/types.ts';
|
|
7
|
-
import { logger } from '../core/logger.ts';
|
|
8
|
-
import { getUserCount } from '../db/auth.ts';
|
|
9
|
-
import { verifyToken } from './auth.ts';
|
|
10
|
-
|
|
11
|
-
function destroyWithStatus(socket: Duplex, status: number, message: string): void {
|
|
12
|
-
const body = `HTTP/1.1 ${status} ${message}\r\n\r\n`;
|
|
13
|
-
socket.end(body);
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
function checkUpgradeAuth(req: IncomingMessage): boolean {
|
|
17
|
-
if (getUserCount() === 0) return true;
|
|
18
|
-
|
|
19
|
-
const url = new URL(req.url ?? '/', `http://${req.headers.host}`);
|
|
20
|
-
const token = url.searchParams.get('token');
|
|
21
|
-
return token != null && verifyToken(token);
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export function handleVncUpgrade(
|
|
25
|
-
getConfig: () => Config,
|
|
26
|
-
req: IncomingMessage,
|
|
27
|
-
socket: Duplex,
|
|
28
|
-
head: Buffer,
|
|
29
|
-
): void {
|
|
30
|
-
const config = getConfig();
|
|
31
|
-
if (!config.browser.enabled) {
|
|
32
|
-
destroyWithStatus(socket, 404, 'Not Found');
|
|
33
|
-
return;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
if (!checkUpgradeAuth(req)) {
|
|
37
|
-
destroyWithStatus(socket, 403, 'Forbidden');
|
|
38
|
-
return;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
const { novncHost, novncPort } = config.browser;
|
|
42
|
-
|
|
43
|
-
logger.info(`vnc proxy connecting to ${novncHost}:${novncPort}`);
|
|
44
|
-
|
|
45
|
-
const upstream = connect(novncPort, novncHost, () => {
|
|
46
|
-
logger.info(`vnc proxy connected to ${novncHost}:${novncPort}`);
|
|
47
|
-
const httpVersion = req.httpVersion;
|
|
48
|
-
|
|
49
|
-
let rawHeaders = `GET /websockify HTTP/${httpVersion}\r\n`;
|
|
50
|
-
for (let i = 0; i < req.rawHeaders.length; i += 2) {
|
|
51
|
-
rawHeaders += `${req.rawHeaders[i]}: ${req.rawHeaders[i + 1]}\r\n`;
|
|
52
|
-
}
|
|
53
|
-
rawHeaders += '\r\n';
|
|
54
|
-
|
|
55
|
-
upstream.write(rawHeaders);
|
|
56
|
-
if (head.length > 0) upstream.write(head);
|
|
57
|
-
socket.pipe(upstream);
|
|
58
|
-
upstream.pipe(socket);
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
upstream.on('error', (err) => {
|
|
62
|
-
const code = (err as { code?: string }).code ?? '';
|
|
63
|
-
logger.error(`vnc proxy upstream error: ${code} ${err.message}`);
|
|
64
|
-
socket.destroy();
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
socket.on('error', (err) => {
|
|
68
|
-
const code = (err as { code?: string }).code ?? '';
|
|
69
|
-
logger.error(`vnc proxy client error: ${code} ${err.message}`);
|
|
70
|
-
upstream.destroy();
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
upstream.on('close', () => socket.destroy());
|
|
74
|
-
socket.on('close', () => upstream.destroy());
|
|
75
|
-
}
|