### Patch CLI Aliases for Rebranding Source: https://context7.com/kaliiiiiiiiii-vinyzu/patchright/llms.txt Performs text replacements across Playwright's CLI source files to rebrand all user-visible strings from "Playwright" to "Patchright". This ensures the `npx patchright install` and `npx patchright` CLI commands work and display consistent branding. ```typescript // Affected files: // packages/playwright-core/src/cli/program.ts // packages/playwright-core/src/cli/programWithTestStub.ts // packages/playwright-core/src/server/android/android.ts // packages/playwright-core/src/server/registry/index.ts // Sample substitutions: // "Playwright version:" → "Patchright version:" // "npx playwright install" → "npx patchright install" // "npm install @playwright/test" → "npm install -D patchright" // "return `playwright`;" → "return `patchright`;" // Result: after patching and building, // $ npx patchright install chromium // Patchright version: 1.58.0 // Downloading Chromium ... ``` -------------------------------- ### On-Demand Clock Initialization in All Frames Source: https://context7.com/kaliiiiiiiiii-vinyzu/patchright/llms.txt Patches `Clock._installIfNeeded` to re-evaluate clock init-scripts in all frames on demand, avoiding race conditions by priming execution contexts before evaluation. This replaces the reliance on `Runtime.enable`-based `evaluateOnNewDocument`. ```typescript // Target: packages/playwright-core/src/server/clock.ts // After patch, _installIfNeeded evaluates clock scripts inline if already installed: if (this._initScripts.length) { const sources = JSON.stringify(this._initScripts.map(s => s.source)); await this._evaluateInFrames(`(() => { if (globalThis.__pwClock?.controller) return; for (const source of ${sources}) (0, eval)(source); })();`); return; } // Consumer usage (patchright-nodejs): import { chromium } from "patchright"; const browser = await chromium.launch(); const page = await browser.newPage(); await page.clock.install({ time: new Date("2024-01-01T00:00:00Z") }); await page.goto("https://example.com"); const now = await page.evaluate(() => Date.now()); console.log(new Date(now).getFullYear()); // 2024 await browser.close(); ``` -------------------------------- ### Patch Entry Point - patchright_driver_patch.ts Source: https://context7.com/kaliiiiiiiiii-vinyzu/patchright/llms.txt This script orchestrates the application of all patches to a cloned Playwright source tree. It also extends the Playwright IPC protocol with new parameters. ```typescript // Apply all patches to a checked-out Playwright source tree: // $ git clone https://github.com/microsoft/playwright --branch v1.58.0 // $ cd playwright && npm ci // $ cd .. && npm run patch # runs: cd playwright && tsx ../patchright_driver_patch.ts import { Project, IndentationText } from "ts-morph"; import YAML from "yaml"; import * as patches from "./driver_patches/index.ts"; import * as clientPatches from "./patchright-nodejs/index.ts"; const project = new Project({ manipulationSettings: { indentationText: IndentationText.TwoSpaces }, }); // Server-side patches patches.patchChromiumSwitches(project); // removes automation flags, adds stealth flag patches.patchFrames(project); // Runtime.enable-free execution context patches.patchCRPage(project); // init-script routing and binding plumbing patches.patchBrowserContext(project); // focusControl, exposeBinding // ... (30+ more patch calls) // Protocol extension: add isolatedContext to Frame/JSHandle/Worker evaluate calls const protocol = YAML.parse(await fs.readFile("packages/protocol/src/protocol.yml", "utf8")); for (const type of ["Frame", "JSHandle", "Worker"]) { protocol[type].commands.evaluateExpression.parameters.isolatedContext = "boolean?"; protocol[type].commands.evaluateExpressionHandle.parameters.isolatedContext = "boolean?"; } protocol.ContextOptions.properties.focusControl = "boolean?"; protocol.Route.commands.continue.parameters.patchrightInitScript = "boolean?"; await fs.writeFile("packages/protocol/src/protocol.yml", YAML.stringify(protocol)); await project.save(); // writes all patched files back to disk ``` -------------------------------- ### Patch Chromium for Headless Mode and Fingerprint Removal Source: https://context7.com/kaliiiiiiiiii-vinyzu/patchright/llms.txt Forces `--headless=new` and removes `--enable-unsafe-swiftshader` to improve stealth and reduce fingerprinting. ```typescript // Target file: packages/playwright-core/src/server/chromium/chromium.ts export function patchChromium(project: Project) { const sourceFile = project.addSourceFileAtPath( "packages/playwright-core/src/server/chromium/chromium.ts" ); const chromiumClass = sourceFile.getClassOrThrow("Chromium"); const innerDefaultArgs = chromiumClass.getMethodOrThrow("_innerDefaultArgs"); // Always use --headless=new instead of checking PLAYWRIGHT_CHROMIUM_USE_HEADLESS_NEW innerDefaultArgs.getDescendantsOfKind(SyntaxKind.IfStatement).forEach(stmt => { if (stmt.getExpression().getText().includes("PLAYWRIGHT_CHROMIUM_USE_HEADLESS_NEW")) stmt.replaceWithText("chromeArguments.push('--headless=new');"); }); // Remove --enable-unsafe-swiftshader (fingerprint vector) innerDefaultArgs .getDescendantsOfKind(SyntaxKind.ExpressionStatement) .filter(s => s.getText().includes("--enable-unsafe-swiftshader")) .forEach(s => s.remove()); } ``` -------------------------------- ### Patch Frames for On-Demand CDP and Shadow DOM Support Source: https://context7.com/kaliiiiiiiiii-vinyzu/patchright/llms.txt Replaces Runtime.enable with on-demand CDP calls and adds support for closed Shadow DOM roots. This patch enables interaction with elements inside closed shadow roots and optimizes context resolution. ```typescript // Key behaviour after patching: // 1. frame._context("main") → resolves main world without Runtime.enable // 2. frame._context("utility") → creates an isolated world via Page.createIsolatedWorld // 3. Closed Shadow Root elements are found and interacted with via standard locators // Example: using patchright-nodejs (consumer of the patched driver) import { chromium } from "patchright"; const browser = await chromium.launch({ headless: true }); const page = await browser.newPage(); await page.goto("https://example.com"); // Works transparently on elements inside closed shadow roots: const shadowEl = page.locator("my-component >> .inner-button"); await shadowEl.click(); // _customFindElementsByParsed resolves the closed shadow root // evaluateExpression in isolated context (no Runtime.enable leak): const result = await page.evaluate(() => document.title); // Internally uses frame._context("main") → Runtime.evaluate("globalThis") → contextId await browser.close(); ``` -------------------------------- ### Extract Patched Symbols Utility Source: https://context7.com/kaliiiiiiiiii-vinyzu/patchright/llms.txt A static analysis utility that scans `driver_patches/*.ts` files using regex to extract (`playwrightFile`, `symbol`, `kind`) triples that Patchright patches. It can optionally fetch upstream Playwright source to resolve exact line numbers. ```typescript import { extractPatchedSymbols } from "./utils/extract_patched_symbols.ts"; // Extract all patched symbols with line numbers from Playwright v1.58.0: const symbols = await extractPatchedSymbols({ newVersionTag: "v1.58.0", githubToken: process.env.GITHUB_TOKEN, }); console.log(symbols[0]); // { // symbol: "FrameManager", // kind: "class", // playwrightFile: "packages/playwright-core/src/server/frames.ts", // patchFile: "framesPatch.ts", // patchFileLineStart: 19, // patchFileLineEnd: 19, // playwrightFileLineStart: 42, // playwrightFileLineEnd: 890 // } // CLI usage: // tsx utils/extract_patched_symbols.ts --new-version v1.58.0 --output symbols.json ``` -------------------------------- ### Check Patch Impact Utility Source: https://context7.com/kaliiiiiiiiii-vinyzu/patchright/llms.txt The CI regression-detection engine that compares two Playwright release tags, fetches changed files, parses diffs, and cross-references changes against the symbol manifest. It produces a JSON report, a GitHub Step Summary, and a `.patch` file. ```typescript // CLI (invoked by .github/workflows/check_patch_impact.yml): // tsx utils/check_patch_impact.ts \ // --old-version v1.57.0 \ // --new-version v1.58.0 \ // --report report.json \ // --summary step_summary.md \ // --diff affected_diff.patch // report.json structure: // { // "old_version": "1.57.0", // "new_version": "1.58.0", // "summary": { "total": 87, "affected": 3, "unaffected": 84 }, // "affected": [ // { // "symbol": "_context", // "kind": "method", // "playwrightFile": "packages/playwright-core/src/server/frames.ts", // "patchFile": "framesPatch.ts", // "changeType": "body_changed", // "diffSnippet": "- const context = await this._contextData...\n+ ..." // } // ], // "unaffected": [ ... ] // } // Change types: // "signature_changed" — method/function parameters changed // "body_changed" — implementation changed but signature stable // "symbol_removed" — symbol deleted from upstream file // "symbol_added" — symbol added (new dependency for patch) // "unchanged" — no upstream diff touches this symbol ``` -------------------------------- ### Robust Context Fallback for Page Binding Dispatch Source: https://context7.com/kaliiiiiiiiii-vinyzu/patchright/llms.txt This patch ensures that binding results are delivered through multiple context fallbacks (current, main, utility) if the original execution context is no longer available. It modifies the `PageBinding.dispatch` method. ```typescript static async dispatch(page: Page, payload: string, context: dom.FrameExecutionContext) { const { name, seq, serializedArgs } = JSON.parse(payload); const deliver = async (deliverPayload: any) => { try { await context.evaluate(deliverBindingResult, deliverPayload); return; } catch (e) { // Fall back to main/utility context if original context is gone const frame = context.frame; const mainCtx = await frame?._mainContext().catch(() => null); const utilCtx = await frame?._utilityContext().catch(() => null); for (const ctx of [mainCtx, utilCtx]) { if (!ctx || ctx === context) continue; try { await ctx.evaluate(deliverBindingResult, deliverPayload); return; } catch {} } } }; const binding = page.getBinding(name); const result = binding.needsHandle ? await binding.playwrightFunction({ frame: context.frame, page }, await context.evaluateHandle(takeBindingHandle, { name, seq })) : await binding.playwrightFunction({ frame: context.frame, page }, ...serializedArgs.map(parseEvaluationResultValue)); await deliver({ name, seq, result }); } ``` -------------------------------- ### Patch CRPage for Reduced Global Calls and Dialog Buffering Source: https://context7.com/kaliiiiiiiiii-vinyzu/patchright/llms.txt Rewires CRPage to eliminate global Runtime.enable/addBinding calls and uses HTML-response injection for init scripts. It also enhances dialog-buffering for popups. ```typescript // Target: packages/playwright-core/src/server/chromium/crPage.ts // After patching, CRPage.constructor does: // this._networkManager.setRequestInterception(true); // for init-script injection // this.initScriptTag = crypto.randomBytes(20).toString('hex'); // unique tag per page // FrameSession._initBinding registers a binding without Runtime.enable: async _initBinding(binding: PageBinding) { this._exposedBindingNames.push(binding.name); this._exposedBindingScripts.push(binding.source); const contextIds = Array.from(this._contextIdToContext.keys()); await Promise.all([ this._client._sendMayFail('Runtime.addBinding', { name: binding.name }), ...contextIds.map(id => this._client._sendMayFail('Runtime.addBinding', { name: binding.name, executionContextId: id }) ), ]); await Promise.all(contextIds.map(id => this._client._sendMayFail('Runtime.evaluate', { expression: binding.source, contextId: id, awaitPromise: true, }) )); } // Consumer usage (patchright-nodejs): const page = await browser.newPage(); await page.exposeBinding("myBinding", (source, arg) => { console.log("Called from browser:", arg); return "response"; }); await page.evaluate(() => window.myBinding("hello")); // → "Called from browser: hello" ``` -------------------------------- ### Patch XPath Selector Engine for Closed Shadow DOM Source: https://context7.com/kaliiiiiiiiii-vinyzu/patchright/llms.txt Extends the injected XPath selector engine to query elements within closed Shadow DOM roots. It achieves this by serializing, re-parsing, and evaluating XPath against the shadow root's content, then mapping results back to live nodes. ```typescript // Target: packages/injected/src/xpathSelectorEngine.ts // Effect: XPath locators now pierce closed shadow roots // Consumer usage (patchright-nodejs / patchright-python): import { chromium } from "patchright"; const browser = await chromium.launch(); const page = await browser.newPage(); await page.goto("https://site-with-closed-shadow-dom.com"); // Standard Playwright would throw; Patchright resolves via the patched engine: const el = page.locator("xpath=//my-element/button[@class='submit']"); await el.click(); // Internally: XPathEngine.queryAll detects DocumentFragment root → DOMParser fallback await browser.close(); ``` -------------------------------- ### Assert Defined Utility in TypeScript Source: https://context7.com/kaliiiiiiiiii-vinyzu/patchright/llms.txt Use this utility to ensure AST node lookups are not null or undefined. It throws a clear error if an expected node is missing, preventing silent failures in patch files. ```typescript export function assertDefined(value: T | undefined | null, name?: string): T { if (value == null) throw new Error(`Required value${name ? ` "${name}"` : ""} is null or undefined"); return value; } ``` ```typescript const updateReqStatement = assertDefined( crPageConstructor .getStatements() .find(s => s.getText() === "this.updateRequestInterception();"), "updateRequestInterception statement" ); ``` -------------------------------- ### Patch BrowserContextDispatcher for Dialog Handling Source: https://context7.com/kaliiiiiiiiii-vinyzu/patchright/llms.txt This patch ensures dialogs are immediately wrapped in a DialogDispatcher and dispatched as events. This prevents dialogs from being lost when a page is opened and a dialog fires before the event listener is fully set up. ```typescript // Target: packages/playwright-core/src/server/dispatchers/browserContextDispatcher.ts // After patch: this._dialogHandler = dialog => { this._dispatchEvent('dialog', { dialog: new DialogDispatcher(this, dialog) }); return true; }; // Consumer usage (patchright-nodejs): const context = await browser.newContext(); context.on("dialog", async dialog => { console.log(dialog.message()); // "Are you sure?" await dialog.accept(); }); const page = await context.newPage(); await page.goto("https://example.com"); await page.evaluate(() => confirm("Are you sure?")); // dialog captured correctly ``` -------------------------------- ### Patch Frame Selectors for Stable DOM Indices Source: https://context7.com/kaliiiiiiiiii-vinyzu/patchright/llms.txt Enhances `FrameSelectors` by adding `_customFindFramesByParsed` and `_findElementPositionInDomTree`. These enable stable DOM-tree position indices for deduplication and ordering of elements across regular and closed shadow DOMs. It also includes a null-check guard for cleaner error handling. ```typescript // _findElementPositionInDomTree: assigns a dot-notation tree index like "0.2.1" // so elements from different shadow roots can be sorted into document order. // _customFindFramesByParsed: iterates selector parts, resolves closed shadow roots // via DOM.describeNode with pierce:true, and merges results in DOM order. // Consumer: this is an internal method; its effect is transparent to end users: import { chromium } from "patchright"; const browser = await chromium.launch(); const page = await browser.newPage(); // locator.all() on a page mixing open/closed shadow roots works correctly: const items = await page.locator("ul.list > li").all(); console.log(items.length); // correct count including items in closed shadow DOMs await browser.close(); ``` -------------------------------- ### Patch BrowserContext for focusControl and serviceWorker Source: https://context7.com/kaliiiiiiiiii-vinyzu/patchright/llms.txt Patches BrowserContext to add the `focusControl` option, disabling Playwright's focus emulation, and replaces the service worker registration override with a less obvious form. This reduces the surface area for detection. ```typescript // Target: packages/playwright-core/src/server/browserContext.ts export function patchBrowserContext(project: Project) { const sourceFile = project.addSourceFileAtPath( "packages/playwright-core/src/server/browserContext.ts" ); const ctxClass = sourceFile.getClassOrThrow("BrowserContext"); // Stealth: replace obvious service worker override with a minimal one // Before: addInitScript({ script: "navigator.serviceWorker.register = ..." }) // After: addInitScript(`if (navigator.serviceWorker) navigator.serviceWorker.register = async () => { };`) // Add focusControl to defaultNewContextParamValues const defaults = sourceFile .getVariableDeclarationOrThrow("defaultNewContextParamValues") .getInitializerIfKindOrThrow(SyntaxKind.ObjectLiteralExpression); if (!defaults.getProperty("focusControl")) defaults.addPropertyAssignment({ name: "focusControl", initializer: "false" }); } ``` ```typescript // Consumer usage: const context = await browser.newContext({ focusControl: true, // disables Emulation.setFocusEmulationEnabled — reduces detection surface }); const page = await context.newPage(); ``` -------------------------------- ### Isolated Context for JS Evaluation Source: https://context7.com/kaliiiiiiiiii-vinyzu/patchright/llms.txt Adds an `isolatedContext` parameter to `JSHandle.evaluateExpression` and `JSHandle.evaluateExpressionHandle`. When true, evaluation occurs in the utility (isolated) world; when false, in the main world. This mechanism prevents the `Runtime.enable` leak. ```typescript // Target: packages/playwright-core/src/server/javascript.ts // After patch, evaluateExpression accepts an optional isolatedContext flag: // isolatedContext = true → uses frame._utilityContext() (isolated world, no Runtime.enable) // isolatedContext = false → uses frame._mainContext() (page's main world) // isolatedContext = undefined → uses this._context (default, unchanged) // Consumer (internal, transparent to end users): // page.evaluate(fn) → main world, no Runtime.enable leak // page.evaluate(fn, {isolatedContext: true}) → utility/isolated world const handle = await page.evaluateHandle(() => document.body); // handle.evaluate uses isolatedContext routing internally const tagName = await handle.evaluate(el => el.tagName); console.log(tagName); // "BODY" ``` -------------------------------- ### Patch Chromium Switches - driver_patches/chromiumSwitchesPatch.ts Source: https://context7.com/kaliiiiiiiiii-vinyzu/patchright/llms.txt This function modifies the Chromium switches in Playwright's source code. It removes flags that reveal automation and adds the `--disable-blink-features=AutomationControlled` flag to counter detection. ```typescript // Target file: packages/playwright-core/src/server/chromium/chromiumSwitches.ts // Effect on the patched binary: // REMOVED: --enable-automation // REMOVED: --disable-popup-blocking // REMOVED: --disable-component-update // REMOVED: --disable-default-apps // REMOVED: --disable-extensions // REMOVED: --disable-features=...AutomationControlled... // ADDED: --disable-blink-features=AutomationControlled export function patchChromiumSwitches(project: Project) { const sourceFile = project.addSourceFileAtPath( "packages/playwright-core/src/server/chromium/chromiumSwitches.ts" ); const switchesArrow = sourceFile .getVariableDeclarationOrThrow("chromiumSwitches") .getInitializerIfKindOrThrow(SyntaxKind.ArrowFunction); const switchesArray = switchesArrow .getBody() .getFirstDescendantByKindOrThrow(SyntaxKind.ArrayLiteralExpression); const toDisable = [ "assistantMode ? '' : '--enable-automation'", "'--disable-popup-blocking'", "'--disable-extensions'", // ... (additional flags) ]; switchesArray .getElements() .filter(el => toDisable.includes(el.getText())) .forEach(el => switchesArray.removeElement(el)); switchesArray.addElement("'--disable-blink-features=AutomationControlled'"); } ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.