@cjwddz/browser-server 0.1.0-alpha

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.
Files changed (58) hide show
  1. package/README.md +148 -0
  2. package/dist/cli.d.ts +3 -0
  3. package/dist/cli.d.ts.map +1 -0
  4. package/dist/cli.js +161 -0
  5. package/dist/cli.js.map +1 -0
  6. package/dist/daemon.d.ts +2 -0
  7. package/dist/daemon.d.ts.map +1 -0
  8. package/dist/daemon.js +57 -0
  9. package/dist/daemon.js.map +1 -0
  10. package/dist/index.d.ts +8 -0
  11. package/dist/index.d.ts.map +1 -0
  12. package/dist/index.js +7 -0
  13. package/dist/index.js.map +1 -0
  14. package/dist/mcp/connection-pool.d.ts +14 -0
  15. package/dist/mcp/connection-pool.d.ts.map +1 -0
  16. package/dist/mcp/connection-pool.js +65 -0
  17. package/dist/mcp/connection-pool.js.map +1 -0
  18. package/dist/mcp/tools.d.ts +230 -0
  19. package/dist/mcp/tools.d.ts.map +1 -0
  20. package/dist/mcp/tools.js +219 -0
  21. package/dist/mcp/tools.js.map +1 -0
  22. package/dist/server/mcp-server.d.ts +15 -0
  23. package/dist/server/mcp-server.d.ts.map +1 -0
  24. package/dist/server/mcp-server.js +96 -0
  25. package/dist/server/mcp-server.js.map +1 -0
  26. package/dist/server/vnc-proxy.d.ts +7 -0
  27. package/dist/server/vnc-proxy.d.ts.map +1 -0
  28. package/dist/server/vnc-proxy.js +38 -0
  29. package/dist/server/vnc-proxy.js.map +1 -0
  30. package/dist/server/web-pages.d.ts +4 -0
  31. package/dist/server/web-pages.d.ts.map +1 -0
  32. package/dist/server/web-pages.js +157 -0
  33. package/dist/server/web-pages.js.map +1 -0
  34. package/dist/server/web-server.d.ts +18 -0
  35. package/dist/server/web-server.d.ts.map +1 -0
  36. package/dist/server/web-server.js +161 -0
  37. package/dist/server/web-server.js.map +1 -0
  38. package/dist/session/process-group.d.ts +33 -0
  39. package/dist/session/process-group.d.ts.map +1 -0
  40. package/dist/session/process-group.js +185 -0
  41. package/dist/session/process-group.js.map +1 -0
  42. package/dist/session/session-manager.d.ts +26 -0
  43. package/dist/session/session-manager.d.ts.map +1 -0
  44. package/dist/session/session-manager.js +133 -0
  45. package/dist/session/session-manager.js.map +1 -0
  46. package/dist/utils/config.d.ts +14 -0
  47. package/dist/utils/config.d.ts.map +1 -0
  48. package/dist/utils/config.js +72 -0
  49. package/dist/utils/config.js.map +1 -0
  50. package/dist/utils/logger.d.ts +9 -0
  51. package/dist/utils/logger.d.ts.map +1 -0
  52. package/dist/utils/logger.js +33 -0
  53. package/dist/utils/logger.js.map +1 -0
  54. package/dist/utils/types.d.ts +26 -0
  55. package/dist/utils/types.d.ts.map +1 -0
  56. package/dist/utils/types.js +2 -0
  57. package/dist/utils/types.js.map +1 -0
  58. package/package.json +42 -0
