cerevox 0.1.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/README.md +388 -0
- package/dist/cli/cerevox-run.d.ts +3 -0
- package/dist/cli/cerevox-run.d.ts.map +1 -0
- package/dist/cli/cerevox-run.js +275 -0
- package/dist/cli/cerevox-run.js.map +1 -0
- package/dist/core/base.d.ts +57 -0
- package/dist/core/base.d.ts.map +1 -0
- package/dist/core/base.js +77 -0
- package/dist/core/base.js.map +1 -0
- package/dist/core/browser.d.ts +30 -0
- package/dist/core/browser.d.ts.map +1 -0
- package/dist/core/browser.js +107 -0
- package/dist/core/browser.js.map +1 -0
- package/dist/core/cerevox.d.ts +34 -0
- package/dist/core/cerevox.d.ts.map +1 -0
- package/dist/core/cerevox.js +153 -0
- package/dist/core/cerevox.js.map +1 -0
- package/dist/core/code-runner.d.ts +22 -0
- package/dist/core/code-runner.d.ts.map +1 -0
- package/dist/core/code-runner.js +56 -0
- package/dist/core/code-runner.js.map +1 -0
- package/dist/core/file-system.d.ts +116 -0
- package/dist/core/file-system.d.ts.map +1 -0
- package/dist/core/file-system.js +383 -0
- package/dist/core/file-system.js.map +1 -0
- package/dist/core/session.d.ts +32 -0
- package/dist/core/session.d.ts.map +1 -0
- package/dist/core/session.js +113 -0
- package/dist/core/session.js.map +1 -0
- package/dist/core/terminal.d.ts +104 -0
- package/dist/core/terminal.d.ts.map +1 -0
- package/dist/core/terminal.js +202 -0
- package/dist/core/terminal.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +29 -0
- package/dist/index.js.map +1 -0
- package/dist/utils/auth.d.ts +4 -0
- package/dist/utils/auth.d.ts.map +1 -0
- package/dist/utils/auth.js +14 -0
- package/dist/utils/auth.js.map +1 -0
- package/dist/utils/constants.d.ts +2 -0
- package/dist/utils/constants.d.ts.map +1 -0
- package/dist/utils/constants.js +5 -0
- package/dist/utils/constants.js.map +1 -0
- package/dist/utils/detect-code.d.ts +30 -0
- package/dist/utils/detect-code.d.ts.map +1 -0
- package/dist/utils/detect-code.js +95 -0
- package/dist/utils/detect-code.js.map +1 -0
- package/dist/utils/logger.d.ts +15 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +127 -0
- package/dist/utils/logger.js.map +1 -0
- package/package.json +86 -0
package/README.md
ADDED
|
@@ -0,0 +1,388 @@
|
|
|
1
|
+
# Cerevox
|
|
2
|
+
|
|
3
|
+
> TypeScript SDK for browser automation and secure command execution in highly available and scalable cloud environments
|
|
4
|
+
|
|
5
|
+
[](https://badge.fury.io/js/cerevox)
|
|
6
|
+
[](https://www.typescriptlang.org/)
|
|
7
|
+
[](https://nodejs.org/)
|
|
8
|
+
[](https://opensource.org/licenses/ISC)
|
|
9
|
+
|
|
10
|
+
## 🎯 项目概述
|
|
11
|
+
|
|
12
|
+
Cerevox 是一个基于 TypeScript 的浏览器自动化和安全命令执行 SDK,专为高可用和可扩展的云浏览器环境设计。它提供了完整的沙箱环境管理、浏览器控制、文件系统操作和终端命令执行功能。
|
|
13
|
+
|
|
14
|
+
### 核心特性
|
|
15
|
+
|
|
16
|
+
- 🚀 **云浏览器自动化** - 基于 E2B 和 Playwright 的高性能浏览器控制
|
|
17
|
+
- 🔒 **安全沙箱环境** - 隔离的命令执行环境,确保安全性
|
|
18
|
+
- 📁 **文件系统操作** - 完整的文件上传、下载、读写功能
|
|
19
|
+
- 💻 **终端命令执行** - 实时流式输出的命令执行
|
|
20
|
+
- 📊 **高性能日志** - 基于 Pino 的结构化日志系统
|
|
21
|
+
- 🎨 **TypeScript 严格模式** - 完整的类型安全保障
|
|
22
|
+
- 🔧 **模块化设计** - 高内聚低耦合的架构设计
|
|
23
|
+
|
|
24
|
+
## 📦 安装
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
# 使用 pnpm (推荐)
|
|
28
|
+
pnpm add cerevox
|
|
29
|
+
|
|
30
|
+
# 使用 npm
|
|
31
|
+
npm install cerevox
|
|
32
|
+
|
|
33
|
+
# 使用 yarn
|
|
34
|
+
yarn add cerevox
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## 🚀 快速开始
|
|
38
|
+
|
|
39
|
+
### 基础使用
|
|
40
|
+
|
|
41
|
+
```typescript
|
|
42
|
+
import { Cerevox } from 'cerevox';
|
|
43
|
+
import { chromium } from 'playwright';
|
|
44
|
+
|
|
45
|
+
async function main() {
|
|
46
|
+
// 初始化 Cerevox 实例
|
|
47
|
+
const cerevox = new Cerevox({
|
|
48
|
+
apiKey: 'your-api-key', // 或通过环境变量 CEREVOX_API_KEY
|
|
49
|
+
debug: true
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
// 启动云浏览器会话
|
|
53
|
+
const session = await cerevox.launch({
|
|
54
|
+
browser: {
|
|
55
|
+
type: 'chrome-stable',
|
|
56
|
+
headless: false,
|
|
57
|
+
liveview: true
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
// 连接到浏览器
|
|
62
|
+
const browser = await chromium.connectOverCDP(session.browser.endpoint);
|
|
63
|
+
const page = await browser.newPage();
|
|
64
|
+
|
|
65
|
+
// 执行浏览器操作
|
|
66
|
+
await page.goto('https://example.com');
|
|
67
|
+
await page.screenshot({ path: './screenshot.png' });
|
|
68
|
+
|
|
69
|
+
// 清理资源
|
|
70
|
+
await page.close();
|
|
71
|
+
await browser.close();
|
|
72
|
+
await session.close();
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
main().catch(console.error);
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### 文件系统操作
|
|
79
|
+
|
|
80
|
+
```typescript
|
|
81
|
+
import { Cerevox } from 'cerevox';
|
|
82
|
+
|
|
83
|
+
async function fileOperations() {
|
|
84
|
+
const cerevox = new Cerevox();
|
|
85
|
+
const session = await cerevox.launch();
|
|
86
|
+
|
|
87
|
+
// 写入文件
|
|
88
|
+
await session.files.write('/home/user/test.txt', 'Hello World!');
|
|
89
|
+
|
|
90
|
+
// 读取文件
|
|
91
|
+
const content = await session.files.read('/home/user/test.txt');
|
|
92
|
+
console.log(content); // "Hello World!"
|
|
93
|
+
|
|
94
|
+
// 上传本地文件
|
|
95
|
+
await session.files.upload('./local-file.txt', '/home/user/remote-file.txt');
|
|
96
|
+
|
|
97
|
+
// 下载远程文件
|
|
98
|
+
await session.files.download('/home/user/remote-file.txt', './downloaded-file.txt');
|
|
99
|
+
|
|
100
|
+
// 列出目录内容
|
|
101
|
+
const files = await session.files.listFiles('/home/user');
|
|
102
|
+
console.log(files);
|
|
103
|
+
|
|
104
|
+
await session.close();
|
|
105
|
+
}
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### 终端命令执行
|
|
109
|
+
|
|
110
|
+
```typescript
|
|
111
|
+
import { Cerevox } from 'cerevox';
|
|
112
|
+
|
|
113
|
+
async function runCommands() {
|
|
114
|
+
const cerevox = new Cerevox();
|
|
115
|
+
const session = await cerevox.launch();
|
|
116
|
+
|
|
117
|
+
// 执行命令并获取结果
|
|
118
|
+
const result = await session.terminal.run('ls -la');
|
|
119
|
+
console.log(await result.json());
|
|
120
|
+
|
|
121
|
+
// 流式输出
|
|
122
|
+
const process = await session.terminal.run('npm install');
|
|
123
|
+
process.stdout.pipe(process.stdout);
|
|
124
|
+
process.stderr.pipe(process.stderr);
|
|
125
|
+
await process.end();
|
|
126
|
+
|
|
127
|
+
await session.close();
|
|
128
|
+
}
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
## 🏗️ 架构设计
|
|
132
|
+
|
|
133
|
+
### 核心模块
|
|
134
|
+
|
|
135
|
+
- **Cerevox** - 主入口类,负责会话管理和配置
|
|
136
|
+
- **Session** - 会话管理,提供统一的资源访问接口
|
|
137
|
+
- **Browser** - 浏览器控制,基于 Playwright 的浏览器操作
|
|
138
|
+
- **FileSystem** - 文件系统操作,支持本地和远程文件管理
|
|
139
|
+
- **Terminal** - 终端命令执行,支持实时流式输出
|
|
140
|
+
- **Logger** - 高性能日志系统,基于 Pino 实现
|
|
141
|
+
|
|
142
|
+
### 技术栈
|
|
143
|
+
|
|
144
|
+
- **语言**: TypeScript 5.8+ (严格模式)
|
|
145
|
+
- **运行时**: Node.js 18+
|
|
146
|
+
- **模块系统**: CommonJS
|
|
147
|
+
- **包管理**: pnpm
|
|
148
|
+
- **浏览器引擎**: Playwright Core
|
|
149
|
+
- **沙箱环境**: E2B
|
|
150
|
+
- **日志系统**: Pino
|
|
151
|
+
- **构建工具**: TypeScript Compiler + esbuild
|
|
152
|
+
|
|
153
|
+
## 📚 API 文档
|
|
154
|
+
|
|
155
|
+
### Cerevox 类
|
|
156
|
+
|
|
157
|
+
#### 构造函数
|
|
158
|
+
|
|
159
|
+
```typescript
|
|
160
|
+
const cerevox = new Cerevox({
|
|
161
|
+
apiKey?: string; // API 密钥,默认从环境变量读取
|
|
162
|
+
debug?: boolean; // 调试模式,默认 false
|
|
163
|
+
logLevel?: 'debug' | 'info' | 'warn' | 'error' | 'fatal'; // 日志级别
|
|
164
|
+
});
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
#### 方法
|
|
168
|
+
|
|
169
|
+
- `launch(config?: ILaunchConfig): Promise<Session>` - 启动新的浏览器会话
|
|
170
|
+
- `connect(sandboxId: string): Promise<Session>` - 连接到现有沙箱
|
|
171
|
+
|
|
172
|
+
### Session 类
|
|
173
|
+
|
|
174
|
+
#### 属性
|
|
175
|
+
|
|
176
|
+
- `browser: Browser` - 浏览器控制实例
|
|
177
|
+
- `files: FileSystem` - 文件系统操作实例
|
|
178
|
+
- `terminal: Terminal` - 终端操作实例
|
|
179
|
+
|
|
180
|
+
#### 方法
|
|
181
|
+
|
|
182
|
+
- `getHost(): string` - 获取会话主机地址
|
|
183
|
+
- `close(force?: boolean): Promise<void>` - 关闭会话
|
|
184
|
+
|
|
185
|
+
### 配置接口
|
|
186
|
+
|
|
187
|
+
```typescript
|
|
188
|
+
interface IBrowserConfig {
|
|
189
|
+
type?: 'chromium' | 'chrome-stable'; // 浏览器类型
|
|
190
|
+
args?: string[]; // 浏览器启动参数
|
|
191
|
+
headless?: boolean; // 无头模式
|
|
192
|
+
liveview?: boolean; // 实时预览
|
|
193
|
+
adblock?: boolean; // 广告拦截
|
|
194
|
+
webgl?: boolean; // WebGL 支持
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
interface ILaunchConfig {
|
|
198
|
+
browser?: IBrowserConfig; // 浏览器配置
|
|
199
|
+
timeoutMS?: number; // 超时时间
|
|
200
|
+
keepAliveMS?: number; // 保活时间
|
|
201
|
+
metadata?: Record<string, string>; // 元数据
|
|
202
|
+
}
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
## 🔧 开发指南
|
|
206
|
+
|
|
207
|
+
### 环境要求
|
|
208
|
+
|
|
209
|
+
- Node.js 18+
|
|
210
|
+
- pnpm 8+
|
|
211
|
+
- TypeScript 5.8+
|
|
212
|
+
|
|
213
|
+
### 本地开发
|
|
214
|
+
|
|
215
|
+
```bash
|
|
216
|
+
# 克隆项目
|
|
217
|
+
git clone https://github.com/liubei-ai/cerevox.git
|
|
218
|
+
cd cerevox
|
|
219
|
+
|
|
220
|
+
# 安装依赖
|
|
221
|
+
pnpm install
|
|
222
|
+
|
|
223
|
+
# 构建项目
|
|
224
|
+
pnpm build
|
|
225
|
+
|
|
226
|
+
# 运行示例
|
|
227
|
+
pnpm dev
|
|
228
|
+
|
|
229
|
+
# 代码检查
|
|
230
|
+
pnpm lint
|
|
231
|
+
|
|
232
|
+
# 代码格式化
|
|
233
|
+
pnpm format
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
### 项目结构
|
|
237
|
+
|
|
238
|
+
```
|
|
239
|
+
cerevox/
|
|
240
|
+
├── src/ # 核心源码
|
|
241
|
+
│ ├── index.ts # 主入口文件
|
|
242
|
+
│ ├── core/ # 核心模块
|
|
243
|
+
│ │ ├── cerevox.ts # 主类
|
|
244
|
+
│ │ ├── session.ts # 会话管理
|
|
245
|
+
│ │ ├── browser.ts # 浏览器控制
|
|
246
|
+
│ │ ├── file-system.ts # 文件系统
|
|
247
|
+
│ │ └── terminal.ts # 终端操作
|
|
248
|
+
│ └── utils/ # 工具函数
|
|
249
|
+
│ └── logger.ts # 日志系统
|
|
250
|
+
├── sandbox/ # 沙箱环境代码
|
|
251
|
+
├── examples/ # 使用示例
|
|
252
|
+
├── scripts/ # 构建脚本
|
|
253
|
+
└── dist/ # 编译输出
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
## 🧪 测试
|
|
257
|
+
|
|
258
|
+
```bash
|
|
259
|
+
# 运行测试
|
|
260
|
+
pnpm test
|
|
261
|
+
|
|
262
|
+
# 运行测试并生成覆盖率报告
|
|
263
|
+
pnpm test:coverage
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
## 🛠️ Template 构建
|
|
267
|
+
|
|
268
|
+
Cerevox 支持构建自定义的 E2B 沙盒模板,提供预配置的浏览器环境:
|
|
269
|
+
|
|
270
|
+
### 构建 Chromium Template
|
|
271
|
+
|
|
272
|
+
```bash
|
|
273
|
+
# 构建 Chromium 模板
|
|
274
|
+
pnpm run deploy:chromium
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
这将创建一个名为 `cerevox-chromium` 的模板,包含:
|
|
278
|
+
- Chromium 浏览器
|
|
279
|
+
- 4GB 内存,4核 CPU
|
|
280
|
+
- 预配置的沙盒环境
|
|
281
|
+
|
|
282
|
+
### 构建 Chrome Stable Template
|
|
283
|
+
|
|
284
|
+
```bash
|
|
285
|
+
# 构建 Chrome Stable 模板
|
|
286
|
+
pnpm run deploy:chrome
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
这将创建一个名为 `cerevox-chrome-stable` 的模板,包含:
|
|
290
|
+
- Chrome 稳定版浏览器
|
|
291
|
+
- 4GB 内存,4核 CPU
|
|
292
|
+
- 预配置的沙盒环境
|
|
293
|
+
|
|
294
|
+
### Template 配置
|
|
295
|
+
|
|
296
|
+
模板配置文件位于:
|
|
297
|
+
- `chromium.toml` - Chromium 模板配置
|
|
298
|
+
- `chrome-stable.toml` - Chrome Stable 模板配置
|
|
299
|
+
|
|
300
|
+
## 🖥️ CLI 工具 - cerevox-run
|
|
301
|
+
|
|
302
|
+
Cerevox 提供了一个强大的 CLI 工具,可以直接运行 TypeScript/JavaScript 文件在沙盒环境中:
|
|
303
|
+
|
|
304
|
+
### 安装和使用
|
|
305
|
+
|
|
306
|
+
```bash
|
|
307
|
+
# 通过 npx 直接运行(推荐)
|
|
308
|
+
npx cerevox-run your-script.ts
|
|
309
|
+
|
|
310
|
+
# 或者全局安装
|
|
311
|
+
npm install -g cerevox
|
|
312
|
+
cerevox-run your-script.ts
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
### CLI 选项
|
|
316
|
+
|
|
317
|
+
```bash
|
|
318
|
+
cerevox-run [options] <file>
|
|
319
|
+
|
|
320
|
+
参数:
|
|
321
|
+
file 要运行的 JavaScript 或 TypeScript 文件
|
|
322
|
+
|
|
323
|
+
选项:
|
|
324
|
+
-V, --version 显示版本号
|
|
325
|
+
-k, --key <string> Cerevox API 密钥(可选,如果设置了 CEREVOX_API_KEY 环境变量)
|
|
326
|
+
-l, --listen <number> 监听端口号
|
|
327
|
+
-h, --help 显示帮助信息
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
### 使用示例
|
|
331
|
+
|
|
332
|
+
```bash
|
|
333
|
+
# 基础使用
|
|
334
|
+
npx cerevox-run script.ts
|
|
335
|
+
|
|
336
|
+
# 指定 API 密钥
|
|
337
|
+
npx cerevox-run -k your-api-key script.ts
|
|
338
|
+
|
|
339
|
+
# 指定监听端口
|
|
340
|
+
npx cerevox-run -l 3000 web-server.ts
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
### 环境变量配置
|
|
344
|
+
|
|
345
|
+
创建 `.env.cerevox` 文件:
|
|
346
|
+
|
|
347
|
+
```bash
|
|
348
|
+
CEREVOX_API_KEY=your-api-key-here
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
### CLI 特性
|
|
352
|
+
|
|
353
|
+
- **自动代码转换**:自动将 Playwright 的 `launch()` 方法替换为 `connectOverCDP()`
|
|
354
|
+
- **TypeScript 支持**:原生支持 TypeScript 文件
|
|
355
|
+
- **实时预览**:非 headless 模式下自动打开浏览器预览
|
|
356
|
+
- **智能打包**:使用 esbuild 进行代码打包和优化
|
|
357
|
+
- **环境管理**:自动创建和管理 API 密钥配置文件
|
|
358
|
+
|
|
359
|
+
## 📄 许可证
|
|
360
|
+
|
|
361
|
+
ISC License - 详见 [LICENSE](LICENSE) 文件
|
|
362
|
+
|
|
363
|
+
## 🤝 贡献
|
|
364
|
+
|
|
365
|
+
欢迎提交 Issue 和 Pull Request!
|
|
366
|
+
|
|
367
|
+
### 开发规范
|
|
368
|
+
|
|
369
|
+
- 遵循 TypeScript 严格模式
|
|
370
|
+
- 使用 ESLint + Prettier 代码规范
|
|
371
|
+
- 所有函数必须包含类型注解
|
|
372
|
+
- 提交前运行 `pnpm lint` 检查代码
|
|
373
|
+
|
|
374
|
+
## 📞 支持
|
|
375
|
+
|
|
376
|
+
- 📧 Email: support@cerevox.io
|
|
377
|
+
- 🐛 Issues: [GitHub Issues](https://github.com/liubei-ai/cerevox/issues)
|
|
378
|
+
- 📖 文档: [官方文档](https://github.com/liubei-ai/cerevox#readme)
|
|
379
|
+
|
|
380
|
+
## 🔗 相关链接
|
|
381
|
+
|
|
382
|
+
- [E2B Platform](https://e2b.dev/) - 云沙箱环境
|
|
383
|
+
- [Playwright](https://playwright.dev/) - 浏览器自动化
|
|
384
|
+
- [Pino](https://getpino.io/) - 高性能日志
|
|
385
|
+
|
|
386
|
+
---
|
|
387
|
+
|
|
388
|
+
**Cerevox** - 让浏览器自动化更简单、更安全、更高效 🚀
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cerevox-run.d.ts","sourceRoot":"","sources":["../../src/cli/cerevox-run.ts"],"names":[],"mappings":";AAmSA,wBAAgB,GAAG,SAElB"}
|
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
4
|
+
if (k2 === undefined) k2 = k;
|
|
5
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
6
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
7
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
8
|
+
}
|
|
9
|
+
Object.defineProperty(o, k2, desc);
|
|
10
|
+
}) : (function(o, m, k, k2) {
|
|
11
|
+
if (k2 === undefined) k2 = k;
|
|
12
|
+
o[k2] = m[k];
|
|
13
|
+
}));
|
|
14
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
15
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
16
|
+
}) : function(o, v) {
|
|
17
|
+
o["default"] = v;
|
|
18
|
+
});
|
|
19
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
20
|
+
var ownKeys = function(o) {
|
|
21
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
22
|
+
var ar = [];
|
|
23
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
24
|
+
return ar;
|
|
25
|
+
};
|
|
26
|
+
return ownKeys(o);
|
|
27
|
+
};
|
|
28
|
+
return function (mod) {
|
|
29
|
+
if (mod && mod.__esModule) return mod;
|
|
30
|
+
var result = {};
|
|
31
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
32
|
+
__setModuleDefault(result, mod);
|
|
33
|
+
return result;
|
|
34
|
+
};
|
|
35
|
+
})();
|
|
36
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
37
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
38
|
+
};
|
|
39
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
40
|
+
exports.run = run;
|
|
41
|
+
const commander_1 = require("commander");
|
|
42
|
+
const node_fs_1 = require("node:fs");
|
|
43
|
+
const node_path_1 = require("node:path");
|
|
44
|
+
const dotenv_1 = require("dotenv");
|
|
45
|
+
const readline = __importStar(require("node:readline"));
|
|
46
|
+
const esbuild_1 = require("esbuild");
|
|
47
|
+
const ts = __importStar(require("typescript"));
|
|
48
|
+
const open_1 = __importDefault(require("open"));
|
|
49
|
+
const __1 = __importDefault(require(".."));
|
|
50
|
+
const promises_1 = require("node:timers/promises");
|
|
51
|
+
// Load environment variables
|
|
52
|
+
(0, dotenv_1.config)({
|
|
53
|
+
path: ['.env.cerevox', '.env'],
|
|
54
|
+
});
|
|
55
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
56
|
+
const VERSION = require('../../package.json').version;
|
|
57
|
+
// esbuild plugin to replace chromium.launch and chromium.launchPersistentContext with chromium.connectOverCDP
|
|
58
|
+
function createChromiumReplacePlugin(wsUrl, headlessRef) {
|
|
59
|
+
return {
|
|
60
|
+
name: 'chromium-replace',
|
|
61
|
+
setup(build) {
|
|
62
|
+
build.onLoad({ filter: /\.(js|ts|mjs)$/ }, async (args) => {
|
|
63
|
+
const fs = await Promise.resolve().then(() => __importStar(require('fs')));
|
|
64
|
+
const contents = fs.readFileSync(args.path, 'utf8');
|
|
65
|
+
// Use TypeScript AST to transform the code
|
|
66
|
+
const isTypeScript = args.path.endsWith('.ts');
|
|
67
|
+
const sourceFile = ts.createSourceFile(args.path, contents, ts.ScriptTarget.Latest, true, isTypeScript ? ts.ScriptKind.TS : ts.ScriptKind.JS);
|
|
68
|
+
const transformer = context => {
|
|
69
|
+
return sourceFile => {
|
|
70
|
+
const visitor = (node) => {
|
|
71
|
+
// Check for method calls like browserType.launch() or browserType.launchPersistentContext()
|
|
72
|
+
if (ts.isCallExpression(node) &&
|
|
73
|
+
ts.isPropertyAccessExpression(node.expression)) {
|
|
74
|
+
const methodName = node.expression.name.text;
|
|
75
|
+
if (methodName === 'launch' ||
|
|
76
|
+
methodName === 'launchPersistentContext') {
|
|
77
|
+
// Extract headless parameter if present
|
|
78
|
+
if (node.arguments.length > 0) {
|
|
79
|
+
const firstArg = node.arguments[0];
|
|
80
|
+
if (ts.isObjectLiteralExpression(firstArg)) {
|
|
81
|
+
for (const property of firstArg.properties) {
|
|
82
|
+
if (ts.isPropertyAssignment(property) &&
|
|
83
|
+
ts.isIdentifier(property.name) &&
|
|
84
|
+
property.name.text === 'headless') {
|
|
85
|
+
// Extract headless value
|
|
86
|
+
if (property.initializer.kind ===
|
|
87
|
+
ts.SyntaxKind.TrueKeyword) {
|
|
88
|
+
headlessRef.value = true;
|
|
89
|
+
}
|
|
90
|
+
else if (property.initializer.kind ===
|
|
91
|
+
ts.SyntaxKind.FalseKeyword) {
|
|
92
|
+
headlessRef.value = false;
|
|
93
|
+
}
|
|
94
|
+
break;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
// Replace with connectOverCDP call
|
|
100
|
+
return ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(node.expression.expression, // Keep the browserType object
|
|
101
|
+
ts.factory.createIdentifier('connectOverCDP')), undefined, [ts.factory.createStringLiteral(wsUrl)]);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return ts.visitEachChild(node, visitor, context);
|
|
105
|
+
};
|
|
106
|
+
return ts.visitNode(sourceFile, visitor);
|
|
107
|
+
};
|
|
108
|
+
};
|
|
109
|
+
const result = ts.transform(sourceFile, [transformer]);
|
|
110
|
+
const printer = ts.createPrinter();
|
|
111
|
+
const transformedCode = printer.printFile(result.transformed[0]);
|
|
112
|
+
result.dispose();
|
|
113
|
+
return {
|
|
114
|
+
contents: transformedCode,
|
|
115
|
+
loader: args.path.endsWith('.ts') ? 'ts' : 'js',
|
|
116
|
+
};
|
|
117
|
+
});
|
|
118
|
+
},
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
async function buildBundleCode(file, session) {
|
|
122
|
+
try {
|
|
123
|
+
// Resolve the absolute path of the file
|
|
124
|
+
const filePath = (0, node_path_1.resolve)(file);
|
|
125
|
+
// Check if file exists
|
|
126
|
+
if (!(0, node_fs_1.existsSync)(filePath)) {
|
|
127
|
+
throw new Error(`File not found: ${filePath}`);
|
|
128
|
+
}
|
|
129
|
+
const wsUrl = session.browser.endpoint;
|
|
130
|
+
const headlessRef = { value: true }; // Default to true
|
|
131
|
+
// Use esbuild to bundle the file with chromium replacement plugin
|
|
132
|
+
const result = await (0, esbuild_1.build)({
|
|
133
|
+
entryPoints: [filePath],
|
|
134
|
+
bundle: true,
|
|
135
|
+
write: false, // Don't write to disk, return the result
|
|
136
|
+
platform: 'node',
|
|
137
|
+
format: 'cjs',
|
|
138
|
+
target: 'node18',
|
|
139
|
+
minify: false,
|
|
140
|
+
sourcemap: false,
|
|
141
|
+
external: [
|
|
142
|
+
'playwright',
|
|
143
|
+
'playwright-core',
|
|
144
|
+
'playwright-extra',
|
|
145
|
+
'puppeteer-extra-plugin-stealth',
|
|
146
|
+
],
|
|
147
|
+
plugins: [createChromiumReplacePlugin(wsUrl, headlessRef)],
|
|
148
|
+
});
|
|
149
|
+
// Get the bundled code from the result
|
|
150
|
+
if (result.outputFiles && result.outputFiles.length > 0) {
|
|
151
|
+
return { code: result.outputFiles[0].text, headless: headlessRef.value };
|
|
152
|
+
}
|
|
153
|
+
else {
|
|
154
|
+
throw new Error('No output generated from esbuild');
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
catch (error) {
|
|
158
|
+
console.error('Error bundling code:', error);
|
|
159
|
+
throw error;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
async function runProgram(session, file) {
|
|
163
|
+
// Run the specified file
|
|
164
|
+
const { code, headless } = await buildBundleCode(file, session);
|
|
165
|
+
if (!headless) {
|
|
166
|
+
const url = await session.browser.getLiveviewPageUrl();
|
|
167
|
+
if (url) {
|
|
168
|
+
(0, open_1.default)(url);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
const result = await session.codeRunner.run(code);
|
|
172
|
+
await session.close();
|
|
173
|
+
return result;
|
|
174
|
+
}
|
|
175
|
+
// Helper function to prompt user for input
|
|
176
|
+
function promptForKey() {
|
|
177
|
+
return new Promise(resolve => {
|
|
178
|
+
const rl = readline.createInterface({
|
|
179
|
+
input: process.stdin,
|
|
180
|
+
output: process.stdout,
|
|
181
|
+
});
|
|
182
|
+
rl.question('Please enter your Cerevox API key: ', answer => {
|
|
183
|
+
rl.close();
|
|
184
|
+
resolve(answer.trim());
|
|
185
|
+
});
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
async function testAndOpenUrl(url) {
|
|
189
|
+
while (true) {
|
|
190
|
+
try {
|
|
191
|
+
const res = await fetch(url);
|
|
192
|
+
if (res.status < 500) {
|
|
193
|
+
(0, open_1.default)(url);
|
|
194
|
+
break;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
finally {
|
|
198
|
+
await (0, promises_1.setTimeout)(300);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
const program = new commander_1.Command();
|
|
203
|
+
program
|
|
204
|
+
.name('cerevox-run')
|
|
205
|
+
.description('Run a command in a Cerevox sandbox')
|
|
206
|
+
.version(VERSION)
|
|
207
|
+
.argument('<file>', 'JavaScript or TypeScript file to run with Cerevox')
|
|
208
|
+
.option('-k, --key <string>', 'Cerevox API key (optional if CEREVOX_API_KEY env var is set)')
|
|
209
|
+
.option('-l, --listen <number>', 'Port number to listen on', parseInt)
|
|
210
|
+
.helpOption('-h, --help', 'Display help for command')
|
|
211
|
+
.action(async (file, options) => {
|
|
212
|
+
let { key } = options;
|
|
213
|
+
// If no key provided via command line, check environment variable
|
|
214
|
+
if (!key) {
|
|
215
|
+
key = process.env.CEREVOX_API_KEY;
|
|
216
|
+
if (key) {
|
|
217
|
+
// console.log('Using Cerevox API key from environment variable.');
|
|
218
|
+
}
|
|
219
|
+
else {
|
|
220
|
+
// console.log('No Cerevox API key found in environment variable.');
|
|
221
|
+
key = await promptForKey();
|
|
222
|
+
if (!key) {
|
|
223
|
+
console.error('Error: Cerevox API key is required to continue.');
|
|
224
|
+
process.exit(1);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
console.log(`File to run: ${file}`);
|
|
229
|
+
try {
|
|
230
|
+
const cerevox = new __1.default({
|
|
231
|
+
apiKey: key,
|
|
232
|
+
logLevel: 'error',
|
|
233
|
+
});
|
|
234
|
+
const session = await cerevox.launch({
|
|
235
|
+
browser: {
|
|
236
|
+
liveview: true,
|
|
237
|
+
},
|
|
238
|
+
keepAliveMS: 10000,
|
|
239
|
+
timeoutMS: 3600000,
|
|
240
|
+
});
|
|
241
|
+
const { listen } = options;
|
|
242
|
+
// Log listen parameter if provided
|
|
243
|
+
if (listen !== undefined) {
|
|
244
|
+
const host = session.getHost(listen);
|
|
245
|
+
// console.log(`Listen: ${host}`);
|
|
246
|
+
testAndOpenUrl(`https://${host}`);
|
|
247
|
+
}
|
|
248
|
+
await runProgram(session, file);
|
|
249
|
+
console.log('Program executed successfully.');
|
|
250
|
+
// Check and create .env.cerevox file
|
|
251
|
+
const envFilePath = (0, node_path_1.join)(process.cwd(), '.env.cerevox');
|
|
252
|
+
if (!(0, node_fs_1.existsSync)(envFilePath)) {
|
|
253
|
+
try {
|
|
254
|
+
(0, node_fs_1.writeFileSync)(envFilePath, `CEREVOX_API_KEY=${key}\n`);
|
|
255
|
+
console.log('Created .env.cerevox file with your API key.');
|
|
256
|
+
}
|
|
257
|
+
catch (error) {
|
|
258
|
+
console.error('Failed to create .env.cerevox file:', error);
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
else {
|
|
262
|
+
console.log('.env.cerevox file already exists, will not overwrite the file content.');
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
catch (error) {
|
|
266
|
+
console.error('Error running the program:', error);
|
|
267
|
+
}
|
|
268
|
+
});
|
|
269
|
+
function run() {
|
|
270
|
+
program.parse();
|
|
271
|
+
}
|
|
272
|
+
if (require.main === module) {
|
|
273
|
+
run();
|
|
274
|
+
}
|
|
275
|
+
//# sourceMappingURL=cerevox-run.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cerevox-run.js","sourceRoot":"","sources":["../../src/cli/cerevox-run.ts"],"names":[],"mappings":"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"}
|