├── .gitignore ├── .npmignore ├── LICENSE ├── README.md ├── SECURITY.md ├── buildpackage.js ├── package-lock.json ├── package.json ├── rollup.config.js ├── src ├── SDK.ts └── XDM.ts ├── tsconfig.amd.json ├── tsconfig.esm.json └── tsconfig.json /.gitignore: -------------------------------------------------------------------------------- 1 | npm-debug.log 2 | node_modules/ 3 | bin/ -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | npm-debug.log 2 | 3 | rollup.config.js 4 | buildpackage.js 5 | tsconfig*.json 6 | 7 | src -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Microsoft Corporation. All rights reserved. 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 | # Azure DevOps Web Extension SDK 2 | 3 | ## Report issues 4 | Report issues or make suggestions via the Developer Community portal: 5 | 6 | https://developercommunity.visualstudio.com/AzureDevOps 7 | 8 | ## Release Notes 9 | New major version, v`4.*.*` provides multiple module support to the SDK. 10 | 11 | ### Details 12 | 13 | - **ES Module Support**: SDK now supports ES (ECMAScript) modules in addition to the existing AMD (Asynchronous Module Definition) modules. You can now import SDK using the ES module syntax, which provides performance improvements and reduces the application size. 14 | 15 | - **Backward Compatibility for AMD Modules**: Existing support for AMD modules remains intact. If your project is using AMD modules, you can continue to use them as before without any changes. 16 | 17 | ### How to Use 18 | 19 | If you're using AMD modules, you can continue to import SDK using the `require` function: 20 | 21 | ```javascript 22 | require(['azure-devops-extension-sdk'], function(SDK) { 23 | // Use the module here 24 | }); 25 | ``` 26 | 27 | For ES modules, you can import our modules using the `import` statement: 28 | 29 | ```javascript 30 | import * as SDK from 'azure-devops-extension-sdk'; 31 | // Use the module here 32 | ``` 33 | 34 | ## Get started with a new extension 35 | 36 | See the [Develop a web extension for Azure DevOps](https://docs.microsoft.com/en-us/azure/devops/extend/get-started/node?view=vsts) documentation for instructions on getting started with a new extension. You can also refer to the [azure-devops-extension-sample](https://github.com/Microsoft/azure-devops-extension-sample) repository as a working reference. 37 | 38 | ## Overview 39 | 40 | Client SDK for developing [Azure DevOps extensions](https://docs.microsoft.com/en-us/azure/devops/extend/overview). 41 | 42 | The client SDK enables web extensions to communicate to the host frame. It can be used to: 43 | 44 | - Notify the host that the extension is loaded or has errors 45 | - Get basic contextual information about the current page (current user, host and extension information) 46 | - Get theme information 47 | - Obtain an authorization token to use in REST calls back to Azure DevOps 48 | - Get remote services offered by the host frame 49 | 50 | A full API reference of can be found [here](https://docs.microsoft.com/en-us/javascript/api/azure-devops-extension-sdk/). 51 | 52 | ## Get started with a new extension 53 | 54 | See the [Develop a web extension for Azure DevOps](https://docs.microsoft.com/en-us/azure/devops/extend/get-started/node?view=vsts) documentation for instructions on getting started with a new extension. You can also refer to the [azure-devops-extension-sample](https://github.com/Microsoft/azure-devops-extension-sample) repository as a working reference. 55 | 56 | ## Import the SDK within your extension project 57 | 58 | 1. Add `azure-devops-extension-sdk` to the list of dependencies in your package.json 59 | 2. Add `import * as SDK from "azure-devops-extension-sdk"` to your TypeScript code 60 | 61 | ## Initialize the SDK 62 | 63 | When you have rendered your extension content, call `SDK.init()`. Your extension content will not be displayed until you have notified the host frame that you are ready. There are two options for doing this: 64 | 65 | 1. Call `SDK.init()` with no `loaded` option 66 | 2. Call `SDK.init({ loaded: false })` to start initializing the SDK. Then call `SDK.notifyLoadSucceeded()` once you have finished your initial rendering. This allows you to make other SDK calls while your content is still loading (and hidden behind a spinner). 67 | 68 | Example: 69 | 70 | ```typescript 71 | import * as SDK from "azure-devops-extension-sdk"; 72 | 73 | SDK.init(); 74 | ``` 75 | 76 | ## API 77 | A full API reference of can be found [here](https://docs.microsoft.com/en-us/javascript/api/azure-devops-extension-sdk/). 78 | 79 | 80 | ## Code of Conduct 81 | 82 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. 83 | -------------------------------------------------------------------------------- /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 definition of a security vulnerability](https://aka.ms/opensource/security/definition), 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://aka.ms/opensource/security/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 [Microsoft Security Response Center PGP Key page](https://aka.ms/opensource/security/pgpkey). 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://aka.ms/opensource/security/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://aka.ms/opensource/security/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://aka.ms/opensource/security/cvd). 40 | 41 | 42 | -------------------------------------------------------------------------------- /buildpackage.js: -------------------------------------------------------------------------------- 1 | /** 2 | * This is solely a build script, intended to prep the azure-devops-extension-sdk npm package for publishing. 3 | */ 4 | 5 | const { execSync } = require("child_process"); 6 | const fs = require("fs"); 7 | const glob = require("glob"); 8 | const path = require("path"); 9 | const copy = require("recursive-copy"); 10 | const shell = require("shelljs"); 11 | const UglifyES = require("uglify-es"); 12 | 13 | (async function() { 14 | // Clean bin directory 15 | console.log("# Cleaning bin. Running shelljs rm -rf ./bin"); 16 | shell.rm("-rf", "./bin"); 17 | 18 | // Compile typescript 19 | console.log("# Compiling TypeScript. Executing `node_modules\\.bin\\tsc -p ./tsconfig.json`."); 20 | 21 | try { 22 | execSync("node_modules\\.bin\\tsc -p ./tsconfig.json", { 23 | stdio: [0, 1, 2], 24 | shell: true, 25 | cwd: __dirname, 26 | }); 27 | } catch (error) { 28 | console.log("ERROR: Failed to build TypeScript."); 29 | process.exit(1); 30 | } 31 | 32 | // Copy ts files to bin 33 | console.log("# Copy declare files to bin."); 34 | try { 35 | await copy(path.join(__dirname, "src"), path.join(__dirname, "bin"), { 36 | filter: f => { 37 | return f.endsWith(".d.ts"); 38 | }, 39 | }); 40 | } catch (e) { 41 | console.log("Copy failed. " + error); 42 | } 43 | 44 | // Uglify JavaScript 45 | console.log("# Minifying JS using the UglifyES API, replacing un-minified files."); 46 | let count = 0; 47 | 48 | const files = await new Promise((resolve, reject) => { 49 | glob("./bin/**/*.js", (err, files) => { 50 | if (err) { 51 | reject(err); 52 | } else { 53 | resolve(files); 54 | } 55 | }); 56 | }); 57 | 58 | for (const file of files) { 59 | if (file.includes("node_modules/")) { 60 | continue; 61 | } 62 | fs.writeFileSync( 63 | file.substr(0, file.length - 2) + "min.js", 64 | UglifyES.minify(fs.readFileSync(file, "utf-8"), { compress: true, mangle: true }).code, 65 | "utf-8", 66 | ); 67 | count++; 68 | } 69 | console.log(`-- Minified ${count} files.`); 70 | 71 | // Copy package.json, LICENSE, README.md to bin 72 | console.log("# Copying package.json, LICENSE, and README.md to bin."); 73 | try { 74 | await copy(path.join(__dirname, "package.json"), path.join(__dirname, "bin", "package.json")); 75 | await copy(path.join(__dirname, "LICENSE"), path.join(__dirname, "bin", "LICENSE")); 76 | await copy(path.join(__dirname, "README.md"), path.join(__dirname, "bin", "README.md")); 77 | } catch (error) { 78 | console.log("ERROR: Failed to copy package.json, LICENSE, or README.md - " + error); 79 | process.exit(1); 80 | } 81 | })(); -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "azure-devops-extension-sdk", 3 | "version": "4.0.2", 4 | "lockfileVersion": 2, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "azure-devops-extension-sdk", 9 | "version": "4.0.2", 10 | "license": "MIT", 11 | "devDependencies": { 12 | "@rollup/plugin-terser": "^0.4.3", 13 | "@rollup/plugin-typescript": "^11.1.4", 14 | "rollup": "^3.29.4", 15 | "rollup-plugin-copy": "^3.5.0", 16 | "rollup-plugin-delete": "^2.0.0", 17 | "tslib": "^2.6.2", 18 | "typescript": "^5.2.2" 19 | }, 20 | "engines": { 21 | "node": ">=18.0.0" 22 | } 23 | }, 24 | "node_modules/@jridgewell/gen-mapping": { 25 | "version": "0.3.3", 26 | "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", 27 | "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", 28 | "dev": true, 29 | "dependencies": { 30 | "@jridgewell/set-array": "^1.0.1", 31 | "@jridgewell/sourcemap-codec": "^1.4.10", 32 | "@jridgewell/trace-mapping": "^0.3.9" 33 | }, 34 | "engines": { 35 | "node": ">=6.0.0" 36 | } 37 | }, 38 | "node_modules/@jridgewell/resolve-uri": { 39 | "version": "3.1.1", 40 | "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", 41 | "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", 42 | "dev": true, 43 | "engines": { 44 | "node": ">=6.0.0" 45 | } 46 | }, 47 | "node_modules/@jridgewell/set-array": { 48 | "version": "1.1.2", 49 | "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", 50 | "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", 51 | "dev": true, 52 | "engines": { 53 | "node": ">=6.0.0" 54 | } 55 | }, 56 | "node_modules/@jridgewell/source-map": { 57 | "version": "0.3.5", 58 | "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.5.tgz", 59 | "integrity": "sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ==", 60 | "dev": true, 61 | "dependencies": { 62 | "@jridgewell/gen-mapping": "^0.3.0", 63 | "@jridgewell/trace-mapping": "^0.3.9" 64 | } 65 | }, 66 | "node_modules/@jridgewell/sourcemap-codec": { 67 | "version": "1.4.15", 68 | "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", 69 | "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", 70 | "dev": true 71 | }, 72 | "node_modules/@jridgewell/trace-mapping": { 73 | "version": "0.3.19", 74 | "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.19.tgz", 75 | "integrity": "sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw==", 76 | "dev": true, 77 | "dependencies": { 78 | "@jridgewell/resolve-uri": "^3.1.0", 79 | "@jridgewell/sourcemap-codec": "^1.4.14" 80 | } 81 | }, 82 | "node_modules/@nodelib/fs.scandir": { 83 | "version": "2.1.5", 84 | "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", 85 | "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", 86 | "dev": true, 87 | "dependencies": { 88 | "@nodelib/fs.stat": "2.0.5", 89 | "run-parallel": "^1.1.9" 90 | }, 91 | "engines": { 92 | "node": ">= 8" 93 | } 94 | }, 95 | "node_modules/@nodelib/fs.stat": { 96 | "version": "2.0.5", 97 | "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", 98 | "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", 99 | "dev": true, 100 | "engines": { 101 | "node": ">= 8" 102 | } 103 | }, 104 | "node_modules/@nodelib/fs.walk": { 105 | "version": "1.2.8", 106 | "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", 107 | "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", 108 | "dev": true, 109 | "dependencies": { 110 | "@nodelib/fs.scandir": "2.1.5", 111 | "fastq": "^1.6.0" 112 | }, 113 | "engines": { 114 | "node": ">= 8" 115 | } 116 | }, 117 | "node_modules/@rollup/plugin-terser": { 118 | "version": "0.4.3", 119 | "resolved": "https://registry.npmjs.org/@rollup/plugin-terser/-/plugin-terser-0.4.3.tgz", 120 | "integrity": "sha512-EF0oejTMtkyhrkwCdg0HJ0IpkcaVg1MMSf2olHb2Jp+1mnLM04OhjpJWGma4HobiDTF0WCyViWuvadyE9ch2XA==", 121 | "dev": true, 122 | "dependencies": { 123 | "serialize-javascript": "^6.0.1", 124 | "smob": "^1.0.0", 125 | "terser": "^5.17.4" 126 | }, 127 | "engines": { 128 | "node": ">=14.0.0" 129 | }, 130 | "peerDependencies": { 131 | "rollup": "^2.x || ^3.x" 132 | }, 133 | "peerDependenciesMeta": { 134 | "rollup": { 135 | "optional": true 136 | } 137 | } 138 | }, 139 | "node_modules/@rollup/plugin-typescript": { 140 | "version": "11.1.4", 141 | "resolved": "https://registry.npmjs.org/@rollup/plugin-typescript/-/plugin-typescript-11.1.4.tgz", 142 | "integrity": "sha512-WZRh5LBVLQXdKFICUId5J3eIpmjGURaBqntfg3GSZACgeOAFS+lOSMGTwfzDkELTaZVp/lWdMVNU3UkwCUBg/Q==", 143 | "dev": true, 144 | "dependencies": { 145 | "@rollup/pluginutils": "^5.0.1", 146 | "resolve": "^1.22.1" 147 | }, 148 | "engines": { 149 | "node": ">=14.0.0" 150 | }, 151 | "peerDependencies": { 152 | "rollup": "^2.14.0||^3.0.0", 153 | "tslib": "*", 154 | "typescript": ">=3.7.0" 155 | }, 156 | "peerDependenciesMeta": { 157 | "rollup": { 158 | "optional": true 159 | }, 160 | "tslib": { 161 | "optional": true 162 | } 163 | } 164 | }, 165 | "node_modules/@rollup/pluginutils": { 166 | "version": "5.0.4", 167 | "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.0.4.tgz", 168 | "integrity": "sha512-0KJnIoRI8A+a1dqOYLxH8vBf8bphDmty5QvIm2hqm7oFCFYKCAZWWd2hXgMibaPsNDhI0AtpYfQZJG47pt/k4g==", 169 | "dev": true, 170 | "dependencies": { 171 | "@types/estree": "^1.0.0", 172 | "estree-walker": "^2.0.2", 173 | "picomatch": "^2.3.1" 174 | }, 175 | "engines": { 176 | "node": ">=14.0.0" 177 | }, 178 | "peerDependencies": { 179 | "rollup": "^1.20.0||^2.0.0||^3.0.0" 180 | }, 181 | "peerDependenciesMeta": { 182 | "rollup": { 183 | "optional": true 184 | } 185 | } 186 | }, 187 | "node_modules/@types/estree": { 188 | "version": "1.0.2", 189 | "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.2.tgz", 190 | "integrity": "sha512-VeiPZ9MMwXjO32/Xu7+OwflfmeoRwkE/qzndw42gGtgJwZopBnzy2gD//NN1+go1mADzkDcqf/KnFRSjTJ8xJA==", 191 | "dev": true 192 | }, 193 | "node_modules/@types/fs-extra": { 194 | "version": "8.1.3", 195 | "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-8.1.3.tgz", 196 | "integrity": "sha512-7IdV01N0u/CaVO0fuY1YmEg14HQN3+EW8mpNgg6NEfxEl/lzCa5OxlBu3iFsCAdamnYOcTQ7oEi43Xc/67Rgzw==", 197 | "dev": true, 198 | "dependencies": { 199 | "@types/node": "*" 200 | } 201 | }, 202 | "node_modules/@types/glob": { 203 | "version": "7.2.0", 204 | "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.2.0.tgz", 205 | "integrity": "sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==", 206 | "dev": true, 207 | "dependencies": { 208 | "@types/minimatch": "*", 209 | "@types/node": "*" 210 | } 211 | }, 212 | "node_modules/@types/minimatch": { 213 | "version": "5.1.2", 214 | "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz", 215 | "integrity": "sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==", 216 | "dev": true 217 | }, 218 | "node_modules/@types/node": { 219 | "version": "20.7.1", 220 | "resolved": "https://registry.npmjs.org/@types/node/-/node-20.7.1.tgz", 221 | "integrity": "sha512-LT+OIXpp2kj4E2S/p91BMe+VgGX2+lfO+XTpfXhh+bCk2LkQtHZSub8ewFBMGP5ClysPjTDFa4sMI8Q3n4T0wg==", 222 | "dev": true 223 | }, 224 | "node_modules/acorn": { 225 | "version": "8.10.0", 226 | "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", 227 | "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==", 228 | "dev": true, 229 | "bin": { 230 | "acorn": "bin/acorn" 231 | }, 232 | "engines": { 233 | "node": ">=0.4.0" 234 | } 235 | }, 236 | "node_modules/aggregate-error": { 237 | "version": "3.1.0", 238 | "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", 239 | "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", 240 | "dev": true, 241 | "dependencies": { 242 | "clean-stack": "^2.0.0", 243 | "indent-string": "^4.0.0" 244 | }, 245 | "engines": { 246 | "node": ">=8" 247 | } 248 | }, 249 | "node_modules/balanced-match": { 250 | "version": "1.0.0", 251 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", 252 | "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", 253 | "dev": true 254 | }, 255 | "node_modules/brace-expansion": { 256 | "version": "1.1.11", 257 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 258 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 259 | "dev": true, 260 | "dependencies": { 261 | "balanced-match": "^1.0.0", 262 | "concat-map": "0.0.1" 263 | } 264 | }, 265 | "node_modules/braces": { 266 | "version": "3.0.2", 267 | "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", 268 | "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", 269 | "dev": true, 270 | "dependencies": { 271 | "fill-range": "^7.0.1" 272 | }, 273 | "engines": { 274 | "node": ">=8" 275 | } 276 | }, 277 | "node_modules/buffer-from": { 278 | "version": "1.1.2", 279 | "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", 280 | "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", 281 | "dev": true 282 | }, 283 | "node_modules/clean-stack": { 284 | "version": "2.2.0", 285 | "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", 286 | "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", 287 | "dev": true, 288 | "engines": { 289 | "node": ">=6" 290 | } 291 | }, 292 | "node_modules/colorette": { 293 | "version": "1.4.0", 294 | "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.4.0.tgz", 295 | "integrity": "sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g==", 296 | "dev": true 297 | }, 298 | "node_modules/commander": { 299 | "version": "2.20.3", 300 | "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", 301 | "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", 302 | "dev": true 303 | }, 304 | "node_modules/concat-map": { 305 | "version": "0.0.1", 306 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 307 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", 308 | "dev": true 309 | }, 310 | "node_modules/dir-glob": { 311 | "version": "3.0.1", 312 | "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", 313 | "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", 314 | "dev": true, 315 | "dependencies": { 316 | "path-type": "^4.0.0" 317 | }, 318 | "engines": { 319 | "node": ">=8" 320 | } 321 | }, 322 | "node_modules/estree-walker": { 323 | "version": "2.0.2", 324 | "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", 325 | "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", 326 | "dev": true 327 | }, 328 | "node_modules/fast-glob": { 329 | "version": "3.3.1", 330 | "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz", 331 | "integrity": "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==", 332 | "dev": true, 333 | "dependencies": { 334 | "@nodelib/fs.stat": "^2.0.2", 335 | "@nodelib/fs.walk": "^1.2.3", 336 | "glob-parent": "^5.1.2", 337 | "merge2": "^1.3.0", 338 | "micromatch": "^4.0.4" 339 | }, 340 | "engines": { 341 | "node": ">=8.6.0" 342 | } 343 | }, 344 | "node_modules/fastq": { 345 | "version": "1.15.0", 346 | "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", 347 | "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", 348 | "dev": true, 349 | "dependencies": { 350 | "reusify": "^1.0.4" 351 | } 352 | }, 353 | "node_modules/fill-range": { 354 | "version": "7.0.1", 355 | "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", 356 | "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", 357 | "dev": true, 358 | "dependencies": { 359 | "to-regex-range": "^5.0.1" 360 | }, 361 | "engines": { 362 | "node": ">=8" 363 | } 364 | }, 365 | "node_modules/fs-extra": { 366 | "version": "8.1.0", 367 | "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", 368 | "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", 369 | "dev": true, 370 | "dependencies": { 371 | "graceful-fs": "^4.2.0", 372 | "jsonfile": "^4.0.0", 373 | "universalify": "^0.1.0" 374 | }, 375 | "engines": { 376 | "node": ">=6 <7 || >=8" 377 | } 378 | }, 379 | "node_modules/fs.realpath": { 380 | "version": "1.0.0", 381 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 382 | "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", 383 | "dev": true 384 | }, 385 | "node_modules/fsevents": { 386 | "version": "2.3.3", 387 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", 388 | "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", 389 | "dev": true, 390 | "hasInstallScript": true, 391 | "optional": true, 392 | "os": [ 393 | "darwin" 394 | ], 395 | "engines": { 396 | "node": "^8.16.0 || ^10.6.0 || >=11.0.0" 397 | } 398 | }, 399 | "node_modules/function-bind": { 400 | "version": "1.1.1", 401 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", 402 | "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", 403 | "dev": true 404 | }, 405 | "node_modules/glob": { 406 | "version": "7.1.3", 407 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", 408 | "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", 409 | "dev": true, 410 | "dependencies": { 411 | "fs.realpath": "^1.0.0", 412 | "inflight": "^1.0.4", 413 | "inherits": "2", 414 | "minimatch": "^3.0.4", 415 | "once": "^1.3.0", 416 | "path-is-absolute": "^1.0.0" 417 | }, 418 | "engines": { 419 | "node": "*" 420 | } 421 | }, 422 | "node_modules/glob-parent": { 423 | "version": "5.1.2", 424 | "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", 425 | "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", 426 | "dev": true, 427 | "dependencies": { 428 | "is-glob": "^4.0.1" 429 | }, 430 | "engines": { 431 | "node": ">= 6" 432 | } 433 | }, 434 | "node_modules/graceful-fs": { 435 | "version": "4.2.11", 436 | "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", 437 | "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", 438 | "dev": true 439 | }, 440 | "node_modules/has": { 441 | "version": "1.0.3", 442 | "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", 443 | "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", 444 | "dev": true, 445 | "dependencies": { 446 | "function-bind": "^1.1.1" 447 | }, 448 | "engines": { 449 | "node": ">= 0.4.0" 450 | } 451 | }, 452 | "node_modules/ignore": { 453 | "version": "5.2.4", 454 | "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", 455 | "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", 456 | "dev": true, 457 | "engines": { 458 | "node": ">= 4" 459 | } 460 | }, 461 | "node_modules/indent-string": { 462 | "version": "4.0.0", 463 | "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", 464 | "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", 465 | "dev": true, 466 | "engines": { 467 | "node": ">=8" 468 | } 469 | }, 470 | "node_modules/inflight": { 471 | "version": "1.0.6", 472 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 473 | "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", 474 | "dev": true, 475 | "dependencies": { 476 | "once": "^1.3.0", 477 | "wrappy": "1" 478 | } 479 | }, 480 | "node_modules/inherits": { 481 | "version": "2.0.3", 482 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", 483 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", 484 | "dev": true 485 | }, 486 | "node_modules/is-core-module": { 487 | "version": "2.13.0", 488 | "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.0.tgz", 489 | "integrity": "sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ==", 490 | "dev": true, 491 | "dependencies": { 492 | "has": "^1.0.3" 493 | }, 494 | "funding": { 495 | "url": "https://github.com/sponsors/ljharb" 496 | } 497 | }, 498 | "node_modules/is-extglob": { 499 | "version": "2.1.1", 500 | "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", 501 | "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", 502 | "dev": true, 503 | "engines": { 504 | "node": ">=0.10.0" 505 | } 506 | }, 507 | "node_modules/is-glob": { 508 | "version": "4.0.3", 509 | "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", 510 | "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", 511 | "dev": true, 512 | "dependencies": { 513 | "is-extglob": "^2.1.1" 514 | }, 515 | "engines": { 516 | "node": ">=0.10.0" 517 | } 518 | }, 519 | "node_modules/is-number": { 520 | "version": "7.0.0", 521 | "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", 522 | "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", 523 | "dev": true, 524 | "engines": { 525 | "node": ">=0.12.0" 526 | } 527 | }, 528 | "node_modules/is-plain-object": { 529 | "version": "3.0.1", 530 | "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-3.0.1.tgz", 531 | "integrity": "sha512-Xnpx182SBMrr/aBik8y+GuR4U1L9FqMSojwDQwPMmxyC6bvEqly9UBCxhauBF5vNh2gwWJNX6oDV7O+OM4z34g==", 532 | "dev": true, 533 | "engines": { 534 | "node": ">=0.10.0" 535 | } 536 | }, 537 | "node_modules/jsonfile": { 538 | "version": "4.0.0", 539 | "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", 540 | "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", 541 | "dev": true, 542 | "optionalDependencies": { 543 | "graceful-fs": "^4.1.6" 544 | } 545 | }, 546 | "node_modules/merge2": { 547 | "version": "1.4.1", 548 | "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", 549 | "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", 550 | "dev": true, 551 | "engines": { 552 | "node": ">= 8" 553 | } 554 | }, 555 | "node_modules/micromatch": { 556 | "version": "4.0.5", 557 | "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", 558 | "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", 559 | "dev": true, 560 | "dependencies": { 561 | "braces": "^3.0.2", 562 | "picomatch": "^2.3.1" 563 | }, 564 | "engines": { 565 | "node": ">=8.6" 566 | } 567 | }, 568 | "node_modules/minimatch": { 569 | "version": "3.1.2", 570 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", 571 | "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", 572 | "dev": true, 573 | "dependencies": { 574 | "brace-expansion": "^1.1.7" 575 | }, 576 | "engines": { 577 | "node": "*" 578 | } 579 | }, 580 | "node_modules/once": { 581 | "version": "1.4.0", 582 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 583 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", 584 | "dev": true, 585 | "dependencies": { 586 | "wrappy": "1" 587 | } 588 | }, 589 | "node_modules/p-map": { 590 | "version": "3.0.0", 591 | "resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz", 592 | "integrity": "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==", 593 | "dev": true, 594 | "dependencies": { 595 | "aggregate-error": "^3.0.0" 596 | }, 597 | "engines": { 598 | "node": ">=8" 599 | } 600 | }, 601 | "node_modules/path-is-absolute": { 602 | "version": "1.0.1", 603 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 604 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", 605 | "dev": true, 606 | "engines": { 607 | "node": ">=0.10.0" 608 | } 609 | }, 610 | "node_modules/path-parse": { 611 | "version": "1.0.7", 612 | "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", 613 | "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", 614 | "dev": true 615 | }, 616 | "node_modules/path-type": { 617 | "version": "4.0.0", 618 | "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", 619 | "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", 620 | "dev": true, 621 | "engines": { 622 | "node": ">=8" 623 | } 624 | }, 625 | "node_modules/picomatch": { 626 | "version": "2.3.1", 627 | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", 628 | "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", 629 | "dev": true, 630 | "engines": { 631 | "node": ">=8.6" 632 | }, 633 | "funding": { 634 | "url": "https://github.com/sponsors/jonschlinkert" 635 | } 636 | }, 637 | "node_modules/queue-microtask": { 638 | "version": "1.2.3", 639 | "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", 640 | "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", 641 | "dev": true, 642 | "funding": [ 643 | { 644 | "type": "github", 645 | "url": "https://github.com/sponsors/feross" 646 | }, 647 | { 648 | "type": "patreon", 649 | "url": "https://www.patreon.com/feross" 650 | }, 651 | { 652 | "type": "consulting", 653 | "url": "https://feross.org/support" 654 | } 655 | ] 656 | }, 657 | "node_modules/randombytes": { 658 | "version": "2.1.0", 659 | "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", 660 | "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", 661 | "dev": true, 662 | "dependencies": { 663 | "safe-buffer": "^5.1.0" 664 | } 665 | }, 666 | "node_modules/resolve": { 667 | "version": "1.22.6", 668 | "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.6.tgz", 669 | "integrity": "sha512-njhxM7mV12JfufShqGy3Rz8j11RPdLy4xi15UurGJeoHLfJpVXKdh3ueuOqbYUcDZnffr6X739JBo5LzyahEsw==", 670 | "dev": true, 671 | "dependencies": { 672 | "is-core-module": "^2.13.0", 673 | "path-parse": "^1.0.7", 674 | "supports-preserve-symlinks-flag": "^1.0.0" 675 | }, 676 | "bin": { 677 | "resolve": "bin/resolve" 678 | }, 679 | "funding": { 680 | "url": "https://github.com/sponsors/ljharb" 681 | } 682 | }, 683 | "node_modules/reusify": { 684 | "version": "1.0.4", 685 | "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", 686 | "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", 687 | "dev": true, 688 | "engines": { 689 | "iojs": ">=1.0.0", 690 | "node": ">=0.10.0" 691 | } 692 | }, 693 | "node_modules/rollup": { 694 | "version": "3.29.4", 695 | "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.4.tgz", 696 | "integrity": "sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==", 697 | "dev": true, 698 | "bin": { 699 | "rollup": "dist/bin/rollup" 700 | }, 701 | "engines": { 702 | "node": ">=14.18.0", 703 | "npm": ">=8.0.0" 704 | }, 705 | "optionalDependencies": { 706 | "fsevents": "~2.3.2" 707 | } 708 | }, 709 | "node_modules/rollup-plugin-copy": { 710 | "version": "3.5.0", 711 | "resolved": "https://registry.npmjs.org/rollup-plugin-copy/-/rollup-plugin-copy-3.5.0.tgz", 712 | "integrity": "sha512-wI8D5dvYovRMx/YYKtUNt3Yxaw4ORC9xo6Gt9t22kveWz1enG9QrhVlagzwrxSC455xD1dHMKhIJkbsQ7d48BA==", 713 | "dev": true, 714 | "dependencies": { 715 | "@types/fs-extra": "^8.0.1", 716 | "colorette": "^1.1.0", 717 | "fs-extra": "^8.1.0", 718 | "globby": "10.0.1", 719 | "is-plain-object": "^3.0.0" 720 | }, 721 | "engines": { 722 | "node": ">=8.3" 723 | } 724 | }, 725 | "node_modules/rollup-plugin-copy/node_modules/array-union": { 726 | "version": "2.1.0", 727 | "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", 728 | "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", 729 | "dev": true, 730 | "engines": { 731 | "node": ">=8" 732 | } 733 | }, 734 | "node_modules/rollup-plugin-copy/node_modules/globby": { 735 | "version": "10.0.1", 736 | "resolved": "https://registry.npmjs.org/globby/-/globby-10.0.1.tgz", 737 | "integrity": "sha512-sSs4inE1FB2YQiymcmTv6NWENryABjUNPeWhOvmn4SjtKybglsyPZxFB3U1/+L1bYi0rNZDqCLlHyLYDl1Pq5A==", 738 | "dev": true, 739 | "dependencies": { 740 | "@types/glob": "^7.1.1", 741 | "array-union": "^2.1.0", 742 | "dir-glob": "^3.0.1", 743 | "fast-glob": "^3.0.3", 744 | "glob": "^7.1.3", 745 | "ignore": "^5.1.1", 746 | "merge2": "^1.2.3", 747 | "slash": "^3.0.0" 748 | }, 749 | "engines": { 750 | "node": ">=8" 751 | } 752 | }, 753 | "node_modules/rollup-plugin-copy/node_modules/slash": { 754 | "version": "3.0.0", 755 | "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", 756 | "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", 757 | "dev": true, 758 | "engines": { 759 | "node": ">=8" 760 | } 761 | }, 762 | "node_modules/rollup-plugin-delete": { 763 | "version": "2.0.0", 764 | "resolved": "https://registry.npmjs.org/rollup-plugin-delete/-/rollup-plugin-delete-2.0.0.tgz", 765 | "integrity": "sha512-/VpLMtDy+8wwRlDANuYmDa9ss/knGsAgrDhM+tEwB1npHwNu4DYNmDfUL55csse/GHs9Q+SMT/rw9uiaZ3pnzA==", 766 | "dev": true, 767 | "dependencies": { 768 | "del": "^5.1.0" 769 | }, 770 | "engines": { 771 | "node": ">=10" 772 | } 773 | }, 774 | "node_modules/rollup-plugin-delete/node_modules/array-union": { 775 | "version": "2.1.0", 776 | "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", 777 | "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", 778 | "dev": true, 779 | "engines": { 780 | "node": ">=8" 781 | } 782 | }, 783 | "node_modules/rollup-plugin-delete/node_modules/del": { 784 | "version": "5.1.0", 785 | "resolved": "https://registry.npmjs.org/del/-/del-5.1.0.tgz", 786 | "integrity": "sha512-wH9xOVHnczo9jN2IW68BabcecVPxacIA3g/7z6vhSU/4stOKQzeCRK0yD0A24WiAAUJmmVpWqrERcTxnLo3AnA==", 787 | "dev": true, 788 | "dependencies": { 789 | "globby": "^10.0.1", 790 | "graceful-fs": "^4.2.2", 791 | "is-glob": "^4.0.1", 792 | "is-path-cwd": "^2.2.0", 793 | "is-path-inside": "^3.0.1", 794 | "p-map": "^3.0.0", 795 | "rimraf": "^3.0.0", 796 | "slash": "^3.0.0" 797 | }, 798 | "engines": { 799 | "node": ">=8" 800 | } 801 | }, 802 | "node_modules/rollup-plugin-delete/node_modules/globby": { 803 | "version": "10.0.2", 804 | "resolved": "https://registry.npmjs.org/globby/-/globby-10.0.2.tgz", 805 | "integrity": "sha512-7dUi7RvCoT/xast/o/dLN53oqND4yk0nsHkhRgn9w65C4PofCLOoJ39iSOg+qVDdWQPIEj+eszMHQ+aLVwwQSg==", 806 | "dev": true, 807 | "dependencies": { 808 | "@types/glob": "^7.1.1", 809 | "array-union": "^2.1.0", 810 | "dir-glob": "^3.0.1", 811 | "fast-glob": "^3.0.3", 812 | "glob": "^7.1.3", 813 | "ignore": "^5.1.1", 814 | "merge2": "^1.2.3", 815 | "slash": "^3.0.0" 816 | }, 817 | "engines": { 818 | "node": ">=8" 819 | } 820 | }, 821 | "node_modules/rollup-plugin-delete/node_modules/is-path-cwd": { 822 | "version": "2.2.0", 823 | "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz", 824 | "integrity": "sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==", 825 | "dev": true, 826 | "engines": { 827 | "node": ">=6" 828 | } 829 | }, 830 | "node_modules/rollup-plugin-delete/node_modules/is-path-inside": { 831 | "version": "3.0.3", 832 | "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", 833 | "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", 834 | "dev": true, 835 | "engines": { 836 | "node": ">=8" 837 | } 838 | }, 839 | "node_modules/rollup-plugin-delete/node_modules/rimraf": { 840 | "version": "3.0.2", 841 | "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", 842 | "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", 843 | "dev": true, 844 | "dependencies": { 845 | "glob": "^7.1.3" 846 | }, 847 | "bin": { 848 | "rimraf": "bin.js" 849 | }, 850 | "funding": { 851 | "url": "https://github.com/sponsors/isaacs" 852 | } 853 | }, 854 | "node_modules/rollup-plugin-delete/node_modules/slash": { 855 | "version": "3.0.0", 856 | "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", 857 | "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", 858 | "dev": true, 859 | "engines": { 860 | "node": ">=8" 861 | } 862 | }, 863 | "node_modules/run-parallel": { 864 | "version": "1.2.0", 865 | "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", 866 | "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", 867 | "dev": true, 868 | "funding": [ 869 | { 870 | "type": "github", 871 | "url": "https://github.com/sponsors/feross" 872 | }, 873 | { 874 | "type": "patreon", 875 | "url": "https://www.patreon.com/feross" 876 | }, 877 | { 878 | "type": "consulting", 879 | "url": "https://feross.org/support" 880 | } 881 | ], 882 | "dependencies": { 883 | "queue-microtask": "^1.2.2" 884 | } 885 | }, 886 | "node_modules/safe-buffer": { 887 | "version": "5.2.1", 888 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", 889 | "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", 890 | "dev": true, 891 | "funding": [ 892 | { 893 | "type": "github", 894 | "url": "https://github.com/sponsors/feross" 895 | }, 896 | { 897 | "type": "patreon", 898 | "url": "https://www.patreon.com/feross" 899 | }, 900 | { 901 | "type": "consulting", 902 | "url": "https://feross.org/support" 903 | } 904 | ] 905 | }, 906 | "node_modules/serialize-javascript": { 907 | "version": "6.0.1", 908 | "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.1.tgz", 909 | "integrity": "sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w==", 910 | "dev": true, 911 | "dependencies": { 912 | "randombytes": "^2.1.0" 913 | } 914 | }, 915 | "node_modules/smob": { 916 | "version": "1.4.1", 917 | "resolved": "https://registry.npmjs.org/smob/-/smob-1.4.1.tgz", 918 | "integrity": "sha512-9LK+E7Hv5R9u4g4C3p+jjLstaLe11MDsL21UpYaCNmapvMkYhqCV4A/f/3gyH8QjMyh6l68q9xC85vihY9ahMQ==", 919 | "dev": true 920 | }, 921 | "node_modules/source-map": { 922 | "version": "0.6.1", 923 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", 924 | "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", 925 | "dev": true, 926 | "engines": { 927 | "node": ">=0.10.0" 928 | } 929 | }, 930 | "node_modules/source-map-support": { 931 | "version": "0.5.21", 932 | "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", 933 | "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", 934 | "dev": true, 935 | "dependencies": { 936 | "buffer-from": "^1.0.0", 937 | "source-map": "^0.6.0" 938 | } 939 | }, 940 | "node_modules/supports-preserve-symlinks-flag": { 941 | "version": "1.0.0", 942 | "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", 943 | "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", 944 | "dev": true, 945 | "engines": { 946 | "node": ">= 0.4" 947 | }, 948 | "funding": { 949 | "url": "https://github.com/sponsors/ljharb" 950 | } 951 | }, 952 | "node_modules/terser": { 953 | "version": "5.20.0", 954 | "resolved": "https://registry.npmjs.org/terser/-/terser-5.20.0.tgz", 955 | "integrity": "sha512-e56ETryaQDyebBwJIWYB2TT6f2EZ0fL0sW/JRXNMN26zZdKi2u/E/5my5lG6jNxym6qsrVXfFRmOdV42zlAgLQ==", 956 | "dev": true, 957 | "dependencies": { 958 | "@jridgewell/source-map": "^0.3.3", 959 | "acorn": "^8.8.2", 960 | "commander": "^2.20.0", 961 | "source-map-support": "~0.5.20" 962 | }, 963 | "bin": { 964 | "terser": "bin/terser" 965 | }, 966 | "engines": { 967 | "node": ">=10" 968 | } 969 | }, 970 | "node_modules/to-regex-range": { 971 | "version": "5.0.1", 972 | "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", 973 | "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", 974 | "dev": true, 975 | "dependencies": { 976 | "is-number": "^7.0.0" 977 | }, 978 | "engines": { 979 | "node": ">=8.0" 980 | } 981 | }, 982 | "node_modules/tslib": { 983 | "version": "2.6.2", 984 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", 985 | "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", 986 | "dev": true 987 | }, 988 | "node_modules/typescript": { 989 | "version": "5.2.2", 990 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", 991 | "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==", 992 | "dev": true, 993 | "bin": { 994 | "tsc": "bin/tsc", 995 | "tsserver": "bin/tsserver" 996 | }, 997 | "engines": { 998 | "node": ">=14.17" 999 | } 1000 | }, 1001 | "node_modules/universalify": { 1002 | "version": "0.1.2", 1003 | "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", 1004 | "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", 1005 | "dev": true, 1006 | "engines": { 1007 | "node": ">= 4.0.0" 1008 | } 1009 | }, 1010 | "node_modules/wrappy": { 1011 | "version": "1.0.2", 1012 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 1013 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", 1014 | "dev": true 1015 | } 1016 | }, 1017 | "dependencies": { 1018 | "@jridgewell/gen-mapping": { 1019 | "version": "0.3.3", 1020 | "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", 1021 | "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", 1022 | "dev": true, 1023 | "requires": { 1024 | "@jridgewell/set-array": "^1.0.1", 1025 | "@jridgewell/sourcemap-codec": "^1.4.10", 1026 | "@jridgewell/trace-mapping": "^0.3.9" 1027 | } 1028 | }, 1029 | "@jridgewell/resolve-uri": { 1030 | "version": "3.1.1", 1031 | "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", 1032 | "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", 1033 | "dev": true 1034 | }, 1035 | "@jridgewell/set-array": { 1036 | "version": "1.1.2", 1037 | "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", 1038 | "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", 1039 | "dev": true 1040 | }, 1041 | "@jridgewell/source-map": { 1042 | "version": "0.3.5", 1043 | "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.5.tgz", 1044 | "integrity": "sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ==", 1045 | "dev": true, 1046 | "requires": { 1047 | "@jridgewell/gen-mapping": "^0.3.0", 1048 | "@jridgewell/trace-mapping": "^0.3.9" 1049 | } 1050 | }, 1051 | "@jridgewell/sourcemap-codec": { 1052 | "version": "1.4.15", 1053 | "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", 1054 | "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", 1055 | "dev": true 1056 | }, 1057 | "@jridgewell/trace-mapping": { 1058 | "version": "0.3.19", 1059 | "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.19.tgz", 1060 | "integrity": "sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw==", 1061 | "dev": true, 1062 | "requires": { 1063 | "@jridgewell/resolve-uri": "^3.1.0", 1064 | "@jridgewell/sourcemap-codec": "^1.4.14" 1065 | } 1066 | }, 1067 | "@nodelib/fs.scandir": { 1068 | "version": "2.1.5", 1069 | "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", 1070 | "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", 1071 | "dev": true, 1072 | "requires": { 1073 | "@nodelib/fs.stat": "2.0.5", 1074 | "run-parallel": "^1.1.9" 1075 | } 1076 | }, 1077 | "@nodelib/fs.stat": { 1078 | "version": "2.0.5", 1079 | "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", 1080 | "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", 1081 | "dev": true 1082 | }, 1083 | "@nodelib/fs.walk": { 1084 | "version": "1.2.8", 1085 | "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", 1086 | "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", 1087 | "dev": true, 1088 | "requires": { 1089 | "@nodelib/fs.scandir": "2.1.5", 1090 | "fastq": "^1.6.0" 1091 | } 1092 | }, 1093 | "@rollup/plugin-terser": { 1094 | "version": "0.4.3", 1095 | "resolved": "https://registry.npmjs.org/@rollup/plugin-terser/-/plugin-terser-0.4.3.tgz", 1096 | "integrity": "sha512-EF0oejTMtkyhrkwCdg0HJ0IpkcaVg1MMSf2olHb2Jp+1mnLM04OhjpJWGma4HobiDTF0WCyViWuvadyE9ch2XA==", 1097 | "dev": true, 1098 | "requires": { 1099 | "serialize-javascript": "^6.0.1", 1100 | "smob": "^1.0.0", 1101 | "terser": "^5.17.4" 1102 | } 1103 | }, 1104 | "@rollup/plugin-typescript": { 1105 | "version": "11.1.4", 1106 | "resolved": "https://registry.npmjs.org/@rollup/plugin-typescript/-/plugin-typescript-11.1.4.tgz", 1107 | "integrity": "sha512-WZRh5LBVLQXdKFICUId5J3eIpmjGURaBqntfg3GSZACgeOAFS+lOSMGTwfzDkELTaZVp/lWdMVNU3UkwCUBg/Q==", 1108 | "dev": true, 1109 | "requires": { 1110 | "@rollup/pluginutils": "^5.0.1", 1111 | "resolve": "^1.22.1" 1112 | } 1113 | }, 1114 | "@rollup/pluginutils": { 1115 | "version": "5.0.4", 1116 | "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.0.4.tgz", 1117 | "integrity": "sha512-0KJnIoRI8A+a1dqOYLxH8vBf8bphDmty5QvIm2hqm7oFCFYKCAZWWd2hXgMibaPsNDhI0AtpYfQZJG47pt/k4g==", 1118 | "dev": true, 1119 | "requires": { 1120 | "@types/estree": "^1.0.0", 1121 | "estree-walker": "^2.0.2", 1122 | "picomatch": "^2.3.1" 1123 | } 1124 | }, 1125 | "@types/estree": { 1126 | "version": "1.0.2", 1127 | "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.2.tgz", 1128 | "integrity": "sha512-VeiPZ9MMwXjO32/Xu7+OwflfmeoRwkE/qzndw42gGtgJwZopBnzy2gD//NN1+go1mADzkDcqf/KnFRSjTJ8xJA==", 1129 | "dev": true 1130 | }, 1131 | "@types/fs-extra": { 1132 | "version": "8.1.3", 1133 | "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-8.1.3.tgz", 1134 | "integrity": "sha512-7IdV01N0u/CaVO0fuY1YmEg14HQN3+EW8mpNgg6NEfxEl/lzCa5OxlBu3iFsCAdamnYOcTQ7oEi43Xc/67Rgzw==", 1135 | "dev": true, 1136 | "requires": { 1137 | "@types/node": "*" 1138 | } 1139 | }, 1140 | "@types/glob": { 1141 | "version": "7.2.0", 1142 | "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.2.0.tgz", 1143 | "integrity": "sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==", 1144 | "dev": true, 1145 | "requires": { 1146 | "@types/minimatch": "*", 1147 | "@types/node": "*" 1148 | } 1149 | }, 1150 | "@types/minimatch": { 1151 | "version": "5.1.2", 1152 | "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz", 1153 | "integrity": "sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==", 1154 | "dev": true 1155 | }, 1156 | "@types/node": { 1157 | "version": "20.7.1", 1158 | "resolved": "https://registry.npmjs.org/@types/node/-/node-20.7.1.tgz", 1159 | "integrity": "sha512-LT+OIXpp2kj4E2S/p91BMe+VgGX2+lfO+XTpfXhh+bCk2LkQtHZSub8ewFBMGP5ClysPjTDFa4sMI8Q3n4T0wg==", 1160 | "dev": true 1161 | }, 1162 | "acorn": { 1163 | "version": "8.10.0", 1164 | "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", 1165 | "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==", 1166 | "dev": true 1167 | }, 1168 | "aggregate-error": { 1169 | "version": "3.1.0", 1170 | "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", 1171 | "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", 1172 | "dev": true, 1173 | "requires": { 1174 | "clean-stack": "^2.0.0", 1175 | "indent-string": "^4.0.0" 1176 | } 1177 | }, 1178 | "balanced-match": { 1179 | "version": "1.0.0", 1180 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", 1181 | "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", 1182 | "dev": true 1183 | }, 1184 | "brace-expansion": { 1185 | "version": "1.1.11", 1186 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 1187 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 1188 | "dev": true, 1189 | "requires": { 1190 | "balanced-match": "^1.0.0", 1191 | "concat-map": "0.0.1" 1192 | } 1193 | }, 1194 | "braces": { 1195 | "version": "3.0.2", 1196 | "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", 1197 | "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", 1198 | "dev": true, 1199 | "requires": { 1200 | "fill-range": "^7.0.1" 1201 | } 1202 | }, 1203 | "buffer-from": { 1204 | "version": "1.1.2", 1205 | "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", 1206 | "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", 1207 | "dev": true 1208 | }, 1209 | "clean-stack": { 1210 | "version": "2.2.0", 1211 | "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", 1212 | "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", 1213 | "dev": true 1214 | }, 1215 | "colorette": { 1216 | "version": "1.4.0", 1217 | "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.4.0.tgz", 1218 | "integrity": "sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g==", 1219 | "dev": true 1220 | }, 1221 | "commander": { 1222 | "version": "2.20.3", 1223 | "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", 1224 | "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", 1225 | "dev": true 1226 | }, 1227 | "concat-map": { 1228 | "version": "0.0.1", 1229 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 1230 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", 1231 | "dev": true 1232 | }, 1233 | "dir-glob": { 1234 | "version": "3.0.1", 1235 | "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", 1236 | "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", 1237 | "dev": true, 1238 | "requires": { 1239 | "path-type": "^4.0.0" 1240 | } 1241 | }, 1242 | "estree-walker": { 1243 | "version": "2.0.2", 1244 | "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", 1245 | "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", 1246 | "dev": true 1247 | }, 1248 | "fast-glob": { 1249 | "version": "3.3.1", 1250 | "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz", 1251 | "integrity": "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==", 1252 | "dev": true, 1253 | "requires": { 1254 | "@nodelib/fs.stat": "^2.0.2", 1255 | "@nodelib/fs.walk": "^1.2.3", 1256 | "glob-parent": "^5.1.2", 1257 | "merge2": "^1.3.0", 1258 | "micromatch": "^4.0.4" 1259 | } 1260 | }, 1261 | "fastq": { 1262 | "version": "1.15.0", 1263 | "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", 1264 | "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", 1265 | "dev": true, 1266 | "requires": { 1267 | "reusify": "^1.0.4" 1268 | } 1269 | }, 1270 | "fill-range": { 1271 | "version": "7.0.1", 1272 | "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", 1273 | "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", 1274 | "dev": true, 1275 | "requires": { 1276 | "to-regex-range": "^5.0.1" 1277 | } 1278 | }, 1279 | "fs-extra": { 1280 | "version": "8.1.0", 1281 | "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", 1282 | "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", 1283 | "dev": true, 1284 | "requires": { 1285 | "graceful-fs": "^4.2.0", 1286 | "jsonfile": "^4.0.0", 1287 | "universalify": "^0.1.0" 1288 | } 1289 | }, 1290 | "fs.realpath": { 1291 | "version": "1.0.0", 1292 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 1293 | "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", 1294 | "dev": true 1295 | }, 1296 | "fsevents": { 1297 | "version": "2.3.3", 1298 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", 1299 | "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", 1300 | "dev": true, 1301 | "optional": true 1302 | }, 1303 | "function-bind": { 1304 | "version": "1.1.1", 1305 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", 1306 | "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", 1307 | "dev": true 1308 | }, 1309 | "glob": { 1310 | "version": "7.1.3", 1311 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", 1312 | "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", 1313 | "dev": true, 1314 | "requires": { 1315 | "fs.realpath": "^1.0.0", 1316 | "inflight": "^1.0.4", 1317 | "inherits": "2", 1318 | "minimatch": "^3.0.4", 1319 | "once": "^1.3.0", 1320 | "path-is-absolute": "^1.0.0" 1321 | } 1322 | }, 1323 | "glob-parent": { 1324 | "version": "5.1.2", 1325 | "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", 1326 | "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", 1327 | "dev": true, 1328 | "requires": { 1329 | "is-glob": "^4.0.1" 1330 | } 1331 | }, 1332 | "graceful-fs": { 1333 | "version": "4.2.11", 1334 | "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", 1335 | "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", 1336 | "dev": true 1337 | }, 1338 | "has": { 1339 | "version": "1.0.3", 1340 | "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", 1341 | "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", 1342 | "dev": true, 1343 | "requires": { 1344 | "function-bind": "^1.1.1" 1345 | } 1346 | }, 1347 | "ignore": { 1348 | "version": "5.2.4", 1349 | "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", 1350 | "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", 1351 | "dev": true 1352 | }, 1353 | "indent-string": { 1354 | "version": "4.0.0", 1355 | "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", 1356 | "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", 1357 | "dev": true 1358 | }, 1359 | "inflight": { 1360 | "version": "1.0.6", 1361 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 1362 | "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", 1363 | "dev": true, 1364 | "requires": { 1365 | "once": "^1.3.0", 1366 | "wrappy": "1" 1367 | } 1368 | }, 1369 | "inherits": { 1370 | "version": "2.0.3", 1371 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", 1372 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", 1373 | "dev": true 1374 | }, 1375 | "is-core-module": { 1376 | "version": "2.13.0", 1377 | "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.0.tgz", 1378 | "integrity": "sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ==", 1379 | "dev": true, 1380 | "requires": { 1381 | "has": "^1.0.3" 1382 | } 1383 | }, 1384 | "is-extglob": { 1385 | "version": "2.1.1", 1386 | "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", 1387 | "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", 1388 | "dev": true 1389 | }, 1390 | "is-glob": { 1391 | "version": "4.0.3", 1392 | "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", 1393 | "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", 1394 | "dev": true, 1395 | "requires": { 1396 | "is-extglob": "^2.1.1" 1397 | } 1398 | }, 1399 | "is-number": { 1400 | "version": "7.0.0", 1401 | "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", 1402 | "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", 1403 | "dev": true 1404 | }, 1405 | "is-plain-object": { 1406 | "version": "3.0.1", 1407 | "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-3.0.1.tgz", 1408 | "integrity": "sha512-Xnpx182SBMrr/aBik8y+GuR4U1L9FqMSojwDQwPMmxyC6bvEqly9UBCxhauBF5vNh2gwWJNX6oDV7O+OM4z34g==", 1409 | "dev": true 1410 | }, 1411 | "jsonfile": { 1412 | "version": "4.0.0", 1413 | "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", 1414 | "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", 1415 | "dev": true, 1416 | "requires": { 1417 | "graceful-fs": "^4.1.6" 1418 | } 1419 | }, 1420 | "merge2": { 1421 | "version": "1.4.1", 1422 | "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", 1423 | "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", 1424 | "dev": true 1425 | }, 1426 | "micromatch": { 1427 | "version": "4.0.5", 1428 | "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", 1429 | "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", 1430 | "dev": true, 1431 | "requires": { 1432 | "braces": "^3.0.2", 1433 | "picomatch": "^2.3.1" 1434 | } 1435 | }, 1436 | "minimatch": { 1437 | "version": "3.1.2", 1438 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", 1439 | "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", 1440 | "dev": true, 1441 | "requires": { 1442 | "brace-expansion": "^1.1.7" 1443 | } 1444 | }, 1445 | "once": { 1446 | "version": "1.4.0", 1447 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 1448 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", 1449 | "dev": true, 1450 | "requires": { 1451 | "wrappy": "1" 1452 | } 1453 | }, 1454 | "p-map": { 1455 | "version": "3.0.0", 1456 | "resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz", 1457 | "integrity": "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==", 1458 | "dev": true, 1459 | "requires": { 1460 | "aggregate-error": "^3.0.0" 1461 | } 1462 | }, 1463 | "path-is-absolute": { 1464 | "version": "1.0.1", 1465 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 1466 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", 1467 | "dev": true 1468 | }, 1469 | "path-parse": { 1470 | "version": "1.0.7", 1471 | "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", 1472 | "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", 1473 | "dev": true 1474 | }, 1475 | "path-type": { 1476 | "version": "4.0.0", 1477 | "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", 1478 | "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", 1479 | "dev": true 1480 | }, 1481 | "picomatch": { 1482 | "version": "2.3.1", 1483 | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", 1484 | "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", 1485 | "dev": true 1486 | }, 1487 | "queue-microtask": { 1488 | "version": "1.2.3", 1489 | "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", 1490 | "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", 1491 | "dev": true 1492 | }, 1493 | "randombytes": { 1494 | "version": "2.1.0", 1495 | "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", 1496 | "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", 1497 | "dev": true, 1498 | "requires": { 1499 | "safe-buffer": "^5.1.0" 1500 | } 1501 | }, 1502 | "resolve": { 1503 | "version": "1.22.6", 1504 | "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.6.tgz", 1505 | "integrity": "sha512-njhxM7mV12JfufShqGy3Rz8j11RPdLy4xi15UurGJeoHLfJpVXKdh3ueuOqbYUcDZnffr6X739JBo5LzyahEsw==", 1506 | "dev": true, 1507 | "requires": { 1508 | "is-core-module": "^2.13.0", 1509 | "path-parse": "^1.0.7", 1510 | "supports-preserve-symlinks-flag": "^1.0.0" 1511 | } 1512 | }, 1513 | "reusify": { 1514 | "version": "1.0.4", 1515 | "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", 1516 | "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", 1517 | "dev": true 1518 | }, 1519 | "rollup": { 1520 | "version": "3.29.4", 1521 | "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.4.tgz", 1522 | "integrity": "sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==", 1523 | "dev": true, 1524 | "requires": { 1525 | "fsevents": "~2.3.2" 1526 | } 1527 | }, 1528 | "rollup-plugin-copy": { 1529 | "version": "3.5.0", 1530 | "resolved": "https://registry.npmjs.org/rollup-plugin-copy/-/rollup-plugin-copy-3.5.0.tgz", 1531 | "integrity": "sha512-wI8D5dvYovRMx/YYKtUNt3Yxaw4ORC9xo6Gt9t22kveWz1enG9QrhVlagzwrxSC455xD1dHMKhIJkbsQ7d48BA==", 1532 | "dev": true, 1533 | "requires": { 1534 | "@types/fs-extra": "^8.0.1", 1535 | "colorette": "^1.1.0", 1536 | "fs-extra": "^8.1.0", 1537 | "globby": "10.0.1", 1538 | "is-plain-object": "^3.0.0" 1539 | }, 1540 | "dependencies": { 1541 | "array-union": { 1542 | "version": "2.1.0", 1543 | "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", 1544 | "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", 1545 | "dev": true 1546 | }, 1547 | "globby": { 1548 | "version": "10.0.1", 1549 | "resolved": "https://registry.npmjs.org/globby/-/globby-10.0.1.tgz", 1550 | "integrity": "sha512-sSs4inE1FB2YQiymcmTv6NWENryABjUNPeWhOvmn4SjtKybglsyPZxFB3U1/+L1bYi0rNZDqCLlHyLYDl1Pq5A==", 1551 | "dev": true, 1552 | "requires": { 1553 | "@types/glob": "^7.1.1", 1554 | "array-union": "^2.1.0", 1555 | "dir-glob": "^3.0.1", 1556 | "fast-glob": "^3.0.3", 1557 | "glob": "^7.1.3", 1558 | "ignore": "^5.1.1", 1559 | "merge2": "^1.2.3", 1560 | "slash": "^3.0.0" 1561 | } 1562 | }, 1563 | "slash": { 1564 | "version": "3.0.0", 1565 | "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", 1566 | "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", 1567 | "dev": true 1568 | } 1569 | } 1570 | }, 1571 | "rollup-plugin-delete": { 1572 | "version": "2.0.0", 1573 | "resolved": "https://registry.npmjs.org/rollup-plugin-delete/-/rollup-plugin-delete-2.0.0.tgz", 1574 | "integrity": "sha512-/VpLMtDy+8wwRlDANuYmDa9ss/knGsAgrDhM+tEwB1npHwNu4DYNmDfUL55csse/GHs9Q+SMT/rw9uiaZ3pnzA==", 1575 | "dev": true, 1576 | "requires": { 1577 | "del": "^5.1.0" 1578 | }, 1579 | "dependencies": { 1580 | "array-union": { 1581 | "version": "2.1.0", 1582 | "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", 1583 | "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", 1584 | "dev": true 1585 | }, 1586 | "del": { 1587 | "version": "5.1.0", 1588 | "resolved": "https://registry.npmjs.org/del/-/del-5.1.0.tgz", 1589 | "integrity": "sha512-wH9xOVHnczo9jN2IW68BabcecVPxacIA3g/7z6vhSU/4stOKQzeCRK0yD0A24WiAAUJmmVpWqrERcTxnLo3AnA==", 1590 | "dev": true, 1591 | "requires": { 1592 | "globby": "^10.0.1", 1593 | "graceful-fs": "^4.2.2", 1594 | "is-glob": "^4.0.1", 1595 | "is-path-cwd": "^2.2.0", 1596 | "is-path-inside": "^3.0.1", 1597 | "p-map": "^3.0.0", 1598 | "rimraf": "^3.0.0", 1599 | "slash": "^3.0.0" 1600 | } 1601 | }, 1602 | "globby": { 1603 | "version": "10.0.2", 1604 | "resolved": "https://registry.npmjs.org/globby/-/globby-10.0.2.tgz", 1605 | "integrity": "sha512-7dUi7RvCoT/xast/o/dLN53oqND4yk0nsHkhRgn9w65C4PofCLOoJ39iSOg+qVDdWQPIEj+eszMHQ+aLVwwQSg==", 1606 | "dev": true, 1607 | "requires": { 1608 | "@types/glob": "^7.1.1", 1609 | "array-union": "^2.1.0", 1610 | "dir-glob": "^3.0.1", 1611 | "fast-glob": "^3.0.3", 1612 | "glob": "^7.1.3", 1613 | "ignore": "^5.1.1", 1614 | "merge2": "^1.2.3", 1615 | "slash": "^3.0.0" 1616 | } 1617 | }, 1618 | "is-path-cwd": { 1619 | "version": "2.2.0", 1620 | "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz", 1621 | "integrity": "sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==", 1622 | "dev": true 1623 | }, 1624 | "is-path-inside": { 1625 | "version": "3.0.3", 1626 | "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", 1627 | "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", 1628 | "dev": true 1629 | }, 1630 | "rimraf": { 1631 | "version": "3.0.2", 1632 | "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", 1633 | "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", 1634 | "dev": true, 1635 | "requires": { 1636 | "glob": "^7.1.3" 1637 | } 1638 | }, 1639 | "slash": { 1640 | "version": "3.0.0", 1641 | "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", 1642 | "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", 1643 | "dev": true 1644 | } 1645 | } 1646 | }, 1647 | "run-parallel": { 1648 | "version": "1.2.0", 1649 | "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", 1650 | "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", 1651 | "dev": true, 1652 | "requires": { 1653 | "queue-microtask": "^1.2.2" 1654 | } 1655 | }, 1656 | "safe-buffer": { 1657 | "version": "5.2.1", 1658 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", 1659 | "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", 1660 | "dev": true 1661 | }, 1662 | "serialize-javascript": { 1663 | "version": "6.0.1", 1664 | "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.1.tgz", 1665 | "integrity": "sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w==", 1666 | "dev": true, 1667 | "requires": { 1668 | "randombytes": "^2.1.0" 1669 | } 1670 | }, 1671 | "smob": { 1672 | "version": "1.4.1", 1673 | "resolved": "https://registry.npmjs.org/smob/-/smob-1.4.1.tgz", 1674 | "integrity": "sha512-9LK+E7Hv5R9u4g4C3p+jjLstaLe11MDsL21UpYaCNmapvMkYhqCV4A/f/3gyH8QjMyh6l68q9xC85vihY9ahMQ==", 1675 | "dev": true 1676 | }, 1677 | "source-map": { 1678 | "version": "0.6.1", 1679 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", 1680 | "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", 1681 | "dev": true 1682 | }, 1683 | "source-map-support": { 1684 | "version": "0.5.21", 1685 | "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", 1686 | "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", 1687 | "dev": true, 1688 | "requires": { 1689 | "buffer-from": "^1.0.0", 1690 | "source-map": "^0.6.0" 1691 | } 1692 | }, 1693 | "supports-preserve-symlinks-flag": { 1694 | "version": "1.0.0", 1695 | "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", 1696 | "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", 1697 | "dev": true 1698 | }, 1699 | "terser": { 1700 | "version": "5.20.0", 1701 | "resolved": "https://registry.npmjs.org/terser/-/terser-5.20.0.tgz", 1702 | "integrity": "sha512-e56ETryaQDyebBwJIWYB2TT6f2EZ0fL0sW/JRXNMN26zZdKi2u/E/5my5lG6jNxym6qsrVXfFRmOdV42zlAgLQ==", 1703 | "dev": true, 1704 | "requires": { 1705 | "@jridgewell/source-map": "^0.3.3", 1706 | "acorn": "^8.8.2", 1707 | "commander": "^2.20.0", 1708 | "source-map-support": "~0.5.20" 1709 | } 1710 | }, 1711 | "to-regex-range": { 1712 | "version": "5.0.1", 1713 | "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", 1714 | "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", 1715 | "dev": true, 1716 | "requires": { 1717 | "is-number": "^7.0.0" 1718 | } 1719 | }, 1720 | "tslib": { 1721 | "version": "2.6.2", 1722 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", 1723 | "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", 1724 | "dev": true 1725 | }, 1726 | "typescript": { 1727 | "version": "5.2.2", 1728 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", 1729 | "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==", 1730 | "dev": true 1731 | }, 1732 | "universalify": { 1733 | "version": "0.1.2", 1734 | "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", 1735 | "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", 1736 | "dev": true 1737 | }, 1738 | "wrappy": { 1739 | "version": "1.0.2", 1740 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 1741 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", 1742 | "dev": true 1743 | } 1744 | } 1745 | } 1746 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "azure-devops-extension-sdk", 3 | "version": "4.0.2", 4 | "description": "Azure DevOps web extension JavaScript library.", 5 | "repository": { 6 | "type": "git", 7 | "url": "https://github.com/Microsoft/azure-devops-extension-sdk.git" 8 | }, 9 | "engines": { 10 | "node": ">=18.0.0" 11 | }, 12 | "scripts": { 13 | "build": "rollup -c rollup.config.js --bundleConfigAsCjs" 14 | }, 15 | "keywords": [ 16 | "extensions", 17 | "Azure DevOps", 18 | "Visual Studio Team Services" 19 | ], 20 | "author": "Microsoft", 21 | "license": "MIT", 22 | "bugs": { 23 | "url": "https://aka.ms/AAk5pcm" 24 | }, 25 | "homepage": "https://docs.microsoft.com/en-us/azure/devops/integrate", 26 | "main": "SDK.js", 27 | "exports": { 28 | "types": "./SDK.d.ts", 29 | "import": "./esm/SDK.min.js", 30 | "require": "./SDK.min.js" 31 | }, 32 | "devDependencies": { 33 | "@rollup/plugin-terser": "^0.4.3", 34 | "@rollup/plugin-typescript": "^11.1.4", 35 | "rollup": "^3.29.4", 36 | "rollup-plugin-copy": "^3.5.0", 37 | "rollup-plugin-delete": "^2.0.0", 38 | "tslib": "^2.6.2", 39 | "typescript": "^5.2.2" 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Rollup configuration file for building a JavaScript SDK in different formats: ESM and AMD 3 | */ 4 | 5 | import typescript from "@rollup/plugin-typescript" // Compiles TypeScript to JavaScript 6 | import del from "rollup-plugin-delete" // Deletes files and folders 7 | import terser from "@rollup/plugin-terser" // Minifies JavaScript 8 | import copy from "rollup-plugin-copy" // Copies files and folders 9 | 10 | export default [ 11 | // AMD Bundle: Backward Compatibility 12 | // Also, cleaning bin folder first and copying License and package.json to the bin folder (root of the package). 13 | { 14 | input: "src/SDK.ts", 15 | external: ["tslib"], // Exclude tslib from the final bundle. It will be imported from external source at runtime. 16 | output: { 17 | dir: "bin", 18 | format: "amd", 19 | sourcemap: true, 20 | preserveModules: true, 21 | }, 22 | plugins: [ 23 | del({ targets: "bin/*" }), 24 | typescript({ tsconfig: "./tsconfig.amd.json" }), // Mentioning tsconfig.amd.json file (where declaration is set to true), so d.ts files are generated. 25 | copy({ 26 | targets: [ 27 | { src: "package.json", dest: "bin" }, 28 | { src: "LICENSE", dest: "bin" }, 29 | { src: "README.md", dest: "bin" }, 30 | { src: "SECURITY.md", dest: "bin" } 31 | ] 32 | }), 33 | ] 34 | }, 35 | // AMD Bundle: Minified - Generating SDK.min.js 36 | { 37 | input: "src/SDK.ts", 38 | output: { 39 | file: "bin/SDK.min.js", 40 | format: "amd", 41 | }, 42 | plugins: [ 43 | typescript(), 44 | terser() 45 | ] 46 | }, 47 | // AMD Bundle: Minified - Generating XDM.min.js 48 | { 49 | input: "src/XDM.ts", 50 | output: { 51 | file: "bin/XDM.min.js", 52 | format: "amd", 53 | }, 54 | plugins: [ 55 | typescript(), 56 | terser() 57 | ] 58 | }, 59 | // ESM Bundle 60 | { 61 | input: "src/SDK.ts", 62 | output: { 63 | dir: "bin/esm", 64 | format: "esm", 65 | sourcemap: true, 66 | preserveModules: true 67 | }, 68 | plugins: [ 69 | del({ targets: "bin/esm/*" }), 70 | typescript({ tsconfig: "./tsconfig.esm.json" }), 71 | ] 72 | }, 73 | // ESM Bundle: Minified - Generating SDK.min.js 74 | { 75 | input: "src/SDK.ts", 76 | output: { 77 | file: "bin/esm/SDK.min.js", 78 | format: "esm", 79 | }, 80 | plugins: [ 81 | typescript({ tsconfig: "./tsconfig.esm.json" }), 82 | terser() 83 | ] 84 | }, 85 | // ESM Bundle: Minified - Generating XDM.min.js 86 | { 87 | input: "src/XDM.ts", 88 | output: { 89 | file: "bin/esm/XDM.min.js", 90 | format: "esm", 91 | }, 92 | plugins: [ 93 | typescript({ tsconfig: "./tsconfig.esm.json" }), 94 | terser() 95 | ] 96 | } 97 | ] 98 | -------------------------------------------------------------------------------- /src/SDK.ts: -------------------------------------------------------------------------------- 1 | import { channelManager } from "./XDM"; 2 | 3 | /** 4 | * Web SDK version number. Can be specified in an extension's set of demands like: vss-sdk-version/3.0 5 | */ 6 | export const sdkVersion = 4.0; 7 | 8 | const global = window as any; 9 | if (global._AzureDevOpsSDKVersion) { 10 | console.error("The AzureDevOps SDK is already loaded. Only one version of this module can be loaded in a given document."); 11 | } 12 | 13 | global._AzureDevOpsSDKVersion = sdkVersion; 14 | 15 | /** 16 | * Options for extension initialization -- passed to DevOps.init() 17 | */ 18 | export interface IExtensionInitOptions { 19 | /** 20 | * True (the default) indicates that the content of this extension is ready to be shown/used as soon as the 21 | * init handshake has completed. Otherwise (loaded: false), the extension must call DevOps.notifyLoadSucceeded() 22 | * once it has finished loading. 23 | */ 24 | loaded?: boolean; 25 | 26 | /** 27 | * Extensions that show UI should specify this to true in order for the current user's theme 28 | * to be applied to this extension content. Defaults to true. 29 | */ 30 | applyTheme?: boolean; 31 | } 32 | 33 | /** 34 | * Information about the current user 35 | */ 36 | export interface IUserContext { 37 | 38 | /** 39 | * Identity descriptor used to represent this user. In the format of {subject-type}.{base64-encoded-subject-id} 40 | */ 41 | descriptor: string; 42 | 43 | /** 44 | * Unique id for the user 45 | */ 46 | id: string; 47 | 48 | /** 49 | * Name of the user (email/login) 50 | */ 51 | name: string; 52 | 53 | /** 54 | * The user's display name (First name / Last name) 55 | */ 56 | displayName: string; 57 | 58 | /** 59 | * Url to the user's profile image 60 | */ 61 | imageUrl: string; 62 | } 63 | 64 | /** 65 | * DevOps host level 66 | */ 67 | export enum HostType { 68 | Unknown = 0, 69 | /** 70 | * The Deployment host 71 | */ 72 | Deployment = 1, 73 | 74 | /** 75 | * The Enterprise host 76 | */ 77 | Enterprise = 2, 78 | 79 | /** 80 | * The organization host 81 | */ 82 | Organization = 4 83 | } 84 | 85 | /** 86 | * Information about the current DevOps host (organization) 87 | */ 88 | export interface IHostContext { 89 | /** 90 | * Unique GUID for this host 91 | */ 92 | id: string; 93 | /** 94 | * Name of the host (i.e. Organization name) 95 | */ 96 | name: string; 97 | /** 98 | * Version of Azure DevOps used by the current host (organization) 99 | */ 100 | serviceVersion: string; 101 | /** 102 | * DevOps host level 103 | */ 104 | type: HostType; 105 | /** 106 | * Distinguish between Azure DevOps Services (true) and Azure DevOps Server (false) 107 | */ 108 | isHosted: boolean; 109 | } 110 | 111 | /** 112 | * Identifier for the current extension 113 | */ 114 | export interface IExtensionContext { 115 | /** 116 | * Full id of the extension . 117 | */ 118 | id: string; 119 | /** 120 | * Id of the publisher 121 | */ 122 | publisherId: string; 123 | /** 124 | * Id of the extension (without the publisher prefix) 125 | */ 126 | extensionId: string; 127 | /** 128 | * Version of the extension 129 | */ 130 | version: string; 131 | } 132 | 133 | /** 134 | * Information about the current DevOps team 135 | */ 136 | export interface ITeamContext { 137 | /** 138 | * Unique GUID for this team 139 | */ 140 | id: string; 141 | 142 | /** 143 | * Name of team 144 | */ 145 | name: string; 146 | } 147 | 148 | export interface GlobalizationContext { 149 | culture: string; 150 | /** 151 | * Gets the explicitly-set theme, or the empty string if a theme was not explicitly set. An explicitly-set theme is set either in the query string (?theme=[themename]) or in the user's profile. However, the default theme set in the profile is not considered to be an explicitly-set theme. 152 | */ 153 | explicitTheme: string; 154 | theme: string; 155 | timeZoneId: string; 156 | timezoneOffset: number; 157 | typeAheadDisabled: boolean; 158 | } 159 | 160 | interface DaylightSavingsAdjustmentEntry { 161 | /** 162 | * Millisecond adjustment from UTC 163 | */ 164 | offset: number; 165 | /** 166 | * Date that the offset adjustment starts 167 | */ 168 | start: Date; 169 | } 170 | 171 | interface TimeZonesConfiguration { 172 | daylightSavingsAdjustments: DaylightSavingsAdjustmentEntry[]; 173 | } 174 | 175 | /** 176 | * Global context placed on each web page 177 | */ 178 | export interface IPageContext { 179 | /** 180 | * Globalization data for the current page based on the current user's settings 181 | */ 182 | globalization: GlobalizationContext; 183 | /** 184 | * Contains global time zone configuration information (e.g. which dates DST changes) 185 | */ 186 | timeZonesConfiguration: TimeZonesConfiguration; 187 | /** 188 | * The web context information for the given page request 189 | */ 190 | webContext: IWebContext; 191 | } 192 | 193 | export interface ContextIdentifier { 194 | id: string; 195 | name: string; 196 | } 197 | 198 | /** 199 | * Context information for all web access requests 200 | */ 201 | interface IWebContext { 202 | /** 203 | * Information about the project used in the current request (may be null) 204 | */ 205 | project: ContextIdentifier; 206 | /** 207 | * Information about the team used in the current request (may be null) 208 | */ 209 | team: ITeamContext; 210 | } 211 | 212 | interface IExtensionHandshakeOptions extends IExtensionInitOptions { 213 | /** 214 | * Version number of this SDK 215 | */ 216 | sdkVersion: number; 217 | } 218 | 219 | interface IExtensionHandshakeResult { 220 | contributionId: string; 221 | context: { 222 | extension: IExtensionContext, 223 | pageContext: IPageContext, 224 | user: IUserContext, 225 | host: IHostContext 226 | }, 227 | initialConfig?: { [key: string]: any }; 228 | themeData?: { [key: string]: string }; 229 | } 230 | 231 | const hostControlId = "DevOps.HostControl"; 232 | const serviceManagerId = "DevOps.ServiceManager"; 233 | const parentChannel = channelManager.addChannel(window.parent); 234 | 235 | let teamContext: ITeamContext | undefined; 236 | let webContext: IWebContext | undefined;; 237 | let hostPageContext: IPageContext | undefined; 238 | let extensionContext: IExtensionContext | undefined; 239 | let initialConfiguration: { [key: string]: any } | undefined; 240 | let initialContributionId: string | undefined; 241 | let userContext: IUserContext | undefined; 242 | let hostContext: IHostContext | undefined; 243 | let themeElement: HTMLStyleElement; 244 | 245 | let resolveReady: () => void; 246 | const readyPromise = new Promise((resolve) => { 247 | resolveReady = resolve; 248 | }); 249 | 250 | /** 251 | * Register a method so that the host frame can invoke events 252 | */ 253 | function dispatchEvent(eventName: string, params: any) { 254 | const global = window as any; 255 | 256 | let evt; 257 | if (typeof global.CustomEvent === "function") { 258 | evt = new global.CustomEvent(eventName, params); 259 | } 260 | else { 261 | params = params || { bubbles: false, cancelable: false }; 262 | evt = document.createEvent('CustomEvent'); 263 | evt.initCustomEvent(eventName, params.bubbles, params.cancelable, params.detail); 264 | } 265 | 266 | window.dispatchEvent(evt); 267 | } 268 | parentChannel.getObjectRegistry().register("DevOps.SdkClient", { 269 | dispatchEvent: dispatchEvent 270 | }); 271 | 272 | /** 273 | * Initiates the handshake with the host window. 274 | * 275 | * @param options - Initialization options for the extension. 276 | */ 277 | export function init(options?: IExtensionInitOptions): Promise { 278 | 279 | return new Promise((resolve) => { 280 | 281 | const initOptions = { ...options, sdkVersion }; 282 | 283 | parentChannel.invokeRemoteMethod("initialHandshake", hostControlId, [initOptions]).then((handshakeData) => { 284 | const context = handshakeData.context; 285 | hostPageContext = context.pageContext; 286 | webContext = hostPageContext ? hostPageContext.webContext : undefined; 287 | teamContext = webContext ? webContext.team : undefined; 288 | 289 | initialConfiguration = handshakeData.initialConfig || {}; 290 | initialContributionId = handshakeData.contributionId; 291 | 292 | extensionContext = context.extension; 293 | userContext = context.user; 294 | hostContext = context.host; 295 | 296 | if (handshakeData.themeData) { 297 | applyTheme(handshakeData.themeData); 298 | 299 | window.addEventListener("themeChanged", (ev: any) => { 300 | applyTheme(ev.detail.data); 301 | }); 302 | } 303 | 304 | resolveReady(); 305 | resolve(); 306 | }); 307 | }); 308 | } 309 | 310 | /** 311 | * Register a callback that gets called once the initial setup/handshake has completed. 312 | * If the initial setup is already completed, the callback is invoked at the end of the current call stack. 313 | */ 314 | export async function ready(): Promise { 315 | return readyPromise; 316 | } 317 | 318 | /** 319 | * Notifies the host that the extension successfully loaded (stop showing the loading indicator) 320 | */ 321 | export function notifyLoadSucceeded(): Promise { 322 | return parentChannel.invokeRemoteMethod("notifyLoadSucceeded", hostControlId); 323 | } 324 | 325 | /** 326 | * Notifies the host that the extension failed to load 327 | */ 328 | export function notifyLoadFailed(e: Error | string): Promise { 329 | return parentChannel.invokeRemoteMethod("notifyLoadFailed", hostControlId, [e]); 330 | } 331 | 332 | function getWaitForReadyError(method: string): string { 333 | return `Attempted to call ${method}() before init() was complete. Wait for init to complete or place within a ready() callback.`; 334 | } 335 | 336 | /** 337 | * Get the configuration data passed in the initial handshake from the parent frame 338 | */ 339 | export function getConfiguration(): { [key: string]: any } { 340 | if (!initialConfiguration) { 341 | throw new Error(getWaitForReadyError("getConfiguration")); 342 | } 343 | return initialConfiguration; 344 | } 345 | 346 | /** 347 | * Gets the information about the contribution that first caused this extension to load. 348 | */ 349 | export function getContributionId(): string { 350 | if (!initialContributionId) { 351 | throw new Error(getWaitForReadyError("getContributionId")); 352 | } 353 | return initialContributionId; 354 | } 355 | 356 | /** 357 | * Gets information about the current user 358 | */ 359 | export function getUser(): IUserContext { 360 | if (!userContext) { 361 | throw new Error(getWaitForReadyError("getUser")); 362 | } 363 | return userContext; 364 | } 365 | 366 | /** 367 | * Gets information about the host (i.e. an Azure DevOps organization) that the page is targeting 368 | */ 369 | export function getHost(): IHostContext { 370 | if (!hostContext) { 371 | throw new Error(getWaitForReadyError("getHost")); 372 | } 373 | return hostContext; 374 | } 375 | 376 | /** 377 | * Get the context about the extension that owns the content that is being hosted 378 | */ 379 | export function getExtensionContext(): IExtensionContext { 380 | if (!extensionContext) { 381 | throw new Error(getWaitForReadyError("getExtensionContext")); 382 | } 383 | return extensionContext; 384 | } 385 | 386 | /** 387 | * Gets information about the team that the page is targeting 388 | */ 389 | export function getTeamContext(): ITeamContext { 390 | if (!teamContext) { 391 | throw new Error(getWaitForReadyError("getTeamContext")); 392 | } 393 | return teamContext; 394 | } 395 | 396 | /** 397 | * Get the context about the host page 398 | */ 399 | export function getPageContext(): IPageContext { 400 | if (!hostPageContext) { 401 | throw new Error(getWaitForReadyError("getPageContext")); 402 | } 403 | return hostPageContext; 404 | } 405 | 406 | /** 407 | * Get the context about the web 408 | */ 409 | export function getWebContext(): IWebContext { 410 | if (!webContext) { 411 | throw new Error(getWaitForReadyError("getWebContext")); 412 | } 413 | return webContext; 414 | } 415 | 416 | /** 417 | * Get the contribution with the given contribution id. The returned contribution has a method to get a registered object within that contribution. 418 | * 419 | * @param contributionId - Id of the contribution to get 420 | */ 421 | export async function getService(contributionId: string): Promise { 422 | return ready().then(() => { 423 | return parentChannel.invokeRemoteMethod("getService", serviceManagerId, [contributionId]); 424 | }); 425 | } 426 | 427 | /** 428 | * Register an object (instance or factory method) that this extension exposes to the host frame. 429 | * 430 | * @param instanceId - unique id of the registered object 431 | * @param instance - Either: (1) an object instance, or (2) a function that takes optional context data and returns an object instance. 432 | */ 433 | export function register(instanceId: string, instance: T): void { 434 | parentChannel.getObjectRegistry().register(instanceId, instance); 435 | } 436 | 437 | /** 438 | * Removes an object that this extension exposed to the host frame. 439 | * 440 | * @param instanceId - unique id of the registered object 441 | */ 442 | export function unregister(instanceId: string): void { 443 | parentChannel.getObjectRegistry().unregister(instanceId); 444 | } 445 | 446 | /** 447 | * Fetch an access token which will allow calls to be made to other DevOps services 448 | */ 449 | export async function getAccessToken(): Promise { 450 | return parentChannel.invokeRemoteMethod<{ token: string }>("getAccessToken", hostControlId).then((tokenObj) => { return tokenObj.token; }); 451 | } 452 | 453 | /** 454 | * Fetch an token which can be used to identify the current user 455 | */ 456 | export async function getAppToken(): Promise { 457 | return parentChannel.invokeRemoteMethod<{ token: string }>("getAppToken", hostControlId).then((tokenObj) => { return tokenObj.token; }); 458 | } 459 | 460 | /** 461 | * Requests the parent window to resize the container for this extension based on the current extension size. 462 | * 463 | * @param width - Optional width, defaults to scrollWidth 464 | * @param height - Optional height, defaults to scrollHeight 465 | */ 466 | export function resize(width?: number, height?: number): void { 467 | const body = document.body; 468 | if (body) { 469 | const newWidth = typeof width === "number" ? width : (body ? body.scrollWidth : undefined); 470 | const newHeight = typeof height === "number" ? height : (body ? body.scrollHeight : undefined); 471 | parentChannel.invokeRemoteMethod("resize", hostControlId, [newWidth, newHeight]); 472 | } 473 | } 474 | 475 | /** 476 | * Applies theme variables to the current document 477 | */ 478 | export function applyTheme(themeData: { [varName: string]: string }): void { 479 | 480 | if (!themeElement) { 481 | themeElement = document.createElement("style"); 482 | themeElement.type = "text/css"; 483 | document.head!.appendChild(themeElement); 484 | } 485 | 486 | const cssVariables: string[] = []; 487 | if (themeData) { 488 | for (const varName in themeData) { 489 | cssVariables.push("--" + varName + ": " + themeData[varName]); 490 | } 491 | } 492 | 493 | themeElement.innerText = ":root { " + cssVariables.join("; ") + " } body { color: var(--text-primary-color) }"; 494 | 495 | dispatchEvent("themeApplied", { detail: themeData }); 496 | } -------------------------------------------------------------------------------- /src/XDM.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Interface for a single XDM channel 3 | */ 4 | export interface IXDMChannel { 5 | 6 | /** 7 | * Invoke a method via RPC. Lookup the registered object on the remote end of the channel and invoke the specified method. 8 | * 9 | * @param method - Name of the method to invoke 10 | * @param instanceId - unique id of the registered object 11 | * @param params - Arguments to the method to invoke 12 | * @param instanceContextData - Optional context data to pass to a registered object's factory method 13 | */ 14 | invokeRemoteMethod(methodName: string, instanceId: string, params?: any[], instanceContextData?: Object): Promise; 15 | 16 | /** 17 | * Get a proxied object that represents the object registered with the given instance id on the remote side of this channel. 18 | * 19 | * @param instanceId - unique id of the registered object 20 | * @param contextData - Optional context data to pass to a registered object's factory method 21 | */ 22 | getRemoteObjectProxy(instanceId: string, contextData?: Object): Promise; 23 | 24 | /** 25 | * Get the object registry to handle messages from this specific channel. 26 | * Upon receiving a message, this channel registry will be used first, then 27 | * the global registry will be used if no handler is found here. 28 | */ 29 | getObjectRegistry(): IXDMObjectRegistry; 30 | } 31 | 32 | /** 33 | * Registry of XDM channels kept per target frame/window 34 | */ 35 | export interface IXDMChannelManager { 36 | 37 | /** 38 | * Add an XDM channel for the given target window/iframe 39 | * 40 | * @param window - Target iframe window to communicate with 41 | * @param targetOrigin - Url of the target iframe (if known) 42 | */ 43 | addChannel(window: Window, targetOrigin?: string): IXDMChannel; 44 | 45 | /** 46 | * Removes an XDM channel, allowing it to be disposed 47 | * 48 | * @param channel - The channel to remove from the channel manager 49 | */ 50 | removeChannel(channel: IXDMChannel): void; 51 | } 52 | 53 | /** 54 | * Registry of XDM objects that can be invoked by an XDM channel 55 | */ 56 | export interface IXDMObjectRegistry { 57 | 58 | /** 59 | * Register an object (instance or factory method) exposed by this frame to callers in a remote frame 60 | * 61 | * @param instanceId - unique id of the registered object 62 | * @param instance - Either: (1) an object instance, or (2) a function that takes optional context data and returns an object instance. 63 | */ 64 | register(instanceId: string, instance: Object | { (contextData?: any): Object; }): void; 65 | 66 | /** 67 | * Unregister an object (instance or factory method) that was previously registered by this frame 68 | * 69 | * @param instanceId - unique id of the registered object 70 | */ 71 | unregister(instanceId: string): void; 72 | 73 | /** 74 | * Get an instance of an object registered with the given id 75 | * 76 | * @param instanceId - unique id of the registered object 77 | * @param contextData - Optional context data to pass to the contructor of an object factory method 78 | */ 79 | getInstance(instanceId: string, contextData?: Object): T | undefined; 80 | } 81 | 82 | 83 | /** 84 | * Settings related to the serialization of data across iframe boundaries. 85 | */ 86 | export interface ISerializationSettings { 87 | 88 | /** 89 | * By default, properties that begin with an underscore are not serialized across 90 | * the iframe boundary. Set this option to true to serialize such properties. 91 | */ 92 | includeUnderscoreProperties: boolean; 93 | } 94 | 95 | /** 96 | * Represents a remote procedure call (rpc) between frames. 97 | */ 98 | export interface IJsonRpcMessage { 99 | id: number; 100 | instanceId?: string; 101 | instanceContext?: Object; 102 | methodName?: string; 103 | params?: any[]; // if method is present then params should be present 104 | result?: any; // method, result, and error are mutucally exclusive. method is set for requrests, result and error are for responses 105 | error?: any; 106 | handshakeToken?: string; 107 | serializationSettings?: ISerializationSettings; 108 | } 109 | 110 | const smallestRandom = parseInt("10000000000", 36); 111 | const maxSafeInteger: number = (Number).MAX_SAFE_INTEGER || 9007199254740991; 112 | 113 | /** 114 | * Create a new random 22-character fingerprint. 115 | * @return string fingerprint 116 | */ 117 | function newFingerprint() { 118 | // smallestRandom ensures we will get a 11-character result from the base-36 conversion. 119 | return Math.floor((Math.random() * (maxSafeInteger - smallestRandom)) + smallestRandom).toString(36) + 120 | Math.floor((Math.random() * (maxSafeInteger - smallestRandom)) + smallestRandom).toString(36); 121 | } 122 | 123 | /** 124 | * Gets all own and inherited property names of the given object, excluding 125 | * those that are inherited from Object's prototype and "constructor". 126 | * @param obj 127 | */ 128 | function getAllPropertyNames(obj: any) { 129 | const properties: { [key: string]: true } = {}; 130 | while (obj && obj !== Object.prototype) { 131 | const ownPropertyNames = Object.getOwnPropertyNames(obj); 132 | for (const name of ownPropertyNames) { 133 | if (name !== "constructor") { 134 | properties[name] = true; 135 | } 136 | } 137 | obj = Object.getPrototypeOf(obj); 138 | } 139 | 140 | return properties; 141 | } 142 | 143 | /** 144 | * Catalog of objects exposed for XDM 145 | */ 146 | export class XDMObjectRegistry implements IXDMObjectRegistry { 147 | 148 | private objects: any = {}; 149 | 150 | /** 151 | * Register an object (instance or factory method) exposed by this frame to callers in a remote frame 152 | * 153 | * @param instanceId - unique id of the registered object 154 | * @param instance - Either: (1) an object instance, or (2) a function that takes optional context data and returns an object instance. 155 | */ 156 | public register(instanceId: string, instance: Object | { (contextData?: any): Object; }) { 157 | this.objects[instanceId] = instance; 158 | } 159 | 160 | /** 161 | * Unregister an object (instance or factory method) that was previously registered by this frame 162 | * 163 | * @param instanceId - unique id of the registered object 164 | */ 165 | public unregister(instanceId: string) { 166 | delete this.objects[instanceId]; 167 | } 168 | 169 | /** 170 | * Get an instance of an object registered with the given id 171 | * 172 | * @param instanceId - unique id of the registered object 173 | * @param contextData - Optional context data to pass to a registered object's factory method 174 | */ 175 | public getInstance(instanceId: string, contextData?: Object): T | undefined { 176 | var instance = this.objects[instanceId]; 177 | if (!instance) { 178 | return undefined; 179 | } 180 | 181 | if (typeof instance === "function") { 182 | return instance(contextData); 183 | } 184 | else { 185 | return instance; 186 | } 187 | } 188 | } 189 | 190 | const MAX_XDM_DEPTH = 100; 191 | let nextChannelId = 1; 192 | 193 | /** 194 | * Represents a channel of communication between frames\document 195 | * Stays "alive" across multiple funtion\method calls 196 | */ 197 | export class XDMChannel implements IXDMChannel { 198 | 199 | private promises: { [id: number]: { resolve: Function, reject: Function } } = {}; 200 | private postToWindow: Window; 201 | private targetOrigin: string | undefined; 202 | private handshakeToken: string | undefined; 203 | private registry: XDMObjectRegistry; 204 | private channelId: number; 205 | 206 | private nextMessageId: number = 1; 207 | private nextProxyId: number = 1; 208 | private proxyFunctions: { [name: string]: Function } = {}; 209 | 210 | constructor(postToWindow: Window, targetOrigin?: string) { 211 | 212 | this.postToWindow = postToWindow; 213 | this.targetOrigin = targetOrigin; 214 | this.registry = new XDMObjectRegistry(); 215 | this.channelId = nextChannelId++; 216 | 217 | if (!this.targetOrigin) { 218 | this.handshakeToken = newFingerprint(); 219 | } 220 | } 221 | 222 | /** 223 | * Get the object registry to handle messages from this specific channel. 224 | * Upon receiving a message, this channel registry will be used first, then 225 | * the global registry will be used if no handler is found here. 226 | */ 227 | public getObjectRegistry(): IXDMObjectRegistry { 228 | return this.registry; 229 | } 230 | 231 | /** 232 | * Invoke a method via RPC. Lookup the registered object on the remote end of the channel and invoke the specified method. 233 | * 234 | * @param method - Name of the method to invoke 235 | * @param instanceId - unique id of the registered object 236 | * @param params - Arguments to the method to invoke 237 | * @param instanceContextData - Optional context data to pass to a registered object's factory method 238 | * @param serializationSettings - Optional serialization settings 239 | */ 240 | public async invokeRemoteMethod(methodName: string, instanceId: string, params?: any[], instanceContextData?: Object, serializationSettings?: ISerializationSettings): Promise { 241 | 242 | const message: IJsonRpcMessage = { 243 | id: this.nextMessageId++, 244 | methodName: methodName, 245 | instanceId: instanceId, 246 | instanceContext: instanceContextData, 247 | params: this._customSerializeObject(params, serializationSettings), 248 | serializationSettings: serializationSettings 249 | }; 250 | 251 | if (!this.targetOrigin) { 252 | message.handshakeToken = this.handshakeToken; 253 | } 254 | 255 | const promise = new Promise((resolve, reject) => { 256 | this.promises[message.id] = { resolve, reject }; 257 | }); 258 | 259 | this._sendRpcMessage(message); 260 | 261 | return promise; 262 | } 263 | 264 | /** 265 | * Get a proxied object that represents the object registered with the given instance id on the remote side of this channel. 266 | * 267 | * @param instanceId - unique id of the registered object 268 | * @param contextData - Optional context data to pass to a registered object's factory method 269 | */ 270 | public getRemoteObjectProxy(instanceId: string, contextData?: Object): Promise { 271 | return this.invokeRemoteMethod("", instanceId, undefined, contextData); 272 | } 273 | 274 | private invokeMethod(registeredInstance: any, rpcMessage: IJsonRpcMessage) { 275 | 276 | if (!rpcMessage.methodName) { 277 | // Null/empty method name indicates to return the registered object itself. 278 | this._success(rpcMessage, registeredInstance, rpcMessage.handshakeToken); 279 | return; 280 | } 281 | 282 | var method: Function = registeredInstance[rpcMessage.methodName]; 283 | if (typeof method !== "function") { 284 | this.error(rpcMessage, new Error("RPC method not found: " + rpcMessage.methodName)); 285 | return; 286 | } 287 | 288 | try { 289 | // Call specified method. Add nested success and error call backs with closure 290 | // so we can post back a response as a result or error as appropriate 291 | var methodArgs = []; 292 | if (rpcMessage.params) { 293 | methodArgs = this._customDeserializeObject(rpcMessage.params, {}); 294 | } 295 | 296 | var result = method.apply(registeredInstance, methodArgs); 297 | if (result && result.then && typeof result.then === "function") { 298 | result.then((asyncResult: any) => { 299 | this._success(rpcMessage, asyncResult, rpcMessage.handshakeToken); 300 | }, (e: any) => { 301 | this.error(rpcMessage, e); 302 | }); 303 | } 304 | else { 305 | this._success(rpcMessage, result, rpcMessage.handshakeToken); 306 | } 307 | } 308 | catch (exception) { 309 | // send back as error if an exception is thrown 310 | this.error(rpcMessage, exception as Error); 311 | } 312 | } 313 | 314 | private getRegisteredObject(instanceId: string, instanceContext?: Object): Object | undefined { 315 | 316 | if (instanceId === "__proxyFunctions") { 317 | // Special case for proxied functions of remote instances 318 | return this.proxyFunctions; 319 | } 320 | 321 | // Look in the channel registry first 322 | var registeredObject = this.registry.getInstance(instanceId, instanceContext); 323 | if (!registeredObject) { 324 | // Look in the global registry as a fallback 325 | registeredObject = globalObjectRegistry.getInstance(instanceId, instanceContext); 326 | } 327 | 328 | return registeredObject as Object; 329 | } 330 | 331 | /** 332 | * Handle a received message on this channel. Dispatch to the appropriate object found via object registry 333 | * 334 | * @param rpcMessage - Message data 335 | * @return True if the message was handled by this channel. Otherwise false. 336 | */ 337 | public onMessage(rpcMessage: IJsonRpcMessage): boolean { 338 | 339 | if (rpcMessage.instanceId) { 340 | // Find the object that handles this requestNeed to find implementation 341 | 342 | // Look in the channel registry first 343 | const registeredObject: any = this.getRegisteredObject(rpcMessage.instanceId, rpcMessage.instanceContext); 344 | if (!registeredObject) { 345 | // If not found return false to indicate that the message was not handled 346 | return false; 347 | } 348 | 349 | if (typeof registeredObject["then"] === "function") { 350 | (>registeredObject).then((resolvedInstance) => { 351 | this.invokeMethod(resolvedInstance, rpcMessage); 352 | }, (e) => { 353 | this.error(rpcMessage, e); 354 | }); 355 | } 356 | else { 357 | this.invokeMethod(registeredObject, rpcMessage); 358 | } 359 | } 360 | else { 361 | const promise = this.promises[rpcMessage.id]; 362 | if (!promise) { 363 | // Message not handled by this channel. 364 | return false; 365 | } 366 | 367 | if (rpcMessage.error) { 368 | promise.reject(this._customDeserializeObject([rpcMessage.error], {})[0]); 369 | } 370 | else { 371 | promise.resolve(this._customDeserializeObject([rpcMessage.result], {})[0]); 372 | } 373 | 374 | delete this.promises[rpcMessage.id]; 375 | } 376 | 377 | // Message handled by this channel 378 | return true; 379 | } 380 | 381 | public owns(source: Window, origin: string, rpcMessage: IJsonRpcMessage): boolean { 382 | /// Determines whether the current message belongs to this channel or not 383 | if (this.postToWindow === source) { 384 | // For messages coming from sandboxed iframes the origin will be set to the string "null". This is 385 | // how onprem works. If it is not a sandboxed iFrame we will get the origin as expected. 386 | if (this.targetOrigin) { 387 | if (origin) { 388 | return origin.toLowerCase() === "null" || this.targetOrigin.toLowerCase().indexOf(origin.toLowerCase()) === 0; 389 | } else { 390 | return false; 391 | } 392 | } 393 | else { 394 | if (rpcMessage.handshakeToken && rpcMessage.handshakeToken === this.handshakeToken) { 395 | this.targetOrigin = origin; 396 | return true; 397 | } 398 | } 399 | } 400 | return false; 401 | } 402 | 403 | public error(messageObj: IJsonRpcMessage, errorObj: Error) { 404 | this._sendRpcMessage({ 405 | id: messageObj.id, 406 | error: this._customSerializeObject([errorObj], messageObj.serializationSettings)[0], 407 | handshakeToken: messageObj.handshakeToken 408 | }); 409 | } 410 | 411 | private _success(messageObj: IJsonRpcMessage, result: any, handshakeToken?: string) { 412 | this._sendRpcMessage({ 413 | id: messageObj.id, 414 | result: this._customSerializeObject([result], messageObj.serializationSettings)[0], 415 | handshakeToken 416 | }); 417 | } 418 | 419 | private _sendRpcMessage(message: IJsonRpcMessage) { 420 | this.postToWindow.postMessage(JSON.stringify(message), "*"); 421 | } 422 | 423 | private _customSerializeObject(obj: Object | undefined, settings: ISerializationSettings | undefined, prevParentObjects?: { originalObjects: any[]; newObjects: any[]; }, nextCircularRefId: number = 1, depth: number = 1): any | undefined { 424 | 425 | if (!obj || depth > MAX_XDM_DEPTH) { 426 | return undefined; 427 | } 428 | 429 | if (obj instanceof Node || obj instanceof Window || obj instanceof Event) { 430 | return undefined; 431 | } 432 | 433 | var returnValue: any; 434 | 435 | let parentObjects: { originalObjects: any[]; newObjects: any[]; }; 436 | if (!prevParentObjects) { 437 | parentObjects = { 438 | newObjects: [], 439 | originalObjects: [] 440 | }; 441 | } 442 | else { 443 | parentObjects = prevParentObjects; 444 | } 445 | 446 | parentObjects.originalObjects.push(obj); 447 | 448 | var serializeMember = (parentObject: any, newObject: any, key: any) => { 449 | var item; 450 | 451 | try { 452 | item = parentObject[key]; 453 | } 454 | catch (ex) { 455 | // Cannot access this property. Skip its serialization. 456 | } 457 | 458 | var itemType = typeof item; 459 | if (itemType === "undefined") { 460 | return; 461 | } 462 | 463 | // Check for a circular reference by looking at parent objects 464 | var parentItemIndex = -1; 465 | if (itemType === "object") { 466 | parentItemIndex = parentObjects.originalObjects.indexOf(item); 467 | } 468 | if (parentItemIndex >= 0) { 469 | // Circular reference found. Add reference to parent 470 | var parentItem = parentObjects.newObjects[parentItemIndex]; 471 | if (!parentItem.__circularReferenceId) { 472 | parentItem.__circularReferenceId = nextCircularRefId++; 473 | } 474 | newObject[key] = { 475 | __circularReference: parentItem.__circularReferenceId 476 | }; 477 | } 478 | else { 479 | if (itemType === "function") { 480 | var proxyFunctionId = this.nextProxyId++; 481 | newObject[key] = { 482 | __proxyFunctionId: this._registerProxyFunction(item, obj), 483 | _channelId: this.channelId 484 | }; 485 | } 486 | else if (itemType === "object") { 487 | if (item && item instanceof Date) { 488 | newObject[key] = { 489 | __proxyDate: item.getTime() 490 | }; 491 | } 492 | else { 493 | newObject[key] = this._customSerializeObject(item, settings, parentObjects, nextCircularRefId, depth + 1); 494 | } 495 | } 496 | else if (key !== "__proxyFunctionId") { 497 | // Just add non object/function properties as-is. Don't include "__proxyFunctionId" to protect 498 | // our proxy methods from being invoked from other messages. 499 | newObject[key] = item; 500 | } 501 | } 502 | }; 503 | 504 | if (obj instanceof Array) { 505 | 506 | returnValue = []; 507 | parentObjects.newObjects.push(returnValue); 508 | 509 | for (var i = 0, l = obj.length; i < l; i++) { 510 | serializeMember(obj, returnValue, i); 511 | } 512 | } 513 | else { 514 | returnValue = {}; 515 | parentObjects.newObjects.push(returnValue); 516 | 517 | let keys: { [key: string]: true } = {}; 518 | try { 519 | keys = getAllPropertyNames(obj); 520 | } catch (ex) { 521 | // We may not be able to access the iterator of this object. Skip its serialization. 522 | } 523 | 524 | for (var key in keys) { 525 | // Don't serialize properties that start with an underscore. 526 | if ((key && key[0] !== "_") || (settings && settings.includeUnderscoreProperties)) { 527 | serializeMember(obj, returnValue, key); 528 | } 529 | } 530 | } 531 | 532 | parentObjects.originalObjects.pop(); 533 | parentObjects.newObjects.pop(); 534 | 535 | return returnValue; 536 | } 537 | 538 | private _registerProxyFunction(func: Function, context: any): number { 539 | var proxyFunctionId = this.nextProxyId++; 540 | this.proxyFunctions["proxy" + proxyFunctionId] = function () { 541 | return func.apply(context, Array.prototype.slice.call(arguments, 0)); 542 | }; 543 | return proxyFunctionId; 544 | } 545 | 546 | private _customDeserializeObject(obj: Object, circularRefs: { [key: number]: Object }): any { 547 | var that = this; 548 | 549 | if (!obj) { 550 | return null; 551 | } 552 | 553 | var deserializeMember = (parentObject: any, key: any) => { 554 | var item = parentObject[key]; 555 | var itemType = typeof item; 556 | 557 | if (key === "__circularReferenceId" && itemType === 'number') { 558 | circularRefs[item] = parentObject; 559 | delete parentObject[key]; 560 | } 561 | else if (itemType === "object" && item) { 562 | 563 | if (item.__proxyFunctionId) { 564 | parentObject[key] = function () { 565 | return that.invokeRemoteMethod("proxy" + item.__proxyFunctionId, "__proxyFunctions", Array.prototype.slice.call(arguments, 0), {}, { includeUnderscoreProperties: true }); 566 | } 567 | } 568 | else if (item.__proxyDate) { 569 | parentObject[key] = new Date(item.__proxyDate); 570 | } 571 | else if (item.__circularReference) { 572 | parentObject[key] = circularRefs[item.__circularReference]; 573 | } 574 | else { 575 | this._customDeserializeObject(item, circularRefs); 576 | } 577 | } 578 | }; 579 | 580 | if (obj instanceof Array) { 581 | for (var i = 0, l = obj.length; i < l; i++) { 582 | deserializeMember(obj, i); 583 | } 584 | } 585 | else if (typeof obj === "object") { 586 | for (var key in obj) { 587 | deserializeMember(obj, key); 588 | } 589 | } 590 | 591 | return obj; 592 | } 593 | } 594 | 595 | /** 596 | * Registry of XDM channels kept per target frame/window 597 | */ 598 | class XDMChannelManager implements IXDMChannelManager { 599 | 600 | private _channels: XDMChannel[] = []; 601 | 602 | constructor() { 603 | window.addEventListener("message", this._handleMessageReceived); 604 | } 605 | 606 | /** 607 | * Add an XDM channel for the given target window/iframe 608 | * 609 | * @param window - Target iframe window to communicate with 610 | * @param targetOrigin - Url of the target iframe (if known) 611 | */ 612 | public addChannel(window: Window, targetOrigin?: string): IXDMChannel { 613 | const channel = new XDMChannel(window, targetOrigin); 614 | this._channels.push(channel); 615 | return channel; 616 | } 617 | 618 | public removeChannel(channel: IXDMChannel) { 619 | this._channels = this._channels.filter(c => c !== channel); 620 | } 621 | 622 | private _handleMessageReceived = (event: any) => { 623 | // get channel and dispatch to it 624 | let rpcMessage: IJsonRpcMessage | undefined; 625 | 626 | if (typeof event.data === "string") { 627 | try { 628 | rpcMessage = JSON.parse(event.data); 629 | } 630 | catch (error) { 631 | // The message is not a valid JSON string. Not one of our events. 632 | } 633 | } 634 | 635 | if (rpcMessage) { 636 | let handled = false; 637 | let channelOwner: XDMChannel | undefined; 638 | 639 | for (const channel of this._channels) { 640 | if (channel.owns(event.source, event.origin, rpcMessage)) { 641 | // keep a reference to the channel owner found. 642 | channelOwner = channel; 643 | handled = channel.onMessage(rpcMessage) || handled; 644 | } 645 | } 646 | 647 | if (channelOwner && !handled) { 648 | if (window.console) { 649 | console.error(`No handler found on any channel for message: ${JSON.stringify(rpcMessage)}`); 650 | } 651 | 652 | // for instance based proxies, send an error on the channel owning the message to resolve any control creation promises 653 | // on the host frame. 654 | if (rpcMessage.instanceId) { 655 | channelOwner.error(rpcMessage, new Error(`The registered object ${rpcMessage.instanceId} could not be found.`)); 656 | } 657 | } 658 | } 659 | } 660 | } 661 | 662 | /** 663 | * The registry of global XDM handlers 664 | */ 665 | export const globalObjectRegistry: IXDMObjectRegistry = new XDMObjectRegistry(); 666 | 667 | /** 668 | * Manages XDM channels per target window/frame 669 | */ 670 | export const channelManager: IXDMChannelManager = new XDMChannelManager(); -------------------------------------------------------------------------------- /tsconfig.amd.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "declaration": true, 5 | "declarationDir": "bin" 6 | } 7 | } -------------------------------------------------------------------------------- /tsconfig.esm.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "target": "ES2022", 5 | "module": "ESNext", 6 | "declaration": true, 7 | "declarationDir": "bin/esm" 8 | } 9 | } -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "rootDir": "src/", 5 | "experimentalDecorators": true, 6 | "moduleResolution": "node", 7 | "noImplicitAny": true, 8 | "noImplicitThis": true, 9 | "strict": true, 10 | "lib": [ 11 | "es5", 12 | "es6", 13 | "dom" 14 | ] 15 | }, 16 | "exclude": [ 17 | "node_modules" 18 | ] 19 | } --------------------------------------------------------------------------------