@vulcn/driver-browser 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/dist/index.cjs +756 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +298 -0
- package/dist/index.d.ts +298 -0
- package/dist/index.js +724 -0
- package/dist/index.js.map +1 -0
- package/package.json +63 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/browser.ts","../src/recorder.ts","../src/runner.ts"],"sourcesContent":["/**\n * @vulcn/driver-browser\n *\n * Browser recording driver for Vulcn.\n * Uses Playwright to record and replay web application interactions.\n *\n * Step types:\n * - browser.navigate - Navigate to a URL\n * - browser.click - Click an element\n * - browser.input - Type into an input field\n * - browser.keypress - Press a key\n * - browser.scroll - Scroll the page\n * - browser.wait - Wait for a duration\n */\n\nimport { z } from \"zod\";\nimport type {\n VulcnDriver,\n RecorderDriver,\n RunnerDriver,\n RecordingHandle,\n RecordOptions,\n Session,\n Step,\n RunContext,\n RunResult,\n} from \"@vulcn/engine\";\n\nimport { BrowserRecorder } from \"./recorder\";\nimport { BrowserRunner } from \"./runner\";\n\n/**\n * Browser driver configuration schema\n */\nexport const configSchema = z.object({\n /** Starting URL for recording */\n startUrl: z.string().url().optional(),\n\n /** Browser type */\n browser: z.enum([\"chromium\", \"firefox\", \"webkit\"]).default(\"chromium\"),\n\n /** Viewport size */\n viewport: z\n .object({\n width: z.number().default(1280),\n height: z.number().default(720),\n })\n .default({ width: 1280, height: 720 }),\n\n /** Run headless */\n headless: z.boolean().default(false),\n});\n\nexport type BrowserConfig = z.infer<typeof configSchema>;\n\n/**\n * Browser step types\n */\nexport const BROWSER_STEP_TYPES = [\n \"browser.navigate\",\n \"browser.click\",\n \"browser.input\",\n \"browser.keypress\",\n \"browser.scroll\",\n \"browser.wait\",\n] as const;\n\nexport type BrowserStepType = (typeof BROWSER_STEP_TYPES)[number];\n\n/**\n * Browser-specific step schemas\n */\nexport const BrowserStepSchema = z.discriminatedUnion(\"type\", [\n z.object({\n id: z.string(),\n type: z.literal(\"browser.navigate\"),\n url: z.string(),\n timestamp: z.number(),\n }),\n z.object({\n id: z.string(),\n type: z.literal(\"browser.click\"),\n selector: z.string(),\n position: z.object({ x: z.number(), y: z.number() }).optional(),\n timestamp: z.number(),\n }),\n z.object({\n id: z.string(),\n type: z.literal(\"browser.input\"),\n selector: z.string(),\n value: z.string(),\n injectable: z.boolean().default(true),\n timestamp: z.number(),\n }),\n z.object({\n id: z.string(),\n type: z.literal(\"browser.keypress\"),\n key: z.string(),\n modifiers: z.array(z.string()).optional(),\n timestamp: z.number(),\n }),\n z.object({\n id: z.string(),\n type: z.literal(\"browser.scroll\"),\n selector: z.string().optional(),\n position: z.object({ x: z.number(), y: z.number() }),\n timestamp: z.number(),\n }),\n z.object({\n id: z.string(),\n type: z.literal(\"browser.wait\"),\n duration: z.number(),\n timestamp: z.number(),\n }),\n]);\n\nexport type BrowserStep = z.infer<typeof BrowserStepSchema>;\n\n/**\n * Browser recorder implementation\n */\nconst recorderDriver: RecorderDriver = {\n async start(\n config: Record<string, unknown>,\n options: RecordOptions,\n ): Promise<RecordingHandle> {\n const parsedConfig = configSchema.parse(config);\n return BrowserRecorder.start(parsedConfig, options);\n },\n};\n\n/**\n * Browser runner implementation\n */\nconst runnerDriver: RunnerDriver = {\n async execute(session: Session, ctx: RunContext): Promise<RunResult> {\n return BrowserRunner.execute(session, ctx);\n },\n};\n\n/**\n * Browser driver for Vulcn\n */\nconst browserDriver: VulcnDriver = {\n name: \"browser\",\n version: \"0.1.0\",\n apiVersion: 1,\n description: \"Browser recording driver using Playwright\",\n configSchema,\n stepTypes: [...BROWSER_STEP_TYPES],\n recorder: recorderDriver,\n runner: runnerDriver,\n};\n\nexport default browserDriver;\n\n// Re-export utilities\nexport { BrowserRecorder } from \"./recorder\";\nexport { BrowserRunner } from \"./runner\";\nexport { launchBrowser, checkBrowsers, installBrowsers } from \"./browser\";\n","/**\n * Browser utilities for @vulcn/driver-browser\n * Smart browser launching with system browser fallback\n */\n\nimport { chromium, firefox, webkit, type Browser } from \"playwright\";\nimport { exec } from \"node:child_process\";\nimport { promisify } from \"node:util\";\n\nconst execAsync = promisify(exec);\n\nexport type BrowserType = \"chromium\" | \"firefox\" | \"webkit\";\n\nexport interface LaunchOptions {\n browser?: BrowserType;\n headless?: boolean;\n}\n\nexport interface BrowserLaunchResult {\n browser: Browser;\n channel?: string;\n}\n\nexport class BrowserNotFoundError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"BrowserNotFoundError\";\n }\n}\n\n/**\n * Launch a browser with smart fallback:\n * 1. Try system Chrome/Edge first (zero-install experience)\n * 2. Fall back to Playwright's bundled browsers\n */\nexport async function launchBrowser(\n options: LaunchOptions = {},\n): Promise<BrowserLaunchResult> {\n const browserType = options.browser ?? \"chromium\";\n const headless = options.headless ?? false;\n\n // For Chromium, try system browsers first\n if (browserType === \"chromium\") {\n // Try system Chrome\n try {\n const browser = await chromium.launch({\n channel: \"chrome\",\n headless,\n });\n return { browser, channel: \"chrome\" };\n } catch {\n // Chrome not available\n }\n\n // Try system Edge\n try {\n const browser = await chromium.launch({\n channel: \"msedge\",\n headless,\n });\n return { browser, channel: \"msedge\" };\n } catch {\n // Edge not available\n }\n\n // Fall back to Playwright's bundled Chromium\n try {\n const browser = await chromium.launch({ headless });\n return { browser, channel: \"chromium\" };\n } catch {\n throw new BrowserNotFoundError(\n \"No Chromium browser found. Install Chrome or run: vulcn install chromium\",\n );\n }\n }\n\n // Firefox\n if (browserType === \"firefox\") {\n try {\n const browser = await firefox.launch({ headless });\n return { browser, channel: \"firefox\" };\n } catch {\n throw new BrowserNotFoundError(\n \"Firefox not found. Run: vulcn install firefox\",\n );\n }\n }\n\n // WebKit\n if (browserType === \"webkit\") {\n try {\n const browser = await webkit.launch({ headless });\n return { browser, channel: \"webkit\" };\n } catch {\n throw new BrowserNotFoundError(\n \"WebKit not found. Run: vulcn install webkit\",\n );\n }\n }\n\n throw new BrowserNotFoundError(`Unknown browser type: ${browserType}`);\n}\n\n/**\n * Install Playwright browsers\n */\nexport async function installBrowsers(\n browsers: BrowserType[] = [\"chromium\"],\n): Promise<void> {\n const browserArg = browsers.join(\" \");\n await execAsync(`npx playwright install ${browserArg}`);\n}\n\n/**\n * Check which browsers are available\n */\nexport async function checkBrowsers(): Promise<{\n systemChrome: boolean;\n systemEdge: boolean;\n playwrightChromium: boolean;\n playwrightFirefox: boolean;\n playwrightWebkit: boolean;\n}> {\n const results = {\n systemChrome: false,\n systemEdge: false,\n playwrightChromium: false,\n playwrightFirefox: false,\n playwrightWebkit: false,\n };\n\n // Check system Chrome\n try {\n const browser = await chromium.launch({\n channel: \"chrome\",\n headless: true,\n });\n await browser.close();\n results.systemChrome = true;\n } catch {\n // Not available\n }\n\n // Check system Edge\n try {\n const browser = await chromium.launch({\n channel: \"msedge\",\n headless: true,\n });\n await browser.close();\n results.systemEdge = true;\n } catch {\n // Not available\n }\n\n // Check Playwright Chromium\n try {\n const browser = await chromium.launch({ headless: true });\n await browser.close();\n results.playwrightChromium = true;\n } catch {\n // Not installed\n }\n\n // Check Playwright Firefox\n try {\n const browser = await firefox.launch({ headless: true });\n await browser.close();\n results.playwrightFirefox = true;\n } catch {\n // Not installed\n }\n\n // Check Playwright WebKit\n try {\n const browser = await webkit.launch({ headless: true });\n await browser.close();\n results.playwrightWebkit = true;\n } catch {\n // Not installed\n }\n\n return results;\n}\n","/**\n * Browser Recorder Implementation\n *\n * Records browser interactions as replayable sessions.\n * Uses Playwright for browser automation.\n */\n\nimport type { Page } from \"playwright\";\nimport type {\n RecordingHandle,\n RecordOptions,\n Session,\n Step,\n} from \"@vulcn/engine\";\n\nimport { launchBrowser } from \"./browser\";\nimport type { BrowserConfig, BrowserStep } from \"./index\";\n\n/**\n * Browser Recorder - captures browser interactions\n */\nexport class BrowserRecorder {\n /**\n * Start a new recording session\n */\n static async start(\n config: BrowserConfig,\n _options: RecordOptions = {},\n ): Promise<RecordingHandle> {\n const { startUrl, browser: browserType, viewport, headless } = config;\n\n if (!startUrl) {\n throw new Error(\"startUrl is required for browser recording\");\n }\n\n // Launch browser with smart fallback\n const { browser } = await launchBrowser({\n browser: browserType,\n headless,\n });\n\n const context = await browser.newContext({ viewport });\n const page = await context.newPage();\n\n // Navigate to start URL\n await page.goto(startUrl);\n\n // Track recording\n const startTime = Date.now();\n const steps: Step[] = [];\n let stepCounter = 0;\n\n const generateStepId = () => {\n stepCounter++;\n return `step_${String(stepCounter).padStart(3, \"0\")}`;\n };\n\n // Add initial navigation step\n steps.push({\n id: generateStepId(),\n type: \"browser.navigate\",\n url: startUrl,\n timestamp: 0,\n });\n\n // Attach event listeners\n BrowserRecorder.attachListeners(page, steps, startTime, generateStepId);\n\n return {\n async stop(): Promise<Session> {\n const session: Session = {\n name: `Recording ${new Date().toISOString()}`,\n driver: \"browser\",\n driverConfig: {\n browser: browserType,\n viewport,\n startUrl,\n },\n steps,\n metadata: {\n recordedAt: new Date().toISOString(),\n version: \"1\",\n },\n };\n\n await browser.close();\n return session;\n },\n\n async abort(): Promise<void> {\n await browser.close();\n },\n\n getSteps(): Step[] {\n return [...steps];\n },\n\n addStep(step: Omit<Step, \"id\" | \"timestamp\">): void {\n steps.push({\n ...step,\n id: generateStepId(),\n timestamp: Date.now() - startTime,\n } as Step);\n },\n };\n }\n\n /**\n * Attach event listeners to the page\n */\n private static attachListeners(\n page: Page,\n steps: Step[],\n startTime: number,\n generateStepId: () => string,\n ) {\n const getTimestamp = () => Date.now() - startTime;\n\n const addStep = (\n step: Omit<Step, \"id\" | \"timestamp\"> & { type: string },\n ) => {\n steps.push({\n ...step,\n id: generateStepId(),\n timestamp: getTimestamp(),\n } as Step);\n };\n\n // Track navigation\n page.on(\"framenavigated\", (frame) => {\n if (frame === page.mainFrame()) {\n const url = frame.url();\n // Avoid duplicate nav steps for initial load\n const lastStep = steps[steps.length - 1];\n if (\n steps.length > 0 &&\n lastStep?.type === \"browser.navigate\" &&\n (lastStep as BrowserStep & { type: \"browser.navigate\" }).url === url\n ) {\n return;\n }\n addStep({\n type: \"browser.navigate\",\n url,\n });\n }\n });\n\n // Expose recording function to browser\n page.exposeFunction(\n \"__vulcn_record\",\n async (event: { type: string; data: Record<string, unknown> }) => {\n switch (event.type) {\n case \"click\": {\n const data = event.data as {\n selector: string;\n x: number;\n y: number;\n };\n addStep({\n type: \"browser.click\",\n selector: data.selector,\n position: { x: data.x, y: data.y },\n });\n break;\n }\n case \"input\": {\n const data = event.data as {\n selector: string;\n value: string;\n inputType: string | null;\n injectable: boolean;\n };\n addStep({\n type: \"browser.input\",\n selector: data.selector,\n value: data.value,\n injectable: data.injectable,\n });\n break;\n }\n case \"keypress\": {\n const data = event.data as { key: string; modifiers?: string[] };\n addStep({\n type: \"browser.keypress\",\n key: data.key,\n modifiers: data.modifiers,\n });\n break;\n }\n }\n },\n );\n\n // Inject recording script into every frame\n page.on(\"load\", async () => {\n await BrowserRecorder.injectRecordingScript(page);\n });\n\n // Inject into initial page\n BrowserRecorder.injectRecordingScript(page);\n }\n\n /**\n * Inject the recording script into the page\n */\n private static async injectRecordingScript(page: Page) {\n await page.evaluate(`\n (function() {\n if (window.__vulcn_injected) return;\n window.__vulcn_injected = true;\n\n var textInputTypes = ['text', 'password', 'email', 'search', 'url', 'tel', 'number'];\n\n function getSelector(el) {\n if (el.id) {\n return '#' + CSS.escape(el.id);\n }\n if (el.name) {\n var tag = el.tagName.toLowerCase();\n var nameSelector = tag + '[name=\"' + el.name + '\"]';\n if (document.querySelectorAll(nameSelector).length === 1) {\n return nameSelector;\n }\n }\n if (el.dataset && el.dataset.testid) {\n return '[data-testid=\"' + el.dataset.testid + '\"]';\n }\n if (el.tagName === 'INPUT' && el.type && el.name) {\n var inputSelector = 'input[type=\"' + el.type + '\"][name=\"' + el.name + '\"]';\n if (document.querySelectorAll(inputSelector).length === 1) {\n return inputSelector;\n }\n }\n if (el.className && typeof el.className === 'string') {\n var classes = el.className.trim().split(/\\\\s+/).filter(function(c) { return c.length > 0; });\n if (classes.length > 0) {\n var classSelector = el.tagName.toLowerCase() + '.' + classes.map(function(c) { return CSS.escape(c); }).join('.');\n if (document.querySelectorAll(classSelector).length === 1) {\n return classSelector;\n }\n }\n }\n var path = [];\n var current = el;\n while (current && current !== document.body) {\n var tag = current.tagName.toLowerCase();\n var parent = current.parentElement;\n if (parent) {\n var siblings = Array.from(parent.children).filter(function(c) { return c.tagName === current.tagName; });\n if (siblings.length > 1) {\n var index = siblings.indexOf(current) + 1;\n tag = tag + ':nth-of-type(' + index + ')';\n }\n }\n path.unshift(tag);\n current = parent;\n }\n return path.join(' > ');\n }\n\n function getInputType(el) {\n if (el.tagName === 'INPUT') return el.type || 'text';\n if (el.tagName === 'TEXTAREA') return 'textarea';\n if (el.tagName === 'SELECT') return 'select';\n return null;\n }\n\n function isTextInjectable(el) {\n var inputType = getInputType(el);\n if (!inputType) return false;\n if (inputType === 'textarea') return true;\n if (inputType === 'select') return false;\n return textInputTypes.indexOf(inputType) !== -1;\n }\n\n document.addEventListener('click', function(e) {\n var target = e.target;\n window.__vulcn_record({\n type: 'click',\n data: {\n selector: getSelector(target),\n x: e.clientX,\n y: e.clientY\n }\n });\n }, true);\n\n document.addEventListener('change', function(e) {\n var target = e.target;\n if ('value' in target) {\n var inputType = getInputType(target);\n window.__vulcn_record({\n type: 'input',\n data: {\n selector: getSelector(target),\n value: target.value,\n inputType: inputType,\n injectable: isTextInjectable(target)\n }\n });\n }\n }, true);\n\n document.addEventListener('keydown', function(e) {\n if (e.ctrlKey || e.metaKey || e.altKey) {\n var modifiers = [];\n if (e.ctrlKey) modifiers.push('ctrl');\n if (e.metaKey) modifiers.push('meta');\n if (e.altKey) modifiers.push('alt');\n if (e.shiftKey) modifiers.push('shift');\n\n window.__vulcn_record({\n type: 'keypress',\n data: {\n key: e.key,\n modifiers: modifiers\n }\n });\n }\n }, true);\n })();\n `);\n }\n}\n","/**\n * Browser Runner Implementation\n *\n * Replays browser sessions with security payloads.\n * Uses plugin hooks for detection.\n */\n\nimport type { Page, Dialog, ConsoleMessage } from \"playwright\";\nimport type {\n Session,\n Step,\n RunContext,\n RunResult,\n Finding,\n RuntimePayload,\n PayloadCategory,\n} from \"@vulcn/engine\";\n\nimport { launchBrowser, type BrowserType } from \"./browser\";\nimport type { BrowserStep } from \"./index\";\n\n/**\n * Browser Runner - replays sessions with payloads\n */\nexport class BrowserRunner {\n /**\n * Execute a session with security payloads\n */\n static async execute(session: Session, ctx: RunContext): Promise<RunResult> {\n const config = session.driverConfig;\n const browserType = (config.browser as BrowserType) ?? \"chromium\";\n const viewport = (config.viewport as { width: number; height: number }) ?? {\n width: 1280,\n height: 720,\n };\n const startUrl = config.startUrl as string;\n const headless = ctx.options.headless ?? true;\n\n const startTime = Date.now();\n const errors: string[] = [];\n let payloadsTested = 0;\n\n const payloads = ctx.payloads;\n if (payloads.length === 0) {\n return {\n findings: [],\n stepsExecuted: session.steps.length,\n payloadsTested: 0,\n duration: Date.now() - startTime,\n errors: [\n \"No payloads loaded. Add a payload plugin or configure payloads.\",\n ],\n };\n }\n\n // Launch browser\n const { browser } = await launchBrowser({\n browser: browserType,\n headless,\n });\n const context = await browser.newContext({ viewport });\n const page = await context.newPage();\n\n // Event findings from dialog/console handlers\n const eventFindings: Finding[] = [];\n let currentPayloadInfo: {\n stepId: string;\n payloadSet: RuntimePayload;\n payloadValue: string;\n } | null = null;\n\n // Dialog handler (for alert-based XSS detection)\n const dialogHandler = async (dialog: Dialog) => {\n if (currentPayloadInfo) {\n // Check if dialog message matches payload\n const message = dialog.message();\n if (\n message.includes(\"vulcn\") ||\n message === currentPayloadInfo.payloadValue\n ) {\n eventFindings.push({\n type: \"xss\",\n severity: \"high\",\n title: \"XSS Confirmed - Dialog Triggered\",\n description: `JavaScript dialog was triggered by payload injection`,\n stepId: currentPayloadInfo.stepId,\n payload: currentPayloadInfo.payloadValue,\n url: page.url(),\n evidence: `Dialog message: ${message}`,\n metadata: {\n dialogType: dialog.type(),\n detectionMethod: \"dialog\",\n },\n });\n }\n }\n // Always dismiss dialogs to prevent blocking\n try {\n await dialog.dismiss();\n } catch {\n // Dialog may have already been handled\n }\n };\n\n // Console message handler\n const consoleHandler = async (msg: ConsoleMessage) => {\n if (currentPayloadInfo && msg.type() === \"log\") {\n const text = msg.text();\n if (\n text.includes(\"vulcn\") ||\n text.includes(currentPayloadInfo.payloadValue)\n ) {\n eventFindings.push({\n type: \"xss\",\n severity: \"high\",\n title: \"XSS Confirmed - Console Output\",\n description: `JavaScript console.log was triggered by payload injection`,\n stepId: currentPayloadInfo.stepId,\n payload: currentPayloadInfo.payloadValue,\n url: page.url(),\n evidence: `Console output: ${text}`,\n metadata: {\n consoleType: msg.type(),\n detectionMethod: \"console\",\n },\n });\n }\n }\n };\n\n page.on(\"dialog\", dialogHandler);\n page.on(\"console\", consoleHandler);\n\n try {\n // Find injectable steps (browser.input with injectable=true)\n const injectableSteps = session.steps.filter(\n (\n step,\n ): step is Step & { type: \"browser.input\"; injectable?: boolean } =>\n step.type === \"browser.input\" &&\n (step as BrowserStep & { type: \"browser.input\" }).injectable !==\n false,\n );\n\n // Build flat list of all individual payloads to test\n const allPayloads: { payloadSet: RuntimePayload; value: string }[] = [];\n for (const payloadSet of payloads) {\n for (const value of payloadSet.payloads) {\n allPayloads.push({ payloadSet, value });\n }\n }\n\n // For each injectable step, test with each payload\n for (const injectableStep of injectableSteps) {\n for (const { payloadSet, value } of allPayloads) {\n try {\n currentPayloadInfo = {\n stepId: injectableStep.id,\n payloadSet,\n payloadValue: value,\n };\n\n // Replay session with payload\n await BrowserRunner.replayWithPayload(\n page,\n session,\n injectableStep,\n value,\n startUrl,\n );\n\n // Check for reflection\n const reflectionFinding = await BrowserRunner.checkReflection(\n page,\n injectableStep,\n payloadSet,\n value,\n );\n\n // Collect all findings\n const allFindings = [...eventFindings];\n if (reflectionFinding) {\n allFindings.push(reflectionFinding);\n }\n\n // Add unique findings\n for (const finding of allFindings) {\n ctx.addFinding(finding);\n }\n\n // Clear event findings for next iteration\n eventFindings.length = 0;\n payloadsTested++;\n\n // Report progress\n ctx.options.onStepComplete?.(injectableStep.id, payloadsTested);\n } catch (err) {\n errors.push(`${injectableStep.id}: ${String(err)}`);\n }\n }\n }\n } finally {\n page.off(\"dialog\", dialogHandler);\n page.off(\"console\", consoleHandler);\n currentPayloadInfo = null;\n await browser.close();\n }\n\n return {\n findings: ctx.findings,\n stepsExecuted: session.steps.length,\n payloadsTested,\n duration: Date.now() - startTime,\n errors,\n };\n }\n\n /**\n * Replay session steps with payload injected at target step\n */\n private static async replayWithPayload(\n page: Page,\n session: Session,\n targetStep: Step & { type: \"browser.input\" },\n payloadValue: string,\n startUrl: string,\n ): Promise<void> {\n // Navigate to start\n await page.goto(startUrl, { waitUntil: \"domcontentloaded\" });\n\n // Replay steps\n for (const step of session.steps) {\n const browserStep = step as BrowserStep;\n\n try {\n switch (browserStep.type) {\n case \"browser.navigate\":\n await page.goto(browserStep.url, { waitUntil: \"domcontentloaded\" });\n break;\n\n case \"browser.click\":\n await page.click(browserStep.selector, { timeout: 5000 });\n break;\n\n case \"browser.input\": {\n // Inject payload for target step\n const value =\n step.id === targetStep.id ? payloadValue : browserStep.value;\n await page.fill(browserStep.selector, value, { timeout: 5000 });\n break;\n }\n\n case \"browser.keypress\": {\n const modifiers = browserStep.modifiers ?? [];\n for (const mod of modifiers) {\n await page.keyboard.down(\n mod as \"Control\" | \"Shift\" | \"Alt\" | \"Meta\",\n );\n }\n await page.keyboard.press(browserStep.key);\n for (const mod of modifiers.reverse()) {\n await page.keyboard.up(\n mod as \"Control\" | \"Shift\" | \"Alt\" | \"Meta\",\n );\n }\n break;\n }\n\n case \"browser.scroll\":\n if (browserStep.selector) {\n await page.locator(browserStep.selector).evaluate((el, pos) => {\n el.scrollTo(pos.x, pos.y);\n }, browserStep.position);\n } else {\n await page.evaluate((pos) => {\n window.scrollTo(pos.x, pos.y);\n }, browserStep.position);\n }\n break;\n\n case \"browser.wait\":\n await page.waitForTimeout(browserStep.duration);\n break;\n }\n } catch {\n // Step failed, continue to next\n }\n\n // Stop after target step is injected\n if (step.id === targetStep.id) {\n // Wait a bit for any scripts to execute\n await page.waitForTimeout(100);\n break;\n }\n }\n }\n\n /**\n * Check for payload reflection in page content\n */\n private static async checkReflection(\n page: Page,\n step: Step & { type: \"browser.input\" },\n payloadSet: RuntimePayload,\n payloadValue: string,\n ): Promise<Finding | undefined> {\n const content = await page.content();\n\n // Check for reflection patterns\n for (const pattern of payloadSet.detectPatterns) {\n if (pattern.test(content)) {\n return {\n type: payloadSet.category,\n severity: BrowserRunner.getSeverity(payloadSet.category),\n title: `${payloadSet.category.toUpperCase()} vulnerability detected`,\n description: `Payload pattern was reflected in page content`,\n stepId: step.id,\n payload: payloadValue,\n url: page.url(),\n evidence: content.match(pattern)?.[0]?.slice(0, 200),\n };\n }\n }\n\n // Check if payload appears verbatim\n if (content.includes(payloadValue)) {\n return {\n type: payloadSet.category,\n severity: \"medium\",\n title: `Potential ${payloadSet.category.toUpperCase()} - payload reflection`,\n description: `Payload was reflected in page without encoding`,\n stepId: step.id,\n payload: payloadValue,\n url: page.url(),\n };\n }\n\n return undefined;\n }\n\n /**\n * Determine severity based on vulnerability category\n */\n private static getSeverity(\n category: PayloadCategory,\n ): \"critical\" | \"high\" | \"medium\" | \"low\" | \"info\" {\n switch (category) {\n case \"sqli\":\n case \"command-injection\":\n case \"xxe\":\n return \"critical\";\n case \"xss\":\n case \"ssrf\":\n case \"path-traversal\":\n return \"high\";\n case \"open-redirect\":\n return \"medium\";\n default:\n return \"medium\";\n }\n }\n}\n"],"mappings":"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","names":[]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { RecordOptions, RecordingHandle, Session, RunContext, RunResult, VulcnDriver } from '@vulcn/engine';
|
|
3
|
+
import { Browser } from 'playwright';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Browser Recorder Implementation
|
|
7
|
+
*
|
|
8
|
+
* Records browser interactions as replayable sessions.
|
|
9
|
+
* Uses Playwright for browser automation.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Browser Recorder - captures browser interactions
|
|
14
|
+
*/
|
|
15
|
+
declare class BrowserRecorder {
|
|
16
|
+
/**
|
|
17
|
+
* Start a new recording session
|
|
18
|
+
*/
|
|
19
|
+
static start(config: BrowserConfig, _options?: RecordOptions): Promise<RecordingHandle>;
|
|
20
|
+
/**
|
|
21
|
+
* Attach event listeners to the page
|
|
22
|
+
*/
|
|
23
|
+
private static attachListeners;
|
|
24
|
+
/**
|
|
25
|
+
* Inject the recording script into the page
|
|
26
|
+
*/
|
|
27
|
+
private static injectRecordingScript;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Browser Runner Implementation
|
|
32
|
+
*
|
|
33
|
+
* Replays browser sessions with security payloads.
|
|
34
|
+
* Uses plugin hooks for detection.
|
|
35
|
+
*/
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Browser Runner - replays sessions with payloads
|
|
39
|
+
*/
|
|
40
|
+
declare class BrowserRunner {
|
|
41
|
+
/**
|
|
42
|
+
* Execute a session with security payloads
|
|
43
|
+
*/
|
|
44
|
+
static execute(session: Session, ctx: RunContext): Promise<RunResult>;
|
|
45
|
+
/**
|
|
46
|
+
* Replay session steps with payload injected at target step
|
|
47
|
+
*/
|
|
48
|
+
private static replayWithPayload;
|
|
49
|
+
/**
|
|
50
|
+
* Check for payload reflection in page content
|
|
51
|
+
*/
|
|
52
|
+
private static checkReflection;
|
|
53
|
+
/**
|
|
54
|
+
* Determine severity based on vulnerability category
|
|
55
|
+
*/
|
|
56
|
+
private static getSeverity;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Browser utilities for @vulcn/driver-browser
|
|
61
|
+
* Smart browser launching with system browser fallback
|
|
62
|
+
*/
|
|
63
|
+
|
|
64
|
+
type BrowserType = "chromium" | "firefox" | "webkit";
|
|
65
|
+
interface LaunchOptions {
|
|
66
|
+
browser?: BrowserType;
|
|
67
|
+
headless?: boolean;
|
|
68
|
+
}
|
|
69
|
+
interface BrowserLaunchResult {
|
|
70
|
+
browser: Browser;
|
|
71
|
+
channel?: string;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Launch a browser with smart fallback:
|
|
75
|
+
* 1. Try system Chrome/Edge first (zero-install experience)
|
|
76
|
+
* 2. Fall back to Playwright's bundled browsers
|
|
77
|
+
*/
|
|
78
|
+
declare function launchBrowser(options?: LaunchOptions): Promise<BrowserLaunchResult>;
|
|
79
|
+
/**
|
|
80
|
+
* Install Playwright browsers
|
|
81
|
+
*/
|
|
82
|
+
declare function installBrowsers(browsers?: BrowserType[]): Promise<void>;
|
|
83
|
+
/**
|
|
84
|
+
* Check which browsers are available
|
|
85
|
+
*/
|
|
86
|
+
declare function checkBrowsers(): Promise<{
|
|
87
|
+
systemChrome: boolean;
|
|
88
|
+
systemEdge: boolean;
|
|
89
|
+
playwrightChromium: boolean;
|
|
90
|
+
playwrightFirefox: boolean;
|
|
91
|
+
playwrightWebkit: boolean;
|
|
92
|
+
}>;
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* @vulcn/driver-browser
|
|
96
|
+
*
|
|
97
|
+
* Browser recording driver for Vulcn.
|
|
98
|
+
* Uses Playwright to record and replay web application interactions.
|
|
99
|
+
*
|
|
100
|
+
* Step types:
|
|
101
|
+
* - browser.navigate - Navigate to a URL
|
|
102
|
+
* - browser.click - Click an element
|
|
103
|
+
* - browser.input - Type into an input field
|
|
104
|
+
* - browser.keypress - Press a key
|
|
105
|
+
* - browser.scroll - Scroll the page
|
|
106
|
+
* - browser.wait - Wait for a duration
|
|
107
|
+
*/
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Browser driver configuration schema
|
|
111
|
+
*/
|
|
112
|
+
declare const configSchema: z.ZodObject<{
|
|
113
|
+
/** Starting URL for recording */
|
|
114
|
+
startUrl: z.ZodOptional<z.ZodString>;
|
|
115
|
+
/** Browser type */
|
|
116
|
+
browser: z.ZodDefault<z.ZodEnum<["chromium", "firefox", "webkit"]>>;
|
|
117
|
+
/** Viewport size */
|
|
118
|
+
viewport: z.ZodDefault<z.ZodObject<{
|
|
119
|
+
width: z.ZodDefault<z.ZodNumber>;
|
|
120
|
+
height: z.ZodDefault<z.ZodNumber>;
|
|
121
|
+
}, "strip", z.ZodTypeAny, {
|
|
122
|
+
width: number;
|
|
123
|
+
height: number;
|
|
124
|
+
}, {
|
|
125
|
+
width?: number | undefined;
|
|
126
|
+
height?: number | undefined;
|
|
127
|
+
}>>;
|
|
128
|
+
/** Run headless */
|
|
129
|
+
headless: z.ZodDefault<z.ZodBoolean>;
|
|
130
|
+
}, "strip", z.ZodTypeAny, {
|
|
131
|
+
browser: "chromium" | "firefox" | "webkit";
|
|
132
|
+
viewport: {
|
|
133
|
+
width: number;
|
|
134
|
+
height: number;
|
|
135
|
+
};
|
|
136
|
+
headless: boolean;
|
|
137
|
+
startUrl?: string | undefined;
|
|
138
|
+
}, {
|
|
139
|
+
startUrl?: string | undefined;
|
|
140
|
+
browser?: "chromium" | "firefox" | "webkit" | undefined;
|
|
141
|
+
viewport?: {
|
|
142
|
+
width?: number | undefined;
|
|
143
|
+
height?: number | undefined;
|
|
144
|
+
} | undefined;
|
|
145
|
+
headless?: boolean | undefined;
|
|
146
|
+
}>;
|
|
147
|
+
type BrowserConfig = z.infer<typeof configSchema>;
|
|
148
|
+
/**
|
|
149
|
+
* Browser step types
|
|
150
|
+
*/
|
|
151
|
+
declare const BROWSER_STEP_TYPES: readonly ["browser.navigate", "browser.click", "browser.input", "browser.keypress", "browser.scroll", "browser.wait"];
|
|
152
|
+
type BrowserStepType = (typeof BROWSER_STEP_TYPES)[number];
|
|
153
|
+
/**
|
|
154
|
+
* Browser-specific step schemas
|
|
155
|
+
*/
|
|
156
|
+
declare const BrowserStepSchema: z.ZodDiscriminatedUnion<"type", [z.ZodObject<{
|
|
157
|
+
id: z.ZodString;
|
|
158
|
+
type: z.ZodLiteral<"browser.navigate">;
|
|
159
|
+
url: z.ZodString;
|
|
160
|
+
timestamp: z.ZodNumber;
|
|
161
|
+
}, "strip", z.ZodTypeAny, {
|
|
162
|
+
type: "browser.navigate";
|
|
163
|
+
id: string;
|
|
164
|
+
url: string;
|
|
165
|
+
timestamp: number;
|
|
166
|
+
}, {
|
|
167
|
+
type: "browser.navigate";
|
|
168
|
+
id: string;
|
|
169
|
+
url: string;
|
|
170
|
+
timestamp: number;
|
|
171
|
+
}>, z.ZodObject<{
|
|
172
|
+
id: z.ZodString;
|
|
173
|
+
type: z.ZodLiteral<"browser.click">;
|
|
174
|
+
selector: z.ZodString;
|
|
175
|
+
position: z.ZodOptional<z.ZodObject<{
|
|
176
|
+
x: z.ZodNumber;
|
|
177
|
+
y: z.ZodNumber;
|
|
178
|
+
}, "strip", z.ZodTypeAny, {
|
|
179
|
+
x: number;
|
|
180
|
+
y: number;
|
|
181
|
+
}, {
|
|
182
|
+
x: number;
|
|
183
|
+
y: number;
|
|
184
|
+
}>>;
|
|
185
|
+
timestamp: z.ZodNumber;
|
|
186
|
+
}, "strip", z.ZodTypeAny, {
|
|
187
|
+
type: "browser.click";
|
|
188
|
+
id: string;
|
|
189
|
+
timestamp: number;
|
|
190
|
+
selector: string;
|
|
191
|
+
position?: {
|
|
192
|
+
x: number;
|
|
193
|
+
y: number;
|
|
194
|
+
} | undefined;
|
|
195
|
+
}, {
|
|
196
|
+
type: "browser.click";
|
|
197
|
+
id: string;
|
|
198
|
+
timestamp: number;
|
|
199
|
+
selector: string;
|
|
200
|
+
position?: {
|
|
201
|
+
x: number;
|
|
202
|
+
y: number;
|
|
203
|
+
} | undefined;
|
|
204
|
+
}>, z.ZodObject<{
|
|
205
|
+
id: z.ZodString;
|
|
206
|
+
type: z.ZodLiteral<"browser.input">;
|
|
207
|
+
selector: z.ZodString;
|
|
208
|
+
value: z.ZodString;
|
|
209
|
+
injectable: z.ZodDefault<z.ZodBoolean>;
|
|
210
|
+
timestamp: z.ZodNumber;
|
|
211
|
+
}, "strip", z.ZodTypeAny, {
|
|
212
|
+
value: string;
|
|
213
|
+
type: "browser.input";
|
|
214
|
+
id: string;
|
|
215
|
+
timestamp: number;
|
|
216
|
+
selector: string;
|
|
217
|
+
injectable: boolean;
|
|
218
|
+
}, {
|
|
219
|
+
value: string;
|
|
220
|
+
type: "browser.input";
|
|
221
|
+
id: string;
|
|
222
|
+
timestamp: number;
|
|
223
|
+
selector: string;
|
|
224
|
+
injectable?: boolean | undefined;
|
|
225
|
+
}>, z.ZodObject<{
|
|
226
|
+
id: z.ZodString;
|
|
227
|
+
type: z.ZodLiteral<"browser.keypress">;
|
|
228
|
+
key: z.ZodString;
|
|
229
|
+
modifiers: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
230
|
+
timestamp: z.ZodNumber;
|
|
231
|
+
}, "strip", z.ZodTypeAny, {
|
|
232
|
+
type: "browser.keypress";
|
|
233
|
+
id: string;
|
|
234
|
+
timestamp: number;
|
|
235
|
+
key: string;
|
|
236
|
+
modifiers?: string[] | undefined;
|
|
237
|
+
}, {
|
|
238
|
+
type: "browser.keypress";
|
|
239
|
+
id: string;
|
|
240
|
+
timestamp: number;
|
|
241
|
+
key: string;
|
|
242
|
+
modifiers?: string[] | undefined;
|
|
243
|
+
}>, z.ZodObject<{
|
|
244
|
+
id: z.ZodString;
|
|
245
|
+
type: z.ZodLiteral<"browser.scroll">;
|
|
246
|
+
selector: z.ZodOptional<z.ZodString>;
|
|
247
|
+
position: z.ZodObject<{
|
|
248
|
+
x: z.ZodNumber;
|
|
249
|
+
y: z.ZodNumber;
|
|
250
|
+
}, "strip", z.ZodTypeAny, {
|
|
251
|
+
x: number;
|
|
252
|
+
y: number;
|
|
253
|
+
}, {
|
|
254
|
+
x: number;
|
|
255
|
+
y: number;
|
|
256
|
+
}>;
|
|
257
|
+
timestamp: z.ZodNumber;
|
|
258
|
+
}, "strip", z.ZodTypeAny, {
|
|
259
|
+
type: "browser.scroll";
|
|
260
|
+
id: string;
|
|
261
|
+
timestamp: number;
|
|
262
|
+
position: {
|
|
263
|
+
x: number;
|
|
264
|
+
y: number;
|
|
265
|
+
};
|
|
266
|
+
selector?: string | undefined;
|
|
267
|
+
}, {
|
|
268
|
+
type: "browser.scroll";
|
|
269
|
+
id: string;
|
|
270
|
+
timestamp: number;
|
|
271
|
+
position: {
|
|
272
|
+
x: number;
|
|
273
|
+
y: number;
|
|
274
|
+
};
|
|
275
|
+
selector?: string | undefined;
|
|
276
|
+
}>, z.ZodObject<{
|
|
277
|
+
id: z.ZodString;
|
|
278
|
+
type: z.ZodLiteral<"browser.wait">;
|
|
279
|
+
duration: z.ZodNumber;
|
|
280
|
+
timestamp: z.ZodNumber;
|
|
281
|
+
}, "strip", z.ZodTypeAny, {
|
|
282
|
+
type: "browser.wait";
|
|
283
|
+
id: string;
|
|
284
|
+
timestamp: number;
|
|
285
|
+
duration: number;
|
|
286
|
+
}, {
|
|
287
|
+
type: "browser.wait";
|
|
288
|
+
id: string;
|
|
289
|
+
timestamp: number;
|
|
290
|
+
duration: number;
|
|
291
|
+
}>]>;
|
|
292
|
+
type BrowserStep = z.infer<typeof BrowserStepSchema>;
|
|
293
|
+
/**
|
|
294
|
+
* Browser driver for Vulcn
|
|
295
|
+
*/
|
|
296
|
+
declare const browserDriver: VulcnDriver;
|
|
297
|
+
|
|
298
|
+
export { BROWSER_STEP_TYPES, type BrowserConfig, BrowserRecorder, BrowserRunner, type BrowserStep, BrowserStepSchema, type BrowserStepType, checkBrowsers, configSchema, browserDriver as default, installBrowsers, launchBrowser };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { RecordOptions, RecordingHandle, Session, RunContext, RunResult, VulcnDriver } from '@vulcn/engine';
|
|
3
|
+
import { Browser } from 'playwright';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Browser Recorder Implementation
|
|
7
|
+
*
|
|
8
|
+
* Records browser interactions as replayable sessions.
|
|
9
|
+
* Uses Playwright for browser automation.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Browser Recorder - captures browser interactions
|
|
14
|
+
*/
|
|
15
|
+
declare class BrowserRecorder {
|
|
16
|
+
/**
|
|
17
|
+
* Start a new recording session
|
|
18
|
+
*/
|
|
19
|
+
static start(config: BrowserConfig, _options?: RecordOptions): Promise<RecordingHandle>;
|
|
20
|
+
/**
|
|
21
|
+
* Attach event listeners to the page
|
|
22
|
+
*/
|
|
23
|
+
private static attachListeners;
|
|
24
|
+
/**
|
|
25
|
+
* Inject the recording script into the page
|
|
26
|
+
*/
|
|
27
|
+
private static injectRecordingScript;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Browser Runner Implementation
|
|
32
|
+
*
|
|
33
|
+
* Replays browser sessions with security payloads.
|
|
34
|
+
* Uses plugin hooks for detection.
|
|
35
|
+
*/
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Browser Runner - replays sessions with payloads
|
|
39
|
+
*/
|
|
40
|
+
declare class BrowserRunner {
|
|
41
|
+
/**
|
|
42
|
+
* Execute a session with security payloads
|
|
43
|
+
*/
|
|
44
|
+
static execute(session: Session, ctx: RunContext): Promise<RunResult>;
|
|
45
|
+
/**
|
|
46
|
+
* Replay session steps with payload injected at target step
|
|
47
|
+
*/
|
|
48
|
+
private static replayWithPayload;
|
|
49
|
+
/**
|
|
50
|
+
* Check for payload reflection in page content
|
|
51
|
+
*/
|
|
52
|
+
private static checkReflection;
|
|
53
|
+
/**
|
|
54
|
+
* Determine severity based on vulnerability category
|
|
55
|
+
*/
|
|
56
|
+
private static getSeverity;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Browser utilities for @vulcn/driver-browser
|
|
61
|
+
* Smart browser launching with system browser fallback
|
|
62
|
+
*/
|
|
63
|
+
|
|
64
|
+
type BrowserType = "chromium" | "firefox" | "webkit";
|
|
65
|
+
interface LaunchOptions {
|
|
66
|
+
browser?: BrowserType;
|
|
67
|
+
headless?: boolean;
|
|
68
|
+
}
|
|
69
|
+
interface BrowserLaunchResult {
|
|
70
|
+
browser: Browser;
|
|
71
|
+
channel?: string;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Launch a browser with smart fallback:
|
|
75
|
+
* 1. Try system Chrome/Edge first (zero-install experience)
|
|
76
|
+
* 2. Fall back to Playwright's bundled browsers
|
|
77
|
+
*/
|
|
78
|
+
declare function launchBrowser(options?: LaunchOptions): Promise<BrowserLaunchResult>;
|
|
79
|
+
/**
|
|
80
|
+
* Install Playwright browsers
|
|
81
|
+
*/
|
|
82
|
+
declare function installBrowsers(browsers?: BrowserType[]): Promise<void>;
|
|
83
|
+
/**
|
|
84
|
+
* Check which browsers are available
|
|
85
|
+
*/
|
|
86
|
+
declare function checkBrowsers(): Promise<{
|
|
87
|
+
systemChrome: boolean;
|
|
88
|
+
systemEdge: boolean;
|
|
89
|
+
playwrightChromium: boolean;
|
|
90
|
+
playwrightFirefox: boolean;
|
|
91
|
+
playwrightWebkit: boolean;
|
|
92
|
+
}>;
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* @vulcn/driver-browser
|
|
96
|
+
*
|
|
97
|
+
* Browser recording driver for Vulcn.
|
|
98
|
+
* Uses Playwright to record and replay web application interactions.
|
|
99
|
+
*
|
|
100
|
+
* Step types:
|
|
101
|
+
* - browser.navigate - Navigate to a URL
|
|
102
|
+
* - browser.click - Click an element
|
|
103
|
+
* - browser.input - Type into an input field
|
|
104
|
+
* - browser.keypress - Press a key
|
|
105
|
+
* - browser.scroll - Scroll the page
|
|
106
|
+
* - browser.wait - Wait for a duration
|
|
107
|
+
*/
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Browser driver configuration schema
|
|
111
|
+
*/
|
|
112
|
+
declare const configSchema: z.ZodObject<{
|
|
113
|
+
/** Starting URL for recording */
|
|
114
|
+
startUrl: z.ZodOptional<z.ZodString>;
|
|
115
|
+
/** Browser type */
|
|
116
|
+
browser: z.ZodDefault<z.ZodEnum<["chromium", "firefox", "webkit"]>>;
|
|
117
|
+
/** Viewport size */
|
|
118
|
+
viewport: z.ZodDefault<z.ZodObject<{
|
|
119
|
+
width: z.ZodDefault<z.ZodNumber>;
|
|
120
|
+
height: z.ZodDefault<z.ZodNumber>;
|
|
121
|
+
}, "strip", z.ZodTypeAny, {
|
|
122
|
+
width: number;
|
|
123
|
+
height: number;
|
|
124
|
+
}, {
|
|
125
|
+
width?: number | undefined;
|
|
126
|
+
height?: number | undefined;
|
|
127
|
+
}>>;
|
|
128
|
+
/** Run headless */
|
|
129
|
+
headless: z.ZodDefault<z.ZodBoolean>;
|
|
130
|
+
}, "strip", z.ZodTypeAny, {
|
|
131
|
+
browser: "chromium" | "firefox" | "webkit";
|
|
132
|
+
viewport: {
|
|
133
|
+
width: number;
|
|
134
|
+
height: number;
|
|
135
|
+
};
|
|
136
|
+
headless: boolean;
|
|
137
|
+
startUrl?: string | undefined;
|
|
138
|
+
}, {
|
|
139
|
+
startUrl?: string | undefined;
|
|
140
|
+
browser?: "chromium" | "firefox" | "webkit" | undefined;
|
|
141
|
+
viewport?: {
|
|
142
|
+
width?: number | undefined;
|
|
143
|
+
height?: number | undefined;
|
|
144
|
+
} | undefined;
|
|
145
|
+
headless?: boolean | undefined;
|
|
146
|
+
}>;
|
|
147
|
+
type BrowserConfig = z.infer<typeof configSchema>;
|
|
148
|
+
/**
|
|
149
|
+
* Browser step types
|
|
150
|
+
*/
|
|
151
|
+
declare const BROWSER_STEP_TYPES: readonly ["browser.navigate", "browser.click", "browser.input", "browser.keypress", "browser.scroll", "browser.wait"];
|
|
152
|
+
type BrowserStepType = (typeof BROWSER_STEP_TYPES)[number];
|
|
153
|
+
/**
|
|
154
|
+
* Browser-specific step schemas
|
|
155
|
+
*/
|
|
156
|
+
declare const BrowserStepSchema: z.ZodDiscriminatedUnion<"type", [z.ZodObject<{
|
|
157
|
+
id: z.ZodString;
|
|
158
|
+
type: z.ZodLiteral<"browser.navigate">;
|
|
159
|
+
url: z.ZodString;
|
|
160
|
+
timestamp: z.ZodNumber;
|
|
161
|
+
}, "strip", z.ZodTypeAny, {
|
|
162
|
+
type: "browser.navigate";
|
|
163
|
+
id: string;
|
|
164
|
+
url: string;
|
|
165
|
+
timestamp: number;
|
|
166
|
+
}, {
|
|
167
|
+
type: "browser.navigate";
|
|
168
|
+
id: string;
|
|
169
|
+
url: string;
|
|
170
|
+
timestamp: number;
|
|
171
|
+
}>, z.ZodObject<{
|
|
172
|
+
id: z.ZodString;
|
|
173
|
+
type: z.ZodLiteral<"browser.click">;
|
|
174
|
+
selector: z.ZodString;
|
|
175
|
+
position: z.ZodOptional<z.ZodObject<{
|
|
176
|
+
x: z.ZodNumber;
|
|
177
|
+
y: z.ZodNumber;
|
|
178
|
+
}, "strip", z.ZodTypeAny, {
|
|
179
|
+
x: number;
|
|
180
|
+
y: number;
|
|
181
|
+
}, {
|
|
182
|
+
x: number;
|
|
183
|
+
y: number;
|
|
184
|
+
}>>;
|
|
185
|
+
timestamp: z.ZodNumber;
|
|
186
|
+
}, "strip", z.ZodTypeAny, {
|
|
187
|
+
type: "browser.click";
|
|
188
|
+
id: string;
|
|
189
|
+
timestamp: number;
|
|
190
|
+
selector: string;
|
|
191
|
+
position?: {
|
|
192
|
+
x: number;
|
|
193
|
+
y: number;
|
|
194
|
+
} | undefined;
|
|
195
|
+
}, {
|
|
196
|
+
type: "browser.click";
|
|
197
|
+
id: string;
|
|
198
|
+
timestamp: number;
|
|
199
|
+
selector: string;
|
|
200
|
+
position?: {
|
|
201
|
+
x: number;
|
|
202
|
+
y: number;
|
|
203
|
+
} | undefined;
|
|
204
|
+
}>, z.ZodObject<{
|
|
205
|
+
id: z.ZodString;
|
|
206
|
+
type: z.ZodLiteral<"browser.input">;
|
|
207
|
+
selector: z.ZodString;
|
|
208
|
+
value: z.ZodString;
|
|
209
|
+
injectable: z.ZodDefault<z.ZodBoolean>;
|
|
210
|
+
timestamp: z.ZodNumber;
|
|
211
|
+
}, "strip", z.ZodTypeAny, {
|
|
212
|
+
value: string;
|
|
213
|
+
type: "browser.input";
|
|
214
|
+
id: string;
|
|
215
|
+
timestamp: number;
|
|
216
|
+
selector: string;
|
|
217
|
+
injectable: boolean;
|
|
218
|
+
}, {
|
|
219
|
+
value: string;
|
|
220
|
+
type: "browser.input";
|
|
221
|
+
id: string;
|
|
222
|
+
timestamp: number;
|
|
223
|
+
selector: string;
|
|
224
|
+
injectable?: boolean | undefined;
|
|
225
|
+
}>, z.ZodObject<{
|
|
226
|
+
id: z.ZodString;
|
|
227
|
+
type: z.ZodLiteral<"browser.keypress">;
|
|
228
|
+
key: z.ZodString;
|
|
229
|
+
modifiers: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
230
|
+
timestamp: z.ZodNumber;
|
|
231
|
+
}, "strip", z.ZodTypeAny, {
|
|
232
|
+
type: "browser.keypress";
|
|
233
|
+
id: string;
|
|
234
|
+
timestamp: number;
|
|
235
|
+
key: string;
|
|
236
|
+
modifiers?: string[] | undefined;
|
|
237
|
+
}, {
|
|
238
|
+
type: "browser.keypress";
|
|
239
|
+
id: string;
|
|
240
|
+
timestamp: number;
|
|
241
|
+
key: string;
|
|
242
|
+
modifiers?: string[] | undefined;
|
|
243
|
+
}>, z.ZodObject<{
|
|
244
|
+
id: z.ZodString;
|
|
245
|
+
type: z.ZodLiteral<"browser.scroll">;
|
|
246
|
+
selector: z.ZodOptional<z.ZodString>;
|
|
247
|
+
position: z.ZodObject<{
|
|
248
|
+
x: z.ZodNumber;
|
|
249
|
+
y: z.ZodNumber;
|
|
250
|
+
}, "strip", z.ZodTypeAny, {
|
|
251
|
+
x: number;
|
|
252
|
+
y: number;
|
|
253
|
+
}, {
|
|
254
|
+
x: number;
|
|
255
|
+
y: number;
|
|
256
|
+
}>;
|
|
257
|
+
timestamp: z.ZodNumber;
|
|
258
|
+
}, "strip", z.ZodTypeAny, {
|
|
259
|
+
type: "browser.scroll";
|
|
260
|
+
id: string;
|
|
261
|
+
timestamp: number;
|
|
262
|
+
position: {
|
|
263
|
+
x: number;
|
|
264
|
+
y: number;
|
|
265
|
+
};
|
|
266
|
+
selector?: string | undefined;
|
|
267
|
+
}, {
|
|
268
|
+
type: "browser.scroll";
|
|
269
|
+
id: string;
|
|
270
|
+
timestamp: number;
|
|
271
|
+
position: {
|
|
272
|
+
x: number;
|
|
273
|
+
y: number;
|
|
274
|
+
};
|
|
275
|
+
selector?: string | undefined;
|
|
276
|
+
}>, z.ZodObject<{
|
|
277
|
+
id: z.ZodString;
|
|
278
|
+
type: z.ZodLiteral<"browser.wait">;
|
|
279
|
+
duration: z.ZodNumber;
|
|
280
|
+
timestamp: z.ZodNumber;
|
|
281
|
+
}, "strip", z.ZodTypeAny, {
|
|
282
|
+
type: "browser.wait";
|
|
283
|
+
id: string;
|
|
284
|
+
timestamp: number;
|
|
285
|
+
duration: number;
|
|
286
|
+
}, {
|
|
287
|
+
type: "browser.wait";
|
|
288
|
+
id: string;
|
|
289
|
+
timestamp: number;
|
|
290
|
+
duration: number;
|
|
291
|
+
}>]>;
|
|
292
|
+
type BrowserStep = z.infer<typeof BrowserStepSchema>;
|
|
293
|
+
/**
|
|
294
|
+
* Browser driver for Vulcn
|
|
295
|
+
*/
|
|
296
|
+
declare const browserDriver: VulcnDriver;
|
|
297
|
+
|
|
298
|
+
export { BROWSER_STEP_TYPES, type BrowserConfig, BrowserRecorder, BrowserRunner, type BrowserStep, BrowserStepSchema, type BrowserStepType, checkBrowsers, configSchema, browserDriver as default, installBrowsers, launchBrowser };
|