├── .editorconfig ├── .github └── workflows │ ├── build.yml │ └── prettier.yml ├── .gitignore ├── .npmrc ├── .nvmrc ├── .prettierrc ├── LICENSE ├── README.md ├── media ├── icon-mac.png └── icon.png ├── package.json ├── pnpm-lock.yaml ├── screenshots ├── screenshot1.png └── screenshot2.png ├── src ├── BaseObserver.ts ├── ConfigEngine.ts ├── DisplayEngine.ts ├── PointerEngine.ts ├── RobotEngine.ts ├── main.ts ├── menu.ts └── permissions.ts └── tsconfig.json /.editorconfig: -------------------------------------------------------------------------------- 1 | [*] 2 | indent_style = space 3 | indent_size = 2 4 | trim_trailing_whitespace = true 5 | max_line_length = 120 -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build/release 2 | 3 | on: push 4 | 5 | jobs: 6 | release: 7 | runs-on: ${{ matrix.os }} 8 | 9 | strategy: 10 | matrix: 11 | os: [macos-latest] 12 | 13 | steps: 14 | - name: Check out Git repository 15 | uses: actions/checkout@v1 16 | 17 | - name: Read .nvmrc 18 | run: echo "##[set-output name=NVMRC;]$(cat .nvmrc)" 19 | id: nvm 20 | 21 | - name: Use Node.js (.nvmrc) 22 | uses: actions/setup-node@v2 23 | with: 24 | node-version: "${{ steps.nvm.outputs.NVMRC }}" 25 | 26 | - name: Install PNPM 27 | uses: pnpm/action-setup@v2 28 | with: 29 | version: latest 30 | 31 | - name: 'Some tooling for GYP libs' 32 | run: sudo -H pip install setuptools 33 | 34 | - name: PNPM install 35 | run: pnpm install 36 | 37 | - name: Build/release Electron app 38 | uses: paneron/action-electron-builder@v1.8.1 39 | with: 40 | package_manager: "pnpm" 41 | # GitHub token, automatically provided to the action 42 | # (No need to define this secret in the repo settings) 43 | github_token: ${{ secrets.github_token }} 44 | 45 | # If the commit is tagged with a version (e.g. "v1.0.0"), 46 | # release the app after building 47 | release: ${{ startsWith(github.ref, 'refs/tags/v') }} -------------------------------------------------------------------------------- /.github/workflows/prettier.yml: -------------------------------------------------------------------------------- 1 | name: Prettier check 2 | 3 | # This action works with pull requests and pushes 4 | on: 5 | pull_request: 6 | 7 | jobs: 8 | prettier: 9 | runs-on: ubuntu-latest 10 | 11 | steps: 12 | - name: Checkout 13 | uses: actions/checkout@v2 14 | with: 15 | # Make sure the actual branch is checked out when running on pull requests 16 | ref: ${{ github.head_ref }} 17 | 18 | 19 | - uses: actions/checkout@v2 # Check out the repository first. 20 | - uses: creyD/prettier_action@v4.3 21 | with: 22 | # prettier CLI arguments. 23 | dry: true 24 | prettier_options: --check --config .prettierrc 'src/**/*.{ts,tsx}' -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | dist_electron 4 | .idea 5 | .DS_Store 6 | *.log -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | shamefully-hoist=true -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | v20.10.0 -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "semi": true, 3 | "singleQuote": true, 4 | "tabWidth": 2, 5 | "useTabs": false, 6 | "printWidth": 120, 7 | "trailingComma": "none" 8 | } 9 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Storm 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. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DynaMouse 2 | 3 | ![](./media/icon-mac.png) 4 | 5 | ## Intro 6 | 7 | Finally, a system for Mac that allows you to have multiple mice, multiple monitors and assign each to one another. 8 | While Mac allows for multiple mice plugged-in at the same time, it doesn't allow multiple _cursors_ at the same time. 9 | 10 | DynaMouse allows you to assign a specific display to a dedicated mouse device (including the built-in mac trackpads) so that when you have multiple screens in a studio-like/complex workstation setup (and far apart from each other), you don't have to drag your mouse over to the other screen. 11 | 12 | Behold: 13 | 14 | ![](screenshots/screenshot1.png) 15 | ![](screenshots/screenshot2.png) 16 | 17 | When you first start DynaMouse and start configuring it, you will be asked to enable Accessibility permissions in System Preferences so that DynaMouse can monitor usb pointer devices and also control the mouse position on the screen. Dynamouse will wait for these permissions to be enabled before continuing to boot up :) 18 | 19 | ## Features 20 | 21 | * Works as a system tray, doesn't appear in the dock 22 | * Supports infinite monitors and pointer devices 23 | * Assign multiple mice to the same monitor 24 | * Configure specific mice to be uncontrolled (not governed by DynaMouse) 25 | * Each mouse's position is remembered on each screen 26 | * Non-obtrusive: doesn't lock the mouse to screen bounds, i.e. you can still drag a mouse to a different screen. 27 | * Can be configured to launch on login. 28 | * Can handle usb devices being attached / detached 29 | * Specify a startup delay (useful when various devices are busy booting up after login) 30 | 31 | ## Devices tested 32 | 33 | The devices below have been tested and work: 34 | 35 | * Corsair HARPOON RGB Gaming Mouse 36 | * Corsair HARPOON Wireless RGB Gaming Mouse 37 | * Apple magic trackpad (‎MMMP3AM/A) 38 | * M1 Macbook trackpad 39 | 40 | ## Troubleshooting 41 | 42 | * You can enable file logging which will log to `~/Library/Logs/@projectstorm/Dynamouse` (this can help with submitting an issue) 43 | * Apple startup items seem use the exact binary at the time of installation, so if you are updating to a newer version, try disabling and re-enabling startup mode to install the newer version of the software 44 | * You may need to remove and re-add Dynamouse accessibility permissions across versions (but I seem to no longer run into this after version 1.0.0) 45 | 46 | ## Development 47 | 48 | 1. `pnpm install` 49 | 2. `pnpm watch` 50 | 3. `pnpm start` 51 | 52 | ### Releasing 53 | 54 | Binaries are auto-created and a release is published when a new tag is pushed to master. 55 | -------------------------------------------------------------------------------- /media/icon-mac.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/projectstorm/dynamouse/bc6fca042a315eb7f85f057b9819b0fd8100ae6f/media/icon-mac.png -------------------------------------------------------------------------------- /media/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/projectstorm/dynamouse/bc6fca042a315eb7f85f057b9819b0fd8100ae6f/media/icon.png -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@projectstorm/dynamouse", 3 | "license": "MIT", 4 | "main": "dist/main.js", 5 | "description": "Mouse and Display assignment for mac", 6 | "version": "1.1.0", 7 | "author": { 8 | "name": "Dylan Vorster", 9 | "url": "dylanvorster.com" 10 | }, 11 | "scripts": { 12 | "build": "tsc", 13 | "watch": "tsc --watch", 14 | "start": "electron .", 15 | "format": "prettier --config .prettierrc --write \"src/**/*.{ts,tsx}\"", 16 | "app:dir": "electron-builder --dir", 17 | "app:dist": "electron-builder", 18 | "prepare": "rm -rf node_modules/electron/dist && node node_modules/electron/install.js" 19 | }, 20 | "build": { 21 | "directories": { 22 | "output": "dist_electron" 23 | }, 24 | "files": [ 25 | "media/*", 26 | "dist/*" 27 | ], 28 | "productName": "DynaMouse", 29 | "appId": "projectstorm.dynamouse", 30 | "mac": { 31 | "icon": "./media/icon.png", 32 | "category": "public.app-category.utilities" 33 | } 34 | }, 35 | "dependencies": { 36 | "@jitsi/robotjs": "^0.6.13", 37 | "auto-launch": "^5.0.6", 38 | "async": "^3.2.5", 39 | "electron-json-storage": "^4.6.0", 40 | "lodash": "^4.17.21", 41 | "node-hid": "^3.0.0", 42 | "source-map-support": "^0.5.21", 43 | "usb": "^2.11.0", 44 | "uuid": "^9.0.1", 45 | "winston": "^3.11.0", 46 | "node-mac-permissions": "^2.3.0" 47 | }, 48 | "devDependencies": { 49 | "@types/async": "^3.2.24", 50 | "@types/auto-launch": "^5.0.5", 51 | "@types/electron-json-storage": "^4.5.4", 52 | "@types/lodash": "^4.14.202", 53 | "@types/node": "^20.11.20", 54 | "@types/uuid": "^9.0.8", 55 | "electron": "^29.0.1", 56 | "electron-builder": "^24.12.0", 57 | "prettier": "^3.2.5", 58 | "typescript": "^5.3.3", 59 | "husky": "^9.0.11" 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /pnpm-lock.yaml: -------------------------------------------------------------------------------- 1 | lockfileVersion: '6.0' 2 | 3 | settings: 4 | autoInstallPeers: true 5 | excludeLinksFromLockfile: false 6 | 7 | dependencies: 8 | '@jitsi/robotjs': 9 | specifier: ^0.6.13 10 | version: 0.6.13 11 | async: 12 | specifier: ^3.2.5 13 | version: 3.2.5 14 | auto-launch: 15 | specifier: ^5.0.6 16 | version: 5.0.6 17 | electron-json-storage: 18 | specifier: ^4.6.0 19 | version: 4.6.0 20 | lodash: 21 | specifier: ^4.17.21 22 | version: 4.17.21 23 | node-hid: 24 | specifier: ^3.0.0 25 | version: 3.0.0 26 | node-mac-permissions: 27 | specifier: ^2.3.0 28 | version: 2.3.0 29 | source-map-support: 30 | specifier: ^0.5.21 31 | version: 0.5.21 32 | usb: 33 | specifier: ^2.11.0 34 | version: 2.11.0 35 | uuid: 36 | specifier: ^9.0.1 37 | version: 9.0.1 38 | winston: 39 | specifier: ^3.11.0 40 | version: 3.11.0 41 | 42 | devDependencies: 43 | '@types/async': 44 | specifier: ^3.2.24 45 | version: 3.2.24 46 | '@types/auto-launch': 47 | specifier: ^5.0.5 48 | version: 5.0.5 49 | '@types/electron-json-storage': 50 | specifier: ^4.5.4 51 | version: 4.5.4 52 | '@types/lodash': 53 | specifier: ^4.14.202 54 | version: 4.14.202 55 | '@types/node': 56 | specifier: ^20.11.20 57 | version: 20.11.20 58 | '@types/uuid': 59 | specifier: ^9.0.8 60 | version: 9.0.8 61 | electron: 62 | specifier: ^29.0.1 63 | version: 29.0.1 64 | electron-builder: 65 | specifier: ^24.12.0 66 | version: 24.12.0 67 | husky: 68 | specifier: ^9.0.11 69 | version: 9.0.11 70 | prettier: 71 | specifier: ^3.2.5 72 | version: 3.2.5 73 | typescript: 74 | specifier: ^5.3.3 75 | version: 5.3.3 76 | 77 | packages: 78 | 79 | /7zip-bin@5.2.0: 80 | resolution: {integrity: sha512-ukTPVhqG4jNzMro2qA9HSCSSVJN3aN7tlb+hfqYCt3ER0yWroeA2VR38MNrOHLQ/cVj+DaIMad0kFCtWWowh/A==} 81 | dev: true 82 | 83 | /@colors/colors@1.6.0: 84 | resolution: {integrity: sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==} 85 | engines: {node: '>=0.1.90'} 86 | dev: false 87 | 88 | /@dabh/diagnostics@2.0.3: 89 | resolution: {integrity: sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA==} 90 | dependencies: 91 | colorspace: 1.1.4 92 | enabled: 2.0.0 93 | kuler: 2.0.0 94 | dev: false 95 | 96 | /@develar/schema-utils@2.6.5: 97 | resolution: {integrity: sha512-0cp4PsWQ/9avqTVMCtZ+GirikIA36ikvjtHweU4/j8yLtgObI0+JUPhYFScgwlteveGB1rt3Cm8UhN04XayDig==} 98 | engines: {node: '>= 8.9.0'} 99 | dependencies: 100 | ajv: 6.12.6 101 | ajv-keywords: 3.5.2(ajv@6.12.6) 102 | dev: true 103 | 104 | /@electron/asar@3.2.8: 105 | resolution: {integrity: sha512-cmskk5M06ewHMZAplSiF4AlME3IrnnZhKnWbtwKVLRkdJkKyUVjMLhDIiPIx/+6zQWVlKX/LtmK9xDme7540Sg==} 106 | engines: {node: '>=10.12.0'} 107 | hasBin: true 108 | dependencies: 109 | commander: 5.1.0 110 | glob: 7.2.3 111 | minimatch: 3.1.2 112 | dev: true 113 | 114 | /@electron/get@2.0.3: 115 | resolution: {integrity: sha512-Qkzpg2s9GnVV2I2BjRksUi43U5e6+zaQMcjoJy0C+C5oxaKl+fmckGDQFtRpZpZV0NQekuZZ+tGz7EA9TVnQtQ==} 116 | engines: {node: '>=12'} 117 | dependencies: 118 | debug: 4.3.4 119 | env-paths: 2.2.1 120 | fs-extra: 8.1.0 121 | got: 11.8.6 122 | progress: 2.0.3 123 | semver: 6.3.1 124 | sumchecker: 3.0.1 125 | optionalDependencies: 126 | global-agent: 3.0.0 127 | transitivePeerDependencies: 128 | - supports-color 129 | dev: true 130 | 131 | /@electron/notarize@2.1.0: 132 | resolution: {integrity: sha512-Q02xem1D0sg4v437xHgmBLxI2iz/fc0D4K7fiVWHa/AnW8o7D751xyKNXgziA6HrTOme9ul1JfWN5ark8WH1xA==} 133 | engines: {node: '>= 10.0.0'} 134 | dependencies: 135 | debug: 4.3.4 136 | fs-extra: 9.1.0 137 | promise-retry: 2.0.1 138 | transitivePeerDependencies: 139 | - supports-color 140 | dev: true 141 | 142 | /@electron/osx-sign@1.0.5: 143 | resolution: {integrity: sha512-k9ZzUQtamSoweGQDV2jILiRIHUu7lYlJ3c6IEmjv1hC17rclE+eb9U+f6UFlOOETo0JzY1HNlXy4YOlCvl+Lww==} 144 | engines: {node: '>=12.0.0'} 145 | hasBin: true 146 | dependencies: 147 | compare-version: 0.1.2 148 | debug: 4.3.4 149 | fs-extra: 10.1.0 150 | isbinaryfile: 4.0.10 151 | minimist: 1.2.8 152 | plist: 3.1.0 153 | transitivePeerDependencies: 154 | - supports-color 155 | dev: true 156 | 157 | /@electron/universal@1.4.1: 158 | resolution: {integrity: sha512-lE/U3UNw1YHuowNbTmKNs9UlS3En3cPgwM5MI+agIgr/B1hSze9NdOP0qn7boZaI9Lph8IDv3/24g9IxnJP7aQ==} 159 | engines: {node: '>=8.6'} 160 | dependencies: 161 | '@electron/asar': 3.2.8 162 | '@malept/cross-spawn-promise': 1.1.1 163 | debug: 4.3.4 164 | dir-compare: 3.3.0 165 | fs-extra: 9.1.0 166 | minimatch: 3.1.2 167 | plist: 3.1.0 168 | transitivePeerDependencies: 169 | - supports-color 170 | dev: true 171 | 172 | /@isaacs/cliui@8.0.2: 173 | resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} 174 | engines: {node: '>=12'} 175 | dependencies: 176 | string-width: 5.1.2 177 | string-width-cjs: /string-width@4.2.3 178 | strip-ansi: 7.1.0 179 | strip-ansi-cjs: /strip-ansi@6.0.1 180 | wrap-ansi: 8.1.0 181 | wrap-ansi-cjs: /wrap-ansi@7.0.0 182 | dev: true 183 | 184 | /@jitsi/robotjs@0.6.13: 185 | resolution: {integrity: sha512-uFxRQp83jbKfMzk3lYIjgevy1X1dU/Z7OMPnqfdO1LcyPaXsOf+FCWSxM/KIxz0PvbBbORxUzuae5O5dAF5Kqw==} 186 | requiresBuild: true 187 | dependencies: 188 | node-addon-api: 4.3.0 189 | node-gyp-build: 4.8.0 190 | dev: false 191 | 192 | /@malept/cross-spawn-promise@1.1.1: 193 | resolution: {integrity: sha512-RTBGWL5FWQcg9orDOCcp4LvItNzUPcyEU9bwaeJX0rJ1IQxzucC48Y0/sQLp/g6t99IQgAlGIaesJS+gTn7tVQ==} 194 | engines: {node: '>= 10'} 195 | dependencies: 196 | cross-spawn: 7.0.3 197 | dev: true 198 | 199 | /@malept/flatpak-bundler@0.4.0: 200 | resolution: {integrity: sha512-9QOtNffcOF/c1seMCDnjckb3R9WHcG34tky+FHpNKKCW0wc/scYLwMtO+ptyGUfMW0/b/n4qRiALlaFHc9Oj7Q==} 201 | engines: {node: '>= 10.0.0'} 202 | dependencies: 203 | debug: 4.3.4 204 | fs-extra: 9.1.0 205 | lodash: 4.17.21 206 | tmp-promise: 3.0.3 207 | transitivePeerDependencies: 208 | - supports-color 209 | dev: true 210 | 211 | /@pkgjs/parseargs@0.11.0: 212 | resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} 213 | engines: {node: '>=14'} 214 | requiresBuild: true 215 | dev: true 216 | optional: true 217 | 218 | /@sindresorhus/is@4.6.0: 219 | resolution: {integrity: sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==} 220 | engines: {node: '>=10'} 221 | dev: true 222 | 223 | /@szmarczak/http-timer@4.0.6: 224 | resolution: {integrity: sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==} 225 | engines: {node: '>=10'} 226 | dependencies: 227 | defer-to-connect: 2.0.1 228 | dev: true 229 | 230 | /@tootallnate/once@2.0.0: 231 | resolution: {integrity: sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==} 232 | engines: {node: '>= 10'} 233 | dev: true 234 | 235 | /@types/async@3.2.24: 236 | resolution: {integrity: sha512-8iHVLHsCCOBKjCF2KwFe0p9Z3rfM9mL+sSP8btyR5vTjJRAqpBYD28/ZLgXPf0pjG1VxOvtCV/BgXkQbpSe8Hw==} 237 | dev: true 238 | 239 | /@types/auto-launch@5.0.5: 240 | resolution: {integrity: sha512-/nGvQZSzM/pvCMCh4Gt2kIeiUmOP/cKGJbjlInI+A+5MoV/7XmT56DJ6EU8bqc3+ItxEe4UC2GVspmPzcCc8cg==} 241 | dev: true 242 | 243 | /@types/cacheable-request@6.0.3: 244 | resolution: {integrity: sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==} 245 | dependencies: 246 | '@types/http-cache-semantics': 4.0.4 247 | '@types/keyv': 3.1.4 248 | '@types/node': 20.11.20 249 | '@types/responselike': 1.0.3 250 | dev: true 251 | 252 | /@types/debug@4.1.12: 253 | resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==} 254 | dependencies: 255 | '@types/ms': 0.7.34 256 | dev: true 257 | 258 | /@types/electron-json-storage@4.5.4: 259 | resolution: {integrity: sha512-M0ZzFYFOFejheqF900ux/CyzKC6Gex28rfeg22+MKxR9E82wU37bWrgboe8KHD63igpORmVjjmsZo6qDfkxdQQ==} 260 | dev: true 261 | 262 | /@types/fs-extra@9.0.13: 263 | resolution: {integrity: sha512-nEnwB++1u5lVDM2UI4c1+5R+FYaKfaAzS4OococimjVm3nQw3TuzH5UNsocrcTBbhnerblyHj4A49qXbIiZdpA==} 264 | dependencies: 265 | '@types/node': 20.11.20 266 | dev: true 267 | 268 | /@types/http-cache-semantics@4.0.4: 269 | resolution: {integrity: sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==} 270 | dev: true 271 | 272 | /@types/keyv@3.1.4: 273 | resolution: {integrity: sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==} 274 | dependencies: 275 | '@types/node': 20.11.20 276 | dev: true 277 | 278 | /@types/lodash@4.14.202: 279 | resolution: {integrity: sha512-OvlIYQK9tNneDlS0VN54LLd5uiPCBOp7gS5Z0f1mjoJYBrtStzgmJBxONW3U6OZqdtNzZPmn9BS/7WI7BFFcFQ==} 280 | dev: true 281 | 282 | /@types/ms@0.7.34: 283 | resolution: {integrity: sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==} 284 | dev: true 285 | 286 | /@types/node@20.11.20: 287 | resolution: {integrity: sha512-7/rR21OS+fq8IyHTgtLkDK949uzsa6n8BkziAKtPVpugIkO6D+/ooXMvzXxDnZrmtXVfjb1bKQafYpb8s89LOg==} 288 | dependencies: 289 | undici-types: 5.26.5 290 | dev: true 291 | 292 | /@types/plist@3.0.5: 293 | resolution: {integrity: sha512-E6OCaRmAe4WDmWNsL/9RMqdkkzDCY1etutkflWk4c+AcjDU07Pcz1fQwTX0TQz+Pxqn9i4L1TU3UFpjnrcDgxA==} 294 | requiresBuild: true 295 | dependencies: 296 | '@types/node': 20.11.20 297 | xmlbuilder: 15.1.1 298 | dev: true 299 | optional: true 300 | 301 | /@types/responselike@1.0.3: 302 | resolution: {integrity: sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw==} 303 | dependencies: 304 | '@types/node': 20.11.20 305 | dev: true 306 | 307 | /@types/triple-beam@1.3.5: 308 | resolution: {integrity: sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==} 309 | dev: false 310 | 311 | /@types/uuid@9.0.8: 312 | resolution: {integrity: sha512-jg+97EGIcY9AGHJJRaaPVgetKDsrTgbRjQ5Msgjh/DQKEFl0DtyRr/VCOyD1T2R1MNeWPK/u7JoGhlDZnKBAfA==} 313 | dev: true 314 | 315 | /@types/verror@1.10.9: 316 | resolution: {integrity: sha512-MLx9Z+9lGzwEuW16ubGeNkpBDE84RpB/NyGgg6z2BTpWzKkGU451cAY3UkUzZEp72RHF585oJ3V8JVNqIplcAQ==} 317 | requiresBuild: true 318 | dev: true 319 | optional: true 320 | 321 | /@types/w3c-web-usb@1.0.10: 322 | resolution: {integrity: sha512-CHgUI5kTc/QLMP8hODUHhge0D4vx+9UiAwIGiT0sTy/B2XpdX1U5rJt6JSISgr6ikRT7vxV9EVAFeYZqUnl1gQ==} 323 | dev: false 324 | 325 | /@types/yauzl@2.10.3: 326 | resolution: {integrity: sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==} 327 | requiresBuild: true 328 | dependencies: 329 | '@types/node': 20.11.20 330 | dev: true 331 | optional: true 332 | 333 | /@xmldom/xmldom@0.8.10: 334 | resolution: {integrity: sha512-2WALfTl4xo2SkGCYRt6rDTFfk9R1czmBvUQy12gK2KuRKIpWEhcbbzy8EZXtz/jkRqHX8bFEc6FC1HjX4TUWYw==} 335 | engines: {node: '>=10.0.0'} 336 | requiresBuild: true 337 | dev: true 338 | 339 | /agent-base@6.0.2: 340 | resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} 341 | engines: {node: '>= 6.0.0'} 342 | dependencies: 343 | debug: 4.3.4 344 | transitivePeerDependencies: 345 | - supports-color 346 | dev: true 347 | 348 | /ajv-keywords@3.5.2(ajv@6.12.6): 349 | resolution: {integrity: sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==} 350 | peerDependencies: 351 | ajv: ^6.9.1 352 | dependencies: 353 | ajv: 6.12.6 354 | dev: true 355 | 356 | /ajv@6.12.6: 357 | resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} 358 | dependencies: 359 | fast-deep-equal: 3.1.3 360 | fast-json-stable-stringify: 2.1.0 361 | json-schema-traverse: 0.4.1 362 | uri-js: 4.4.1 363 | dev: true 364 | 365 | /ansi-regex@5.0.1: 366 | resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} 367 | engines: {node: '>=8'} 368 | 369 | /ansi-regex@6.0.1: 370 | resolution: {integrity: sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==} 371 | engines: {node: '>=12'} 372 | dev: true 373 | 374 | /ansi-styles@4.3.0: 375 | resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} 376 | engines: {node: '>=8'} 377 | dependencies: 378 | color-convert: 2.0.1 379 | 380 | /ansi-styles@6.2.1: 381 | resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} 382 | engines: {node: '>=12'} 383 | dev: true 384 | 385 | /app-builder-bin@4.0.0: 386 | resolution: {integrity: sha512-xwdG0FJPQMe0M0UA4Tz0zEB8rBJTRA5a476ZawAqiBkMv16GRK5xpXThOjMaEOFnZ6zabejjG4J3da0SXG63KA==} 387 | dev: true 388 | 389 | /app-builder-lib@24.12.0: 390 | resolution: {integrity: sha512-t/xinVrMbsEhwljLDoFOtGkiZlaxY1aceZbHERGAS02EkUHJp9lgs/+L8okXLlYCaDSqYdB05Yb8Co+krvguXA==} 391 | engines: {node: '>=14.0.0'} 392 | dependencies: 393 | '@develar/schema-utils': 2.6.5 394 | '@electron/notarize': 2.1.0 395 | '@electron/osx-sign': 1.0.5 396 | '@electron/universal': 1.4.1 397 | '@malept/flatpak-bundler': 0.4.0 398 | '@types/fs-extra': 9.0.13 399 | async-exit-hook: 2.0.1 400 | bluebird-lst: 1.0.9 401 | builder-util: 24.9.4 402 | builder-util-runtime: 9.2.3 403 | chromium-pickle-js: 0.2.0 404 | debug: 4.3.4 405 | ejs: 3.1.9 406 | electron-publish: 24.9.4 407 | form-data: 4.0.0 408 | fs-extra: 10.1.0 409 | hosted-git-info: 4.1.0 410 | is-ci: 3.0.1 411 | isbinaryfile: 5.0.0 412 | js-yaml: 4.1.0 413 | lazy-val: 1.0.5 414 | minimatch: 5.1.6 415 | read-config-file: 6.3.2 416 | sanitize-filename: 1.6.3 417 | semver: 7.5.4 418 | tar: 6.2.0 419 | temp-file: 3.4.0 420 | transitivePeerDependencies: 421 | - supports-color 422 | dev: true 423 | 424 | /applescript@1.0.0: 425 | resolution: {integrity: sha512-yvtNHdWvtbYEiIazXAdp/NY+BBb65/DAseqlNiJQjOx9DynuzOYDbVLBJvuc0ve0VL9x6B3OHF6eH52y9hCBtQ==} 426 | dev: false 427 | 428 | /argparse@2.0.1: 429 | resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} 430 | dev: true 431 | 432 | /assert-plus@1.0.0: 433 | resolution: {integrity: sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==} 434 | engines: {node: '>=0.8'} 435 | requiresBuild: true 436 | dev: true 437 | optional: true 438 | 439 | /astral-regex@2.0.0: 440 | resolution: {integrity: sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==} 441 | engines: {node: '>=8'} 442 | requiresBuild: true 443 | dev: true 444 | optional: true 445 | 446 | /async-exit-hook@2.0.1: 447 | resolution: {integrity: sha512-NW2cX8m1Q7KPA7a5M2ULQeZ2wR5qI5PAbw5L0UOMxdioVk9PMZ0h1TmyZEkPYrCvYjDlFICusOu1dlEKAAeXBw==} 448 | engines: {node: '>=0.12.0'} 449 | dev: true 450 | 451 | /async@2.6.4: 452 | resolution: {integrity: sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==} 453 | dependencies: 454 | lodash: 4.17.21 455 | dev: false 456 | 457 | /async@3.2.5: 458 | resolution: {integrity: sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==} 459 | 460 | /asynckit@0.4.0: 461 | resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} 462 | dev: true 463 | 464 | /at-least-node@1.0.0: 465 | resolution: {integrity: sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==} 466 | engines: {node: '>= 4.0.0'} 467 | dev: true 468 | 469 | /auto-launch@5.0.6: 470 | resolution: {integrity: sha512-OgxiAm4q9EBf9EeXdPBiVNENaWE3jUZofwrhAkWjHDYGezu1k3FRZHU8V2FBxGuSJOHzKmTJEd0G7L7/0xDGFA==} 471 | engines: {node: '>=4.0.0'} 472 | dependencies: 473 | applescript: 1.0.0 474 | mkdirp: 0.5.6 475 | path-is-absolute: 1.0.1 476 | untildify: 3.0.3 477 | winreg: 1.2.4 478 | dev: false 479 | 480 | /balanced-match@1.0.2: 481 | resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} 482 | 483 | /base64-js@1.5.1: 484 | resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} 485 | requiresBuild: true 486 | dev: true 487 | 488 | /bindings@1.5.0: 489 | resolution: {integrity: sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==} 490 | dependencies: 491 | file-uri-to-path: 1.0.0 492 | dev: false 493 | 494 | /bluebird-lst@1.0.9: 495 | resolution: {integrity: sha512-7B1Rtx82hjnSD4PGLAjVWeYH3tHAcVUmChh85a3lltKQm6FresXh9ErQo6oAv6CqxttczC3/kEg8SY5NluPuUw==} 496 | dependencies: 497 | bluebird: 3.7.2 498 | dev: true 499 | 500 | /bluebird@3.7.2: 501 | resolution: {integrity: sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==} 502 | dev: true 503 | 504 | /boolean@3.2.0: 505 | resolution: {integrity: sha512-d0II/GO9uf9lfUHH2BQsjxzRJZBdsjgsBiW4BvhWk/3qoKwQFjIDVN19PfX8F2D/r9PCMTtLWjYVCFrpeYUzsw==} 506 | requiresBuild: true 507 | dev: true 508 | optional: true 509 | 510 | /brace-expansion@1.1.11: 511 | resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} 512 | dependencies: 513 | balanced-match: 1.0.2 514 | concat-map: 0.0.1 515 | 516 | /brace-expansion@2.0.1: 517 | resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} 518 | dependencies: 519 | balanced-match: 1.0.2 520 | dev: true 521 | 522 | /buffer-crc32@0.2.13: 523 | resolution: {integrity: sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==} 524 | dev: true 525 | 526 | /buffer-equal@1.0.1: 527 | resolution: {integrity: sha512-QoV3ptgEaQpvVwbXdSO39iqPQTCxSF7A5U99AxbHYqUdCizL/lH2Z0A2y6nbZucxMEOtNyZfG2s6gsVugGpKkg==} 528 | engines: {node: '>=0.4'} 529 | dev: true 530 | 531 | /buffer-from@1.1.2: 532 | resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} 533 | 534 | /buffer@5.7.1: 535 | resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} 536 | requiresBuild: true 537 | dependencies: 538 | base64-js: 1.5.1 539 | ieee754: 1.2.1 540 | dev: true 541 | optional: true 542 | 543 | /builder-util-runtime@9.2.3: 544 | resolution: {integrity: sha512-FGhkqXdFFZ5dNC4C+yuQB9ak311rpGAw+/ASz8ZdxwODCv1GGMWgLDeofRkdi0F3VCHQEWy/aXcJQozx2nOPiw==} 545 | engines: {node: '>=12.0.0'} 546 | dependencies: 547 | debug: 4.3.4 548 | sax: 1.3.0 549 | transitivePeerDependencies: 550 | - supports-color 551 | dev: true 552 | 553 | /builder-util@24.9.4: 554 | resolution: {integrity: sha512-YNon3rYjPSm4XDDho9wD6jq7vLRJZUy9FR+yFZnHoWvvdVCnZakL4BctTlPABP41MvIH5yk2cTZ2YfkOhGistQ==} 555 | dependencies: 556 | 7zip-bin: 5.2.0 557 | '@types/debug': 4.1.12 558 | app-builder-bin: 4.0.0 559 | bluebird-lst: 1.0.9 560 | builder-util-runtime: 9.2.3 561 | chalk: 4.1.2 562 | cross-spawn: 7.0.3 563 | debug: 4.3.4 564 | fs-extra: 10.1.0 565 | http-proxy-agent: 5.0.0 566 | https-proxy-agent: 5.0.1 567 | is-ci: 3.0.1 568 | js-yaml: 4.1.0 569 | source-map-support: 0.5.21 570 | stat-mode: 1.0.0 571 | temp-file: 3.4.0 572 | transitivePeerDependencies: 573 | - supports-color 574 | dev: true 575 | 576 | /cacheable-lookup@5.0.4: 577 | resolution: {integrity: sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==} 578 | engines: {node: '>=10.6.0'} 579 | dev: true 580 | 581 | /cacheable-request@7.0.4: 582 | resolution: {integrity: sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg==} 583 | engines: {node: '>=8'} 584 | dependencies: 585 | clone-response: 1.0.3 586 | get-stream: 5.2.0 587 | http-cache-semantics: 4.1.1 588 | keyv: 4.5.4 589 | lowercase-keys: 2.0.0 590 | normalize-url: 6.1.0 591 | responselike: 2.0.1 592 | dev: true 593 | 594 | /chalk@4.1.2: 595 | resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} 596 | engines: {node: '>=10'} 597 | dependencies: 598 | ansi-styles: 4.3.0 599 | supports-color: 7.2.0 600 | dev: true 601 | 602 | /chownr@2.0.0: 603 | resolution: {integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==} 604 | engines: {node: '>=10'} 605 | dev: true 606 | 607 | /chromium-pickle-js@0.2.0: 608 | resolution: {integrity: sha512-1R5Fho+jBq0DDydt+/vHWj5KJNJCKdARKOCwZUen84I5BreWoLqRLANH1U87eJy1tiASPtMnGqJJq0ZsLoRPOw==} 609 | dev: true 610 | 611 | /ci-info@3.9.0: 612 | resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} 613 | engines: {node: '>=8'} 614 | dev: true 615 | 616 | /cli-truncate@2.1.0: 617 | resolution: {integrity: sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==} 618 | engines: {node: '>=8'} 619 | requiresBuild: true 620 | dependencies: 621 | slice-ansi: 3.0.0 622 | string-width: 4.2.3 623 | dev: true 624 | optional: true 625 | 626 | /cliui@8.0.1: 627 | resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} 628 | engines: {node: '>=12'} 629 | dependencies: 630 | string-width: 4.2.3 631 | strip-ansi: 6.0.1 632 | wrap-ansi: 7.0.0 633 | 634 | /clone-response@1.0.3: 635 | resolution: {integrity: sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==} 636 | dependencies: 637 | mimic-response: 1.0.1 638 | dev: true 639 | 640 | /color-convert@1.9.3: 641 | resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} 642 | dependencies: 643 | color-name: 1.1.3 644 | dev: false 645 | 646 | /color-convert@2.0.1: 647 | resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} 648 | engines: {node: '>=7.0.0'} 649 | dependencies: 650 | color-name: 1.1.4 651 | 652 | /color-name@1.1.3: 653 | resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} 654 | dev: false 655 | 656 | /color-name@1.1.4: 657 | resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} 658 | 659 | /color-string@1.9.1: 660 | resolution: {integrity: sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==} 661 | dependencies: 662 | color-name: 1.1.4 663 | simple-swizzle: 0.2.2 664 | dev: false 665 | 666 | /color@3.2.1: 667 | resolution: {integrity: sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==} 668 | dependencies: 669 | color-convert: 1.9.3 670 | color-string: 1.9.1 671 | dev: false 672 | 673 | /colorspace@1.1.4: 674 | resolution: {integrity: sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==} 675 | dependencies: 676 | color: 3.2.1 677 | text-hex: 1.0.0 678 | dev: false 679 | 680 | /combined-stream@1.0.8: 681 | resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} 682 | engines: {node: '>= 0.8'} 683 | dependencies: 684 | delayed-stream: 1.0.0 685 | dev: true 686 | 687 | /commander@5.1.0: 688 | resolution: {integrity: sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==} 689 | engines: {node: '>= 6'} 690 | dev: true 691 | 692 | /compare-version@0.1.2: 693 | resolution: {integrity: sha512-pJDh5/4wrEnXX/VWRZvruAGHkzKdr46z11OlTPN+VrATlWWhSKewNCJ1futCO5C7eJB3nPMFZA1LeYtcFboZ2A==} 694 | engines: {node: '>=0.10.0'} 695 | dev: true 696 | 697 | /concat-map@0.0.1: 698 | resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} 699 | 700 | /config-file-ts@0.2.6: 701 | resolution: {integrity: sha512-6boGVaglwblBgJqGyxm4+xCmEGcWgnWHSWHY5jad58awQhB6gftq0G8HbzU39YqCIYHMLAiL1yjwiZ36m/CL8w==} 702 | dependencies: 703 | glob: 10.3.10 704 | typescript: 5.3.3 705 | dev: true 706 | 707 | /core-util-is@1.0.2: 708 | resolution: {integrity: sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==} 709 | requiresBuild: true 710 | dev: true 711 | optional: true 712 | 713 | /crc@3.8.0: 714 | resolution: {integrity: sha512-iX3mfgcTMIq3ZKLIsVFAbv7+Mc10kxabAGQb8HvjA1o3T1PIYprbakQ65d3I+2HGHt6nSKkM9PYjgoJO2KcFBQ==} 715 | requiresBuild: true 716 | dependencies: 717 | buffer: 5.7.1 718 | dev: true 719 | optional: true 720 | 721 | /cross-spawn@7.0.3: 722 | resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} 723 | engines: {node: '>= 8'} 724 | dependencies: 725 | path-key: 3.1.1 726 | shebang-command: 2.0.0 727 | which: 2.0.2 728 | dev: true 729 | 730 | /debug@4.3.4: 731 | resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} 732 | engines: {node: '>=6.0'} 733 | peerDependencies: 734 | supports-color: '*' 735 | peerDependenciesMeta: 736 | supports-color: 737 | optional: true 738 | dependencies: 739 | ms: 2.1.2 740 | dev: true 741 | 742 | /decompress-response@6.0.0: 743 | resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==} 744 | engines: {node: '>=10'} 745 | dependencies: 746 | mimic-response: 3.1.0 747 | dev: true 748 | 749 | /defer-to-connect@2.0.1: 750 | resolution: {integrity: sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==} 751 | engines: {node: '>=10'} 752 | dev: true 753 | 754 | /define-data-property@1.1.1: 755 | resolution: {integrity: sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==} 756 | engines: {node: '>= 0.4'} 757 | requiresBuild: true 758 | dependencies: 759 | get-intrinsic: 1.2.2 760 | gopd: 1.0.1 761 | has-property-descriptors: 1.0.1 762 | dev: true 763 | optional: true 764 | 765 | /define-properties@1.2.1: 766 | resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} 767 | engines: {node: '>= 0.4'} 768 | requiresBuild: true 769 | dependencies: 770 | define-data-property: 1.1.1 771 | has-property-descriptors: 1.0.1 772 | object-keys: 1.1.1 773 | dev: true 774 | optional: true 775 | 776 | /delayed-stream@1.0.0: 777 | resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} 778 | engines: {node: '>=0.4.0'} 779 | dev: true 780 | 781 | /detect-node@2.1.0: 782 | resolution: {integrity: sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==} 783 | requiresBuild: true 784 | dev: true 785 | optional: true 786 | 787 | /dir-compare@3.3.0: 788 | resolution: {integrity: sha512-J7/et3WlGUCxjdnD3HAAzQ6nsnc0WL6DD7WcwJb7c39iH1+AWfg+9OqzJNaI6PkBwBvm1mhZNL9iY/nRiZXlPg==} 789 | dependencies: 790 | buffer-equal: 1.0.1 791 | minimatch: 3.1.2 792 | dev: true 793 | 794 | /dmg-builder@24.12.0: 795 | resolution: {integrity: sha512-nS22OyHUIYcK40UnILOtqC5Qffd1SN1Ljqy/6e+QR2H1wM3iNBrKJoEbDRfEmYYaALKNFRkKPqSbZKRsGUBdPw==} 796 | dependencies: 797 | app-builder-lib: 24.12.0 798 | builder-util: 24.9.4 799 | builder-util-runtime: 9.2.3 800 | fs-extra: 10.1.0 801 | iconv-lite: 0.6.3 802 | js-yaml: 4.1.0 803 | optionalDependencies: 804 | dmg-license: 1.0.11 805 | transitivePeerDependencies: 806 | - supports-color 807 | dev: true 808 | 809 | /dmg-license@1.0.11: 810 | resolution: {integrity: sha512-ZdzmqwKmECOWJpqefloC5OJy1+WZBBse5+MR88z9g9Zn4VY+WYUkAyojmhzJckH5YbbZGcYIuGAkY5/Ys5OM2Q==} 811 | engines: {node: '>=8'} 812 | os: [darwin] 813 | hasBin: true 814 | requiresBuild: true 815 | dependencies: 816 | '@types/plist': 3.0.5 817 | '@types/verror': 1.10.9 818 | ajv: 6.12.6 819 | crc: 3.8.0 820 | iconv-corefoundation: 1.1.7 821 | plist: 3.1.0 822 | smart-buffer: 4.2.0 823 | verror: 1.10.1 824 | dev: true 825 | optional: true 826 | 827 | /dotenv-expand@5.1.0: 828 | resolution: {integrity: sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA==} 829 | dev: true 830 | 831 | /dotenv@9.0.2: 832 | resolution: {integrity: sha512-I9OvvrHp4pIARv4+x9iuewrWycX6CcZtoAu1XrzPxc5UygMJXJZYmBsynku8IkrJwgypE5DGNjDPmPRhDCptUg==} 833 | engines: {node: '>=10'} 834 | dev: true 835 | 836 | /eastasianwidth@0.2.0: 837 | resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} 838 | dev: true 839 | 840 | /ejs@3.1.9: 841 | resolution: {integrity: sha512-rC+QVNMJWv+MtPgkt0y+0rVEIdbtxVADApW9JXrUVlzHetgcyczP/E7DJmWJ4fJCZF2cPcBk0laWO9ZHMG3DmQ==} 842 | engines: {node: '>=0.10.0'} 843 | hasBin: true 844 | dependencies: 845 | jake: 10.8.7 846 | dev: true 847 | 848 | /electron-builder@24.12.0: 849 | resolution: {integrity: sha512-dH4O9zkxFxFbBVFobIR5FA71yJ1TZSCvjZ2maCskpg7CWjBF+SNRSQAThlDyUfRuB+jBTMwEMzwARywmap0CSw==} 850 | engines: {node: '>=14.0.0'} 851 | hasBin: true 852 | dependencies: 853 | app-builder-lib: 24.12.0 854 | builder-util: 24.9.4 855 | builder-util-runtime: 9.2.3 856 | chalk: 4.1.2 857 | dmg-builder: 24.12.0 858 | fs-extra: 10.1.0 859 | is-ci: 3.0.1 860 | lazy-val: 1.0.5 861 | read-config-file: 6.3.2 862 | simple-update-notifier: 2.0.0 863 | yargs: 17.7.2 864 | transitivePeerDependencies: 865 | - supports-color 866 | dev: true 867 | 868 | /electron-json-storage@4.6.0: 869 | resolution: {integrity: sha512-gAgNsnA7tEtV9LzzOnZTyVIb3cQtCva+bEBVT5pbRGU8ZSZTVKPBrTxIAYjeVfdSjyNXgfb1mr/CZrOJgeHyqg==} 870 | dependencies: 871 | async: 2.6.4 872 | lockfile: 1.0.4 873 | lodash: 4.17.21 874 | mkdirp: 0.5.6 875 | rimraf: 2.7.1 876 | write-file-atomic: 2.4.3 877 | dev: false 878 | 879 | /electron-publish@24.9.4: 880 | resolution: {integrity: sha512-FghbeVMfxHneHjsG2xUSC0NMZYWOOWhBxfZKPTbibcJ0CjPH0Ph8yb5CUO62nqywXfA5u1Otq6K8eOdOixxmNg==} 881 | dependencies: 882 | '@types/fs-extra': 9.0.13 883 | builder-util: 24.9.4 884 | builder-util-runtime: 9.2.3 885 | chalk: 4.1.2 886 | fs-extra: 10.1.0 887 | lazy-val: 1.0.5 888 | mime: 2.6.0 889 | transitivePeerDependencies: 890 | - supports-color 891 | dev: true 892 | 893 | /electron@29.0.1: 894 | resolution: {integrity: sha512-hsQr9clm8NCAMv4uhHlXThHn52UAgrHgyz3ubBAxZIPuUcpKVDtg4HPmx4hbmHIbYICI5OyLN3Ztp7rS+Dn4Lw==} 895 | engines: {node: '>= 12.20.55'} 896 | hasBin: true 897 | requiresBuild: true 898 | dependencies: 899 | '@electron/get': 2.0.3 900 | '@types/node': 20.11.20 901 | extract-zip: 2.0.1 902 | transitivePeerDependencies: 903 | - supports-color 904 | dev: true 905 | 906 | /emoji-regex@8.0.0: 907 | resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} 908 | 909 | /emoji-regex@9.2.2: 910 | resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} 911 | dev: true 912 | 913 | /enabled@2.0.0: 914 | resolution: {integrity: sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==} 915 | dev: false 916 | 917 | /end-of-stream@1.4.4: 918 | resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==} 919 | dependencies: 920 | once: 1.4.0 921 | dev: true 922 | 923 | /env-paths@2.2.1: 924 | resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==} 925 | engines: {node: '>=6'} 926 | dev: true 927 | 928 | /err-code@2.0.3: 929 | resolution: {integrity: sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==} 930 | dev: true 931 | 932 | /es6-error@4.1.1: 933 | resolution: {integrity: sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==} 934 | requiresBuild: true 935 | dev: true 936 | optional: true 937 | 938 | /escalade@3.1.1: 939 | resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==} 940 | engines: {node: '>=6'} 941 | 942 | /escape-string-regexp@4.0.0: 943 | resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} 944 | engines: {node: '>=10'} 945 | requiresBuild: true 946 | dev: true 947 | optional: true 948 | 949 | /extract-zip@2.0.1: 950 | resolution: {integrity: sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==} 951 | engines: {node: '>= 10.17.0'} 952 | hasBin: true 953 | dependencies: 954 | debug: 4.3.4 955 | get-stream: 5.2.0 956 | yauzl: 2.10.0 957 | optionalDependencies: 958 | '@types/yauzl': 2.10.3 959 | transitivePeerDependencies: 960 | - supports-color 961 | dev: true 962 | 963 | /extsprintf@1.4.1: 964 | resolution: {integrity: sha512-Wrk35e8ydCKDj/ArClo1VrPVmN8zph5V4AtHwIuHhvMXsKf73UT3BOD+azBIW+3wOJ4FhEH7zyaJCFvChjYvMA==} 965 | engines: {'0': node >=0.6.0} 966 | requiresBuild: true 967 | dev: true 968 | optional: true 969 | 970 | /fast-deep-equal@3.1.3: 971 | resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} 972 | requiresBuild: true 973 | dev: true 974 | 975 | /fast-json-stable-stringify@2.1.0: 976 | resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} 977 | requiresBuild: true 978 | dev: true 979 | 980 | /fd-slicer@1.1.0: 981 | resolution: {integrity: sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==} 982 | dependencies: 983 | pend: 1.2.0 984 | dev: true 985 | 986 | /fecha@4.2.3: 987 | resolution: {integrity: sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==} 988 | dev: false 989 | 990 | /file-uri-to-path@1.0.0: 991 | resolution: {integrity: sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==} 992 | dev: false 993 | 994 | /filelist@1.0.4: 995 | resolution: {integrity: sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==} 996 | dependencies: 997 | minimatch: 5.1.6 998 | dev: true 999 | 1000 | /fn.name@1.1.0: 1001 | resolution: {integrity: sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==} 1002 | dev: false 1003 | 1004 | /foreground-child@3.1.1: 1005 | resolution: {integrity: sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==} 1006 | engines: {node: '>=14'} 1007 | dependencies: 1008 | cross-spawn: 7.0.3 1009 | signal-exit: 4.1.0 1010 | dev: true 1011 | 1012 | /form-data@4.0.0: 1013 | resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==} 1014 | engines: {node: '>= 6'} 1015 | dependencies: 1016 | asynckit: 0.4.0 1017 | combined-stream: 1.0.8 1018 | mime-types: 2.1.35 1019 | dev: true 1020 | 1021 | /fs-extra@10.1.0: 1022 | resolution: {integrity: sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==} 1023 | engines: {node: '>=12'} 1024 | dependencies: 1025 | graceful-fs: 4.2.11 1026 | jsonfile: 6.1.0 1027 | universalify: 2.0.1 1028 | dev: true 1029 | 1030 | /fs-extra@8.1.0: 1031 | resolution: {integrity: sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==} 1032 | engines: {node: '>=6 <7 || >=8'} 1033 | dependencies: 1034 | graceful-fs: 4.2.11 1035 | jsonfile: 4.0.0 1036 | universalify: 0.1.2 1037 | dev: true 1038 | 1039 | /fs-extra@9.1.0: 1040 | resolution: {integrity: sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==} 1041 | engines: {node: '>=10'} 1042 | dependencies: 1043 | at-least-node: 1.0.0 1044 | graceful-fs: 4.2.11 1045 | jsonfile: 6.1.0 1046 | universalify: 2.0.1 1047 | dev: true 1048 | 1049 | /fs-minipass@2.1.0: 1050 | resolution: {integrity: sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==} 1051 | engines: {node: '>= 8'} 1052 | dependencies: 1053 | minipass: 3.3.6 1054 | dev: true 1055 | 1056 | /fs.realpath@1.0.0: 1057 | resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} 1058 | 1059 | /function-bind@1.1.2: 1060 | resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} 1061 | requiresBuild: true 1062 | dev: true 1063 | optional: true 1064 | 1065 | /get-caller-file@2.0.5: 1066 | resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} 1067 | engines: {node: 6.* || 8.* || >= 10.*} 1068 | 1069 | /get-intrinsic@1.2.2: 1070 | resolution: {integrity: sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==} 1071 | requiresBuild: true 1072 | dependencies: 1073 | function-bind: 1.1.2 1074 | has-proto: 1.0.1 1075 | has-symbols: 1.0.3 1076 | hasown: 2.0.0 1077 | dev: true 1078 | optional: true 1079 | 1080 | /get-stream@5.2.0: 1081 | resolution: {integrity: sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==} 1082 | engines: {node: '>=8'} 1083 | dependencies: 1084 | pump: 3.0.0 1085 | dev: true 1086 | 1087 | /glob@10.3.10: 1088 | resolution: {integrity: sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==} 1089 | engines: {node: '>=16 || 14 >=14.17'} 1090 | hasBin: true 1091 | dependencies: 1092 | foreground-child: 3.1.1 1093 | jackspeak: 2.3.6 1094 | minimatch: 9.0.3 1095 | minipass: 7.0.4 1096 | path-scurry: 1.10.1 1097 | dev: true 1098 | 1099 | /glob@7.2.3: 1100 | resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} 1101 | dependencies: 1102 | fs.realpath: 1.0.0 1103 | inflight: 1.0.6 1104 | inherits: 2.0.4 1105 | minimatch: 3.1.2 1106 | once: 1.4.0 1107 | path-is-absolute: 1.0.1 1108 | 1109 | /global-agent@3.0.0: 1110 | resolution: {integrity: sha512-PT6XReJ+D07JvGoxQMkT6qji/jVNfX/h364XHZOWeRzy64sSFr+xJ5OX7LI3b4MPQzdL4H8Y8M0xzPpsVMwA8Q==} 1111 | engines: {node: '>=10.0'} 1112 | requiresBuild: true 1113 | dependencies: 1114 | boolean: 3.2.0 1115 | es6-error: 4.1.1 1116 | matcher: 3.0.0 1117 | roarr: 2.15.4 1118 | semver: 7.5.4 1119 | serialize-error: 7.0.1 1120 | dev: true 1121 | optional: true 1122 | 1123 | /globalthis@1.0.3: 1124 | resolution: {integrity: sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==} 1125 | engines: {node: '>= 0.4'} 1126 | requiresBuild: true 1127 | dependencies: 1128 | define-properties: 1.2.1 1129 | dev: true 1130 | optional: true 1131 | 1132 | /gopd@1.0.1: 1133 | resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==} 1134 | requiresBuild: true 1135 | dependencies: 1136 | get-intrinsic: 1.2.2 1137 | dev: true 1138 | optional: true 1139 | 1140 | /got@11.8.6: 1141 | resolution: {integrity: sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==} 1142 | engines: {node: '>=10.19.0'} 1143 | dependencies: 1144 | '@sindresorhus/is': 4.6.0 1145 | '@szmarczak/http-timer': 4.0.6 1146 | '@types/cacheable-request': 6.0.3 1147 | '@types/responselike': 1.0.3 1148 | cacheable-lookup: 5.0.4 1149 | cacheable-request: 7.0.4 1150 | decompress-response: 6.0.0 1151 | http2-wrapper: 1.0.3 1152 | lowercase-keys: 2.0.0 1153 | p-cancelable: 2.1.1 1154 | responselike: 2.0.1 1155 | dev: true 1156 | 1157 | /graceful-fs@4.2.11: 1158 | resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} 1159 | 1160 | /has-flag@4.0.0: 1161 | resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} 1162 | engines: {node: '>=8'} 1163 | dev: true 1164 | 1165 | /has-property-descriptors@1.0.1: 1166 | resolution: {integrity: sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==} 1167 | requiresBuild: true 1168 | dependencies: 1169 | get-intrinsic: 1.2.2 1170 | dev: true 1171 | optional: true 1172 | 1173 | /has-proto@1.0.1: 1174 | resolution: {integrity: sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==} 1175 | engines: {node: '>= 0.4'} 1176 | requiresBuild: true 1177 | dev: true 1178 | optional: true 1179 | 1180 | /has-symbols@1.0.3: 1181 | resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==} 1182 | engines: {node: '>= 0.4'} 1183 | requiresBuild: true 1184 | dev: true 1185 | optional: true 1186 | 1187 | /hasown@2.0.0: 1188 | resolution: {integrity: sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==} 1189 | engines: {node: '>= 0.4'} 1190 | requiresBuild: true 1191 | dependencies: 1192 | function-bind: 1.1.2 1193 | dev: true 1194 | optional: true 1195 | 1196 | /hosted-git-info@4.1.0: 1197 | resolution: {integrity: sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==} 1198 | engines: {node: '>=10'} 1199 | dependencies: 1200 | lru-cache: 6.0.0 1201 | dev: true 1202 | 1203 | /http-cache-semantics@4.1.1: 1204 | resolution: {integrity: sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==} 1205 | dev: true 1206 | 1207 | /http-proxy-agent@5.0.0: 1208 | resolution: {integrity: sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==} 1209 | engines: {node: '>= 6'} 1210 | dependencies: 1211 | '@tootallnate/once': 2.0.0 1212 | agent-base: 6.0.2 1213 | debug: 4.3.4 1214 | transitivePeerDependencies: 1215 | - supports-color 1216 | dev: true 1217 | 1218 | /http2-wrapper@1.0.3: 1219 | resolution: {integrity: sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==} 1220 | engines: {node: '>=10.19.0'} 1221 | dependencies: 1222 | quick-lru: 5.1.1 1223 | resolve-alpn: 1.2.1 1224 | dev: true 1225 | 1226 | /https-proxy-agent@5.0.1: 1227 | resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==} 1228 | engines: {node: '>= 6'} 1229 | dependencies: 1230 | agent-base: 6.0.2 1231 | debug: 4.3.4 1232 | transitivePeerDependencies: 1233 | - supports-color 1234 | dev: true 1235 | 1236 | /husky@9.0.11: 1237 | resolution: {integrity: sha512-AB6lFlbwwyIqMdHYhwPe+kjOC3Oc5P3nThEoW/AaO2BX3vJDjWPFxYLxokUZOo6RNX20He3AaT8sESs9NJcmEw==} 1238 | engines: {node: '>=18'} 1239 | hasBin: true 1240 | dev: true 1241 | 1242 | /iconv-corefoundation@1.1.7: 1243 | resolution: {integrity: sha512-T10qvkw0zz4wnm560lOEg0PovVqUXuOFhhHAkixw8/sycy7TJt7v/RrkEKEQnAw2viPSJu6iAkErxnzR0g8PpQ==} 1244 | engines: {node: ^8.11.2 || >=10} 1245 | os: [darwin] 1246 | requiresBuild: true 1247 | dependencies: 1248 | cli-truncate: 2.1.0 1249 | node-addon-api: 1.7.2 1250 | dev: true 1251 | optional: true 1252 | 1253 | /iconv-lite@0.6.3: 1254 | resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} 1255 | engines: {node: '>=0.10.0'} 1256 | dependencies: 1257 | safer-buffer: 2.1.2 1258 | dev: true 1259 | 1260 | /ieee754@1.2.1: 1261 | resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} 1262 | requiresBuild: true 1263 | dev: true 1264 | optional: true 1265 | 1266 | /imurmurhash@0.1.4: 1267 | resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} 1268 | engines: {node: '>=0.8.19'} 1269 | dev: false 1270 | 1271 | /inflight@1.0.6: 1272 | resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} 1273 | dependencies: 1274 | once: 1.4.0 1275 | wrappy: 1.0.2 1276 | 1277 | /inherits@2.0.4: 1278 | resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} 1279 | 1280 | /is-arrayish@0.3.2: 1281 | resolution: {integrity: sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==} 1282 | dev: false 1283 | 1284 | /is-ci@3.0.1: 1285 | resolution: {integrity: sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==} 1286 | hasBin: true 1287 | dependencies: 1288 | ci-info: 3.9.0 1289 | dev: true 1290 | 1291 | /is-fullwidth-code-point@3.0.0: 1292 | resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} 1293 | engines: {node: '>=8'} 1294 | 1295 | /is-stream@2.0.1: 1296 | resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} 1297 | engines: {node: '>=8'} 1298 | dev: false 1299 | 1300 | /isbinaryfile@4.0.10: 1301 | resolution: {integrity: sha512-iHrqe5shvBUcFbmZq9zOQHBoeOhZJu6RQGrDpBgenUm/Am+F3JM2MgQj+rK3Z601fzrL5gLZWtAPH2OBaSVcyw==} 1302 | engines: {node: '>= 8.0.0'} 1303 | dev: true 1304 | 1305 | /isbinaryfile@5.0.0: 1306 | resolution: {integrity: sha512-UDdnyGvMajJUWCkib7Cei/dvyJrrvo4FIrsvSFWdPpXSUorzXrDJ0S+X5Q4ZlasfPjca4yqCNNsjbCeiy8FFeg==} 1307 | engines: {node: '>= 14.0.0'} 1308 | dev: true 1309 | 1310 | /isexe@2.0.0: 1311 | resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} 1312 | dev: true 1313 | 1314 | /jackspeak@2.3.6: 1315 | resolution: {integrity: sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==} 1316 | engines: {node: '>=14'} 1317 | dependencies: 1318 | '@isaacs/cliui': 8.0.2 1319 | optionalDependencies: 1320 | '@pkgjs/parseargs': 0.11.0 1321 | dev: true 1322 | 1323 | /jake@10.8.7: 1324 | resolution: {integrity: sha512-ZDi3aP+fG/LchyBzUM804VjddnwfSfsdeYkwt8NcbKRvo4rFkjhs456iLFn3k2ZUWvNe4i48WACDbza8fhq2+w==} 1325 | engines: {node: '>=10'} 1326 | hasBin: true 1327 | dependencies: 1328 | async: 3.2.5 1329 | chalk: 4.1.2 1330 | filelist: 1.0.4 1331 | minimatch: 3.1.2 1332 | dev: true 1333 | 1334 | /js-yaml@4.1.0: 1335 | resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} 1336 | hasBin: true 1337 | dependencies: 1338 | argparse: 2.0.1 1339 | dev: true 1340 | 1341 | /json-buffer@3.0.1: 1342 | resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} 1343 | dev: true 1344 | 1345 | /json-schema-traverse@0.4.1: 1346 | resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} 1347 | requiresBuild: true 1348 | dev: true 1349 | 1350 | /json-stringify-safe@5.0.1: 1351 | resolution: {integrity: sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==} 1352 | requiresBuild: true 1353 | dev: true 1354 | optional: true 1355 | 1356 | /json5@2.2.3: 1357 | resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} 1358 | engines: {node: '>=6'} 1359 | hasBin: true 1360 | dev: true 1361 | 1362 | /jsonfile@4.0.0: 1363 | resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==} 1364 | optionalDependencies: 1365 | graceful-fs: 4.2.11 1366 | dev: true 1367 | 1368 | /jsonfile@6.1.0: 1369 | resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==} 1370 | dependencies: 1371 | universalify: 2.0.1 1372 | optionalDependencies: 1373 | graceful-fs: 4.2.11 1374 | dev: true 1375 | 1376 | /keyv@4.5.4: 1377 | resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} 1378 | dependencies: 1379 | json-buffer: 3.0.1 1380 | dev: true 1381 | 1382 | /kuler@2.0.0: 1383 | resolution: {integrity: sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==} 1384 | dev: false 1385 | 1386 | /lazy-val@1.0.5: 1387 | resolution: {integrity: sha512-0/BnGCCfyUMkBpeDgWihanIAF9JmZhHBgUhEqzvf+adhNGLoP6TaiI5oF8oyb3I45P+PcnrqihSf01M0l0G5+Q==} 1388 | dev: true 1389 | 1390 | /lockfile@1.0.4: 1391 | resolution: {integrity: sha512-cvbTwETRfsFh4nHsL1eGWapU1XFi5Ot9E85sWAwia7Y7EgB7vfqcZhTKZ+l7hCGxSPoushMv5GKhT5PdLv03WA==} 1392 | dependencies: 1393 | signal-exit: 3.0.7 1394 | dev: false 1395 | 1396 | /lodash@4.17.21: 1397 | resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} 1398 | 1399 | /logform@2.6.0: 1400 | resolution: {integrity: sha512-1ulHeNPp6k/LD8H91o7VYFBng5i1BDE7HoKxVbZiGFidS1Rj65qcywLxX+pVfAPoQJEjRdvKcusKwOupHCVOVQ==} 1401 | engines: {node: '>= 12.0.0'} 1402 | dependencies: 1403 | '@colors/colors': 1.6.0 1404 | '@types/triple-beam': 1.3.5 1405 | fecha: 4.2.3 1406 | ms: 2.1.2 1407 | safe-stable-stringify: 2.4.3 1408 | triple-beam: 1.4.1 1409 | dev: false 1410 | 1411 | /lowercase-keys@2.0.0: 1412 | resolution: {integrity: sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==} 1413 | engines: {node: '>=8'} 1414 | dev: true 1415 | 1416 | /lru-cache@10.2.0: 1417 | resolution: {integrity: sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==} 1418 | engines: {node: 14 || >=16.14} 1419 | dev: true 1420 | 1421 | /lru-cache@6.0.0: 1422 | resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} 1423 | engines: {node: '>=10'} 1424 | dependencies: 1425 | yallist: 4.0.0 1426 | dev: true 1427 | 1428 | /matcher@3.0.0: 1429 | resolution: {integrity: sha512-OkeDaAZ/bQCxeFAozM55PKcKU0yJMPGifLwV4Qgjitu+5MoAfSQN4lsLJeXZ1b8w0x+/Emda6MZgXS1jvsapng==} 1430 | engines: {node: '>=10'} 1431 | requiresBuild: true 1432 | dependencies: 1433 | escape-string-regexp: 4.0.0 1434 | dev: true 1435 | optional: true 1436 | 1437 | /mime-db@1.52.0: 1438 | resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} 1439 | engines: {node: '>= 0.6'} 1440 | dev: true 1441 | 1442 | /mime-types@2.1.35: 1443 | resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} 1444 | engines: {node: '>= 0.6'} 1445 | dependencies: 1446 | mime-db: 1.52.0 1447 | dev: true 1448 | 1449 | /mime@2.6.0: 1450 | resolution: {integrity: sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==} 1451 | engines: {node: '>=4.0.0'} 1452 | hasBin: true 1453 | dev: true 1454 | 1455 | /mimic-response@1.0.1: 1456 | resolution: {integrity: sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==} 1457 | engines: {node: '>=4'} 1458 | dev: true 1459 | 1460 | /mimic-response@3.1.0: 1461 | resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==} 1462 | engines: {node: '>=10'} 1463 | dev: true 1464 | 1465 | /minimatch@3.1.2: 1466 | resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} 1467 | dependencies: 1468 | brace-expansion: 1.1.11 1469 | 1470 | /minimatch@5.1.6: 1471 | resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==} 1472 | engines: {node: '>=10'} 1473 | dependencies: 1474 | brace-expansion: 2.0.1 1475 | dev: true 1476 | 1477 | /minimatch@9.0.3: 1478 | resolution: {integrity: sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==} 1479 | engines: {node: '>=16 || 14 >=14.17'} 1480 | dependencies: 1481 | brace-expansion: 2.0.1 1482 | dev: true 1483 | 1484 | /minimist@1.2.8: 1485 | resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} 1486 | 1487 | /minipass@3.3.6: 1488 | resolution: {integrity: sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==} 1489 | engines: {node: '>=8'} 1490 | dependencies: 1491 | yallist: 4.0.0 1492 | dev: true 1493 | 1494 | /minipass@5.0.0: 1495 | resolution: {integrity: sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==} 1496 | engines: {node: '>=8'} 1497 | dev: true 1498 | 1499 | /minipass@7.0.4: 1500 | resolution: {integrity: sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==} 1501 | engines: {node: '>=16 || 14 >=14.17'} 1502 | dev: true 1503 | 1504 | /minizlib@2.1.2: 1505 | resolution: {integrity: sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==} 1506 | engines: {node: '>= 8'} 1507 | dependencies: 1508 | minipass: 3.3.6 1509 | yallist: 4.0.0 1510 | dev: true 1511 | 1512 | /mkdirp@0.5.6: 1513 | resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==} 1514 | hasBin: true 1515 | dependencies: 1516 | minimist: 1.2.8 1517 | dev: false 1518 | 1519 | /mkdirp@1.0.4: 1520 | resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==} 1521 | engines: {node: '>=10'} 1522 | hasBin: true 1523 | dev: true 1524 | 1525 | /ms@2.1.2: 1526 | resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} 1527 | 1528 | /node-addon-api@1.7.2: 1529 | resolution: {integrity: sha512-ibPK3iA+vaY1eEjESkQkM0BbCqFOaZMiXRTtdB0u7b4djtY6JnsjvPdUHVMg6xQt3B8fpTTWHI9A+ADjM9frzg==} 1530 | requiresBuild: true 1531 | dev: true 1532 | optional: true 1533 | 1534 | /node-addon-api@3.2.1: 1535 | resolution: {integrity: sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==} 1536 | dev: false 1537 | 1538 | /node-addon-api@4.3.0: 1539 | resolution: {integrity: sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ==} 1540 | dev: false 1541 | 1542 | /node-addon-api@7.1.0: 1543 | resolution: {integrity: sha512-mNcltoe1R8o7STTegSOHdnJNN7s5EUvhoS7ShnTHDyOSd+8H+UdWODq6qSv67PjC8Zc5JRT8+oLAMCr0SIXw7g==} 1544 | engines: {node: ^16 || ^18 || >= 20} 1545 | dev: false 1546 | 1547 | /node-gyp-build@4.8.0: 1548 | resolution: {integrity: sha512-u6fs2AEUljNho3EYTJNBfImO5QTo/J/1Etd+NVdCj7qWKUSN/bSLkZwhDv7I+w/MSC6qJ4cknepkAYykDdK8og==} 1549 | hasBin: true 1550 | dev: false 1551 | 1552 | /node-hid@3.0.0: 1553 | resolution: {integrity: sha512-8CZdobqYCKTnKx9M5r9/clAehC7jOLXu9Ts2ItMWVT6LJa0bjmkkM1SdB7TgJsothng7GE/Y+fex5AidiJLjKA==} 1554 | engines: {node: '>=10.16'} 1555 | hasBin: true 1556 | requiresBuild: true 1557 | dependencies: 1558 | node-addon-api: 3.2.1 1559 | pkg-prebuilds: 0.2.1 1560 | dev: false 1561 | 1562 | /node-mac-permissions@2.3.0: 1563 | resolution: {integrity: sha512-kZ/bUeXv+Xp6+VLS77ShgSfS8df9HB13SnS1ql+d3Cd5ry0uZkOgNh434cAhZBHiagYQWykPqgY7n9jd7t74Fw==} 1564 | os: [darwin] 1565 | requiresBuild: true 1566 | dependencies: 1567 | bindings: 1.5.0 1568 | node-addon-api: 3.2.1 1569 | dev: false 1570 | 1571 | /normalize-url@6.1.0: 1572 | resolution: {integrity: sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==} 1573 | engines: {node: '>=10'} 1574 | dev: true 1575 | 1576 | /object-keys@1.1.1: 1577 | resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} 1578 | engines: {node: '>= 0.4'} 1579 | requiresBuild: true 1580 | dev: true 1581 | optional: true 1582 | 1583 | /once@1.4.0: 1584 | resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} 1585 | dependencies: 1586 | wrappy: 1.0.2 1587 | 1588 | /one-time@1.0.0: 1589 | resolution: {integrity: sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==} 1590 | dependencies: 1591 | fn.name: 1.1.0 1592 | dev: false 1593 | 1594 | /p-cancelable@2.1.1: 1595 | resolution: {integrity: sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==} 1596 | engines: {node: '>=8'} 1597 | dev: true 1598 | 1599 | /path-is-absolute@1.0.1: 1600 | resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} 1601 | engines: {node: '>=0.10.0'} 1602 | 1603 | /path-key@3.1.1: 1604 | resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} 1605 | engines: {node: '>=8'} 1606 | dev: true 1607 | 1608 | /path-scurry@1.10.1: 1609 | resolution: {integrity: sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==} 1610 | engines: {node: '>=16 || 14 >=14.17'} 1611 | dependencies: 1612 | lru-cache: 10.2.0 1613 | minipass: 7.0.4 1614 | dev: true 1615 | 1616 | /pend@1.2.0: 1617 | resolution: {integrity: sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==} 1618 | dev: true 1619 | 1620 | /pkg-prebuilds@0.2.1: 1621 | resolution: {integrity: sha512-FdOlDiRqRL7i9aYzQflhGWCoiJf/8u6Qgzq48gKsRDYejtfjvGb1U5QGSzllcqpNg2a8Swx/9fMgtuVefwU+zw==} 1622 | engines: {node: '>= 14.15.0'} 1623 | hasBin: true 1624 | dependencies: 1625 | yargs: 17.7.2 1626 | dev: false 1627 | 1628 | /plist@3.1.0: 1629 | resolution: {integrity: sha512-uysumyrvkUX0rX/dEVqt8gC3sTBzd4zoWfLeS29nb53imdaXVvLINYXTI2GNqzaMuvacNx4uJQ8+b3zXR0pkgQ==} 1630 | engines: {node: '>=10.4.0'} 1631 | dependencies: 1632 | '@xmldom/xmldom': 0.8.10 1633 | base64-js: 1.5.1 1634 | xmlbuilder: 15.1.1 1635 | dev: true 1636 | 1637 | /prettier@3.2.5: 1638 | resolution: {integrity: sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==} 1639 | engines: {node: '>=14'} 1640 | hasBin: true 1641 | dev: true 1642 | 1643 | /progress@2.0.3: 1644 | resolution: {integrity: sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==} 1645 | engines: {node: '>=0.4.0'} 1646 | dev: true 1647 | 1648 | /promise-retry@2.0.1: 1649 | resolution: {integrity: sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==} 1650 | engines: {node: '>=10'} 1651 | dependencies: 1652 | err-code: 2.0.3 1653 | retry: 0.12.0 1654 | dev: true 1655 | 1656 | /pump@3.0.0: 1657 | resolution: {integrity: sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==} 1658 | dependencies: 1659 | end-of-stream: 1.4.4 1660 | once: 1.4.0 1661 | dev: true 1662 | 1663 | /punycode@2.3.1: 1664 | resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} 1665 | engines: {node: '>=6'} 1666 | requiresBuild: true 1667 | dev: true 1668 | 1669 | /quick-lru@5.1.1: 1670 | resolution: {integrity: sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==} 1671 | engines: {node: '>=10'} 1672 | dev: true 1673 | 1674 | /read-config-file@6.3.2: 1675 | resolution: {integrity: sha512-M80lpCjnE6Wt6zb98DoW8WHR09nzMSpu8XHtPkiTHrJ5Az9CybfeQhTJ8D7saeBHpGhLPIVyA8lcL6ZmdKwY6Q==} 1676 | engines: {node: '>=12.0.0'} 1677 | dependencies: 1678 | config-file-ts: 0.2.6 1679 | dotenv: 9.0.2 1680 | dotenv-expand: 5.1.0 1681 | js-yaml: 4.1.0 1682 | json5: 2.2.3 1683 | lazy-val: 1.0.5 1684 | dev: true 1685 | 1686 | /readable-stream@3.6.2: 1687 | resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} 1688 | engines: {node: '>= 6'} 1689 | dependencies: 1690 | inherits: 2.0.4 1691 | string_decoder: 1.3.0 1692 | util-deprecate: 1.0.2 1693 | dev: false 1694 | 1695 | /require-directory@2.1.1: 1696 | resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} 1697 | engines: {node: '>=0.10.0'} 1698 | 1699 | /resolve-alpn@1.2.1: 1700 | resolution: {integrity: sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==} 1701 | dev: true 1702 | 1703 | /responselike@2.0.1: 1704 | resolution: {integrity: sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==} 1705 | dependencies: 1706 | lowercase-keys: 2.0.0 1707 | dev: true 1708 | 1709 | /retry@0.12.0: 1710 | resolution: {integrity: sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==} 1711 | engines: {node: '>= 4'} 1712 | dev: true 1713 | 1714 | /rimraf@2.7.1: 1715 | resolution: {integrity: sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==} 1716 | hasBin: true 1717 | dependencies: 1718 | glob: 7.2.3 1719 | dev: false 1720 | 1721 | /rimraf@3.0.2: 1722 | resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} 1723 | hasBin: true 1724 | dependencies: 1725 | glob: 7.2.3 1726 | dev: true 1727 | 1728 | /roarr@2.15.4: 1729 | resolution: {integrity: sha512-CHhPh+UNHD2GTXNYhPWLnU8ONHdI+5DI+4EYIAOaiD63rHeYlZvyh8P+in5999TTSFgUYuKUAjzRI4mdh/p+2A==} 1730 | engines: {node: '>=8.0'} 1731 | requiresBuild: true 1732 | dependencies: 1733 | boolean: 3.2.0 1734 | detect-node: 2.1.0 1735 | globalthis: 1.0.3 1736 | json-stringify-safe: 5.0.1 1737 | semver-compare: 1.0.0 1738 | sprintf-js: 1.1.3 1739 | dev: true 1740 | optional: true 1741 | 1742 | /safe-buffer@5.2.1: 1743 | resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} 1744 | dev: false 1745 | 1746 | /safe-stable-stringify@2.4.3: 1747 | resolution: {integrity: sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g==} 1748 | engines: {node: '>=10'} 1749 | dev: false 1750 | 1751 | /safer-buffer@2.1.2: 1752 | resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} 1753 | dev: true 1754 | 1755 | /sanitize-filename@1.6.3: 1756 | resolution: {integrity: sha512-y/52Mcy7aw3gRm7IrcGDFx/bCk4AhRh2eI9luHOQM86nZsqwiRkkq2GekHXBBD+SmPidc8i2PqtYZl+pWJ8Oeg==} 1757 | dependencies: 1758 | truncate-utf8-bytes: 1.0.2 1759 | dev: true 1760 | 1761 | /sax@1.3.0: 1762 | resolution: {integrity: sha512-0s+oAmw9zLl1V1cS9BtZN7JAd0cW5e0QH4W3LWEK6a4LaLEA2OTpGYWDY+6XasBLtz6wkm3u1xRw95mRuJ59WA==} 1763 | dev: true 1764 | 1765 | /semver-compare@1.0.0: 1766 | resolution: {integrity: sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==} 1767 | requiresBuild: true 1768 | dev: true 1769 | optional: true 1770 | 1771 | /semver@6.3.1: 1772 | resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} 1773 | hasBin: true 1774 | dev: true 1775 | 1776 | /semver@7.5.4: 1777 | resolution: {integrity: sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==} 1778 | engines: {node: '>=10'} 1779 | hasBin: true 1780 | dependencies: 1781 | lru-cache: 6.0.0 1782 | dev: true 1783 | 1784 | /serialize-error@7.0.1: 1785 | resolution: {integrity: sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw==} 1786 | engines: {node: '>=10'} 1787 | requiresBuild: true 1788 | dependencies: 1789 | type-fest: 0.13.1 1790 | dev: true 1791 | optional: true 1792 | 1793 | /shebang-command@2.0.0: 1794 | resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} 1795 | engines: {node: '>=8'} 1796 | dependencies: 1797 | shebang-regex: 3.0.0 1798 | dev: true 1799 | 1800 | /shebang-regex@3.0.0: 1801 | resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} 1802 | engines: {node: '>=8'} 1803 | dev: true 1804 | 1805 | /signal-exit@3.0.7: 1806 | resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} 1807 | dev: false 1808 | 1809 | /signal-exit@4.1.0: 1810 | resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} 1811 | engines: {node: '>=14'} 1812 | dev: true 1813 | 1814 | /simple-swizzle@0.2.2: 1815 | resolution: {integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==} 1816 | dependencies: 1817 | is-arrayish: 0.3.2 1818 | dev: false 1819 | 1820 | /simple-update-notifier@2.0.0: 1821 | resolution: {integrity: sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==} 1822 | engines: {node: '>=10'} 1823 | dependencies: 1824 | semver: 7.5.4 1825 | dev: true 1826 | 1827 | /slice-ansi@3.0.0: 1828 | resolution: {integrity: sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==} 1829 | engines: {node: '>=8'} 1830 | requiresBuild: true 1831 | dependencies: 1832 | ansi-styles: 4.3.0 1833 | astral-regex: 2.0.0 1834 | is-fullwidth-code-point: 3.0.0 1835 | dev: true 1836 | optional: true 1837 | 1838 | /smart-buffer@4.2.0: 1839 | resolution: {integrity: sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==} 1840 | engines: {node: '>= 6.0.0', npm: '>= 3.0.0'} 1841 | requiresBuild: true 1842 | dev: true 1843 | optional: true 1844 | 1845 | /source-map-support@0.5.21: 1846 | resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} 1847 | dependencies: 1848 | buffer-from: 1.1.2 1849 | source-map: 0.6.1 1850 | 1851 | /source-map@0.6.1: 1852 | resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} 1853 | engines: {node: '>=0.10.0'} 1854 | 1855 | /sprintf-js@1.1.3: 1856 | resolution: {integrity: sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==} 1857 | requiresBuild: true 1858 | dev: true 1859 | optional: true 1860 | 1861 | /stack-trace@0.0.10: 1862 | resolution: {integrity: sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==} 1863 | dev: false 1864 | 1865 | /stat-mode@1.0.0: 1866 | resolution: {integrity: sha512-jH9EhtKIjuXZ2cWxmXS8ZP80XyC3iasQxMDV8jzhNJpfDb7VbQLVW4Wvsxz9QZvzV+G4YoSfBUVKDOyxLzi/sg==} 1867 | engines: {node: '>= 6'} 1868 | dev: true 1869 | 1870 | /string-width@4.2.3: 1871 | resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} 1872 | engines: {node: '>=8'} 1873 | dependencies: 1874 | emoji-regex: 8.0.0 1875 | is-fullwidth-code-point: 3.0.0 1876 | strip-ansi: 6.0.1 1877 | 1878 | /string-width@5.1.2: 1879 | resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} 1880 | engines: {node: '>=12'} 1881 | dependencies: 1882 | eastasianwidth: 0.2.0 1883 | emoji-regex: 9.2.2 1884 | strip-ansi: 7.1.0 1885 | dev: true 1886 | 1887 | /string_decoder@1.3.0: 1888 | resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} 1889 | dependencies: 1890 | safe-buffer: 5.2.1 1891 | dev: false 1892 | 1893 | /strip-ansi@6.0.1: 1894 | resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} 1895 | engines: {node: '>=8'} 1896 | dependencies: 1897 | ansi-regex: 5.0.1 1898 | 1899 | /strip-ansi@7.1.0: 1900 | resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} 1901 | engines: {node: '>=12'} 1902 | dependencies: 1903 | ansi-regex: 6.0.1 1904 | dev: true 1905 | 1906 | /sumchecker@3.0.1: 1907 | resolution: {integrity: sha512-MvjXzkz/BOfyVDkG0oFOtBxHX2u3gKbMHIF/dXblZsgD3BWOFLmHovIpZY7BykJdAjcqRCBi1WYBNdEC9yI7vg==} 1908 | engines: {node: '>= 8.0'} 1909 | dependencies: 1910 | debug: 4.3.4 1911 | transitivePeerDependencies: 1912 | - supports-color 1913 | dev: true 1914 | 1915 | /supports-color@7.2.0: 1916 | resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} 1917 | engines: {node: '>=8'} 1918 | dependencies: 1919 | has-flag: 4.0.0 1920 | dev: true 1921 | 1922 | /tar@6.2.0: 1923 | resolution: {integrity: sha512-/Wo7DcT0u5HUV486xg675HtjNd3BXZ6xDbzsCUZPt5iw8bTQ63bP0Raut3mvro9u+CUyq7YQd8Cx55fsZXxqLQ==} 1924 | engines: {node: '>=10'} 1925 | dependencies: 1926 | chownr: 2.0.0 1927 | fs-minipass: 2.1.0 1928 | minipass: 5.0.0 1929 | minizlib: 2.1.2 1930 | mkdirp: 1.0.4 1931 | yallist: 4.0.0 1932 | dev: true 1933 | 1934 | /temp-file@3.4.0: 1935 | resolution: {integrity: sha512-C5tjlC/HCtVUOi3KWVokd4vHVViOmGjtLwIh4MuzPo/nMYTV/p1urt3RnMz2IWXDdKEGJH3k5+KPxtqRsUYGtg==} 1936 | dependencies: 1937 | async-exit-hook: 2.0.1 1938 | fs-extra: 10.1.0 1939 | dev: true 1940 | 1941 | /text-hex@1.0.0: 1942 | resolution: {integrity: sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==} 1943 | dev: false 1944 | 1945 | /tmp-promise@3.0.3: 1946 | resolution: {integrity: sha512-RwM7MoPojPxsOBYnyd2hy0bxtIlVrihNs9pj5SUvY8Zz1sQcQG2tG1hSr8PDxfgEB8RNKDhqbIlroIarSNDNsQ==} 1947 | dependencies: 1948 | tmp: 0.2.1 1949 | dev: true 1950 | 1951 | /tmp@0.2.1: 1952 | resolution: {integrity: sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==} 1953 | engines: {node: '>=8.17.0'} 1954 | dependencies: 1955 | rimraf: 3.0.2 1956 | dev: true 1957 | 1958 | /triple-beam@1.4.1: 1959 | resolution: {integrity: sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg==} 1960 | engines: {node: '>= 14.0.0'} 1961 | dev: false 1962 | 1963 | /truncate-utf8-bytes@1.0.2: 1964 | resolution: {integrity: sha512-95Pu1QXQvruGEhv62XCMO3Mm90GscOCClvrIUwCM0PYOXK3kaF3l3sIHxx71ThJfcbM2O5Au6SO3AWCSEfW4mQ==} 1965 | dependencies: 1966 | utf8-byte-length: 1.0.4 1967 | dev: true 1968 | 1969 | /type-fest@0.13.1: 1970 | resolution: {integrity: sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==} 1971 | engines: {node: '>=10'} 1972 | requiresBuild: true 1973 | dev: true 1974 | optional: true 1975 | 1976 | /typescript@5.3.3: 1977 | resolution: {integrity: sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==} 1978 | engines: {node: '>=14.17'} 1979 | hasBin: true 1980 | dev: true 1981 | 1982 | /undici-types@5.26.5: 1983 | resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} 1984 | dev: true 1985 | 1986 | /universalify@0.1.2: 1987 | resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==} 1988 | engines: {node: '>= 4.0.0'} 1989 | dev: true 1990 | 1991 | /universalify@2.0.1: 1992 | resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} 1993 | engines: {node: '>= 10.0.0'} 1994 | dev: true 1995 | 1996 | /untildify@3.0.3: 1997 | resolution: {integrity: sha512-iSk/J8efr8uPT/Z4eSUywnqyrQU7DSdMfdqK4iWEaUVVmcP5JcnpRqmVMwcwcnmI1ATFNgC5V90u09tBynNFKA==} 1998 | engines: {node: '>=4'} 1999 | dev: false 2000 | 2001 | /uri-js@4.4.1: 2002 | resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} 2003 | requiresBuild: true 2004 | dependencies: 2005 | punycode: 2.3.1 2006 | dev: true 2007 | 2008 | /usb@2.11.0: 2009 | resolution: {integrity: sha512-u5+NZ6DtoW8TIBtuSArQGAZZ/K15i3lYvZBAYmcgI+RcDS9G50/KPrUd3CrU8M92ahyCvg5e0gc8BDvr5Hwejg==} 2010 | engines: {node: '>=12.22.0 <13.0 || >=14.17.0'} 2011 | requiresBuild: true 2012 | dependencies: 2013 | '@types/w3c-web-usb': 1.0.10 2014 | node-addon-api: 7.1.0 2015 | node-gyp-build: 4.8.0 2016 | dev: false 2017 | 2018 | /utf8-byte-length@1.0.4: 2019 | resolution: {integrity: sha512-4+wkEYLBbWxqTahEsWrhxepcoVOJ+1z5PGIjPZxRkytcdSUaNjIjBM7Xn8E+pdSuV7SzvWovBFA54FO0JSoqhA==} 2020 | dev: true 2021 | 2022 | /util-deprecate@1.0.2: 2023 | resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} 2024 | dev: false 2025 | 2026 | /uuid@9.0.1: 2027 | resolution: {integrity: sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==} 2028 | hasBin: true 2029 | dev: false 2030 | 2031 | /verror@1.10.1: 2032 | resolution: {integrity: sha512-veufcmxri4e3XSrT0xwfUR7kguIkaxBeosDg00yDWhk49wdwkSUrvvsm7nc75e1PUyvIeZj6nS8VQRYz2/S4Xg==} 2033 | engines: {node: '>=0.6.0'} 2034 | requiresBuild: true 2035 | dependencies: 2036 | assert-plus: 1.0.0 2037 | core-util-is: 1.0.2 2038 | extsprintf: 1.4.1 2039 | dev: true 2040 | optional: true 2041 | 2042 | /which@2.0.2: 2043 | resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} 2044 | engines: {node: '>= 8'} 2045 | hasBin: true 2046 | dependencies: 2047 | isexe: 2.0.0 2048 | dev: true 2049 | 2050 | /winreg@1.2.4: 2051 | resolution: {integrity: sha512-IHpzORub7kYlb8A43Iig3reOvlcBJGX9gZ0WycHhghHtA65X0LYnMRuJs+aH1abVnMJztQkvQNlltnbPi5aGIA==} 2052 | dev: false 2053 | 2054 | /winston-transport@4.7.0: 2055 | resolution: {integrity: sha512-ajBj65K5I7denzer2IYW6+2bNIVqLGDHqDw3Ow8Ohh+vdW+rv4MZ6eiDvHoKhfJFZ2auyN8byXieDDJ96ViONg==} 2056 | engines: {node: '>= 12.0.0'} 2057 | dependencies: 2058 | logform: 2.6.0 2059 | readable-stream: 3.6.2 2060 | triple-beam: 1.4.1 2061 | dev: false 2062 | 2063 | /winston@3.11.0: 2064 | resolution: {integrity: sha512-L3yR6/MzZAOl0DsysUXHVjOwv8mKZ71TrA/41EIduGpOOV5LQVodqN+QdQ6BS6PJ/RdIshZhq84P/fStEZkk7g==} 2065 | engines: {node: '>= 12.0.0'} 2066 | dependencies: 2067 | '@colors/colors': 1.6.0 2068 | '@dabh/diagnostics': 2.0.3 2069 | async: 3.2.5 2070 | is-stream: 2.0.1 2071 | logform: 2.6.0 2072 | one-time: 1.0.0 2073 | readable-stream: 3.6.2 2074 | safe-stable-stringify: 2.4.3 2075 | stack-trace: 0.0.10 2076 | triple-beam: 1.4.1 2077 | winston-transport: 4.7.0 2078 | dev: false 2079 | 2080 | /wrap-ansi@7.0.0: 2081 | resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} 2082 | engines: {node: '>=10'} 2083 | dependencies: 2084 | ansi-styles: 4.3.0 2085 | string-width: 4.2.3 2086 | strip-ansi: 6.0.1 2087 | 2088 | /wrap-ansi@8.1.0: 2089 | resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} 2090 | engines: {node: '>=12'} 2091 | dependencies: 2092 | ansi-styles: 6.2.1 2093 | string-width: 5.1.2 2094 | strip-ansi: 7.1.0 2095 | dev: true 2096 | 2097 | /wrappy@1.0.2: 2098 | resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} 2099 | 2100 | /write-file-atomic@2.4.3: 2101 | resolution: {integrity: sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ==} 2102 | dependencies: 2103 | graceful-fs: 4.2.11 2104 | imurmurhash: 0.1.4 2105 | signal-exit: 3.0.7 2106 | dev: false 2107 | 2108 | /xmlbuilder@15.1.1: 2109 | resolution: {integrity: sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==} 2110 | engines: {node: '>=8.0'} 2111 | requiresBuild: true 2112 | dev: true 2113 | 2114 | /y18n@5.0.8: 2115 | resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} 2116 | engines: {node: '>=10'} 2117 | 2118 | /yallist@4.0.0: 2119 | resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} 2120 | dev: true 2121 | 2122 | /yargs-parser@21.1.1: 2123 | resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} 2124 | engines: {node: '>=12'} 2125 | 2126 | /yargs@17.7.2: 2127 | resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} 2128 | engines: {node: '>=12'} 2129 | dependencies: 2130 | cliui: 8.0.1 2131 | escalade: 3.1.1 2132 | get-caller-file: 2.0.5 2133 | require-directory: 2.1.1 2134 | string-width: 4.2.3 2135 | y18n: 5.0.8 2136 | yargs-parser: 21.1.1 2137 | 2138 | /yauzl@2.10.0: 2139 | resolution: {integrity: sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==} 2140 | dependencies: 2141 | buffer-crc32: 0.2.13 2142 | fd-slicer: 1.1.0 2143 | dev: true 2144 | -------------------------------------------------------------------------------- /screenshots/screenshot1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/projectstorm/dynamouse/bc6fca042a315eb7f85f057b9819b0fd8100ae6f/screenshots/screenshot1.png -------------------------------------------------------------------------------- /screenshots/screenshot2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/projectstorm/dynamouse/bc6fca042a315eb7f85f057b9819b0fd8100ae6f/screenshots/screenshot2.png -------------------------------------------------------------------------------- /src/BaseObserver.ts: -------------------------------------------------------------------------------- 1 | import { v1 } from 'uuid'; 2 | 3 | export interface BaseObserverInterface { 4 | registerListener(listener: Partial): () => void; 5 | 6 | iterateListeners(cb: (listener: Partial) => any); 7 | } 8 | 9 | export class BaseObserver implements BaseObserverInterface { 10 | protected listeners: { [id: string]: Partial }; 11 | 12 | constructor() { 13 | this.listeners = {}; 14 | } 15 | 16 | registerListener(listener: Partial): () => void { 17 | const id = v1(); 18 | this.listeners[id] = listener; 19 | return () => { 20 | delete this.listeners[id]; 21 | }; 22 | } 23 | 24 | iterateListeners(cb: (listener: Partial) => any) { 25 | for (let i in this.listeners) { 26 | cb(this.listeners[i]); 27 | } 28 | } 29 | 30 | async iterateAsyncListeners(cb: (listener: Partial) => Promise) { 31 | for (let i in this.listeners) { 32 | await cb(this.listeners[i]); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/ConfigEngine.ts: -------------------------------------------------------------------------------- 1 | import * as storage from 'electron-json-storage'; 2 | import { BaseObserver } from './BaseObserver'; 3 | import { Logger } from 'winston'; 4 | 5 | export interface Config { 6 | devices: { 7 | [key: string]: { 8 | display: string; 9 | }; 10 | }; 11 | startupDelay: number; 12 | logFile: boolean; 13 | } 14 | 15 | export interface ConfigEngineListener { 16 | configChanged: (changedConfig: Partial) => any; 17 | } 18 | 19 | export interface ConfigEngineOptions { 20 | logger: Logger; 21 | } 22 | 23 | export class ConfigEngine extends BaseObserver { 24 | static VERSION = 2; 25 | static KEY = 'dynamouse'; 26 | 27 | config: Config; 28 | protected logger: Logger; 29 | 30 | constructor(protected options: ConfigEngineOptions) { 31 | super(); 32 | this.logger = options.logger.child({ namespace: 'CONFIG' }); 33 | this.config = { devices: {}, startupDelay: 0, logFile: false }; 34 | } 35 | 36 | init() { 37 | const config = storage.getSync(this.saveKey) as Config | null; 38 | if (config) { 39 | this.config = config; 40 | } 41 | } 42 | 43 | private get saveKey() { 44 | return `${ConfigEngine.KEY}-${ConfigEngine.VERSION}`; 45 | } 46 | 47 | async update(config: Partial) { 48 | this.config = { 49 | ...this.config, 50 | ...config 51 | }; 52 | await new Promise((resolve, reject) => { 53 | storage.set(this.saveKey, this.config, (err) => { 54 | if (err) { 55 | this.logger.error('failed to store settings', err); 56 | return reject(err); 57 | } 58 | resolve(); 59 | }); 60 | }); 61 | this.logger.debug(`Config updated`, this.config); 62 | this.iterateListeners((cb) => cb.configChanged?.(config)); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/DisplayEngine.ts: -------------------------------------------------------------------------------- 1 | import { screen } from 'electron'; 2 | import { BaseObserver } from './BaseObserver'; 3 | import Display = Electron.Display; 4 | 5 | export interface DisplayListener { 6 | displaysChanged: (displays: Display[]) => any; 7 | } 8 | 9 | export class DisplayEngine extends BaseObserver { 10 | displays: Display[]; 11 | constructor() { 12 | super(); 13 | this.displays = []; 14 | } 15 | 16 | recompute() { 17 | this.displays = screen.getAllDisplays(); 18 | this.iterateListeners((cb) => cb.displaysChanged?.(this.displays)); 19 | } 20 | 21 | init() { 22 | screen.on('display-added', () => { 23 | this.recompute(); 24 | }); 25 | screen.on('display-removed', () => { 26 | this.recompute(); 27 | }); 28 | this.recompute(); 29 | } 30 | 31 | getDisplay(name: string) { 32 | return this.displays.find((d) => d.label === name); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/PointerEngine.ts: -------------------------------------------------------------------------------- 1 | import { Device, devices, HID } from 'node-hid'; 2 | import { BaseObserver } from './BaseObserver'; 3 | import { usb } from 'usb'; 4 | import * as _ from 'lodash'; 5 | import { Logger } from 'winston'; 6 | 7 | export interface PointerDeviceListener { 8 | moved: () => any; 9 | detached: () => any; 10 | } 11 | 12 | export interface PointerDeviceOptions { 13 | device: Device; 14 | logger: Logger; 15 | } 16 | 17 | export class PointerDevice extends BaseObserver { 18 | resource: HID; 19 | logger: Logger; 20 | private dispose: () => any; 21 | 22 | constructor(protected options: PointerDeviceOptions) { 23 | super(); 24 | this.logger = options.logger.child({ namespace: options.device.product }); 25 | } 26 | 27 | async connect() { 28 | this.logger.info(`Connecting`); 29 | this.resource = new HID(this.device.path); 30 | 31 | const data_cb = () => { 32 | this.iterateListeners((cb) => cb.moved?.()); 33 | }; 34 | const error_cb = (err) => { 35 | this.logger.error(err); 36 | // do nothing for now 37 | }; 38 | this.resource.on('error', error_cb); 39 | this.resource.on('data', data_cb); 40 | this.dispose = () => { 41 | this.resource?.off('error', error_cb); 42 | this.resource?.off('data', data_cb); 43 | this.dispose = null; 44 | }; 45 | } 46 | 47 | async detach() { 48 | this.logger.info('Detaching'); 49 | this.dispose?.(); 50 | if (this.resource) { 51 | await this.disconnect(); 52 | } 53 | this.iterateListeners((cb) => cb.detached?.()); 54 | } 55 | 56 | async disconnect() { 57 | if (!this.resource) { 58 | return; 59 | } 60 | this.logger.info('Disconnecting'); 61 | try { 62 | this.resource.close(); 63 | } catch (ex) {} 64 | this.resource = null; 65 | } 66 | 67 | get device() { 68 | return this.options.device; 69 | } 70 | 71 | get sn() { 72 | return this.device.serialNumber; 73 | } 74 | 75 | get product() { 76 | return this.device.product; 77 | } 78 | } 79 | 80 | export interface PointerEngineListener { 81 | devicesChanged: () => any; 82 | } 83 | 84 | export interface PointerEngineOptions { 85 | logger: Logger; 86 | } 87 | 88 | export class PointerEngine extends BaseObserver { 89 | _devices: Set; 90 | logger: Logger; 91 | 92 | constructor(protected options: PointerEngineOptions) { 93 | super(); 94 | this._devices = new Set(); 95 | this.logger = options.logger.child({ namespace: 'POINTERS' }); 96 | } 97 | 98 | async dispose() { 99 | await Promise.all( 100 | this.getDevices().map((d) => { 101 | return d.disconnect(); 102 | }) 103 | ); 104 | } 105 | 106 | refreshDeviceList() { 107 | this.logger.info('Refreshing device list'); 108 | let pointerDevices = _.filter(devices(), (d) => d.usage === 2 && d.usagePage === 1); 109 | let unique = _.uniqBy(pointerDevices, (u) => u.serialNumber || u.product); 110 | const snMapper = (a: PointerDevice | Device) => { 111 | if (a instanceof PointerDevice) { 112 | return a.sn; 113 | } 114 | return (a as Device).serialNumber; 115 | }; 116 | 117 | // devices to remove 118 | _.differenceBy(this.getDevices(), unique, snMapper).forEach((d) => { 119 | d.detach(); 120 | }); 121 | 122 | // devices to add 123 | _.differenceBy(unique, this.getDevices(), snMapper).forEach((d) => { 124 | const device = new PointerDevice({ 125 | device: d, 126 | logger: this.logger 127 | }); 128 | const l1 = device.registerListener({ 129 | detached: () => { 130 | l1(); 131 | this._devices.delete(device); 132 | this.iterateListeners((cb) => cb.devicesChanged?.()); 133 | } 134 | }); 135 | this._devices.add(device); 136 | this.iterateListeners((cb) => cb.devicesChanged?.()); 137 | }); 138 | } 139 | 140 | init() { 141 | usb.on('attach', () => { 142 | this.logger.debug('Device attached'); 143 | this.refreshDeviceList(); 144 | }); 145 | 146 | usb.on('detach', () => { 147 | this.logger.debug('Device detached'); 148 | this.refreshDeviceList(); 149 | }); 150 | this.refreshDeviceList(); 151 | } 152 | 153 | getDevices() { 154 | return Array.from(this._devices.values()); 155 | } 156 | 157 | getDevice(name: string) { 158 | return this.getDevices().find((d) => d.product === name); 159 | } 160 | 161 | getDeviceFromSN(sn: string) { 162 | return this.getDevices().find((d) => d.sn === sn); 163 | } 164 | } 165 | -------------------------------------------------------------------------------- /src/RobotEngine.ts: -------------------------------------------------------------------------------- 1 | import { Display } from 'electron'; 2 | import { Config } from './ConfigEngine'; 3 | import { PointerDevice, PointerEngine } from './PointerEngine'; 4 | import { DisplayEngine } from './DisplayEngine'; 5 | import { BaseObserver } from './BaseObserver'; 6 | import { screen } from 'electron'; 7 | import { moveMouse } from '@jitsi/robotjs'; 8 | import { Logger } from 'winston'; 9 | 10 | export interface AssignmentListener { 11 | willActivate: () => any; 12 | disposed: () => any; 13 | } 14 | 15 | export class Assignment extends BaseObserver { 16 | position_x: number; 17 | position_y: number; 18 | activated: boolean; 19 | moved: boolean; 20 | listener: () => any; 21 | 22 | constructor( 23 | protected device: PointerDevice, 24 | protected display: Display 25 | ) { 26 | super(); 27 | this.position_x = null; 28 | this.position_y = null; 29 | this.activated = false; 30 | this.moved = false; 31 | this.listener = device.registerListener({ 32 | moved: () => { 33 | if (!this.activated) { 34 | this.iterateListeners((cb) => cb.willActivate?.()); 35 | } 36 | } 37 | }); 38 | } 39 | 40 | async init() { 41 | return this.device.connect(); 42 | } 43 | 44 | contains(px: number, py: number) { 45 | if (px == null || py == null) { 46 | return false; 47 | } 48 | const { x, y, width, height } = this.display.bounds; 49 | const insideHorizontal = px > x && px < x + width; 50 | const insideVertical = py > y && py < y + height; 51 | return insideHorizontal && insideVertical; 52 | } 53 | 54 | async deactivate() { 55 | this.activated = false; 56 | const point = screen.getCursorScreenPoint(); 57 | this.position_x = point.x; 58 | this.position_y = point.y; 59 | return this.device.connect(); 60 | } 61 | 62 | async activate(prev?: Assignment) { 63 | if (this.activated) { 64 | return; 65 | } 66 | const { x, y, width, height } = this.display.bounds; 67 | let pos_x = this.position_x; 68 | let pos_y = this.position_y; 69 | 70 | if (pos_x == null || pos_y == null) { 71 | pos_x = x + width / 2; 72 | pos_y = y + height / 2; 73 | } 74 | 75 | // previous device cursor was on this display, just use it 76 | if (prev && this.contains(prev.position_x, prev.position_y)) { 77 | pos_x = prev.position_x; 78 | pos_y = prev.position_y; 79 | } 80 | 81 | // this device cursor was on a different screen, use center 82 | else if (!this.contains(pos_x, pos_y)) { 83 | pos_x = x + width / 2; 84 | pos_y = y + height / 2; 85 | } 86 | 87 | moveMouse(pos_x, pos_y); 88 | this.activated = true; 89 | return this.device.disconnect(); 90 | } 91 | 92 | async dispose() { 93 | this.listener(); 94 | await this.device.disconnect(); 95 | this.iterateListeners((cb) => cb.disposed?.()); 96 | } 97 | } 98 | 99 | export interface RobotEngineOptions { 100 | pointerEngine: PointerEngine; 101 | displayEngine: DisplayEngine; 102 | logger: Logger; 103 | } 104 | 105 | export class RobotEngine { 106 | assignments: Assignment[]; 107 | lock: boolean; 108 | 109 | protected logger: Logger; 110 | 111 | constructor(protected options: RobotEngineOptions) { 112 | this.assignments = []; 113 | this.lock = false; 114 | this.logger = options.logger.child({ namespace: 'ROBOT' }); 115 | } 116 | 117 | async setupAssignments(config: Config) { 118 | this.logger.debug('Re-initializing'); 119 | await Promise.all(this.assignments.map((a) => a.dispose())); 120 | this.assignments = []; 121 | for (let key in config.devices) { 122 | const device = this.options.pointerEngine.getDevice(key); 123 | if (!config.devices[key].display) { 124 | continue; 125 | } 126 | const display = this.options.displayEngine.getDisplay(config.devices[key].display); 127 | if (!display || !device) { 128 | continue; 129 | } 130 | let assignment = new Assignment(device, display); 131 | const listener = assignment.registerListener({ 132 | willActivate: async () => { 133 | if (this.lock) { 134 | return; 135 | } 136 | this.logger.debug(`Activating: ${device.product}`); 137 | this.lock = true; 138 | const activated = this.assignments.find((a) => a.activated); 139 | await activated?.deactivate(); 140 | await assignment.activate(activated); 141 | this.lock = false; 142 | }, 143 | disposed: () => { 144 | listener?.(); 145 | } 146 | }); 147 | this.assignments.push(assignment); 148 | } 149 | 150 | await Promise.all(this.assignments.map((a) => a.init())); 151 | } 152 | } 153 | -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | import { app, nativeImage, Tray } from 'electron'; 2 | import * as path from 'path'; 3 | import { DisplayEngine } from './DisplayEngine'; 4 | import { PointerEngine } from './PointerEngine'; 5 | import { ConfigEngine } from './ConfigEngine'; 6 | import { RobotEngine } from './RobotEngine'; 7 | import AutoLaunch from 'auto-launch'; 8 | import { createLogger, transports } from 'winston'; 9 | import { buildLoadingMenu, buildMenu } from './menu'; 10 | import { waitForAllPermissions } from './permissions'; 11 | 12 | require('source-map-support').install(); 13 | 14 | const autolauncher = new AutoLaunch({ 15 | name: 'DynaMouse' 16 | }); 17 | 18 | const icon_mac = nativeImage.createFromPath(path.join(__dirname, '../media/icon-mac.png')); 19 | 20 | const logger = createLogger(); 21 | 22 | logger.add(new transports.Console({ level: 'debug' })); 23 | 24 | const displayEngine = new DisplayEngine(); 25 | const pointerEngine = new PointerEngine({ logger }); 26 | const configEngine = new ConfigEngine({ logger }); 27 | const robotEngine = new RobotEngine({ 28 | logger, 29 | displayEngine, 30 | pointerEngine 31 | }); 32 | 33 | app.on('ready', async () => { 34 | const tray = new Tray( 35 | icon_mac.resize({ 36 | width: 16, 37 | height: 16 38 | }) 39 | ); 40 | buildLoadingMenu({ tray }); 41 | 42 | // need to get some permissions before we can continue 43 | await waitForAllPermissions(); 44 | 45 | // can hide the dock at this point as permissions checks might need to icon so users can switch to the dialog 46 | app.dock.hide(); 47 | 48 | const setupMovement = () => { 49 | return robotEngine.setupAssignments(configEngine.config); 50 | }; 51 | 52 | const dispose = async () => { 53 | logger.debug('Disposing app'); 54 | await pointerEngine.dispose(); 55 | }; 56 | 57 | const buildMenuWrapped = () => { 58 | buildMenu({ 59 | tray, 60 | quit: async () => { 61 | await dispose(); 62 | app.exit(0); 63 | }, 64 | displayEngine, 65 | pointerEngine, 66 | configEngine, 67 | autolauncher, 68 | rebuildMenu: () => { 69 | buildMenuWrapped(); 70 | } 71 | }); 72 | }; 73 | 74 | const init = () => { 75 | pointerEngine.init(); 76 | displayEngine.init(); 77 | 78 | configEngine.registerListener({ 79 | configChanged: ({ devices }) => { 80 | buildMenuWrapped(); 81 | 82 | // if devices changed, then also setupMovementAgain 83 | if (devices) { 84 | setupMovement(); 85 | } 86 | } 87 | }); 88 | 89 | pointerEngine.registerListener({ 90 | devicesChanged: () => { 91 | buildMenuWrapped(); 92 | setupMovement(); 93 | } 94 | }); 95 | 96 | buildMenuWrapped(); 97 | setupMovement(); 98 | }; 99 | 100 | configEngine.init(); 101 | 102 | // useful for debugging 103 | if (configEngine.config.logFile) { 104 | logger.add(new transports.File({ filename: 'combined.log', dirname: app.getPath('logs'), level: 'debug' })); 105 | } 106 | 107 | // add a startup delay 108 | const delay = (configEngine.config.startupDelay || 0) * 1_000; 109 | if (delay > 0) { 110 | buildLoadingMenu({ tray, message: `...waiting ${delay}ms (startup delay)` }); 111 | setTimeout(init, delay); 112 | } else { 113 | // doing this outside of a setTimeout may help with node event loops for some cases :shrug: 114 | init(); 115 | } 116 | }); 117 | -------------------------------------------------------------------------------- /src/menu.ts: -------------------------------------------------------------------------------- 1 | import { Menu, MenuItem, Tray } from 'electron'; 2 | import { DisplayEngine } from './DisplayEngine'; 3 | import { PointerEngine } from './PointerEngine'; 4 | import { ConfigEngine } from './ConfigEngine'; 5 | import AutoLaunch from 'auto-launch'; 6 | 7 | export interface BuildMenuOptions { 8 | autolauncher: AutoLaunch; 9 | pointerEngine: PointerEngine; 10 | displayEngine: DisplayEngine; 11 | configEngine: ConfigEngine; 12 | rebuildMenu: () => any; 13 | quit: () => any; 14 | tray: Tray; 15 | } 16 | 17 | export const buildLoadingMenu = (options: { tray: Tray; message?: string }) => { 18 | const { tray, message } = options; 19 | const menu = new Menu(); 20 | menu.append( 21 | new MenuItem({ 22 | type: 'normal', 23 | label: message || 'loading...' 24 | }) 25 | ); 26 | tray.setContextMenu(menu); 27 | return menu; 28 | }; 29 | 30 | export const buildMenu = async (options: BuildMenuOptions) => { 31 | const { tray } = options; 32 | const menu = new Menu(); 33 | 34 | // assignments 35 | buildAssignmentMenus(options).forEach((m) => { 36 | menu.append(m); 37 | }); 38 | 39 | // eveything else 40 | menu.append(new MenuItem({ type: 'separator' })); 41 | menu.append(await buildStartupMenu(options)); 42 | menu.append(buildDebugMenu(options)); 43 | menu.append(new MenuItem({ type: 'separator' })); 44 | menu.append( 45 | new MenuItem({ 46 | label: 'Quit', 47 | click: async () => { 48 | options.quit(); 49 | } 50 | }) 51 | ); 52 | 53 | tray.setContextMenu(menu); 54 | 55 | return menu; 56 | }; 57 | 58 | export const buildDebugMenu = (options: BuildMenuOptions) => { 59 | const { configEngine } = options; 60 | const menu = new Menu(); 61 | 62 | menu.append( 63 | new MenuItem({ 64 | label: 'File Logging', 65 | type: 'checkbox', 66 | checked: !!configEngine.config.logFile, 67 | click: () => { 68 | configEngine.update({ 69 | logFile: !configEngine.config.logFile 70 | }); 71 | } 72 | }) 73 | ); 74 | 75 | return new MenuItem({ 76 | label: 'Debug', 77 | submenu: menu 78 | }); 79 | }; 80 | 81 | export const buildAssignmentMenus = (options: BuildMenuOptions) => { 82 | const { pointerEngine, displayEngine, configEngine, tray } = options; 83 | return pointerEngine.getDevices().map((device) => { 84 | const submenu = new Menu(); 85 | displayEngine.displays.forEach((display) => { 86 | submenu.append( 87 | new MenuItem({ 88 | label: display.label, 89 | type: 'radio', 90 | checked: configEngine.config.devices?.[device.product]?.display === display.label, 91 | click: () => { 92 | configEngine.update({ 93 | devices: { 94 | ...configEngine.config.devices, 95 | [device.product]: { display: display.label } 96 | } 97 | }); 98 | } 99 | }) 100 | ); 101 | }); 102 | submenu.append(new MenuItem({ type: 'separator' })); 103 | submenu.append( 104 | new MenuItem({ 105 | type: 'radio', 106 | label: 'None (uncontrolled)', 107 | checked: configEngine.config.devices?.[device.product]?.display == null, 108 | click: () => { 109 | configEngine.update({ 110 | devices: { 111 | ...configEngine.config.devices, 112 | [device.product]: { display: null } 113 | } 114 | }); 115 | } 116 | }) 117 | ); 118 | 119 | return new MenuItem({ label: device.product, submenu: submenu }); 120 | }); 121 | }; 122 | 123 | export const buildStartupMenu = async (options: { 124 | autolauncher: AutoLaunch; 125 | rebuildMenu: () => any; 126 | configEngine: ConfigEngine; 127 | }) => { 128 | const { autolauncher, rebuildMenu, configEngine } = options; 129 | 130 | const autoLaunchEnabled = await autolauncher.isEnabled(); 131 | const startupMenu = new Menu(); 132 | startupMenu.append( 133 | new MenuItem({ 134 | label: 'Enabled', 135 | type: 'checkbox', 136 | checked: autoLaunchEnabled, 137 | click: async () => { 138 | if (autoLaunchEnabled) { 139 | await autolauncher.disable(); 140 | } else { 141 | await autolauncher.enable(); 142 | } 143 | rebuildMenu(); 144 | } 145 | }) 146 | ); 147 | startupMenu.append(new MenuItem({ type: 'separator' })); 148 | 149 | const currentDelay = configEngine.config.startupDelay || 0; 150 | let intervals = [0, 2, 5, 10]; 151 | intervals.forEach((i) => { 152 | startupMenu.append( 153 | new MenuItem({ 154 | label: `Startup delay ${i}s`, 155 | type: 'checkbox', 156 | checked: i == currentDelay, 157 | click: async () => { 158 | configEngine.update({ 159 | startupDelay: i 160 | }); 161 | rebuildMenu(); 162 | } 163 | }) 164 | ); 165 | }); 166 | 167 | return new MenuItem({ 168 | label: 'Launch on startup', 169 | submenu: startupMenu 170 | }); 171 | }; 172 | -------------------------------------------------------------------------------- /src/permissions.ts: -------------------------------------------------------------------------------- 1 | import { askForAccessibilityAccess, askForInputMonitoringAccess, AuthType, getAuthStatus } from 'node-mac-permissions'; 2 | import { dialog } from 'electron'; 3 | 4 | const waitForPermission = (perm: AuthType) => { 5 | let interval; 6 | return new Promise((resolve) => { 7 | interval = setInterval(() => { 8 | if (getAuthStatus(perm) === 'authorized') { 9 | resolve(null); 10 | } 11 | }, 1000); 12 | }).then(() => { 13 | clearInterval(interval); 14 | }); 15 | }; 16 | 17 | export const waitForAllPermissions = async () => { 18 | if (getAuthStatus('accessibility') !== 'authorized') { 19 | await dialog.showMessageBox({ 20 | type: 'info', 21 | title: 'Some permissions needed', 22 | message: 'You will be asked for accessibility access, we need this so we can control the mouse position.' 23 | }); 24 | askForAccessibilityAccess(); 25 | await waitForPermission('accessibility'); 26 | } 27 | 28 | if (getAuthStatus('input-monitoring') !== 'authorized') { 29 | await askForInputMonitoringAccess(); 30 | await waitForPermission('input-monitoring'); 31 | } 32 | }; 33 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": false, 3 | "compilerOptions": { 4 | "inlineSourceMap": true, 5 | "outDir": "dist", 6 | "rootDir": "src", 7 | "baseUrl": ".", 8 | "downlevelIteration": true, 9 | "esModuleInterop": true 10 | } 11 | } --------------------------------------------------------------------------------