diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 000000000..c6c8b3621 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,9 @@ +root = true + +[*] +indent_style = space +indent_size = 2 +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..087b570bb --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +examples/recorder-crx/dist +examples/todomvc-crx/dist +node_modules/ +lib/ diff --git a/.npmignore b/.npmignore new file mode 100644 index 000000000..7f10a1e2a --- /dev/null +++ b/.npmignore @@ -0,0 +1,15 @@ +# This ignores everything by default, except for package.json and LICENSE and README.md. +# See https://docs.npmjs.com/misc/developers +**/* +# Include sources from lib, but not map files. +!lib/**/*.js +!lib/**/*.mjs +# Include generated types and entrypoint. +!index.d.ts +!src/types/types.d.ts +!playwright/packages/playwright-core/types/types.d.ts +!playwright/packages/playwright/types/test.d.ts +# Include essentials. +!README.md +!LICENSE +!NOTICE diff --git a/LICENSE b/LICENSE new file mode 100644 index 000000000..717e848c6 --- /dev/null +++ b/LICENSE @@ -0,0 +1,203 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Portions Copyright (c) Rui Figueira. + Portions Copyright (c) Microsoft Corporation. + Portions Copyright 2017 Google Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/NOTICE b/NOTICE new file mode 100644 index 000000000..a132ddb6d --- /dev/null +++ b/NOTICE @@ -0,0 +1,5 @@ +Playwright CRX +Copyright (c) Rui Figueira + +This software contains code derived from the Playwright project (https://github.com/microsoft/playwright), +available under the Apache 2.0 license (https://github.com/microsoft/playwright/blob/master/LICENSE). diff --git a/README.md b/README.md new file mode 100644 index 000000000..f6dc31264 --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# playwright-crx + +This package contains the [Chrome Extensions](https://developer.chrome.com/docs/extensions/) flavor of the [Playwright](http://github.com/microsoft/playwright) library. If you want to write end-to-end tests, we recommend [@playwright/test](https://playwright.dev/docs/intro). diff --git a/examples/recorder-crx/package.json b/examples/recorder-crx/package.json new file mode 100644 index 000000000..8f5096bf2 --- /dev/null +++ b/examples/recorder-crx/package.json @@ -0,0 +1,14 @@ +{ + "name": "recorder-crx", + "version": "0.0.4-next", + "type": "module", + "keywords": [], + "author": "", + "license": "ISC", + "scripts": { + "build": "tsc && vite build && vite --config vite.recorder.config.ts build" + }, + "dependencies": { + "playwright-crx": "0.0.4-next" + } +} diff --git a/examples/recorder-crx/public/icon-16x16.png b/examples/recorder-crx/public/icon-16x16.png new file mode 100644 index 000000000..1f6c4d6c1 Binary files /dev/null and b/examples/recorder-crx/public/icon-16x16.png differ diff --git a/examples/recorder-crx/public/icon-192x192.png b/examples/recorder-crx/public/icon-192x192.png new file mode 100644 index 000000000..a4f0dbfa9 Binary files /dev/null and b/examples/recorder-crx/public/icon-192x192.png differ diff --git a/examples/recorder-crx/public/icon-32x32.png b/examples/recorder-crx/public/icon-32x32.png new file mode 100644 index 000000000..650be1334 Binary files /dev/null and b/examples/recorder-crx/public/icon-32x32.png differ diff --git a/examples/recorder-crx/public/icon-48x48.png b/examples/recorder-crx/public/icon-48x48.png new file mode 100644 index 000000000..2abbb660e Binary files /dev/null and b/examples/recorder-crx/public/icon-48x48.png differ diff --git a/examples/recorder-crx/public/manifest.json b/examples/recorder-crx/public/manifest.json new file mode 100644 index 000000000..9d2eb4831 --- /dev/null +++ b/examples/recorder-crx/public/manifest.json @@ -0,0 +1,23 @@ +{ + "name": "Playwright CRX", + "version": "0.0.0.2", + "manifest_version": 3, + "icons": { + "16": "icon-16x16.png", + "32": "icon-32x32.png", + "48": "icon-48x48.png", + "128": "icon-192x192.png" + }, + "background": { + "service_worker": "background.js", + "type": "module" + }, + "action": { + "default_icon": { + "16": "icon-16x16.png", + "32": "icon-32x32.png" + }, + "default_title": "Record" + }, + "permissions": ["debugger", "tabs", "contextMenus"] +} diff --git a/examples/recorder-crx/src/background.ts b/examples/recorder-crx/src/background.ts new file mode 100644 index 000000000..01aaf224d --- /dev/null +++ b/examples/recorder-crx/src/background.ts @@ -0,0 +1,64 @@ +/** + * Copyright (c) Rui Figueira. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type { CrxApplication } from 'playwright-crx'; +import { _setUnderTest, crx } from 'playwright-crx'; + +// we must lazy initialize it +let crxAppPromise: Promise | undefined; + +async function getCrxApp() { + if (!crxAppPromise) { + crxAppPromise = crx.start().then(crxApp => { + crxApp.recorder.addListener('hide', async () => { + await crxApp.detachAll(); + await chrome.action.enable(); + }); + return crxApp; + }); + } + + return await crxAppPromise; +} + +async function attach(tab: chrome.tabs.Tab) { + await chrome.action.disable(); + + const crxApp = await getCrxApp(); + + if (crxApp.recorder.isHidden()) + await crxApp.recorder.show({ mode: 'recording' }); + + try { + await crxApp.attach(tab.id!); + await chrome.action.disable(tab.id); + } catch (e) { + // do nothing + } + await chrome.action.enable(); +} + +chrome.action.onClicked.addListener(attach); + +chrome.contextMenus.create({ + id: 'pw-recorder', + title: 'Attach to Playwright Recorder', + contexts: ['page'], +}); + +chrome.contextMenus.onClicked.addListener(async (_, tab) => { + if (tab) await attach(tab); +}); diff --git a/examples/recorder-crx/src/contentscript.ts b/examples/recorder-crx/src/contentscript.ts new file mode 100644 index 000000000..13dcb063a --- /dev/null +++ b/examples/recorder-crx/src/contentscript.ts @@ -0,0 +1,47 @@ +/** + * Copyright (c) Rui Figueira. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// if not running as a chrome extension, skip this... +if (typeof chrome !== 'undefined' && chrome.runtime) { + let _port: chrome.runtime.Port | undefined; + + const wnd: any = window; + + wnd.dispatch = async function _onDispatch(data: any) { + _port?.postMessage({ type: 'recorderEvent', ...data }); + }; + + chrome.runtime.onConnect.addListener(port => { + _port = port; + + port.onMessage.addListener(async msg => { + if (!('type' in msg) || msg.type !== 'recorder') return; + + switch (msg.method) { + case 'setPaused': wnd.playwrightSetPaused(msg.paused); break; + case 'setMode': wnd.playwrightSetMode(msg.mode); break; + case 'setSources': wnd.playwrightSetSources(msg.sources); break; + case 'updateCallLogs': wnd.playwrightUpdateLogs(msg.callLogs); break; + case 'setSelector': wnd.playwrightSetSelector(msg.selector, msg.focus); break; + case 'setFileIfNeeded': wnd.playwrightSetFileIfNeeded(msg.file); break; + } + }); + + port.onDisconnect.addListener(() => { + _port = undefined; + }); + }); +} diff --git a/examples/recorder-crx/tsconfig.json b/examples/recorder-crx/tsconfig.json new file mode 100644 index 000000000..196c455c1 --- /dev/null +++ b/examples/recorder-crx/tsconfig.json @@ -0,0 +1,23 @@ +{ + "compilerOptions": { + "target": "ES2020", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2020", "DOM", "DOM.Iterable"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true, + }, + "include": ["src"] +} diff --git a/examples/recorder-crx/vite.config.ts b/examples/recorder-crx/vite.config.ts new file mode 100644 index 000000000..0770a3d73 --- /dev/null +++ b/examples/recorder-crx/vite.config.ts @@ -0,0 +1,44 @@ +/** + * Copyright (c) Rui Figueira. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import path from 'path'; +import { defineConfig } from 'vite'; +import sourcemaps from 'rollup-plugin-sourcemaps'; + +// https://vitejs.dev/config/ +export default defineConfig({ + build: { + // recorder assets are copied to devtools output dir, so this will prevent those assets from being deleted. + emptyOutDir: false, + // skip code obfuscation + minify: false, + // chunk limit is not an issue, this is a browser extension + chunkSizeWarningLimit: 10240, + sourcemap: true, + rollupOptions: { + // @ts-ignore + plugins: [sourcemaps()], + input: { + 'background': path.resolve(__dirname, 'src/background.ts'), + }, + output: { + entryFileNames: '[name].js', + chunkFileNames: '[name].js', + assetFileNames: '[name].[ext]', + }, + }, + }, +}); diff --git a/examples/recorder-crx/vite.recorder.config.ts b/examples/recorder-crx/vite.recorder.config.ts new file mode 100644 index 000000000..3ab9a79e1 --- /dev/null +++ b/examples/recorder-crx/vite.recorder.config.ts @@ -0,0 +1,58 @@ +/** + * Copyright (c) Rui Figueira. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import path from 'path'; +import recorderConfig from '../../playwright/packages/recorder/vite.config'; +import type { UserConfig } from 'vite'; +import { defineConfig } from 'vite'; +import assert from 'assert'; + +const userRecorderConfig = recorderConfig as UserConfig; + +// https://vitejs.dev/config/ +export default defineConfig({ + ...userRecorderConfig, + plugins: [ + ...userRecorderConfig.plugins!, + { + name: 'playwright-bundle', + transformIndexHtml: { + order: 'pre', + handler: (html) => { + // inject contentscript.ts in the recorder + const result = html.replace(``, ` + + + `); + assert(html !== result, 'html should have been changed'); + return result; + } + }, + } + ], + base: './', + root: '../../playwright/packages/recorder', + build: { + ...userRecorderConfig.build, + emptyOutDir: false, + outDir: path.resolve(__dirname, './dist'), + }, + optimizeDeps: { + include: [ + path.resolve(__dirname, './src/contentscript.ts'), + ], + }, +}); diff --git a/examples/todomvc-crx/.gitignore b/examples/todomvc-crx/.gitignore new file mode 100644 index 000000000..849ddff3b --- /dev/null +++ b/examples/todomvc-crx/.gitignore @@ -0,0 +1 @@ +dist/ diff --git a/examples/todomvc-crx/package.json b/examples/todomvc-crx/package.json new file mode 100644 index 000000000..47fa2f40f --- /dev/null +++ b/examples/todomvc-crx/package.json @@ -0,0 +1,18 @@ +{ + "name": "todomvc-crx", + "version": "0.0.4-next", + "type": "module", + "keywords": [], + "author": "", + "license": "ISC", + "scripts": { + "build": "tsc && vite build" + }, + "dependencies": { + "playwright-crx": "0.0.4-next" + }, + "devDependencies": { + "typescript": "^5.1.3", + "vite": "^4.3.9" + } +} diff --git a/examples/todomvc-crx/public/manifest.json b/examples/todomvc-crx/public/manifest.json new file mode 100644 index 000000000..3fb955c27 --- /dev/null +++ b/examples/todomvc-crx/public/manifest.json @@ -0,0 +1,13 @@ +{ + "name": "Playwright CRX - TodoMVC", + "version": "0.0.0.1", + "manifest_version": 3, + "background": { + "service_worker": "background.js", + "type": "module" + }, + "action": { + "default_title": "Playwright CRX - TodoMVC" + }, + "permissions": ["debugger", "tabs"] +} diff --git a/examples/todomvc-crx/src/background.ts b/examples/todomvc-crx/src/background.ts new file mode 100644 index 000000000..fcfb55e2e --- /dev/null +++ b/examples/todomvc-crx/src/background.ts @@ -0,0 +1,34 @@ +/** + * Copyright (c) Rui Figueira. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { crx } from 'playwright-crx'; +import { createTodos } from './todos'; + +const crxAppPromise = crx.start({ slowMo: 500 }); + +chrome.action.onClicked.addListener(async ({ id: tabId }) => { + await chrome.action.disable(); + + const crxApp = await crxAppPromise; + const page = await crxApp.attach(tabId!).catch(() => crxApp.newPage()); + + try { + await createTodos(page); + } finally { + await crxApp.detach(page); + await chrome.action.enable(); + } +}); diff --git a/examples/todomvc-crx/src/todos.ts b/examples/todomvc-crx/src/todos.ts new file mode 100644 index 000000000..3cb5d20c6 --- /dev/null +++ b/examples/todomvc-crx/src/todos.ts @@ -0,0 +1,28 @@ +import { Page } from "playwright-crx"; + +export async function createTodos(page: Page) { + + const TODO_ITEMS = [ + 'buy some cheese', + 'feed the cat', + 'book a doctors appointment' + ]; + + await page.goto('https://demo.playwright.dev/todomvc'); + + // delete all todos + await page.evaluate(() => { + if (localStorage?.length) { + localStorage.clear(); + location.reload(); + } + }); + + // create a new todo locator + const newTodo = page.getByPlaceholder('What needs to be done?'); + + for (const item of TODO_ITEMS) { + await newTodo.fill(item); + await newTodo.press('Enter'); + } +} diff --git a/examples/todomvc-crx/tsconfig.json b/examples/todomvc-crx/tsconfig.json new file mode 100644 index 000000000..75abdef26 --- /dev/null +++ b/examples/todomvc-crx/tsconfig.json @@ -0,0 +1,23 @@ +{ + "compilerOptions": { + "target": "ES2020", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2020", "DOM", "DOM.Iterable"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true + }, + "include": ["src"] +} diff --git a/examples/todomvc-crx/vite.config.ts b/examples/todomvc-crx/vite.config.ts new file mode 100644 index 000000000..63f58b240 --- /dev/null +++ b/examples/todomvc-crx/vite.config.ts @@ -0,0 +1,34 @@ +/** + * Copyright (c) Rui Figueira. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import path from 'path'; +import { defineConfig } from 'vite'; + +// https://vitejs.dev/config/ +export default defineConfig({ + build: { + // playwright-crx cannot be obfuscated + minify: false, + rollupOptions: { + input: { + 'background': path.resolve(__dirname, 'src/background.ts'), + }, + output: { + entryFileNames: '[name].js', + }, + }, + }, +}); diff --git a/index.d.ts b/index.d.ts new file mode 100644 index 000000000..1ebd96761 --- /dev/null +++ b/index.d.ts @@ -0,0 +1,24 @@ +/** + * Copyright (c) Microsoft Corporation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type { Crx } from './src/types/types'; +export type { Crx, CrxApplication, CrxRecorder } from './src/types/types'; +export type { Page, Frame, BrowserContext, Worker, JSHandle, ElementHandle, Locator, BrowserType, CDPSession, Accessibility, ElectronApplication, Android, AndroidDevice, AndroidInput, AndroidSocket, AndroidWebView, APIRequest, APIRequestContext, APIResponse, Browser, BrowserServer, ConsoleMessage, Coverage, Dialog, Download, Electron, FileChooser, FrameLocator, Keyboard, Logger, Mouse, Request, Response, Route, Selectors, Touchscreen, Tracing, Video, WebError, WebSocket, BrowserContextOptions, ViewportSize, HTTPCredentials, Geolocation, LaunchOptions, ConnectOverCDPOptions, ConnectOptions, LocatorScreenshotOptions, Cookie, PageScreenshotOptions, ChromiumBrowserContext, ChromiumBrowser, FirefoxBrowser, WebKitBrowser, ChromiumCoverage } from './playwright/packages/playwright-core/types/types'; +export type { expect, test } from './playwright/packages/playwright/types/test'; + +export const crx: Crx; + +export function _setUnderTest(): void; diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 000000000..e8e091c60 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,4695 @@ +{ + "name": "playwright-crx", + "version": "0.0.4-next", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "playwright-crx", + "version": "0.0.4-next", + "license": "Apache-2.0", + "workspaces": [ + "." + ], + "dependencies": { + "@isomorphic-git/lightning-fs": "^4.6.0", + "assert": "^2.1.0", + "babel-bundle": "file:./playwright/packages/playwright/bundles/babel", + "browserify-zlib": "^0.2.0", + "buffer": "^6.0.3", + "crypto-browserify": "^3.12.0", + "events": "^3.3.0", + "expect-bundle": "file:./playwright/packages/playwright/bundles/expect", + "https-browserify": "^1.0.0", + "inspector": "^0.5.0", + "os-browserify": "^0.3.0", + "path": "^0.12.7", + "process": "^0.11.10", + "readable-stream": "^4.4.2", + "setimmediate": "^1.0.5", + "stream-http": "^3.2.0", + "string_decoder": "^1.3.0", + "test-utils-bundle": "file:./playwright/packages/playwright/bundles/utils", + "url": "^0.11.3", + "util": "^0.12.5", + "utils-bundle": "file:./playwright/packages/playwright-core/bundles/utils", + "zip-bundle": "file:./playwright/packages/playwright-core/bundles/zip" + }, + "devDependencies": { + "@types/chrome": "^0.0.246", + "@vitejs/plugin-react": "^4.1.0", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "rimraf": "^5.0.5", + "rollup-plugin-sourcemaps": "^0.6.3", + "typescript": "5.2.2", + "vite": "4.4.10", + "vite-plugin-require-transform": "1.0.21", + "web-package": "file:./playwright/packages/web" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", + "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.22.13", + "license": "MIT", + "dependencies": { + "@babel/highlight": "^7.22.13", + "chalk": "^2.4.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.22.20.tgz", + "integrity": "sha512-BQYjKbpXjoXwFW5jGqiizJQQT/aC7pFm9Ok1OWssonuguICi264lbgMzRp2ZMmRSlfkX6DsWDDcsrctK8Rwfiw==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.0.tgz", + "integrity": "sha512-97z/ju/Jy1rZmDxybphrBuI+jtJjFVoz7Mr9yUQVVVi+DNZE333uFQeMOqcCIy1x3WYBIbWftUSLmbNXNT7qFQ==", + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.22.13", + "@babel/generator": "^7.23.0", + "@babel/helper-compilation-targets": "^7.22.15", + "@babel/helper-module-transforms": "^7.23.0", + "@babel/helpers": "^7.23.0", + "@babel/parser": "^7.23.0", + "@babel/template": "^7.22.15", + "@babel/traverse": "^7.23.0", + "@babel/types": "^7.23.0", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.23.0", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.23.0", + "@jridgewell/gen-mapping": "^0.3.2", + "@jridgewell/trace-mapping": "^0.3.17", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.15.tgz", + "integrity": "sha512-y6EEzULok0Qvz8yyLkCvVX+02ic+By2UdOhylwUOvOn9dvYc9mKICJuuU1n1XBI02YWsNsnrY1kc6DVbjcXbtw==", + "dependencies": { + "@babel/compat-data": "^7.22.9", + "@babel/helper-validator-option": "^7.22.15", + "browserslist": "^4.21.9", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/@babel/helper-environment-visitor": { + "version": "7.22.20", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-function-name": { + "version": "7.23.0", + "license": "MIT", + "dependencies": { + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-hoist-variables": { + "version": "7.22.5", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz", + "integrity": "sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==", + "dependencies": { + "@babel/types": "^7.22.15" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.0.tgz", + "integrity": "sha512-WhDWw1tdrlT0gMgUJSlX0IQvoO1eN279zrAUbVB+KpV2c3Tylz8+GnKOLllCS6Z/iZQEyVYxhZVUdPTqs2YYPw==", + "dependencies": { + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-module-imports": "^7.22.15", + "@babel/helper-simple-access": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/helper-validator-identifier": "^7.22.20" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", + "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-simple-access": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", + "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.22.6", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.22.5", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.22.20", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.22.15.tgz", + "integrity": "sha512-bMn7RmyFjY/mdECUbgn9eoSY4vqvacUnS9i9vGAGttgFWesO6B4CYWA7XlpbWgBt71iv/hfbPlynohStqnu5hA==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.23.1", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.1.tgz", + "integrity": "sha512-chNpneuK18yW5Oxsr+t553UZzzAs3aZnFm4bxhebsNTeshrC95yA7l5yl7GBAG+JG1rF0F7zzD2EixK9mWSDoA==", + "dependencies": { + "@babel/template": "^7.22.15", + "@babel/traverse": "^7.23.0", + "@babel/types": "^7.23.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.22.20", + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.23.0", + "license": "MIT", + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-self": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.22.5.tgz", + "integrity": "sha512-nTh2ogNUtxbiSbxaT4Ds6aXnXEipHweN9YRgOX/oNXdf0cCrGn/+2LozFa3lnPV5D90MkjhgckCPBrsoSc1a7g==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-source": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.22.5.tgz", + "integrity": "sha512-yIiRO6yobeEIaI0RTbIr8iAK9FcBHLtZq0S89ZPjDLQXBA4xvghaKqI0etp/tF3htTM0sazJKKLz9oEiGRtu7w==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/template": { + "version": "7.22.15", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.22.13", + "@babel/parser": "^7.22.15", + "@babel/types": "^7.22.15" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.23.0", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.22.13", + "@babel/generator": "^7.23.0", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/parser": "^7.23.0", + "@babel/types": "^7.23.0", + "debug": "^4.1.0", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.23.0", + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.20", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.18.20", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isomorphic-git/idb-keyval": { + "version": "3.3.2", + "license": "Apache-2.0" + }, + "node_modules/@isomorphic-git/lightning-fs": { + "version": "4.6.0", + "license": "MIT", + "dependencies": { + "@isomorphic-git/idb-keyval": "3.3.2", + "isomorphic-textencoder": "1.0.1", + "just-debounce-it": "1.1.0", + "just-once": "1.1.0" + }, + "bin": { + "superblocktxt": "src/superblocktxt.js" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.3", + "license": "MIT", + "dependencies": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.1", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.1.2", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.19", + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@rollup/pluginutils": { + "version": "3.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "0.0.39", + "estree-walker": "^1.0.1", + "picomatch": "^2.2.2" + }, + "engines": { + "node": ">= 8.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0" + } + }, + "node_modules/@types/babel__core": { + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.2.tgz", + "integrity": "sha512-pNpr1T1xLUc2l3xJKuPtsEky3ybxN3m4fJkknfIpTCTfIZCDW57oAg+EfCgIIp2rvCe0Wn++/FfodDS4YXxBwA==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.6.5", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.5.tgz", + "integrity": "sha512-h9yIuWbJKdOPLJTbmSpPzkF67e659PbQDba7ifWm5BJ8xTv+sDmS7rFmywkWOvXedGTivCdeGSIIX8WLcRTz8w==", + "dev": true, + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.2", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.2.tgz", + "integrity": "sha512-/AVzPICMhMOMYoSx9MoKpGDKdBRsIXMNByh1PXSZoa+v6ZoLa8xxtsT/uLQ/NJm0XVAWl/BvId4MlDeXJaeIZQ==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.2.tgz", + "integrity": "sha512-ojlGK1Hsfce93J0+kn3H5R73elidKUaZonirN33GSmgTUMpzI/MIFfSpF3haANe3G1bEBS9/9/QEqwTzwqFsKw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.20.7" + } + }, + "node_modules/@types/chrome": { + "version": "0.0.246", + "resolved": "https://registry.npmjs.org/@types/chrome/-/chrome-0.0.246.tgz", + "integrity": "sha512-MxGxEomGxsJiL9xe/7ZwVgwdn8XVKWbPvxpVQl3nWOjrS0Ce63JsfzxUc4aU3GvRcUPYsfufHmJ17BFyKxeA4g==", + "dev": true, + "dependencies": { + "@types/filesystem": "*", + "@types/har-format": "*" + } + }, + "node_modules/@types/estree": { + "version": "0.0.39", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/filesystem": { + "version": "0.0.33", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/filewriter": "*" + } + }, + "node_modules/@types/filewriter": { + "version": "0.0.30", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/har-format": { + "version": "1.2.13", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "20.8.0", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true + }, + "node_modules/@vitejs/plugin-react": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.1.0.tgz", + "integrity": "sha512-rM0SqazU9iqPUraQ2JlIvReeaxOoRj6n+PzB1C0cBzIbd8qP336nC39/R9yPi3wVcah7E7j/kdU1uCUqMEU4OQ==", + "dev": true, + "dependencies": { + "@babel/core": "^7.22.20", + "@babel/plugin-transform-react-jsx-self": "^7.22.5", + "@babel/plugin-transform-react-jsx-source": "^7.22.5", + "@types/babel__core": "^7.20.2", + "react-refresh": "^0.14.0" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "peerDependencies": { + "vite": "^4.2.0" + } + }, + "node_modules/abort-controller": { + "version": "3.0.0", + "license": "MIT", + "dependencies": { + "event-target-shim": "^5.0.0" + }, + "engines": { + "node": ">=6.5" + } + }, + "node_modules/ansi-regex": { + "version": "6.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/ansi-styles": { + "version": "3.2.1", + "license": "MIT", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/asn1.js": { + "version": "5.4.1", + "license": "MIT", + "dependencies": { + "bn.js": "^4.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0", + "safer-buffer": "^2.1.0" + } + }, + "node_modules/asn1.js/node_modules/bn.js": { + "version": "4.12.0", + "license": "MIT" + }, + "node_modules/assert": { + "version": "2.1.0", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "is-nan": "^1.3.2", + "object-is": "^1.1.5", + "object.assign": "^4.1.4", + "util": "^0.12.5" + } + }, + "node_modules/atob": { + "version": "2.1.2", + "dev": true, + "license": "(MIT OR Apache-2.0)", + "bin": { + "atob": "bin/atob.js" + }, + "engines": { + "node": ">= 4.5.0" + } + }, + "node_modules/available-typed-arrays": { + "version": "1.0.5", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/babel-bundle": { + "resolved": "playwright/packages/playwright/bundles/babel", + "link": true + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "node_modules/base64-js": { + "version": "1.5.1", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/bindings": { + "version": "1.2.1", + "license": "MIT", + "optional": true + }, + "node_modules/bn.js": { + "version": "5.2.1", + "license": "MIT" + }, + "node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/brorand": { + "version": "1.1.0", + "license": "MIT" + }, + "node_modules/browserify-aes": { + "version": "1.2.0", + "license": "MIT", + "dependencies": { + "buffer-xor": "^1.0.3", + "cipher-base": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.3", + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/browserify-cipher": { + "version": "1.0.1", + "license": "MIT", + "dependencies": { + "browserify-aes": "^1.0.4", + "browserify-des": "^1.0.0", + "evp_bytestokey": "^1.0.0" + } + }, + "node_modules/browserify-des": { + "version": "1.0.2", + "license": "MIT", + "dependencies": { + "cipher-base": "^1.0.1", + "des.js": "^1.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "node_modules/browserify-rsa": { + "version": "4.1.0", + "license": "MIT", + "dependencies": { + "bn.js": "^5.0.0", + "randombytes": "^2.0.1" + } + }, + "node_modules/browserify-sign": { + "version": "4.2.1", + "license": "ISC", + "dependencies": { + "bn.js": "^5.1.1", + "browserify-rsa": "^4.0.1", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "elliptic": "^6.5.3", + "inherits": "^2.0.4", + "parse-asn1": "^5.1.5", + "readable-stream": "^3.6.0", + "safe-buffer": "^5.2.0" + } + }, + "node_modules/browserify-sign/node_modules/readable-stream": { + "version": "3.6.2", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/browserify-zlib": { + "version": "0.2.0", + "license": "MIT", + "dependencies": { + "pako": "~1.0.5" + } + }, + "node_modules/browserslist": { + "version": "4.22.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.1.tgz", + "integrity": "sha512-FEVc202+2iuClEhZhrWy6ZiAcRLvNMyYcxZ8raemul1DYVOVdFsbqckWLdsixQZCpJlwe77Z3UTalE7jsjnKfQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "caniuse-lite": "^1.0.30001541", + "electron-to-chromium": "^1.4.535", + "node-releases": "^2.0.13", + "update-browserslist-db": "^1.0.13" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/buffer": { + "version": "6.0.3", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/buffer-xor": { + "version": "1.0.3", + "license": "MIT" + }, + "node_modules/bufferutil": { + "version": "4.0.7", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "node-gyp-build": "^4.3.0" + }, + "engines": { + "node": ">=6.14.2" + } + }, + "node_modules/builtin-status-codes": { + "version": "3.0.0", + "license": "MIT" + }, + "node_modules/call-bind": { + "version": "1.0.2", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001546", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001546.tgz", + "integrity": "sha512-zvtSJwuQFpewSyRrI3AsftF6rM0X80mZkChIt1spBGEvRglCrjTniXvinc8JKRoqTwXAgvqTImaN9igfSMtUBw==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ] + }, + "node_modules/chalk": { + "version": "2.4.2", + "license": "MIT", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/chalk/node_modules/escape-string-regexp": { + "version": "1.0.5", + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/cipher-base": { + "version": "1.0.4", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/codemirror": { + "version": "5.65.15", + "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.65.15.tgz", + "integrity": "sha512-YC4EHbbwQeubZzxLl5G4nlbLc1T21QTrKGaOal/Pkm9dVDMZXMH7+ieSPEOZCtO9I68i8/oteJKOxzHC2zR+0g==", + "dev": true + }, + "node_modules/color-convert": { + "version": "1.9.3", + "license": "MIT", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color-name": { + "version": "1.1.3", + "license": "MIT" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==" + }, + "node_modules/create-ecdh": { + "version": "4.0.4", + "license": "MIT", + "dependencies": { + "bn.js": "^4.1.0", + "elliptic": "^6.5.3" + } + }, + "node_modules/create-ecdh/node_modules/bn.js": { + "version": "4.12.0", + "license": "MIT" + }, + "node_modules/create-hash": { + "version": "1.2.0", + "license": "MIT", + "dependencies": { + "cipher-base": "^1.0.1", + "inherits": "^2.0.1", + "md5.js": "^1.3.4", + "ripemd160": "^2.0.1", + "sha.js": "^2.4.0" + } + }, + "node_modules/create-hmac": { + "version": "1.1.7", + "license": "MIT", + "dependencies": { + "cipher-base": "^1.0.3", + "create-hash": "^1.1.0", + "inherits": "^2.0.1", + "ripemd160": "^2.0.0", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/crypto-browserify": { + "version": "3.12.0", + "license": "MIT", + "dependencies": { + "browserify-cipher": "^1.0.0", + "browserify-sign": "^4.0.0", + "create-ecdh": "^4.0.0", + "create-hash": "^1.1.0", + "create-hmac": "^1.1.0", + "diffie-hellman": "^5.0.0", + "inherits": "^2.0.1", + "pbkdf2": "^3.0.3", + "public-encrypt": "^4.0.0", + "randombytes": "^2.0.0", + "randomfill": "^1.0.3" + }, + "engines": { + "node": "*" + } + }, + "node_modules/debug": { + "version": "4.3.4", + "license": "MIT", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decode-uri-component": { + "version": "0.2.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/define-data-property": { + "version": "1.1.0", + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.2.1", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/define-properties": { + "version": "1.2.1", + "license": "MIT", + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/des.js": { + "version": "1.1.0", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" + } + }, + "node_modules/diffie-hellman": { + "version": "5.0.3", + "license": "MIT", + "dependencies": { + "bn.js": "^4.1.0", + "miller-rabin": "^4.0.0", + "randombytes": "^2.0.0" + } + }, + "node_modules/diffie-hellman/node_modules/bn.js": { + "version": "4.12.0", + "license": "MIT" + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "dev": true, + "license": "MIT" + }, + "node_modules/electron-to-chromium": { + "version": "1.4.544", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.544.tgz", + "integrity": "sha512-54z7squS1FyFRSUqq/knOFSptjjogLZXbKcYk3B0qkE1KZzvqASwRZnY2KzZQJqIYLVD38XZeoiMRflYSwyO4w==" + }, + "node_modules/elliptic": { + "version": "6.5.4", + "license": "MIT", + "dependencies": { + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/elliptic/node_modules/bn.js": { + "version": "4.12.0", + "license": "MIT" + }, + "node_modules/emoji-regex": { + "version": "9.2.2", + "dev": true, + "license": "MIT" + }, + "node_modules/endpoint": { + "version": "0.4.5", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.1" + } + }, + "node_modules/esbuild": { + "version": "0.18.20", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/android-arm": "0.18.20", + "@esbuild/android-arm64": "0.18.20", + "@esbuild/android-x64": "0.18.20", + "@esbuild/darwin-arm64": "0.18.20", + "@esbuild/darwin-x64": "0.18.20", + "@esbuild/freebsd-arm64": "0.18.20", + "@esbuild/freebsd-x64": "0.18.20", + "@esbuild/linux-arm": "0.18.20", + "@esbuild/linux-arm64": "0.18.20", + "@esbuild/linux-ia32": "0.18.20", + "@esbuild/linux-loong64": "0.18.20", + "@esbuild/linux-mips64el": "0.18.20", + "@esbuild/linux-ppc64": "0.18.20", + "@esbuild/linux-riscv64": "0.18.20", + "@esbuild/linux-s390x": "0.18.20", + "@esbuild/linux-x64": "0.18.20", + "@esbuild/netbsd-x64": "0.18.20", + "@esbuild/openbsd-x64": "0.18.20", + "@esbuild/sunos-x64": "0.18.20", + "@esbuild/win32-arm64": "0.18.20", + "@esbuild/win32-ia32": "0.18.20", + "@esbuild/win32-x64": "0.18.20" + } + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "engines": { + "node": ">=6" + } + }, + "node_modules/estree-walker": { + "version": "1.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/event-target-shim": { + "version": "5.0.1", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/events": { + "version": "3.3.0", + "license": "MIT", + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/evp_bytestokey": { + "version": "1.0.3", + "license": "MIT", + "dependencies": { + "md5.js": "^1.3.4", + "safe-buffer": "^5.1.1" + } + }, + "node_modules/expect-bundle": { + "resolved": "playwright/packages/playwright/bundles/expect", + "link": true + }, + "node_modules/fast-text-encoding": { + "version": "1.0.6", + "license": "Apache-2.0" + }, + "node_modules/for-each": { + "version": "0.3.3", + "license": "MIT", + "dependencies": { + "is-callable": "^1.1.3" + } + }, + "node_modules/foreground-child": { + "version": "3.1.1", + "dev": true, + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/foreground-child/node_modules/signal-exit": { + "version": "4.1.0", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/function-bind": { + "version": "1.1.1", + "license": "MIT" + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.1", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/glob": { + "version": "10.3.10", + "dev": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^2.3.5", + "minimatch": "^9.0.1", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", + "path-scurry": "^1.10.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/globals": { + "version": "11.12.0", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/gopd": { + "version": "1.0.1", + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" + }, + "node_modules/has": { + "version": "1.0.3", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-flag": { + "version": "3.0.0", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.1.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.1", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hash-base": { + "version": "3.1.0", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.4", + "readable-stream": "^3.6.0", + "safe-buffer": "^5.2.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/hash-base/node_modules/readable-stream": { + "version": "3.6.2", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/hash.js": { + "version": "1.1.7", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "node_modules/hmac-drbg": { + "version": "1.0.1", + "license": "MIT", + "dependencies": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/https-browserify": { + "version": "1.0.0", + "license": "MIT" + }, + "node_modules/ieee754": { + "version": "1.2.1", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/inherits": { + "version": "2.0.4", + "license": "ISC" + }, + "node_modules/inspector": { + "version": "0.5.0", + "license": "MIT", + "dependencies": { + "endpoint": "0.4.x", + "ws": "0.7.x" + } + }, + "node_modules/inspector/node_modules/bufferutil": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-1.1.0.tgz", + "integrity": "sha512-bttEVtkre4VYrZH+ciatjApTuac7jLMQXVXzM/ymw82WFREdOrJO496C4Bkh0/FfYoBUSOFaAYF32a5Q8dyiLw==", + "hasInstallScript": true, + "optional": true, + "dependencies": { + "bindings": "1.2.x", + "nan": "1.8.x" + } + }, + "node_modules/inspector/node_modules/utf-8-validate": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-1.1.0.tgz", + "integrity": "sha512-Qsgu1u2akdyOneurUEVf/tXhkqBQMoE3x0GY5+P7ayPHvVzTqOkkgBhtl26wm6ap10Amhwy0jIhPwMGywx76QQ==", + "hasInstallScript": true, + "optional": true, + "dependencies": { + "bindings": "1.2.x", + "nan": "1.8.x" + } + }, + "node_modules/inspector/node_modules/ws": { + "version": "0.7.2", + "license": "MIT", + "dependencies": { + "options": ">=0.0.5", + "ultron": "1.0.x" + }, + "optionalDependencies": { + "bufferutil": "1.1.x", + "utf-8-validate": "1.1.x" + } + }, + "node_modules/is-arguments": { + "version": "1.1.1", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-generator-function": { + "version": "1.0.10", + "license": "MIT", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-nan": { + "version": "1.3.2", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.12", + "license": "MIT", + "dependencies": { + "which-typed-array": "^1.1.11" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "dev": true, + "license": "ISC" + }, + "node_modules/isomorphic-textencoder": { + "version": "1.0.1", + "license": "MIT", + "dependencies": { + "fast-text-encoding": "^1.0.0" + } + }, + "node_modules/jackspeak": { + "version": "2.3.6", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "license": "MIT" + }, + "node_modules/jsesc": { + "version": "2.5.2", + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/just-debounce-it": { + "version": "1.1.0", + "license": "MIT" + }, + "node_modules/just-once": { + "version": "1.1.0", + "license": "MIT" + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dev": true, + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lru-cache": { + "version": "10.0.1", + "dev": true, + "license": "ISC", + "engines": { + "node": "14 || >=16.14" + } + }, + "node_modules/md5.js": { + "version": "1.3.5", + "license": "MIT", + "dependencies": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "node_modules/miller-rabin": { + "version": "4.0.1", + "license": "MIT", + "dependencies": { + "bn.js": "^4.0.0", + "brorand": "^1.0.1" + }, + "bin": { + "miller-rabin": "bin/miller-rabin" + } + }, + "node_modules/miller-rabin/node_modules/bn.js": { + "version": "4.12.0", + "license": "MIT" + }, + "node_modules/minimalistic-assert": { + "version": "1.0.1", + "license": "ISC" + }, + "node_modules/minimalistic-crypto-utils": { + "version": "1.0.1", + "license": "MIT" + }, + "node_modules/minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minipass": { + "version": "7.0.4", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "license": "MIT" + }, + "node_modules/nan": { + "version": "1.8.4", + "license": "MIT", + "optional": true + }, + "node_modules/nanoid": { + "version": "3.3.6", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/node-gyp-build": { + "version": "4.6.1", + "license": "MIT", + "optional": true, + "peer": true, + "bin": { + "node-gyp-build": "bin.js", + "node-gyp-build-optional": "optional.js", + "node-gyp-build-test": "build-test.js" + } + }, + "node_modules/node-releases": { + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz", + "integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==" + }, + "node_modules/object-inspect": { + "version": "1.12.3", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-is": { + "version": "1.1.5", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.4", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/options": { + "version": "0.0.6", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/os-browserify": { + "version": "0.3.0", + "license": "MIT" + }, + "node_modules/pako": { + "version": "1.0.11", + "license": "(MIT AND Zlib)" + }, + "node_modules/parse-asn1": { + "version": "5.1.6", + "license": "ISC", + "dependencies": { + "asn1.js": "^5.2.0", + "browserify-aes": "^1.0.0", + "evp_bytestokey": "^1.0.0", + "pbkdf2": "^3.0.3", + "safe-buffer": "^5.1.1" + } + }, + "node_modules/path": { + "version": "0.12.7", + "license": "MIT", + "dependencies": { + "process": "^0.11.1", + "util": "^0.10.3" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-scurry": { + "version": "1.10.1", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^9.1.1 || ^10.0.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path/node_modules/inherits": { + "version": "2.0.3", + "license": "ISC" + }, + "node_modules/path/node_modules/util": { + "version": "0.10.4", + "license": "MIT", + "dependencies": { + "inherits": "2.0.3" + } + }, + "node_modules/pbkdf2": { + "version": "3.1.2", + "license": "MIT", + "dependencies": { + "create-hash": "^1.1.2", + "create-hmac": "^1.1.4", + "ripemd160": "^2.0.1", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + }, + "engines": { + "node": ">=0.12" + } + }, + "node_modules/picocolors": { + "version": "1.0.0", + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/playwright-crx": { + "resolved": "", + "link": true + }, + "node_modules/postcss": { + "version": "8.4.31", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.6", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/process": { + "version": "0.11.10", + "license": "MIT", + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/public-encrypt": { + "version": "4.0.3", + "license": "MIT", + "dependencies": { + "bn.js": "^4.1.0", + "browserify-rsa": "^4.0.0", + "create-hash": "^1.1.0", + "parse-asn1": "^5.0.0", + "randombytes": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "node_modules/public-encrypt/node_modules/bn.js": { + "version": "4.12.0", + "license": "MIT" + }, + "node_modules/punycode": { + "version": "1.4.1", + "license": "MIT" + }, + "node_modules/qs": { + "version": "6.11.2", + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/randombytes": { + "version": "2.1.0", + "license": "MIT", + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/randomfill": { + "version": "1.0.4", + "license": "MIT", + "dependencies": { + "randombytes": "^2.0.5", + "safe-buffer": "^5.1.0" + } + }, + "node_modules/react": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", + "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", + "dev": true, + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", + "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", + "dev": true, + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.0" + }, + "peerDependencies": { + "react": "^18.2.0" + } + }, + "node_modules/react-refresh": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.0.tgz", + "integrity": "sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/readable-stream": { + "version": "4.4.2", + "license": "MIT", + "dependencies": { + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10", + "string_decoder": "^1.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/rimraf": { + "version": "5.0.5", + "dev": true, + "license": "ISC", + "dependencies": { + "glob": "^10.3.7" + }, + "bin": { + "rimraf": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/ripemd160": { + "version": "2.0.2", + "license": "MIT", + "dependencies": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1" + } + }, + "node_modules/rollup": { + "version": "2.79.1", + "dev": true, + "license": "MIT", + "peer": true, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=10.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/rollup-plugin-sourcemaps": { + "version": "0.6.3", + "dev": true, + "license": "MIT", + "dependencies": { + "@rollup/pluginutils": "^3.0.9", + "source-map-resolve": "^0.6.0" + }, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "@types/node": ">=10.0.0", + "rollup": ">=0.31.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "license": "MIT" + }, + "node_modules/scheduler": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", + "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", + "dev": true, + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/setimmediate": { + "version": "1.0.5", + "license": "MIT" + }, + "node_modules/sha.js": { + "version": "2.4.11", + "license": "(MIT AND BSD-3-Clause)", + "dependencies": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + }, + "bin": { + "sha.js": "bin.js" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.0.4", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-js": { + "version": "1.0.2", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-resolve": { + "version": "0.6.0", + "dev": true, + "license": "MIT", + "dependencies": { + "atob": "^2.1.2", + "decode-uri-component": "^0.2.0" + } + }, + "node_modules/stream-http": { + "version": "3.2.0", + "license": "MIT", + "dependencies": { + "builtin-status-codes": "^3.0.0", + "inherits": "^2.0.4", + "readable-stream": "^3.6.0", + "xtend": "^4.0.2" + } + }, + "node_modules/stream-http/node_modules/readable-stream": { + "version": "3.6.2", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-width": { + "version": "5.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/string-width-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "7.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-color": { + "version": "5.5.0", + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/test-utils-bundle": { + "resolved": "playwright/packages/playwright/bundles/utils", + "link": true + }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/typescript": { + "version": "5.2.2", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/ultron": { + "version": "1.0.2", + "license": "MIT" + }, + "node_modules/update-browserslist-db": { + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", + "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/url": { + "version": "0.11.3", + "license": "MIT", + "dependencies": { + "punycode": "^1.4.1", + "qs": "^6.11.2" + } + }, + "node_modules/utf-8-validate": { + "version": "5.0.10", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "node-gyp-build": "^4.3.0" + }, + "engines": { + "node": ">=6.14.2" + } + }, + "node_modules/util": { + "version": "0.12.5", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "is-arguments": "^1.0.4", + "is-generator-function": "^1.0.7", + "is-typed-array": "^1.1.3", + "which-typed-array": "^1.1.2" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "license": "MIT" + }, + "node_modules/utils-bundle": { + "resolved": "playwright/packages/playwright-core/bundles/utils", + "link": true + }, + "node_modules/vite": { + "version": "4.4.10", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.18.10", + "postcss": "^8.4.27", + "rollup": "^3.27.1" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + }, + "peerDependencies": { + "@types/node": ">= 14", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + }, + "node_modules/vite-plugin-require-transform": { + "version": "1.0.21", + "dev": true, + "license": "ISC", + "dependencies": { + "@babel/generator": "^7.22.5", + "@babel/parser": "^7.22.5", + "@babel/traverse": "^7.22.5", + "@babel/types": "^7.22.5" + } + }, + "node_modules/vite/node_modules/rollup": { + "version": "3.29.4", + "dev": true, + "license": "MIT", + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=14.18.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/web-package": { + "resolved": "playwright/packages/web", + "link": true + }, + "node_modules/which": { + "version": "2.0.2", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.11", + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/wrap-ansi": { + "version": "8.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { + "version": "4.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/color-convert": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/color-name": { + "version": "1.1.4", + "dev": true, + "license": "MIT" + }, + "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/wrap-ansi-cjs/node_modules/string-width": { + "version": "4.2.3", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "6.2.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/xtend": { + "version": "4.0.2", + "license": "MIT", + "engines": { + "node": ">=0.4" + } + }, + "node_modules/xterm": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/xterm/-/xterm-5.3.0.tgz", + "integrity": "sha512-8QqjlekLUFTrU6x7xck1MsPzPA571K5zNqWm0M0oroYEWVOptZ0+ubQSkQ3uxIEhcIHRujJy6emDWX4A7qyFzg==", + "dev": true + }, + "node_modules/xterm-addon-fit": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/xterm-addon-fit/-/xterm-addon-fit-0.7.0.tgz", + "integrity": "sha512-tQgHGoHqRTgeROPnvmtEJywLKoC/V9eNs4bLLz7iyJr1aW/QFzRwfd3MGiJ6odJd9xEfxcW36/xRU47JkD5NKQ==", + "dev": true, + "peerDependencies": { + "xterm": "^5.0.0" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" + }, + "node_modules/zip-bundle": { + "resolved": "playwright/packages/playwright-core/bundles/zip", + "link": true + }, + "playwright/packages/playwright-core/bundles/utils": { + "name": "utils-bundle", + "version": "0.0.1", + "dependencies": { + "colors": "1.4.0", + "commander": "8.3.0", + "debug": "^4.3.4", + "graceful-fs": "4.2.10", + "https-proxy-agent": "5.0.0", + "jpeg-js": "0.4.4", + "mime": "^3.0.0", + "minimatch": "^3.1.2", + "open": "8.4.0", + "pngjs": "6.0.0", + "progress": "2.0.3", + "proxy-from-env": "1.1.0", + "retry": "0.12.0", + "rimraf": "^4.4.1", + "signal-exit": "3.0.7", + "socks-proxy-agent": "6.1.1", + "stack-utils": "2.0.5", + "ws": "8.4.2" + }, + "devDependencies": { + "@types/debug": "^4.1.7", + "@types/mime": "^2.0.3", + "@types/minimatch": "^3.0.5", + "@types/pngjs": "^6.0.1", + "@types/progress": "^2.0.5", + "@types/proper-lockfile": "^4.1.2", + "@types/proxy-from-env": "^1.0.1", + "@types/stack-utils": "^2.0.1", + "@types/ws": "8.2.2" + } + }, + "playwright/packages/playwright-core/bundles/utils/node_modules/@types/debug": { + "version": "4.1.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/ms": "*" + } + }, + "playwright/packages/playwright-core/bundles/utils/node_modules/@types/mime": { + "version": "2.0.3", + "dev": true, + "license": "MIT" + }, + "playwright/packages/playwright-core/bundles/utils/node_modules/@types/minimatch": { + "version": "3.0.5", + "dev": true, + "license": "MIT" + }, + "playwright/packages/playwright-core/bundles/utils/node_modules/@types/ms": { + "version": "0.7.31", + "dev": true, + "license": "MIT" + }, + "playwright/packages/playwright-core/bundles/utils/node_modules/@types/node": { + "version": "17.0.25", + "dev": true, + "license": "MIT" + }, + "playwright/packages/playwright-core/bundles/utils/node_modules/@types/pngjs": { + "version": "6.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "playwright/packages/playwright-core/bundles/utils/node_modules/@types/progress": { + "version": "2.0.5", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "playwright/packages/playwright-core/bundles/utils/node_modules/@types/proper-lockfile": { + "version": "4.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/retry": "*" + } + }, + "playwright/packages/playwright-core/bundles/utils/node_modules/@types/proxy-from-env": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "playwright/packages/playwright-core/bundles/utils/node_modules/@types/retry": { + "version": "0.12.2", + "dev": true, + "license": "MIT" + }, + "playwright/packages/playwright-core/bundles/utils/node_modules/@types/stack-utils": { + "version": "2.0.1", + "dev": true, + "license": "MIT" + }, + "playwright/packages/playwright-core/bundles/utils/node_modules/@types/ws": { + "version": "8.2.2", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "playwright/packages/playwright-core/bundles/utils/node_modules/agent-base": { + "version": "6.0.2", + "license": "MIT", + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "playwright/packages/playwright-core/bundles/utils/node_modules/colors": { + "version": "1.4.0", + "license": "MIT", + "engines": { + "node": ">=0.1.90" + } + }, + "playwright/packages/playwright-core/bundles/utils/node_modules/commander": { + "version": "8.3.0", + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, + "playwright/packages/playwright-core/bundles/utils/node_modules/debug": { + "version": "4.3.4", + "license": "MIT", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "playwright/packages/playwright-core/bundles/utils/node_modules/define-lazy-prop": { + "version": "2.0.0", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "playwright/packages/playwright-core/bundles/utils/node_modules/escape-string-regexp": { + "version": "2.0.0", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "playwright/packages/playwright-core/bundles/utils/node_modules/fs.realpath": { + "version": "1.0.0", + "license": "ISC" + }, + "playwright/packages/playwright-core/bundles/utils/node_modules/glob": { + "version": "9.3.5", + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "minimatch": "^8.0.2", + "minipass": "^4.2.4", + "path-scurry": "^1.6.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "playwright/packages/playwright-core/bundles/utils/node_modules/glob/node_modules/minimatch": { + "version": "8.0.4", + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "playwright/packages/playwright-core/bundles/utils/node_modules/graceful-fs": { + "version": "4.2.10", + "license": "ISC" + }, + "playwright/packages/playwright-core/bundles/utils/node_modules/https-proxy-agent": { + "version": "5.0.0", + "license": "MIT", + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "playwright/packages/playwright-core/bundles/utils/node_modules/ip": { + "version": "2.0.0", + "license": "MIT" + }, + "playwright/packages/playwright-core/bundles/utils/node_modules/is-docker": { + "version": "2.2.1", + "license": "MIT", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "playwright/packages/playwright-core/bundles/utils/node_modules/is-wsl": { + "version": "2.2.0", + "license": "MIT", + "dependencies": { + "is-docker": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "playwright/packages/playwright-core/bundles/utils/node_modules/jpeg-js": { + "version": "0.4.4", + "license": "BSD-3-Clause" + }, + "playwright/packages/playwright-core/bundles/utils/node_modules/lru-cache": { + "version": "10.0.0", + "license": "ISC", + "engines": { + "node": "14 || >=16.14" + } + }, + "playwright/packages/playwright-core/bundles/utils/node_modules/mime": { + "version": "3.0.0", + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "playwright/packages/playwright-core/bundles/utils/node_modules/minimatch": { + "version": "3.1.2", + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "playwright/packages/playwright-core/bundles/utils/node_modules/minimatch/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "playwright/packages/playwright-core/bundles/utils/node_modules/minipass": { + "version": "4.2.8", + "license": "ISC", + "engines": { + "node": ">=8" + } + }, + "playwright/packages/playwright-core/bundles/utils/node_modules/ms": { + "version": "2.1.2", + "license": "MIT" + }, + "playwright/packages/playwright-core/bundles/utils/node_modules/open": { + "version": "8.4.0", + "license": "MIT", + "dependencies": { + "define-lazy-prop": "^2.0.0", + "is-docker": "^2.1.1", + "is-wsl": "^2.2.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "playwright/packages/playwright-core/bundles/utils/node_modules/path-scurry": { + "version": "1.10.1", + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^9.1.1 || ^10.0.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "playwright/packages/playwright-core/bundles/utils/node_modules/path-scurry/node_modules/minipass": { + "version": "7.0.2", + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "playwright/packages/playwright-core/bundles/utils/node_modules/pngjs": { + "version": "6.0.0", + "license": "MIT", + "engines": { + "node": ">=12.13.0" + } + }, + "playwright/packages/playwright-core/bundles/utils/node_modules/progress": { + "version": "2.0.3", + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "playwright/packages/playwright-core/bundles/utils/node_modules/proxy-from-env": { + "version": "1.1.0", + "license": "MIT" + }, + "playwright/packages/playwright-core/bundles/utils/node_modules/retry": { + "version": "0.12.0", + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "playwright/packages/playwright-core/bundles/utils/node_modules/rimraf": { + "version": "4.4.1", + "license": "ISC", + "dependencies": { + "glob": "^9.2.0" + }, + "bin": { + "rimraf": "dist/cjs/src/bin.js" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "playwright/packages/playwright-core/bundles/utils/node_modules/signal-exit": { + "version": "3.0.7", + "license": "ISC" + }, + "playwright/packages/playwright-core/bundles/utils/node_modules/smart-buffer": { + "version": "4.2.0", + "license": "MIT", + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "playwright/packages/playwright-core/bundles/utils/node_modules/socks": { + "version": "2.7.0", + "license": "MIT", + "dependencies": { + "ip": "^2.0.0", + "smart-buffer": "^4.2.0" + }, + "engines": { + "node": ">= 10.13.0", + "npm": ">= 3.0.0" + } + }, + "playwright/packages/playwright-core/bundles/utils/node_modules/socks-proxy-agent": { + "version": "6.1.1", + "license": "MIT", + "dependencies": { + "agent-base": "^6.0.2", + "debug": "^4.3.1", + "socks": "^2.6.1" + }, + "engines": { + "node": ">= 10" + } + }, + "playwright/packages/playwright-core/bundles/utils/node_modules/stack-utils": { + "version": "2.0.5", + "license": "MIT", + "dependencies": { + "escape-string-regexp": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "playwright/packages/playwright-core/bundles/utils/node_modules/ws": { + "version": "8.4.2", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "playwright/packages/playwright-core/bundles/zip": { + "name": "zip-bundle", + "version": "0.0.1", + "dependencies": { + "extract-zip": "2.0.1", + "yauzl": "2.10.0", + "yazl": "2.5.1" + }, + "devDependencies": { + "@types/yauzl": "^2.10.0", + "@types/yazl": "^2.4.2" + } + }, + "playwright/packages/playwright-core/bundles/zip/node_modules/@types/node": { + "version": "17.0.24", + "devOptional": true, + "license": "MIT" + }, + "playwright/packages/playwright-core/bundles/zip/node_modules/@types/yauzl": { + "version": "2.10.0", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "playwright/packages/playwright-core/bundles/zip/node_modules/@types/yazl": { + "version": "2.4.2", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "playwright/packages/playwright-core/bundles/zip/node_modules/buffer-crc32": { + "version": "0.2.13", + "license": "MIT", + "engines": { + "node": "*" + } + }, + "playwright/packages/playwright-core/bundles/zip/node_modules/debug": { + "version": "4.3.4", + "license": "MIT", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "playwright/packages/playwright-core/bundles/zip/node_modules/end-of-stream": { + "version": "1.4.4", + "license": "MIT", + "dependencies": { + "once": "^1.4.0" + } + }, + "playwright/packages/playwright-core/bundles/zip/node_modules/extract-zip": { + "version": "2.0.1", + "license": "BSD-2-Clause", + "dependencies": { + "debug": "^4.1.1", + "get-stream": "^5.1.0", + "yauzl": "^2.10.0" + }, + "bin": { + "extract-zip": "cli.js" + }, + "engines": { + "node": ">= 10.17.0" + }, + "optionalDependencies": { + "@types/yauzl": "^2.9.1" + } + }, + "playwright/packages/playwright-core/bundles/zip/node_modules/fd-slicer": { + "version": "1.1.0", + "license": "MIT", + "dependencies": { + "pend": "~1.2.0" + } + }, + "playwright/packages/playwright-core/bundles/zip/node_modules/get-stream": { + "version": "5.2.0", + "license": "MIT", + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "playwright/packages/playwright-core/bundles/zip/node_modules/ms": { + "version": "2.1.2", + "license": "MIT" + }, + "playwright/packages/playwright-core/bundles/zip/node_modules/once": { + "version": "1.4.0", + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "playwright/packages/playwright-core/bundles/zip/node_modules/pend": { + "version": "1.2.0", + "license": "MIT" + }, + "playwright/packages/playwright-core/bundles/zip/node_modules/pump": { + "version": "3.0.0", + "license": "MIT", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "playwright/packages/playwright-core/bundles/zip/node_modules/wrappy": { + "version": "1.0.2", + "license": "ISC" + }, + "playwright/packages/playwright-core/bundles/zip/node_modules/yauzl": { + "version": "2.10.0", + "license": "MIT", + "dependencies": { + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" + } + }, + "playwright/packages/playwright-core/bundles/zip/node_modules/yazl": { + "version": "2.5.1", + "license": "MIT", + "dependencies": { + "buffer-crc32": "~0.2.3" + } + }, + "playwright/packages/playwright/bundles/babel": { + "name": "babel-bundle", + "version": "0.0.1", + "dependencies": { + "@babel/code-frame": "^7.18.6", + "@babel/core": "^7.22.8", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/parser": "^7.21.3", + "@babel/plugin-proposal-class-properties": "^7.18.6", + "@babel/plugin-proposal-class-static-block": "^7.21.0", + "@babel/plugin-proposal-decorators": "^7.21.0", + "@babel/plugin-proposal-dynamic-import": "^7.18.6", + "@babel/plugin-proposal-export-namespace-from": "^7.18.9", + "@babel/plugin-proposal-logical-assignment-operators": "^7.20.7", + "@babel/plugin-proposal-nullish-coalescing-operator": "^7.18.6", + "@babel/plugin-proposal-numeric-separator": "^7.18.6", + "@babel/plugin-proposal-optional-chaining": "^7.21.0", + "@babel/plugin-proposal-private-methods": "^7.18.6", + "@babel/plugin-proposal-private-property-in-object": "^7.21.0", + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-import-assertions": "^7.20.0", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-transform-modules-commonjs": "^7.21.2", + "@babel/plugin-transform-react-jsx": "^7.21.0", + "@babel/preset-typescript": "^7.21.0" + }, + "devDependencies": { + "@types/babel__code-frame": "^7.0.3", + "@types/babel__core": "^7.20.0", + "@types/babel__helper-plugin-utils": "^7.10.0", + "@types/babel__traverse": "^7.18.3" + } + }, + "playwright/packages/playwright/bundles/babel/node_modules/@babel/code-frame": { + "version": "7.22.5", + "license": "MIT", + "dependencies": { + "@babel/highlight": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "playwright/packages/playwright/bundles/babel/node_modules/@babel/generator": { + "version": "7.22.7", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.22.5", + "@jridgewell/gen-mapping": "^0.3.2", + "@jridgewell/trace-mapping": "^0.3.17", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "playwright/packages/playwright/bundles/babel/node_modules/@babel/generator/node_modules/@jridgewell/gen-mapping": { + "version": "0.3.2", + "license": "MIT", + "dependencies": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "playwright/packages/playwright/bundles/babel/node_modules/@babel/helper-annotate-as-pure": { + "version": "7.18.6", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "playwright/packages/playwright/bundles/babel/node_modules/@babel/helper-create-class-features-plugin": { + "version": "7.21.0", + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-function-name": "^7.21.0", + "@babel/helper-member-expression-to-functions": "^7.21.0", + "@babel/helper-optimise-call-expression": "^7.18.6", + "@babel/helper-replace-supers": "^7.20.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.20.0", + "@babel/helper-split-export-declaration": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "playwright/packages/playwright/bundles/babel/node_modules/@babel/helper-environment-visitor": { + "version": "7.22.5", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "playwright/packages/playwright/bundles/babel/node_modules/@babel/helper-function-name": { + "version": "7.22.5", + "license": "MIT", + "dependencies": { + "@babel/template": "^7.22.5", + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "playwright/packages/playwright/bundles/babel/node_modules/@babel/helper-hoist-variables": { + "version": "7.22.5", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "playwright/packages/playwright/bundles/babel/node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.21.0", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.21.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "playwright/packages/playwright/bundles/babel/node_modules/@babel/helper-optimise-call-expression": { + "version": "7.18.6", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "playwright/packages/playwright/bundles/babel/node_modules/@babel/helper-replace-supers": { + "version": "7.20.7", + "license": "MIT", + "dependencies": { + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-member-expression-to-functions": "^7.20.7", + "@babel/helper-optimise-call-expression": "^7.18.6", + "@babel/template": "^7.20.7", + "@babel/traverse": "^7.20.7", + "@babel/types": "^7.20.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "playwright/packages/playwright/bundles/babel/node_modules/@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.20.0", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.20.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "playwright/packages/playwright/bundles/babel/node_modules/@babel/helper-split-export-declaration": { + "version": "7.22.6", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "playwright/packages/playwright/bundles/babel/node_modules/@babel/helper-string-parser": { + "version": "7.22.5", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "playwright/packages/playwright/bundles/babel/node_modules/@babel/helper-validator-identifier": { + "version": "7.22.5", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "playwright/packages/playwright/bundles/babel/node_modules/@babel/highlight": { + "version": "7.22.5", + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.22.5", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "playwright/packages/playwright/bundles/babel/node_modules/@babel/parser": { + "version": "7.22.7", + "license": "MIT", + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "playwright/packages/playwright/bundles/babel/node_modules/@babel/plugin-proposal-class-properties": { + "version": "7.18.6", + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "playwright/packages/playwright/bundles/babel/node_modules/@babel/plugin-proposal-class-static-block": { + "version": "7.21.0", + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.21.0", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/plugin-syntax-class-static-block": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.0" + } + }, + "playwright/packages/playwright/bundles/babel/node_modules/@babel/plugin-proposal-decorators": { + "version": "7.21.0", + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.21.0", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/helper-replace-supers": "^7.20.7", + "@babel/helper-split-export-declaration": "^7.18.6", + "@babel/plugin-syntax-decorators": "^7.21.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "playwright/packages/playwright/bundles/babel/node_modules/@babel/plugin-proposal-dynamic-import": { + "version": "7.18.6", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-dynamic-import": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "playwright/packages/playwright/bundles/babel/node_modules/@babel/plugin-proposal-export-namespace-from": { + "version": "7.18.9", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "playwright/packages/playwright/bundles/babel/node_modules/@babel/plugin-proposal-logical-assignment-operators": { + "version": "7.20.7", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "playwright/packages/playwright/bundles/babel/node_modules/@babel/plugin-proposal-nullish-coalescing-operator": { + "version": "7.18.6", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "playwright/packages/playwright/bundles/babel/node_modules/@babel/plugin-proposal-numeric-separator": { + "version": "7.18.6", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-numeric-separator": "^7.10.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "playwright/packages/playwright/bundles/babel/node_modules/@babel/plugin-proposal-optional-chaining": { + "version": "7.21.0", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/helper-skip-transparent-expression-wrappers": "^7.20.0", + "@babel/plugin-syntax-optional-chaining": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "playwright/packages/playwright/bundles/babel/node_modules/@babel/plugin-proposal-private-methods": { + "version": "7.18.6", + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "playwright/packages/playwright/bundles/babel/node_modules/@babel/plugin-proposal-private-property-in-object": { + "version": "7.21.0", + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-create-class-features-plugin": "^7.21.0", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "playwright/packages/playwright/bundles/babel/node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "playwright/packages/playwright/bundles/babel/node_modules/@babel/plugin-syntax-class-static-block": { + "version": "7.14.5", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "playwright/packages/playwright/bundles/babel/node_modules/@babel/plugin-syntax-decorators": { + "version": "7.21.0", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.20.2" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "playwright/packages/playwright/bundles/babel/node_modules/@babel/plugin-syntax-dynamic-import": { + "version": "7.8.3", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "playwright/packages/playwright/bundles/babel/node_modules/@babel/plugin-syntax-export-namespace-from": { + "version": "7.8.3", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "playwright/packages/playwright/bundles/babel/node_modules/@babel/plugin-syntax-import-assertions": { + "version": "7.20.0", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.19.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "playwright/packages/playwright/bundles/babel/node_modules/@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "playwright/packages/playwright/bundles/babel/node_modules/@babel/plugin-syntax-jsx": { + "version": "7.18.6", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "playwright/packages/playwright/bundles/babel/node_modules/@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "playwright/packages/playwright/bundles/babel/node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "playwright/packages/playwright/bundles/babel/node_modules/@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "playwright/packages/playwright/bundles/babel/node_modules/@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "playwright/packages/playwright/bundles/babel/node_modules/@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "playwright/packages/playwright/bundles/babel/node_modules/@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "playwright/packages/playwright/bundles/babel/node_modules/@babel/plugin-syntax-private-property-in-object": { + "version": "7.14.5", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "playwright/packages/playwright/bundles/babel/node_modules/@babel/plugin-syntax-typescript": { + "version": "7.20.0", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.19.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "playwright/packages/playwright/bundles/babel/node_modules/@babel/plugin-transform-modules-commonjs": { + "version": "7.21.2", + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.21.2", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/helper-simple-access": "^7.20.2" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "playwright/packages/playwright/bundles/babel/node_modules/@babel/plugin-transform-react-jsx": { + "version": "7.21.0", + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/plugin-syntax-jsx": "^7.18.6", + "@babel/types": "^7.21.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "playwright/packages/playwright/bundles/babel/node_modules/@babel/plugin-transform-typescript": { + "version": "7.21.3", + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-create-class-features-plugin": "^7.21.0", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/plugin-syntax-typescript": "^7.20.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "playwright/packages/playwright/bundles/babel/node_modules/@babel/preset-typescript": { + "version": "7.21.0", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/helper-validator-option": "^7.21.0", + "@babel/plugin-transform-typescript": "^7.21.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "playwright/packages/playwright/bundles/babel/node_modules/@babel/template": { + "version": "7.22.5", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.22.5", + "@babel/parser": "^7.22.5", + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "playwright/packages/playwright/bundles/babel/node_modules/@babel/traverse": { + "version": "7.22.8", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.22.5", + "@babel/generator": "^7.22.7", + "@babel/helper-environment-visitor": "^7.22.5", + "@babel/helper-function-name": "^7.22.5", + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/parser": "^7.22.7", + "@babel/types": "^7.22.5", + "debug": "^4.1.0", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "playwright/packages/playwright/bundles/babel/node_modules/@babel/types": { + "version": "7.22.5", + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.5", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "playwright/packages/playwright/bundles/babel/node_modules/@jridgewell/resolve-uri": { + "version": "3.1.0", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "playwright/packages/playwright/bundles/babel/node_modules/@jridgewell/set-array": { + "version": "1.1.1", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "playwright/packages/playwright/bundles/babel/node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "license": "MIT" + }, + "playwright/packages/playwright/bundles/babel/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.17", + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "3.1.0", + "@jridgewell/sourcemap-codec": "1.4.14" + } + }, + "playwright/packages/playwright/bundles/babel/node_modules/@types/babel__code-frame": { + "version": "7.0.3", + "dev": true, + "license": "MIT" + }, + "playwright/packages/playwright/bundles/babel/node_modules/@types/babel__helper-plugin-utils": { + "version": "7.10.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/babel__core": "*" + } + }, + "playwright/packages/playwright/bundles/babel/node_modules/ansi-styles": { + "version": "3.2.1", + "license": "MIT", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "playwright/packages/playwright/bundles/babel/node_modules/chalk": { + "version": "2.4.2", + "license": "MIT", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "playwright/packages/playwright/bundles/babel/node_modules/color-convert": { + "version": "1.9.3", + "license": "MIT", + "dependencies": { + "color-name": "1.1.3" + } + }, + "playwright/packages/playwright/bundles/babel/node_modules/color-name": { + "version": "1.1.3", + "license": "MIT" + }, + "playwright/packages/playwright/bundles/babel/node_modules/debug": { + "version": "4.3.4", + "license": "MIT", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "playwright/packages/playwright/bundles/babel/node_modules/escape-string-regexp": { + "version": "1.0.5", + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "playwright/packages/playwright/bundles/babel/node_modules/globals": { + "version": "11.12.0", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "playwright/packages/playwright/bundles/babel/node_modules/has-flag": { + "version": "3.0.0", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "playwright/packages/playwright/bundles/babel/node_modules/js-tokens": { + "version": "4.0.0", + "license": "MIT" + }, + "playwright/packages/playwright/bundles/babel/node_modules/jsesc": { + "version": "2.5.2", + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, + "playwright/packages/playwright/bundles/babel/node_modules/ms": { + "version": "2.1.2", + "license": "MIT" + }, + "playwright/packages/playwright/bundles/babel/node_modules/supports-color": { + "version": "5.5.0", + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "playwright/packages/playwright/bundles/babel/node_modules/to-fast-properties": { + "version": "2.0.0", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "playwright/packages/playwright/bundles/expect": { + "name": "expect-bundle", + "version": "0.0.1", + "dependencies": { + "expect": "29.5.0", + "jest-matcher-utils": "29.5.0" + } + }, + "playwright/packages/playwright/bundles/expect/node_modules/@babel/code-frame": { + "version": "7.22.5", + "license": "MIT", + "dependencies": { + "@babel/highlight": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "playwright/packages/playwright/bundles/expect/node_modules/@babel/helper-validator-identifier": { + "version": "7.22.5", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "playwright/packages/playwright/bundles/expect/node_modules/@babel/highlight": { + "version": "7.22.5", + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.22.5", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "playwright/packages/playwright/bundles/expect/node_modules/@babel/highlight/node_modules/ansi-styles": { + "version": "3.2.1", + "license": "MIT", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "playwright/packages/playwright/bundles/expect/node_modules/@babel/highlight/node_modules/chalk": { + "version": "2.4.2", + "license": "MIT", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "playwright/packages/playwright/bundles/expect/node_modules/@babel/highlight/node_modules/color-convert": { + "version": "1.9.3", + "license": "MIT", + "dependencies": { + "color-name": "1.1.3" + } + }, + "playwright/packages/playwright/bundles/expect/node_modules/@babel/highlight/node_modules/color-name": { + "version": "1.1.3", + "license": "MIT" + }, + "playwright/packages/playwright/bundles/expect/node_modules/@babel/highlight/node_modules/escape-string-regexp": { + "version": "1.0.5", + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "playwright/packages/playwright/bundles/expect/node_modules/@babel/highlight/node_modules/has-flag": { + "version": "3.0.0", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "playwright/packages/playwright/bundles/expect/node_modules/@babel/highlight/node_modules/supports-color": { + "version": "5.5.0", + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "playwright/packages/playwright/bundles/expect/node_modules/@jest/expect-utils": { + "version": "29.5.0", + "license": "MIT", + "dependencies": { + "jest-get-type": "^29.4.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "playwright/packages/playwright/bundles/expect/node_modules/@jest/schemas": { + "version": "29.4.3", + "license": "MIT", + "dependencies": { + "@sinclair/typebox": "^0.25.16" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "playwright/packages/playwright/bundles/expect/node_modules/@jest/types": { + "version": "29.5.0", + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.4.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "playwright/packages/playwright/bundles/expect/node_modules/@sinclair/typebox": { + "version": "0.25.24", + "license": "MIT" + }, + "playwright/packages/playwright/bundles/expect/node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.4", + "license": "MIT" + }, + "playwright/packages/playwright/bundles/expect/node_modules/@types/istanbul-lib-report": { + "version": "3.0.0", + "license": "MIT", + "dependencies": { + "@types/istanbul-lib-coverage": "*" + } + }, + "playwright/packages/playwright/bundles/expect/node_modules/@types/istanbul-reports": { + "version": "3.0.1", + "license": "MIT", + "dependencies": { + "@types/istanbul-lib-report": "*" + } + }, + "playwright/packages/playwright/bundles/expect/node_modules/@types/node": { + "version": "20.2.5", + "license": "MIT" + }, + "playwright/packages/playwright/bundles/expect/node_modules/@types/stack-utils": { + "version": "2.0.1", + "license": "MIT" + }, + "playwright/packages/playwright/bundles/expect/node_modules/@types/yargs": { + "version": "17.0.24", + "license": "MIT", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "playwright/packages/playwright/bundles/expect/node_modules/@types/yargs-parser": { + "version": "21.0.0", + "license": "MIT" + }, + "playwright/packages/playwright/bundles/expect/node_modules/ansi-styles": { + "version": "4.3.0", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "playwright/packages/playwright/bundles/expect/node_modules/braces": { + "version": "3.0.2", + "license": "MIT", + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "playwright/packages/playwright/bundles/expect/node_modules/chalk": { + "version": "4.1.2", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "playwright/packages/playwright/bundles/expect/node_modules/ci-info": { + "version": "3.8.0", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "playwright/packages/playwright/bundles/expect/node_modules/color-convert": { + "version": "2.0.1", + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "playwright/packages/playwright/bundles/expect/node_modules/color-name": { + "version": "1.1.4", + "license": "MIT" + }, + "playwright/packages/playwright/bundles/expect/node_modules/diff-sequences": { + "version": "29.4.3", + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "playwright/packages/playwright/bundles/expect/node_modules/escape-string-regexp": { + "version": "2.0.0", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "playwright/packages/playwright/bundles/expect/node_modules/expect": { + "version": "29.5.0", + "license": "MIT", + "dependencies": { + "@jest/expect-utils": "^29.5.0", + "jest-get-type": "^29.4.3", + "jest-matcher-utils": "^29.5.0", + "jest-message-util": "^29.5.0", + "jest-util": "^29.5.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "playwright/packages/playwright/bundles/expect/node_modules/fill-range": { + "version": "7.0.1", + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "playwright/packages/playwright/bundles/expect/node_modules/has-flag": { + "version": "4.0.0", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "playwright/packages/playwright/bundles/expect/node_modules/is-number": { + "version": "7.0.0", + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "playwright/packages/playwright/bundles/expect/node_modules/jest-diff": { + "version": "29.5.0", + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^29.4.3", + "jest-get-type": "^29.4.3", + "pretty-format": "^29.5.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "playwright/packages/playwright/bundles/expect/node_modules/jest-get-type": { + "version": "29.4.3", + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "playwright/packages/playwright/bundles/expect/node_modules/jest-matcher-utils": { + "version": "29.5.0", + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "jest-diff": "^29.5.0", + "jest-get-type": "^29.4.3", + "pretty-format": "^29.5.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "playwright/packages/playwright/bundles/expect/node_modules/jest-message-util": { + "version": "29.5.0", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.5.0", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.5.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "playwright/packages/playwright/bundles/expect/node_modules/jest-util": { + "version": "29.5.0", + "license": "MIT", + "dependencies": { + "@jest/types": "^29.5.0", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "playwright/packages/playwright/bundles/expect/node_modules/js-tokens": { + "version": "4.0.0", + "license": "MIT" + }, + "playwright/packages/playwright/bundles/expect/node_modules/micromatch": { + "version": "4.0.5", + "license": "MIT", + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "playwright/packages/playwright/bundles/expect/node_modules/picomatch": { + "version": "2.3.1", + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "playwright/packages/playwright/bundles/expect/node_modules/pretty-format": { + "version": "29.5.0", + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.4.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "playwright/packages/playwright/bundles/expect/node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "playwright/packages/playwright/bundles/expect/node_modules/react-is": { + "version": "18.2.0", + "license": "MIT" + }, + "playwright/packages/playwright/bundles/expect/node_modules/slash": { + "version": "3.0.0", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "playwright/packages/playwright/bundles/expect/node_modules/stack-utils": { + "version": "2.0.6", + "license": "MIT", + "dependencies": { + "escape-string-regexp": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "playwright/packages/playwright/bundles/expect/node_modules/supports-color": { + "version": "7.2.0", + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "playwright/packages/playwright/bundles/expect/node_modules/to-regex-range": { + "version": "5.0.1", + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "playwright/packages/playwright/bundles/utils": { + "name": "utils-bundle", + "version": "0.0.1", + "dependencies": { + "chokidar": "3.5.3", + "enquirer": "2.3.6", + "json5": "2.2.3", + "pirates": "4.0.4", + "source-map-support": "0.5.21", + "stoppable": "1.1.0" + }, + "devDependencies": { + "@types/source-map-support": "^0.5.4", + "@types/stoppable": "^1.1.1" + } + }, + "playwright/packages/playwright/bundles/utils/node_modules/@types/node": { + "version": "18.6.4", + "dev": true, + "license": "MIT" + }, + "playwright/packages/playwright/bundles/utils/node_modules/@types/source-map-support": { + "version": "0.5.4", + "dev": true, + "license": "MIT", + "dependencies": { + "source-map": "^0.6.0" + } + }, + "playwright/packages/playwright/bundles/utils/node_modules/@types/stoppable": { + "version": "1.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "playwright/packages/playwright/bundles/utils/node_modules/ansi-colors": { + "version": "4.1.3", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "playwright/packages/playwright/bundles/utils/node_modules/anymatch": { + "version": "3.1.3", + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "playwright/packages/playwright/bundles/utils/node_modules/binary-extensions": { + "version": "2.2.0", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "playwright/packages/playwright/bundles/utils/node_modules/braces": { + "version": "3.0.2", + "license": "MIT", + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "playwright/packages/playwright/bundles/utils/node_modules/buffer-from": { + "version": "1.1.2", + "license": "MIT" + }, + "playwright/packages/playwright/bundles/utils/node_modules/chokidar": { + "version": "3.5.3", + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "playwright/packages/playwright/bundles/utils/node_modules/enquirer": { + "version": "2.3.6", + "license": "MIT", + "dependencies": { + "ansi-colors": "^4.1.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "playwright/packages/playwright/bundles/utils/node_modules/fill-range": { + "version": "7.0.1", + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "playwright/packages/playwright/bundles/utils/node_modules/glob-parent": { + "version": "5.1.2", + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "playwright/packages/playwright/bundles/utils/node_modules/is-binary-path": { + "version": "2.1.0", + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "playwright/packages/playwright/bundles/utils/node_modules/is-extglob": { + "version": "2.1.1", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "playwright/packages/playwright/bundles/utils/node_modules/is-glob": { + "version": "4.0.3", + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "playwright/packages/playwright/bundles/utils/node_modules/is-number": { + "version": "7.0.0", + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "playwright/packages/playwright/bundles/utils/node_modules/normalize-path": { + "version": "3.0.0", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "playwright/packages/playwright/bundles/utils/node_modules/picomatch": { + "version": "2.3.1", + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "playwright/packages/playwright/bundles/utils/node_modules/pirates": { + "version": "4.0.4", + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "playwright/packages/playwright/bundles/utils/node_modules/readdirp": { + "version": "3.6.0", + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "playwright/packages/playwright/bundles/utils/node_modules/source-map-support": { + "version": "0.5.21", + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "playwright/packages/playwright/bundles/utils/node_modules/stoppable": { + "version": "1.1.0", + "license": "MIT", + "engines": { + "node": ">=4", + "npm": ">=6" + } + }, + "playwright/packages/playwright/bundles/utils/node_modules/to-regex-range": { + "version": "5.0.1", + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "playwright/packages/web": { + "version": "0.0.0", + "dev": true, + "dependencies": { + "codemirror": "^5.65.9", + "xterm": "^5.1.0", + "xterm-addon-fit": "^0.7.0" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 000000000..7b8f8908f --- /dev/null +++ b/package.json @@ -0,0 +1,77 @@ +{ + "name": "playwright-crx", + "version": "0.0.4-next", + "engines": { + "node": ">=16" + }, + "author": { + "name": "Rui Figueira" + }, + "license": "Apache-2.0", + "scripts": { + "pw:ci:core-utils-bundle": "npm ci --prefix ./playwright/packages/playwright-core/bundles/utils", + "pw:ci:core-zip-bundle": "npm ci --prefix ./playwright/packages/playwright-core/bundles/zip", + "pw:ci:test-babel-bundle": "npm ci --prefix ./playwright/packages/playwright/bundles/babel", + "pw:ci:test-expect-bundle": "npm ci --prefix ./playwright/packages/playwright/bundles/expect", + "pw:ci:test-utils-bundle": "npm ci --prefix ./playwright/packages/playwright/bundles/utils", + "pw:ci:bundles": "npm run pw:ci:core-utils-bundle && npm run pw:ci:core-zip-bundle && npm run pw:ci:test-babel-bundle && npm run pw:ci:test-expect-bundle && npm run pw:ci:test-utils-bundle", + "pw:clean-bundles": "rimraf -g ./playwright/packages/playwright-core/bundles/**/node_modules && rimraf -g ./playwright/packages/playwright/bundles/**/node_modules", + "pw:clean": "npm run pw:clean-bundles && cd ./playwright && npm run clean", + "pw:generate-injected": "cd ./playwright && node ./utils/generate_injected.js", + "examples:build:todomvc": "npm run build --prefix ./examples/todomvc-crx", + "examples:build:recorder": "npm run build --prefix ./examples/recorder-crx", + "examples:build": "npm run examples:build:todomvc && npm run examples:build:recorder", + "examples:clean": "rimraf ./examples/recorder-crx/dist && rimraf ./examples/todomvc-crx/dist", + "build:crx": "npm run pw:generate-injected && vite build", + "build": "npm run pw:ci:bundles && npm run build:crx && npm run examples:build", + "clean": "npm run pw:clean && npm run examples:clean && rimraf ./lib" + }, + "workspaces": [ + "." + ], + "exports": { + ".": { + "types": "./index.d.ts", + "import": "./lib/index.mjs", + "require": "./lib/index.umd.js", + "default": "./lib/index.umd.js" + }, + "./package.json": "./package.json" + }, + "dependencies": { + "@isomorphic-git/lightning-fs": "^4.6.0", + "assert": "^2.1.0", + "babel-bundle": "file:./playwright/packages/playwright/bundles/babel", + "browserify-zlib": "^0.2.0", + "buffer": "^6.0.3", + "crypto-browserify": "^3.12.0", + "events": "^3.3.0", + "expect-bundle": "file:./playwright/packages/playwright/bundles/expect", + "https-browserify": "^1.0.0", + "inspector": "^0.5.0", + "os-browserify": "^0.3.0", + "path": "^0.12.7", + "process": "^0.11.10", + "readable-stream": "^4.4.2", + "setimmediate": "^1.0.5", + "stream-http": "^3.2.0", + "string_decoder": "^1.3.0", + "test-utils-bundle": "file:./playwright/packages/playwright/bundles/utils", + "url": "^0.11.3", + "util": "^0.12.5", + "utils-bundle": "file:./playwright/packages/playwright-core/bundles/utils", + "zip-bundle": "file:./playwright/packages/playwright-core/bundles/zip" + }, + "devDependencies": { + "@types/chrome": "^0.0.246", + "@vitejs/plugin-react": "^4.1.0", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "rimraf": "^5.0.5", + "rollup-plugin-sourcemaps": "^0.6.3", + "typescript": "5.2.2", + "vite": "4.4.10", + "vite-plugin-require-transform": "1.0.21", + "web-package": "file:./playwright/packages/web" + } +} diff --git a/src/client/crx.ts b/src/client/crx.ts new file mode 100644 index 000000000..ce30e53a7 --- /dev/null +++ b/src/client/crx.ts @@ -0,0 +1,133 @@ +/** + * Copyright (c) Rui Figueira. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { EventEmitter } from 'events'; +import { ChannelOwner } from 'playwright-core/lib/client/channelOwner'; +import type * as api from '../types/types'; +import type * as channels from '../protocol/channels'; +import type { Page } from 'playwright-core/lib/client/page'; +import type { BrowserContext } from 'playwright-core/lib/client/browserContext'; + +function from(obj: any): T { + return obj._object as T; +} + +export class Crx extends ChannelOwner implements api.Crx { + + private _crxApplication?: CrxApplication; + + static from(crx: channels.CrxChannel): Crx { + return (crx as any)._object; + } + + async start(options?: channels.CrxStartOptions) { + if (!this._crxApplication) { + this._crxApplication = from((await this._channel.start(options ?? {})).crxApplication); + this._crxApplication.on('close', () => { + this._crxApplication = undefined; + }); + } + + return this._crxApplication; + } +} + +export class CrxRecorder extends EventEmitter { + private _channel: channels.CrxApplicationChannel; + private _hidden: boolean = true; + + constructor(channel: channels.CrxApplicationChannel) { + super(); + this._channel = channel; + this._channel.on('hide', () => { + this._hidden = true; + this.emit('hide'); + }); + this._channel.on('show', () => { + this._hidden = false; + this.emit('show'); + }); + } + + isHidden() { + return this._hidden; + } + + async show(options?: channels.CrxApplicationShowRecorderOptions) { + await this._channel.showRecorder(options ?? {}); + } + + async hide() { + await this._channel.hideRecorder(); + } +} + +export class CrxApplication extends ChannelOwner implements api.CrxApplication { + private _context: BrowserContext; + readonly recorder: api.CrxRecorder; + + static from(crxApplication: channels.CrxApplicationChannel): CrxApplication { + return (crxApplication as any)._object; + } + + constructor(parent: ChannelOwner, type: string, guid: string, initializer: channels.CrxApplicationInitializer) { + super(parent, type, guid, initializer); + this._context = (initializer.context as any)._object; + this.recorder = new CrxRecorder(this._channel); + } + + context() { + return this._context; + } + + pages(): api.Page[] { + return this._context.pages(); + } + + async attach(tabId: number) { + return from((await this._channel.attach({ tabId })).page); + } + + async attachAll(options?: channels.CrxApplicationAttachAllOptions) { + // we must convert url as string into string[] + const { url: urlOrUrls, ...remaining } = options ?? {}; + const url = urlOrUrls ? typeof urlOrUrls === 'string' ? [urlOrUrls] : urlOrUrls : undefined; + const params = { ...remaining, url }; + + return (await this._channel.attachAll(params)).pages.map(p => from(p)); + } + + async detach(tabIdOrPage: number | Page): Promise { + const params = typeof tabIdOrPage === 'number' ? + { tabId: tabIdOrPage } : + { page: tabIdOrPage._channel }; + + await this._channel.detach(params); + } + + async detachAll(): Promise { + await this._channel.detachAll(); + } + + async newPage(options?: channels.CrxApplicationNewPageOptions) { + return from((await this._channel.newPage(options ?? {})).page); + } + + async close() { + await this._channel.close().catch(() => {}); + this.emit('close'); + } +} diff --git a/src/client/crxConnection.ts b/src/client/crxConnection.ts new file mode 100644 index 000000000..86a565ebd --- /dev/null +++ b/src/client/crxConnection.ts @@ -0,0 +1,53 @@ +/** + * Copyright (c) Rui Figueira. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Connection } from 'playwright-core/lib/client/connection'; +import { Crx, CrxApplication } from './crx'; +import { CrxPlaywright } from './crxPlaywright'; +import { findValidator } from 'playwright-core/lib/protocol/validatorPrimitives'; + +export class CrxConnection extends Connection { + constructor() { + super(undefined, undefined); + } + + dispatch(message: object): void { + const { guid: parentGuid, method, params } = message as any; + + if (method === '__create__') { + const { type, guid } = params; + let initializer = params.initializer; + + const parent = this._objects.get(parentGuid)!; + const validator = findValidator(type, '', 'Initializer'); + initializer = validator(initializer, '', { tChannelImpl: (this as any)._tChannelImplFromWire.bind(this), binary: 'buffer' }); + + switch (type) { + case 'Playwright': + new CrxPlaywright(parent, type, guid, initializer); + return; + case 'Crx': + new Crx(parent, type, guid, initializer); + return; + case 'CrxApplication': + new CrxApplication(parent, type, guid, initializer); + return; + } + } + + return super.dispatch(message); + } +} diff --git a/src/client/crxPlaywright.ts b/src/client/crxPlaywright.ts new file mode 100644 index 000000000..75d93d851 --- /dev/null +++ b/src/client/crxPlaywright.ts @@ -0,0 +1,30 @@ +/** + * Copyright (c) Rui Figueira. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +import type * as channels from '../protocol/channels'; +import { ChannelOwner } from "playwright-core/lib/client/channelOwner"; +import { Playwright } from "playwright-core/lib/client/playwright"; +import { Crx } from './crx'; + +export class CrxPlaywright extends Playwright { + + readonly _crx: Crx; + + constructor(parent: ChannelOwner, type: string, guid: string, initializer: channels.CrxPlaywrightInitializer) { + super(parent, type, guid, initializer); + this._crx = Crx.from(initializer._crx); + } +} diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 000000000..f8972754c --- /dev/null +++ b/src/index.ts @@ -0,0 +1,53 @@ +/** + * Copyright (c) Rui Figueira. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import './shims/global'; + +import './protocol/validator'; + +import { DispatcherConnection, RootDispatcher } from 'playwright-core/lib/server'; +import { setUnderTest } from 'playwright-core/lib/utils'; +import { CrxConnection } from './client/crxConnection'; +import type { CrxPlaywright as CrxPlaywrightAPI } from './client/crxPlaywright'; +import { CrxPlaywright } from './server/crxPlaywright'; +import { CrxPlaywrightDispatcher } from './server/dispatchers/crxPlaywrightDispatcher'; +export { expect, test } from '@playwright/test/lib/index'; + +const playwright = new CrxPlaywright(); + +const clientConnection = new CrxConnection(); +const dispatcherConnection = new DispatcherConnection(true /* local */); + +// Dispatch synchronously at first. +dispatcherConnection.onmessage = message => clientConnection.dispatch(message); +clientConnection.onmessage = message => dispatcherConnection.dispatch(message); + +const rootScope = new RootDispatcher(dispatcherConnection); + +// Initialize Playwright channel. +new CrxPlaywrightDispatcher(rootScope, playwright); +const playwrightAPI = clientConnection.getObjectWithKnownName('Playwright') as CrxPlaywrightAPI; + +// Switch to async dispatch after we got Playwright object. +dispatcherConnection.onmessage = message => setImmediate(() => clientConnection.dispatch(message)); +clientConnection.onmessage = message => setImmediate(() => dispatcherConnection.dispatch(message)); + +clientConnection.toImpl = (x: any) => x ? dispatcherConnection._dispatchers.get(x._guid)!._object : dispatcherConnection._dispatchers.get(''); +(playwrightAPI as any)._toImpl = clientConnection.toImpl; + +export const _setUnderTest = setUnderTest; +export const { _crx: crx } = playwrightAPI; +export default playwrightAPI; diff --git a/src/protocol/channels.ts b/src/protocol/channels.ts new file mode 100644 index 000000000..3812ce975 --- /dev/null +++ b/src/protocol/channels.ts @@ -0,0 +1,166 @@ +/** + * Copyright (c) Rui Figueira. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type { BrowserContextChannel, Channel, PageChannel, PlaywrightInitializer } from '@protocol/channels'; +import type { CallMetadata } from 'playwright-core/lib/server/instrumentation'; + +export type CrxPlaywrightInitializer = PlaywrightInitializer & { _crx: CrxChannel }; + +// ----------- Crx ----------- +export type CrxInitializer = {}; +export interface CrxEventTarget { +} +export interface CrxChannel extends CrxEventTarget, Channel { + _type_Crx: boolean; + start(params: CrxStartParams, metadata?: CallMetadata): Promise; +} +export type CrxStartParams = { + slowMo?: number, +}; +export type CrxStartOptions = { + slowMo?: number, +}; +export type CrxStartResult = { + crxApplication: CrxApplicationChannel, +}; + +export interface CrxEvents { +} + +// ----------- CrxApplication ----------- +export type CrxApplicationInitializer = { + context: BrowserContextChannel, +}; +export interface CrxApplicationEventTarget { + on(event: 'hide', callback: (params: CrxApplicationHideEvent) => void): this; + on(event: 'show', callback: (params: CrxApplicationShowEvent) => void): this; +} +export interface CrxApplicationChannel extends CrxApplicationEventTarget, Channel { + _type_CrxApplication: boolean; + attach(params: CrxApplicationAttachParams, metadata?: CallMetadata): Promise; + attachAll(params: CrxApplicationAttachAllParams, metadata?: CallMetadata): Promise; + detach(params: CrxApplicationDetachParams, metadata?: CallMetadata): Promise; + detachAll(params?: CrxApplicationDetachAllParams, metadata?: CallMetadata): Promise; + newPage(params: CrxApplicationNewPageParams, metadata?: CallMetadata): Promise; + showRecorder(params: CrxApplicationShowRecorderParams, metadata?: CallMetadata): Promise; + hideRecorder(params?: CrxApplicationHideRecorderParams, metadata?: CallMetadata): Promise; + close(params?: CrxApplicationCloseParams, metadata?: CallMetadata): Promise; +} +export type CrxApplicationHideEvent = {}; +export type CrxApplicationShowEvent = {}; +export type CrxApplicationAttachParams = { + tabId: number, +}; +export type CrxApplicationAttachOptions = { + +}; +export type CrxApplicationAttachResult = { + page: PageChannel, +}; +export type CrxApplicationAttachAllParams = { + status?: 'loading' | 'complete', + lastFocusedWindow?: boolean, + windowId?: number, + windowType?: 'normal' | 'popup' | 'panel' | 'app' | 'devtools', + active?: boolean, + index?: number, + title?: string, + url?: string[], + currentWindow?: boolean, + highlighted?: boolean, + discarded?: boolean, + autoDiscardable?: boolean, + pinned?: boolean, + audible?: boolean, + muted?: boolean, + groupId?: number, +}; +export type CrxApplicationAttachAllOptions = { + status?: 'loading' | 'complete', + lastFocusedWindow?: boolean, + windowId?: number, + windowType?: 'normal' | 'popup' | 'panel' | 'app' | 'devtools', + active?: boolean, + index?: number, + title?: string, + url?: string[], + currentWindow?: boolean, + highlighted?: boolean, + discarded?: boolean, + autoDiscardable?: boolean, + pinned?: boolean, + audible?: boolean, + muted?: boolean, + groupId?: number, +}; +export type CrxApplicationAttachAllResult = { + pages: PageChannel[], +}; +export type CrxApplicationDetachParams = { + tabId?: number, + page?: PageChannel, +}; +export type CrxApplicationDetachOptions = { + tabId?: number, + page?: PageChannel, +}; +export type CrxApplicationDetachResult = void; +export type CrxApplicationDetachAllParams = {}; +export type CrxApplicationDetachAllOptions = {}; +export type CrxApplicationDetachAllResult = void; +export type CrxApplicationNewPageParams = { + index?: number, + openerTabId?: number, + url?: string, + pinned?: boolean, + windowId?: number, + active?: boolean, + selected?: boolean, +}; +export type CrxApplicationNewPageOptions = { + index?: number, + openerTabId?: number, + url?: string, + pinned?: boolean, + windowId?: number, + active?: boolean, + selected?: boolean, +}; +export type CrxApplicationNewPageResult = { + page: PageChannel, +}; +export type CrxApplicationShowRecorderParams = { + mode?: 'none' | 'recording' | 'inspecting', + language?: string, + testIdAttributeName?: string, +}; +export type CrxApplicationShowRecorderOptions = { + mode?: 'none' | 'recording' | 'inspecting', + language?: string, + testIdAttributeName?: string, +}; +export type CrxApplicationShowRecorderResult = void; +export type CrxApplicationHideRecorderParams = {}; +export type CrxApplicationHideRecorderOptions = {}; +export type CrxApplicationHideRecorderResult = void; +export type CrxApplicationCloseParams = {}; +export type CrxApplicationCloseOptions = {}; +export type CrxApplicationCloseResult = void; + +export interface CrxApplicationEvents { + 'hide': CrxApplicationHideEvent; + 'show': CrxApplicationShowEvent; +} diff --git a/src/protocol/validator.ts b/src/protocol/validator.ts new file mode 100644 index 000000000..cc05470a6 --- /dev/null +++ b/src/protocol/validator.ts @@ -0,0 +1,121 @@ +/** + * Copyright (c) Rui Figueira. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import 'playwright-core/lib/protocol/validator'; + +import { scheme, tArray, tBoolean, tChannel, tEnum, tNumber, tObject, tOptional, tString } from 'playwright-core/lib/protocol/validatorPrimitives'; + +// "override" PlaywrightInitializer, adds _crx +scheme.PlaywrightInitializer = tObject({ + chromium: tChannel(['BrowserType']), + firefox: tChannel(['BrowserType']), + webkit: tChannel(['BrowserType']), + android: tChannel(['Android']), + electron: tChannel(['Electron']), + utils: tChannel(['LocalUtils']), + deviceDescriptors: tArray(tObject({ + name: tString, + descriptor: tObject({ + userAgent: tString, + viewport: tObject({ + width: tNumber, + height: tNumber, + }), + screen: tOptional(tObject({ + width: tNumber, + height: tNumber, + })), + deviceScaleFactor: tNumber, + isMobile: tBoolean, + hasTouch: tBoolean, + defaultBrowserType: tEnum(['chromium', 'firefox', 'webkit']), + }), + })), + selectors: tChannel(['Selectors']), + preLaunchedBrowser: tOptional(tChannel(['Browser'])), + preConnectedAndroidDevice: tOptional(tChannel(['AndroidDevice'])), + socksSupport: tOptional(tChannel(['SocksSupport'])), + _crx: tChannel(['Crx']), +}); + +scheme.CrxInitializer = tOptional(tObject({})); +scheme.CrxStartParams = tObject({ + slowMo: tOptional(tNumber), +}); +scheme.CrxStartResult = tObject({ + crxApplication: tChannel(['CrxApplication']), +}); +scheme.CrxApplicationInitializer = tObject({ + context: tChannel(['BrowserContext']), +}); +scheme.CrxApplicationHideEvent = tOptional(tObject({})); +scheme.CrxApplicationShowEvent = tOptional(tObject({})); +scheme.CrxApplicationAttachParams = tObject({ + tabId: tNumber, +}); +scheme.CrxApplicationAttachResult = tObject({ + page: tChannel(['Page']), +}); +scheme.CrxApplicationAttachAllParams = tObject({ + status: tOptional(tEnum(['loading', 'complete'])), + lastFocusedWindow: tOptional(tBoolean), + windowId: tOptional(tNumber), + windowType: tOptional(tEnum(['normal', 'popup', 'panel', 'app', 'devtools'])), + active: tOptional(tBoolean), + index: tOptional(tNumber), + title: tOptional(tString), + url: tOptional(tArray(tString)), + currentWindow: tOptional(tBoolean), + highlighted: tOptional(tBoolean), + discarded: tOptional(tBoolean), + autoDiscardable: tOptional(tBoolean), + pinned: tOptional(tBoolean), + audible: tOptional(tBoolean), + muted: tOptional(tBoolean), + groupId: tOptional(tNumber), +}); +scheme.CrxApplicationAttachAllResult = tObject({ + pages: tArray(tChannel(['Page'])), +}); +scheme.CrxApplicationDetachParams = tObject({ + tabId: tOptional(tNumber), + page: tOptional(tChannel(['Page'])), +}); +scheme.CrxApplicationDetachResult = tOptional(tObject({})); +scheme.CrxApplicationDetachAllParams = tOptional(tObject({})); +scheme.CrxApplicationDetachAllResult = tOptional(tObject({})); +scheme.CrxApplicationNewPageParams = tObject({ + index: tOptional(tNumber), + openerTabId: tOptional(tNumber), + url: tOptional(tString), + pinned: tOptional(tBoolean), + windowId: tOptional(tNumber), + active: tOptional(tBoolean), + selected: tOptional(tBoolean), +}); +scheme.CrxApplicationNewPageResult = tObject({ + page: tChannel(['Page']), +}); +scheme.CrxApplicationShowRecorderParams = tObject({ + mode: tOptional(tEnum(['none', 'recording', 'inspecting'])), + language: tOptional(tString), + testIdAttributeName: tOptional(tString), +}); +scheme.CrxApplicationShowRecorderResult = tOptional(tObject({})); +scheme.CrxApplicationHideRecorderParams = tOptional(tObject({})); +scheme.CrxApplicationHideRecorderResult = tOptional(tObject({})); +scheme.CrxApplicationCloseParams = tOptional(tObject({})); +scheme.CrxApplicationCloseResult = tOptional(tObject({})); diff --git a/src/server/crx.ts b/src/server/crx.ts new file mode 100644 index 000000000..af64accc7 --- /dev/null +++ b/src/server/crx.ts @@ -0,0 +1,184 @@ +/** + * Copyright (c) Rui Figueira. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type * as channels from '@protocol/channels'; +import { RecentLogsCollector } from 'playwright-core/lib/common/debugLogger'; +import type { BrowserOptions, BrowserProcess } from 'playwright-core/lib/server/browser'; +import { CRBrowser } from 'playwright-core/lib/server/chromium/crBrowser'; +import type { CRPage } from 'playwright-core/lib/server/chromium/crPage'; +import { helper } from 'playwright-core/lib/server/helper'; +import { SdkObject } from 'playwright-core/lib/server/instrumentation'; +import { Page } from 'playwright-core/lib/server/page'; +import type { Playwright } from 'playwright-core/lib/server/playwright'; +import { Recorder } from 'playwright-core/lib/server/recorder'; +import { assert } from 'playwright-core/lib/utils/debug'; +import type * as crxchannels from '../protocol/channels'; +import { CrxRecorderApp } from './recorder/crxRecorderApp'; +import { CrxTransport } from './transport/crxTransport'; + +export class Crx extends SdkObject { + + constructor(playwright: Playwright) { + super(playwright, 'crx'); + } + + async start(options?: crxchannels.CrxStartOptions): Promise { + const transport = new CrxTransport(); + const browserLogsCollector = new RecentLogsCollector(); + const browserProcess: BrowserProcess = { + onclose: undefined, + process: undefined, + close: () => Promise.resolve(), + kill: () => Promise.resolve(), + }; + const contextOptions: channels.BrowserNewContextParams = { + noDefaultViewport: true, + viewport: undefined, + }; + const browserOptions: BrowserOptions = { + name: 'chromium', + isChromium: true, + headful: true, + persistent: contextOptions, + browserProcess, + protocolLogger: helper.debugProtocolLogger(), + browserLogsCollector, + originalLaunchOptions: {}, + artifactsDir: '.', + downloadsPath: '.', + tracesDir: '.', + ...options + }; + const browser = await CRBrowser.connect(this.attribution.playwright, transport, browserOptions); + return new CrxApplication(browser, transport); + } + +} + +export class CrxApplication extends SdkObject { + static Events = { + RecorderHide: 'hide', + RecorderShow: 'show', + }; + + private _browser: CRBrowser; + private _transport: CrxTransport; + private _recorderApp?: CrxRecorderApp; + + constructor(browser: CRBrowser, transport: CrxTransport) { + super(browser, 'crxApplication'); + this.instrumentation.addListener({ + onPageClose: page => { + page.hideHighlight(); + }, + }, null); + Recorder.setAppFactory(async recorder => { + if (!this._recorderApp) { + this._recorderApp = await new CrxRecorderApp(recorder); + this._recorderApp.on('show', () => this.emit(CrxApplication.Events.RecorderShow)); + this._recorderApp.on('hide', () => this.emit(CrxApplication.Events.RecorderHide)); + } + return this._recorderApp; + }); + this._browser = browser; + this._transport = transport; + } + + _context() { + return this._browser._defaultContext!; + } + + async showRecorder(options?: crxchannels.CrxApplicationShowRecorderParams) { + if (!this._recorderApp) { + const { mode, ...otherOptions } = options ?? {}; + await Recorder.show(this._context(), { + language: 'javascript', + mode: mode === 'none' ? undefined : mode, + ...otherOptions + }); + } + + await this._recorderApp!.open(options); + } + + async hideRecorder() { + if (!this._recorderApp) return; + await this._recorderApp.hide(); + } + + async attach(tabId: number): Promise { + const targetId = await this._transport.attach(tabId); + const crPage = this._browser?._crPages.get(targetId); + assert(crPage); + const pageOrError = await crPage.pageOrError(); + if (pageOrError instanceof Error) throw pageOrError; + return pageOrError; + } + + async attachAll(params: crxchannels.CrxApplicationAttachAllParams) { + const tabs = await chrome.tabs.query(params); + const pages = await Promise.all(tabs.map(async tab => { + const baseUrl = chrome.runtime.getURL(''); + if (tab.id && !tab.url?.startsWith(baseUrl)) + return await this.attach(tab.id).catch(() => {}); + })); + return pages.filter(Boolean) as Page[]; + } + + async detach(tabIdOrPage: number | Page) { + const targetId = tabIdOrPage instanceof Page ? + (tabIdOrPage._delegate as CRPage)._targetId : + this._transport.getTargetId(tabIdOrPage); + + await this._doDetach(targetId); + } + + async detachAll() { + const tabs = await chrome.tabs.query({}); + await Promise.all(tabs.map(async tab => { + if (tab.id) + await this.detach(tab.id).catch(() => {}); + })); + } + + async newPage(params: crxchannels.CrxApplicationNewPageParams) { + const tab = await chrome.tabs.create({ url: 'about:blank', ...params }); + if (!tab.id) throw new Error(`No ID found for tab`); + return await this.attach(tab.id); + } + + async close() { + await Promise.all([...this._browser._crPages.keys()].map(this._doDetach)); + await this._browser.close(); + await this._transport.closeAndWait(); + } + + private async _doDetach(targetId?: string) { + if (!targetId) return; + + const crPage = this._browser._crPages.get(targetId); + if (!crPage) return; + + const pageOrError = await crPage.pageOrError(); + if (pageOrError instanceof Error) throw pageOrError; + + // ensure we don't have any injected highlights + await pageOrError.hideHighlight(); + const closed = new Promise(x => pageOrError.once(Page.Events.Close, x)); + await this._transport.detach(targetId); + await closed; + } +} diff --git a/src/server/crxPlaywright.ts b/src/server/crxPlaywright.ts new file mode 100644 index 000000000..9a751834f --- /dev/null +++ b/src/server/crxPlaywright.ts @@ -0,0 +1,27 @@ +/** + * Copyright (c) Rui Figueira. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { Playwright } from 'playwright-core/lib/server/playwright'; +import { Crx } from './crx'; + +export class CrxPlaywright extends Playwright { + + readonly _crx: Crx; + + constructor() { + super({ sdkLanguage: 'javascript' }); + this._crx = new Crx(this); + } +} diff --git a/src/server/dispatchers/crxDispatcher.ts b/src/server/dispatchers/crxDispatcher.ts new file mode 100644 index 000000000..fcce507e6 --- /dev/null +++ b/src/server/dispatchers/crxDispatcher.ts @@ -0,0 +1,90 @@ +/** + * Copyright (c) Rui Figueira. + * + * Licensed under the Apache License, Version 2.0 (the 'License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type * as channels from '../../protocol/channels'; +import { PageDispatcher } from 'playwright-core/lib/server/dispatchers/pageDispatcher'; +import type { Crx } from '../crx'; +import { CrxApplication } from '../crx'; +import type { RootDispatcher } from 'playwright-core/lib/server/dispatchers/dispatcher'; +import { Dispatcher } from 'playwright-core/lib/server/dispatchers/dispatcher'; +import { BrowserContextDispatcher } from 'playwright-core/lib/server/dispatchers/browserContextDispatcher'; + +export class CrxDispatcher extends Dispatcher implements channels.CrxChannel { + _type_Crx = true; + + constructor(scope: RootDispatcher, crx: Crx) { + super(scope, crx, 'Crx', { }); + } + + async start(params: channels.CrxStartParams): Promise { + return { crxApplication: new CrxApplicationDispatcher(this, await this._object.start(params)) }; + } +} + +export class CrxApplicationDispatcher extends Dispatcher implements channels.CrxApplicationChannel { + _type_CrxApplication = true; + + private _context: BrowserContextDispatcher; + + constructor(scope: CrxDispatcher, crxApplication: CrxApplication) { + const context = new BrowserContextDispatcher(scope, crxApplication._context()); + super(scope, crxApplication, 'CrxApplication', { context }); + this._context = context; + this.addObjectListener(CrxApplication.Events.RecorderHide, () => { + (this._dispatchEvent as any)('hide'); + }); + this.addObjectListener(CrxApplication.Events.RecorderShow, () => { + (this._dispatchEvent as any)('show'); + }); + } + + async attach(params: channels.CrxApplicationAttachParams): Promise { + return { page: PageDispatcher.from(this._context, await this._object.attach(params.tabId)) }; + } + + async attachAll(params: channels.CrxApplicationAttachAllParams): Promise { + return { pages: (await this._object.attachAll(params)).map(page => PageDispatcher.from(this._context, page)) }; + } + + async detach(params: channels.CrxApplicationDetachParams): Promise { + if ((params.tabId && params.page)) + throw new Error(`Only either tabId or page must be specified, not both`); + if ((!params.tabId && !params.page)) + throw new Error(`Either tabId or page must be specified, not none`); + await this._object.detach(params.tabId ?? (params.page as PageDispatcher)._object); + } + + async detachAll(): Promise { + await this._object.detachAll(); + } + + async newPage(params: channels.CrxApplicationNewPageParams): Promise { + return { page: PageDispatcher.from(this._context, await this._object.newPage(params)) }; + } + + async showRecorder(params: channels.CrxApplicationShowRecorderParams): Promise { + await this._object.showRecorder(params); + } + + async hideRecorder(): Promise { + await this._object.hideRecorder(); + } + + async close(): Promise { + await this._object.close(); + this._dispose(); + } +} diff --git a/src/server/dispatchers/crxPlaywrightDispatcher.ts b/src/server/dispatchers/crxPlaywrightDispatcher.ts new file mode 100644 index 000000000..ac72d003e --- /dev/null +++ b/src/server/dispatchers/crxPlaywrightDispatcher.ts @@ -0,0 +1,58 @@ +/** + * Copyright (c) Rui Figueira. + * + * Licensed under the Apache License, Version 2.0 (the 'License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import type * as channels from '@protocol/channels'; +import descriptors from 'playwright-core/lib/server/deviceDescriptors'; +import { AndroidDispatcher } from 'playwright-core/lib/server/dispatchers/androidDispatcher'; +import { BrowserTypeDispatcher } from 'playwright-core/lib/server/dispatchers/browserTypeDispatcher'; +import type { RootDispatcher } from 'playwright-core/lib/server/dispatchers/dispatcher'; +import { Dispatcher } from 'playwright-core/lib/server/dispatchers/dispatcher'; +import { ElectronDispatcher } from 'playwright-core/lib/server/dispatchers/electronDispatcher'; +import { LocalUtilsDispatcher } from 'playwright-core/lib/server/dispatchers/localUtilsDispatcher'; +import { APIRequestContextDispatcher } from 'playwright-core/lib/server/dispatchers/networkDispatchers'; +import { SelectorsDispatcher } from 'playwright-core/lib/server/dispatchers/selectorsDispatcher'; +import { GlobalAPIRequestContext } from 'playwright-core/lib/server/fetch'; +import type { Playwright } from 'playwright-core/lib/server/playwright'; +import { CrxDispatcher } from './crxDispatcher'; +import type { CrxPlaywright } from '../crxPlaywright'; + +// based on PlaywrightDispatcher +export class CrxPlaywrightDispatcher extends Dispatcher implements channels.PlaywrightChannel { + _type_Playwright; + + constructor(scope: RootDispatcher, playwright: CrxPlaywright) { + super(scope, playwright, 'Playwright', { + chromium: new BrowserTypeDispatcher(scope, playwright.chromium), + firefox: new BrowserTypeDispatcher(scope, playwright.firefox), + webkit: new BrowserTypeDispatcher(scope, playwright.webkit), + android: new AndroidDispatcher(scope, playwright.android), + electron: new ElectronDispatcher(scope, playwright.electron), + utils: new LocalUtilsDispatcher(scope, playwright), + deviceDescriptors: Object.entries(descriptors).map(([name, descriptor]) => ({ name, descriptor })), + selectors: new SelectorsDispatcher(scope, playwright.selectors), + _crx: new CrxDispatcher(scope, playwright._crx), + }); + this._type_Playwright = true; + } + + async newRequest(params: channels.PlaywrightNewRequestParams): Promise { + const request = new GlobalAPIRequestContext(this._object, params); + return { request: APIRequestContextDispatcher.from(this.parentScope(), request) }; + } + + async cleanup() { + // do nothing + } +} diff --git a/src/server/recorder/crxRecorderApp.ts b/src/server/recorder/crxRecorderApp.ts new file mode 100644 index 000000000..3444d2f14 --- /dev/null +++ b/src/server/recorder/crxRecorderApp.ts @@ -0,0 +1,134 @@ +/** + * Copyright (c) Rui Figueira. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import type { CallLog, EventData, Source } from '@recorder/recorderTypes'; +import { EventEmitter } from 'events'; +import type { Recorder } from 'playwright-core/lib/server/recorder'; +import type { IRecorderApp } from 'playwright-core/lib/server/recorder/recorderApp'; +import { ManualPromise } from 'playwright-core/lib/utils'; +import type * as channels from '../../protocol/channels'; + +type Port = chrome.runtime.Port; +type TabChangeInfo = chrome.tabs.TabChangeInfo; +type ChromeWindow = chrome.windows.Window; + +export type RecorderMessage = { type: 'recorder' } & ( + | { method: 'updateCallLogs', callLogs: CallLog[] } + | { method: 'setPaused', paused: boolean } + | { method: 'setMode', mode: 'none' | 'recording' | 'inspecting' } + | { method: 'setSources', sources: Source[] } + | { method: 'setFileIfNeeded', file: string } + | { method: 'setSelector', selector: string, focus?: boolean } +); + +export class CrxRecorderApp extends EventEmitter implements IRecorderApp { + private _recorder: Recorder; + private _window?: ChromeWindow; + private _port?: Port; + + constructor(recorder: Recorder) { + super(); + this._recorder = recorder; + chrome.windows.onRemoved.addListener(window => { + if (this._window?.id === window) + this.hide(); + }); + } + + async open(options?: channels.CrxApplicationShowRecorderParams) { + if (!this._window) { + const promise = new ManualPromise(); + this._window = await chrome.windows.create({ type: 'popup', url: 'index.html', }); + const onUpdated = (tabId: number, { status }: TabChangeInfo) => { + if (this._window?.tabs?.find(t => t.id === tabId) && status === 'complete') { + chrome.tabs.onUpdated.removeListener(onUpdated); + promise.resolve(tabId); + } + }; + chrome.tabs.onUpdated.addListener(onUpdated); + const tabId = await promise; + this._port = chrome.tabs.connect(tabId); + this._port.onMessage.addListener(this._onMessage); + this._port.onDisconnect.addListener(this.hide.bind(this)); + this.emit('show'); + } else { + await chrome.windows.update(this._window.id!, { drawAttention: true, focused: true }); + } + const mode = options?.mode ?? 'none'; + + // set in recorder + this._onMessage({ type: 'recorderEvent', event: 'clear', params: {} }); + this._onMessage({ type: 'recorderEvent', event: 'fileChanged', params: { file: 'playwright-test' } }); + this._recorder.setMode(mode); + this.setMode(mode); + } + + async hide() { + if (!this._window) return; + + this._recorder.setMode('none'); + this.setMode('none'); + + this._port?.disconnect(); + if (this._window?.id) chrome.windows.remove(this._window.id).catch(() => {}); + this._window = undefined; + this._port = undefined; + this.emit('hide'); + } + + close = async () => { + this.hide(); + this.emit('close'); + }; + + async setPaused(paused: boolean) { + await this._sendMessage({ type: 'recorder', method: 'setPaused', paused }); + } + + async setMode(mode: 'none' | 'recording' | 'inspecting') { + await this._sendMessage({ type: 'recorder', method: 'setMode', mode }); + } + + async setFileIfNeeded(file: string) { + await this._sendMessage({ type: 'recorder', method: 'setFileIfNeeded', file }); + } + + async setSelector(selector: string, focus?: boolean) { + if (focus) + this._recorder.setMode('none'); + await this._sendMessage({ type: 'recorder', method: 'setSelector', selector, focus }); + } + + async updateCallLogs(callLogs: CallLog[]) { + await this._sendMessage({ type: 'recorder', method: 'updateCallLogs', callLogs }); + } + + async setSources(sources: Source[]) { + await this._sendMessage({ type: 'recorder', method: 'setSources', sources }); + } + + private _onMessage = ({ type, ...eventData }: EventData & { type: string }) => { + if (type === 'recorderEvent') + this.emit('event', eventData); + }; + + async _sendMessage(msg: RecorderMessage) { + try { + return this._port?.postMessage({ ...msg }); + } catch (e) { + // just ignore + } + } +} diff --git a/src/server/transport/crxTransport.ts b/src/server/transport/crxTransport.ts new file mode 100644 index 000000000..2efcae071 --- /dev/null +++ b/src/server/transport/crxTransport.ts @@ -0,0 +1,225 @@ +/** + * Copyright (c) Rui Figueira. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type { Protocol } from 'playwright-core/lib/server/chromium/protocol'; +import type { Progress } from 'playwright-core/lib/server/progress'; +import type { ConnectionTransport, ProtocolRequest, ProtocolResponse } from 'playwright-core/lib/server/transport'; + +type Tab = chrome.tabs.Tab; + +export class CrxTransport implements ConnectionTransport { + private _progress?: Progress; + private _detachedPromise?: Promise; + private _targetToTab: Map; + private _tabToTarget: Map; + + onmessage?: (message: ProtocolResponse) => void; + onclose?: () => void; + + constructor(progress?: Progress) { + this._progress = progress; + this._tabToTarget = new Map(); + this._targetToTab = new Map(); + chrome.debugger.onEvent.addListener(this._onDebuggerEvent); + chrome.debugger.onDetach.addListener(this._onRemoved); + chrome.tabs.onRemoved.addListener(this._onRemoved); + chrome.tabs.onCreated.addListener(this._onPopupCreated); + } + + getTargetId(tabId: number) { + return this._tabToTarget.get(tabId); + } + + async send(message: ProtocolRequest) { + try { + const [, tabIdStr] = /crx-tab-(\d+)/.exec(message.sessionId ?? '') ?? []; + const tabId = tabIdStr ? parseInt(tabIdStr, 10) : undefined; + + let result; + // chrome extensions doesn't support all CDP commands so we need to handle them + if (message.method === 'Target.setAutoAttach' && !tabId) { + // no tab to attach, just skip for now... + result = await Promise.resolve().then(); + } else if (message.method === 'Target.getTargetInfo' && !tabId) { + // most likely related with https://chromium-review.googlesource.com/c/chromium/src/+/2885888 + // See CRBrowser.connect + result = await Promise.resolve().then(); + } else if (message.method === 'Target.createTarget') { + const { id: tabId } = await chrome.tabs.create({ url: 'about:blank' }); + if (!tabId) throw new Error(`New tab has no id`); + const targetId = await this.attach(tabId); + result = { targetId }; + } else if (message.method === 'Target.closeTarget') { + const { targetId } = message.params; + await this.detach(targetId); + result = true; + } else if (message.method === 'Target.disposeBrowserContext') { + // do nothing... + result = await Promise.resolve().then(); + } else if (message.method === 'Browser.getVersion') { + const userAgent = navigator.userAgent; + const [, product] = userAgent.match(/(Chrome\/[0-9\.]+)\b/) ?? []; + result = await Promise.resolve({ product, userAgent }).then(); + } else if (message.method === 'Browser.getWindowForTarget') { + // just don't send a window ID... + result = await Promise.resolve({}).then(); + } else if (message.method === 'Browser.setDownloadBehavior') { + // do nothing... + result = await Promise.resolve().then(); + } else { + // @ts-ignore + result = await this._send(message.method, { tabId, ...message.params }); + } + + this._emitMessage({ + ...message, + result, + }); + } catch (error) { + this._emitMessage({ + ...message, + // @ts-ignore + error, + }); + } + } + + async attach(tabId: number) { + let targetId = this._tabToTarget.get(tabId); + + if (!targetId) { + this._progress?.log(``); + await chrome.debugger.attach({ tabId }, '1.3'); + // we don't create a new browser context, just return the current one + const { targetInfo } = await this._send('Target.getTargetInfo', { tabId }); + targetId = targetInfo.targetId; + + // force browser to create a page + this._emitAttachedToTarget(tabId, targetInfo); + + this._tabToTarget.set(tabId, targetId); + this._targetToTab.set(targetId, tabId); + } + + return targetId; + } + + async detach(tabOrTarget: number | string) { + const tabId = typeof tabOrTarget === 'number' ? tabOrTarget : this._targetToTab.get(tabOrTarget); + if (!tabId) return; + + const targetId = this._tabToTarget.get(tabId); + this._tabToTarget.delete(tabId); + if (targetId) { + this._targetToTab.delete(targetId); + this._emitDetachedToTarget(tabId, targetId); + } + await chrome.debugger.detach({ tabId }).catch(() => {}); + } + + close() { + if (this._detachedPromise) return; + this._detachedPromise = Promise.all([...this._tabToTarget.keys()] + .map(this.detach)) + .then(() => this.onclose?.()); + } + + async closeAndWait() { + this._progress?.log(``); + chrome.debugger.onEvent.removeListener(this._onDebuggerEvent); + chrome.tabs.onCreated.removeListener(this._onPopupCreated); + this.close(); + await this._detachedPromise; // Make sure to await the actual disconnect. + chrome.tabs.onRemoved.removeListener(this._onRemoved); + chrome.tabs.onDetached.removeListener(this._onRemoved); + this._progress?.log(``); + } + + private async _send( + method: T, + params?: Protocol.CommandParameters[T] & { tabId?: number } + ) { + const { tabId, ...commandParams } = params ?? {}; + // eslint-disable-next-line no-console + if (!tabId) console.trace(`No tabId provided for ${method}`); + + return await chrome.debugger.sendCommand({ tabId }, method, commandParams) as + Protocol.CommandReturnValues[T]; + } + + private _onPopupCreated = async ({ openerTabId, id }: Tab) => { + if (!openerTabId || !id) return; + + if (this._tabToTarget.has(openerTabId)) + // it can fail due to "Cannot access a chrome:// URL" + await this.attach(id).catch(() => {}); + }; + + private _onRemoved = (tabIdOrDebuggee: number | { tabId?: number }) => { + const tabId = typeof tabIdOrDebuggee === 'number' ? tabIdOrDebuggee : tabIdOrDebuggee.tabId; + if (!tabId) return; + + const targetId = this._tabToTarget.get(tabId); + this._tabToTarget.delete(tabId); + if (targetId) { + this._targetToTab.delete(targetId); + this._emitDetachedToTarget(tabId, targetId); + } + }; + + private _onDebuggerEvent = ({ tabId }: { tabId?: number }, message?: string, params?: any) => { + if (!tabId) return; + + this._emitMessage({ + method: message, + sessionId: this._sessionIdFor(tabId), + params, + }); + }; + + private _emitMessage(message: ProtocolResponse) { + if (this.onmessage) + this.onmessage(message); + } + + private _sessionIdFor(tabId: number): string { + return `crx-tab-${tabId}`; + } + + private _emitAttachedToTarget(tabId: number, targetInfo: Protocol.Target.TargetInfo) { + const sessionId = this._sessionIdFor(tabId); + this._emitMessage({ + method: 'Target.attachedToTarget', + sessionId: '', + params: { + sessionId, + targetInfo, + } + }); + } + + private _emitDetachedToTarget(tabId: number, targetId: string) { + const sessionId = this._sessionIdFor(tabId); + this._emitMessage({ + method: 'Target.detachedFromTarget', + sessionId: '', + params: { + sessionId, + targetId, + } + }); + } +} diff --git a/src/shims/buffer.ts b/src/shims/buffer.ts new file mode 100644 index 000000000..ab2043762 --- /dev/null +++ b/src/shims/buffer.ts @@ -0,0 +1,19 @@ +/** + * Copyright (c) Rui Figueira. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import buffer from 'buffer'; + +self.Buffer = buffer.Buffer; diff --git a/src/shims/child_process.ts b/src/shims/child_process.ts new file mode 100644 index 000000000..96c56e598 --- /dev/null +++ b/src/shims/child_process.ts @@ -0,0 +1,27 @@ +/** + * Copyright (c) Rui Figueira. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +function noop() {} + +export const spawn = noop; +export const spawnSync = noop; +export const execSync = noop; + +export default { + spawn, + spawnSync, + execSync, +}; diff --git a/src/shims/chokidar.ts b/src/shims/chokidar.ts new file mode 100644 index 000000000..1d63f7a66 --- /dev/null +++ b/src/shims/chokidar.ts @@ -0,0 +1,21 @@ +/** + * Copyright (c) Rui Figueira. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +function noop() {} + +export default { + watch: noop, +}; diff --git a/src/shims/dns.ts b/src/shims/dns.ts new file mode 100644 index 000000000..f3df9a7c7 --- /dev/null +++ b/src/shims/dns.ts @@ -0,0 +1,21 @@ +/** + * Copyright (c) Rui Figueira. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +function noop() {} + +export const promises = { + lookup: noop() +}; diff --git a/src/shims/fs/index.ts b/src/shims/fs/index.ts new file mode 100644 index 000000000..08e90937f --- /dev/null +++ b/src/shims/fs/index.ts @@ -0,0 +1,39 @@ +/** + * Copyright (c) Rui Figueira. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import FS from '@isomorphic-git/lightning-fs'; + +const fs = new FS('crx'); +const noop = () => ({});; + +export default fs; +export const { promises, readFile, readlink, rename, readdir, stat, lstat } = fs; + +export const chmodSync = noop; +export const createWriteStream = noop; +export const existsSync = noop; +export const lstatSync = noop; +export const mkdirSync = noop; +export const readdirSync = noop; +export const readFileSync = noop; +export const readlinkSync = noop; +export const realpathSync = noop; +export const renameSync = noop; +export const rmdirSync = noop; +export const rmSync = noop; +export const statSync = noop; +export const unlinkSync = noop; +export const writeFileSync = noop; diff --git a/src/shims/fs/promises.ts b/src/shims/fs/promises.ts new file mode 100644 index 000000000..e1c7ba02d --- /dev/null +++ b/src/shims/fs/promises.ts @@ -0,0 +1,5 @@ +import { promises } from "./index"; + +export const { readFile, readlink, rename, readdir, stat, lstat } = promises; + +export const realpath = () => ({}); \ No newline at end of file diff --git a/src/shims/global.ts b/src/shims/global.ts new file mode 100644 index 000000000..ccc619379 --- /dev/null +++ b/src/shims/global.ts @@ -0,0 +1,22 @@ +/** + * Copyright (c) Rui Figueira. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import './process'; +import './setImmediate'; +import './buffer'; + +self.global = self; +self.__dirname = '.'; diff --git a/src/shims/module.ts b/src/shims/module.ts new file mode 100644 index 000000000..9f4745442 --- /dev/null +++ b/src/shims/module.ts @@ -0,0 +1,19 @@ +/** + * Copyright (c) Rui Figueira. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export default { + builtinModules: [], +}; diff --git a/src/shims/net.ts b/src/shims/net.ts new file mode 100644 index 000000000..ee7690900 --- /dev/null +++ b/src/shims/net.ts @@ -0,0 +1,25 @@ +/** + * Copyright (c) Rui Figueira. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +function noop() {} + +export const createConnection = noop; +export const isIP = noop; + +export default { + createConnection, + isIP, +}; diff --git a/src/shims/process.ts b/src/shims/process.ts new file mode 100644 index 000000000..ee2cab07c --- /dev/null +++ b/src/shims/process.ts @@ -0,0 +1,38 @@ +/** + * Copyright (c) Rui Figueira. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// @ts-ignore +import process from 'process/browser'; + +// https://github.com/cabinjs/browser-hrtime/blob/cb6b7c336e93726a302e04a5ac4755e7e353edaf/src/index.ts#L22 +process.hrtime = (previousTimestamp?: [number, number]): [number, number] => { + const baseNow = Math.floor((Date.now() - performance.now()) * 1e-3); + const clocktime = performance.now() * 1e-3; + let seconds = Math.floor(clocktime) + baseNow; + let nanoseconds = Math.floor((clocktime % 1) * 1e9); + + if (previousTimestamp) { + seconds = seconds - previousTimestamp[0]; + nanoseconds = nanoseconds - previousTimestamp[1]; + if (nanoseconds < 0) { + seconds--; + nanoseconds += 1e9; + } + } + return [seconds, nanoseconds]; +}; + +self.process = process; diff --git a/src/shims/readline.ts b/src/shims/readline.ts new file mode 100644 index 000000000..05de3e4a8 --- /dev/null +++ b/src/shims/readline.ts @@ -0,0 +1,23 @@ +/** + * Copyright (c) Rui Figueira. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +function noop() {} + +export const createInterface = noop; + +export default { + createInterface, +}; diff --git a/src/shims/setImmediate.ts b/src/shims/setImmediate.ts new file mode 100644 index 000000000..501e4dfb9 --- /dev/null +++ b/src/shims/setImmediate.ts @@ -0,0 +1,20 @@ +/** + * Copyright (c) Rui Figueira. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import 'setimmediate'; + +// @ts-ignore +self.setImmediate = setImmediate; diff --git a/src/shims/tls.ts b/src/shims/tls.ts new file mode 100644 index 000000000..5beb30a4a --- /dev/null +++ b/src/shims/tls.ts @@ -0,0 +1,23 @@ +/** + * Copyright (c) Rui Figueira. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +function noop() {} + +export const connect = noop; + +export default { + connect, +}; diff --git a/src/shims/util/index.ts b/src/shims/util/index.ts new file mode 100644 index 000000000..161b74d20 --- /dev/null +++ b/src/shims/util/index.ts @@ -0,0 +1,28 @@ +/** + * Copyright (c) Rui Figueira. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// @ts-nocheck +import _util, { promisify as promisify } from '_util'; + +export const promisify = function(first, ...rest) { + if (first !== 'function') return Promise.resolve(); + return _promisify(first, ...rest); +}; + +export * from '_util'; + +const util = { ..._util, promisify }; +export default util; diff --git a/src/types/types.d.ts b/src/types/types.d.ts new file mode 100644 index 000000000..b227c5da4 --- /dev/null +++ b/src/types/types.d.ts @@ -0,0 +1,282 @@ +/** + * Copyright (c) Rui Figueira. + * + * Licensed under the Apache License, Version 2.0 (the 'License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type { BrowserContext } from "playwright-core/lib/client/browserContext"; +import type { Page } from "playwright-core/lib/client/page"; + +export type { BrowserContext } from "playwright-core/lib/client/browserContext"; +export type { Page } from "playwright-core/lib/client/page"; + +export interface Crx { + /** + * @param options + */ + start(options?: { + /** + * Slows down Playwright operations by the specified amount of milliseconds. Useful so that you can see what is going + * on. + */ + slowMo?: number; + }): Promise; +} + +export interface CrxApplication { + /** + * Attach a tab and returns the corresponding `Page`. + * @param tabId + */ + attach(tabId: number): Promise; + + /** + * @param options + */ + attachAll(options?: { + /** + * Optional. Whether the tabs are active in their windows. + */ + active?: null|boolean; + + /** + * Optional. Whether the tabs are audible. @since Chrome 45. + */ + audible?: null|boolean; + + /** + * Optional. Whether the tabs can be discarded automatically by the browser when resources are low. @since Chrome 54. + */ + autoDiscardable?: null|boolean; + + /** + * Optional. Whether the tabs are in the current window. @since Chrome 19. + */ + currentWindow?: null|boolean; + + /** + * Optional. Whether the tabs are discarded. A discarded tab is one whose content has been unloaded from memory, but + * is still visible in the tab strip. Its content gets reloaded the next time it's activated. @since Chrome 54. + */ + discarded?: null|boolean; + + /** + * Optional. The ID of the group that the tabs are in, or chrome.tabGroups.TAB_GROUP_ID_NONE for ungrouped tabs. + * @since Chrome 88 + */ + groupId?: null|number; + + /** + * Optional. Whether the tabs are highlighted. + */ + highlighted?: null|boolean; + + /** + * Optional. The position of the tabs within their windows. @since Chrome 18. + */ + index?: null|number; + + /** + * Optional. Whether the tabs are in the last focused window. @since Chrome 19. + */ + lastFocusedWindow?: null|boolean; + + /** + * Optional. Whether the tabs are muted. @since Chrome 45. + */ + muted?: null|boolean; + + /** + * Optional. Whether the tabs are pinned. + */ + pinned?: null|boolean; + + /** + * Optional. Whether the tabs have completed loading. One of: "loading", or "complete" + */ + status?: null|"loading"|"complete"|"serial"; + + /** + * Optional. Match page titles against a pattern. + */ + title?: null|string; + + /** + * Optional. Match tabs against one or more URL patterns. Note that fragment identifiers are not matched. + */ + url?: null|string|Array; + + /** + * Optional. The ID of the parent window, or `windows.WINDOW_ID_CURRENT` for the current window. + */ + windowId?: null|number; + + /** + * Optional. The type of window the tabs are in. One of: "normal", "popup", "panel", "app", or "devtools" + */ + windowType?: null|"normal"|"popup"|"panel"|"app"|"devtools"; + }): Promise>; + + /** + * Detaches all pages and closes. + */ + close(): Promise; + + /** + * This method returns browser context that can be used for setting up context-wide routing, etc. + */ + context(): BrowserContext; + + /** + * @param tabIdOrPage + */ + detach(tabIdOrPage: number|Page): Promise; + + /** + * Detaches all pages. + */ + detachAll(): Promise; + + /** + * Creates a chrome tab using + * [chrome.tabs.create(createProperties)](https://developer.chrome.com/docs/extensions/reference/tabs/#method-create) + * and attaches it. + * @param options + */ + newPage(options?: { + /** + * Optional. Whether the tab should become the active tab in the window. Does not affect whether the window is focused + * (see windows.update). Defaults to true. @since Chrome 16. + */ + active?: null|boolean; + + /** + * Optional. The position the tab should take in the window. The provided value will be clamped to between zero and + * the number of tabs in the window. + */ + index?: null|number; + + /** + * Optional. The ID of the tab that opened this tab. If specified, the opener tab must be in the same window as the + * newly created tab. @since Chrome 18. + */ + openerTabId?: null|number; + + /** + * Optional. Whether the tab should be pinned. Defaults to false @since Chrome 9. + */ + pinned?: null|boolean; + + /** + * Optional. Whether the tab should become the selected tab in the window. Defaults to true @deprecated since Chrome + * 33. Please use active. + */ + selected?: null|boolean; + + /** + * Optional. The URL to navigate the tab to initially. Fully-qualified URLs must include a scheme (i.e. + * 'http://www.google.com', not 'www.google.com'). Relative URLs will be relative to the current page within the + * extension. Defaults to the New Tab Page. + */ + url?: null|string; + + /** + * Optional. The window to create the new tab in. Defaults to the current window. + */ + windowId?: null|number; + }): Promise; + + /** + * Convenience method that returns all the attached pages. + */ + pages(): Array; + + recorder: CrxRecorder; +} + +export interface CrxRecorder { + /** + * Emitted when recorder is hidden. + */ + on(event: 'hide', listener: (crxRecorder: CrxRecorder) => void): this; + + /** + * Emitted when recorder is shown. + */ + on(event: 'show', listener: (crxRecorder: CrxRecorder) => void): this; + + /** + * Adds an event listener that will be automatically removed after it is triggered once. See `addListener` for more information about this event. + */ + once(event: 'hide', listener: (crxRecorder: CrxRecorder) => void): this; + + /** + * Adds an event listener that will be automatically removed after it is triggered once. See `addListener` for more information about this event. + */ + once(event: 'show', listener: (crxRecorder: CrxRecorder) => void): this; + + /** + * Emitted when recorder is hidden. + */ + addListener(event: 'hide', listener: (crxRecorder: CrxRecorder) => void): this; + + /** + * Emitted when recorder is shown. + */ + addListener(event: 'show', listener: (crxRecorder: CrxRecorder) => void): this; + + /** + * Removes an event listener added by `on` or `addListener`. + */ + removeListener(event: 'hide', listener: (crxRecorder: CrxRecorder) => void): this; + + /** + * Removes an event listener added by `on` or `addListener`. + */ + removeListener(event: 'show', listener: (crxRecorder: CrxRecorder) => void): this; + + /** + * Removes an event listener added by `on` or `addListener`. + */ + off(event: 'hide', listener: (crxRecorder: CrxRecorder) => void): this; + + /** + * Removes an event listener added by `on` or `addListener`. + */ + off(event: 'show', listener: (crxRecorder: CrxRecorder) => void): this; + + /** + * Emitted when recorder is hidden. + */ + prependListener(event: 'hide', listener: (crxRecorder: CrxRecorder) => void): this; + + /** + * Emitted when recorder is shown. + */ + prependListener(event: 'show', listener: (crxRecorder: CrxRecorder) => void): this; + + hide(): Promise; + + isHidden(): boolean; + + /** + * @param options + */ + show(options?: { + language?: null|string; + + mode?: null|"none"|"recording"|"inspecting"; + + testIdAttributeName?: null|string; + }): Promise; +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 000000000..08ce81363 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,34 @@ +{ + "compilerOptions": { + "target": "ES2020", + "useDefineForClassFields": true, + "lib": ["ES2020", "DOM", "DOM.Iterable"], + "skipLibCheck": false, + "esModuleInterop": false, + "allowSyntheticDefaultImports": true, + "allowJs": true, + "strict": true, + "module": "ESNext", + "moduleResolution": "Node", + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": false, + "baseUrl": ".", + "useUnknownInCatchVariables": false, + "paths": { + "@html-reporter/*": ["./playwright/packages/html-reporter/src/*"], + "@injected/*": ["./playwright/packages/playwright-core/src/server/injected/*"], + "@isomorphic/*": ["./playwright/packages/playwright-core/src/utils/isomorphic/*"], + "@protocol/*": ["./playwright/packages/protocol/src/*"], + "@recorder/*": ["./playwright/packages/recorder/src/*"], + "@testIsomorphic/*": ["./playwright/packages/playwright/src/isomorphic/*"], + "@trace/*": ["./playwright/packages/trace/src/*"], + "@web/*": ["./playwright/packages/web/src/*"], + "playwright-core/lib/*": ["./playwright/packages/playwright-core/src/*"], + "@playwright/test/lib/*": ["./playwright/packages/playwright/src/*"], + "tests/*": ["./playwright/tests/*"], + } + }, + "include": ["src"], + "references": [{ "path": "./tsconfig.node.json" }] +} diff --git a/tsconfig.node.json b/tsconfig.node.json new file mode 100644 index 000000000..4bab3b435 --- /dev/null +++ b/tsconfig.node.json @@ -0,0 +1,10 @@ +{ + "compilerOptions": { + "composite": true, + "skipLibCheck": true, + "module": "ESNext", + "moduleResolution": "bundler", + "allowSyntheticDefaultImports": true, + }, + "include": ["../recorder/vite.config.ts"] +} diff --git a/vite.config.ts b/vite.config.ts new file mode 100644 index 000000000..4968bded8 --- /dev/null +++ b/vite.config.ts @@ -0,0 +1,129 @@ +/** + * Copyright (c) Microsoft Corporation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import path from 'path'; +import { defineConfig } from 'vite'; +import requireTransform from 'vite-plugin-require-transform'; + +// we exclude some files with require, otherwise we can get out-of-order dependencies +const requireTransformFiles = [ + 'playwright/packages/playwright-core/bundles/utils/src/utilsBundleImpl.ts', + 'playwright/packages/playwright-core/src/server/dispatchers/playwrightDispatcher.ts', + 'playwright/packages/playwright-core/src/server/recorder/csharp.ts', + 'playwright/packages/playwright-core/src/server/recorder/java.ts', + 'playwright/packages/playwright-core/src/server/recorder/javascript.ts', + 'playwright/packages/playwright-core/src/server/recorder/python.ts', + 'playwright/packages/playwright-core/src/server/registry/dependencies.ts', + 'playwright/packages/playwright-core/src/server/registry/index.ts', + 'playwright/packages/playwright-core/src/utils/comparators.ts', + 'playwright/packages/playwright-core/src/utils/userAgent.ts', + 'playwright/packages/playwright-core/src/utilsBundle.ts', + 'playwright/packages/playwright-core/src/zipBundle.ts', + // tests + 'playwright/packages/playwright/bundles/babel/src/babelBundleImpl.ts', + 'playwright/packages/playwright/src/common/config.ts', + 'playwright/packages/playwright/src/common/expectBundle.ts', + 'playwright/packages/playwright/src/index.ts', + 'playwright/packages/playwright/src/transform/babelBundle.ts', + 'playwright/packages/playwright/src/transform/transform.ts', + 'playwright/packages/playwright/src/utilsBundle.ts', +]; + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [ + requireTransform({ fileRegex: new RegExp('(' + requireTransformFiles.map(s => s.replace(/\//g, '\\/').replace(/\./g, '\.')).join('|') + ')$') }), + ], + resolve: { + alias: { + 'playwright-core/lib': path.resolve(__dirname, './playwright/packages/playwright-core/src'), + '@playwright/test/lib': path.resolve(__dirname, './playwright/packages/playwright/src'), + 'playwright-core': path.resolve(__dirname, './src/index'), + + // for bundles, we use relative paths because different utilsBundleImpl exists in both playwright-core and playwright + './utilsBundleImpl': '../bundles/utils/src/utilsBundleImpl', + './zipBundleImpl': '../bundles/zip/src/zipBundleImpl', + './babelBundleImpl': '../../bundles/babel/src/babelBundleImpl', + './expectBundleImpl': '../../bundles/expect/src/expectBundleImpl', + + // shims + '_util': path.resolve(__dirname, './node_modules/util'), + '@isomorphic-git/lightning-fs': path.resolve(__dirname, './node_modules/@isomorphic-git/lightning-fs'), + 'assert': path.resolve(__dirname, './node_modules/assert'), + 'buffer': path.resolve(__dirname, './node_modules/buffer'), + 'child_process': path.resolve(__dirname, './src/shims/child_process'), + 'chokidar': path.resolve(__dirname, './src/shims/chokidar'), + 'constants': path.resolve(__dirname, './node_modules/constants-browserify'), + 'crypto': path.resolve(__dirname, './node_modules/crypto-browserify'), + 'dns': path.resolve(__dirname, './src/shims/dns'), + 'events': path.resolve(__dirname, './node_modules/events'), + 'fs': path.resolve(__dirname, './src/shims/fs'), + 'graceful-fs': path.resolve(__dirname, './src/shims/fs'), + 'http': path.resolve(__dirname, './node_modules/stream-http'), + 'https': path.resolve(__dirname, './node_modules/https-browserify'), + 'module': path.resolve(__dirname, './src/shims/module'), + 'net': path.resolve(__dirname, './src/shims/net'), + 'os': path.resolve(__dirname, './node_modules/os-browserify/browser'), + 'path': path.resolve(__dirname, './node_modules/path'), + 'process': path.resolve(__dirname, './node_modules/process'), + 'readline': path.resolve(__dirname, './src/shims/readline'), + 'setimmediate': path.resolve(__dirname, './node_modules/setimmediate'), + 'stream': path.resolve(__dirname, './node_modules/readable-stream'), + 'tls': path.resolve(__dirname, './src/shims/tls'), + 'url': path.resolve(__dirname, './node_modules/url'), + 'util': path.resolve(__dirname, './src/shims/util'), + 'zlib': path.resolve(__dirname, './node_modules/browserify-zlib'), + + 'node:events': path.resolve(__dirname, './node_modules/events'), + 'node:stream': path.resolve(__dirname, './node_modules/readable-stream'), + 'node:string_decoder': path.resolve(__dirname, './node_modules/string_decoder'), + }, + }, + define: { + // we need this one because of PLAYWRIGHT_CORE_PATH (it checks the actual version of playwright-core) + 'require.resolve': '((s) => s)', + 'process.platform': '"browser"', + 'process.versions.node': '"18.16"', + 'process.stdout.isTTY': 'false', + 'getFromENV("PLAYWRIGHT_BROWSERS_PATH")': '"."', + 'url.pathToFileURL': '((s) => s)', + 'process.geteuid': '(() => "")', + }, + build: { + outDir: path.resolve(__dirname, './lib/'), + // skip code obfuscation + minify: false, + lib: { + entry: path.resolve(__dirname, 'src/index.ts'), + name: 'playwright-crx', + fileName: 'index', + }, + rollupOptions: { + output: { + exports: 'named', + }, + }, + commonjsOptions: { + include: [ + path.resolve(__dirname, './playwright/packages/playwright-core/src/**/*.js'), + path.resolve(__dirname, './playwright/packages/playwright-core/bundles/utils/src/third_party/**/*.js'), + path.resolve(__dirname, './playwright/packages/playwright-core/bundles/utils/src/utilsBundleImpl.ts'), + /node_modules/, + ], + } + }, + optimizeDeps: { include: ['./utilsBundleImpl'] }, +});