├── .gitignore ├── .npmignore ├── CODE_OF_CONDUCT.md ├── LICENSE ├── README.md ├── SECURITY.md ├── demo.js ├── example.dot ├── example.png ├── package-lock.json ├── package.json ├── src ├── cdp-error.ts ├── cdp.d.ts ├── connection.ts ├── disposable.ts ├── index.ts ├── server.ts └── transports │ ├── transports.ts │ └── websocket.ts └── tsconfig.json /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | 9 | # Diagnostic reports (https://nodejs.org/api/report.html) 10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 11 | 12 | # Runtime data 13 | pids 14 | *.pid 15 | *.seed 16 | *.pid.lock 17 | 18 | # Directory for instrumented libs generated by jscoverage/JSCover 19 | lib-cov 20 | 21 | # Coverage directory used by tools like istanbul 22 | coverage 23 | *.lcov 24 | 25 | # nyc test coverage 26 | .nyc_output 27 | 28 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 29 | .grunt 30 | 31 | # Bower dependency directory (https://bower.io/) 32 | bower_components 33 | 34 | # node-waf configuration 35 | .lock-wscript 36 | 37 | # Compiled binary addons (https://nodejs.org/api/addons.html) 38 | build/Release 39 | 40 | # Dependency directories 41 | node_modules/ 42 | jspm_packages/ 43 | 44 | # TypeScript v1 declaration files 45 | typings/ 46 | 47 | # TypeScript cache 48 | *.tsbuildinfo 49 | 50 | # Optional npm cache directory 51 | .npm 52 | 53 | # Optional eslint cache 54 | .eslintcache 55 | 56 | # Microbundle cache 57 | .rpt2_cache/ 58 | .rts2_cache_cjs/ 59 | .rts2_cache_es/ 60 | .rts2_cache_umd/ 61 | 62 | # Optional REPL history 63 | .node_repl_history 64 | 65 | # Output of 'npm pack' 66 | *.tgz 67 | 68 | # Yarn Integrity file 69 | .yarn-integrity 70 | 71 | # dotenv environment variables file 72 | .env 73 | .env.test 74 | 75 | # parcel-bundler cache (https://parceljs.org/) 76 | .cache 77 | 78 | # Next.js build output 79 | .next 80 | 81 | # Nuxt.js build / generate output 82 | .nuxt 83 | dist 84 | 85 | # Gatsby files 86 | .cache/ 87 | # Comment in the public line in if your project uses Gatsby and *not* Next.js 88 | # https://nextjs.org/blog/next-9-1#public-directory-support 89 | # public 90 | 91 | # vuepress build output 92 | .vuepress/dist 93 | 94 | # Serverless directories 95 | .serverless/ 96 | 97 | # FuseBox cache 98 | .fusebox/ 99 | 100 | # DynamoDB Local files 101 | .dynamodb/ 102 | 103 | # TernJS port file 104 | .tern-port 105 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | /* 2 | !/dist 3 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Microsoft Open Source Code of Conduct 2 | 3 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). 4 | 5 | Resources: 6 | 7 | - [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/) 8 | - [Microsoft Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) 9 | - Contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with questions or concerns 10 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Microsoft Corporation. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vscode-cdp-proxy 2 | 3 | Sample Chrome Debug Protocol proxy used to extend `vscode-js-debug` with custom targets. This can be used to allow js-debug to work with esoteric targets, like WebAssembly-compiled and frameworks like React Native. Say you're building a React Native debugger. The general flow would work like so: 4 | 5 | ![](./example.png) 6 | 7 | 1. You have a React Native extension, which allows users to start debugging via a command or a launch config. 8 | 2. When a session starts, you start a CDP proxy, like the one in this repo. Say it starts listening on `localhost:3000` 9 | 3. Then, you call [`vscode.debug.startDebugger`](https://code.visualstudio.com/api/references/vscode-api#debug.startDebugging) with a configuration like: 10 | 11 | ```js 12 | { 13 | "type": "pwa-chrome", 14 | "request": "attach", 15 | "address": "localhost", // <- host your proxy is running on 16 | "port": 3000, // <- port your proxy is running on 17 | } 18 | ``` 19 | 20 | 4. The debugger will then connect to the proxy like it would any other CDP-enabled target. 21 | 5. Finally, you translate between CDP and the protocol used to debug your target application. In the case of React Native, this is might be a minimal rewrite of some CDP behavior. In the case of more advanced WebAssembly targets, you might translate into something entirely new. 22 | 23 | ## Using this Package 24 | 25 | Parts of this package are exported from [js-debug](https://github.com/microsoft/vscode-js-debug). We may publish these parts as nicely packaged bits for reuse here and in the extension, but that's not done right now. 26 | 27 | Check out `demo.js` for an example of a server. 28 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Security 4 | 5 | Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/). 6 | 7 | If you believe you have found a security vulnerability in any Microsoft-owned repository that meets Microsoft's [Microsoft's definition of a security vulnerability]() of a security vulnerability, please report it to us as described below. 8 | 9 | ## Reporting Security Issues 10 | 11 | **Please do not report security vulnerabilities through public GitHub issues.** 12 | 13 | Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://msrc.microsoft.com/create-report). 14 | 15 | If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the the [Microsoft Security Response Center PGP Key page](https://www.microsoft.com/en-us/msrc/pgp-key-msrc). 16 | 17 | You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://www.microsoft.com/msrc). 18 | 19 | Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue: 20 | 21 | - Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.) 22 | - Full paths of source file(s) related to the manifestation of the issue 23 | - The location of the affected source code (tag/branch/commit or direct URL) 24 | - Any special configuration required to reproduce the issue 25 | - Step-by-step instructions to reproduce the issue 26 | - Proof-of-concept or exploit code (if possible) 27 | - Impact of the issue, including how an attacker might exploit the issue 28 | 29 | This information will help us triage your report more quickly. 30 | 31 | If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://microsoft.com/msrc/bounty) page for more details about our active programs. 32 | 33 | ## Preferred Languages 34 | 35 | We prefer all communications to be in English. 36 | 37 | ## Policy 38 | 39 | Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://www.microsoft.com/en-us/msrc/cvd). 40 | 41 | 42 | -------------------------------------------------------------------------------- /demo.js: -------------------------------------------------------------------------------- 1 | /*--------------------------------------------------------- 2 | * Copyright (C) Microsoft Corporation. All rights reserved. 3 | *--------------------------------------------------------*/ 4 | 5 | // A simple demo proxy that just logs traffic going back and forth. 6 | 7 | const { Connection, Server, WebSocketTransport } = require('./'); 8 | 9 | (async () => { 10 | const server = await Server.create({ port: 8999}); 11 | 12 | server.onConnection(async ([toDebugger, req]) => { 13 | console.log('Got connection from debugger'); 14 | toDebugger.onError(err => console.error('Error on debugger transport', err)); 15 | toDebugger.pause(); // don't listen for events until the target is ready 16 | 17 | const url = new URL('http://localhost' + req.url); 18 | const browserInspectUri = url.searchParams.get('browser'); 19 | 20 | const toTarget = new Connection(await WebSocketTransport.create(browserInspectUri)); 21 | console.log('Connected to target'); 22 | toTarget.onError(err => console.error('Error on target transport', err)); 23 | 24 | // Copy commands (requests) from one pipe to the other. 25 | toTarget.onCommand(evt => { 26 | console.log(`target -> debugger`, evt); 27 | toDebugger.send(evt); 28 | }); 29 | toDebugger.onCommand(evt => { 30 | console.log(`debugger -> target`, evt); 31 | toTarget.send(evt); 32 | }); 33 | 34 | // Copy replies (responses) the same way 35 | toTarget.onReply(evt => { 36 | console.log(`target -> debugger`, evt); 37 | toDebugger.send(evt); 38 | }); 39 | toDebugger.onReply(evt => { 40 | console.log(`debugger -> target`, evt); 41 | toTarget.send(evt); 42 | }); 43 | 44 | // // dequeue any messages we got in the meantime 45 | toDebugger.unpause(); 46 | }); 47 | 48 | console.log('Server listening on port', server.address.port) 49 | })(); 50 | -------------------------------------------------------------------------------- /example.dot: -------------------------------------------------------------------------------- 1 | digraph G { 2 | U [label="User"]; 3 | F [label="Your Extension", shape=box]; 4 | T [label="Your Target", shape=box]; 5 | S [label="CDP Proxy", shape=box]; 6 | J [label="vscode-js-debug", shape=box]; 7 | 8 | { rank=same F S } 9 | 10 | U -> F [label="1. Start debugging"]; 11 | F -> S [label="2. Start this server"]; 12 | F -> J [label="3. vscode.debug.startDebugging"]; 13 | J -> S [label="4. Connect and speak CDP"]; 14 | S -> T [label="5. Debug target"] 15 | } 16 | 17 | // render via: dot -Tpng example.dot -o example.png 18 | -------------------------------------------------------------------------------- /example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/vscode-cdp-proxy/0d88aabe3f38a9c2b7d10611751ae74bb252912e/example.png -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vscode-cdp-proxy", 3 | "version": "0.2.1", 4 | "lockfileVersion": 3, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "vscode-cdp-proxy", 9 | "version": "0.2.1", 10 | "license": "MIT", 11 | "dependencies": { 12 | "cockatiel": "^2.0.2", 13 | "ws": "^8.2.3" 14 | }, 15 | "devDependencies": { 16 | "@types/chai": "^4.2.22", 17 | "@types/mocha": "^9.0.0", 18 | "@types/node": "^16.11.1", 19 | "@types/ws": "^8.2.0", 20 | "chai": "^4.3.4", 21 | "devtools-protocol": "0.0.932485", 22 | "mocha": "^11.1.0", 23 | "prettier": "^2.4.1", 24 | "rimraf": "^3.0.2", 25 | "typescript": "^4.4.4" 26 | } 27 | }, 28 | "node_modules/@isaacs/cliui": { 29 | "version": "8.0.2", 30 | "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", 31 | "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", 32 | "dev": true, 33 | "license": "ISC", 34 | "dependencies": { 35 | "string-width": "^5.1.2", 36 | "string-width-cjs": "npm:string-width@^4.2.0", 37 | "strip-ansi": "^7.0.1", 38 | "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", 39 | "wrap-ansi": "^8.1.0", 40 | "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" 41 | }, 42 | "engines": { 43 | "node": ">=12" 44 | } 45 | }, 46 | "node_modules/@isaacs/cliui/node_modules/ansi-regex": { 47 | "version": "6.1.0", 48 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", 49 | "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", 50 | "dev": true, 51 | "license": "MIT", 52 | "engines": { 53 | "node": ">=12" 54 | }, 55 | "funding": { 56 | "url": "https://github.com/chalk/ansi-regex?sponsor=1" 57 | } 58 | }, 59 | "node_modules/@isaacs/cliui/node_modules/ansi-styles": { 60 | "version": "6.2.1", 61 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", 62 | "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", 63 | "dev": true, 64 | "license": "MIT", 65 | "engines": { 66 | "node": ">=12" 67 | }, 68 | "funding": { 69 | "url": "https://github.com/chalk/ansi-styles?sponsor=1" 70 | } 71 | }, 72 | "node_modules/@isaacs/cliui/node_modules/emoji-regex": { 73 | "version": "9.2.2", 74 | "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", 75 | "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", 76 | "dev": true, 77 | "license": "MIT" 78 | }, 79 | "node_modules/@isaacs/cliui/node_modules/string-width": { 80 | "version": "5.1.2", 81 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", 82 | "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", 83 | "dev": true, 84 | "license": "MIT", 85 | "dependencies": { 86 | "eastasianwidth": "^0.2.0", 87 | "emoji-regex": "^9.2.2", 88 | "strip-ansi": "^7.0.1" 89 | }, 90 | "engines": { 91 | "node": ">=12" 92 | }, 93 | "funding": { 94 | "url": "https://github.com/sponsors/sindresorhus" 95 | } 96 | }, 97 | "node_modules/@isaacs/cliui/node_modules/strip-ansi": { 98 | "version": "7.1.0", 99 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", 100 | "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", 101 | "dev": true, 102 | "license": "MIT", 103 | "dependencies": { 104 | "ansi-regex": "^6.0.1" 105 | }, 106 | "engines": { 107 | "node": ">=12" 108 | }, 109 | "funding": { 110 | "url": "https://github.com/chalk/strip-ansi?sponsor=1" 111 | } 112 | }, 113 | "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { 114 | "version": "8.1.0", 115 | "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", 116 | "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", 117 | "dev": true, 118 | "license": "MIT", 119 | "dependencies": { 120 | "ansi-styles": "^6.1.0", 121 | "string-width": "^5.0.1", 122 | "strip-ansi": "^7.0.1" 123 | }, 124 | "engines": { 125 | "node": ">=12" 126 | }, 127 | "funding": { 128 | "url": "https://github.com/chalk/wrap-ansi?sponsor=1" 129 | } 130 | }, 131 | "node_modules/@pkgjs/parseargs": { 132 | "version": "0.11.0", 133 | "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", 134 | "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", 135 | "dev": true, 136 | "license": "MIT", 137 | "optional": true, 138 | "engines": { 139 | "node": ">=14" 140 | } 141 | }, 142 | "node_modules/@types/chai": { 143 | "version": "4.2.22", 144 | "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.2.22.tgz", 145 | "integrity": "sha512-tFfcE+DSTzWAgifkjik9AySNqIyNoYwmR+uecPwwD/XRNfvOjmC/FjCxpiUGDkDVDphPfCUecSQVFw+lN3M3kQ==", 146 | "dev": true, 147 | "license": "MIT" 148 | }, 149 | "node_modules/@types/mocha": { 150 | "version": "9.0.0", 151 | "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-9.0.0.tgz", 152 | "integrity": "sha512-scN0hAWyLVAvLR9AyW7HoFF5sJZglyBsbPuHO4fv7JRvfmPBMfp1ozWqOf/e4wwPNxezBZXRfWzMb6iFLgEVRA==", 153 | "dev": true, 154 | "license": "MIT" 155 | }, 156 | "node_modules/@types/node": { 157 | "version": "16.11.1", 158 | "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.1.tgz", 159 | "integrity": "sha512-PYGcJHL9mwl1Ek3PLiYgyEKtwTMmkMw4vbiyz/ps3pfdRYLVv+SN7qHVAImrjdAXxgluDEw6Ph4lyv+m9UpRmA==", 160 | "dev": true, 161 | "license": "MIT" 162 | }, 163 | "node_modules/@types/ws": { 164 | "version": "8.2.0", 165 | "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.2.0.tgz", 166 | "integrity": "sha512-cyeefcUCgJlEk+hk2h3N+MqKKsPViQgF5boi9TTHSK+PoR9KWBb/C5ccPcDyAqgsbAYHTwulch725DV84+pSpg==", 167 | "dev": true, 168 | "license": "MIT", 169 | "dependencies": { 170 | "@types/node": "*" 171 | } 172 | }, 173 | "node_modules/ansi-colors": { 174 | "version": "4.1.3", 175 | "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", 176 | "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", 177 | "dev": true, 178 | "license": "MIT", 179 | "engines": { 180 | "node": ">=6" 181 | } 182 | }, 183 | "node_modules/ansi-regex": { 184 | "version": "5.0.1", 185 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", 186 | "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", 187 | "dev": true, 188 | "license": "MIT", 189 | "engines": { 190 | "node": ">=8" 191 | } 192 | }, 193 | "node_modules/ansi-styles": { 194 | "version": "4.3.0", 195 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", 196 | "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", 197 | "dev": true, 198 | "license": "MIT", 199 | "dependencies": { 200 | "color-convert": "^2.0.1" 201 | }, 202 | "engines": { 203 | "node": ">=8" 204 | }, 205 | "funding": { 206 | "url": "https://github.com/chalk/ansi-styles?sponsor=1" 207 | } 208 | }, 209 | "node_modules/anymatch": { 210 | "version": "3.1.3", 211 | "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", 212 | "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", 213 | "dev": true, 214 | "license": "ISC", 215 | "dependencies": { 216 | "normalize-path": "^3.0.0", 217 | "picomatch": "^2.0.4" 218 | }, 219 | "engines": { 220 | "node": ">= 8" 221 | } 222 | }, 223 | "node_modules/argparse": { 224 | "version": "2.0.1", 225 | "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", 226 | "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", 227 | "dev": true, 228 | "license": "Python-2.0" 229 | }, 230 | "node_modules/assertion-error": { 231 | "version": "1.1.0", 232 | "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", 233 | "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", 234 | "dev": true, 235 | "license": "MIT", 236 | "engines": { 237 | "node": "*" 238 | } 239 | }, 240 | "node_modules/balanced-match": { 241 | "version": "1.0.0", 242 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", 243 | "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c= sha512-9Y0g0Q8rmSt+H33DfKv7FOc3v+iRI+o1lbzt8jGcIosYW37IIW/2XVYq5NPdmaD5NQ59Nk26Kl/vZbwW9Fr8vg==", 244 | "dev": true, 245 | "license": "MIT" 246 | }, 247 | "node_modules/binary-extensions": { 248 | "version": "2.3.0", 249 | "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", 250 | "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", 251 | "dev": true, 252 | "license": "MIT", 253 | "engines": { 254 | "node": ">=8" 255 | }, 256 | "funding": { 257 | "url": "https://github.com/sponsors/sindresorhus" 258 | } 259 | }, 260 | "node_modules/brace-expansion": { 261 | "version": "1.1.11", 262 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 263 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 264 | "dev": true, 265 | "license": "MIT", 266 | "dependencies": { 267 | "balanced-match": "^1.0.0", 268 | "concat-map": "0.0.1" 269 | } 270 | }, 271 | "node_modules/browser-stdout": { 272 | "version": "1.3.1", 273 | "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", 274 | "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", 275 | "dev": true, 276 | "license": "ISC" 277 | }, 278 | "node_modules/chai": { 279 | "version": "4.3.4", 280 | "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.4.tgz", 281 | "integrity": "sha512-yS5H68VYOCtN1cjfwumDSuzn/9c+yza4f3reKXlE5rUg7SFcCEy90gJvydNgOYtblyf4Zi6jIWRnXOgErta0KA==", 282 | "dev": true, 283 | "license": "MIT", 284 | "dependencies": { 285 | "assertion-error": "^1.1.0", 286 | "check-error": "^1.0.2", 287 | "deep-eql": "^3.0.1", 288 | "get-func-name": "^2.0.0", 289 | "pathval": "^1.1.1", 290 | "type-detect": "^4.0.5" 291 | }, 292 | "engines": { 293 | "node": ">=4" 294 | } 295 | }, 296 | "node_modules/chalk": { 297 | "version": "4.1.2", 298 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", 299 | "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", 300 | "dev": true, 301 | "license": "MIT", 302 | "dependencies": { 303 | "ansi-styles": "^4.1.0", 304 | "supports-color": "^7.1.0" 305 | }, 306 | "engines": { 307 | "node": ">=10" 308 | }, 309 | "funding": { 310 | "url": "https://github.com/chalk/chalk?sponsor=1" 311 | } 312 | }, 313 | "node_modules/chalk/node_modules/supports-color": { 314 | "version": "7.2.0", 315 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", 316 | "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", 317 | "dev": true, 318 | "license": "MIT", 319 | "dependencies": { 320 | "has-flag": "^4.0.0" 321 | }, 322 | "engines": { 323 | "node": ">=8" 324 | } 325 | }, 326 | "node_modules/check-error": { 327 | "version": "1.0.2", 328 | "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", 329 | "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII= sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA==", 330 | "dev": true, 331 | "license": "MIT", 332 | "engines": { 333 | "node": "*" 334 | } 335 | }, 336 | "node_modules/chokidar": { 337 | "version": "3.5.3", 338 | "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", 339 | "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", 340 | "dev": true, 341 | "funding": [ 342 | { 343 | "type": "individual", 344 | "url": "https://paulmillr.com/funding/" 345 | } 346 | ], 347 | "license": "MIT", 348 | "dependencies": { 349 | "anymatch": "~3.1.2", 350 | "braces": "~3.0.2", 351 | "glob-parent": "~5.1.2", 352 | "is-binary-path": "~2.1.0", 353 | "is-glob": "~4.0.1", 354 | "normalize-path": "~3.0.0", 355 | "readdirp": "~3.6.0" 356 | }, 357 | "engines": { 358 | "node": ">= 8.10.0" 359 | }, 360 | "optionalDependencies": { 361 | "fsevents": "~2.3.2" 362 | } 363 | }, 364 | "node_modules/chokidar/node_modules/braces": { 365 | "version": "3.0.3", 366 | "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", 367 | "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", 368 | "dev": true, 369 | "license": "MIT", 370 | "dependencies": { 371 | "fill-range": "^7.1.1" 372 | }, 373 | "engines": { 374 | "node": ">=8" 375 | } 376 | }, 377 | "node_modules/chokidar/node_modules/fill-range": { 378 | "version": "7.1.1", 379 | "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", 380 | "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", 381 | "dev": true, 382 | "license": "MIT", 383 | "dependencies": { 384 | "to-regex-range": "^5.0.1" 385 | }, 386 | "engines": { 387 | "node": ">=8" 388 | } 389 | }, 390 | "node_modules/chokidar/node_modules/glob-parent": { 391 | "version": "5.1.2", 392 | "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", 393 | "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", 394 | "dev": true, 395 | "license": "ISC", 396 | "dependencies": { 397 | "is-glob": "^4.0.1" 398 | }, 399 | "engines": { 400 | "node": ">= 6" 401 | } 402 | }, 403 | "node_modules/chokidar/node_modules/is-number": { 404 | "version": "7.0.0", 405 | "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", 406 | "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", 407 | "dev": true, 408 | "license": "MIT", 409 | "engines": { 410 | "node": ">=0.12.0" 411 | } 412 | }, 413 | "node_modules/chokidar/node_modules/to-regex-range": { 414 | "version": "5.0.1", 415 | "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", 416 | "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", 417 | "dev": true, 418 | "license": "MIT", 419 | "dependencies": { 420 | "is-number": "^7.0.0" 421 | }, 422 | "engines": { 423 | "node": ">=8.0" 424 | } 425 | }, 426 | "node_modules/cliui": { 427 | "version": "8.0.1", 428 | "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", 429 | "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", 430 | "dev": true, 431 | "license": "ISC", 432 | "dependencies": { 433 | "string-width": "^4.2.0", 434 | "strip-ansi": "^6.0.1", 435 | "wrap-ansi": "^7.0.0" 436 | }, 437 | "engines": { 438 | "node": ">=12" 439 | } 440 | }, 441 | "node_modules/cockatiel": { 442 | "version": "2.0.2", 443 | "resolved": "https://registry.npmjs.org/cockatiel/-/cockatiel-2.0.2.tgz", 444 | "integrity": "sha512-ehw7t3twohGiMTxARX0AcFiUxndXLhnIBWbnRnHtfde2jRywlPpPB/o3s9YSptXPj6tkOG0fzET4CUUx4GIpEg==", 445 | "license": "MIT", 446 | "engines": { 447 | "node": ">=10 <11 || >=12" 448 | } 449 | }, 450 | "node_modules/color-convert": { 451 | "version": "2.0.1", 452 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", 453 | "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", 454 | "dev": true, 455 | "license": "MIT", 456 | "dependencies": { 457 | "color-name": "~1.1.4" 458 | }, 459 | "engines": { 460 | "node": ">=7.0.0" 461 | } 462 | }, 463 | "node_modules/color-name": { 464 | "version": "1.1.4", 465 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", 466 | "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", 467 | "dev": true, 468 | "license": "MIT" 469 | }, 470 | "node_modules/concat-map": { 471 | "version": "0.0.1", 472 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 473 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", 474 | "dev": true, 475 | "license": "MIT" 476 | }, 477 | "node_modules/cross-spawn": { 478 | "version": "7.0.6", 479 | "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", 480 | "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", 481 | "dev": true, 482 | "license": "MIT", 483 | "dependencies": { 484 | "path-key": "^3.1.0", 485 | "shebang-command": "^2.0.0", 486 | "which": "^2.0.1" 487 | }, 488 | "engines": { 489 | "node": ">= 8" 490 | } 491 | }, 492 | "node_modules/debug": { 493 | "version": "4.4.0", 494 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", 495 | "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", 496 | "dev": true, 497 | "license": "MIT", 498 | "dependencies": { 499 | "ms": "^2.1.3" 500 | }, 501 | "engines": { 502 | "node": ">=6.0" 503 | }, 504 | "peerDependenciesMeta": { 505 | "supports-color": { 506 | "optional": true 507 | } 508 | } 509 | }, 510 | "node_modules/deep-eql": { 511 | "version": "3.0.1", 512 | "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", 513 | "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", 514 | "dev": true, 515 | "license": "MIT", 516 | "dependencies": { 517 | "type-detect": "^4.0.0" 518 | }, 519 | "engines": { 520 | "node": ">=0.12" 521 | } 522 | }, 523 | "node_modules/devtools-protocol": { 524 | "version": "0.0.932485", 525 | "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.932485.tgz", 526 | "integrity": "sha512-XnBHwvwRzlpsgpR7RHxjY5pd/JzoaKzmrsubEPyKbNM0GHBLebNtRdPFYknSUC9i6mrlIGNMAmaoCm1W8e8Bzw==", 527 | "dev": true, 528 | "license": "BSD-3-Clause" 529 | }, 530 | "node_modules/diff": { 531 | "version": "5.2.0", 532 | "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz", 533 | "integrity": "sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==", 534 | "dev": true, 535 | "license": "BSD-3-Clause", 536 | "engines": { 537 | "node": ">=0.3.1" 538 | } 539 | }, 540 | "node_modules/eastasianwidth": { 541 | "version": "0.2.0", 542 | "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", 543 | "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", 544 | "dev": true, 545 | "license": "MIT" 546 | }, 547 | "node_modules/emoji-regex": { 548 | "version": "8.0.0", 549 | "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", 550 | "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", 551 | "dev": true, 552 | "license": "MIT" 553 | }, 554 | "node_modules/escalade": { 555 | "version": "3.2.0", 556 | "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", 557 | "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", 558 | "dev": true, 559 | "license": "MIT", 560 | "engines": { 561 | "node": ">=6" 562 | } 563 | }, 564 | "node_modules/escape-string-regexp": { 565 | "version": "4.0.0", 566 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", 567 | "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", 568 | "dev": true, 569 | "license": "MIT", 570 | "engines": { 571 | "node": ">=10" 572 | }, 573 | "funding": { 574 | "url": "https://github.com/sponsors/sindresorhus" 575 | } 576 | }, 577 | "node_modules/find-up": { 578 | "version": "5.0.0", 579 | "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", 580 | "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", 581 | "dev": true, 582 | "license": "MIT", 583 | "dependencies": { 584 | "locate-path": "^6.0.0", 585 | "path-exists": "^4.0.0" 586 | }, 587 | "engines": { 588 | "node": ">=10" 589 | }, 590 | "funding": { 591 | "url": "https://github.com/sponsors/sindresorhus" 592 | } 593 | }, 594 | "node_modules/flat": { 595 | "version": "5.0.2", 596 | "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", 597 | "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", 598 | "dev": true, 599 | "license": "BSD-3-Clause", 600 | "bin": { 601 | "flat": "cli.js" 602 | } 603 | }, 604 | "node_modules/foreground-child": { 605 | "version": "3.3.0", 606 | "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz", 607 | "integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==", 608 | "dev": true, 609 | "license": "ISC", 610 | "dependencies": { 611 | "cross-spawn": "^7.0.0", 612 | "signal-exit": "^4.0.1" 613 | }, 614 | "engines": { 615 | "node": ">=14" 616 | }, 617 | "funding": { 618 | "url": "https://github.com/sponsors/isaacs" 619 | } 620 | }, 621 | "node_modules/fs.realpath": { 622 | "version": "1.0.0", 623 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 624 | "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8= sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", 625 | "dev": true, 626 | "license": "ISC" 627 | }, 628 | "node_modules/fsevents": { 629 | "version": "2.3.3", 630 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", 631 | "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", 632 | "dev": true, 633 | "hasInstallScript": true, 634 | "license": "MIT", 635 | "optional": true, 636 | "os": [ 637 | "darwin" 638 | ], 639 | "engines": { 640 | "node": "^8.16.0 || ^10.6.0 || >=11.0.0" 641 | } 642 | }, 643 | "node_modules/get-caller-file": { 644 | "version": "2.0.5", 645 | "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", 646 | "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", 647 | "dev": true, 648 | "license": "ISC", 649 | "engines": { 650 | "node": "6.* || 8.* || >= 10.*" 651 | } 652 | }, 653 | "node_modules/get-func-name": { 654 | "version": "2.0.2", 655 | "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", 656 | "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==", 657 | "dev": true, 658 | "license": "MIT", 659 | "engines": { 660 | "node": "*" 661 | } 662 | }, 663 | "node_modules/glob": { 664 | "version": "7.2.0", 665 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", 666 | "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", 667 | "deprecated": "Glob versions prior to v9 are no longer supported", 668 | "dev": true, 669 | "license": "ISC", 670 | "dependencies": { 671 | "fs.realpath": "^1.0.0", 672 | "inflight": "^1.0.4", 673 | "inherits": "2", 674 | "minimatch": "^3.0.4", 675 | "once": "^1.3.0", 676 | "path-is-absolute": "^1.0.0" 677 | }, 678 | "engines": { 679 | "node": "*" 680 | }, 681 | "funding": { 682 | "url": "https://github.com/sponsors/isaacs" 683 | } 684 | }, 685 | "node_modules/has-flag": { 686 | "version": "4.0.0", 687 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", 688 | "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", 689 | "dev": true, 690 | "license": "MIT", 691 | "engines": { 692 | "node": ">=8" 693 | } 694 | }, 695 | "node_modules/he": { 696 | "version": "1.2.0", 697 | "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", 698 | "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", 699 | "dev": true, 700 | "license": "MIT", 701 | "bin": { 702 | "he": "bin/he" 703 | } 704 | }, 705 | "node_modules/inflight": { 706 | "version": "1.0.6", 707 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 708 | "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", 709 | "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", 710 | "dev": true, 711 | "license": "ISC", 712 | "dependencies": { 713 | "once": "^1.3.0", 714 | "wrappy": "1" 715 | } 716 | }, 717 | "node_modules/inherits": { 718 | "version": "2.0.4", 719 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 720 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", 721 | "dev": true, 722 | "license": "ISC" 723 | }, 724 | "node_modules/is-binary-path": { 725 | "version": "2.1.0", 726 | "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", 727 | "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", 728 | "dev": true, 729 | "license": "MIT", 730 | "dependencies": { 731 | "binary-extensions": "^2.0.0" 732 | }, 733 | "engines": { 734 | "node": ">=8" 735 | } 736 | }, 737 | "node_modules/is-extglob": { 738 | "version": "2.1.1", 739 | "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", 740 | "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", 741 | "dev": true, 742 | "license": "MIT", 743 | "engines": { 744 | "node": ">=0.10.0" 745 | } 746 | }, 747 | "node_modules/is-fullwidth-code-point": { 748 | "version": "3.0.0", 749 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", 750 | "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", 751 | "dev": true, 752 | "license": "MIT", 753 | "engines": { 754 | "node": ">=8" 755 | } 756 | }, 757 | "node_modules/is-glob": { 758 | "version": "4.0.3", 759 | "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", 760 | "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", 761 | "dev": true, 762 | "license": "MIT", 763 | "dependencies": { 764 | "is-extglob": "^2.1.1" 765 | }, 766 | "engines": { 767 | "node": ">=0.10.0" 768 | } 769 | }, 770 | "node_modules/is-unicode-supported": { 771 | "version": "0.1.0", 772 | "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", 773 | "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", 774 | "dev": true, 775 | "license": "MIT", 776 | "engines": { 777 | "node": ">=10" 778 | }, 779 | "funding": { 780 | "url": "https://github.com/sponsors/sindresorhus" 781 | } 782 | }, 783 | "node_modules/isexe": { 784 | "version": "2.0.0", 785 | "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", 786 | "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", 787 | "dev": true, 788 | "license": "ISC" 789 | }, 790 | "node_modules/jackspeak": { 791 | "version": "3.4.3", 792 | "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", 793 | "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", 794 | "dev": true, 795 | "license": "BlueOak-1.0.0", 796 | "dependencies": { 797 | "@isaacs/cliui": "^8.0.2" 798 | }, 799 | "funding": { 800 | "url": "https://github.com/sponsors/isaacs" 801 | }, 802 | "optionalDependencies": { 803 | "@pkgjs/parseargs": "^0.11.0" 804 | } 805 | }, 806 | "node_modules/js-yaml": { 807 | "version": "4.1.0", 808 | "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", 809 | "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", 810 | "dev": true, 811 | "license": "MIT", 812 | "dependencies": { 813 | "argparse": "^2.0.1" 814 | }, 815 | "bin": { 816 | "js-yaml": "bin/js-yaml.js" 817 | } 818 | }, 819 | "node_modules/locate-path": { 820 | "version": "6.0.0", 821 | "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", 822 | "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", 823 | "dev": true, 824 | "license": "MIT", 825 | "dependencies": { 826 | "p-locate": "^5.0.0" 827 | }, 828 | "engines": { 829 | "node": ">=10" 830 | }, 831 | "funding": { 832 | "url": "https://github.com/sponsors/sindresorhus" 833 | } 834 | }, 835 | "node_modules/log-symbols": { 836 | "version": "4.1.0", 837 | "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", 838 | "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", 839 | "dev": true, 840 | "license": "MIT", 841 | "dependencies": { 842 | "chalk": "^4.1.0", 843 | "is-unicode-supported": "^0.1.0" 844 | }, 845 | "engines": { 846 | "node": ">=10" 847 | }, 848 | "funding": { 849 | "url": "https://github.com/sponsors/sindresorhus" 850 | } 851 | }, 852 | "node_modules/lru-cache": { 853 | "version": "10.4.3", 854 | "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", 855 | "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", 856 | "dev": true, 857 | "license": "ISC" 858 | }, 859 | "node_modules/minimatch": { 860 | "version": "3.1.2", 861 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", 862 | "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", 863 | "dev": true, 864 | "license": "ISC", 865 | "dependencies": { 866 | "brace-expansion": "^1.1.7" 867 | }, 868 | "engines": { 869 | "node": "*" 870 | } 871 | }, 872 | "node_modules/minipass": { 873 | "version": "7.1.2", 874 | "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", 875 | "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", 876 | "dev": true, 877 | "license": "ISC", 878 | "engines": { 879 | "node": ">=16 || 14 >=14.17" 880 | } 881 | }, 882 | "node_modules/mocha": { 883 | "version": "11.1.0", 884 | "resolved": "https://registry.npmjs.org/mocha/-/mocha-11.1.0.tgz", 885 | "integrity": "sha512-8uJR5RTC2NgpY3GrYcgpZrsEd9zKbPDpob1RezyR2upGHRQtHWofmzTMzTMSV6dru3tj5Ukt0+Vnq1qhFEEwAg==", 886 | "dev": true, 887 | "license": "MIT", 888 | "dependencies": { 889 | "ansi-colors": "^4.1.3", 890 | "browser-stdout": "^1.3.1", 891 | "chokidar": "^3.5.3", 892 | "debug": "^4.3.5", 893 | "diff": "^5.2.0", 894 | "escape-string-regexp": "^4.0.0", 895 | "find-up": "^5.0.0", 896 | "glob": "^10.4.5", 897 | "he": "^1.2.0", 898 | "js-yaml": "^4.1.0", 899 | "log-symbols": "^4.1.0", 900 | "minimatch": "^5.1.6", 901 | "ms": "^2.1.3", 902 | "serialize-javascript": "^6.0.2", 903 | "strip-json-comments": "^3.1.1", 904 | "supports-color": "^8.1.1", 905 | "workerpool": "^6.5.1", 906 | "yargs": "^17.7.2", 907 | "yargs-parser": "^21.1.1", 908 | "yargs-unparser": "^2.0.0" 909 | }, 910 | "bin": { 911 | "_mocha": "bin/_mocha", 912 | "mocha": "bin/mocha.js" 913 | }, 914 | "engines": { 915 | "node": "^18.18.0 || ^20.9.0 || >=21.1.0" 916 | } 917 | }, 918 | "node_modules/mocha/node_modules/brace-expansion": { 919 | "version": "2.0.1", 920 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", 921 | "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", 922 | "dev": true, 923 | "license": "MIT", 924 | "dependencies": { 925 | "balanced-match": "^1.0.0" 926 | } 927 | }, 928 | "node_modules/mocha/node_modules/glob": { 929 | "version": "10.4.5", 930 | "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", 931 | "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", 932 | "dev": true, 933 | "license": "ISC", 934 | "dependencies": { 935 | "foreground-child": "^3.1.0", 936 | "jackspeak": "^3.1.2", 937 | "minimatch": "^9.0.4", 938 | "minipass": "^7.1.2", 939 | "package-json-from-dist": "^1.0.0", 940 | "path-scurry": "^1.11.1" 941 | }, 942 | "bin": { 943 | "glob": "dist/esm/bin.mjs" 944 | }, 945 | "funding": { 946 | "url": "https://github.com/sponsors/isaacs" 947 | } 948 | }, 949 | "node_modules/mocha/node_modules/glob/node_modules/minimatch": { 950 | "version": "9.0.5", 951 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", 952 | "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", 953 | "dev": true, 954 | "license": "ISC", 955 | "dependencies": { 956 | "brace-expansion": "^2.0.1" 957 | }, 958 | "engines": { 959 | "node": ">=16 || 14 >=14.17" 960 | }, 961 | "funding": { 962 | "url": "https://github.com/sponsors/isaacs" 963 | } 964 | }, 965 | "node_modules/mocha/node_modules/minimatch": { 966 | "version": "5.1.6", 967 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", 968 | "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", 969 | "dev": true, 970 | "license": "ISC", 971 | "dependencies": { 972 | "brace-expansion": "^2.0.1" 973 | }, 974 | "engines": { 975 | "node": ">=10" 976 | } 977 | }, 978 | "node_modules/ms": { 979 | "version": "2.1.3", 980 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", 981 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", 982 | "dev": true, 983 | "license": "MIT" 984 | }, 985 | "node_modules/normalize-path": { 986 | "version": "3.0.0", 987 | "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", 988 | "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", 989 | "dev": true, 990 | "license": "MIT", 991 | "engines": { 992 | "node": ">=0.10.0" 993 | } 994 | }, 995 | "node_modules/once": { 996 | "version": "1.4.0", 997 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 998 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E= sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", 999 | "dev": true, 1000 | "license": "ISC", 1001 | "dependencies": { 1002 | "wrappy": "1" 1003 | } 1004 | }, 1005 | "node_modules/p-limit": { 1006 | "version": "3.1.0", 1007 | "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", 1008 | "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", 1009 | "dev": true, 1010 | "license": "MIT", 1011 | "dependencies": { 1012 | "yocto-queue": "^0.1.0" 1013 | }, 1014 | "engines": { 1015 | "node": ">=10" 1016 | }, 1017 | "funding": { 1018 | "url": "https://github.com/sponsors/sindresorhus" 1019 | } 1020 | }, 1021 | "node_modules/p-locate": { 1022 | "version": "5.0.0", 1023 | "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", 1024 | "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", 1025 | "dev": true, 1026 | "license": "MIT", 1027 | "dependencies": { 1028 | "p-limit": "^3.0.2" 1029 | }, 1030 | "engines": { 1031 | "node": ">=10" 1032 | }, 1033 | "funding": { 1034 | "url": "https://github.com/sponsors/sindresorhus" 1035 | } 1036 | }, 1037 | "node_modules/package-json-from-dist": { 1038 | "version": "1.0.1", 1039 | "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", 1040 | "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", 1041 | "dev": true, 1042 | "license": "BlueOak-1.0.0" 1043 | }, 1044 | "node_modules/path-exists": { 1045 | "version": "4.0.0", 1046 | "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", 1047 | "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", 1048 | "dev": true, 1049 | "license": "MIT", 1050 | "engines": { 1051 | "node": ">=8" 1052 | } 1053 | }, 1054 | "node_modules/path-is-absolute": { 1055 | "version": "1.0.1", 1056 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 1057 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18= sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", 1058 | "dev": true, 1059 | "license": "MIT", 1060 | "engines": { 1061 | "node": ">=0.10.0" 1062 | } 1063 | }, 1064 | "node_modules/path-key": { 1065 | "version": "3.1.1", 1066 | "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", 1067 | "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", 1068 | "dev": true, 1069 | "license": "MIT", 1070 | "engines": { 1071 | "node": ">=8" 1072 | } 1073 | }, 1074 | "node_modules/path-scurry": { 1075 | "version": "1.11.1", 1076 | "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", 1077 | "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", 1078 | "dev": true, 1079 | "license": "BlueOak-1.0.0", 1080 | "dependencies": { 1081 | "lru-cache": "^10.2.0", 1082 | "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" 1083 | }, 1084 | "engines": { 1085 | "node": ">=16 || 14 >=14.18" 1086 | }, 1087 | "funding": { 1088 | "url": "https://github.com/sponsors/isaacs" 1089 | } 1090 | }, 1091 | "node_modules/pathval": { 1092 | "version": "1.1.1", 1093 | "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", 1094 | "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", 1095 | "dev": true, 1096 | "license": "MIT", 1097 | "engines": { 1098 | "node": "*" 1099 | } 1100 | }, 1101 | "node_modules/picomatch": { 1102 | "version": "2.3.1", 1103 | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", 1104 | "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", 1105 | "dev": true, 1106 | "license": "MIT", 1107 | "engines": { 1108 | "node": ">=8.6" 1109 | }, 1110 | "funding": { 1111 | "url": "https://github.com/sponsors/jonschlinkert" 1112 | } 1113 | }, 1114 | "node_modules/prettier": { 1115 | "version": "2.4.1", 1116 | "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.4.1.tgz", 1117 | "integrity": "sha512-9fbDAXSBcc6Bs1mZrDYb3XKzDLm4EXXL9sC1LqKP5rZkT6KRr/rf9amVUcODVXgguK/isJz0d0hP72WeaKWsvA==", 1118 | "dev": true, 1119 | "license": "MIT", 1120 | "bin": { 1121 | "prettier": "bin-prettier.js" 1122 | }, 1123 | "engines": { 1124 | "node": ">=10.13.0" 1125 | } 1126 | }, 1127 | "node_modules/randombytes": { 1128 | "version": "2.1.0", 1129 | "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", 1130 | "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", 1131 | "dev": true, 1132 | "license": "MIT", 1133 | "dependencies": { 1134 | "safe-buffer": "^5.1.0" 1135 | } 1136 | }, 1137 | "node_modules/readdirp": { 1138 | "version": "3.6.0", 1139 | "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", 1140 | "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", 1141 | "dev": true, 1142 | "license": "MIT", 1143 | "dependencies": { 1144 | "picomatch": "^2.2.1" 1145 | }, 1146 | "engines": { 1147 | "node": ">=8.10.0" 1148 | } 1149 | }, 1150 | "node_modules/require-directory": { 1151 | "version": "2.1.1", 1152 | "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", 1153 | "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", 1154 | "dev": true, 1155 | "license": "MIT", 1156 | "engines": { 1157 | "node": ">=0.10.0" 1158 | } 1159 | }, 1160 | "node_modules/rimraf": { 1161 | "version": "3.0.2", 1162 | "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", 1163 | "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", 1164 | "deprecated": "Rimraf versions prior to v4 are no longer supported", 1165 | "dev": true, 1166 | "license": "ISC", 1167 | "dependencies": { 1168 | "glob": "^7.1.3" 1169 | }, 1170 | "bin": { 1171 | "rimraf": "bin.js" 1172 | }, 1173 | "funding": { 1174 | "url": "https://github.com/sponsors/isaacs" 1175 | } 1176 | }, 1177 | "node_modules/safe-buffer": { 1178 | "version": "5.2.1", 1179 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", 1180 | "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", 1181 | "dev": true, 1182 | "funding": [ 1183 | { 1184 | "type": "github", 1185 | "url": "https://github.com/sponsors/feross" 1186 | }, 1187 | { 1188 | "type": "patreon", 1189 | "url": "https://www.patreon.com/feross" 1190 | }, 1191 | { 1192 | "type": "consulting", 1193 | "url": "https://feross.org/support" 1194 | } 1195 | ], 1196 | "license": "MIT" 1197 | }, 1198 | "node_modules/serialize-javascript": { 1199 | "version": "6.0.2", 1200 | "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", 1201 | "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", 1202 | "dev": true, 1203 | "license": "BSD-3-Clause", 1204 | "dependencies": { 1205 | "randombytes": "^2.1.0" 1206 | } 1207 | }, 1208 | "node_modules/shebang-command": { 1209 | "version": "2.0.0", 1210 | "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", 1211 | "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", 1212 | "dev": true, 1213 | "license": "MIT", 1214 | "dependencies": { 1215 | "shebang-regex": "^3.0.0" 1216 | }, 1217 | "engines": { 1218 | "node": ">=8" 1219 | } 1220 | }, 1221 | "node_modules/shebang-regex": { 1222 | "version": "3.0.0", 1223 | "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", 1224 | "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", 1225 | "dev": true, 1226 | "license": "MIT", 1227 | "engines": { 1228 | "node": ">=8" 1229 | } 1230 | }, 1231 | "node_modules/signal-exit": { 1232 | "version": "4.1.0", 1233 | "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", 1234 | "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", 1235 | "dev": true, 1236 | "license": "ISC", 1237 | "engines": { 1238 | "node": ">=14" 1239 | }, 1240 | "funding": { 1241 | "url": "https://github.com/sponsors/isaacs" 1242 | } 1243 | }, 1244 | "node_modules/string-width": { 1245 | "version": "4.2.3", 1246 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", 1247 | "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", 1248 | "dev": true, 1249 | "license": "MIT", 1250 | "dependencies": { 1251 | "emoji-regex": "^8.0.0", 1252 | "is-fullwidth-code-point": "^3.0.0", 1253 | "strip-ansi": "^6.0.1" 1254 | }, 1255 | "engines": { 1256 | "node": ">=8" 1257 | } 1258 | }, 1259 | "node_modules/string-width-cjs": { 1260 | "name": "string-width", 1261 | "version": "4.2.3", 1262 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", 1263 | "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", 1264 | "dev": true, 1265 | "license": "MIT", 1266 | "dependencies": { 1267 | "emoji-regex": "^8.0.0", 1268 | "is-fullwidth-code-point": "^3.0.0", 1269 | "strip-ansi": "^6.0.1" 1270 | }, 1271 | "engines": { 1272 | "node": ">=8" 1273 | } 1274 | }, 1275 | "node_modules/strip-ansi": { 1276 | "version": "6.0.1", 1277 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", 1278 | "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", 1279 | "dev": true, 1280 | "license": "MIT", 1281 | "dependencies": { 1282 | "ansi-regex": "^5.0.1" 1283 | }, 1284 | "engines": { 1285 | "node": ">=8" 1286 | } 1287 | }, 1288 | "node_modules/strip-ansi-cjs": { 1289 | "name": "strip-ansi", 1290 | "version": "6.0.1", 1291 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", 1292 | "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", 1293 | "dev": true, 1294 | "license": "MIT", 1295 | "dependencies": { 1296 | "ansi-regex": "^5.0.1" 1297 | }, 1298 | "engines": { 1299 | "node": ">=8" 1300 | } 1301 | }, 1302 | "node_modules/strip-json-comments": { 1303 | "version": "3.1.1", 1304 | "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", 1305 | "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", 1306 | "dev": true, 1307 | "license": "MIT", 1308 | "engines": { 1309 | "node": ">=8" 1310 | }, 1311 | "funding": { 1312 | "url": "https://github.com/sponsors/sindresorhus" 1313 | } 1314 | }, 1315 | "node_modules/supports-color": { 1316 | "version": "8.1.1", 1317 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", 1318 | "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", 1319 | "dev": true, 1320 | "license": "MIT", 1321 | "dependencies": { 1322 | "has-flag": "^4.0.0" 1323 | }, 1324 | "engines": { 1325 | "node": ">=10" 1326 | }, 1327 | "funding": { 1328 | "url": "https://github.com/chalk/supports-color?sponsor=1" 1329 | } 1330 | }, 1331 | "node_modules/type-detect": { 1332 | "version": "4.0.8", 1333 | "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", 1334 | "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", 1335 | "dev": true, 1336 | "license": "MIT", 1337 | "engines": { 1338 | "node": ">=4" 1339 | } 1340 | }, 1341 | "node_modules/typescript": { 1342 | "version": "4.4.4", 1343 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.4.4.tgz", 1344 | "integrity": "sha512-DqGhF5IKoBl8WNf8C1gu8q0xZSInh9j1kJJMqT3a94w1JzVaBU4EXOSMrz9yDqMT0xt3selp83fuFMQ0uzv6qA==", 1345 | "dev": true, 1346 | "license": "Apache-2.0", 1347 | "bin": { 1348 | "tsc": "bin/tsc", 1349 | "tsserver": "bin/tsserver" 1350 | }, 1351 | "engines": { 1352 | "node": ">=4.2.0" 1353 | } 1354 | }, 1355 | "node_modules/which": { 1356 | "version": "2.0.2", 1357 | "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", 1358 | "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", 1359 | "dev": true, 1360 | "license": "ISC", 1361 | "dependencies": { 1362 | "isexe": "^2.0.0" 1363 | }, 1364 | "bin": { 1365 | "node-which": "bin/node-which" 1366 | }, 1367 | "engines": { 1368 | "node": ">= 8" 1369 | } 1370 | }, 1371 | "node_modules/workerpool": { 1372 | "version": "6.5.1", 1373 | "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.5.1.tgz", 1374 | "integrity": "sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA==", 1375 | "dev": true, 1376 | "license": "Apache-2.0" 1377 | }, 1378 | "node_modules/wrap-ansi": { 1379 | "version": "7.0.0", 1380 | "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", 1381 | "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", 1382 | "dev": true, 1383 | "license": "MIT", 1384 | "dependencies": { 1385 | "ansi-styles": "^4.0.0", 1386 | "string-width": "^4.1.0", 1387 | "strip-ansi": "^6.0.0" 1388 | }, 1389 | "engines": { 1390 | "node": ">=10" 1391 | }, 1392 | "funding": { 1393 | "url": "https://github.com/chalk/wrap-ansi?sponsor=1" 1394 | } 1395 | }, 1396 | "node_modules/wrap-ansi-cjs": { 1397 | "name": "wrap-ansi", 1398 | "version": "7.0.0", 1399 | "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", 1400 | "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", 1401 | "dev": true, 1402 | "license": "MIT", 1403 | "dependencies": { 1404 | "ansi-styles": "^4.0.0", 1405 | "string-width": "^4.1.0", 1406 | "strip-ansi": "^6.0.0" 1407 | }, 1408 | "engines": { 1409 | "node": ">=10" 1410 | }, 1411 | "funding": { 1412 | "url": "https://github.com/chalk/wrap-ansi?sponsor=1" 1413 | } 1414 | }, 1415 | "node_modules/wrappy": { 1416 | "version": "1.0.2", 1417 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 1418 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", 1419 | "dev": true, 1420 | "license": "ISC" 1421 | }, 1422 | "node_modules/ws": { 1423 | "version": "8.17.1", 1424 | "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", 1425 | "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", 1426 | "license": "MIT", 1427 | "engines": { 1428 | "node": ">=10.0.0" 1429 | }, 1430 | "peerDependencies": { 1431 | "bufferutil": "^4.0.1", 1432 | "utf-8-validate": ">=5.0.2" 1433 | }, 1434 | "peerDependenciesMeta": { 1435 | "bufferutil": { 1436 | "optional": true 1437 | }, 1438 | "utf-8-validate": { 1439 | "optional": true 1440 | } 1441 | } 1442 | }, 1443 | "node_modules/y18n": { 1444 | "version": "5.0.8", 1445 | "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", 1446 | "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", 1447 | "dev": true, 1448 | "license": "ISC", 1449 | "engines": { 1450 | "node": ">=10" 1451 | } 1452 | }, 1453 | "node_modules/yargs": { 1454 | "version": "17.7.2", 1455 | "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", 1456 | "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", 1457 | "dev": true, 1458 | "license": "MIT", 1459 | "dependencies": { 1460 | "cliui": "^8.0.1", 1461 | "escalade": "^3.1.1", 1462 | "get-caller-file": "^2.0.5", 1463 | "require-directory": "^2.1.1", 1464 | "string-width": "^4.2.3", 1465 | "y18n": "^5.0.5", 1466 | "yargs-parser": "^21.1.1" 1467 | }, 1468 | "engines": { 1469 | "node": ">=12" 1470 | } 1471 | }, 1472 | "node_modules/yargs-parser": { 1473 | "version": "21.1.1", 1474 | "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", 1475 | "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", 1476 | "dev": true, 1477 | "license": "ISC", 1478 | "engines": { 1479 | "node": ">=12" 1480 | } 1481 | }, 1482 | "node_modules/yargs-unparser": { 1483 | "version": "2.0.0", 1484 | "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", 1485 | "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", 1486 | "dev": true, 1487 | "license": "MIT", 1488 | "dependencies": { 1489 | "camelcase": "^6.0.0", 1490 | "decamelize": "^4.0.0", 1491 | "flat": "^5.0.2", 1492 | "is-plain-obj": "^2.1.0" 1493 | }, 1494 | "engines": { 1495 | "node": ">=10" 1496 | } 1497 | }, 1498 | "node_modules/yargs-unparser/node_modules/camelcase": { 1499 | "version": "6.2.0", 1500 | "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.0.tgz", 1501 | "integrity": "sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==", 1502 | "dev": true, 1503 | "license": "MIT", 1504 | "engines": { 1505 | "node": ">=10" 1506 | }, 1507 | "funding": { 1508 | "url": "https://github.com/sponsors/sindresorhus" 1509 | } 1510 | }, 1511 | "node_modules/yargs-unparser/node_modules/decamelize": { 1512 | "version": "4.0.0", 1513 | "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", 1514 | "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", 1515 | "dev": true, 1516 | "license": "MIT", 1517 | "engines": { 1518 | "node": ">=10" 1519 | }, 1520 | "funding": { 1521 | "url": "https://github.com/sponsors/sindresorhus" 1522 | } 1523 | }, 1524 | "node_modules/yargs-unparser/node_modules/is-plain-obj": { 1525 | "version": "2.1.0", 1526 | "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", 1527 | "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", 1528 | "dev": true, 1529 | "license": "MIT", 1530 | "engines": { 1531 | "node": ">=8" 1532 | } 1533 | }, 1534 | "node_modules/yocto-queue": { 1535 | "version": "0.1.0", 1536 | "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", 1537 | "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", 1538 | "dev": true, 1539 | "license": "MIT", 1540 | "engines": { 1541 | "node": ">=10" 1542 | }, 1543 | "funding": { 1544 | "url": "https://github.com/sponsors/sindresorhus" 1545 | } 1546 | } 1547 | } 1548 | } 1549 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vscode-cdp-proxy", 3 | "version": "0.2.1", 4 | "description": "Sample Chrome Debug Protocol proxy used to extend vscode-js-debug", 5 | "main": "dist/index.js", 6 | "scripts": { 7 | "prepublishOnly": "npm run compile", 8 | "test": "rimraf dist && tsc && npm run test:unit npm run test:fmt", 9 | "test:unit": "mocha --opts mocha.opts", 10 | "test:fmt": "prettier --list-different \"src/**/*.ts\" \"*.md\"", 11 | "fmt": "prettier --write \"src/**/*.ts\" \"*.md\"", 12 | "compile": "rimraf dist && tsc && cpy src/cdp.d.ts dist", 13 | "watch": "rimraf dist && tsc --watch" 14 | }, 15 | "repository": { 16 | "type": "git", 17 | "url": "git+https://github.com/microsoft/vscode-cdp-proxy.git" 18 | }, 19 | "author": "Connor Peet ", 20 | "license": "MIT", 21 | "bugs": { 22 | "url": "https://github.com/microsoft/vscode-cdp-proxy/issues" 23 | }, 24 | "prettier": { 25 | "trailingComma": "all", 26 | "singleQuote": true, 27 | "printWidth": 100, 28 | "tabWidth": 2 29 | }, 30 | "homepage": "https://github.com/microsoft/vscode-cdp-proxy#readme", 31 | "devDependencies": { 32 | "@types/chai": "^4.2.22", 33 | "@types/mocha": "^9.0.0", 34 | "@types/node": "^16.11.1", 35 | "@types/ws": "^8.2.0", 36 | "chai": "^4.3.4", 37 | "devtools-protocol": "0.0.932485", 38 | "mocha": "^11.1.0", 39 | "prettier": "^2.4.1", 40 | "rimraf": "^3.0.2", 41 | "typescript": "^4.4.4" 42 | }, 43 | "dependencies": { 44 | "cockatiel": "^2.0.2", 45 | "ws": "^8.2.3" 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/cdp-error.ts: -------------------------------------------------------------------------------- 1 | /*--------------------------------------------------------- 2 | * Copyright (C) Microsoft Corporation. All rights reserved. 3 | *--------------------------------------------------------*/ 4 | 5 | import { IProtocolError } from './connection'; 6 | 7 | export class CdpError extends Error { 8 | constructor(public readonly cause: IProtocolError) { 9 | super(cause.error.message); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/connection.ts: -------------------------------------------------------------------------------- 1 | /*--------------------------------------------------------- 2 | * Copyright (C) Microsoft Corporation. All rights reserved. 3 | *--------------------------------------------------------*/ 4 | 5 | import { ITransport } from './transports/transports'; 6 | import Cdp from './cdp'; 7 | import { EventEmitter as NodeEmitter } from 'events'; 8 | import { CdpError } from './cdp-error'; 9 | import { TaskCancelledError, EventEmitter } from 'cockatiel'; 10 | 11 | export interface IProtocolCommand { 12 | id?: number; 13 | method: string; 14 | params: object; 15 | sessionId?: string; 16 | } 17 | 18 | export interface IProtocolError { 19 | id: number; 20 | method?: string; 21 | error: { code: number; message: string }; 22 | sessionId?: string; 23 | } 24 | 25 | export interface IProtocolSuccess { 26 | id: number; 27 | result: object; 28 | sessionId?: string; 29 | } 30 | 31 | type ProtocolMessage = IProtocolCommand | IProtocolSuccess | IProtocolError; 32 | 33 | interface IDeferred { 34 | resolve(data: T): void; 35 | reject(err: Error): void; 36 | } 37 | 38 | /** 39 | * The Connection provides a high-level wrapper for the underlying Transport. 40 | */ 41 | export class Connection { 42 | /** 43 | * Gets the API used to talk to CDP. 44 | */ 45 | public readonly api = new Proxy({} as any, { 46 | get: (target, domain: string) => (target[domain] = target[domain] ?? this.createDomain(domain)), 47 | }) as Cdp.Api; 48 | 49 | private lastId = 0; 50 | private pauseQueue?: ProtocolMessage[]; 51 | private readonly callbacks = new Map>(); 52 | private readonly innerEmitter = new NodeEmitter(); 53 | private readonly commandEmitter = new EventEmitter(); 54 | private readonly replyEmitter = new EventEmitter(); 55 | 56 | /** 57 | * Emitter that fires if an error happens on the underlying transport. 58 | */ 59 | public readonly onError = this.transport.onError; 60 | 61 | /** 62 | * Emitter that fires when the underlying connection is closed. 63 | */ 64 | public readonly onEnd = this.transport.onEnd; 65 | 66 | /** 67 | * Emitter that fires when any command is received, on addition to any 68 | * listener set up through the `.api`. 69 | */ 70 | public readonly onCommand = this.commandEmitter.addListener; 71 | 72 | /** 73 | * Emitter that fires when any command reply is received. 74 | */ 75 | public readonly onReply = this.replyEmitter.addListener; 76 | 77 | constructor(private readonly transport: ITransport) { 78 | transport.onMessage((msg) => this.processResponse(msg as ProtocolMessage)); 79 | } 80 | 81 | /** 82 | * Pauses receiving events, queuing them until unpause is called. 83 | */ 84 | public pause() { 85 | this.pauseQueue = this.pauseQueue || []; 86 | } 87 | 88 | /** 89 | * Unpauses the event queue, firing any ones that have built up. 90 | */ 91 | public unpause() { 92 | console.log('process', this.pauseQueue); 93 | if (!this.pauseQueue) { 94 | return; 95 | } 96 | 97 | const queue = this.pauseQueue; 98 | this.pauseQueue = undefined; 99 | 100 | for (const item of queue) { 101 | this.processResponse(item); 102 | } 103 | } 104 | 105 | /** 106 | * Returns a new unique ID for a message, incrementing the internal ID counter. 107 | */ 108 | public getId() { 109 | return this.lastId++; 110 | } 111 | 112 | /** 113 | * Low-level send command. 114 | */ 115 | public send(message: ProtocolMessage) { 116 | this.transport.send(message); 117 | } 118 | 119 | /** 120 | * Makes a call to the given method over CDP. Note that you should generally 121 | * use `.api` for a better, typed interface to this. 122 | */ 123 | public call(method: string, params: object): Promise { 124 | const id = this.lastId++; 125 | const message: IProtocolCommand = { id, method, params }; 126 | this.transport.send(message); 127 | 128 | return new Promise((resolve, reject) => { 129 | this.callbacks.set(id, { resolve, reject }); 130 | }); 131 | } 132 | 133 | /** 134 | * Closes the underlying transport. Cancels any outstanding callbacks. 135 | */ 136 | public async close() { 137 | await this.transport.close(); 138 | for (const { reject } of this.callbacks.values()) { 139 | reject(new TaskCancelledError('CDP connection closed')); 140 | } 141 | 142 | this.callbacks.clear(); 143 | } 144 | 145 | private createDomain(domain: string) { 146 | return new Proxy( 147 | {}, 148 | { 149 | get: (_target, method: string) => { 150 | if (method === 'on') { 151 | return (eventName: string, listener: (params: object) => void) => { 152 | const evt = `${domain}.${eventName}`; 153 | this.innerEmitter.on(evt, listener); 154 | return () => this.innerEmitter.off(evt, listener); 155 | }; 156 | } 157 | 158 | return (params: object) => this.call(`${domain}.${method}`, params); 159 | }, 160 | }, 161 | ); 162 | } 163 | 164 | private processResponse(message: ProtocolMessage) { 165 | if (this.pauseQueue) { 166 | this.pauseQueue.push(message); 167 | } 168 | 169 | if (message.id === undefined) { 170 | // for some reason, TS doesn't narrow this even though IProtocolCommand 171 | // is the only type of the tuple where id can be undefined. 172 | const asCommand = message as IProtocolCommand; 173 | this.commandEmitter.emit(asCommand); 174 | this.innerEmitter.emit(asCommand.method, asCommand.params); 175 | return; 176 | } 177 | 178 | this.replyEmitter.emit(message as IProtocolError | IProtocolSuccess); 179 | const callback = this.callbacks.get(message.id); 180 | if (!callback) { 181 | return; 182 | } 183 | 184 | this.callbacks.delete(message.id); 185 | if ('error' in message) { 186 | callback.reject(new CdpError(message)); 187 | } else if ('result' in message) { 188 | callback.resolve(message.result); 189 | } 190 | } 191 | } 192 | -------------------------------------------------------------------------------- /src/disposable.ts: -------------------------------------------------------------------------------- 1 | /*--------------------------------------------------------- 2 | * Copyright (C) Microsoft Corporation. All rights reserved. 3 | *--------------------------------------------------------*/ 4 | 5 | export interface IDisposable { 6 | dispose(): void; 7 | } 8 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | /*--------------------------------------------------------- 2 | * Copyright (C) Microsoft Corporation. All rights reserved. 3 | *--------------------------------------------------------*/ 4 | 5 | export * from './server'; 6 | export * from './disposable'; 7 | export * from './connection'; 8 | export * from './cdp'; 9 | export * from './cdp-error'; 10 | export * from './transports/transports'; 11 | export * from './transports/websocket'; 12 | -------------------------------------------------------------------------------- /src/server.ts: -------------------------------------------------------------------------------- 1 | /*--------------------------------------------------------- 2 | * Copyright (C) Microsoft Corporation. All rights reserved. 3 | *--------------------------------------------------------*/ 4 | 5 | import { Server as WebSocketServer, ServerOptions } from 'ws'; 6 | import { EventEmitter } from 'cockatiel'; 7 | import { Connection } from './connection'; 8 | import { WebSocketTransport } from './transports/websocket'; 9 | import { IDisposable } from './disposable'; 10 | import { Server as HttpServer, createServer, IncomingMessage } from 'http'; 11 | import { AddressInfo } from 'net'; 12 | 13 | export interface IServerOptions { 14 | host: string; 15 | port: string; 16 | } 17 | 18 | /** 19 | * WebSocket server used to set up a CDP proxy. 20 | */ 21 | export class Server implements IDisposable { 22 | /** 23 | * Creates a new server, returning a promise that's resolved when it's opened. 24 | */ 25 | public static async create(options: Partial = {}) { 26 | const { host = '127.0.0.1', port = 0 } = options; 27 | 28 | const server = createServer((_req, res) => { 29 | // The adapter makes an http call to discover the address to connect 30 | // to first. Mock that out here. 31 | const resolvedPort = port || (server.address() as AddressInfo).port; 32 | res.write( 33 | JSON.stringify({ 34 | webSocketDebuggerUrl: `ws://${host}:${resolvedPort}/ws`, 35 | }), 36 | ); 37 | res.end(); 38 | }); 39 | 40 | const wss = new WebSocketServer({ server }); 41 | server.listen(port); 42 | 43 | return new Server(wss, server); 44 | } 45 | 46 | private readonly connectionEmitter = new EventEmitter<[Connection, IncomingMessage]>(); 47 | 48 | /** 49 | * Emitter that fires when we get a new connection over CDP. 50 | */ 51 | public readonly onConnection = this.connectionEmitter.addListener; 52 | 53 | /** 54 | * Address the server is listening on. 55 | */ 56 | public readonly address = this.httpServer.address() as AddressInfo; 57 | 58 | protected constructor( 59 | private readonly wss: WebSocketServer, 60 | private readonly httpServer: HttpServer, 61 | ) { 62 | wss.on('connection', (ws, req) => { 63 | this.connectionEmitter.emit([new Connection(new WebSocketTransport(ws)), req]); 64 | }); 65 | } 66 | 67 | /** 68 | * @inheritdoc 69 | */ 70 | public dispose() { 71 | this.wss.close(); 72 | this.httpServer.close(); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/transports/transports.ts: -------------------------------------------------------------------------------- 1 | /*--------------------------------------------------------- 2 | * Copyright (C) Microsoft Corporation. All rights reserved. 3 | *--------------------------------------------------------*/ 4 | 5 | import { Event } from 'cockatiel'; 6 | 7 | export interface ITransport { 8 | /** 9 | * Sends the given message. 10 | */ 11 | send(message: object): void; 12 | 13 | /** 14 | * Closees the transport, returning a promise that returns once it's done. 15 | */ 16 | close(): Promise; 17 | 18 | /** 19 | * Emitter that fires if there's an error with the underlying transport. 20 | */ 21 | onError: Event; 22 | 23 | /** 24 | * Emitter that fires when a new message comes in. 25 | */ 26 | onMessage: Event; 27 | 28 | /** 29 | * Emitter that fires when the underlying transport closes 30 | */ 31 | onEnd: Event; 32 | } 33 | -------------------------------------------------------------------------------- /src/transports/websocket.ts: -------------------------------------------------------------------------------- 1 | /*--------------------------------------------------------- 2 | * Copyright (C) Microsoft Corporation. All rights reserved. 3 | *--------------------------------------------------------*/ 4 | 5 | import * as WebSocket from 'ws'; 6 | import { ITransport } from './transports'; 7 | import { CancellationToken, TaskCancelledError, EventEmitter } from 'cockatiel'; 8 | 9 | export class WebSocketError extends Error { 10 | constructor(public readonly cause: WebSocket.ErrorEvent) { 11 | super(cause.message); 12 | } 13 | } 14 | 15 | /** 16 | * A WebSocket-based transports. Can connect to a URL via 17 | * {@link WebSocketTransport.create} or be created from a {@link WebSocket} 18 | * received by other means. 19 | */ 20 | export class WebSocketTransport implements ITransport { 21 | private ws: WebSocket | undefined; 22 | private endEmitter = new EventEmitter(); 23 | private messageEmitter = new EventEmitter(); 24 | private errorEmitter = new EventEmitter(); 25 | 26 | /** 27 | * @inheritdoc 28 | */ 29 | public onMessage = this.messageEmitter.addListener; 30 | 31 | /** 32 | * @inheritdoc 33 | */ 34 | public onError = this.errorEmitter.addListener; 35 | 36 | /** 37 | * @inheritdoc 38 | */ 39 | public onEnd = this.endEmitter.addListener; 40 | 41 | /** 42 | * Creates a new websocket transport connecting to the given URL. 43 | */ 44 | public static async create( 45 | url: string, 46 | cancellationToken: CancellationToken = CancellationToken.None, 47 | ): Promise { 48 | const ws = new WebSocket(url, [], { 49 | perMessageDeflate: false, 50 | maxPayload: 256 * 1024 * 1024, // 256Mb 51 | }); 52 | 53 | return await new Promise((resolve, reject) => { 54 | const onCancel = cancellationToken.onCancellationRequested(() => { 55 | ws.close(); 56 | reject(new TaskCancelledError()); 57 | }); 58 | 59 | ws.addEventListener('open', () => { 60 | resolve(new WebSocketTransport(ws)); 61 | onCancel.dispose(); 62 | }); 63 | ws.addEventListener('error', () => { 64 | reject(); 65 | onCancel.dispose(); 66 | }); 67 | }); 68 | } 69 | 70 | constructor(ws: WebSocket) { 71 | this.ws = ws; 72 | this.ws.addEventListener('message', (event) => { 73 | this.messageEmitter.emit(JSON.parse(event.data as string)); 74 | }); 75 | 76 | this.ws.addEventListener('close', () => { 77 | this.endEmitter.emit(); 78 | }); 79 | 80 | this.ws.addEventListener('error', (error) => { 81 | this.errorEmitter.emit(new WebSocketError(error)); 82 | }); 83 | } 84 | 85 | /** 86 | * @inheritdoc 87 | */ 88 | public send(message: object) { 89 | this.ws?.send(JSON.stringify(message)); 90 | } 91 | 92 | /** 93 | * @inheritdoc 94 | */ 95 | public async close(): Promise { 96 | if (!this.ws) { 97 | return; 98 | } 99 | 100 | let callback: () => void; 101 | const result = new Promise((f) => (callback = f)); 102 | this.ws.addEventListener('close', () => callback()); 103 | this.ws.close(); 104 | this.ws = undefined; 105 | 106 | return result; 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "forceConsistentCasingInFileNames": true, 4 | "experimentalDecorators": true, 5 | "sourceMap": true, 6 | "declaration": true, 7 | "noImplicitReturns": true, 8 | "noUnusedLocals": true, 9 | "noUnusedParameters": true, 10 | "strict": true, 11 | "moduleResolution": "node", 12 | "newLine": "LF", 13 | "module": "commonjs", 14 | "target": "es2016", 15 | "lib": ["es6", "es7"], 16 | "outDir": "dist", 17 | "types": [ 18 | "node", 19 | ] 20 | } 21 | } 22 | --------------------------------------------------------------------------------