@vulcn/engine 0.2.0 → 0.3.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/CHANGELOG.md +62 -0
- package/README.md +40 -174
- package/dist/index.cjs +361 -201
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +342 -101
- package/dist/index.d.ts +342 -101
- package/dist/index.js +355 -198
- package/dist/index.js.map +1 -1
- package/package.json +31 -14
package/dist/index.cjs
CHANGED
|
@@ -27,10 +27,12 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
27
27
|
));
|
|
28
28
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
29
|
|
|
30
|
-
// index.ts
|
|
30
|
+
// src/index.ts
|
|
31
31
|
var index_exports = {};
|
|
32
32
|
__export(index_exports, {
|
|
33
33
|
BrowserNotFoundError: () => BrowserNotFoundError,
|
|
34
|
+
DRIVER_API_VERSION: () => DRIVER_API_VERSION,
|
|
35
|
+
DriverManager: () => DriverManager,
|
|
34
36
|
PLUGIN_API_VERSION: () => PLUGIN_API_VERSION,
|
|
35
37
|
PluginManager: () => PluginManager,
|
|
36
38
|
Recorder: () => Recorder,
|
|
@@ -39,6 +41,7 @@ __export(index_exports, {
|
|
|
39
41
|
StepSchema: () => StepSchema,
|
|
40
42
|
checkBrowsers: () => checkBrowsers,
|
|
41
43
|
createSession: () => createSession,
|
|
44
|
+
driverManager: () => driverManager,
|
|
42
45
|
installBrowsers: () => installBrowsers,
|
|
43
46
|
launchBrowser: () => launchBrowser,
|
|
44
47
|
parseSession: () => parseSession,
|
|
@@ -47,221 +50,185 @@ __export(index_exports, {
|
|
|
47
50
|
});
|
|
48
51
|
module.exports = __toCommonJS(index_exports);
|
|
49
52
|
|
|
50
|
-
//
|
|
51
|
-
var
|
|
52
|
-
var
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
selector: import_zod.z.string(),
|
|
64
|
-
position: import_zod.z.object({ x: import_zod.z.number(), y: import_zod.z.number() }).optional(),
|
|
65
|
-
timestamp: import_zod.z.number()
|
|
66
|
-
}),
|
|
67
|
-
import_zod.z.object({
|
|
68
|
-
id: import_zod.z.string(),
|
|
69
|
-
type: import_zod.z.literal("input"),
|
|
70
|
-
selector: import_zod.z.string(),
|
|
71
|
-
value: import_zod.z.string(),
|
|
72
|
-
injectable: import_zod.z.boolean().optional().default(true),
|
|
73
|
-
timestamp: import_zod.z.number()
|
|
74
|
-
}),
|
|
75
|
-
import_zod.z.object({
|
|
76
|
-
id: import_zod.z.string(),
|
|
77
|
-
type: import_zod.z.literal("keypress"),
|
|
78
|
-
key: import_zod.z.string(),
|
|
79
|
-
modifiers: import_zod.z.array(import_zod.z.string()).optional(),
|
|
80
|
-
timestamp: import_zod.z.number()
|
|
81
|
-
}),
|
|
82
|
-
import_zod.z.object({
|
|
83
|
-
id: import_zod.z.string(),
|
|
84
|
-
type: import_zod.z.literal("scroll"),
|
|
85
|
-
selector: import_zod.z.string().optional(),
|
|
86
|
-
position: import_zod.z.object({ x: import_zod.z.number(), y: import_zod.z.number() }),
|
|
87
|
-
timestamp: import_zod.z.number()
|
|
88
|
-
}),
|
|
89
|
-
import_zod.z.object({
|
|
90
|
-
id: import_zod.z.string(),
|
|
91
|
-
type: import_zod.z.literal("wait"),
|
|
92
|
-
duration: import_zod.z.number(),
|
|
93
|
-
timestamp: import_zod.z.number()
|
|
94
|
-
})
|
|
95
|
-
]);
|
|
96
|
-
var SessionSchema = import_zod.z.object({
|
|
97
|
-
version: import_zod.z.string().default("1"),
|
|
98
|
-
name: import_zod.z.string(),
|
|
99
|
-
recordedAt: import_zod.z.string(),
|
|
100
|
-
browser: import_zod.z.enum(["chromium", "firefox", "webkit"]).default("chromium"),
|
|
101
|
-
viewport: import_zod.z.object({
|
|
102
|
-
width: import_zod.z.number(),
|
|
103
|
-
height: import_zod.z.number()
|
|
104
|
-
}),
|
|
105
|
-
startUrl: import_zod.z.string(),
|
|
106
|
-
steps: import_zod.z.array(StepSchema)
|
|
107
|
-
});
|
|
108
|
-
function createSession(options) {
|
|
109
|
-
return {
|
|
110
|
-
version: "1",
|
|
111
|
-
name: options.name,
|
|
112
|
-
recordedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
113
|
-
browser: options.browser ?? "chromium",
|
|
114
|
-
viewport: options.viewport ?? { width: 1280, height: 720 },
|
|
115
|
-
startUrl: options.startUrl,
|
|
116
|
-
steps: []
|
|
117
|
-
};
|
|
118
|
-
}
|
|
119
|
-
function parseSession(yaml) {
|
|
120
|
-
const data = (0, import_yaml.parse)(yaml);
|
|
121
|
-
return SessionSchema.parse(data);
|
|
122
|
-
}
|
|
123
|
-
function serializeSession(session) {
|
|
124
|
-
return (0, import_yaml.stringify)(session, { lineWidth: 0 });
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
// browser.ts
|
|
128
|
-
var import_playwright = require("playwright");
|
|
129
|
-
var import_node_child_process = require("child_process");
|
|
130
|
-
var import_node_util = require("util");
|
|
131
|
-
var execAsync = (0, import_node_util.promisify)(import_node_child_process.exec);
|
|
132
|
-
var BrowserNotFoundError = class extends Error {
|
|
133
|
-
constructor(message) {
|
|
134
|
-
super(message);
|
|
135
|
-
this.name = "BrowserNotFoundError";
|
|
136
|
-
}
|
|
137
|
-
};
|
|
138
|
-
async function launchBrowser(options = {}) {
|
|
139
|
-
const browserType = options.browser ?? "chromium";
|
|
140
|
-
const headless = options.headless ?? false;
|
|
141
|
-
if (browserType === "chromium") {
|
|
142
|
-
try {
|
|
143
|
-
const browser = await import_playwright.chromium.launch({
|
|
144
|
-
channel: "chrome",
|
|
145
|
-
headless
|
|
146
|
-
});
|
|
147
|
-
return { browser, channel: "chrome" };
|
|
148
|
-
} catch {
|
|
149
|
-
}
|
|
150
|
-
try {
|
|
151
|
-
const browser = await import_playwright.chromium.launch({
|
|
152
|
-
channel: "msedge",
|
|
153
|
-
headless
|
|
154
|
-
});
|
|
155
|
-
return { browser, channel: "msedge" };
|
|
156
|
-
} catch {
|
|
53
|
+
// src/driver-manager.ts
|
|
54
|
+
var import_node_path = require("path");
|
|
55
|
+
var DriverManager = class {
|
|
56
|
+
drivers = /* @__PURE__ */ new Map();
|
|
57
|
+
defaultDriver = null;
|
|
58
|
+
/**
|
|
59
|
+
* Register a driver
|
|
60
|
+
*/
|
|
61
|
+
register(driver, source = "builtin") {
|
|
62
|
+
this.validateDriver(driver);
|
|
63
|
+
this.drivers.set(driver.name, { driver, source });
|
|
64
|
+
if (this.drivers.size === 1) {
|
|
65
|
+
this.defaultDriver = driver.name;
|
|
157
66
|
}
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Load a driver from npm or local path
|
|
70
|
+
*/
|
|
71
|
+
async load(nameOrPath) {
|
|
72
|
+
let driver;
|
|
73
|
+
let source;
|
|
74
|
+
if (nameOrPath.startsWith("./") || nameOrPath.startsWith("../") || (0, import_node_path.isAbsolute)(nameOrPath)) {
|
|
75
|
+
const resolved = (0, import_node_path.isAbsolute)(nameOrPath) ? nameOrPath : (0, import_node_path.resolve)(process.cwd(), nameOrPath);
|
|
76
|
+
const module2 = await import(resolved);
|
|
77
|
+
driver = module2.default || module2;
|
|
78
|
+
source = "local";
|
|
79
|
+
} else {
|
|
80
|
+
const module2 = await import(nameOrPath);
|
|
81
|
+
driver = module2.default || module2;
|
|
82
|
+
source = "npm";
|
|
165
83
|
}
|
|
84
|
+
this.register(driver, source);
|
|
166
85
|
}
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
86
|
+
/**
|
|
87
|
+
* Get a loaded driver by name
|
|
88
|
+
*/
|
|
89
|
+
get(name) {
|
|
90
|
+
return this.drivers.get(name)?.driver;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Get the default driver
|
|
94
|
+
*/
|
|
95
|
+
getDefault() {
|
|
96
|
+
if (!this.defaultDriver) return void 0;
|
|
97
|
+
return this.get(this.defaultDriver);
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Set the default driver
|
|
101
|
+
*/
|
|
102
|
+
setDefault(name) {
|
|
103
|
+
if (!this.drivers.has(name)) {
|
|
104
|
+
throw new Error(`Driver "${name}" is not registered`);
|
|
175
105
|
}
|
|
106
|
+
this.defaultDriver = name;
|
|
176
107
|
}
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
108
|
+
/**
|
|
109
|
+
* Check if a driver is registered
|
|
110
|
+
*/
|
|
111
|
+
has(name) {
|
|
112
|
+
return this.drivers.has(name);
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Get all registered drivers
|
|
116
|
+
*/
|
|
117
|
+
list() {
|
|
118
|
+
return Array.from(this.drivers.values());
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Get driver for a session
|
|
122
|
+
*/
|
|
123
|
+
getForSession(session) {
|
|
124
|
+
const driverName = session.driver;
|
|
125
|
+
const driver = this.get(driverName);
|
|
126
|
+
if (!driver) {
|
|
127
|
+
throw new Error(
|
|
128
|
+
`Driver "${driverName}" not found. Install @vulcn/driver-${driverName} or load it manually.`
|
|
184
129
|
);
|
|
185
130
|
}
|
|
131
|
+
return driver;
|
|
186
132
|
}
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
systemEdge: false,
|
|
197
|
-
playwrightChromium: false,
|
|
198
|
-
playwrightFirefox: false,
|
|
199
|
-
playwrightWebkit: false
|
|
200
|
-
};
|
|
201
|
-
try {
|
|
202
|
-
const browser = await import_playwright.chromium.launch({
|
|
203
|
-
channel: "chrome",
|
|
204
|
-
headless: true
|
|
205
|
-
});
|
|
206
|
-
await browser.close();
|
|
207
|
-
results.systemChrome = true;
|
|
208
|
-
} catch {
|
|
209
|
-
}
|
|
210
|
-
try {
|
|
211
|
-
const browser = await import_playwright.chromium.launch({
|
|
212
|
-
channel: "msedge",
|
|
213
|
-
headless: true
|
|
214
|
-
});
|
|
215
|
-
await browser.close();
|
|
216
|
-
results.systemEdge = true;
|
|
217
|
-
} catch {
|
|
133
|
+
/**
|
|
134
|
+
* Start recording with a driver
|
|
135
|
+
*/
|
|
136
|
+
async startRecording(driverName, config, options = {}) {
|
|
137
|
+
const driver = this.get(driverName);
|
|
138
|
+
if (!driver) {
|
|
139
|
+
throw new Error(`Driver "${driverName}" not found`);
|
|
140
|
+
}
|
|
141
|
+
return driver.recorder.start(config, options);
|
|
218
142
|
}
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
143
|
+
/**
|
|
144
|
+
* Execute a session
|
|
145
|
+
*/
|
|
146
|
+
async execute(session, pluginManager2, options = {}) {
|
|
147
|
+
const driver = this.getForSession(session);
|
|
148
|
+
const findings = [];
|
|
149
|
+
const logger = this.createLogger(driver.name);
|
|
150
|
+
const ctx = {
|
|
151
|
+
session,
|
|
152
|
+
pluginManager: pluginManager2,
|
|
153
|
+
payloads: pluginManager2.getPayloads(),
|
|
154
|
+
findings,
|
|
155
|
+
addFinding: (finding) => {
|
|
156
|
+
findings.push(finding);
|
|
157
|
+
pluginManager2.addFinding(finding);
|
|
158
|
+
options.onFinding?.(finding);
|
|
159
|
+
},
|
|
160
|
+
logger,
|
|
161
|
+
options
|
|
162
|
+
};
|
|
163
|
+
return driver.runner.execute(session, ctx);
|
|
224
164
|
}
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
165
|
+
/**
|
|
166
|
+
* Validate driver structure
|
|
167
|
+
*/
|
|
168
|
+
validateDriver(driver) {
|
|
169
|
+
if (!driver || typeof driver !== "object") {
|
|
170
|
+
throw new Error("Driver must be an object");
|
|
171
|
+
}
|
|
172
|
+
const d = driver;
|
|
173
|
+
if (typeof d.name !== "string" || !d.name) {
|
|
174
|
+
throw new Error("Driver must have a name");
|
|
175
|
+
}
|
|
176
|
+
if (typeof d.version !== "string" || !d.version) {
|
|
177
|
+
throw new Error("Driver must have a version");
|
|
178
|
+
}
|
|
179
|
+
if (!Array.isArray(d.stepTypes) || d.stepTypes.length === 0) {
|
|
180
|
+
throw new Error("Driver must define stepTypes");
|
|
181
|
+
}
|
|
182
|
+
if (!d.recorder || typeof d.recorder !== "object") {
|
|
183
|
+
throw new Error("Driver must have a recorder");
|
|
184
|
+
}
|
|
185
|
+
if (!d.runner || typeof d.runner !== "object") {
|
|
186
|
+
throw new Error("Driver must have a runner");
|
|
187
|
+
}
|
|
230
188
|
}
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
189
|
+
/**
|
|
190
|
+
* Create a scoped logger for a driver
|
|
191
|
+
*/
|
|
192
|
+
createLogger(name) {
|
|
193
|
+
const prefix = `[driver:${name}]`;
|
|
194
|
+
return {
|
|
195
|
+
debug: (msg, ...args) => console.debug(prefix, msg, ...args),
|
|
196
|
+
info: (msg, ...args) => console.info(prefix, msg, ...args),
|
|
197
|
+
warn: (msg, ...args) => console.warn(prefix, msg, ...args),
|
|
198
|
+
error: (msg, ...args) => console.error(prefix, msg, ...args)
|
|
199
|
+
};
|
|
236
200
|
}
|
|
237
|
-
|
|
238
|
-
|
|
201
|
+
};
|
|
202
|
+
var driverManager = new DriverManager();
|
|
203
|
+
|
|
204
|
+
// src/driver-types.ts
|
|
205
|
+
var DRIVER_API_VERSION = 1;
|
|
239
206
|
|
|
240
|
-
// plugin-manager.ts
|
|
207
|
+
// src/plugin-manager.ts
|
|
241
208
|
var import_promises = require("fs/promises");
|
|
242
209
|
var import_node_fs = require("fs");
|
|
243
|
-
var
|
|
244
|
-
var
|
|
245
|
-
var
|
|
210
|
+
var import_node_path2 = require("path");
|
|
211
|
+
var import_yaml = __toESM(require("yaml"), 1);
|
|
212
|
+
var import_zod = require("zod");
|
|
246
213
|
|
|
247
|
-
// plugin-types.ts
|
|
214
|
+
// src/plugin-types.ts
|
|
248
215
|
var PLUGIN_API_VERSION = 1;
|
|
249
216
|
|
|
250
|
-
// plugin-manager.ts
|
|
217
|
+
// src/plugin-manager.ts
|
|
251
218
|
var ENGINE_VERSION = "0.2.0";
|
|
252
|
-
var VulcnConfigSchema =
|
|
253
|
-
version:
|
|
254
|
-
plugins:
|
|
255
|
-
|
|
256
|
-
name:
|
|
257
|
-
config:
|
|
258
|
-
enabled:
|
|
219
|
+
var VulcnConfigSchema = import_zod.z.object({
|
|
220
|
+
version: import_zod.z.string().default("1"),
|
|
221
|
+
plugins: import_zod.z.array(
|
|
222
|
+
import_zod.z.object({
|
|
223
|
+
name: import_zod.z.string(),
|
|
224
|
+
config: import_zod.z.record(import_zod.z.unknown()).optional(),
|
|
225
|
+
enabled: import_zod.z.boolean().default(true)
|
|
259
226
|
})
|
|
260
227
|
).optional(),
|
|
261
|
-
settings:
|
|
262
|
-
browser:
|
|
263
|
-
headless:
|
|
264
|
-
timeout:
|
|
228
|
+
settings: import_zod.z.object({
|
|
229
|
+
browser: import_zod.z.enum(["chromium", "firefox", "webkit"]).optional(),
|
|
230
|
+
headless: import_zod.z.boolean().optional(),
|
|
231
|
+
timeout: import_zod.z.number().optional()
|
|
265
232
|
}).optional()
|
|
266
233
|
});
|
|
267
234
|
var PluginManager = class {
|
|
@@ -286,10 +253,10 @@ var PluginManager = class {
|
|
|
286
253
|
".vulcnrc.json"
|
|
287
254
|
];
|
|
288
255
|
for (const path of paths) {
|
|
289
|
-
const resolved = (0,
|
|
256
|
+
const resolved = (0, import_node_path2.isAbsolute)(path) ? path : (0, import_node_path2.resolve)(process.cwd(), path);
|
|
290
257
|
if ((0, import_node_fs.existsSync)(resolved)) {
|
|
291
258
|
const content = await (0, import_promises.readFile)(resolved, "utf-8");
|
|
292
|
-
const parsed = path.endsWith(".json") ? JSON.parse(content) :
|
|
259
|
+
const parsed = path.endsWith(".json") ? JSON.parse(content) : import_yaml.default.parse(content);
|
|
293
260
|
this.config = VulcnConfigSchema.parse(parsed);
|
|
294
261
|
return this.config;
|
|
295
262
|
}
|
|
@@ -325,8 +292,8 @@ var PluginManager = class {
|
|
|
325
292
|
const { name, config: pluginConfig = {} } = config;
|
|
326
293
|
let plugin;
|
|
327
294
|
let source;
|
|
328
|
-
if (name.startsWith("./") || name.startsWith("../") || (0,
|
|
329
|
-
const resolved = (0,
|
|
295
|
+
if (name.startsWith("./") || name.startsWith("../") || (0, import_node_path2.isAbsolute)(name)) {
|
|
296
|
+
const resolved = (0, import_node_path2.isAbsolute)(name) ? name : (0, import_node_path2.resolve)(process.cwd(), name);
|
|
330
297
|
const module2 = await import(resolved);
|
|
331
298
|
plugin = module2.default || module2;
|
|
332
299
|
source = "local";
|
|
@@ -566,7 +533,197 @@ var PluginManager = class {
|
|
|
566
533
|
};
|
|
567
534
|
var pluginManager = new PluginManager();
|
|
568
535
|
|
|
569
|
-
//
|
|
536
|
+
// src/session.ts
|
|
537
|
+
var import_zod2 = require("zod");
|
|
538
|
+
var import_yaml2 = require("yaml");
|
|
539
|
+
var StepSchema = import_zod2.z.discriminatedUnion("type", [
|
|
540
|
+
import_zod2.z.object({
|
|
541
|
+
id: import_zod2.z.string(),
|
|
542
|
+
type: import_zod2.z.literal("navigate"),
|
|
543
|
+
url: import_zod2.z.string(),
|
|
544
|
+
timestamp: import_zod2.z.number()
|
|
545
|
+
}),
|
|
546
|
+
import_zod2.z.object({
|
|
547
|
+
id: import_zod2.z.string(),
|
|
548
|
+
type: import_zod2.z.literal("click"),
|
|
549
|
+
selector: import_zod2.z.string(),
|
|
550
|
+
position: import_zod2.z.object({ x: import_zod2.z.number(), y: import_zod2.z.number() }).optional(),
|
|
551
|
+
timestamp: import_zod2.z.number()
|
|
552
|
+
}),
|
|
553
|
+
import_zod2.z.object({
|
|
554
|
+
id: import_zod2.z.string(),
|
|
555
|
+
type: import_zod2.z.literal("input"),
|
|
556
|
+
selector: import_zod2.z.string(),
|
|
557
|
+
value: import_zod2.z.string(),
|
|
558
|
+
injectable: import_zod2.z.boolean().optional().default(true),
|
|
559
|
+
timestamp: import_zod2.z.number()
|
|
560
|
+
}),
|
|
561
|
+
import_zod2.z.object({
|
|
562
|
+
id: import_zod2.z.string(),
|
|
563
|
+
type: import_zod2.z.literal("keypress"),
|
|
564
|
+
key: import_zod2.z.string(),
|
|
565
|
+
modifiers: import_zod2.z.array(import_zod2.z.string()).optional(),
|
|
566
|
+
timestamp: import_zod2.z.number()
|
|
567
|
+
}),
|
|
568
|
+
import_zod2.z.object({
|
|
569
|
+
id: import_zod2.z.string(),
|
|
570
|
+
type: import_zod2.z.literal("scroll"),
|
|
571
|
+
selector: import_zod2.z.string().optional(),
|
|
572
|
+
position: import_zod2.z.object({ x: import_zod2.z.number(), y: import_zod2.z.number() }),
|
|
573
|
+
timestamp: import_zod2.z.number()
|
|
574
|
+
}),
|
|
575
|
+
import_zod2.z.object({
|
|
576
|
+
id: import_zod2.z.string(),
|
|
577
|
+
type: import_zod2.z.literal("wait"),
|
|
578
|
+
duration: import_zod2.z.number(),
|
|
579
|
+
timestamp: import_zod2.z.number()
|
|
580
|
+
})
|
|
581
|
+
]);
|
|
582
|
+
var SessionSchema = import_zod2.z.object({
|
|
583
|
+
version: import_zod2.z.string().default("1"),
|
|
584
|
+
name: import_zod2.z.string(),
|
|
585
|
+
recordedAt: import_zod2.z.string(),
|
|
586
|
+
browser: import_zod2.z.enum(["chromium", "firefox", "webkit"]).default("chromium"),
|
|
587
|
+
viewport: import_zod2.z.object({
|
|
588
|
+
width: import_zod2.z.number(),
|
|
589
|
+
height: import_zod2.z.number()
|
|
590
|
+
}),
|
|
591
|
+
startUrl: import_zod2.z.string(),
|
|
592
|
+
steps: import_zod2.z.array(StepSchema)
|
|
593
|
+
});
|
|
594
|
+
function createSession(options) {
|
|
595
|
+
return {
|
|
596
|
+
version: "1",
|
|
597
|
+
name: options.name,
|
|
598
|
+
recordedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
599
|
+
browser: options.browser ?? "chromium",
|
|
600
|
+
viewport: options.viewport ?? { width: 1280, height: 720 },
|
|
601
|
+
startUrl: options.startUrl,
|
|
602
|
+
steps: []
|
|
603
|
+
};
|
|
604
|
+
}
|
|
605
|
+
function parseSession(yaml) {
|
|
606
|
+
const data = (0, import_yaml2.parse)(yaml);
|
|
607
|
+
return SessionSchema.parse(data);
|
|
608
|
+
}
|
|
609
|
+
function serializeSession(session) {
|
|
610
|
+
return (0, import_yaml2.stringify)(session, { lineWidth: 0 });
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
// src/browser.ts
|
|
614
|
+
var import_playwright = require("playwright");
|
|
615
|
+
var import_node_child_process = require("child_process");
|
|
616
|
+
var import_node_util = require("util");
|
|
617
|
+
var execAsync = (0, import_node_util.promisify)(import_node_child_process.exec);
|
|
618
|
+
var BrowserNotFoundError = class extends Error {
|
|
619
|
+
constructor(message) {
|
|
620
|
+
super(message);
|
|
621
|
+
this.name = "BrowserNotFoundError";
|
|
622
|
+
}
|
|
623
|
+
};
|
|
624
|
+
async function launchBrowser(options = {}) {
|
|
625
|
+
const browserType = options.browser ?? "chromium";
|
|
626
|
+
const headless = options.headless ?? false;
|
|
627
|
+
if (browserType === "chromium") {
|
|
628
|
+
try {
|
|
629
|
+
const browser = await import_playwright.chromium.launch({
|
|
630
|
+
channel: "chrome",
|
|
631
|
+
headless
|
|
632
|
+
});
|
|
633
|
+
return { browser, channel: "chrome" };
|
|
634
|
+
} catch {
|
|
635
|
+
}
|
|
636
|
+
try {
|
|
637
|
+
const browser = await import_playwright.chromium.launch({
|
|
638
|
+
channel: "msedge",
|
|
639
|
+
headless
|
|
640
|
+
});
|
|
641
|
+
return { browser, channel: "msedge" };
|
|
642
|
+
} catch {
|
|
643
|
+
}
|
|
644
|
+
try {
|
|
645
|
+
const browser = await import_playwright.chromium.launch({ headless });
|
|
646
|
+
return { browser, channel: "chromium" };
|
|
647
|
+
} catch {
|
|
648
|
+
throw new BrowserNotFoundError(
|
|
649
|
+
"No Chromium browser found. Install Chrome or run: vulcn install chromium"
|
|
650
|
+
);
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
if (browserType === "firefox") {
|
|
654
|
+
try {
|
|
655
|
+
const browser = await import_playwright.firefox.launch({ headless });
|
|
656
|
+
return { browser, channel: "firefox" };
|
|
657
|
+
} catch {
|
|
658
|
+
throw new BrowserNotFoundError(
|
|
659
|
+
"Firefox not found. Run: vulcn install firefox"
|
|
660
|
+
);
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
if (browserType === "webkit") {
|
|
664
|
+
try {
|
|
665
|
+
const browser = await import_playwright.webkit.launch({ headless });
|
|
666
|
+
return { browser, channel: "webkit" };
|
|
667
|
+
} catch {
|
|
668
|
+
throw new BrowserNotFoundError(
|
|
669
|
+
"WebKit not found. Run: vulcn install webkit"
|
|
670
|
+
);
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
throw new BrowserNotFoundError(`Unknown browser type: ${browserType}`);
|
|
674
|
+
}
|
|
675
|
+
async function installBrowsers(browsers = ["chromium"]) {
|
|
676
|
+
const browserArg = browsers.join(" ");
|
|
677
|
+
await execAsync(`npx playwright install ${browserArg}`);
|
|
678
|
+
}
|
|
679
|
+
async function checkBrowsers() {
|
|
680
|
+
const results = {
|
|
681
|
+
systemChrome: false,
|
|
682
|
+
systemEdge: false,
|
|
683
|
+
playwrightChromium: false,
|
|
684
|
+
playwrightFirefox: false,
|
|
685
|
+
playwrightWebkit: false
|
|
686
|
+
};
|
|
687
|
+
try {
|
|
688
|
+
const browser = await import_playwright.chromium.launch({
|
|
689
|
+
channel: "chrome",
|
|
690
|
+
headless: true
|
|
691
|
+
});
|
|
692
|
+
await browser.close();
|
|
693
|
+
results.systemChrome = true;
|
|
694
|
+
} catch {
|
|
695
|
+
}
|
|
696
|
+
try {
|
|
697
|
+
const browser = await import_playwright.chromium.launch({
|
|
698
|
+
channel: "msedge",
|
|
699
|
+
headless: true
|
|
700
|
+
});
|
|
701
|
+
await browser.close();
|
|
702
|
+
results.systemEdge = true;
|
|
703
|
+
} catch {
|
|
704
|
+
}
|
|
705
|
+
try {
|
|
706
|
+
const browser = await import_playwright.chromium.launch({ headless: true });
|
|
707
|
+
await browser.close();
|
|
708
|
+
results.playwrightChromium = true;
|
|
709
|
+
} catch {
|
|
710
|
+
}
|
|
711
|
+
try {
|
|
712
|
+
const browser = await import_playwright.firefox.launch({ headless: true });
|
|
713
|
+
await browser.close();
|
|
714
|
+
results.playwrightFirefox = true;
|
|
715
|
+
} catch {
|
|
716
|
+
}
|
|
717
|
+
try {
|
|
718
|
+
const browser = await import_playwright.webkit.launch({ headless: true });
|
|
719
|
+
await browser.close();
|
|
720
|
+
results.playwrightWebkit = true;
|
|
721
|
+
} catch {
|
|
722
|
+
}
|
|
723
|
+
return results;
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
// src/recorder.ts
|
|
570
727
|
var Recorder = class _Recorder {
|
|
571
728
|
/**
|
|
572
729
|
* Start a new recording session
|
|
@@ -872,7 +1029,7 @@ var Recorder = class _Recorder {
|
|
|
872
1029
|
}
|
|
873
1030
|
};
|
|
874
1031
|
|
|
875
|
-
// runner.ts
|
|
1032
|
+
// src/runner.ts
|
|
876
1033
|
var Runner = class _Runner {
|
|
877
1034
|
/**
|
|
878
1035
|
* Execute a session with security payloads from plugins
|
|
@@ -1148,6 +1305,8 @@ var Runner = class _Runner {
|
|
|
1148
1305
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1149
1306
|
0 && (module.exports = {
|
|
1150
1307
|
BrowserNotFoundError,
|
|
1308
|
+
DRIVER_API_VERSION,
|
|
1309
|
+
DriverManager,
|
|
1151
1310
|
PLUGIN_API_VERSION,
|
|
1152
1311
|
PluginManager,
|
|
1153
1312
|
Recorder,
|
|
@@ -1156,6 +1315,7 @@ var Runner = class _Runner {
|
|
|
1156
1315
|
StepSchema,
|
|
1157
1316
|
checkBrowsers,
|
|
1158
1317
|
createSession,
|
|
1318
|
+
driverManager,
|
|
1159
1319
|
installBrowsers,
|
|
1160
1320
|
launchBrowser,
|
|
1161
1321
|
parseSession,
|