@@ -0,0 +1,133 @@
1
+ import * as fs from 'node:fs';
2
+ import * as path from 'node:path';
3
+ import * as crypto from 'node:crypto';
4
+ import { getSessionsPath } from '../utils/config.js';
5
+ import { log } from '../utils/logger.js';
6
+ import { ProcessGroup } from './process-group.js';
7
+ const PORT_BASE_DISPLAY = 33301;
8
+ const PORT_BASE_CDP = 33401;
9
+ const PORT_BASE_VNC = 33501;
10
+ export class SessionManager {
11
+ dataDir;
12
+ sessionsPath;
13
+ data;
14
+ processGroups = new Map();
15
+ constructor(dataDir) {
16
+ this.dataDir = dataDir;
17
+ this.sessionsPath = getSessionsPath(dataDir);
18
+ this.data = this.loadSessionsData();
19
+ }
20
+ loadSessionsData() {
21
+ if (fs.existsSync(this.sessionsPath)) {
22
+ try {
23
+ return JSON.parse(fs.readFileSync(this.sessionsPath, 'utf-8'));
24
+ }
25
+ catch {
26
+ log.warn('sessions.json 解析失败,使用空数据');
27
+ }
28
+ }
29
+ return { nextIndex: 0, sessions: [] };
30
+ }
31
+ saveSessionsData() {
32
+ fs.writeFileSync(this.sessionsPath, JSON.stringify(this.data, null, 2), 'utf-8');
33
+ }
34
+ sessionDir(id) {
35
+ return path.join(this.dataDir, id);
36
+ }
37
+ chromeDataDir(id) {
38
+ return path.join(this.sessionDir(id), 'chrome-data');
39
+ }
40
+ chromeLogPath(id) {
41
+ return path.join(this.sessionDir(id), 'chrome.log');
42
+ }
43
+ createSession(name) {
44
+ const id = crypto.randomBytes(8).toString('hex');
45
+ const index = this.data.nextIndex++;
46
+ const session = {
47
+ id,
48
+ name,
49
+ displayNum: PORT_BASE_DISPLAY + index,
50
+ cdpPort: PORT_BASE_CDP + index,
51
+ vncPort: PORT_BASE_VNC + index,
52
+ createdAt: new Date().toISOString(),
53
+ };
54
+ fs.mkdirSync(this.chromeDataDir(id), { recursive: true });
55
+ this.data.sessions.push(session);
56
+ this.saveSessionsData();
57
+ log.info(`会话已创建: ${name} (${id}), CDP=${session.cdpPort}, VNC=${session.vncPort}`);
58
+ return session;
59
+ }
60
+ async deleteSession(id) {
61
+ const index = this.data.sessions.findIndex(s => s.id === id);
62
+ if (index === -1)
63
+ return false;
64
+ await this.stopSession(id);
65
+ const dir = this.sessionDir(id);
66
+ if (fs.existsSync(dir)) {
67
+ fs.rmSync(dir, { recursive: true, force: true });
68
+ }
69
+ this.data.sessions.splice(index, 1);
70
+ this.saveSessionsData();
71
+ log.info(`会话已删除: ${id}`);
72
+ return true;
73
+ }
74
+ getSession(id) {
75
+ return this.data.sessions.find(s => s.id === id);
76
+ }
77
+ listSessions() {
78
+ return [...this.data.sessions];
79
+ }
80
+ async startSession(session) {
81
+ if (this.processGroups.has(session.id)) {
82
+ log.warn(`会话 ${session.id} 的进程组已存在`);
83
+ return;
84
+ }
85
+ const pg = new ProcessGroup({
86
+ sessionId: session.id,
87
+ displayNum: session.displayNum,
88
+ cdpPort: session.cdpPort,
89
+ vncPort: session.vncPort,
90
+ chromeDataDir: this.chromeDataDir(session.id),
91
+ chromeLogPath: this.chromeLogPath(session.id),
92
+ });
93
+ await pg.start();
94
+ this.processGroups.set(session.id, pg);
95
+ }
96
+ async stopSession(id) {
97
+ const pg = this.processGroups.get(id);
98
+ if (pg) {
99
+ await pg.stop();
100
+ this.processGroups.delete(id);
101
+ }
102
+ }
103
+ async restoreSessions() {
104
+ for (const session of this.data.sessions) {
105
+ log.info(`恢复会话: ${session.name} (${session.id})`);
106
+ try {
107
+ await this.startSession(session);
108
+ }
109
+ catch (err) {
110
+ log.error(`恢复会话 ${session.id} 失败:`, err instanceof Error ? err.message : err);
111
+ }
112
+ }
113
+ }
114
+ async stopAllSessions() {
115
+ for (const [id, pg] of this.processGroups) {
116
+ log.info(`停止会话: ${id}`);
117
+ await pg.stop();
118
+ }
119
+ this.processGroups.clear();
120
+ }
121
+ getProcessGroup(id) {
122
+ return this.processGroups.get(id);
123
+ }
124
+ getSessionTabCount(id) {
125
+ const pg = this.processGroups.get(id);
126
+ return pg?.getTabCount() ?? 0;
127
+ }
128
+ getSessionUptime(id) {
129
+ const pg = this.processGroups.get(id);
130
+ return pg?.getUptime() ?? 0;
131
+ }
132
+ }
133
+ //# sourceMappingURL=session-manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-manager.js","sourceRoot":"","sources":["../../src/session/session-manager.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ import type { ServerConfig } from './types.js';
2
+ export declare function resolveDataDir(dataDir?: string): string;
3
+ export declare function ensureDataDir(dataDir: string): void;
4
+ export declare function getServerConfigPath(dataDir: string): string;
5
+ export declare function getPidPath(dataDir: string): string;
6
+ export declare function getSessionsPath(dataDir: string): string;
7
+ export declare function getLogPath(dataDir: string): string;
8
+ export declare function saveServerConfig(config: ServerConfig): void;
9
+ export declare function loadServerConfig(dataDir: string): ServerConfig | null;
10
+ export declare function savePid(dataDir: string, pid: number): void;
11
+ export declare function loadPid(dataDir: string): number | null;
12
+ export declare function removePid(dataDir: string): void;
13
+ export declare function isProcessRunning(pid: number): boolean;
14
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/utils/config.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAI/C,wBAAgB,cAAc,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAEvD;AAED,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAEnD;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAE3D;AAED,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAElD;AAED,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAEvD;AAED,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAElD;AAED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,YAAY,GAAG,IAAI,CAI3D;AAED,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI,CAQrE;AAED,wBAAgB,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI,CAE1D;AAED,wBAAgB,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAStD;AAED,wBAAgB,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAO/C;AAED,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAOrD"}
@@ -0,0 +1,72 @@
1
+ import * as fs from 'node:fs';
2
+ import * as path from 'node:path';
3
+ import * as os from 'node:os';
4
+ const DEFAULT_DATA_DIR = path.join(os.homedir(), '.browser-server');
5
+ export function resolveDataDir(dataDir) {
6
+ return dataDir || DEFAULT_DATA_DIR;
7
+ }
8
+ export function ensureDataDir(dataDir) {
9
+ fs.mkdirSync(dataDir, { recursive: true });
10
+ }
11
+ export function getServerConfigPath(dataDir) {
12
+ return path.join(dataDir, 'server.json');
13
+ }
14
+ export function getPidPath(dataDir) {
15
+ return path.join(dataDir, 'server.pid');
16
+ }
17
+ export function getSessionsPath(dataDir) {
18
+ return path.join(dataDir, 'sessions.json');
19
+ }
20
+ export function getLogPath(dataDir) {
21
+ return path.join(dataDir, 'server.log');
22
+ }
23
+ export function saveServerConfig(config) {
24
+ ensureDataDir(config.dataDir);
25
+ const configPath = getServerConfigPath(config.dataDir);
26
+ fs.writeFileSync(configPath, JSON.stringify(config, null, 2), 'utf-8');
27
+ }
28
+ export function loadServerConfig(dataDir) {
29
+ const configPath = getServerConfigPath(dataDir);
30
+ if (!fs.existsSync(configPath))
31
+ return null;
32
+ try {
33
+ return JSON.parse(fs.readFileSync(configPath, 'utf-8'));
34
+ }
35
+ catch {
36
+ return null;
37
+ }
38
+ }
39
+ export function savePid(dataDir, pid) {
40
+ fs.writeFileSync(getPidPath(dataDir), String(pid), 'utf-8');
41
+ }
42
+ export function loadPid(dataDir) {
43
+ const pidPath = getPidPath(dataDir);
44
+ if (!fs.existsSync(pidPath))
45
+ return null;
46
+ try {
47
+ const pid = parseInt(fs.readFileSync(pidPath, 'utf-8').trim(), 10);
48
+ return isNaN(pid) ? null : pid;
49
+ }
50
+ catch {
51
+ return null;
52
+ }
53
+ }
54
+ export function removePid(dataDir) {
55
+ const pidPath = getPidPath(dataDir);
56
+ try {
57
+ fs.unlinkSync(pidPath);
58
+ }
59
+ catch {
60
+ // ignore
61
+ }
62
+ }
63
+ export function isProcessRunning(pid) {
64
+ try {
65
+ process.kill(pid, 0);
66
+ return true;
67
+ }
68
+ catch {
69
+ return false;
70
+ }
71
+ }
72
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/utils/config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ export declare function initLogger(dataDir: string): void;
2
+ export declare const log: {
3
+ info: (...args: unknown[]) => void;
4
+ warn: (...args: unknown[]) => void;
5
+ error: (...args: unknown[]) => void;
6
+ debug: (...args: unknown[]) => void;
7
+ };
8
+ export declare function closeLogger(): void;
9
+ //# sourceMappingURL=logger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/utils/logger.ts"],"names":[],"mappings":"AAKA,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAGhD;AAkBD,eAAO,MAAM,GAAG;oBACE,OAAO,EAAE;oBACT,OAAO,EAAE;qBACR,OAAO,EAAE;qBACT,OAAO,EAAE;CAC3B,CAAC;AAEF,wBAAgB,WAAW,IAAI,IAAI,CAGlC"}
@@ -0,0 +1,33 @@
1
+ import * as fs from 'node:fs';
2
+ import { getLogPath } from './config.js';
3
+ let logStream = null;
4
+ export function initLogger(dataDir) {
5
+ const logPath = getLogPath(dataDir);
6
+ logStream = fs.createWriteStream(logPath, { flags: 'a' });
7
+ }
8
+ function timestamp() {
9
+ return new Date().toISOString();
10
+ }
11
+ function write(level, ...args) {
12
+ const msg = `[${timestamp()}] [${level}] ${args.map(a => typeof a === 'string' ? a : JSON.stringify(a)).join(' ')}`;
13
+ if (logStream) {
14
+ logStream.write(msg + '\n');
15
+ }
16
+ if (level === 'ERROR') {
17
+ console.error(msg);
18
+ }
19
+ else {
20
+ console.log(msg);
21
+ }
22
+ }
23
+ export const log = {
24
+ info: (...args) => write('INFO', ...args),
25
+ warn: (...args) => write('WARN', ...args),
26
+ error: (...args) => write('ERROR', ...args),
27
+ debug: (...args) => write('DEBUG', ...args),
28
+ };
29
+ export function closeLogger() {
30
+ logStream?.end();
31
+ logStream = null;
32
+ }
33
+ //# sourceMappingURL=logger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.js","sourceRoot":"","sources":["../../src/utils/logger.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,IAAI,SAAS,GAA0B,IAAI,CAAC;AAE5C,MAAM,UAAU,UAAU,CAAC,OAAe;IACxC,MAAM,OAAO,GAAG,UAAU,CAAC,OAAO,CAAC,CAAC;IACpC,SAAS,GAAG,EAAE,CAAC,iBAAiB,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC;AAC5D,CAAC;AAED,SAAS,SAAS;IAChB,OAAO,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;AAClC,CAAC;AAED,SAAS,KAAK,CAAC,KAAa,EAAE,GAAG,IAAe;IAC9C,MAAM,GAAG,GAAG,IAAI,SAAS,EAAE,MAAM,KAAK,KAAK,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;IACpH,IAAI,SAAS,EAAE,CAAC;QACd,SAAS,CAAC,KAAK,CAAC,GAAG,GAAG,IAAI,CAAC,CAAC;IAC9B,CAAC;IACD,IAAI,KAAK,KAAK,OAAO,EAAE,CAAC;QACtB,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACrB,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IACnB,CAAC;AACH,CAAC;AAED,MAAM,CAAC,MAAM,GAAG,GAAG;IACjB,IAAI,EAAE,CAAC,GAAG,IAAe,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,EAAE,GAAG,IAAI,CAAC;IACpD,IAAI,EAAE,CAAC,GAAG,IAAe,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,EAAE,GAAG,IAAI,CAAC;IACpD,KAAK,EAAE,CAAC,GAAG,IAAe,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC;IACtD,KAAK,EAAE,CAAC,GAAG,IAAe,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC;CACvD,CAAC;AAEF,MAAM,UAAU,WAAW;IACzB,SAAS,EAAE,GAAG,EAAE,CAAC;IACjB,SAAS,GAAG,IAAI,CAAC;AACnB,CAAC"}
@@ -0,0 +1,26 @@
1
+ export interface ServerConfig {
2
+ webPort: number;
3
+ mcpPort: number;
4
+ host: string;
5
+ user: string;
6
+ pass: string;
7
+ dataDir: string;
8
+ }
9
+ export interface SessionInfo {
10
+ id: string;
11
+ name: string;
12
+ displayNum: number;
13
+ cdpPort: number;
14
+ vncPort: number;
15
+ createdAt: string;
16
+ }
17
+ export interface SessionsData {
18
+ nextIndex: number;
19
+ sessions: SessionInfo[];
20
+ }
21
+ export interface ProcessGroupPids {
22
+ xvfb?: number;
23
+ chromium?: number;
24
+ vnc?: number;
25
+ }
26
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/utils/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,WAAW,EAAE,CAAC;CACzB;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,GAAG,CAAC,EAAE,MAAM,CAAC;CACd"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/utils/types.ts"],"names":[],"mappings":""}
package/package.json ADDED
@@ -0,0 +1,42 @@
1
+ {
2
+ "name": "@cjwddz/browser-server",
3
+ "version": "0.1.0-alpha",
4
+ "type": "module",
5
+ "description": "Self-hosted headless browser service for AI agents — persistent sessions, web viewer, MCP integration",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "bin": {
9
+ "browser-server": "./dist/cli.js"
10
+ },
11
+ "files": [
12
+ "dist"
13
+ ],
14
+ "scripts": {
15
+ "build": "tsc",
16
+ "dev": "tsc --watch",
17
+ "lint": "tsc --noEmit"
18
+ },
19
+ "keywords": [
20
+ "browser",
21
+ "headless",
22
+ "mcp",
23
+ "ai-agent",
24
+ "playwright",
25
+ "vnc",
26
+ "browser-service"
27
+ ],
28
+ "author": "cjwddz",
29
+ "license": "MIT",
30
+ "dependencies": {
31
+ "@modelcontextprotocol/sdk": "^1.12.1",
32
+ "commander": "^11.1.0",
33
+ "playwright-core": "^1.49.0",
34
+ "ws": "^8.18.0",
35
+ "zod": "^4.3.6"
36
+ },
37
+ "devDependencies": {
38
+ "@types/node": "^20.0.0",
39
+ "@types/ws": "^8.5.0",
40
+ "typescript": "^5.0.0"
41
+ }
42
+ }