diff --git a/.editorconfig b/.editorconfig index aaac3258..c6c8b362 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,7 +1,8 @@ root = true [*] -indent_style = tab +indent_style = space +indent_size = 2 end_of_line = lf charset = utf-8 trim_trailing_whitespace = true diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 00000000..a9ba028c --- /dev/null +++ b/.eslintignore @@ -0,0 +1 @@ +.eslintrc.js diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 00000000..e1698f08 --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,69 @@ +module.exports = { + extends: [ + 'eslint:recommended', + 'plugin:import/recommended', + 'plugin:import/typescript', + 'plugin:@typescript-eslint/eslint-recommended', + 'plugin:@typescript-eslint/recommended', + 'plugin:@typescript-eslint/recommended-requiring-type-checking', + ], + plugins: ['@typescript-eslint', 'import'], + parser: '@typescript-eslint/parser', + parserOptions: { + project: './tsconfig.json', + tsconfigRootDir: __dirname, + sourceType: 'module', + ecmaVersion: 'latest' + }, + rules: { + 'arrow-parens': ['error', 'always'], + 'object-curly-spacing': ['error', 'always'], + '@typescript-eslint/no-floating-promises': 'off', + '@typescript-eslint/no-misused-promises': ['off', { checksVoidReturn: false }], + '@typescript-eslint/no-unused-vars': ['warn', { argsIgnorePattern: '^_' }], + "@typescript-eslint/no-non-null-assertion": "off", + 'import/first': 'error', + 'import/newline-after-import': 'error', + 'import/no-default-export': 'off', + 'import/no-duplicates': 'error', + 'import/order': [ + 'error', + { + 'groups': ['builtin', 'external', ['internal', 'index', 'sibling'], 'parent', 'type'], + 'newlines-between': 'always-and-inside-groups', + 'alphabetize': {order: 'ignore', caseInsensitive: false} + } + ], + 'import/prefer-default-export': 'off', + 'camelcase': ['error', {properties: 'never'}], + 'class-methods-use-this': 'off', + 'lines-around-comment': [ + 'error', + { + beforeBlockComment: false, + afterBlockComment: false, + beforeLineComment: false, + afterLineComment: false, + }, + ], + 'max-len': 'off', + 'no-mixed-operators': 'error', + 'no-multi-spaces': ['error', {ignoreEOLComments: true}], + 'no-tabs': 'error', + 'no-void': 'error', + 'no-empty': 'off', + 'prefer-promise-reject-errors': 'off', + 'quotes': ['error', 'single', { + avoidEscape: true, + allowTemplateLiterals: false, + }], + 'quote-props': ['error', 'consistent'], + 'semi': ['error', 'always'], + }, + env: { + browser: true, + node: true, + es6: true, + }, + ignorePatterns: ['dist', 'node_modules'], +}; diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 962b4adb..5378a66e 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -6,7 +6,7 @@ on: pull_request: env: - NODE_VERSION: "16.x" + NODE_VERSION: "20.x" jobs: build: @@ -15,57 +15,26 @@ jobs: strategy: fail-fast: true matrix: - os: [macos-latest, ubuntu-latest, windows-latest] + os: [ macos-latest, ubuntu-latest, windows-latest ] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Setup NodeJS uses: actions/setup-node@v3 with: node-version: ${{ env.NODE_VERSION }} - - - name: Expose yarn config as "$GITHUB_OUTPUT" - id: yarn-config - shell: bash - run: | - echo "CACHE_FOLDER=$(yarn config get cacheFolder)" >> $GITHUB_OUTPUT - - # Yarn rotates the downloaded cache archives, @see https://github.com/actions/setup-node/issues/325 - # Yarn cache is also reusable between arch and os. - - name: Restore yarn cache - uses: actions/cache@v3 - id: yarn-download-cache - with: - path: ${{ steps.yarn-config.outputs.CACHE_FOLDER }} - key: yarn-download-cache-${{ hashFiles('yarn.lock') }} - restore-keys: | - yarn-download-cache- - - # Invalidated on yarn.lock changes - - name: Restore yarn install state - id: yarn-install-state-cache - uses: actions/cache@v3 - with: - path: .yarn/ci-cache/ - key: ${{ runner.os }}-yarn-install-state-cache-${{ hashFiles('yarn.lock', '.yarnrc.yml') }} + cache: 'npm' - name: Install dependencies - shell: bash - run: | - yarn install --immutable --inline-builds - env: - # CI optimizations. Overrides yarnrc.yml options (or their defaults) in the CI action. - YARN_ENABLE_GLOBAL_CACHE: "false" # Use local cache folder to keep downloaded archives - YARN_NM_MODE: "hardlinks-local" # Hardlinks-(local|global) reduces io / node_modules size - YARN_INSTALL_STATE_PATH: .yarn/ci-cache/install-state.gz # Very small speedup when lock does not change + run: npm ci - name: Test uses: GabrielBB/xvfb-action@v1 env: PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1 with: - run: yarn test + run: npm run test # Build and release if it's the main repository - name: Build and release on Mac @@ -73,37 +42,37 @@ jobs: env: GH_TOKEN: ${{ secrets.GH_TOKEN }} run: | - yarn run release:mac + npm run release:mac - name: Build and release on Linux if: startsWith(matrix.os, 'ubuntu') && github.repository == 'th-ch/youtube-music' env: GH_TOKEN: ${{ secrets.GH_TOKEN }} run: | - yarn run release:linux + npm run release:linux - name: Build and release on Windows if: startsWith(matrix.os, 'windows') && github.repository == 'th-ch/youtube-music' env: GH_TOKEN: ${{ secrets.GH_TOKEN }} run: | - yarn run release:win + npm run release:win # Only build without release if it is a fork - name: Build on Mac if: startsWith(matrix.os, 'macOS') && github.repository != 'th-ch/youtube-music' run: | - yarn run build:mac + npm run build:mac - name: Build on Linux if: startsWith(matrix.os, 'ubuntu') && github.repository != 'th-ch/youtube-music' run: | - yarn run build:linux + npm run build:linux - name: Build on Windows if: startsWith(matrix.os, 'windows') && github.repository != 'th-ch/youtube-music' run: | - yarn run build:win + npm run build:win release: runs-on: ubuntu-latest @@ -111,7 +80,7 @@ jobs: if: github.repository == 'th-ch/youtube-music' && github.ref == 'refs/heads/master' needs: build steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: 0 @@ -119,41 +88,10 @@ jobs: uses: actions/setup-node@v3 with: node-version: ${{ env.NODE_VERSION }} - - - name: Expose yarn config as "$GITHUB_OUTPUT" - id: yarn-config - shell: bash - run: | - echo "CACHE_FOLDER=$(yarn config get cacheFolder)" >> $GITHUB_OUTPUT - - # Yarn rotates the downloaded cache archives, @see https://github.com/actions/setup-node/issues/325 - # Yarn cache is also reusable between arch and os. - - name: Restore yarn cache - uses: actions/cache@v3 - id: yarn-download-cache - with: - path: ${{ steps.yarn-config.outputs.CACHE_FOLDER }} - key: yarn-download-cache-${{ hashFiles('yarn.lock') }} - restore-keys: | - yarn-download-cache- - - # Invalidated on yarn.lock changes - - name: Restore yarn install state - id: yarn-install-state-cache - uses: actions/cache@v3 - with: - path: .yarn/ci-cache/ - key: ${{ runner.os }}-yarn-install-state-cache-${{ hashFiles('yarn.lock', '.yarnrc.yml') }} + cache: 'npm' - name: Install dependencies - shell: bash - run: | - yarn install --immutable --inline-builds - env: - # CI optimizations. Overrides yarnrc.yml options (or their defaults) in the CI action. - YARN_ENABLE_GLOBAL_CACHE: "false" # Use local cache folder to keep downloaded archives - YARN_NM_MODE: "hardlinks-local" # Hardlinks-(local|global) reduces io / node_modules size - YARN_INSTALL_STATE_PATH: .yarn/ci-cache/install-state.gz # Very small speedup when lock does not change + run: npm ci - name: Get version run: | @@ -194,7 +132,7 @@ jobs: - name: Update changelog if: ${{ env.VERSION_HASH == '' }} run: | - yarn changelog + npm run changelog - name: Commit changelog if: ${{ env.VERSION_HASH == '' }} diff --git a/.github/workflows/dependency-review.yml b/.github/workflows/dependency-review.yml index 05661a91..bac08e6c 100644 --- a/.github/workflows/dependency-review.yml +++ b/.github/workflows/dependency-review.yml @@ -5,7 +5,7 @@ # Source repository: https://github.com/actions/dependency-review-action # Public documentation: https://docs.github.com/en/code-security/supply-chain-security/understanding-your-software-supply-chain/about-dependency-review#dependency-review-enforcement name: "Dependency Review" -on: [pull_request] +on: [ pull_request ] permissions: contents: read diff --git a/.github/workflows/winget-submission.yml b/.github/workflows/winget-submission.yml index 7df63253..c697a6c8 100644 --- a/.github/workflows/winget-submission.yml +++ b/.github/workflows/winget-submission.yml @@ -2,7 +2,7 @@ name: Submit to Windows Package Manager Community Repository on: release: - types: [released] + types: [ released ] workflow_dispatch: inputs: tag_name: diff --git a/.gitignore b/.gitignore index b8b851db..ec2a06da 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ node_modules /dist +/pack electron-builder.yml .vscode/settings.json .idea diff --git a/.yarn/patches/electron-is-dev-npm-2.0.0-9d41637d91.patch b/.yarn/patches/electron-is-dev-npm-2.0.0-9d41637d91.patch deleted file mode 100644 index ae749982..00000000 --- a/.yarn/patches/electron-is-dev-npm-2.0.0-9d41637d91.patch +++ /dev/null @@ -1,24 +0,0 @@ -diff --git a/index.js b/index.js -index c8f2fd4467c11b484fe654f7f250e2ba37e8100d..c9ae1ed3d3c7683b14dfe0eee801f5a07585d2aa 100644 ---- a/index.js -+++ b/index.js -@@ -5,7 +5,16 @@ if (typeof electron === 'string') { - throw new TypeError('Not running in an Electron environment!'); - } - --const isEnvSet = 'ELECTRON_IS_DEV' in process.env; --const getFromEnv = Number.parseInt(process.env.ELECTRON_IS_DEV, 10) === 1; -+const isDev = () => { -+ if ('ELECTRON_IS_DEV' in process.env) { -+ return Number.parseInt(process.env.ELECTRON_IS_DEV, 10) === 1; -+ } - --module.exports = isEnvSet ? getFromEnv : !electron.app.isPackaged; -+ if (process.type === 'browser') { -+ return !electron.app.isPackaged; -+ } -+ -+ return 'npm_package_name' in process.env; -+}; -+ -+module.exports = isDev(); diff --git a/.yarn/plugins/@yarnpkg/plugin-after-install.cjs b/.yarn/plugins/@yarnpkg/plugin-after-install.cjs deleted file mode 100644 index 070ea99c..00000000 --- a/.yarn/plugins/@yarnpkg/plugin-after-install.cjs +++ /dev/null @@ -1,9 +0,0 @@ -/* eslint-disable */ -//prettier-ignore -module.exports = { -name: "@yarnpkg/plugin-after-install", -factory: function (require) { -var plugin=(()=>{var g=Object.create,r=Object.defineProperty;var x=Object.getOwnPropertyDescriptor;var C=Object.getOwnPropertyNames;var k=Object.getPrototypeOf,y=Object.prototype.hasOwnProperty;var I=t=>r(t,"__esModule",{value:!0});var i=t=>{if(typeof require!="undefined")return require(t);throw new Error('Dynamic require of "'+t+'" is not supported')};var h=(t,o)=>{for(var e in o)r(t,e,{get:o[e],enumerable:!0})},w=(t,o,e)=>{if(o&&typeof o=="object"||typeof o=="function")for(let n of C(o))!y.call(t,n)&&n!=="default"&&r(t,n,{get:()=>o[n],enumerable:!(e=x(o,n))||e.enumerable});return t},a=t=>w(I(r(t!=null?g(k(t)):{},"default",t&&t.__esModule&&"default"in t?{get:()=>t.default,enumerable:!0}:{value:t,enumerable:!0})),t);var j={};h(j,{default:()=>b});var c=a(i("@yarnpkg/core")),m={afterInstall:{description:"Hook that will always run after install",type:c.SettingsType.STRING,default:""}};var u=a(i("clipanion")),d=a(i("@yarnpkg/core"));var p=a(i("@yarnpkg/shell")),l=async(t,o)=>{var f;let e=t.get("afterInstall"),n=!!((f=t.projectCwd)==null?void 0:f.endsWith(`dlx-${process.pid}`));return e&&!n?(o&&console.log("Running `afterInstall` hook..."),(0,p.execute)(e,[],{cwd:t.projectCwd||void 0})):0};var s=class extends u.Command{async execute(){let o=await d.Configuration.find(this.context.cwd,this.context.plugins);return l(o,!1)}};s.paths=[["after-install"]];var P={configuration:m,commands:[s],hooks:{afterAllInstalled:async t=>{if(await l(t.configuration,!0))throw new Error("The `afterInstall` hook failed, see output above.")}}},b=P;return j;})(); -return plugin; -} -}; diff --git a/.yarn/releases/yarn-3.4.1.cjs b/.yarn/releases/yarn-3.4.1.cjs deleted file mode 100755 index 2bdb752d..00000000 --- a/.yarn/releases/yarn-3.4.1.cjs +++ /dev/null @@ -1,873 +0,0 @@ -#!/usr/bin/env node -/* eslint-disable */ -//prettier-ignore -(()=>{var Mue=Object.create;var Wb=Object.defineProperty;var Kue=Object.getOwnPropertyDescriptor;var Uue=Object.getOwnPropertyNames;var Hue=Object.getPrototypeOf,Gue=Object.prototype.hasOwnProperty;var J=(r=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(r,{get:(e,t)=>(typeof require<"u"?require:e)[t]}):r)(function(r){if(typeof require<"u")return require.apply(this,arguments);throw new Error('Dynamic require of "'+r+'" is not supported')});var Yue=(r,e)=>()=>(r&&(e=r(r=0)),e);var w=(r,e)=>()=>(e||r((e={exports:{}}).exports,e),e.exports),ut=(r,e)=>{for(var t in e)Wb(r,t,{get:e[t],enumerable:!0})},jue=(r,e,t,i)=>{if(e&&typeof e=="object"||typeof e=="function")for(let n of Uue(e))!Gue.call(r,n)&&n!==t&&Wb(r,n,{get:()=>e[n],enumerable:!(i=Kue(e,n))||i.enumerable});return r};var Pe=(r,e,t)=>(t=r!=null?Mue(Hue(r)):{},jue(e||!r||!r.__esModule?Wb(t,"default",{value:r,enumerable:!0}):t,r));var _1=w((O7e,X1)=>{X1.exports=V1;V1.sync=uge;var W1=J("fs");function cge(r,e){var t=e.pathExt!==void 0?e.pathExt:process.env.PATHEXT;if(!t||(t=t.split(";"),t.indexOf("")!==-1))return!0;for(var i=0;i{tK.exports=$1;$1.sync=gge;var Z1=J("fs");function $1(r,e,t){Z1.stat(r,function(i,n){t(i,i?!1:eK(n,e))})}function gge(r,e){return eK(Z1.statSync(r),e)}function eK(r,e){return r.isFile()&&fge(r,e)}function fge(r,e){var t=r.mode,i=r.uid,n=r.gid,s=e.uid!==void 0?e.uid:process.getuid&&process.getuid(),o=e.gid!==void 0?e.gid:process.getgid&&process.getgid(),a=parseInt("100",8),l=parseInt("010",8),c=parseInt("001",8),u=a|l,g=t&c||t&l&&n===o||t&a&&i===s||t&u&&s===0;return g}});var nK=w((U7e,iK)=>{var K7e=J("fs"),_E;process.platform==="win32"||global.TESTING_WINDOWS?_E=_1():_E=rK();iK.exports=uS;uS.sync=hge;function uS(r,e,t){if(typeof e=="function"&&(t=e,e={}),!t){if(typeof Promise!="function")throw new TypeError("callback not provided");return new Promise(function(i,n){uS(r,e||{},function(s,o){s?n(s):i(o)})})}_E(r,e||{},function(i,n){i&&(i.code==="EACCES"||e&&e.ignoreErrors)&&(i=null,n=!1),t(i,n)})}function hge(r,e){try{return _E.sync(r,e||{})}catch(t){if(e&&e.ignoreErrors||t.code==="EACCES")return!1;throw t}}});var uK=w((H7e,cK)=>{var Ig=process.platform==="win32"||process.env.OSTYPE==="cygwin"||process.env.OSTYPE==="msys",sK=J("path"),pge=Ig?";":":",oK=nK(),aK=r=>Object.assign(new Error(`not found: ${r}`),{code:"ENOENT"}),AK=(r,e)=>{let t=e.colon||pge,i=r.match(/\//)||Ig&&r.match(/\\/)?[""]:[...Ig?[process.cwd()]:[],...(e.path||process.env.PATH||"").split(t)],n=Ig?e.pathExt||process.env.PATHEXT||".EXE;.CMD;.BAT;.COM":"",s=Ig?n.split(t):[""];return Ig&&r.indexOf(".")!==-1&&s[0]!==""&&s.unshift(""),{pathEnv:i,pathExt:s,pathExtExe:n}},lK=(r,e,t)=>{typeof e=="function"&&(t=e,e={}),e||(e={});let{pathEnv:i,pathExt:n,pathExtExe:s}=AK(r,e),o=[],a=c=>new Promise((u,g)=>{if(c===i.length)return e.all&&o.length?u(o):g(aK(r));let f=i[c],h=/^".*"$/.test(f)?f.slice(1,-1):f,p=sK.join(h,r),C=!h&&/^\.[\\\/]/.test(r)?r.slice(0,2)+p:p;u(l(C,c,0))}),l=(c,u,g)=>new Promise((f,h)=>{if(g===n.length)return f(a(u+1));let p=n[g];oK(c+p,{pathExt:s},(C,y)=>{if(!C&&y)if(e.all)o.push(c+p);else return f(c+p);return f(l(c,u,g+1))})});return t?a(0).then(c=>t(null,c),t):a(0)},dge=(r,e)=>{e=e||{};let{pathEnv:t,pathExt:i,pathExtExe:n}=AK(r,e),s=[];for(let o=0;o{"use strict";var gK=(r={})=>{let e=r.env||process.env;return(r.platform||process.platform)!=="win32"?"PATH":Object.keys(e).reverse().find(i=>i.toUpperCase()==="PATH")||"Path"};gS.exports=gK;gS.exports.default=gK});var CK=w((Y7e,dK)=>{"use strict";var hK=J("path"),Cge=uK(),mge=fK();function pK(r,e){let t=r.options.env||process.env,i=process.cwd(),n=r.options.cwd!=null,s=n&&process.chdir!==void 0&&!process.chdir.disabled;if(s)try{process.chdir(r.options.cwd)}catch{}let o;try{o=Cge.sync(r.command,{path:t[mge({env:t})],pathExt:e?hK.delimiter:void 0})}catch{}finally{s&&process.chdir(i)}return o&&(o=hK.resolve(n?r.options.cwd:"",o)),o}function Ege(r){return pK(r)||pK(r,!0)}dK.exports=Ege});var mK=w((j7e,hS)=>{"use strict";var fS=/([()\][%!^"`<>&|;, *?])/g;function Ige(r){return r=r.replace(fS,"^$1"),r}function yge(r,e){return r=`${r}`,r=r.replace(/(\\*)"/g,'$1$1\\"'),r=r.replace(/(\\*)$/,"$1$1"),r=`"${r}"`,r=r.replace(fS,"^$1"),e&&(r=r.replace(fS,"^$1")),r}hS.exports.command=Ige;hS.exports.argument=yge});var IK=w((q7e,EK)=>{"use strict";EK.exports=/^#!(.*)/});var wK=w((J7e,yK)=>{"use strict";var wge=IK();yK.exports=(r="")=>{let e=r.match(wge);if(!e)return null;let[t,i]=e[0].replace(/#! ?/,"").split(" "),n=t.split("/").pop();return n==="env"?i:i?`${n} ${i}`:n}});var QK=w((W7e,BK)=>{"use strict";var pS=J("fs"),Bge=wK();function Qge(r){let t=Buffer.alloc(150),i;try{i=pS.openSync(r,"r"),pS.readSync(i,t,0,150,0),pS.closeSync(i)}catch{}return Bge(t.toString())}BK.exports=Qge});var xK=w((z7e,vK)=>{"use strict";var bge=J("path"),bK=CK(),SK=mK(),Sge=QK(),vge=process.platform==="win32",xge=/\.(?:com|exe)$/i,Pge=/node_modules[\\/].bin[\\/][^\\/]+\.cmd$/i;function Dge(r){r.file=bK(r);let e=r.file&&Sge(r.file);return e?(r.args.unshift(r.file),r.command=e,bK(r)):r.file}function kge(r){if(!vge)return r;let e=Dge(r),t=!xge.test(e);if(r.options.forceShell||t){let i=Pge.test(e);r.command=bge.normalize(r.command),r.command=SK.command(r.command),r.args=r.args.map(s=>SK.argument(s,i));let n=[r.command].concat(r.args).join(" ");r.args=["/d","/s","/c",`"${n}"`],r.command=process.env.comspec||"cmd.exe",r.options.windowsVerbatimArguments=!0}return r}function Rge(r,e,t){e&&!Array.isArray(e)&&(t=e,e=null),e=e?e.slice(0):[],t=Object.assign({},t);let i={command:r,args:e,options:t,file:void 0,original:{command:r,args:e}};return t.shell?i:kge(i)}vK.exports=Rge});var kK=w((V7e,DK)=>{"use strict";var dS=process.platform==="win32";function CS(r,e){return Object.assign(new Error(`${e} ${r.command} ENOENT`),{code:"ENOENT",errno:"ENOENT",syscall:`${e} ${r.command}`,path:r.command,spawnargs:r.args})}function Fge(r,e){if(!dS)return;let t=r.emit;r.emit=function(i,n){if(i==="exit"){let s=PK(n,e,"spawn");if(s)return t.call(r,"error",s)}return t.apply(r,arguments)}}function PK(r,e){return dS&&r===1&&!e.file?CS(e.original,"spawn"):null}function Nge(r,e){return dS&&r===1&&!e.file?CS(e.original,"spawnSync"):null}DK.exports={hookChildProcess:Fge,verifyENOENT:PK,verifyENOENTSync:Nge,notFoundError:CS}});var IS=w((X7e,yg)=>{"use strict";var RK=J("child_process"),mS=xK(),ES=kK();function FK(r,e,t){let i=mS(r,e,t),n=RK.spawn(i.command,i.args,i.options);return ES.hookChildProcess(n,i),n}function Lge(r,e,t){let i=mS(r,e,t),n=RK.spawnSync(i.command,i.args,i.options);return n.error=n.error||ES.verifyENOENTSync(n.status,i),n}yg.exports=FK;yg.exports.spawn=FK;yg.exports.sync=Lge;yg.exports._parse=mS;yg.exports._enoent=ES});var LK=w((_7e,NK)=>{"use strict";function Tge(r,e){function t(){this.constructor=r}t.prototype=e.prototype,r.prototype=new t}function Ml(r,e,t,i){this.message=r,this.expected=e,this.found=t,this.location=i,this.name="SyntaxError",typeof Error.captureStackTrace=="function"&&Error.captureStackTrace(this,Ml)}Tge(Ml,Error);Ml.buildMessage=function(r,e){var t={literal:function(c){return'"'+n(c.text)+'"'},class:function(c){var u="",g;for(g=0;g0){for(g=1,f=1;g>",ie=me(">>",!1),de=">&",tt=me(">&",!1),Pt=">",It=me(">",!1),Or="<<<",ii=me("<<<",!1),gi="<&",hr=me("<&",!1),fi="<",ni=me("<",!1),Ls=function(m){return{type:"argument",segments:[].concat(...m)}},pr=function(m){return m},Ei="$'",_n=me("$'",!1),oa="'",aA=me("'",!1),eg=function(m){return[{type:"text",text:m}]},Zn='""',AA=me('""',!1),aa=function(){return{type:"text",text:""}},up='"',lA=me('"',!1),cA=function(m){return m},wr=function(m){return{type:"arithmetic",arithmetic:m,quoted:!0}},wl=function(m){return{type:"shell",shell:m,quoted:!0}},tg=function(m){return{type:"variable",...m,quoted:!0}},po=function(m){return{type:"text",text:m}},rg=function(m){return{type:"arithmetic",arithmetic:m,quoted:!1}},gp=function(m){return{type:"shell",shell:m,quoted:!1}},fp=function(m){return{type:"variable",...m,quoted:!1}},vr=function(m){return{type:"glob",pattern:m}},se=/^[^']/,Co=Je(["'"],!0,!1),Dn=function(m){return m.join("")},ig=/^[^$"]/,Qt=Je(["$",'"'],!0,!1),Bl=`\\ -`,kn=me(`\\ -`,!1),$n=function(){return""},es="\\",gt=me("\\",!1),mo=/^[\\$"`]/,At=Je(["\\","$",'"',"`"],!1,!1),an=function(m){return m},S="\\a",Tt=me("\\a",!1),ng=function(){return"a"},Ql="\\b",hp=me("\\b",!1),pp=function(){return"\b"},dp=/^[Ee]/,Cp=Je(["E","e"],!1,!1),mp=function(){return"\x1B"},G="\\f",yt=me("\\f",!1),uA=function(){return"\f"},ji="\\n",bl=me("\\n",!1),Xe=function(){return` -`},Aa="\\r",sg=me("\\r",!1),bE=function(){return"\r"},Ep="\\t",SE=me("\\t",!1),ar=function(){return" "},Rn="\\v",Sl=me("\\v",!1),Ip=function(){return"\v"},Ts=/^[\\'"?]/,la=Je(["\\","'",'"',"?"],!1,!1),An=function(m){return String.fromCharCode(parseInt(m,16))},Te="\\x",og=me("\\x",!1),vl="\\u",Os=me("\\u",!1),xl="\\U",gA=me("\\U",!1),ag=function(m){return String.fromCodePoint(parseInt(m,16))},Ag=/^[0-7]/,ca=Je([["0","7"]],!1,!1),ua=/^[0-9a-fA-f]/,rt=Je([["0","9"],["a","f"],["A","f"]],!1,!1),Eo=nt(),fA="-",Pl=me("-",!1),Ms="+",Dl=me("+",!1),vE=".",yp=me(".",!1),lg=function(m,b,N){return{type:"number",value:(m==="-"?-1:1)*parseFloat(b.join("")+"."+N.join(""))}},wp=function(m,b){return{type:"number",value:(m==="-"?-1:1)*parseInt(b.join(""))}},xE=function(m){return{type:"variable",...m}},kl=function(m){return{type:"variable",name:m}},PE=function(m){return m},cg="*",hA=me("*",!1),Rr="/",DE=me("/",!1),Ks=function(m,b,N){return{type:b==="*"?"multiplication":"division",right:N}},Us=function(m,b){return b.reduce((N,U)=>({left:N,...U}),m)},ug=function(m,b,N){return{type:b==="+"?"addition":"subtraction",right:N}},pA="$((",R=me("$((",!1),q="))",Ce=me("))",!1),Ke=function(m){return m},Re="$(",ze=me("$(",!1),dt=function(m){return m},Ft="${",Fn=me("${",!1),Db=":-",$M=me(":-",!1),e1=function(m,b){return{name:m,defaultValue:b}},kb=":-}",t1=me(":-}",!1),r1=function(m){return{name:m,defaultValue:[]}},Rb=":+",i1=me(":+",!1),n1=function(m,b){return{name:m,alternativeValue:b}},Fb=":+}",s1=me(":+}",!1),o1=function(m){return{name:m,alternativeValue:[]}},Nb=function(m){return{name:m}},a1="$",A1=me("$",!1),l1=function(m){return e.isGlobPattern(m)},c1=function(m){return m},Lb=/^[a-zA-Z0-9_]/,Tb=Je([["a","z"],["A","Z"],["0","9"],"_"],!1,!1),Ob=function(){return T()},Mb=/^[$@*?#a-zA-Z0-9_\-]/,Kb=Je(["$","@","*","?","#",["a","z"],["A","Z"],["0","9"],"_","-"],!1,!1),u1=/^[(){}<>$|&; \t"']/,gg=Je(["(",")","{","}","<",">","$","|","&",";"," "," ",'"',"'"],!1,!1),Ub=/^[<>&; \t"']/,Hb=Je(["<",">","&",";"," "," ",'"',"'"],!1,!1),kE=/^[ \t]/,RE=Je([" "," "],!1,!1),Q=0,Me=0,dA=[{line:1,column:1}],d=0,E=[],I=0,k;if("startRule"in e){if(!(e.startRule in i))throw new Error(`Can't start parsing from rule "`+e.startRule+'".');n=i[e.startRule]}function T(){return r.substring(Me,Q)}function _(){return Et(Me,Q)}function te(m,b){throw b=b!==void 0?b:Et(Me,Q),ki([lt(m)],r.substring(Me,Q),b)}function Be(m,b){throw b=b!==void 0?b:Et(Me,Q),Nn(m,b)}function me(m,b){return{type:"literal",text:m,ignoreCase:b}}function Je(m,b,N){return{type:"class",parts:m,inverted:b,ignoreCase:N}}function nt(){return{type:"any"}}function wt(){return{type:"end"}}function lt(m){return{type:"other",description:m}}function it(m){var b=dA[m],N;if(b)return b;for(N=m-1;!dA[N];)N--;for(b=dA[N],b={line:b.line,column:b.column};Nd&&(d=Q,E=[]),E.push(m))}function Nn(m,b){return new Ml(m,null,null,b)}function ki(m,b,N){return new Ml(Ml.buildMessage(m,b),m,b,N)}function CA(){var m,b;return m=Q,b=Mr(),b===t&&(b=null),b!==t&&(Me=m,b=s(b)),m=b,m}function Mr(){var m,b,N,U,ce;if(m=Q,b=Kr(),b!==t){for(N=[],U=He();U!==t;)N.push(U),U=He();N!==t?(U=ga(),U!==t?(ce=ts(),ce===t&&(ce=null),ce!==t?(Me=m,b=o(b,U,ce),m=b):(Q=m,m=t)):(Q=m,m=t)):(Q=m,m=t)}else Q=m,m=t;if(m===t)if(m=Q,b=Kr(),b!==t){for(N=[],U=He();U!==t;)N.push(U),U=He();N!==t?(U=ga(),U===t&&(U=null),U!==t?(Me=m,b=a(b,U),m=b):(Q=m,m=t)):(Q=m,m=t)}else Q=m,m=t;return m}function ts(){var m,b,N,U,ce;for(m=Q,b=[],N=He();N!==t;)b.push(N),N=He();if(b!==t)if(N=Mr(),N!==t){for(U=[],ce=He();ce!==t;)U.push(ce),ce=He();U!==t?(Me=m,b=l(N),m=b):(Q=m,m=t)}else Q=m,m=t;else Q=m,m=t;return m}function ga(){var m;return r.charCodeAt(Q)===59?(m=c,Q++):(m=t,I===0&&Qe(u)),m===t&&(r.charCodeAt(Q)===38?(m=g,Q++):(m=t,I===0&&Qe(f))),m}function Kr(){var m,b,N;return m=Q,b=g1(),b!==t?(N=yue(),N===t&&(N=null),N!==t?(Me=m,b=h(b,N),m=b):(Q=m,m=t)):(Q=m,m=t),m}function yue(){var m,b,N,U,ce,Se,ht;for(m=Q,b=[],N=He();N!==t;)b.push(N),N=He();if(b!==t)if(N=wue(),N!==t){for(U=[],ce=He();ce!==t;)U.push(ce),ce=He();if(U!==t)if(ce=Kr(),ce!==t){for(Se=[],ht=He();ht!==t;)Se.push(ht),ht=He();Se!==t?(Me=m,b=p(N,ce),m=b):(Q=m,m=t)}else Q=m,m=t;else Q=m,m=t}else Q=m,m=t;else Q=m,m=t;return m}function wue(){var m;return r.substr(Q,2)===C?(m=C,Q+=2):(m=t,I===0&&Qe(y)),m===t&&(r.substr(Q,2)===B?(m=B,Q+=2):(m=t,I===0&&Qe(v))),m}function g1(){var m,b,N;return m=Q,b=bue(),b!==t?(N=Bue(),N===t&&(N=null),N!==t?(Me=m,b=D(b,N),m=b):(Q=m,m=t)):(Q=m,m=t),m}function Bue(){var m,b,N,U,ce,Se,ht;for(m=Q,b=[],N=He();N!==t;)b.push(N),N=He();if(b!==t)if(N=Que(),N!==t){for(U=[],ce=He();ce!==t;)U.push(ce),ce=He();if(U!==t)if(ce=g1(),ce!==t){for(Se=[],ht=He();ht!==t;)Se.push(ht),ht=He();Se!==t?(Me=m,b=L(N,ce),m=b):(Q=m,m=t)}else Q=m,m=t;else Q=m,m=t}else Q=m,m=t;else Q=m,m=t;return m}function Que(){var m;return r.substr(Q,2)===H?(m=H,Q+=2):(m=t,I===0&&Qe(j)),m===t&&(r.charCodeAt(Q)===124?(m=$,Q++):(m=t,I===0&&Qe(V))),m}function FE(){var m,b,N,U,ce,Se;if(m=Q,b=Q1(),b!==t)if(r.charCodeAt(Q)===61?(N=W,Q++):(N=t,I===0&&Qe(Z)),N!==t)if(U=p1(),U!==t){for(ce=[],Se=He();Se!==t;)ce.push(Se),Se=He();ce!==t?(Me=m,b=A(b,U),m=b):(Q=m,m=t)}else Q=m,m=t;else Q=m,m=t;else Q=m,m=t;if(m===t)if(m=Q,b=Q1(),b!==t)if(r.charCodeAt(Q)===61?(N=W,Q++):(N=t,I===0&&Qe(Z)),N!==t){for(U=[],ce=He();ce!==t;)U.push(ce),ce=He();U!==t?(Me=m,b=ae(b),m=b):(Q=m,m=t)}else Q=m,m=t;else Q=m,m=t;return m}function bue(){var m,b,N,U,ce,Se,ht,Bt,Jr,hi,rs;for(m=Q,b=[],N=He();N!==t;)b.push(N),N=He();if(b!==t)if(r.charCodeAt(Q)===40?(N=ge,Q++):(N=t,I===0&&Qe(re)),N!==t){for(U=[],ce=He();ce!==t;)U.push(ce),ce=He();if(U!==t)if(ce=Mr(),ce!==t){for(Se=[],ht=He();ht!==t;)Se.push(ht),ht=He();if(Se!==t)if(r.charCodeAt(Q)===41?(ht=O,Q++):(ht=t,I===0&&Qe(F)),ht!==t){for(Bt=[],Jr=He();Jr!==t;)Bt.push(Jr),Jr=He();if(Bt!==t){for(Jr=[],hi=Bp();hi!==t;)Jr.push(hi),hi=Bp();if(Jr!==t){for(hi=[],rs=He();rs!==t;)hi.push(rs),rs=He();hi!==t?(Me=m,b=ue(ce,Jr),m=b):(Q=m,m=t)}else Q=m,m=t}else Q=m,m=t}else Q=m,m=t;else Q=m,m=t}else Q=m,m=t;else Q=m,m=t}else Q=m,m=t;else Q=m,m=t;if(m===t){for(m=Q,b=[],N=He();N!==t;)b.push(N),N=He();if(b!==t)if(r.charCodeAt(Q)===123?(N=he,Q++):(N=t,I===0&&Qe(ke)),N!==t){for(U=[],ce=He();ce!==t;)U.push(ce),ce=He();if(U!==t)if(ce=Mr(),ce!==t){for(Se=[],ht=He();ht!==t;)Se.push(ht),ht=He();if(Se!==t)if(r.charCodeAt(Q)===125?(ht=Fe,Q++):(ht=t,I===0&&Qe(Ne)),ht!==t){for(Bt=[],Jr=He();Jr!==t;)Bt.push(Jr),Jr=He();if(Bt!==t){for(Jr=[],hi=Bp();hi!==t;)Jr.push(hi),hi=Bp();if(Jr!==t){for(hi=[],rs=He();rs!==t;)hi.push(rs),rs=He();hi!==t?(Me=m,b=oe(ce,Jr),m=b):(Q=m,m=t)}else Q=m,m=t}else Q=m,m=t}else Q=m,m=t;else Q=m,m=t}else Q=m,m=t;else Q=m,m=t}else Q=m,m=t;else Q=m,m=t;if(m===t){for(m=Q,b=[],N=He();N!==t;)b.push(N),N=He();if(b!==t){for(N=[],U=FE();U!==t;)N.push(U),U=FE();if(N!==t){for(U=[],ce=He();ce!==t;)U.push(ce),ce=He();if(U!==t){if(ce=[],Se=h1(),Se!==t)for(;Se!==t;)ce.push(Se),Se=h1();else ce=t;if(ce!==t){for(Se=[],ht=He();ht!==t;)Se.push(ht),ht=He();Se!==t?(Me=m,b=le(N,ce),m=b):(Q=m,m=t)}else Q=m,m=t}else Q=m,m=t}else Q=m,m=t}else Q=m,m=t;if(m===t){for(m=Q,b=[],N=He();N!==t;)b.push(N),N=He();if(b!==t){if(N=[],U=FE(),U!==t)for(;U!==t;)N.push(U),U=FE();else N=t;if(N!==t){for(U=[],ce=He();ce!==t;)U.push(ce),ce=He();U!==t?(Me=m,b=we(N),m=b):(Q=m,m=t)}else Q=m,m=t}else Q=m,m=t}}}return m}function f1(){var m,b,N,U,ce;for(m=Q,b=[],N=He();N!==t;)b.push(N),N=He();if(b!==t){if(N=[],U=NE(),U!==t)for(;U!==t;)N.push(U),U=NE();else N=t;if(N!==t){for(U=[],ce=He();ce!==t;)U.push(ce),ce=He();U!==t?(Me=m,b=fe(N),m=b):(Q=m,m=t)}else Q=m,m=t}else Q=m,m=t;return m}function h1(){var m,b,N;for(m=Q,b=[],N=He();N!==t;)b.push(N),N=He();if(b!==t?(N=Bp(),N!==t?(Me=m,b=Ae(N),m=b):(Q=m,m=t)):(Q=m,m=t),m===t){for(m=Q,b=[],N=He();N!==t;)b.push(N),N=He();b!==t?(N=NE(),N!==t?(Me=m,b=Ae(N),m=b):(Q=m,m=t)):(Q=m,m=t)}return m}function Bp(){var m,b,N,U,ce;for(m=Q,b=[],N=He();N!==t;)b.push(N),N=He();return b!==t?(qe.test(r.charAt(Q))?(N=r.charAt(Q),Q++):(N=t,I===0&&Qe(ne)),N===t&&(N=null),N!==t?(U=Sue(),U!==t?(ce=NE(),ce!==t?(Me=m,b=Y(N,U,ce),m=b):(Q=m,m=t)):(Q=m,m=t)):(Q=m,m=t)):(Q=m,m=t),m}function Sue(){var m;return r.substr(Q,2)===pe?(m=pe,Q+=2):(m=t,I===0&&Qe(ie)),m===t&&(r.substr(Q,2)===de?(m=de,Q+=2):(m=t,I===0&&Qe(tt)),m===t&&(r.charCodeAt(Q)===62?(m=Pt,Q++):(m=t,I===0&&Qe(It)),m===t&&(r.substr(Q,3)===Or?(m=Or,Q+=3):(m=t,I===0&&Qe(ii)),m===t&&(r.substr(Q,2)===gi?(m=gi,Q+=2):(m=t,I===0&&Qe(hr)),m===t&&(r.charCodeAt(Q)===60?(m=fi,Q++):(m=t,I===0&&Qe(ni))))))),m}function NE(){var m,b,N;for(m=Q,b=[],N=He();N!==t;)b.push(N),N=He();return b!==t?(N=p1(),N!==t?(Me=m,b=Ae(N),m=b):(Q=m,m=t)):(Q=m,m=t),m}function p1(){var m,b,N;if(m=Q,b=[],N=d1(),N!==t)for(;N!==t;)b.push(N),N=d1();else b=t;return b!==t&&(Me=m,b=Ls(b)),m=b,m}function d1(){var m,b;return m=Q,b=vue(),b!==t&&(Me=m,b=pr(b)),m=b,m===t&&(m=Q,b=xue(),b!==t&&(Me=m,b=pr(b)),m=b,m===t&&(m=Q,b=Pue(),b!==t&&(Me=m,b=pr(b)),m=b,m===t&&(m=Q,b=Due(),b!==t&&(Me=m,b=pr(b)),m=b))),m}function vue(){var m,b,N,U;return m=Q,r.substr(Q,2)===Ei?(b=Ei,Q+=2):(b=t,I===0&&Qe(_n)),b!==t?(N=Fue(),N!==t?(r.charCodeAt(Q)===39?(U=oa,Q++):(U=t,I===0&&Qe(aA)),U!==t?(Me=m,b=eg(N),m=b):(Q=m,m=t)):(Q=m,m=t)):(Q=m,m=t),m}function xue(){var m,b,N,U;return m=Q,r.charCodeAt(Q)===39?(b=oa,Q++):(b=t,I===0&&Qe(aA)),b!==t?(N=kue(),N!==t?(r.charCodeAt(Q)===39?(U=oa,Q++):(U=t,I===0&&Qe(aA)),U!==t?(Me=m,b=eg(N),m=b):(Q=m,m=t)):(Q=m,m=t)):(Q=m,m=t),m}function Pue(){var m,b,N,U;if(m=Q,r.substr(Q,2)===Zn?(b=Zn,Q+=2):(b=t,I===0&&Qe(AA)),b!==t&&(Me=m,b=aa()),m=b,m===t)if(m=Q,r.charCodeAt(Q)===34?(b=up,Q++):(b=t,I===0&&Qe(lA)),b!==t){for(N=[],U=C1();U!==t;)N.push(U),U=C1();N!==t?(r.charCodeAt(Q)===34?(U=up,Q++):(U=t,I===0&&Qe(lA)),U!==t?(Me=m,b=cA(N),m=b):(Q=m,m=t)):(Q=m,m=t)}else Q=m,m=t;return m}function Due(){var m,b,N;if(m=Q,b=[],N=m1(),N!==t)for(;N!==t;)b.push(N),N=m1();else b=t;return b!==t&&(Me=m,b=cA(b)),m=b,m}function C1(){var m,b;return m=Q,b=w1(),b!==t&&(Me=m,b=wr(b)),m=b,m===t&&(m=Q,b=B1(),b!==t&&(Me=m,b=wl(b)),m=b,m===t&&(m=Q,b=qb(),b!==t&&(Me=m,b=tg(b)),m=b,m===t&&(m=Q,b=Rue(),b!==t&&(Me=m,b=po(b)),m=b))),m}function m1(){var m,b;return m=Q,b=w1(),b!==t&&(Me=m,b=rg(b)),m=b,m===t&&(m=Q,b=B1(),b!==t&&(Me=m,b=gp(b)),m=b,m===t&&(m=Q,b=qb(),b!==t&&(Me=m,b=fp(b)),m=b,m===t&&(m=Q,b=Tue(),b!==t&&(Me=m,b=vr(b)),m=b,m===t&&(m=Q,b=Lue(),b!==t&&(Me=m,b=po(b)),m=b)))),m}function kue(){var m,b,N;for(m=Q,b=[],se.test(r.charAt(Q))?(N=r.charAt(Q),Q++):(N=t,I===0&&Qe(Co));N!==t;)b.push(N),se.test(r.charAt(Q))?(N=r.charAt(Q),Q++):(N=t,I===0&&Qe(Co));return b!==t&&(Me=m,b=Dn(b)),m=b,m}function Rue(){var m,b,N;if(m=Q,b=[],N=E1(),N===t&&(ig.test(r.charAt(Q))?(N=r.charAt(Q),Q++):(N=t,I===0&&Qe(Qt))),N!==t)for(;N!==t;)b.push(N),N=E1(),N===t&&(ig.test(r.charAt(Q))?(N=r.charAt(Q),Q++):(N=t,I===0&&Qe(Qt)));else b=t;return b!==t&&(Me=m,b=Dn(b)),m=b,m}function E1(){var m,b,N;return m=Q,r.substr(Q,2)===Bl?(b=Bl,Q+=2):(b=t,I===0&&Qe(kn)),b!==t&&(Me=m,b=$n()),m=b,m===t&&(m=Q,r.charCodeAt(Q)===92?(b=es,Q++):(b=t,I===0&&Qe(gt)),b!==t?(mo.test(r.charAt(Q))?(N=r.charAt(Q),Q++):(N=t,I===0&&Qe(At)),N!==t?(Me=m,b=an(N),m=b):(Q=m,m=t)):(Q=m,m=t)),m}function Fue(){var m,b,N;for(m=Q,b=[],N=I1(),N===t&&(se.test(r.charAt(Q))?(N=r.charAt(Q),Q++):(N=t,I===0&&Qe(Co)));N!==t;)b.push(N),N=I1(),N===t&&(se.test(r.charAt(Q))?(N=r.charAt(Q),Q++):(N=t,I===0&&Qe(Co)));return b!==t&&(Me=m,b=Dn(b)),m=b,m}function I1(){var m,b,N;return m=Q,r.substr(Q,2)===S?(b=S,Q+=2):(b=t,I===0&&Qe(Tt)),b!==t&&(Me=m,b=ng()),m=b,m===t&&(m=Q,r.substr(Q,2)===Ql?(b=Ql,Q+=2):(b=t,I===0&&Qe(hp)),b!==t&&(Me=m,b=pp()),m=b,m===t&&(m=Q,r.charCodeAt(Q)===92?(b=es,Q++):(b=t,I===0&&Qe(gt)),b!==t?(dp.test(r.charAt(Q))?(N=r.charAt(Q),Q++):(N=t,I===0&&Qe(Cp)),N!==t?(Me=m,b=mp(),m=b):(Q=m,m=t)):(Q=m,m=t),m===t&&(m=Q,r.substr(Q,2)===G?(b=G,Q+=2):(b=t,I===0&&Qe(yt)),b!==t&&(Me=m,b=uA()),m=b,m===t&&(m=Q,r.substr(Q,2)===ji?(b=ji,Q+=2):(b=t,I===0&&Qe(bl)),b!==t&&(Me=m,b=Xe()),m=b,m===t&&(m=Q,r.substr(Q,2)===Aa?(b=Aa,Q+=2):(b=t,I===0&&Qe(sg)),b!==t&&(Me=m,b=bE()),m=b,m===t&&(m=Q,r.substr(Q,2)===Ep?(b=Ep,Q+=2):(b=t,I===0&&Qe(SE)),b!==t&&(Me=m,b=ar()),m=b,m===t&&(m=Q,r.substr(Q,2)===Rn?(b=Rn,Q+=2):(b=t,I===0&&Qe(Sl)),b!==t&&(Me=m,b=Ip()),m=b,m===t&&(m=Q,r.charCodeAt(Q)===92?(b=es,Q++):(b=t,I===0&&Qe(gt)),b!==t?(Ts.test(r.charAt(Q))?(N=r.charAt(Q),Q++):(N=t,I===0&&Qe(la)),N!==t?(Me=m,b=an(N),m=b):(Q=m,m=t)):(Q=m,m=t),m===t&&(m=Nue()))))))))),m}function Nue(){var m,b,N,U,ce,Se,ht,Bt,Jr,hi,rs,Jb;return m=Q,r.charCodeAt(Q)===92?(b=es,Q++):(b=t,I===0&&Qe(gt)),b!==t?(N=Gb(),N!==t?(Me=m,b=An(N),m=b):(Q=m,m=t)):(Q=m,m=t),m===t&&(m=Q,r.substr(Q,2)===Te?(b=Te,Q+=2):(b=t,I===0&&Qe(og)),b!==t?(N=Q,U=Q,ce=Gb(),ce!==t?(Se=Ln(),Se!==t?(ce=[ce,Se],U=ce):(Q=U,U=t)):(Q=U,U=t),U===t&&(U=Gb()),U!==t?N=r.substring(N,Q):N=U,N!==t?(Me=m,b=An(N),m=b):(Q=m,m=t)):(Q=m,m=t),m===t&&(m=Q,r.substr(Q,2)===vl?(b=vl,Q+=2):(b=t,I===0&&Qe(Os)),b!==t?(N=Q,U=Q,ce=Ln(),ce!==t?(Se=Ln(),Se!==t?(ht=Ln(),ht!==t?(Bt=Ln(),Bt!==t?(ce=[ce,Se,ht,Bt],U=ce):(Q=U,U=t)):(Q=U,U=t)):(Q=U,U=t)):(Q=U,U=t),U!==t?N=r.substring(N,Q):N=U,N!==t?(Me=m,b=An(N),m=b):(Q=m,m=t)):(Q=m,m=t),m===t&&(m=Q,r.substr(Q,2)===xl?(b=xl,Q+=2):(b=t,I===0&&Qe(gA)),b!==t?(N=Q,U=Q,ce=Ln(),ce!==t?(Se=Ln(),Se!==t?(ht=Ln(),ht!==t?(Bt=Ln(),Bt!==t?(Jr=Ln(),Jr!==t?(hi=Ln(),hi!==t?(rs=Ln(),rs!==t?(Jb=Ln(),Jb!==t?(ce=[ce,Se,ht,Bt,Jr,hi,rs,Jb],U=ce):(Q=U,U=t)):(Q=U,U=t)):(Q=U,U=t)):(Q=U,U=t)):(Q=U,U=t)):(Q=U,U=t)):(Q=U,U=t)):(Q=U,U=t),U!==t?N=r.substring(N,Q):N=U,N!==t?(Me=m,b=ag(N),m=b):(Q=m,m=t)):(Q=m,m=t)))),m}function Gb(){var m;return Ag.test(r.charAt(Q))?(m=r.charAt(Q),Q++):(m=t,I===0&&Qe(ca)),m}function Ln(){var m;return ua.test(r.charAt(Q))?(m=r.charAt(Q),Q++):(m=t,I===0&&Qe(rt)),m}function Lue(){var m,b,N,U,ce;if(m=Q,b=[],N=Q,r.charCodeAt(Q)===92?(U=es,Q++):(U=t,I===0&&Qe(gt)),U!==t?(r.length>Q?(ce=r.charAt(Q),Q++):(ce=t,I===0&&Qe(Eo)),ce!==t?(Me=N,U=an(ce),N=U):(Q=N,N=t)):(Q=N,N=t),N===t&&(N=Q,U=Q,I++,ce=b1(),I--,ce===t?U=void 0:(Q=U,U=t),U!==t?(r.length>Q?(ce=r.charAt(Q),Q++):(ce=t,I===0&&Qe(Eo)),ce!==t?(Me=N,U=an(ce),N=U):(Q=N,N=t)):(Q=N,N=t)),N!==t)for(;N!==t;)b.push(N),N=Q,r.charCodeAt(Q)===92?(U=es,Q++):(U=t,I===0&&Qe(gt)),U!==t?(r.length>Q?(ce=r.charAt(Q),Q++):(ce=t,I===0&&Qe(Eo)),ce!==t?(Me=N,U=an(ce),N=U):(Q=N,N=t)):(Q=N,N=t),N===t&&(N=Q,U=Q,I++,ce=b1(),I--,ce===t?U=void 0:(Q=U,U=t),U!==t?(r.length>Q?(ce=r.charAt(Q),Q++):(ce=t,I===0&&Qe(Eo)),ce!==t?(Me=N,U=an(ce),N=U):(Q=N,N=t)):(Q=N,N=t));else b=t;return b!==t&&(Me=m,b=Dn(b)),m=b,m}function Yb(){var m,b,N,U,ce,Se;if(m=Q,r.charCodeAt(Q)===45?(b=fA,Q++):(b=t,I===0&&Qe(Pl)),b===t&&(r.charCodeAt(Q)===43?(b=Ms,Q++):(b=t,I===0&&Qe(Dl))),b===t&&(b=null),b!==t){if(N=[],qe.test(r.charAt(Q))?(U=r.charAt(Q),Q++):(U=t,I===0&&Qe(ne)),U!==t)for(;U!==t;)N.push(U),qe.test(r.charAt(Q))?(U=r.charAt(Q),Q++):(U=t,I===0&&Qe(ne));else N=t;if(N!==t)if(r.charCodeAt(Q)===46?(U=vE,Q++):(U=t,I===0&&Qe(yp)),U!==t){if(ce=[],qe.test(r.charAt(Q))?(Se=r.charAt(Q),Q++):(Se=t,I===0&&Qe(ne)),Se!==t)for(;Se!==t;)ce.push(Se),qe.test(r.charAt(Q))?(Se=r.charAt(Q),Q++):(Se=t,I===0&&Qe(ne));else ce=t;ce!==t?(Me=m,b=lg(b,N,ce),m=b):(Q=m,m=t)}else Q=m,m=t;else Q=m,m=t}else Q=m,m=t;if(m===t){if(m=Q,r.charCodeAt(Q)===45?(b=fA,Q++):(b=t,I===0&&Qe(Pl)),b===t&&(r.charCodeAt(Q)===43?(b=Ms,Q++):(b=t,I===0&&Qe(Dl))),b===t&&(b=null),b!==t){if(N=[],qe.test(r.charAt(Q))?(U=r.charAt(Q),Q++):(U=t,I===0&&Qe(ne)),U!==t)for(;U!==t;)N.push(U),qe.test(r.charAt(Q))?(U=r.charAt(Q),Q++):(U=t,I===0&&Qe(ne));else N=t;N!==t?(Me=m,b=wp(b,N),m=b):(Q=m,m=t)}else Q=m,m=t;if(m===t&&(m=Q,b=qb(),b!==t&&(Me=m,b=xE(b)),m=b,m===t&&(m=Q,b=Rl(),b!==t&&(Me=m,b=kl(b)),m=b,m===t)))if(m=Q,r.charCodeAt(Q)===40?(b=ge,Q++):(b=t,I===0&&Qe(re)),b!==t){for(N=[],U=He();U!==t;)N.push(U),U=He();if(N!==t)if(U=y1(),U!==t){for(ce=[],Se=He();Se!==t;)ce.push(Se),Se=He();ce!==t?(r.charCodeAt(Q)===41?(Se=O,Q++):(Se=t,I===0&&Qe(F)),Se!==t?(Me=m,b=PE(U),m=b):(Q=m,m=t)):(Q=m,m=t)}else Q=m,m=t;else Q=m,m=t}else Q=m,m=t}return m}function jb(){var m,b,N,U,ce,Se,ht,Bt;if(m=Q,b=Yb(),b!==t){for(N=[],U=Q,ce=[],Se=He();Se!==t;)ce.push(Se),Se=He();if(ce!==t)if(r.charCodeAt(Q)===42?(Se=cg,Q++):(Se=t,I===0&&Qe(hA)),Se===t&&(r.charCodeAt(Q)===47?(Se=Rr,Q++):(Se=t,I===0&&Qe(DE))),Se!==t){for(ht=[],Bt=He();Bt!==t;)ht.push(Bt),Bt=He();ht!==t?(Bt=Yb(),Bt!==t?(Me=U,ce=Ks(b,Se,Bt),U=ce):(Q=U,U=t)):(Q=U,U=t)}else Q=U,U=t;else Q=U,U=t;for(;U!==t;){for(N.push(U),U=Q,ce=[],Se=He();Se!==t;)ce.push(Se),Se=He();if(ce!==t)if(r.charCodeAt(Q)===42?(Se=cg,Q++):(Se=t,I===0&&Qe(hA)),Se===t&&(r.charCodeAt(Q)===47?(Se=Rr,Q++):(Se=t,I===0&&Qe(DE))),Se!==t){for(ht=[],Bt=He();Bt!==t;)ht.push(Bt),Bt=He();ht!==t?(Bt=Yb(),Bt!==t?(Me=U,ce=Ks(b,Se,Bt),U=ce):(Q=U,U=t)):(Q=U,U=t)}else Q=U,U=t;else Q=U,U=t}N!==t?(Me=m,b=Us(b,N),m=b):(Q=m,m=t)}else Q=m,m=t;return m}function y1(){var m,b,N,U,ce,Se,ht,Bt;if(m=Q,b=jb(),b!==t){for(N=[],U=Q,ce=[],Se=He();Se!==t;)ce.push(Se),Se=He();if(ce!==t)if(r.charCodeAt(Q)===43?(Se=Ms,Q++):(Se=t,I===0&&Qe(Dl)),Se===t&&(r.charCodeAt(Q)===45?(Se=fA,Q++):(Se=t,I===0&&Qe(Pl))),Se!==t){for(ht=[],Bt=He();Bt!==t;)ht.push(Bt),Bt=He();ht!==t?(Bt=jb(),Bt!==t?(Me=U,ce=ug(b,Se,Bt),U=ce):(Q=U,U=t)):(Q=U,U=t)}else Q=U,U=t;else Q=U,U=t;for(;U!==t;){for(N.push(U),U=Q,ce=[],Se=He();Se!==t;)ce.push(Se),Se=He();if(ce!==t)if(r.charCodeAt(Q)===43?(Se=Ms,Q++):(Se=t,I===0&&Qe(Dl)),Se===t&&(r.charCodeAt(Q)===45?(Se=fA,Q++):(Se=t,I===0&&Qe(Pl))),Se!==t){for(ht=[],Bt=He();Bt!==t;)ht.push(Bt),Bt=He();ht!==t?(Bt=jb(),Bt!==t?(Me=U,ce=ug(b,Se,Bt),U=ce):(Q=U,U=t)):(Q=U,U=t)}else Q=U,U=t;else Q=U,U=t}N!==t?(Me=m,b=Us(b,N),m=b):(Q=m,m=t)}else Q=m,m=t;return m}function w1(){var m,b,N,U,ce,Se;if(m=Q,r.substr(Q,3)===pA?(b=pA,Q+=3):(b=t,I===0&&Qe(R)),b!==t){for(N=[],U=He();U!==t;)N.push(U),U=He();if(N!==t)if(U=y1(),U!==t){for(ce=[],Se=He();Se!==t;)ce.push(Se),Se=He();ce!==t?(r.substr(Q,2)===q?(Se=q,Q+=2):(Se=t,I===0&&Qe(Ce)),Se!==t?(Me=m,b=Ke(U),m=b):(Q=m,m=t)):(Q=m,m=t)}else Q=m,m=t;else Q=m,m=t}else Q=m,m=t;return m}function B1(){var m,b,N,U;return m=Q,r.substr(Q,2)===Re?(b=Re,Q+=2):(b=t,I===0&&Qe(ze)),b!==t?(N=Mr(),N!==t?(r.charCodeAt(Q)===41?(U=O,Q++):(U=t,I===0&&Qe(F)),U!==t?(Me=m,b=dt(N),m=b):(Q=m,m=t)):(Q=m,m=t)):(Q=m,m=t),m}function qb(){var m,b,N,U,ce,Se;return m=Q,r.substr(Q,2)===Ft?(b=Ft,Q+=2):(b=t,I===0&&Qe(Fn)),b!==t?(N=Rl(),N!==t?(r.substr(Q,2)===Db?(U=Db,Q+=2):(U=t,I===0&&Qe($M)),U!==t?(ce=f1(),ce!==t?(r.charCodeAt(Q)===125?(Se=Fe,Q++):(Se=t,I===0&&Qe(Ne)),Se!==t?(Me=m,b=e1(N,ce),m=b):(Q=m,m=t)):(Q=m,m=t)):(Q=m,m=t)):(Q=m,m=t)):(Q=m,m=t),m===t&&(m=Q,r.substr(Q,2)===Ft?(b=Ft,Q+=2):(b=t,I===0&&Qe(Fn)),b!==t?(N=Rl(),N!==t?(r.substr(Q,3)===kb?(U=kb,Q+=3):(U=t,I===0&&Qe(t1)),U!==t?(Me=m,b=r1(N),m=b):(Q=m,m=t)):(Q=m,m=t)):(Q=m,m=t),m===t&&(m=Q,r.substr(Q,2)===Ft?(b=Ft,Q+=2):(b=t,I===0&&Qe(Fn)),b!==t?(N=Rl(),N!==t?(r.substr(Q,2)===Rb?(U=Rb,Q+=2):(U=t,I===0&&Qe(i1)),U!==t?(ce=f1(),ce!==t?(r.charCodeAt(Q)===125?(Se=Fe,Q++):(Se=t,I===0&&Qe(Ne)),Se!==t?(Me=m,b=n1(N,ce),m=b):(Q=m,m=t)):(Q=m,m=t)):(Q=m,m=t)):(Q=m,m=t)):(Q=m,m=t),m===t&&(m=Q,r.substr(Q,2)===Ft?(b=Ft,Q+=2):(b=t,I===0&&Qe(Fn)),b!==t?(N=Rl(),N!==t?(r.substr(Q,3)===Fb?(U=Fb,Q+=3):(U=t,I===0&&Qe(s1)),U!==t?(Me=m,b=o1(N),m=b):(Q=m,m=t)):(Q=m,m=t)):(Q=m,m=t),m===t&&(m=Q,r.substr(Q,2)===Ft?(b=Ft,Q+=2):(b=t,I===0&&Qe(Fn)),b!==t?(N=Rl(),N!==t?(r.charCodeAt(Q)===125?(U=Fe,Q++):(U=t,I===0&&Qe(Ne)),U!==t?(Me=m,b=Nb(N),m=b):(Q=m,m=t)):(Q=m,m=t)):(Q=m,m=t),m===t&&(m=Q,r.charCodeAt(Q)===36?(b=a1,Q++):(b=t,I===0&&Qe(A1)),b!==t?(N=Rl(),N!==t?(Me=m,b=Nb(N),m=b):(Q=m,m=t)):(Q=m,m=t)))))),m}function Tue(){var m,b,N;return m=Q,b=Oue(),b!==t?(Me=Q,N=l1(b),N?N=void 0:N=t,N!==t?(Me=m,b=c1(b),m=b):(Q=m,m=t)):(Q=m,m=t),m}function Oue(){var m,b,N,U,ce;if(m=Q,b=[],N=Q,U=Q,I++,ce=S1(),I--,ce===t?U=void 0:(Q=U,U=t),U!==t?(r.length>Q?(ce=r.charAt(Q),Q++):(ce=t,I===0&&Qe(Eo)),ce!==t?(Me=N,U=an(ce),N=U):(Q=N,N=t)):(Q=N,N=t),N!==t)for(;N!==t;)b.push(N),N=Q,U=Q,I++,ce=S1(),I--,ce===t?U=void 0:(Q=U,U=t),U!==t?(r.length>Q?(ce=r.charAt(Q),Q++):(ce=t,I===0&&Qe(Eo)),ce!==t?(Me=N,U=an(ce),N=U):(Q=N,N=t)):(Q=N,N=t);else b=t;return b!==t&&(Me=m,b=Dn(b)),m=b,m}function Q1(){var m,b,N;if(m=Q,b=[],Lb.test(r.charAt(Q))?(N=r.charAt(Q),Q++):(N=t,I===0&&Qe(Tb)),N!==t)for(;N!==t;)b.push(N),Lb.test(r.charAt(Q))?(N=r.charAt(Q),Q++):(N=t,I===0&&Qe(Tb));else b=t;return b!==t&&(Me=m,b=Ob()),m=b,m}function Rl(){var m,b,N;if(m=Q,b=[],Mb.test(r.charAt(Q))?(N=r.charAt(Q),Q++):(N=t,I===0&&Qe(Kb)),N!==t)for(;N!==t;)b.push(N),Mb.test(r.charAt(Q))?(N=r.charAt(Q),Q++):(N=t,I===0&&Qe(Kb));else b=t;return b!==t&&(Me=m,b=Ob()),m=b,m}function b1(){var m;return u1.test(r.charAt(Q))?(m=r.charAt(Q),Q++):(m=t,I===0&&Qe(gg)),m}function S1(){var m;return Ub.test(r.charAt(Q))?(m=r.charAt(Q),Q++):(m=t,I===0&&Qe(Hb)),m}function He(){var m,b;if(m=[],kE.test(r.charAt(Q))?(b=r.charAt(Q),Q++):(b=t,I===0&&Qe(RE)),b!==t)for(;b!==t;)m.push(b),kE.test(r.charAt(Q))?(b=r.charAt(Q),Q++):(b=t,I===0&&Qe(RE));else m=t;return m}if(k=n(),k!==t&&Q===r.length)return k;throw k!==t&&Q{"use strict";function Mge(r,e){function t(){this.constructor=r}t.prototype=e.prototype,r.prototype=new t}function Ul(r,e,t,i){this.message=r,this.expected=e,this.found=t,this.location=i,this.name="SyntaxError",typeof Error.captureStackTrace=="function"&&Error.captureStackTrace(this,Ul)}Mge(Ul,Error);Ul.buildMessage=function(r,e){var t={literal:function(c){return'"'+n(c.text)+'"'},class:function(c){var u="",g;for(g=0;g0){for(g=1,f=1;gH&&(H=v,j=[]),j.push(ne))}function Ne(ne,Y){return new Ul(ne,null,null,Y)}function oe(ne,Y,pe){return new Ul(Ul.buildMessage(ne,Y),ne,Y,pe)}function le(){var ne,Y,pe,ie;return ne=v,Y=we(),Y!==t?(r.charCodeAt(v)===47?(pe=s,v++):(pe=t,$===0&&Fe(o)),pe!==t?(ie=we(),ie!==t?(D=ne,Y=a(Y,ie),ne=Y):(v=ne,ne=t)):(v=ne,ne=t)):(v=ne,ne=t),ne===t&&(ne=v,Y=we(),Y!==t&&(D=ne,Y=l(Y)),ne=Y),ne}function we(){var ne,Y,pe,ie;return ne=v,Y=fe(),Y!==t?(r.charCodeAt(v)===64?(pe=c,v++):(pe=t,$===0&&Fe(u)),pe!==t?(ie=qe(),ie!==t?(D=ne,Y=g(Y,ie),ne=Y):(v=ne,ne=t)):(v=ne,ne=t)):(v=ne,ne=t),ne===t&&(ne=v,Y=fe(),Y!==t&&(D=ne,Y=f(Y)),ne=Y),ne}function fe(){var ne,Y,pe,ie,de;return ne=v,r.charCodeAt(v)===64?(Y=c,v++):(Y=t,$===0&&Fe(u)),Y!==t?(pe=Ae(),pe!==t?(r.charCodeAt(v)===47?(ie=s,v++):(ie=t,$===0&&Fe(o)),ie!==t?(de=Ae(),de!==t?(D=ne,Y=h(),ne=Y):(v=ne,ne=t)):(v=ne,ne=t)):(v=ne,ne=t)):(v=ne,ne=t),ne===t&&(ne=v,Y=Ae(),Y!==t&&(D=ne,Y=h()),ne=Y),ne}function Ae(){var ne,Y,pe;if(ne=v,Y=[],p.test(r.charAt(v))?(pe=r.charAt(v),v++):(pe=t,$===0&&Fe(C)),pe!==t)for(;pe!==t;)Y.push(pe),p.test(r.charAt(v))?(pe=r.charAt(v),v++):(pe=t,$===0&&Fe(C));else Y=t;return Y!==t&&(D=ne,Y=h()),ne=Y,ne}function qe(){var ne,Y,pe;if(ne=v,Y=[],y.test(r.charAt(v))?(pe=r.charAt(v),v++):(pe=t,$===0&&Fe(B)),pe!==t)for(;pe!==t;)Y.push(pe),y.test(r.charAt(v))?(pe=r.charAt(v),v++):(pe=t,$===0&&Fe(B));else Y=t;return Y!==t&&(D=ne,Y=h()),ne=Y,ne}if(V=n(),V!==t&&v===r.length)return V;throw V!==t&&v{"use strict";function UK(r){return typeof r>"u"||r===null}function Uge(r){return typeof r=="object"&&r!==null}function Hge(r){return Array.isArray(r)?r:UK(r)?[]:[r]}function Gge(r,e){var t,i,n,s;if(e)for(s=Object.keys(e),t=0,i=s.length;t{"use strict";function Op(r,e){Error.call(this),this.name="YAMLException",this.reason=r,this.mark=e,this.message=(this.reason||"(unknown reason)")+(this.mark?" "+this.mark.toString():""),Error.captureStackTrace?Error.captureStackTrace(this,this.constructor):this.stack=new Error().stack||""}Op.prototype=Object.create(Error.prototype);Op.prototype.constructor=Op;Op.prototype.toString=function(e){var t=this.name+": ";return t+=this.reason||"(unknown reason)",!e&&this.mark&&(t+=" "+this.mark.toString()),t};HK.exports=Op});var jK=w((pXe,YK)=>{"use strict";var GK=Gl();function SS(r,e,t,i,n){this.name=r,this.buffer=e,this.position=t,this.line=i,this.column=n}SS.prototype.getSnippet=function(e,t){var i,n,s,o,a;if(!this.buffer)return null;for(e=e||4,t=t||75,i="",n=this.position;n>0&&`\0\r -\x85\u2028\u2029`.indexOf(this.buffer.charAt(n-1))===-1;)if(n-=1,this.position-n>t/2-1){i=" ... ",n+=5;break}for(s="",o=this.position;ot/2-1){s=" ... ",o-=5;break}return a=this.buffer.slice(n,o),GK.repeat(" ",e)+i+a+s+` -`+GK.repeat(" ",e+this.position-n+i.length)+"^"};SS.prototype.toString=function(e){var t,i="";return this.name&&(i+='in "'+this.name+'" '),i+="at line "+(this.line+1)+", column "+(this.column+1),e||(t=this.getSnippet(),t&&(i+=`: -`+t)),i};YK.exports=SS});var si=w((dXe,JK)=>{"use strict";var qK=Qg(),qge=["kind","resolve","construct","instanceOf","predicate","represent","defaultStyle","styleAliases"],Jge=["scalar","sequence","mapping"];function Wge(r){var e={};return r!==null&&Object.keys(r).forEach(function(t){r[t].forEach(function(i){e[String(i)]=t})}),e}function zge(r,e){if(e=e||{},Object.keys(e).forEach(function(t){if(qge.indexOf(t)===-1)throw new qK('Unknown option "'+t+'" is met in definition of "'+r+'" YAML type.')}),this.tag=r,this.kind=e.kind||null,this.resolve=e.resolve||function(){return!0},this.construct=e.construct||function(t){return t},this.instanceOf=e.instanceOf||null,this.predicate=e.predicate||null,this.represent=e.represent||null,this.defaultStyle=e.defaultStyle||null,this.styleAliases=Wge(e.styleAliases||null),Jge.indexOf(this.kind)===-1)throw new qK('Unknown kind "'+this.kind+'" is specified for "'+r+'" YAML type.')}JK.exports=zge});var Yl=w((CXe,zK)=>{"use strict";var WK=Gl(),nI=Qg(),Vge=si();function vS(r,e,t){var i=[];return r.include.forEach(function(n){t=vS(n,e,t)}),r[e].forEach(function(n){t.forEach(function(s,o){s.tag===n.tag&&s.kind===n.kind&&i.push(o)}),t.push(n)}),t.filter(function(n,s){return i.indexOf(s)===-1})}function Xge(){var r={scalar:{},sequence:{},mapping:{},fallback:{}},e,t;function i(n){r[n.kind][n.tag]=r.fallback[n.tag]=n}for(e=0,t=arguments.length;e{"use strict";var _ge=si();VK.exports=new _ge("tag:yaml.org,2002:str",{kind:"scalar",construct:function(r){return r!==null?r:""}})});var ZK=w((EXe,_K)=>{"use strict";var Zge=si();_K.exports=new Zge("tag:yaml.org,2002:seq",{kind:"sequence",construct:function(r){return r!==null?r:[]}})});var eU=w((IXe,$K)=>{"use strict";var $ge=si();$K.exports=new $ge("tag:yaml.org,2002:map",{kind:"mapping",construct:function(r){return r!==null?r:{}}})});var sI=w((yXe,tU)=>{"use strict";var efe=Yl();tU.exports=new efe({explicit:[XK(),ZK(),eU()]})});var iU=w((wXe,rU)=>{"use strict";var tfe=si();function rfe(r){if(r===null)return!0;var e=r.length;return e===1&&r==="~"||e===4&&(r==="null"||r==="Null"||r==="NULL")}function ife(){return null}function nfe(r){return r===null}rU.exports=new tfe("tag:yaml.org,2002:null",{kind:"scalar",resolve:rfe,construct:ife,predicate:nfe,represent:{canonical:function(){return"~"},lowercase:function(){return"null"},uppercase:function(){return"NULL"},camelcase:function(){return"Null"}},defaultStyle:"lowercase"})});var sU=w((BXe,nU)=>{"use strict";var sfe=si();function ofe(r){if(r===null)return!1;var e=r.length;return e===4&&(r==="true"||r==="True"||r==="TRUE")||e===5&&(r==="false"||r==="False"||r==="FALSE")}function afe(r){return r==="true"||r==="True"||r==="TRUE"}function Afe(r){return Object.prototype.toString.call(r)==="[object Boolean]"}nU.exports=new sfe("tag:yaml.org,2002:bool",{kind:"scalar",resolve:ofe,construct:afe,predicate:Afe,represent:{lowercase:function(r){return r?"true":"false"},uppercase:function(r){return r?"TRUE":"FALSE"},camelcase:function(r){return r?"True":"False"}},defaultStyle:"lowercase"})});var aU=w((QXe,oU)=>{"use strict";var lfe=Gl(),cfe=si();function ufe(r){return 48<=r&&r<=57||65<=r&&r<=70||97<=r&&r<=102}function gfe(r){return 48<=r&&r<=55}function ffe(r){return 48<=r&&r<=57}function hfe(r){if(r===null)return!1;var e=r.length,t=0,i=!1,n;if(!e)return!1;if(n=r[t],(n==="-"||n==="+")&&(n=r[++t]),n==="0"){if(t+1===e)return!0;if(n=r[++t],n==="b"){for(t++;t=0?"0b"+r.toString(2):"-0b"+r.toString(2).slice(1)},octal:function(r){return r>=0?"0"+r.toString(8):"-0"+r.toString(8).slice(1)},decimal:function(r){return r.toString(10)},hexadecimal:function(r){return r>=0?"0x"+r.toString(16).toUpperCase():"-0x"+r.toString(16).toUpperCase().slice(1)}},defaultStyle:"decimal",styleAliases:{binary:[2,"bin"],octal:[8,"oct"],decimal:[10,"dec"],hexadecimal:[16,"hex"]}})});var cU=w((bXe,lU)=>{"use strict";var AU=Gl(),Cfe=si(),mfe=new RegExp("^(?:[-+]?(?:0|[1-9][0-9_]*)(?:\\.[0-9_]*)?(?:[eE][-+]?[0-9]+)?|\\.[0-9_]+(?:[eE][-+]?[0-9]+)?|[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\\.[0-9_]*|[-+]?\\.(?:inf|Inf|INF)|\\.(?:nan|NaN|NAN))$");function Efe(r){return!(r===null||!mfe.test(r)||r[r.length-1]==="_")}function Ife(r){var e,t,i,n;return e=r.replace(/_/g,"").toLowerCase(),t=e[0]==="-"?-1:1,n=[],"+-".indexOf(e[0])>=0&&(e=e.slice(1)),e===".inf"?t===1?Number.POSITIVE_INFINITY:Number.NEGATIVE_INFINITY:e===".nan"?NaN:e.indexOf(":")>=0?(e.split(":").forEach(function(s){n.unshift(parseFloat(s,10))}),e=0,i=1,n.forEach(function(s){e+=s*i,i*=60}),t*e):t*parseFloat(e,10)}var yfe=/^[-+]?[0-9]+e/;function wfe(r,e){var t;if(isNaN(r))switch(e){case"lowercase":return".nan";case"uppercase":return".NAN";case"camelcase":return".NaN"}else if(Number.POSITIVE_INFINITY===r)switch(e){case"lowercase":return".inf";case"uppercase":return".INF";case"camelcase":return".Inf"}else if(Number.NEGATIVE_INFINITY===r)switch(e){case"lowercase":return"-.inf";case"uppercase":return"-.INF";case"camelcase":return"-.Inf"}else if(AU.isNegativeZero(r))return"-0.0";return t=r.toString(10),yfe.test(t)?t.replace("e",".e"):t}function Bfe(r){return Object.prototype.toString.call(r)==="[object Number]"&&(r%1!==0||AU.isNegativeZero(r))}lU.exports=new Cfe("tag:yaml.org,2002:float",{kind:"scalar",resolve:Efe,construct:Ife,predicate:Bfe,represent:wfe,defaultStyle:"lowercase"})});var xS=w((SXe,uU)=>{"use strict";var Qfe=Yl();uU.exports=new Qfe({include:[sI()],implicit:[iU(),sU(),aU(),cU()]})});var PS=w((vXe,gU)=>{"use strict";var bfe=Yl();gU.exports=new bfe({include:[xS()]})});var dU=w((xXe,pU)=>{"use strict";var Sfe=si(),fU=new RegExp("^([0-9][0-9][0-9][0-9])-([0-9][0-9])-([0-9][0-9])$"),hU=new RegExp("^([0-9][0-9][0-9][0-9])-([0-9][0-9]?)-([0-9][0-9]?)(?:[Tt]|[ \\t]+)([0-9][0-9]?):([0-9][0-9]):([0-9][0-9])(?:\\.([0-9]*))?(?:[ \\t]*(Z|([-+])([0-9][0-9]?)(?::([0-9][0-9]))?))?$");function vfe(r){return r===null?!1:fU.exec(r)!==null||hU.exec(r)!==null}function xfe(r){var e,t,i,n,s,o,a,l=0,c=null,u,g,f;if(e=fU.exec(r),e===null&&(e=hU.exec(r)),e===null)throw new Error("Date resolve error");if(t=+e[1],i=+e[2]-1,n=+e[3],!e[4])return new Date(Date.UTC(t,i,n));if(s=+e[4],o=+e[5],a=+e[6],e[7]){for(l=e[7].slice(0,3);l.length<3;)l+="0";l=+l}return e[9]&&(u=+e[10],g=+(e[11]||0),c=(u*60+g)*6e4,e[9]==="-"&&(c=-c)),f=new Date(Date.UTC(t,i,n,s,o,a,l)),c&&f.setTime(f.getTime()-c),f}function Pfe(r){return r.toISOString()}pU.exports=new Sfe("tag:yaml.org,2002:timestamp",{kind:"scalar",resolve:vfe,construct:xfe,instanceOf:Date,represent:Pfe})});var mU=w((PXe,CU)=>{"use strict";var Dfe=si();function kfe(r){return r==="<<"||r===null}CU.exports=new Dfe("tag:yaml.org,2002:merge",{kind:"scalar",resolve:kfe})});var yU=w((DXe,IU)=>{"use strict";var jl;try{EU=J,jl=EU("buffer").Buffer}catch{}var EU,Rfe=si(),DS=`ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/= -\r`;function Ffe(r){if(r===null)return!1;var e,t,i=0,n=r.length,s=DS;for(t=0;t64)){if(e<0)return!1;i+=6}return i%8===0}function Nfe(r){var e,t,i=r.replace(/[\r\n=]/g,""),n=i.length,s=DS,o=0,a=[];for(e=0;e>16&255),a.push(o>>8&255),a.push(o&255)),o=o<<6|s.indexOf(i.charAt(e));return t=n%4*6,t===0?(a.push(o>>16&255),a.push(o>>8&255),a.push(o&255)):t===18?(a.push(o>>10&255),a.push(o>>2&255)):t===12&&a.push(o>>4&255),jl?jl.from?jl.from(a):new jl(a):a}function Lfe(r){var e="",t=0,i,n,s=r.length,o=DS;for(i=0;i>18&63],e+=o[t>>12&63],e+=o[t>>6&63],e+=o[t&63]),t=(t<<8)+r[i];return n=s%3,n===0?(e+=o[t>>18&63],e+=o[t>>12&63],e+=o[t>>6&63],e+=o[t&63]):n===2?(e+=o[t>>10&63],e+=o[t>>4&63],e+=o[t<<2&63],e+=o[64]):n===1&&(e+=o[t>>2&63],e+=o[t<<4&63],e+=o[64],e+=o[64]),e}function Tfe(r){return jl&&jl.isBuffer(r)}IU.exports=new Rfe("tag:yaml.org,2002:binary",{kind:"scalar",resolve:Ffe,construct:Nfe,predicate:Tfe,represent:Lfe})});var BU=w((kXe,wU)=>{"use strict";var Ofe=si(),Mfe=Object.prototype.hasOwnProperty,Kfe=Object.prototype.toString;function Ufe(r){if(r===null)return!0;var e=[],t,i,n,s,o,a=r;for(t=0,i=a.length;t{"use strict";var Gfe=si(),Yfe=Object.prototype.toString;function jfe(r){if(r===null)return!0;var e,t,i,n,s,o=r;for(s=new Array(o.length),e=0,t=o.length;e{"use strict";var Jfe=si(),Wfe=Object.prototype.hasOwnProperty;function zfe(r){if(r===null)return!0;var e,t=r;for(e in t)if(Wfe.call(t,e)&&t[e]!==null)return!1;return!0}function Vfe(r){return r!==null?r:{}}SU.exports=new Jfe("tag:yaml.org,2002:set",{kind:"mapping",resolve:zfe,construct:Vfe})});var Sg=w((NXe,xU)=>{"use strict";var Xfe=Yl();xU.exports=new Xfe({include:[PS()],implicit:[dU(),mU()],explicit:[yU(),BU(),bU(),vU()]})});var DU=w((LXe,PU)=>{"use strict";var _fe=si();function Zfe(){return!0}function $fe(){}function ehe(){return""}function the(r){return typeof r>"u"}PU.exports=new _fe("tag:yaml.org,2002:js/undefined",{kind:"scalar",resolve:Zfe,construct:$fe,predicate:the,represent:ehe})});var RU=w((TXe,kU)=>{"use strict";var rhe=si();function ihe(r){if(r===null||r.length===0)return!1;var e=r,t=/\/([gim]*)$/.exec(r),i="";return!(e[0]==="/"&&(t&&(i=t[1]),i.length>3||e[e.length-i.length-1]!=="/"))}function nhe(r){var e=r,t=/\/([gim]*)$/.exec(r),i="";return e[0]==="/"&&(t&&(i=t[1]),e=e.slice(1,e.length-i.length-1)),new RegExp(e,i)}function she(r){var e="/"+r.source+"/";return r.global&&(e+="g"),r.multiline&&(e+="m"),r.ignoreCase&&(e+="i"),e}function ohe(r){return Object.prototype.toString.call(r)==="[object RegExp]"}kU.exports=new rhe("tag:yaml.org,2002:js/regexp",{kind:"scalar",resolve:ihe,construct:nhe,predicate:ohe,represent:she})});var LU=w((OXe,NU)=>{"use strict";var oI;try{FU=J,oI=FU("esprima")}catch{typeof window<"u"&&(oI=window.esprima)}var FU,ahe=si();function Ahe(r){if(r===null)return!1;try{var e="("+r+")",t=oI.parse(e,{range:!0});return!(t.type!=="Program"||t.body.length!==1||t.body[0].type!=="ExpressionStatement"||t.body[0].expression.type!=="ArrowFunctionExpression"&&t.body[0].expression.type!=="FunctionExpression")}catch{return!1}}function lhe(r){var e="("+r+")",t=oI.parse(e,{range:!0}),i=[],n;if(t.type!=="Program"||t.body.length!==1||t.body[0].type!=="ExpressionStatement"||t.body[0].expression.type!=="ArrowFunctionExpression"&&t.body[0].expression.type!=="FunctionExpression")throw new Error("Failed to resolve function");return t.body[0].expression.params.forEach(function(s){i.push(s.name)}),n=t.body[0].expression.body.range,t.body[0].expression.body.type==="BlockStatement"?new Function(i,e.slice(n[0]+1,n[1]-1)):new Function(i,"return "+e.slice(n[0],n[1]))}function che(r){return r.toString()}function uhe(r){return Object.prototype.toString.call(r)==="[object Function]"}NU.exports=new ahe("tag:yaml.org,2002:js/function",{kind:"scalar",resolve:Ahe,construct:lhe,predicate:uhe,represent:che})});var Mp=w((MXe,OU)=>{"use strict";var TU=Yl();OU.exports=TU.DEFAULT=new TU({include:[Sg()],explicit:[DU(),RU(),LU()]})});var r2=w((KXe,Kp)=>{"use strict";var da=Gl(),jU=Qg(),ghe=jK(),qU=Sg(),fhe=Mp(),wA=Object.prototype.hasOwnProperty,aI=1,JU=2,WU=3,AI=4,kS=1,hhe=2,MU=3,phe=/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F-\x84\x86-\x9F\uFFFE\uFFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF]/,dhe=/[\x85\u2028\u2029]/,Che=/[,\[\]\{\}]/,zU=/^(?:!|!!|![a-z\-]+!)$/i,VU=/^(?:!|[^,\[\]\{\}])(?:%[0-9a-f]{2}|[0-9a-z\-#;\/\?:@&=\+\$,_\.!~\*'\(\)\[\]])*$/i;function KU(r){return Object.prototype.toString.call(r)}function Bo(r){return r===10||r===13}function Jl(r){return r===9||r===32}function un(r){return r===9||r===32||r===10||r===13}function vg(r){return r===44||r===91||r===93||r===123||r===125}function mhe(r){var e;return 48<=r&&r<=57?r-48:(e=r|32,97<=e&&e<=102?e-97+10:-1)}function Ehe(r){return r===120?2:r===117?4:r===85?8:0}function Ihe(r){return 48<=r&&r<=57?r-48:-1}function UU(r){return r===48?"\0":r===97?"\x07":r===98?"\b":r===116||r===9?" ":r===110?` -`:r===118?"\v":r===102?"\f":r===114?"\r":r===101?"\x1B":r===32?" ":r===34?'"':r===47?"/":r===92?"\\":r===78?"\x85":r===95?"\xA0":r===76?"\u2028":r===80?"\u2029":""}function yhe(r){return r<=65535?String.fromCharCode(r):String.fromCharCode((r-65536>>10)+55296,(r-65536&1023)+56320)}var XU=new Array(256),_U=new Array(256);for(ql=0;ql<256;ql++)XU[ql]=UU(ql)?1:0,_U[ql]=UU(ql);var ql;function whe(r,e){this.input=r,this.filename=e.filename||null,this.schema=e.schema||fhe,this.onWarning=e.onWarning||null,this.legacy=e.legacy||!1,this.json=e.json||!1,this.listener=e.listener||null,this.implicitTypes=this.schema.compiledImplicit,this.typeMap=this.schema.compiledTypeMap,this.length=r.length,this.position=0,this.line=0,this.lineStart=0,this.lineIndent=0,this.documents=[]}function ZU(r,e){return new jU(e,new ghe(r.filename,r.input,r.position,r.line,r.position-r.lineStart))}function ft(r,e){throw ZU(r,e)}function lI(r,e){r.onWarning&&r.onWarning.call(null,ZU(r,e))}var HU={YAML:function(e,t,i){var n,s,o;e.version!==null&&ft(e,"duplication of %YAML directive"),i.length!==1&&ft(e,"YAML directive accepts exactly one argument"),n=/^([0-9]+)\.([0-9]+)$/.exec(i[0]),n===null&&ft(e,"ill-formed argument of the YAML directive"),s=parseInt(n[1],10),o=parseInt(n[2],10),s!==1&&ft(e,"unacceptable YAML version of the document"),e.version=i[0],e.checkLineBreaks=o<2,o!==1&&o!==2&&lI(e,"unsupported YAML version of the document")},TAG:function(e,t,i){var n,s;i.length!==2&&ft(e,"TAG directive accepts exactly two arguments"),n=i[0],s=i[1],zU.test(n)||ft(e,"ill-formed tag handle (first argument) of the TAG directive"),wA.call(e.tagMap,n)&&ft(e,'there is a previously declared suffix for "'+n+'" tag handle'),VU.test(s)||ft(e,"ill-formed tag prefix (second argument) of the TAG directive"),e.tagMap[n]=s}};function yA(r,e,t,i){var n,s,o,a;if(e1&&(r.result+=da.repeat(` -`,e-1))}function Bhe(r,e,t){var i,n,s,o,a,l,c,u,g=r.kind,f=r.result,h;if(h=r.input.charCodeAt(r.position),un(h)||vg(h)||h===35||h===38||h===42||h===33||h===124||h===62||h===39||h===34||h===37||h===64||h===96||(h===63||h===45)&&(n=r.input.charCodeAt(r.position+1),un(n)||t&&vg(n)))return!1;for(r.kind="scalar",r.result="",s=o=r.position,a=!1;h!==0;){if(h===58){if(n=r.input.charCodeAt(r.position+1),un(n)||t&&vg(n))break}else if(h===35){if(i=r.input.charCodeAt(r.position-1),un(i))break}else{if(r.position===r.lineStart&&cI(r)||t&&vg(h))break;if(Bo(h))if(l=r.line,c=r.lineStart,u=r.lineIndent,zr(r,!1,-1),r.lineIndent>=e){a=!0,h=r.input.charCodeAt(r.position);continue}else{r.position=o,r.line=l,r.lineStart=c,r.lineIndent=u;break}}a&&(yA(r,s,o,!1),FS(r,r.line-l),s=o=r.position,a=!1),Jl(h)||(o=r.position+1),h=r.input.charCodeAt(++r.position)}return yA(r,s,o,!1),r.result?!0:(r.kind=g,r.result=f,!1)}function Qhe(r,e){var t,i,n;if(t=r.input.charCodeAt(r.position),t!==39)return!1;for(r.kind="scalar",r.result="",r.position++,i=n=r.position;(t=r.input.charCodeAt(r.position))!==0;)if(t===39)if(yA(r,i,r.position,!0),t=r.input.charCodeAt(++r.position),t===39)i=r.position,r.position++,n=r.position;else return!0;else Bo(t)?(yA(r,i,n,!0),FS(r,zr(r,!1,e)),i=n=r.position):r.position===r.lineStart&&cI(r)?ft(r,"unexpected end of the document within a single quoted scalar"):(r.position++,n=r.position);ft(r,"unexpected end of the stream within a single quoted scalar")}function bhe(r,e){var t,i,n,s,o,a;if(a=r.input.charCodeAt(r.position),a!==34)return!1;for(r.kind="scalar",r.result="",r.position++,t=i=r.position;(a=r.input.charCodeAt(r.position))!==0;){if(a===34)return yA(r,t,r.position,!0),r.position++,!0;if(a===92){if(yA(r,t,r.position,!0),a=r.input.charCodeAt(++r.position),Bo(a))zr(r,!1,e);else if(a<256&&XU[a])r.result+=_U[a],r.position++;else if((o=Ehe(a))>0){for(n=o,s=0;n>0;n--)a=r.input.charCodeAt(++r.position),(o=mhe(a))>=0?s=(s<<4)+o:ft(r,"expected hexadecimal character");r.result+=yhe(s),r.position++}else ft(r,"unknown escape sequence");t=i=r.position}else Bo(a)?(yA(r,t,i,!0),FS(r,zr(r,!1,e)),t=i=r.position):r.position===r.lineStart&&cI(r)?ft(r,"unexpected end of the document within a double quoted scalar"):(r.position++,i=r.position)}ft(r,"unexpected end of the stream within a double quoted scalar")}function She(r,e){var t=!0,i,n=r.tag,s,o=r.anchor,a,l,c,u,g,f={},h,p,C,y;if(y=r.input.charCodeAt(r.position),y===91)l=93,g=!1,s=[];else if(y===123)l=125,g=!0,s={};else return!1;for(r.anchor!==null&&(r.anchorMap[r.anchor]=s),y=r.input.charCodeAt(++r.position);y!==0;){if(zr(r,!0,e),y=r.input.charCodeAt(r.position),y===l)return r.position++,r.tag=n,r.anchor=o,r.kind=g?"mapping":"sequence",r.result=s,!0;t||ft(r,"missed comma between flow collection entries"),p=h=C=null,c=u=!1,y===63&&(a=r.input.charCodeAt(r.position+1),un(a)&&(c=u=!0,r.position++,zr(r,!0,e))),i=r.line,Pg(r,e,aI,!1,!0),p=r.tag,h=r.result,zr(r,!0,e),y=r.input.charCodeAt(r.position),(u||r.line===i)&&y===58&&(c=!0,y=r.input.charCodeAt(++r.position),zr(r,!0,e),Pg(r,e,aI,!1,!0),C=r.result),g?xg(r,s,f,p,h,C):c?s.push(xg(r,null,f,p,h,C)):s.push(h),zr(r,!0,e),y=r.input.charCodeAt(r.position),y===44?(t=!0,y=r.input.charCodeAt(++r.position)):t=!1}ft(r,"unexpected end of the stream within a flow collection")}function vhe(r,e){var t,i,n=kS,s=!1,o=!1,a=e,l=0,c=!1,u,g;if(g=r.input.charCodeAt(r.position),g===124)i=!1;else if(g===62)i=!0;else return!1;for(r.kind="scalar",r.result="";g!==0;)if(g=r.input.charCodeAt(++r.position),g===43||g===45)kS===n?n=g===43?MU:hhe:ft(r,"repeat of a chomping mode identifier");else if((u=Ihe(g))>=0)u===0?ft(r,"bad explicit indentation width of a block scalar; it cannot be less than one"):o?ft(r,"repeat of an indentation width identifier"):(a=e+u-1,o=!0);else break;if(Jl(g)){do g=r.input.charCodeAt(++r.position);while(Jl(g));if(g===35)do g=r.input.charCodeAt(++r.position);while(!Bo(g)&&g!==0)}for(;g!==0;){for(RS(r),r.lineIndent=0,g=r.input.charCodeAt(r.position);(!o||r.lineIndenta&&(a=r.lineIndent),Bo(g)){l++;continue}if(r.lineIndente)&&l!==0)ft(r,"bad indentation of a sequence entry");else if(r.lineIndente)&&(Pg(r,e,AI,!0,n)&&(p?f=r.result:h=r.result),p||(xg(r,c,u,g,f,h,s,o),g=f=h=null),zr(r,!0,-1),y=r.input.charCodeAt(r.position)),r.lineIndent>e&&y!==0)ft(r,"bad indentation of a mapping entry");else if(r.lineIndente?l=1:r.lineIndent===e?l=0:r.lineIndente?l=1:r.lineIndent===e?l=0:r.lineIndent tag; it should be "scalar", not "'+r.kind+'"'),g=0,f=r.implicitTypes.length;g tag; it should be "'+h.kind+'", not "'+r.kind+'"'),h.resolve(r.result)?(r.result=h.construct(r.result),r.anchor!==null&&(r.anchorMap[r.anchor]=r.result)):ft(r,"cannot resolve a node with !<"+r.tag+"> explicit tag")):ft(r,"unknown tag !<"+r.tag+">");return r.listener!==null&&r.listener("close",r),r.tag!==null||r.anchor!==null||u}function Rhe(r){var e=r.position,t,i,n,s=!1,o;for(r.version=null,r.checkLineBreaks=r.legacy,r.tagMap={},r.anchorMap={};(o=r.input.charCodeAt(r.position))!==0&&(zr(r,!0,-1),o=r.input.charCodeAt(r.position),!(r.lineIndent>0||o!==37));){for(s=!0,o=r.input.charCodeAt(++r.position),t=r.position;o!==0&&!un(o);)o=r.input.charCodeAt(++r.position);for(i=r.input.slice(t,r.position),n=[],i.length<1&&ft(r,"directive name must not be less than one character in length");o!==0;){for(;Jl(o);)o=r.input.charCodeAt(++r.position);if(o===35){do o=r.input.charCodeAt(++r.position);while(o!==0&&!Bo(o));break}if(Bo(o))break;for(t=r.position;o!==0&&!un(o);)o=r.input.charCodeAt(++r.position);n.push(r.input.slice(t,r.position))}o!==0&&RS(r),wA.call(HU,i)?HU[i](r,i,n):lI(r,'unknown document directive "'+i+'"')}if(zr(r,!0,-1),r.lineIndent===0&&r.input.charCodeAt(r.position)===45&&r.input.charCodeAt(r.position+1)===45&&r.input.charCodeAt(r.position+2)===45?(r.position+=3,zr(r,!0,-1)):s&&ft(r,"directives end mark is expected"),Pg(r,r.lineIndent-1,AI,!1,!0),zr(r,!0,-1),r.checkLineBreaks&&dhe.test(r.input.slice(e,r.position))&&lI(r,"non-ASCII line breaks are interpreted as content"),r.documents.push(r.result),r.position===r.lineStart&&cI(r)){r.input.charCodeAt(r.position)===46&&(r.position+=3,zr(r,!0,-1));return}if(r.position"u"&&(t=e,e=null);var i=$U(r,t);if(typeof e!="function")return i;for(var n=0,s=i.length;n"u"&&(t=e,e=null),e2(r,e,da.extend({schema:qU},t))}function Nhe(r,e){return t2(r,da.extend({schema:qU},e))}Kp.exports.loadAll=e2;Kp.exports.load=t2;Kp.exports.safeLoadAll=Fhe;Kp.exports.safeLoad=Nhe});var b2=w((UXe,OS)=>{"use strict";var Hp=Gl(),Gp=Qg(),Lhe=Mp(),The=Sg(),c2=Object.prototype.toString,u2=Object.prototype.hasOwnProperty,Ohe=9,Up=10,Mhe=13,Khe=32,Uhe=33,Hhe=34,g2=35,Ghe=37,Yhe=38,jhe=39,qhe=42,f2=44,Jhe=45,h2=58,Whe=61,zhe=62,Vhe=63,Xhe=64,p2=91,d2=93,_he=96,C2=123,Zhe=124,m2=125,Fi={};Fi[0]="\\0";Fi[7]="\\a";Fi[8]="\\b";Fi[9]="\\t";Fi[10]="\\n";Fi[11]="\\v";Fi[12]="\\f";Fi[13]="\\r";Fi[27]="\\e";Fi[34]='\\"';Fi[92]="\\\\";Fi[133]="\\N";Fi[160]="\\_";Fi[8232]="\\L";Fi[8233]="\\P";var $he=["y","Y","yes","Yes","YES","on","On","ON","n","N","no","No","NO","off","Off","OFF"];function epe(r,e){var t,i,n,s,o,a,l;if(e===null)return{};for(t={},i=Object.keys(e),n=0,s=i.length;n0?r.charCodeAt(s-1):null,f=f&&s2(o,a)}else{for(s=0;si&&r[g+1]!==" ",g=s);else if(!Dg(o))return uI;a=s>0?r.charCodeAt(s-1):null,f=f&&s2(o,a)}c=c||u&&s-g-1>i&&r[g+1]!==" "}return!l&&!c?f&&!n(r)?I2:y2:t>9&&E2(r)?uI:c?B2:w2}function ope(r,e,t,i){r.dump=function(){if(e.length===0)return"''";if(!r.noCompatMode&&$he.indexOf(e)!==-1)return"'"+e+"'";var n=r.indent*Math.max(1,t),s=r.lineWidth===-1?-1:Math.max(Math.min(r.lineWidth,40),r.lineWidth-n),o=i||r.flowLevel>-1&&t>=r.flowLevel;function a(l){return rpe(r,l)}switch(spe(e,o,r.indent,s,a)){case I2:return e;case y2:return"'"+e.replace(/'/g,"''")+"'";case w2:return"|"+o2(e,r.indent)+a2(n2(e,n));case B2:return">"+o2(e,r.indent)+a2(n2(ape(e,s),n));case uI:return'"'+Ape(e,s)+'"';default:throw new Gp("impossible error: invalid scalar style")}}()}function o2(r,e){var t=E2(r)?String(e):"",i=r[r.length-1]===` -`,n=i&&(r[r.length-2]===` -`||r===` -`),s=n?"+":i?"":"-";return t+s+` -`}function a2(r){return r[r.length-1]===` -`?r.slice(0,-1):r}function ape(r,e){for(var t=/(\n+)([^\n]*)/g,i=function(){var c=r.indexOf(` -`);return c=c!==-1?c:r.length,t.lastIndex=c,A2(r.slice(0,c),e)}(),n=r[0]===` -`||r[0]===" ",s,o;o=t.exec(r);){var a=o[1],l=o[2];s=l[0]===" ",i+=a+(!n&&!s&&l!==""?` -`:"")+A2(l,e),n=s}return i}function A2(r,e){if(r===""||r[0]===" ")return r;for(var t=/ [^ ]/g,i,n=0,s,o=0,a=0,l="";i=t.exec(r);)a=i.index,a-n>e&&(s=o>n?o:a,l+=` -`+r.slice(n,s),n=s+1),o=a;return l+=` -`,r.length-n>e&&o>n?l+=r.slice(n,o)+` -`+r.slice(o+1):l+=r.slice(n),l.slice(1)}function Ape(r){for(var e="",t,i,n,s=0;s=55296&&t<=56319&&(i=r.charCodeAt(s+1),i>=56320&&i<=57343)){e+=i2((t-55296)*1024+i-56320+65536),s++;continue}n=Fi[t],e+=!n&&Dg(t)?r[s]:n||i2(t)}return e}function lpe(r,e,t){var i="",n=r.tag,s,o;for(s=0,o=t.length;s1024&&(u+="? "),u+=r.dump+(r.condenseFlow?'"':"")+":"+(r.condenseFlow?"":" "),Wl(r,e,c,!1,!1)&&(u+=r.dump,i+=u));r.tag=n,r.dump="{"+i+"}"}function gpe(r,e,t,i){var n="",s=r.tag,o=Object.keys(t),a,l,c,u,g,f;if(r.sortKeys===!0)o.sort();else if(typeof r.sortKeys=="function")o.sort(r.sortKeys);else if(r.sortKeys)throw new Gp("sortKeys must be a boolean or a function");for(a=0,l=o.length;a1024,g&&(r.dump&&Up===r.dump.charCodeAt(0)?f+="?":f+="? "),f+=r.dump,g&&(f+=NS(r,e)),Wl(r,e+1,u,!0,g)&&(r.dump&&Up===r.dump.charCodeAt(0)?f+=":":f+=": ",f+=r.dump,n+=f));r.tag=s,r.dump=n||"{}"}function l2(r,e,t){var i,n,s,o,a,l;for(n=t?r.explicitTypes:r.implicitTypes,s=0,o=n.length;s tag resolver accepts not "'+l+'" style');r.dump=i}return!0}return!1}function Wl(r,e,t,i,n,s){r.tag=null,r.dump=t,l2(r,t,!1)||l2(r,t,!0);var o=c2.call(r.dump);i&&(i=r.flowLevel<0||r.flowLevel>e);var a=o==="[object Object]"||o==="[object Array]",l,c;if(a&&(l=r.duplicates.indexOf(t),c=l!==-1),(r.tag!==null&&r.tag!=="?"||c||r.indent!==2&&e>0)&&(n=!1),c&&r.usedDuplicates[l])r.dump="*ref_"+l;else{if(a&&c&&!r.usedDuplicates[l]&&(r.usedDuplicates[l]=!0),o==="[object Object]")i&&Object.keys(r.dump).length!==0?(gpe(r,e,r.dump,n),c&&(r.dump="&ref_"+l+r.dump)):(upe(r,e,r.dump),c&&(r.dump="&ref_"+l+" "+r.dump));else if(o==="[object Array]"){var u=r.noArrayIndent&&e>0?e-1:e;i&&r.dump.length!==0?(cpe(r,u,r.dump,n),c&&(r.dump="&ref_"+l+r.dump)):(lpe(r,u,r.dump),c&&(r.dump="&ref_"+l+" "+r.dump))}else if(o==="[object String]")r.tag!=="?"&&ope(r,r.dump,e,s);else{if(r.skipInvalid)return!1;throw new Gp("unacceptable kind of an object to dump "+o)}r.tag!==null&&r.tag!=="?"&&(r.dump="!<"+r.tag+"> "+r.dump)}return!0}function fpe(r,e){var t=[],i=[],n,s;for(LS(r,t,i),n=0,s=i.length;n{"use strict";var gI=r2(),S2=b2();function fI(r){return function(){throw new Error("Function "+r+" is deprecated and cannot be used.")}}Fr.exports.Type=si();Fr.exports.Schema=Yl();Fr.exports.FAILSAFE_SCHEMA=sI();Fr.exports.JSON_SCHEMA=xS();Fr.exports.CORE_SCHEMA=PS();Fr.exports.DEFAULT_SAFE_SCHEMA=Sg();Fr.exports.DEFAULT_FULL_SCHEMA=Mp();Fr.exports.load=gI.load;Fr.exports.loadAll=gI.loadAll;Fr.exports.safeLoad=gI.safeLoad;Fr.exports.safeLoadAll=gI.safeLoadAll;Fr.exports.dump=S2.dump;Fr.exports.safeDump=S2.safeDump;Fr.exports.YAMLException=Qg();Fr.exports.MINIMAL_SCHEMA=sI();Fr.exports.SAFE_SCHEMA=Sg();Fr.exports.DEFAULT_SCHEMA=Mp();Fr.exports.scan=fI("scan");Fr.exports.parse=fI("parse");Fr.exports.compose=fI("compose");Fr.exports.addConstructor=fI("addConstructor")});var P2=w((GXe,x2)=>{"use strict";var ppe=v2();x2.exports=ppe});var k2=w((YXe,D2)=>{"use strict";function dpe(r,e){function t(){this.constructor=r}t.prototype=e.prototype,r.prototype=new t}function zl(r,e,t,i){this.message=r,this.expected=e,this.found=t,this.location=i,this.name="SyntaxError",typeof Error.captureStackTrace=="function"&&Error.captureStackTrace(this,zl)}dpe(zl,Error);zl.buildMessage=function(r,e){var t={literal:function(c){return'"'+n(c.text)+'"'},class:function(c){var u="",g;for(g=0;g0){for(g=1,f=1;g({[Ke]:Ce})))},H=function(R){return R},j=function(R){return R},$=Ts("correct indentation"),V=" ",W=ar(" ",!1),Z=function(R){return R.length===pA*ug},A=function(R){return R.length===(pA+1)*ug},ae=function(){return pA++,!0},ge=function(){return pA--,!0},re=function(){return sg()},O=Ts("pseudostring"),F=/^[^\r\n\t ?:,\][{}#&*!|>'"%@`\-]/,ue=Rn(["\r",` -`," "," ","?",":",",","]","[","{","}","#","&","*","!","|",">","'",'"',"%","@","`","-"],!0,!1),he=/^[^\r\n\t ,\][{}:#"']/,ke=Rn(["\r",` -`," "," ",",","]","[","{","}",":","#",'"',"'"],!0,!1),Fe=function(){return sg().replace(/^ *| *$/g,"")},Ne="--",oe=ar("--",!1),le=/^[a-zA-Z\/0-9]/,we=Rn([["a","z"],["A","Z"],"/",["0","9"]],!1,!1),fe=/^[^\r\n\t :,]/,Ae=Rn(["\r",` -`," "," ",":",","],!0,!1),qe="null",ne=ar("null",!1),Y=function(){return null},pe="true",ie=ar("true",!1),de=function(){return!0},tt="false",Pt=ar("false",!1),It=function(){return!1},Or=Ts("string"),ii='"',gi=ar('"',!1),hr=function(){return""},fi=function(R){return R},ni=function(R){return R.join("")},Ls=/^[^"\\\0-\x1F\x7F]/,pr=Rn(['"',"\\",["\0",""],"\x7F"],!0,!1),Ei='\\"',_n=ar('\\"',!1),oa=function(){return'"'},aA="\\\\",eg=ar("\\\\",!1),Zn=function(){return"\\"},AA="\\/",aa=ar("\\/",!1),up=function(){return"/"},lA="\\b",cA=ar("\\b",!1),wr=function(){return"\b"},wl="\\f",tg=ar("\\f",!1),po=function(){return"\f"},rg="\\n",gp=ar("\\n",!1),fp=function(){return` -`},vr="\\r",se=ar("\\r",!1),Co=function(){return"\r"},Dn="\\t",ig=ar("\\t",!1),Qt=function(){return" "},Bl="\\u",kn=ar("\\u",!1),$n=function(R,q,Ce,Ke){return String.fromCharCode(parseInt(`0x${R}${q}${Ce}${Ke}`))},es=/^[0-9a-fA-F]/,gt=Rn([["0","9"],["a","f"],["A","F"]],!1,!1),mo=Ts("blank space"),At=/^[ \t]/,an=Rn([" "," "],!1,!1),S=Ts("white space"),Tt=/^[ \t\n\r]/,ng=Rn([" "," ",` -`,"\r"],!1,!1),Ql=`\r -`,hp=ar(`\r -`,!1),pp=` -`,dp=ar(` -`,!1),Cp="\r",mp=ar("\r",!1),G=0,yt=0,uA=[{line:1,column:1}],ji=0,bl=[],Xe=0,Aa;if("startRule"in e){if(!(e.startRule in i))throw new Error(`Can't start parsing from rule "`+e.startRule+'".');n=i[e.startRule]}function sg(){return r.substring(yt,G)}function bE(){return An(yt,G)}function Ep(R,q){throw q=q!==void 0?q:An(yt,G),vl([Ts(R)],r.substring(yt,G),q)}function SE(R,q){throw q=q!==void 0?q:An(yt,G),og(R,q)}function ar(R,q){return{type:"literal",text:R,ignoreCase:q}}function Rn(R,q,Ce){return{type:"class",parts:R,inverted:q,ignoreCase:Ce}}function Sl(){return{type:"any"}}function Ip(){return{type:"end"}}function Ts(R){return{type:"other",description:R}}function la(R){var q=uA[R],Ce;if(q)return q;for(Ce=R-1;!uA[Ce];)Ce--;for(q=uA[Ce],q={line:q.line,column:q.column};Ceji&&(ji=G,bl=[]),bl.push(R))}function og(R,q){return new zl(R,null,null,q)}function vl(R,q,Ce){return new zl(zl.buildMessage(R,q),R,q,Ce)}function Os(){var R;return R=ag(),R}function xl(){var R,q,Ce;for(R=G,q=[],Ce=gA();Ce!==t;)q.push(Ce),Ce=gA();return q!==t&&(yt=R,q=s(q)),R=q,R}function gA(){var R,q,Ce,Ke,Re;return R=G,q=ua(),q!==t?(r.charCodeAt(G)===45?(Ce=o,G++):(Ce=t,Xe===0&&Te(a)),Ce!==t?(Ke=Rr(),Ke!==t?(Re=ca(),Re!==t?(yt=R,q=l(Re),R=q):(G=R,R=t)):(G=R,R=t)):(G=R,R=t)):(G=R,R=t),R}function ag(){var R,q,Ce;for(R=G,q=[],Ce=Ag();Ce!==t;)q.push(Ce),Ce=Ag();return q!==t&&(yt=R,q=c(q)),R=q,R}function Ag(){var R,q,Ce,Ke,Re,ze,dt,Ft,Fn;if(R=G,q=Rr(),q===t&&(q=null),q!==t){if(Ce=G,r.charCodeAt(G)===35?(Ke=u,G++):(Ke=t,Xe===0&&Te(g)),Ke!==t){if(Re=[],ze=G,dt=G,Xe++,Ft=Us(),Xe--,Ft===t?dt=void 0:(G=dt,dt=t),dt!==t?(r.length>G?(Ft=r.charAt(G),G++):(Ft=t,Xe===0&&Te(f)),Ft!==t?(dt=[dt,Ft],ze=dt):(G=ze,ze=t)):(G=ze,ze=t),ze!==t)for(;ze!==t;)Re.push(ze),ze=G,dt=G,Xe++,Ft=Us(),Xe--,Ft===t?dt=void 0:(G=dt,dt=t),dt!==t?(r.length>G?(Ft=r.charAt(G),G++):(Ft=t,Xe===0&&Te(f)),Ft!==t?(dt=[dt,Ft],ze=dt):(G=ze,ze=t)):(G=ze,ze=t);else Re=t;Re!==t?(Ke=[Ke,Re],Ce=Ke):(G=Ce,Ce=t)}else G=Ce,Ce=t;if(Ce===t&&(Ce=null),Ce!==t){if(Ke=[],Re=Ks(),Re!==t)for(;Re!==t;)Ke.push(Re),Re=Ks();else Ke=t;Ke!==t?(yt=R,q=h(),R=q):(G=R,R=t)}else G=R,R=t}else G=R,R=t;if(R===t&&(R=G,q=ua(),q!==t?(Ce=Pl(),Ce!==t?(Ke=Rr(),Ke===t&&(Ke=null),Ke!==t?(r.charCodeAt(G)===58?(Re=p,G++):(Re=t,Xe===0&&Te(C)),Re!==t?(ze=Rr(),ze===t&&(ze=null),ze!==t?(dt=ca(),dt!==t?(yt=R,q=y(Ce,dt),R=q):(G=R,R=t)):(G=R,R=t)):(G=R,R=t)):(G=R,R=t)):(G=R,R=t)):(G=R,R=t),R===t&&(R=G,q=ua(),q!==t?(Ce=Ms(),Ce!==t?(Ke=Rr(),Ke===t&&(Ke=null),Ke!==t?(r.charCodeAt(G)===58?(Re=p,G++):(Re=t,Xe===0&&Te(C)),Re!==t?(ze=Rr(),ze===t&&(ze=null),ze!==t?(dt=ca(),dt!==t?(yt=R,q=y(Ce,dt),R=q):(G=R,R=t)):(G=R,R=t)):(G=R,R=t)):(G=R,R=t)):(G=R,R=t)):(G=R,R=t),R===t))){if(R=G,q=ua(),q!==t)if(Ce=Ms(),Ce!==t)if(Ke=Rr(),Ke!==t)if(Re=vE(),Re!==t){if(ze=[],dt=Ks(),dt!==t)for(;dt!==t;)ze.push(dt),dt=Ks();else ze=t;ze!==t?(yt=R,q=y(Ce,Re),R=q):(G=R,R=t)}else G=R,R=t;else G=R,R=t;else G=R,R=t;else G=R,R=t;if(R===t)if(R=G,q=ua(),q!==t)if(Ce=Ms(),Ce!==t){if(Ke=[],Re=G,ze=Rr(),ze===t&&(ze=null),ze!==t?(r.charCodeAt(G)===44?(dt=B,G++):(dt=t,Xe===0&&Te(v)),dt!==t?(Ft=Rr(),Ft===t&&(Ft=null),Ft!==t?(Fn=Ms(),Fn!==t?(yt=Re,ze=D(Ce,Fn),Re=ze):(G=Re,Re=t)):(G=Re,Re=t)):(G=Re,Re=t)):(G=Re,Re=t),Re!==t)for(;Re!==t;)Ke.push(Re),Re=G,ze=Rr(),ze===t&&(ze=null),ze!==t?(r.charCodeAt(G)===44?(dt=B,G++):(dt=t,Xe===0&&Te(v)),dt!==t?(Ft=Rr(),Ft===t&&(Ft=null),Ft!==t?(Fn=Ms(),Fn!==t?(yt=Re,ze=D(Ce,Fn),Re=ze):(G=Re,Re=t)):(G=Re,Re=t)):(G=Re,Re=t)):(G=Re,Re=t);else Ke=t;Ke!==t?(Re=Rr(),Re===t&&(Re=null),Re!==t?(r.charCodeAt(G)===58?(ze=p,G++):(ze=t,Xe===0&&Te(C)),ze!==t?(dt=Rr(),dt===t&&(dt=null),dt!==t?(Ft=ca(),Ft!==t?(yt=R,q=L(Ce,Ke,Ft),R=q):(G=R,R=t)):(G=R,R=t)):(G=R,R=t)):(G=R,R=t)):(G=R,R=t)}else G=R,R=t;else G=R,R=t}return R}function ca(){var R,q,Ce,Ke,Re,ze,dt;if(R=G,q=G,Xe++,Ce=G,Ke=Us(),Ke!==t?(Re=rt(),Re!==t?(r.charCodeAt(G)===45?(ze=o,G++):(ze=t,Xe===0&&Te(a)),ze!==t?(dt=Rr(),dt!==t?(Ke=[Ke,Re,ze,dt],Ce=Ke):(G=Ce,Ce=t)):(G=Ce,Ce=t)):(G=Ce,Ce=t)):(G=Ce,Ce=t),Xe--,Ce!==t?(G=q,q=void 0):q=t,q!==t?(Ce=Ks(),Ce!==t?(Ke=Eo(),Ke!==t?(Re=xl(),Re!==t?(ze=fA(),ze!==t?(yt=R,q=H(Re),R=q):(G=R,R=t)):(G=R,R=t)):(G=R,R=t)):(G=R,R=t)):(G=R,R=t),R===t&&(R=G,q=Us(),q!==t?(Ce=Eo(),Ce!==t?(Ke=ag(),Ke!==t?(Re=fA(),Re!==t?(yt=R,q=H(Ke),R=q):(G=R,R=t)):(G=R,R=t)):(G=R,R=t)):(G=R,R=t),R===t))if(R=G,q=Dl(),q!==t){if(Ce=[],Ke=Ks(),Ke!==t)for(;Ke!==t;)Ce.push(Ke),Ke=Ks();else Ce=t;Ce!==t?(yt=R,q=j(q),R=q):(G=R,R=t)}else G=R,R=t;return R}function ua(){var R,q,Ce;for(Xe++,R=G,q=[],r.charCodeAt(G)===32?(Ce=V,G++):(Ce=t,Xe===0&&Te(W));Ce!==t;)q.push(Ce),r.charCodeAt(G)===32?(Ce=V,G++):(Ce=t,Xe===0&&Te(W));return q!==t?(yt=G,Ce=Z(q),Ce?Ce=void 0:Ce=t,Ce!==t?(q=[q,Ce],R=q):(G=R,R=t)):(G=R,R=t),Xe--,R===t&&(q=t,Xe===0&&Te($)),R}function rt(){var R,q,Ce;for(R=G,q=[],r.charCodeAt(G)===32?(Ce=V,G++):(Ce=t,Xe===0&&Te(W));Ce!==t;)q.push(Ce),r.charCodeAt(G)===32?(Ce=V,G++):(Ce=t,Xe===0&&Te(W));return q!==t?(yt=G,Ce=A(q),Ce?Ce=void 0:Ce=t,Ce!==t?(q=[q,Ce],R=q):(G=R,R=t)):(G=R,R=t),R}function Eo(){var R;return yt=G,R=ae(),R?R=void 0:R=t,R}function fA(){var R;return yt=G,R=ge(),R?R=void 0:R=t,R}function Pl(){var R;return R=kl(),R===t&&(R=yp()),R}function Ms(){var R,q,Ce;if(R=kl(),R===t){if(R=G,q=[],Ce=lg(),Ce!==t)for(;Ce!==t;)q.push(Ce),Ce=lg();else q=t;q!==t&&(yt=R,q=re()),R=q}return R}function Dl(){var R;return R=wp(),R===t&&(R=xE(),R===t&&(R=kl(),R===t&&(R=yp()))),R}function vE(){var R;return R=wp(),R===t&&(R=kl(),R===t&&(R=lg())),R}function yp(){var R,q,Ce,Ke,Re,ze;if(Xe++,R=G,F.test(r.charAt(G))?(q=r.charAt(G),G++):(q=t,Xe===0&&Te(ue)),q!==t){for(Ce=[],Ke=G,Re=Rr(),Re===t&&(Re=null),Re!==t?(he.test(r.charAt(G))?(ze=r.charAt(G),G++):(ze=t,Xe===0&&Te(ke)),ze!==t?(Re=[Re,ze],Ke=Re):(G=Ke,Ke=t)):(G=Ke,Ke=t);Ke!==t;)Ce.push(Ke),Ke=G,Re=Rr(),Re===t&&(Re=null),Re!==t?(he.test(r.charAt(G))?(ze=r.charAt(G),G++):(ze=t,Xe===0&&Te(ke)),ze!==t?(Re=[Re,ze],Ke=Re):(G=Ke,Ke=t)):(G=Ke,Ke=t);Ce!==t?(yt=R,q=Fe(),R=q):(G=R,R=t)}else G=R,R=t;return Xe--,R===t&&(q=t,Xe===0&&Te(O)),R}function lg(){var R,q,Ce,Ke,Re;if(R=G,r.substr(G,2)===Ne?(q=Ne,G+=2):(q=t,Xe===0&&Te(oe)),q===t&&(q=null),q!==t)if(le.test(r.charAt(G))?(Ce=r.charAt(G),G++):(Ce=t,Xe===0&&Te(we)),Ce!==t){for(Ke=[],fe.test(r.charAt(G))?(Re=r.charAt(G),G++):(Re=t,Xe===0&&Te(Ae));Re!==t;)Ke.push(Re),fe.test(r.charAt(G))?(Re=r.charAt(G),G++):(Re=t,Xe===0&&Te(Ae));Ke!==t?(yt=R,q=Fe(),R=q):(G=R,R=t)}else G=R,R=t;else G=R,R=t;return R}function wp(){var R,q;return R=G,r.substr(G,4)===qe?(q=qe,G+=4):(q=t,Xe===0&&Te(ne)),q!==t&&(yt=R,q=Y()),R=q,R}function xE(){var R,q;return R=G,r.substr(G,4)===pe?(q=pe,G+=4):(q=t,Xe===0&&Te(ie)),q!==t&&(yt=R,q=de()),R=q,R===t&&(R=G,r.substr(G,5)===tt?(q=tt,G+=5):(q=t,Xe===0&&Te(Pt)),q!==t&&(yt=R,q=It()),R=q),R}function kl(){var R,q,Ce,Ke;return Xe++,R=G,r.charCodeAt(G)===34?(q=ii,G++):(q=t,Xe===0&&Te(gi)),q!==t?(r.charCodeAt(G)===34?(Ce=ii,G++):(Ce=t,Xe===0&&Te(gi)),Ce!==t?(yt=R,q=hr(),R=q):(G=R,R=t)):(G=R,R=t),R===t&&(R=G,r.charCodeAt(G)===34?(q=ii,G++):(q=t,Xe===0&&Te(gi)),q!==t?(Ce=PE(),Ce!==t?(r.charCodeAt(G)===34?(Ke=ii,G++):(Ke=t,Xe===0&&Te(gi)),Ke!==t?(yt=R,q=fi(Ce),R=q):(G=R,R=t)):(G=R,R=t)):(G=R,R=t)),Xe--,R===t&&(q=t,Xe===0&&Te(Or)),R}function PE(){var R,q,Ce;if(R=G,q=[],Ce=cg(),Ce!==t)for(;Ce!==t;)q.push(Ce),Ce=cg();else q=t;return q!==t&&(yt=R,q=ni(q)),R=q,R}function cg(){var R,q,Ce,Ke,Re,ze;return Ls.test(r.charAt(G))?(R=r.charAt(G),G++):(R=t,Xe===0&&Te(pr)),R===t&&(R=G,r.substr(G,2)===Ei?(q=Ei,G+=2):(q=t,Xe===0&&Te(_n)),q!==t&&(yt=R,q=oa()),R=q,R===t&&(R=G,r.substr(G,2)===aA?(q=aA,G+=2):(q=t,Xe===0&&Te(eg)),q!==t&&(yt=R,q=Zn()),R=q,R===t&&(R=G,r.substr(G,2)===AA?(q=AA,G+=2):(q=t,Xe===0&&Te(aa)),q!==t&&(yt=R,q=up()),R=q,R===t&&(R=G,r.substr(G,2)===lA?(q=lA,G+=2):(q=t,Xe===0&&Te(cA)),q!==t&&(yt=R,q=wr()),R=q,R===t&&(R=G,r.substr(G,2)===wl?(q=wl,G+=2):(q=t,Xe===0&&Te(tg)),q!==t&&(yt=R,q=po()),R=q,R===t&&(R=G,r.substr(G,2)===rg?(q=rg,G+=2):(q=t,Xe===0&&Te(gp)),q!==t&&(yt=R,q=fp()),R=q,R===t&&(R=G,r.substr(G,2)===vr?(q=vr,G+=2):(q=t,Xe===0&&Te(se)),q!==t&&(yt=R,q=Co()),R=q,R===t&&(R=G,r.substr(G,2)===Dn?(q=Dn,G+=2):(q=t,Xe===0&&Te(ig)),q!==t&&(yt=R,q=Qt()),R=q,R===t&&(R=G,r.substr(G,2)===Bl?(q=Bl,G+=2):(q=t,Xe===0&&Te(kn)),q!==t?(Ce=hA(),Ce!==t?(Ke=hA(),Ke!==t?(Re=hA(),Re!==t?(ze=hA(),ze!==t?(yt=R,q=$n(Ce,Ke,Re,ze),R=q):(G=R,R=t)):(G=R,R=t)):(G=R,R=t)):(G=R,R=t)):(G=R,R=t)))))))))),R}function hA(){var R;return es.test(r.charAt(G))?(R=r.charAt(G),G++):(R=t,Xe===0&&Te(gt)),R}function Rr(){var R,q;if(Xe++,R=[],At.test(r.charAt(G))?(q=r.charAt(G),G++):(q=t,Xe===0&&Te(an)),q!==t)for(;q!==t;)R.push(q),At.test(r.charAt(G))?(q=r.charAt(G),G++):(q=t,Xe===0&&Te(an));else R=t;return Xe--,R===t&&(q=t,Xe===0&&Te(mo)),R}function DE(){var R,q;if(Xe++,R=[],Tt.test(r.charAt(G))?(q=r.charAt(G),G++):(q=t,Xe===0&&Te(ng)),q!==t)for(;q!==t;)R.push(q),Tt.test(r.charAt(G))?(q=r.charAt(G),G++):(q=t,Xe===0&&Te(ng));else R=t;return Xe--,R===t&&(q=t,Xe===0&&Te(S)),R}function Ks(){var R,q,Ce,Ke,Re,ze;if(R=G,q=Us(),q!==t){for(Ce=[],Ke=G,Re=Rr(),Re===t&&(Re=null),Re!==t?(ze=Us(),ze!==t?(Re=[Re,ze],Ke=Re):(G=Ke,Ke=t)):(G=Ke,Ke=t);Ke!==t;)Ce.push(Ke),Ke=G,Re=Rr(),Re===t&&(Re=null),Re!==t?(ze=Us(),ze!==t?(Re=[Re,ze],Ke=Re):(G=Ke,Ke=t)):(G=Ke,Ke=t);Ce!==t?(q=[q,Ce],R=q):(G=R,R=t)}else G=R,R=t;return R}function Us(){var R;return r.substr(G,2)===Ql?(R=Ql,G+=2):(R=t,Xe===0&&Te(hp)),R===t&&(r.charCodeAt(G)===10?(R=pp,G++):(R=t,Xe===0&&Te(dp)),R===t&&(r.charCodeAt(G)===13?(R=Cp,G++):(R=t,Xe===0&&Te(mp)))),R}let ug=2,pA=0;if(Aa=n(),Aa!==t&&G===r.length)return Aa;throw Aa!==t&&G{"use strict";var wpe=r=>{let e=!1,t=!1,i=!1;for(let n=0;n{if(!(typeof r=="string"||Array.isArray(r)))throw new TypeError("Expected the input to be `string | string[]`");e=Object.assign({pascalCase:!1},e);let t=n=>e.pascalCase?n.charAt(0).toUpperCase()+n.slice(1):n;return Array.isArray(r)?r=r.map(n=>n.trim()).filter(n=>n.length).join("-"):r=r.trim(),r.length===0?"":r.length===1?e.pascalCase?r.toUpperCase():r.toLowerCase():(r!==r.toLowerCase()&&(r=wpe(r)),r=r.replace(/^[_.\- ]+/,"").toLowerCase().replace(/[_.\- ]+(\w|$)/g,(n,s)=>s.toUpperCase()).replace(/\d+(\w|$)/g,n=>n.toUpperCase()),t(r))};KS.exports=T2;KS.exports.default=T2});var M2=w((VXe,Bpe)=>{Bpe.exports=[{name:"AppVeyor",constant:"APPVEYOR",env:"APPVEYOR",pr:"APPVEYOR_PULL_REQUEST_NUMBER"},{name:"Azure Pipelines",constant:"AZURE_PIPELINES",env:"SYSTEM_TEAMFOUNDATIONCOLLECTIONURI",pr:"SYSTEM_PULLREQUEST_PULLREQUESTID"},{name:"Appcircle",constant:"APPCIRCLE",env:"AC_APPCIRCLE"},{name:"Bamboo",constant:"BAMBOO",env:"bamboo_planKey"},{name:"Bitbucket Pipelines",constant:"BITBUCKET",env:"BITBUCKET_COMMIT",pr:"BITBUCKET_PR_ID"},{name:"Bitrise",constant:"BITRISE",env:"BITRISE_IO",pr:"BITRISE_PULL_REQUEST"},{name:"Buddy",constant:"BUDDY",env:"BUDDY_WORKSPACE_ID",pr:"BUDDY_EXECUTION_PULL_REQUEST_ID"},{name:"Buildkite",constant:"BUILDKITE",env:"BUILDKITE",pr:{env:"BUILDKITE_PULL_REQUEST",ne:"false"}},{name:"CircleCI",constant:"CIRCLE",env:"CIRCLECI",pr:"CIRCLE_PULL_REQUEST"},{name:"Cirrus CI",constant:"CIRRUS",env:"CIRRUS_CI",pr:"CIRRUS_PR"},{name:"AWS CodeBuild",constant:"CODEBUILD",env:"CODEBUILD_BUILD_ARN"},{name:"Codefresh",constant:"CODEFRESH",env:"CF_BUILD_ID",pr:{any:["CF_PULL_REQUEST_NUMBER","CF_PULL_REQUEST_ID"]}},{name:"Codeship",constant:"CODESHIP",env:{CI_NAME:"codeship"}},{name:"Drone",constant:"DRONE",env:"DRONE",pr:{DRONE_BUILD_EVENT:"pull_request"}},{name:"dsari",constant:"DSARI",env:"DSARI"},{name:"GitHub Actions",constant:"GITHUB_ACTIONS",env:"GITHUB_ACTIONS",pr:{GITHUB_EVENT_NAME:"pull_request"}},{name:"GitLab CI",constant:"GITLAB",env:"GITLAB_CI",pr:"CI_MERGE_REQUEST_ID"},{name:"GoCD",constant:"GOCD",env:"GO_PIPELINE_LABEL"},{name:"LayerCI",constant:"LAYERCI",env:"LAYERCI",pr:"LAYERCI_PULL_REQUEST"},{name:"Hudson",constant:"HUDSON",env:"HUDSON_URL"},{name:"Jenkins",constant:"JENKINS",env:["JENKINS_URL","BUILD_ID"],pr:{any:["ghprbPullId","CHANGE_ID"]}},{name:"Magnum CI",constant:"MAGNUM",env:"MAGNUM"},{name:"Netlify CI",constant:"NETLIFY",env:"NETLIFY",pr:{env:"PULL_REQUEST",ne:"false"}},{name:"Nevercode",constant:"NEVERCODE",env:"NEVERCODE",pr:{env:"NEVERCODE_PULL_REQUEST",ne:"false"}},{name:"Render",constant:"RENDER",env:"RENDER",pr:{IS_PULL_REQUEST:"true"}},{name:"Sail CI",constant:"SAIL",env:"SAILCI",pr:"SAIL_PULL_REQUEST_NUMBER"},{name:"Semaphore",constant:"SEMAPHORE",env:"SEMAPHORE",pr:"PULL_REQUEST_NUMBER"},{name:"Screwdriver",constant:"SCREWDRIVER",env:"SCREWDRIVER",pr:{env:"SD_PULL_REQUEST",ne:"false"}},{name:"Shippable",constant:"SHIPPABLE",env:"SHIPPABLE",pr:{IS_PULL_REQUEST:"true"}},{name:"Solano CI",constant:"SOLANO",env:"TDDIUM",pr:"TDDIUM_PR_ID"},{name:"Strider CD",constant:"STRIDER",env:"STRIDER"},{name:"TaskCluster",constant:"TASKCLUSTER",env:["TASK_ID","RUN_ID"]},{name:"TeamCity",constant:"TEAMCITY",env:"TEAMCITY_VERSION"},{name:"Travis CI",constant:"TRAVIS",env:"TRAVIS",pr:{env:"TRAVIS_PULL_REQUEST",ne:"false"}},{name:"Vercel",constant:"VERCEL",env:"NOW_BUILDER"},{name:"Visual Studio App Center",constant:"APPCENTER",env:"APPCENTER_BUILD_ID"}]});var Vl=w(On=>{"use strict";var U2=M2(),Qo=process.env;Object.defineProperty(On,"_vendors",{value:U2.map(function(r){return r.constant})});On.name=null;On.isPR=null;U2.forEach(function(r){let t=(Array.isArray(r.env)?r.env:[r.env]).every(function(i){return K2(i)});if(On[r.constant]=t,t)switch(On.name=r.name,typeof r.pr){case"string":On.isPR=!!Qo[r.pr];break;case"object":"env"in r.pr?On.isPR=r.pr.env in Qo&&Qo[r.pr.env]!==r.pr.ne:"any"in r.pr?On.isPR=r.pr.any.some(function(i){return!!Qo[i]}):On.isPR=K2(r.pr);break;default:On.isPR=null}});On.isCI=!!(Qo.CI||Qo.CONTINUOUS_INTEGRATION||Qo.BUILD_NUMBER||Qo.RUN_ID||On.name);function K2(r){return typeof r=="string"?!!Qo[r]:Object.keys(r).every(function(e){return Qo[e]===r[e]})}});var gn={};ut(gn,{KeyRelationship:()=>Xl,applyCascade:()=>zp,base64RegExp:()=>q2,colorStringAlphaRegExp:()=>j2,colorStringRegExp:()=>Y2,computeKey:()=>BA,getPrintable:()=>Vr,hasExactLength:()=>X2,hasForbiddenKeys:()=>tde,hasKeyRelationship:()=>JS,hasMaxLength:()=>Mpe,hasMinLength:()=>Ope,hasMutuallyExclusiveKeys:()=>rde,hasRequiredKeys:()=>ede,hasUniqueItems:()=>Kpe,isArray:()=>Ppe,isAtLeast:()=>Gpe,isAtMost:()=>Ype,isBase64:()=>Zpe,isBoolean:()=>Spe,isDate:()=>xpe,isDict:()=>kpe,isEnum:()=>Wi,isHexColor:()=>_pe,isISO8601:()=>Xpe,isInExclusiveRange:()=>qpe,isInInclusiveRange:()=>jpe,isInstanceOf:()=>Fpe,isInteger:()=>Jpe,isJSON:()=>$pe,isLiteral:()=>Qpe,isLowerCase:()=>Wpe,isNegative:()=>Upe,isNullable:()=>Tpe,isNumber:()=>vpe,isObject:()=>Rpe,isOneOf:()=>Npe,isOptional:()=>Lpe,isPositive:()=>Hpe,isString:()=>Wp,isTuple:()=>Dpe,isUUID4:()=>Vpe,isUnknown:()=>V2,isUpperCase:()=>zpe,iso8601RegExp:()=>qS,makeCoercionFn:()=>_l,makeSetter:()=>z2,makeTrait:()=>W2,makeValidator:()=>bt,matchesRegExp:()=>Vp,plural:()=>EI,pushError:()=>pt,simpleKeyRegExp:()=>G2,uuid4RegExp:()=>J2});function bt({test:r}){return W2(r)()}function Vr(r){return r===null?"null":r===void 0?"undefined":r===""?"an empty string":JSON.stringify(r)}function BA(r,e){var t,i,n;return typeof e=="number"?`${(t=r==null?void 0:r.p)!==null&&t!==void 0?t:"."}[${e}]`:G2.test(e)?`${(i=r==null?void 0:r.p)!==null&&i!==void 0?i:""}.${e}`:`${(n=r==null?void 0:r.p)!==null&&n!==void 0?n:"."}[${JSON.stringify(e)}]`}function _l(r,e){return t=>{let i=r[e];return r[e]=t,_l(r,e).bind(null,i)}}function z2(r,e){return t=>{r[e]=t}}function EI(r,e,t){return r===1?e:t}function pt({errors:r,p:e}={},t){return r==null||r.push(`${e!=null?e:"."}: ${t}`),!1}function Qpe(r){return bt({test:(e,t)=>e!==r?pt(t,`Expected a literal (got ${Vr(r)})`):!0})}function Wi(r){let e=Array.isArray(r)?r:Object.values(r),t=new Set(e);return bt({test:(i,n)=>t.has(i)?!0:pt(n,`Expected a valid enumeration value (got ${Vr(i)})`)})}var G2,Y2,j2,q2,J2,qS,W2,V2,Wp,bpe,Spe,vpe,xpe,Ppe,Dpe,kpe,Rpe,Fpe,Npe,zp,Lpe,Tpe,Ope,Mpe,X2,Kpe,Upe,Hpe,Gpe,Ype,jpe,qpe,Jpe,Vp,Wpe,zpe,Vpe,Xpe,_pe,Zpe,$pe,ede,tde,rde,Xl,ide,JS,ns=Yue(()=>{G2=/^[a-zA-Z_][a-zA-Z0-9_]*$/,Y2=/^#[0-9a-f]{6}$/i,j2=/^#[0-9a-f]{6}([0-9a-f]{2})?$/i,q2=/^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/,J2=/^[a-f0-9]{8}-[a-f0-9]{4}-4[a-f0-9]{3}-[89aAbB][a-f0-9]{3}-[a-f0-9]{12}$/i,qS=/^(?:[1-9]\d{3}(-?)(?:(?:0[1-9]|1[0-2])\1(?:0[1-9]|1\d|2[0-8])|(?:0[13-9]|1[0-2])\1(?:29|30)|(?:0[13578]|1[02])(?:\1)31|00[1-9]|0[1-9]\d|[12]\d{2}|3(?:[0-5]\d|6[0-5]))|(?:[1-9]\d(?:0[48]|[2468][048]|[13579][26])|(?:[2468][048]|[13579][26])00)(?:(-?)02(?:\2)29|-?366))T(?:[01]\d|2[0-3])(:?)[0-5]\d(?:\3[0-5]\d)?(?:Z|[+-][01]\d(?:\3[0-5]\d)?)$/,W2=r=>()=>r;V2=()=>bt({test:(r,e)=>!0});Wp=()=>bt({test:(r,e)=>typeof r!="string"?pt(e,`Expected a string (got ${Vr(r)})`):!0});bpe=new Map([["true",!0],["True",!0],["1",!0],[1,!0],["false",!1],["False",!1],["0",!1],[0,!1]]),Spe=()=>bt({test:(r,e)=>{var t;if(typeof r!="boolean"){if(typeof(e==null?void 0:e.coercions)<"u"){if(typeof(e==null?void 0:e.coercion)>"u")return pt(e,"Unbound coercion result");let i=bpe.get(r);if(typeof i<"u")return e.coercions.push([(t=e.p)!==null&&t!==void 0?t:".",e.coercion.bind(null,i)]),!0}return pt(e,`Expected a boolean (got ${Vr(r)})`)}return!0}}),vpe=()=>bt({test:(r,e)=>{var t;if(typeof r!="number"){if(typeof(e==null?void 0:e.coercions)<"u"){if(typeof(e==null?void 0:e.coercion)>"u")return pt(e,"Unbound coercion result");let i;if(typeof r=="string"){let n;try{n=JSON.parse(r)}catch{}if(typeof n=="number")if(JSON.stringify(n)===r)i=n;else return pt(e,`Received a number that can't be safely represented by the runtime (${r})`)}if(typeof i<"u")return e.coercions.push([(t=e.p)!==null&&t!==void 0?t:".",e.coercion.bind(null,i)]),!0}return pt(e,`Expected a number (got ${Vr(r)})`)}return!0}}),xpe=()=>bt({test:(r,e)=>{var t;if(!(r instanceof Date)){if(typeof(e==null?void 0:e.coercions)<"u"){if(typeof(e==null?void 0:e.coercion)>"u")return pt(e,"Unbound coercion result");let i;if(typeof r=="string"&&qS.test(r))i=new Date(r);else{let n;if(typeof r=="string"){let s;try{s=JSON.parse(r)}catch{}typeof s=="number"&&(n=s)}else typeof r=="number"&&(n=r);if(typeof n<"u")if(Number.isSafeInteger(n)||!Number.isSafeInteger(n*1e3))i=new Date(n*1e3);else return pt(e,`Received a timestamp that can't be safely represented by the runtime (${r})`)}if(typeof i<"u")return e.coercions.push([(t=e.p)!==null&&t!==void 0?t:".",e.coercion.bind(null,i)]),!0}return pt(e,`Expected a date (got ${Vr(r)})`)}return!0}}),Ppe=(r,{delimiter:e}={})=>bt({test:(t,i)=>{var n;if(typeof t=="string"&&typeof e<"u"&&typeof(i==null?void 0:i.coercions)<"u"){if(typeof(i==null?void 0:i.coercion)>"u")return pt(i,"Unbound coercion result");t=t.split(e),i.coercions.push([(n=i.p)!==null&&n!==void 0?n:".",i.coercion.bind(null,t)])}if(!Array.isArray(t))return pt(i,`Expected an array (got ${Vr(t)})`);let s=!0;for(let o=0,a=t.length;o{let t=X2(r.length);return bt({test:(i,n)=>{var s;if(typeof i=="string"&&typeof e<"u"&&typeof(n==null?void 0:n.coercions)<"u"){if(typeof(n==null?void 0:n.coercion)>"u")return pt(n,"Unbound coercion result");i=i.split(e),n.coercions.push([(s=n.p)!==null&&s!==void 0?s:".",n.coercion.bind(null,i)])}if(!Array.isArray(i))return pt(n,`Expected a tuple (got ${Vr(i)})`);let o=t(i,Object.assign({},n));for(let a=0,l=i.length;abt({test:(t,i)=>{if(typeof t!="object"||t===null)return pt(i,`Expected an object (got ${Vr(t)})`);let n=Object.keys(t),s=!0;for(let o=0,a=n.length;o{let t=Object.keys(r);return bt({test:(i,n)=>{if(typeof i!="object"||i===null)return pt(n,`Expected an object (got ${Vr(i)})`);let s=new Set([...t,...Object.keys(i)]),o={},a=!0;for(let l of s){if(l==="constructor"||l==="__proto__")a=pt(Object.assign(Object.assign({},n),{p:BA(n,l)}),"Unsafe property name");else{let c=Object.prototype.hasOwnProperty.call(r,l)?r[l]:void 0,u=Object.prototype.hasOwnProperty.call(i,l)?i[l]:void 0;typeof c<"u"?a=c(u,Object.assign(Object.assign({},n),{p:BA(n,l),coercion:_l(i,l)}))&&a:e===null?a=pt(Object.assign(Object.assign({},n),{p:BA(n,l)}),`Extraneous property (got ${Vr(u)})`):Object.defineProperty(o,l,{enumerable:!0,get:()=>u,set:z2(i,l)})}if(!a&&(n==null?void 0:n.errors)==null)break}return e!==null&&(a||(n==null?void 0:n.errors)!=null)&&(a=e(o,n)&&a),a}})},Fpe=r=>bt({test:(e,t)=>e instanceof r?!0:pt(t,`Expected an instance of ${r.name} (got ${Vr(e)})`)}),Npe=(r,{exclusive:e=!1}={})=>bt({test:(t,i)=>{var n,s,o;let a=[],l=typeof(i==null?void 0:i.errors)<"u"?[]:void 0;for(let c=0,u=r.length;c1?pt(i,`Expected to match exactly a single predicate (matched ${a.join(", ")})`):(o=i==null?void 0:i.errors)===null||o===void 0||o.push(...l),!1}}),zp=(r,e)=>bt({test:(t,i)=>{var n,s;let o={value:t},a=typeof(i==null?void 0:i.coercions)<"u"?_l(o,"value"):void 0,l=typeof(i==null?void 0:i.coercions)<"u"?[]:void 0;if(!r(t,Object.assign(Object.assign({},i),{coercion:a,coercions:l})))return!1;let c=[];if(typeof l<"u")for(let[,u]of l)c.push(u());try{if(typeof(i==null?void 0:i.coercions)<"u"){if(o.value!==t){if(typeof(i==null?void 0:i.coercion)>"u")return pt(i,"Unbound coercion result");i.coercions.push([(n=i.p)!==null&&n!==void 0?n:".",i.coercion.bind(null,o.value)])}(s=i==null?void 0:i.coercions)===null||s===void 0||s.push(...l)}return e.every(u=>u(o.value,i))}finally{for(let u of c)u()}}}),Lpe=r=>bt({test:(e,t)=>typeof e>"u"?!0:r(e,t)}),Tpe=r=>bt({test:(e,t)=>e===null?!0:r(e,t)}),Ope=r=>bt({test:(e,t)=>e.length>=r?!0:pt(t,`Expected to have a length of at least ${r} elements (got ${e.length})`)}),Mpe=r=>bt({test:(e,t)=>e.length<=r?!0:pt(t,`Expected to have a length of at most ${r} elements (got ${e.length})`)}),X2=r=>bt({test:(e,t)=>e.length!==r?pt(t,`Expected to have a length of exactly ${r} elements (got ${e.length})`):!0}),Kpe=({map:r}={})=>bt({test:(e,t)=>{let i=new Set,n=new Set;for(let s=0,o=e.length;sbt({test:(r,e)=>r<=0?!0:pt(e,`Expected to be negative (got ${r})`)}),Hpe=()=>bt({test:(r,e)=>r>=0?!0:pt(e,`Expected to be positive (got ${r})`)}),Gpe=r=>bt({test:(e,t)=>e>=r?!0:pt(t,`Expected to be at least ${r} (got ${e})`)}),Ype=r=>bt({test:(e,t)=>e<=r?!0:pt(t,`Expected to be at most ${r} (got ${e})`)}),jpe=(r,e)=>bt({test:(t,i)=>t>=r&&t<=e?!0:pt(i,`Expected to be in the [${r}; ${e}] range (got ${t})`)}),qpe=(r,e)=>bt({test:(t,i)=>t>=r&&tbt({test:(e,t)=>e!==Math.round(e)?pt(t,`Expected to be an integer (got ${e})`):Number.isSafeInteger(e)?!0:pt(t,`Expected to be a safe integer (got ${e})`)}),Vp=r=>bt({test:(e,t)=>r.test(e)?!0:pt(t,`Expected to match the pattern ${r.toString()} (got ${Vr(e)})`)}),Wpe=()=>bt({test:(r,e)=>r!==r.toLowerCase()?pt(e,`Expected to be all-lowercase (got ${r})`):!0}),zpe=()=>bt({test:(r,e)=>r!==r.toUpperCase()?pt(e,`Expected to be all-uppercase (got ${r})`):!0}),Vpe=()=>bt({test:(r,e)=>J2.test(r)?!0:pt(e,`Expected to be a valid UUID v4 (got ${Vr(r)})`)}),Xpe=()=>bt({test:(r,e)=>qS.test(r)?!1:pt(e,`Expected to be a valid ISO 8601 date string (got ${Vr(r)})`)}),_pe=({alpha:r=!1})=>bt({test:(e,t)=>(r?Y2.test(e):j2.test(e))?!0:pt(t,`Expected to be a valid hexadecimal color string (got ${Vr(e)})`)}),Zpe=()=>bt({test:(r,e)=>q2.test(r)?!0:pt(e,`Expected to be a valid base 64 string (got ${Vr(r)})`)}),$pe=(r=V2())=>bt({test:(e,t)=>{let i;try{i=JSON.parse(e)}catch{return pt(t,`Expected to be a valid JSON string (got ${Vr(e)})`)}return r(i,t)}}),ede=r=>{let e=new Set(r);return bt({test:(t,i)=>{let n=new Set(Object.keys(t)),s=[];for(let o of e)n.has(o)||s.push(o);return s.length>0?pt(i,`Missing required ${EI(s.length,"property","properties")} ${s.map(o=>`"${o}"`).join(", ")}`):!0}})},tde=r=>{let e=new Set(r);return bt({test:(t,i)=>{let n=new Set(Object.keys(t)),s=[];for(let o of e)n.has(o)&&s.push(o);return s.length>0?pt(i,`Forbidden ${EI(s.length,"property","properties")} ${s.map(o=>`"${o}"`).join(", ")}`):!0}})},rde=r=>{let e=new Set(r);return bt({test:(t,i)=>{let n=new Set(Object.keys(t)),s=[];for(let o of e)n.has(o)&&s.push(o);return s.length>1?pt(i,`Mutually exclusive properties ${s.map(o=>`"${o}"`).join(", ")}`):!0}})};(function(r){r.Forbids="Forbids",r.Requires="Requires"})(Xl||(Xl={}));ide={[Xl.Forbids]:{expect:!1,message:"forbids using"},[Xl.Requires]:{expect:!0,message:"requires using"}},JS=(r,e,t,{ignore:i=[]}={})=>{let n=new Set(i),s=new Set(t),o=ide[e];return bt({test:(a,l)=>{let c=new Set(Object.keys(a));if(!c.has(r)||n.has(a[r]))return!0;let u=[];for(let g of s)(c.has(g)&&!n.has(a[g]))!==o.expect&&u.push(g);return u.length>=1?pt(l,`Property "${r}" ${o.message} ${EI(u.length,"property","properties")} ${u.map(g=>`"${g}"`).join(", ")}`):!0}})}});var fH=w((V_e,gH)=>{"use strict";gH.exports=(r,...e)=>new Promise(t=>{t(r(...e))})});var Tg=w((X_e,ev)=>{"use strict";var Ide=fH(),hH=r=>{if(r<1)throw new TypeError("Expected `concurrency` to be a number from 1 and up");let e=[],t=0,i=()=>{t--,e.length>0&&e.shift()()},n=(a,l,...c)=>{t++;let u=Ide(a,...c);l(u),u.then(i,i)},s=(a,l,...c)=>{tnew Promise(c=>s(a,c,...l));return Object.defineProperties(o,{activeCount:{get:()=>t},pendingCount:{get:()=>e.length}}),o};ev.exports=hH;ev.exports.default=hH});var ed=w((Z_e,pH)=>{var yde="2.0.0",wde=Number.MAX_SAFE_INTEGER||9007199254740991,Bde=16;pH.exports={SEMVER_SPEC_VERSION:yde,MAX_LENGTH:256,MAX_SAFE_INTEGER:wde,MAX_SAFE_COMPONENT_LENGTH:Bde}});var td=w(($_e,dH)=>{var Qde=typeof process=="object"&&process.env&&process.env.NODE_DEBUG&&/\bsemver\b/i.test(process.env.NODE_DEBUG)?(...r)=>console.error("SEMVER",...r):()=>{};dH.exports=Qde});var Zl=w((bA,CH)=>{var{MAX_SAFE_COMPONENT_LENGTH:tv}=ed(),bde=td();bA=CH.exports={};var Sde=bA.re=[],$e=bA.src=[],et=bA.t={},vde=0,St=(r,e,t)=>{let i=vde++;bde(i,e),et[r]=i,$e[i]=e,Sde[i]=new RegExp(e,t?"g":void 0)};St("NUMERICIDENTIFIER","0|[1-9]\\d*");St("NUMERICIDENTIFIERLOOSE","[0-9]+");St("NONNUMERICIDENTIFIER","\\d*[a-zA-Z-][a-zA-Z0-9-]*");St("MAINVERSION",`(${$e[et.NUMERICIDENTIFIER]})\\.(${$e[et.NUMERICIDENTIFIER]})\\.(${$e[et.NUMERICIDENTIFIER]})`);St("MAINVERSIONLOOSE",`(${$e[et.NUMERICIDENTIFIERLOOSE]})\\.(${$e[et.NUMERICIDENTIFIERLOOSE]})\\.(${$e[et.NUMERICIDENTIFIERLOOSE]})`);St("PRERELEASEIDENTIFIER",`(?:${$e[et.NUMERICIDENTIFIER]}|${$e[et.NONNUMERICIDENTIFIER]})`);St("PRERELEASEIDENTIFIERLOOSE",`(?:${$e[et.NUMERICIDENTIFIERLOOSE]}|${$e[et.NONNUMERICIDENTIFIER]})`);St("PRERELEASE",`(?:-(${$e[et.PRERELEASEIDENTIFIER]}(?:\\.${$e[et.PRERELEASEIDENTIFIER]})*))`);St("PRERELEASELOOSE",`(?:-?(${$e[et.PRERELEASEIDENTIFIERLOOSE]}(?:\\.${$e[et.PRERELEASEIDENTIFIERLOOSE]})*))`);St("BUILDIDENTIFIER","[0-9A-Za-z-]+");St("BUILD",`(?:\\+(${$e[et.BUILDIDENTIFIER]}(?:\\.${$e[et.BUILDIDENTIFIER]})*))`);St("FULLPLAIN",`v?${$e[et.MAINVERSION]}${$e[et.PRERELEASE]}?${$e[et.BUILD]}?`);St("FULL",`^${$e[et.FULLPLAIN]}$`);St("LOOSEPLAIN",`[v=\\s]*${$e[et.MAINVERSIONLOOSE]}${$e[et.PRERELEASELOOSE]}?${$e[et.BUILD]}?`);St("LOOSE",`^${$e[et.LOOSEPLAIN]}$`);St("GTLT","((?:<|>)?=?)");St("XRANGEIDENTIFIERLOOSE",`${$e[et.NUMERICIDENTIFIERLOOSE]}|x|X|\\*`);St("XRANGEIDENTIFIER",`${$e[et.NUMERICIDENTIFIER]}|x|X|\\*`);St("XRANGEPLAIN",`[v=\\s]*(${$e[et.XRANGEIDENTIFIER]})(?:\\.(${$e[et.XRANGEIDENTIFIER]})(?:\\.(${$e[et.XRANGEIDENTIFIER]})(?:${$e[et.PRERELEASE]})?${$e[et.BUILD]}?)?)?`);St("XRANGEPLAINLOOSE",`[v=\\s]*(${$e[et.XRANGEIDENTIFIERLOOSE]})(?:\\.(${$e[et.XRANGEIDENTIFIERLOOSE]})(?:\\.(${$e[et.XRANGEIDENTIFIERLOOSE]})(?:${$e[et.PRERELEASELOOSE]})?${$e[et.BUILD]}?)?)?`);St("XRANGE",`^${$e[et.GTLT]}\\s*${$e[et.XRANGEPLAIN]}$`);St("XRANGELOOSE",`^${$e[et.GTLT]}\\s*${$e[et.XRANGEPLAINLOOSE]}$`);St("COERCE",`(^|[^\\d])(\\d{1,${tv}})(?:\\.(\\d{1,${tv}}))?(?:\\.(\\d{1,${tv}}))?(?:$|[^\\d])`);St("COERCERTL",$e[et.COERCE],!0);St("LONETILDE","(?:~>?)");St("TILDETRIM",`(\\s*)${$e[et.LONETILDE]}\\s+`,!0);bA.tildeTrimReplace="$1~";St("TILDE",`^${$e[et.LONETILDE]}${$e[et.XRANGEPLAIN]}$`);St("TILDELOOSE",`^${$e[et.LONETILDE]}${$e[et.XRANGEPLAINLOOSE]}$`);St("LONECARET","(?:\\^)");St("CARETTRIM",`(\\s*)${$e[et.LONECARET]}\\s+`,!0);bA.caretTrimReplace="$1^";St("CARET",`^${$e[et.LONECARET]}${$e[et.XRANGEPLAIN]}$`);St("CARETLOOSE",`^${$e[et.LONECARET]}${$e[et.XRANGEPLAINLOOSE]}$`);St("COMPARATORLOOSE",`^${$e[et.GTLT]}\\s*(${$e[et.LOOSEPLAIN]})$|^$`);St("COMPARATOR",`^${$e[et.GTLT]}\\s*(${$e[et.FULLPLAIN]})$|^$`);St("COMPARATORTRIM",`(\\s*)${$e[et.GTLT]}\\s*(${$e[et.LOOSEPLAIN]}|${$e[et.XRANGEPLAIN]})`,!0);bA.comparatorTrimReplace="$1$2$3";St("HYPHENRANGE",`^\\s*(${$e[et.XRANGEPLAIN]})\\s+-\\s+(${$e[et.XRANGEPLAIN]})\\s*$`);St("HYPHENRANGELOOSE",`^\\s*(${$e[et.XRANGEPLAINLOOSE]})\\s+-\\s+(${$e[et.XRANGEPLAINLOOSE]})\\s*$`);St("STAR","(<|>)?=?\\s*\\*");St("GTE0","^\\s*>=\\s*0.0.0\\s*$");St("GTE0PRE","^\\s*>=\\s*0.0.0-0\\s*$")});var rd=w((eZe,mH)=>{var xde=["includePrerelease","loose","rtl"],Pde=r=>r?typeof r!="object"?{loose:!0}:xde.filter(e=>r[e]).reduce((e,t)=>(e[t]=!0,e),{}):{};mH.exports=Pde});var bI=w((tZe,yH)=>{var EH=/^[0-9]+$/,IH=(r,e)=>{let t=EH.test(r),i=EH.test(e);return t&&i&&(r=+r,e=+e),r===e?0:t&&!i?-1:i&&!t?1:rIH(e,r);yH.exports={compareIdentifiers:IH,rcompareIdentifiers:Dde}});var Li=w((rZe,bH)=>{var SI=td(),{MAX_LENGTH:wH,MAX_SAFE_INTEGER:vI}=ed(),{re:BH,t:QH}=Zl(),kde=rd(),{compareIdentifiers:id}=bI(),Un=class{constructor(e,t){if(t=kde(t),e instanceof Un){if(e.loose===!!t.loose&&e.includePrerelease===!!t.includePrerelease)return e;e=e.version}else if(typeof e!="string")throw new TypeError(`Invalid Version: ${e}`);if(e.length>wH)throw new TypeError(`version is longer than ${wH} characters`);SI("SemVer",e,t),this.options=t,this.loose=!!t.loose,this.includePrerelease=!!t.includePrerelease;let i=e.trim().match(t.loose?BH[QH.LOOSE]:BH[QH.FULL]);if(!i)throw new TypeError(`Invalid Version: ${e}`);if(this.raw=e,this.major=+i[1],this.minor=+i[2],this.patch=+i[3],this.major>vI||this.major<0)throw new TypeError("Invalid major version");if(this.minor>vI||this.minor<0)throw new TypeError("Invalid minor version");if(this.patch>vI||this.patch<0)throw new TypeError("Invalid patch version");i[4]?this.prerelease=i[4].split(".").map(n=>{if(/^[0-9]+$/.test(n)){let s=+n;if(s>=0&&s=0;)typeof this.prerelease[i]=="number"&&(this.prerelease[i]++,i=-2);i===-1&&this.prerelease.push(0)}t&&(this.prerelease[0]===t?isNaN(this.prerelease[1])&&(this.prerelease=[t,0]):this.prerelease=[t,0]);break;default:throw new Error(`invalid increment argument: ${e}`)}return this.format(),this.raw=this.version,this}};bH.exports=Un});var $l=w((iZe,PH)=>{var{MAX_LENGTH:Rde}=ed(),{re:SH,t:vH}=Zl(),xH=Li(),Fde=rd(),Nde=(r,e)=>{if(e=Fde(e),r instanceof xH)return r;if(typeof r!="string"||r.length>Rde||!(e.loose?SH[vH.LOOSE]:SH[vH.FULL]).test(r))return null;try{return new xH(r,e)}catch{return null}};PH.exports=Nde});var kH=w((nZe,DH)=>{var Lde=$l(),Tde=(r,e)=>{let t=Lde(r,e);return t?t.version:null};DH.exports=Tde});var FH=w((sZe,RH)=>{var Ode=$l(),Mde=(r,e)=>{let t=Ode(r.trim().replace(/^[=v]+/,""),e);return t?t.version:null};RH.exports=Mde});var LH=w((oZe,NH)=>{var Kde=Li(),Ude=(r,e,t,i)=>{typeof t=="string"&&(i=t,t=void 0);try{return new Kde(r,t).inc(e,i).version}catch{return null}};NH.exports=Ude});var ss=w((aZe,OH)=>{var TH=Li(),Hde=(r,e,t)=>new TH(r,t).compare(new TH(e,t));OH.exports=Hde});var xI=w((AZe,MH)=>{var Gde=ss(),Yde=(r,e,t)=>Gde(r,e,t)===0;MH.exports=Yde});var HH=w((lZe,UH)=>{var KH=$l(),jde=xI(),qde=(r,e)=>{if(jde(r,e))return null;{let t=KH(r),i=KH(e),n=t.prerelease.length||i.prerelease.length,s=n?"pre":"",o=n?"prerelease":"";for(let a in t)if((a==="major"||a==="minor"||a==="patch")&&t[a]!==i[a])return s+a;return o}};UH.exports=qde});var YH=w((cZe,GH)=>{var Jde=Li(),Wde=(r,e)=>new Jde(r,e).major;GH.exports=Wde});var qH=w((uZe,jH)=>{var zde=Li(),Vde=(r,e)=>new zde(r,e).minor;jH.exports=Vde});var WH=w((gZe,JH)=>{var Xde=Li(),_de=(r,e)=>new Xde(r,e).patch;JH.exports=_de});var VH=w((fZe,zH)=>{var Zde=$l(),$de=(r,e)=>{let t=Zde(r,e);return t&&t.prerelease.length?t.prerelease:null};zH.exports=$de});var _H=w((hZe,XH)=>{var eCe=ss(),tCe=(r,e,t)=>eCe(e,r,t);XH.exports=tCe});var $H=w((pZe,ZH)=>{var rCe=ss(),iCe=(r,e)=>rCe(r,e,!0);ZH.exports=iCe});var PI=w((dZe,tG)=>{var eG=Li(),nCe=(r,e,t)=>{let i=new eG(r,t),n=new eG(e,t);return i.compare(n)||i.compareBuild(n)};tG.exports=nCe});var iG=w((CZe,rG)=>{var sCe=PI(),oCe=(r,e)=>r.sort((t,i)=>sCe(t,i,e));rG.exports=oCe});var sG=w((mZe,nG)=>{var aCe=PI(),ACe=(r,e)=>r.sort((t,i)=>aCe(i,t,e));nG.exports=ACe});var nd=w((EZe,oG)=>{var lCe=ss(),cCe=(r,e,t)=>lCe(r,e,t)>0;oG.exports=cCe});var DI=w((IZe,aG)=>{var uCe=ss(),gCe=(r,e,t)=>uCe(r,e,t)<0;aG.exports=gCe});var rv=w((yZe,AG)=>{var fCe=ss(),hCe=(r,e,t)=>fCe(r,e,t)!==0;AG.exports=hCe});var kI=w((wZe,lG)=>{var pCe=ss(),dCe=(r,e,t)=>pCe(r,e,t)>=0;lG.exports=dCe});var RI=w((BZe,cG)=>{var CCe=ss(),mCe=(r,e,t)=>CCe(r,e,t)<=0;cG.exports=mCe});var iv=w((QZe,uG)=>{var ECe=xI(),ICe=rv(),yCe=nd(),wCe=kI(),BCe=DI(),QCe=RI(),bCe=(r,e,t,i)=>{switch(e){case"===":return typeof r=="object"&&(r=r.version),typeof t=="object"&&(t=t.version),r===t;case"!==":return typeof r=="object"&&(r=r.version),typeof t=="object"&&(t=t.version),r!==t;case"":case"=":case"==":return ECe(r,t,i);case"!=":return ICe(r,t,i);case">":return yCe(r,t,i);case">=":return wCe(r,t,i);case"<":return BCe(r,t,i);case"<=":return QCe(r,t,i);default:throw new TypeError(`Invalid operator: ${e}`)}};uG.exports=bCe});var fG=w((bZe,gG)=>{var SCe=Li(),vCe=$l(),{re:FI,t:NI}=Zl(),xCe=(r,e)=>{if(r instanceof SCe)return r;if(typeof r=="number"&&(r=String(r)),typeof r!="string")return null;e=e||{};let t=null;if(!e.rtl)t=r.match(FI[NI.COERCE]);else{let i;for(;(i=FI[NI.COERCERTL].exec(r))&&(!t||t.index+t[0].length!==r.length);)(!t||i.index+i[0].length!==t.index+t[0].length)&&(t=i),FI[NI.COERCERTL].lastIndex=i.index+i[1].length+i[2].length;FI[NI.COERCERTL].lastIndex=-1}return t===null?null:vCe(`${t[2]}.${t[3]||"0"}.${t[4]||"0"}`,e)};gG.exports=xCe});var pG=w((SZe,hG)=>{"use strict";hG.exports=function(r){r.prototype[Symbol.iterator]=function*(){for(let e=this.head;e;e=e.next)yield e.value}}});var sd=w((vZe,dG)=>{"use strict";dG.exports=Ht;Ht.Node=ec;Ht.create=Ht;function Ht(r){var e=this;if(e instanceof Ht||(e=new Ht),e.tail=null,e.head=null,e.length=0,r&&typeof r.forEach=="function")r.forEach(function(n){e.push(n)});else if(arguments.length>0)for(var t=0,i=arguments.length;t1)t=e;else if(this.head)i=this.head.next,t=this.head.value;else throw new TypeError("Reduce of empty list with no initial value");for(var n=0;i!==null;n++)t=r(t,i.value,n),i=i.next;return t};Ht.prototype.reduceReverse=function(r,e){var t,i=this.tail;if(arguments.length>1)t=e;else if(this.tail)i=this.tail.prev,t=this.tail.value;else throw new TypeError("Reduce of empty list with no initial value");for(var n=this.length-1;i!==null;n--)t=r(t,i.value,n),i=i.prev;return t};Ht.prototype.toArray=function(){for(var r=new Array(this.length),e=0,t=this.head;t!==null;e++)r[e]=t.value,t=t.next;return r};Ht.prototype.toArrayReverse=function(){for(var r=new Array(this.length),e=0,t=this.tail;t!==null;e++)r[e]=t.value,t=t.prev;return r};Ht.prototype.slice=function(r,e){e=e||this.length,e<0&&(e+=this.length),r=r||0,r<0&&(r+=this.length);var t=new Ht;if(ethis.length&&(e=this.length);for(var i=0,n=this.head;n!==null&&ithis.length&&(e=this.length);for(var i=this.length,n=this.tail;n!==null&&i>e;i--)n=n.prev;for(;n!==null&&i>r;i--,n=n.prev)t.push(n.value);return t};Ht.prototype.splice=function(r,e,...t){r>this.length&&(r=this.length-1),r<0&&(r=this.length+r);for(var i=0,n=this.head;n!==null&&i{"use strict";var RCe=sd(),tc=Symbol("max"),Ia=Symbol("length"),Og=Symbol("lengthCalculator"),ad=Symbol("allowStale"),rc=Symbol("maxAge"),Ea=Symbol("dispose"),CG=Symbol("noDisposeOnSet"),di=Symbol("lruList"),Ws=Symbol("cache"),EG=Symbol("updateAgeOnGet"),nv=()=>1,ov=class{constructor(e){if(typeof e=="number"&&(e={max:e}),e||(e={}),e.max&&(typeof e.max!="number"||e.max<0))throw new TypeError("max must be a non-negative number");let t=this[tc]=e.max||1/0,i=e.length||nv;if(this[Og]=typeof i!="function"?nv:i,this[ad]=e.stale||!1,e.maxAge&&typeof e.maxAge!="number")throw new TypeError("maxAge must be a number");this[rc]=e.maxAge||0,this[Ea]=e.dispose,this[CG]=e.noDisposeOnSet||!1,this[EG]=e.updateAgeOnGet||!1,this.reset()}set max(e){if(typeof e!="number"||e<0)throw new TypeError("max must be a non-negative number");this[tc]=e||1/0,od(this)}get max(){return this[tc]}set allowStale(e){this[ad]=!!e}get allowStale(){return this[ad]}set maxAge(e){if(typeof e!="number")throw new TypeError("maxAge must be a non-negative number");this[rc]=e,od(this)}get maxAge(){return this[rc]}set lengthCalculator(e){typeof e!="function"&&(e=nv),e!==this[Og]&&(this[Og]=e,this[Ia]=0,this[di].forEach(t=>{t.length=this[Og](t.value,t.key),this[Ia]+=t.length})),od(this)}get lengthCalculator(){return this[Og]}get length(){return this[Ia]}get itemCount(){return this[di].length}rforEach(e,t){t=t||this;for(let i=this[di].tail;i!==null;){let n=i.prev;mG(this,e,i,t),i=n}}forEach(e,t){t=t||this;for(let i=this[di].head;i!==null;){let n=i.next;mG(this,e,i,t),i=n}}keys(){return this[di].toArray().map(e=>e.key)}values(){return this[di].toArray().map(e=>e.value)}reset(){this[Ea]&&this[di]&&this[di].length&&this[di].forEach(e=>this[Ea](e.key,e.value)),this[Ws]=new Map,this[di]=new RCe,this[Ia]=0}dump(){return this[di].map(e=>LI(this,e)?!1:{k:e.key,v:e.value,e:e.now+(e.maxAge||0)}).toArray().filter(e=>e)}dumpLru(){return this[di]}set(e,t,i){if(i=i||this[rc],i&&typeof i!="number")throw new TypeError("maxAge must be a number");let n=i?Date.now():0,s=this[Og](t,e);if(this[Ws].has(e)){if(s>this[tc])return Mg(this,this[Ws].get(e)),!1;let l=this[Ws].get(e).value;return this[Ea]&&(this[CG]||this[Ea](e,l.value)),l.now=n,l.maxAge=i,l.value=t,this[Ia]+=s-l.length,l.length=s,this.get(e),od(this),!0}let o=new av(e,t,s,n,i);return o.length>this[tc]?(this[Ea]&&this[Ea](e,t),!1):(this[Ia]+=o.length,this[di].unshift(o),this[Ws].set(e,this[di].head),od(this),!0)}has(e){if(!this[Ws].has(e))return!1;let t=this[Ws].get(e).value;return!LI(this,t)}get(e){return sv(this,e,!0)}peek(e){return sv(this,e,!1)}pop(){let e=this[di].tail;return e?(Mg(this,e),e.value):null}del(e){Mg(this,this[Ws].get(e))}load(e){this.reset();let t=Date.now();for(let i=e.length-1;i>=0;i--){let n=e[i],s=n.e||0;if(s===0)this.set(n.k,n.v);else{let o=s-t;o>0&&this.set(n.k,n.v,o)}}}prune(){this[Ws].forEach((e,t)=>sv(this,t,!1))}},sv=(r,e,t)=>{let i=r[Ws].get(e);if(i){let n=i.value;if(LI(r,n)){if(Mg(r,i),!r[ad])return}else t&&(r[EG]&&(i.value.now=Date.now()),r[di].unshiftNode(i));return n.value}},LI=(r,e)=>{if(!e||!e.maxAge&&!r[rc])return!1;let t=Date.now()-e.now;return e.maxAge?t>e.maxAge:r[rc]&&t>r[rc]},od=r=>{if(r[Ia]>r[tc])for(let e=r[di].tail;r[Ia]>r[tc]&&e!==null;){let t=e.prev;Mg(r,e),e=t}},Mg=(r,e)=>{if(e){let t=e.value;r[Ea]&&r[Ea](t.key,t.value),r[Ia]-=t.length,r[Ws].delete(t.key),r[di].removeNode(e)}},av=class{constructor(e,t,i,n,s){this.key=e,this.value=t,this.length=i,this.now=n,this.maxAge=s||0}},mG=(r,e,t,i)=>{let n=t.value;LI(r,n)&&(Mg(r,t),r[ad]||(n=void 0)),n&&e.call(i,n.value,n.key,r)};IG.exports=ov});var os=w((PZe,bG)=>{var ic=class{constructor(e,t){if(t=NCe(t),e instanceof ic)return e.loose===!!t.loose&&e.includePrerelease===!!t.includePrerelease?e:new ic(e.raw,t);if(e instanceof Av)return this.raw=e.value,this.set=[[e]],this.format(),this;if(this.options=t,this.loose=!!t.loose,this.includePrerelease=!!t.includePrerelease,this.raw=e,this.set=e.split(/\s*\|\|\s*/).map(i=>this.parseRange(i.trim())).filter(i=>i.length),!this.set.length)throw new TypeError(`Invalid SemVer Range: ${e}`);if(this.set.length>1){let i=this.set[0];if(this.set=this.set.filter(n=>!BG(n[0])),this.set.length===0)this.set=[i];else if(this.set.length>1){for(let n of this.set)if(n.length===1&&KCe(n[0])){this.set=[n];break}}}this.format()}format(){return this.range=this.set.map(e=>e.join(" ").trim()).join("||").trim(),this.range}toString(){return this.range}parseRange(e){e=e.trim();let i=`parseRange:${Object.keys(this.options).join(",")}:${e}`,n=wG.get(i);if(n)return n;let s=this.options.loose,o=s?Ti[Bi.HYPHENRANGELOOSE]:Ti[Bi.HYPHENRANGE];e=e.replace(o,VCe(this.options.includePrerelease)),Gr("hyphen replace",e),e=e.replace(Ti[Bi.COMPARATORTRIM],TCe),Gr("comparator trim",e,Ti[Bi.COMPARATORTRIM]),e=e.replace(Ti[Bi.TILDETRIM],OCe),e=e.replace(Ti[Bi.CARETTRIM],MCe),e=e.split(/\s+/).join(" ");let a=s?Ti[Bi.COMPARATORLOOSE]:Ti[Bi.COMPARATOR],l=e.split(" ").map(f=>UCe(f,this.options)).join(" ").split(/\s+/).map(f=>zCe(f,this.options)).filter(this.options.loose?f=>!!f.match(a):()=>!0).map(f=>new Av(f,this.options)),c=l.length,u=new Map;for(let f of l){if(BG(f))return[f];u.set(f.value,f)}u.size>1&&u.has("")&&u.delete("");let g=[...u.values()];return wG.set(i,g),g}intersects(e,t){if(!(e instanceof ic))throw new TypeError("a Range is required");return this.set.some(i=>QG(i,t)&&e.set.some(n=>QG(n,t)&&i.every(s=>n.every(o=>s.intersects(o,t)))))}test(e){if(!e)return!1;if(typeof e=="string")try{e=new LCe(e,this.options)}catch{return!1}for(let t=0;tr.value==="<0.0.0-0",KCe=r=>r.value==="",QG=(r,e)=>{let t=!0,i=r.slice(),n=i.pop();for(;t&&i.length;)t=i.every(s=>n.intersects(s,e)),n=i.pop();return t},UCe=(r,e)=>(Gr("comp",r,e),r=YCe(r,e),Gr("caret",r),r=HCe(r,e),Gr("tildes",r),r=qCe(r,e),Gr("xrange",r),r=WCe(r,e),Gr("stars",r),r),Vi=r=>!r||r.toLowerCase()==="x"||r==="*",HCe=(r,e)=>r.trim().split(/\s+/).map(t=>GCe(t,e)).join(" "),GCe=(r,e)=>{let t=e.loose?Ti[Bi.TILDELOOSE]:Ti[Bi.TILDE];return r.replace(t,(i,n,s,o,a)=>{Gr("tilde",r,i,n,s,o,a);let l;return Vi(n)?l="":Vi(s)?l=`>=${n}.0.0 <${+n+1}.0.0-0`:Vi(o)?l=`>=${n}.${s}.0 <${n}.${+s+1}.0-0`:a?(Gr("replaceTilde pr",a),l=`>=${n}.${s}.${o}-${a} <${n}.${+s+1}.0-0`):l=`>=${n}.${s}.${o} <${n}.${+s+1}.0-0`,Gr("tilde return",l),l})},YCe=(r,e)=>r.trim().split(/\s+/).map(t=>jCe(t,e)).join(" "),jCe=(r,e)=>{Gr("caret",r,e);let t=e.loose?Ti[Bi.CARETLOOSE]:Ti[Bi.CARET],i=e.includePrerelease?"-0":"";return r.replace(t,(n,s,o,a,l)=>{Gr("caret",r,n,s,o,a,l);let c;return Vi(s)?c="":Vi(o)?c=`>=${s}.0.0${i} <${+s+1}.0.0-0`:Vi(a)?s==="0"?c=`>=${s}.${o}.0${i} <${s}.${+o+1}.0-0`:c=`>=${s}.${o}.0${i} <${+s+1}.0.0-0`:l?(Gr("replaceCaret pr",l),s==="0"?o==="0"?c=`>=${s}.${o}.${a}-${l} <${s}.${o}.${+a+1}-0`:c=`>=${s}.${o}.${a}-${l} <${s}.${+o+1}.0-0`:c=`>=${s}.${o}.${a}-${l} <${+s+1}.0.0-0`):(Gr("no pr"),s==="0"?o==="0"?c=`>=${s}.${o}.${a}${i} <${s}.${o}.${+a+1}-0`:c=`>=${s}.${o}.${a}${i} <${s}.${+o+1}.0-0`:c=`>=${s}.${o}.${a} <${+s+1}.0.0-0`),Gr("caret return",c),c})},qCe=(r,e)=>(Gr("replaceXRanges",r,e),r.split(/\s+/).map(t=>JCe(t,e)).join(" ")),JCe=(r,e)=>{r=r.trim();let t=e.loose?Ti[Bi.XRANGELOOSE]:Ti[Bi.XRANGE];return r.replace(t,(i,n,s,o,a,l)=>{Gr("xRange",r,i,n,s,o,a,l);let c=Vi(s),u=c||Vi(o),g=u||Vi(a),f=g;return n==="="&&f&&(n=""),l=e.includePrerelease?"-0":"",c?n===">"||n==="<"?i="<0.0.0-0":i="*":n&&f?(u&&(o=0),a=0,n===">"?(n=">=",u?(s=+s+1,o=0,a=0):(o=+o+1,a=0)):n==="<="&&(n="<",u?s=+s+1:o=+o+1),n==="<"&&(l="-0"),i=`${n+s}.${o}.${a}${l}`):u?i=`>=${s}.0.0${l} <${+s+1}.0.0-0`:g&&(i=`>=${s}.${o}.0${l} <${s}.${+o+1}.0-0`),Gr("xRange return",i),i})},WCe=(r,e)=>(Gr("replaceStars",r,e),r.trim().replace(Ti[Bi.STAR],"")),zCe=(r,e)=>(Gr("replaceGTE0",r,e),r.trim().replace(Ti[e.includePrerelease?Bi.GTE0PRE:Bi.GTE0],"")),VCe=r=>(e,t,i,n,s,o,a,l,c,u,g,f,h)=>(Vi(i)?t="":Vi(n)?t=`>=${i}.0.0${r?"-0":""}`:Vi(s)?t=`>=${i}.${n}.0${r?"-0":""}`:o?t=`>=${t}`:t=`>=${t}${r?"-0":""}`,Vi(c)?l="":Vi(u)?l=`<${+c+1}.0.0-0`:Vi(g)?l=`<${c}.${+u+1}.0-0`:f?l=`<=${c}.${u}.${g}-${f}`:r?l=`<${c}.${u}.${+g+1}-0`:l=`<=${l}`,`${t} ${l}`.trim()),XCe=(r,e,t)=>{for(let i=0;i0){let n=r[i].semver;if(n.major===e.major&&n.minor===e.minor&&n.patch===e.patch)return!0}return!1}return!0}});var Ad=w((DZe,DG)=>{var ld=Symbol("SemVer ANY"),Kg=class{static get ANY(){return ld}constructor(e,t){if(t=_Ce(t),e instanceof Kg){if(e.loose===!!t.loose)return e;e=e.value}cv("comparator",e,t),this.options=t,this.loose=!!t.loose,this.parse(e),this.semver===ld?this.value="":this.value=this.operator+this.semver.version,cv("comp",this)}parse(e){let t=this.options.loose?SG[vG.COMPARATORLOOSE]:SG[vG.COMPARATOR],i=e.match(t);if(!i)throw new TypeError(`Invalid comparator: ${e}`);this.operator=i[1]!==void 0?i[1]:"",this.operator==="="&&(this.operator=""),i[2]?this.semver=new xG(i[2],this.options.loose):this.semver=ld}toString(){return this.value}test(e){if(cv("Comparator.test",e,this.options.loose),this.semver===ld||e===ld)return!0;if(typeof e=="string")try{e=new xG(e,this.options)}catch{return!1}return lv(e,this.operator,this.semver,this.options)}intersects(e,t){if(!(e instanceof Kg))throw new TypeError("a Comparator is required");if((!t||typeof t!="object")&&(t={loose:!!t,includePrerelease:!1}),this.operator==="")return this.value===""?!0:new PG(e.value,t).test(this.value);if(e.operator==="")return e.value===""?!0:new PG(this.value,t).test(e.semver);let i=(this.operator===">="||this.operator===">")&&(e.operator===">="||e.operator===">"),n=(this.operator==="<="||this.operator==="<")&&(e.operator==="<="||e.operator==="<"),s=this.semver.version===e.semver.version,o=(this.operator===">="||this.operator==="<=")&&(e.operator===">="||e.operator==="<="),a=lv(this.semver,"<",e.semver,t)&&(this.operator===">="||this.operator===">")&&(e.operator==="<="||e.operator==="<"),l=lv(this.semver,">",e.semver,t)&&(this.operator==="<="||this.operator==="<")&&(e.operator===">="||e.operator===">");return i||n||s&&o||a||l}};DG.exports=Kg;var _Ce=rd(),{re:SG,t:vG}=Zl(),lv=iv(),cv=td(),xG=Li(),PG=os()});var cd=w((kZe,kG)=>{var ZCe=os(),$Ce=(r,e,t)=>{try{e=new ZCe(e,t)}catch{return!1}return e.test(r)};kG.exports=$Ce});var FG=w((RZe,RG)=>{var eme=os(),tme=(r,e)=>new eme(r,e).set.map(t=>t.map(i=>i.value).join(" ").trim().split(" "));RG.exports=tme});var LG=w((FZe,NG)=>{var rme=Li(),ime=os(),nme=(r,e,t)=>{let i=null,n=null,s=null;try{s=new ime(e,t)}catch{return null}return r.forEach(o=>{s.test(o)&&(!i||n.compare(o)===-1)&&(i=o,n=new rme(i,t))}),i};NG.exports=nme});var OG=w((NZe,TG)=>{var sme=Li(),ome=os(),ame=(r,e,t)=>{let i=null,n=null,s=null;try{s=new ome(e,t)}catch{return null}return r.forEach(o=>{s.test(o)&&(!i||n.compare(o)===1)&&(i=o,n=new sme(i,t))}),i};TG.exports=ame});var UG=w((LZe,KG)=>{var uv=Li(),Ame=os(),MG=nd(),lme=(r,e)=>{r=new Ame(r,e);let t=new uv("0.0.0");if(r.test(t)||(t=new uv("0.0.0-0"),r.test(t)))return t;t=null;for(let i=0;i{let a=new uv(o.semver.version);switch(o.operator){case">":a.prerelease.length===0?a.patch++:a.prerelease.push(0),a.raw=a.format();case"":case">=":(!s||MG(a,s))&&(s=a);break;case"<":case"<=":break;default:throw new Error(`Unexpected operation: ${o.operator}`)}}),s&&(!t||MG(t,s))&&(t=s)}return t&&r.test(t)?t:null};KG.exports=lme});var GG=w((TZe,HG)=>{var cme=os(),ume=(r,e)=>{try{return new cme(r,e).range||"*"}catch{return null}};HG.exports=ume});var TI=w((OZe,JG)=>{var gme=Li(),qG=Ad(),{ANY:fme}=qG,hme=os(),pme=cd(),YG=nd(),jG=DI(),dme=RI(),Cme=kI(),mme=(r,e,t,i)=>{r=new gme(r,i),e=new hme(e,i);let n,s,o,a,l;switch(t){case">":n=YG,s=dme,o=jG,a=">",l=">=";break;case"<":n=jG,s=Cme,o=YG,a="<",l="<=";break;default:throw new TypeError('Must provide a hilo val of "<" or ">"')}if(pme(r,e,i))return!1;for(let c=0;c{h.semver===fme&&(h=new qG(">=0.0.0")),g=g||h,f=f||h,n(h.semver,g.semver,i)?g=h:o(h.semver,f.semver,i)&&(f=h)}),g.operator===a||g.operator===l||(!f.operator||f.operator===a)&&s(r,f.semver))return!1;if(f.operator===l&&o(r,f.semver))return!1}return!0};JG.exports=mme});var zG=w((MZe,WG)=>{var Eme=TI(),Ime=(r,e,t)=>Eme(r,e,">",t);WG.exports=Ime});var XG=w((KZe,VG)=>{var yme=TI(),wme=(r,e,t)=>yme(r,e,"<",t);VG.exports=wme});var $G=w((UZe,ZG)=>{var _G=os(),Bme=(r,e,t)=>(r=new _G(r,t),e=new _G(e,t),r.intersects(e));ZG.exports=Bme});var tY=w((HZe,eY)=>{var Qme=cd(),bme=ss();eY.exports=(r,e,t)=>{let i=[],n=null,s=null,o=r.sort((u,g)=>bme(u,g,t));for(let u of o)Qme(u,e,t)?(s=u,n||(n=u)):(s&&i.push([n,s]),s=null,n=null);n&&i.push([n,null]);let a=[];for(let[u,g]of i)u===g?a.push(u):!g&&u===o[0]?a.push("*"):g?u===o[0]?a.push(`<=${g}`):a.push(`${u} - ${g}`):a.push(`>=${u}`);let l=a.join(" || "),c=typeof e.raw=="string"?e.raw:String(e);return l.length{var rY=os(),OI=Ad(),{ANY:gv}=OI,ud=cd(),fv=ss(),Sme=(r,e,t={})=>{if(r===e)return!0;r=new rY(r,t),e=new rY(e,t);let i=!1;e:for(let n of r.set){for(let s of e.set){let o=vme(n,s,t);if(i=i||o!==null,o)continue e}if(i)return!1}return!0},vme=(r,e,t)=>{if(r===e)return!0;if(r.length===1&&r[0].semver===gv){if(e.length===1&&e[0].semver===gv)return!0;t.includePrerelease?r=[new OI(">=0.0.0-0")]:r=[new OI(">=0.0.0")]}if(e.length===1&&e[0].semver===gv){if(t.includePrerelease)return!0;e=[new OI(">=0.0.0")]}let i=new Set,n,s;for(let h of r)h.operator===">"||h.operator===">="?n=iY(n,h,t):h.operator==="<"||h.operator==="<="?s=nY(s,h,t):i.add(h.semver);if(i.size>1)return null;let o;if(n&&s){if(o=fv(n.semver,s.semver,t),o>0)return null;if(o===0&&(n.operator!==">="||s.operator!=="<="))return null}for(let h of i){if(n&&!ud(h,String(n),t)||s&&!ud(h,String(s),t))return null;for(let p of e)if(!ud(h,String(p),t))return!1;return!0}let a,l,c,u,g=s&&!t.includePrerelease&&s.semver.prerelease.length?s.semver:!1,f=n&&!t.includePrerelease&&n.semver.prerelease.length?n.semver:!1;g&&g.prerelease.length===1&&s.operator==="<"&&g.prerelease[0]===0&&(g=!1);for(let h of e){if(u=u||h.operator===">"||h.operator===">=",c=c||h.operator==="<"||h.operator==="<=",n){if(f&&h.semver.prerelease&&h.semver.prerelease.length&&h.semver.major===f.major&&h.semver.minor===f.minor&&h.semver.patch===f.patch&&(f=!1),h.operator===">"||h.operator===">="){if(a=iY(n,h,t),a===h&&a!==n)return!1}else if(n.operator===">="&&!ud(n.semver,String(h),t))return!1}if(s){if(g&&h.semver.prerelease&&h.semver.prerelease.length&&h.semver.major===g.major&&h.semver.minor===g.minor&&h.semver.patch===g.patch&&(g=!1),h.operator==="<"||h.operator==="<="){if(l=nY(s,h,t),l===h&&l!==s)return!1}else if(s.operator==="<="&&!ud(s.semver,String(h),t))return!1}if(!h.operator&&(s||n)&&o!==0)return!1}return!(n&&c&&!s&&o!==0||s&&u&&!n&&o!==0||f||g)},iY=(r,e,t)=>{if(!r)return e;let i=fv(r.semver,e.semver,t);return i>0?r:i<0||e.operator===">"&&r.operator===">="?e:r},nY=(r,e,t)=>{if(!r)return e;let i=fv(r.semver,e.semver,t);return i<0?r:i>0||e.operator==="<"&&r.operator==="<="?e:r};sY.exports=Sme});var Xr=w((YZe,aY)=>{var hv=Zl();aY.exports={re:hv.re,src:hv.src,tokens:hv.t,SEMVER_SPEC_VERSION:ed().SEMVER_SPEC_VERSION,SemVer:Li(),compareIdentifiers:bI().compareIdentifiers,rcompareIdentifiers:bI().rcompareIdentifiers,parse:$l(),valid:kH(),clean:FH(),inc:LH(),diff:HH(),major:YH(),minor:qH(),patch:WH(),prerelease:VH(),compare:ss(),rcompare:_H(),compareLoose:$H(),compareBuild:PI(),sort:iG(),rsort:sG(),gt:nd(),lt:DI(),eq:xI(),neq:rv(),gte:kI(),lte:RI(),cmp:iv(),coerce:fG(),Comparator:Ad(),Range:os(),satisfies:cd(),toComparators:FG(),maxSatisfying:LG(),minSatisfying:OG(),minVersion:UG(),validRange:GG(),outside:TI(),gtr:zG(),ltr:XG(),intersects:$G(),simplifyRange:tY(),subset:oY()}});var pv=w(MI=>{"use strict";Object.defineProperty(MI,"__esModule",{value:!0});MI.VERSION=void 0;MI.VERSION="9.1.0"});var Gt=w((exports,module)=>{"use strict";var __spreadArray=exports&&exports.__spreadArray||function(r,e,t){if(t||arguments.length===2)for(var i=0,n=e.length,s;i{(function(r,e){typeof define=="function"&&define.amd?define([],e):typeof KI=="object"&&KI.exports?KI.exports=e():r.regexpToAst=e()})(typeof self<"u"?self:AY,function(){function r(){}r.prototype.saveState=function(){return{idx:this.idx,input:this.input,groupIdx:this.groupIdx}},r.prototype.restoreState=function(p){this.idx=p.idx,this.input=p.input,this.groupIdx=p.groupIdx},r.prototype.pattern=function(p){this.idx=0,this.input=p,this.groupIdx=0,this.consumeChar("/");var C=this.disjunction();this.consumeChar("/");for(var y={type:"Flags",loc:{begin:this.idx,end:p.length},global:!1,ignoreCase:!1,multiLine:!1,unicode:!1,sticky:!1};this.isRegExpFlag();)switch(this.popChar()){case"g":o(y,"global");break;case"i":o(y,"ignoreCase");break;case"m":o(y,"multiLine");break;case"u":o(y,"unicode");break;case"y":o(y,"sticky");break}if(this.idx!==this.input.length)throw Error("Redundant input: "+this.input.substring(this.idx));return{type:"Pattern",flags:y,value:C,loc:this.loc(0)}},r.prototype.disjunction=function(){var p=[],C=this.idx;for(p.push(this.alternative());this.peekChar()==="|";)this.consumeChar("|"),p.push(this.alternative());return{type:"Disjunction",value:p,loc:this.loc(C)}},r.prototype.alternative=function(){for(var p=[],C=this.idx;this.isTerm();)p.push(this.term());return{type:"Alternative",value:p,loc:this.loc(C)}},r.prototype.term=function(){return this.isAssertion()?this.assertion():this.atom()},r.prototype.assertion=function(){var p=this.idx;switch(this.popChar()){case"^":return{type:"StartAnchor",loc:this.loc(p)};case"$":return{type:"EndAnchor",loc:this.loc(p)};case"\\":switch(this.popChar()){case"b":return{type:"WordBoundary",loc:this.loc(p)};case"B":return{type:"NonWordBoundary",loc:this.loc(p)}}throw Error("Invalid Assertion Escape");case"(":this.consumeChar("?");var C;switch(this.popChar()){case"=":C="Lookahead";break;case"!":C="NegativeLookahead";break}a(C);var y=this.disjunction();return this.consumeChar(")"),{type:C,value:y,loc:this.loc(p)}}l()},r.prototype.quantifier=function(p){var C,y=this.idx;switch(this.popChar()){case"*":C={atLeast:0,atMost:1/0};break;case"+":C={atLeast:1,atMost:1/0};break;case"?":C={atLeast:0,atMost:1};break;case"{":var B=this.integerIncludingZero();switch(this.popChar()){case"}":C={atLeast:B,atMost:B};break;case",":var v;this.isDigit()?(v=this.integerIncludingZero(),C={atLeast:B,atMost:v}):C={atLeast:B,atMost:1/0},this.consumeChar("}");break}if(p===!0&&C===void 0)return;a(C);break}if(!(p===!0&&C===void 0))return a(C),this.peekChar(0)==="?"?(this.consumeChar("?"),C.greedy=!1):C.greedy=!0,C.type="Quantifier",C.loc=this.loc(y),C},r.prototype.atom=function(){var p,C=this.idx;switch(this.peekChar()){case".":p=this.dotAll();break;case"\\":p=this.atomEscape();break;case"[":p=this.characterClass();break;case"(":p=this.group();break}return p===void 0&&this.isPatternCharacter()&&(p=this.patternCharacter()),a(p),p.loc=this.loc(C),this.isQuantifier()&&(p.quantifier=this.quantifier()),p},r.prototype.dotAll=function(){return this.consumeChar("."),{type:"Set",complement:!0,value:[n(` -`),n("\r"),n("\u2028"),n("\u2029")]}},r.prototype.atomEscape=function(){switch(this.consumeChar("\\"),this.peekChar()){case"1":case"2":case"3":case"4":case"5":case"6":case"7":case"8":case"9":return this.decimalEscapeAtom();case"d":case"D":case"s":case"S":case"w":case"W":return this.characterClassEscape();case"f":case"n":case"r":case"t":case"v":return this.controlEscapeAtom();case"c":return this.controlLetterEscapeAtom();case"0":return this.nulCharacterAtom();case"x":return this.hexEscapeSequenceAtom();case"u":return this.regExpUnicodeEscapeSequenceAtom();default:return this.identityEscapeAtom()}},r.prototype.decimalEscapeAtom=function(){var p=this.positiveInteger();return{type:"GroupBackReference",value:p}},r.prototype.characterClassEscape=function(){var p,C=!1;switch(this.popChar()){case"d":p=u;break;case"D":p=u,C=!0;break;case"s":p=f;break;case"S":p=f,C=!0;break;case"w":p=g;break;case"W":p=g,C=!0;break}return a(p),{type:"Set",value:p,complement:C}},r.prototype.controlEscapeAtom=function(){var p;switch(this.popChar()){case"f":p=n("\f");break;case"n":p=n(` -`);break;case"r":p=n("\r");break;case"t":p=n(" ");break;case"v":p=n("\v");break}return a(p),{type:"Character",value:p}},r.prototype.controlLetterEscapeAtom=function(){this.consumeChar("c");var p=this.popChar();if(/[a-zA-Z]/.test(p)===!1)throw Error("Invalid ");var C=p.toUpperCase().charCodeAt(0)-64;return{type:"Character",value:C}},r.prototype.nulCharacterAtom=function(){return this.consumeChar("0"),{type:"Character",value:n("\0")}},r.prototype.hexEscapeSequenceAtom=function(){return this.consumeChar("x"),this.parseHexDigits(2)},r.prototype.regExpUnicodeEscapeSequenceAtom=function(){return this.consumeChar("u"),this.parseHexDigits(4)},r.prototype.identityEscapeAtom=function(){var p=this.popChar();return{type:"Character",value:n(p)}},r.prototype.classPatternCharacterAtom=function(){switch(this.peekChar()){case` -`:case"\r":case"\u2028":case"\u2029":case"\\":case"]":throw Error("TBD");default:var p=this.popChar();return{type:"Character",value:n(p)}}},r.prototype.characterClass=function(){var p=[],C=!1;for(this.consumeChar("["),this.peekChar(0)==="^"&&(this.consumeChar("^"),C=!0);this.isClassAtom();){var y=this.classAtom(),B=y.type==="Character";if(B&&this.isRangeDash()){this.consumeChar("-");var v=this.classAtom(),D=v.type==="Character";if(D){if(v.value=this.input.length)throw Error("Unexpected end of input");this.idx++},r.prototype.loc=function(p){return{begin:p,end:this.idx}};var e=/[0-9a-fA-F]/,t=/[0-9]/,i=/[1-9]/;function n(p){return p.charCodeAt(0)}function s(p,C){p.length!==void 0?p.forEach(function(y){C.push(y)}):C.push(p)}function o(p,C){if(p[C]===!0)throw"duplicate flag "+C;p[C]=!0}function a(p){if(p===void 0)throw Error("Internal Error - Should never get here!")}function l(){throw Error("Internal Error - Should never get here!")}var c,u=[];for(c=n("0");c<=n("9");c++)u.push(c);var g=[n("_")].concat(u);for(c=n("a");c<=n("z");c++)g.push(c);for(c=n("A");c<=n("Z");c++)g.push(c);var f=[n(" "),n("\f"),n(` -`),n("\r"),n(" "),n("\v"),n(" "),n("\xA0"),n("\u1680"),n("\u2000"),n("\u2001"),n("\u2002"),n("\u2003"),n("\u2004"),n("\u2005"),n("\u2006"),n("\u2007"),n("\u2008"),n("\u2009"),n("\u200A"),n("\u2028"),n("\u2029"),n("\u202F"),n("\u205F"),n("\u3000"),n("\uFEFF")];function h(){}return h.prototype.visitChildren=function(p){for(var C in p){var y=p[C];p.hasOwnProperty(C)&&(y.type!==void 0?this.visit(y):Array.isArray(y)&&y.forEach(function(B){this.visit(B)},this))}},h.prototype.visit=function(p){switch(p.type){case"Pattern":this.visitPattern(p);break;case"Flags":this.visitFlags(p);break;case"Disjunction":this.visitDisjunction(p);break;case"Alternative":this.visitAlternative(p);break;case"StartAnchor":this.visitStartAnchor(p);break;case"EndAnchor":this.visitEndAnchor(p);break;case"WordBoundary":this.visitWordBoundary(p);break;case"NonWordBoundary":this.visitNonWordBoundary(p);break;case"Lookahead":this.visitLookahead(p);break;case"NegativeLookahead":this.visitNegativeLookahead(p);break;case"Character":this.visitCharacter(p);break;case"Set":this.visitSet(p);break;case"Group":this.visitGroup(p);break;case"GroupBackReference":this.visitGroupBackReference(p);break;case"Quantifier":this.visitQuantifier(p);break}this.visitChildren(p)},h.prototype.visitPattern=function(p){},h.prototype.visitFlags=function(p){},h.prototype.visitDisjunction=function(p){},h.prototype.visitAlternative=function(p){},h.prototype.visitStartAnchor=function(p){},h.prototype.visitEndAnchor=function(p){},h.prototype.visitWordBoundary=function(p){},h.prototype.visitNonWordBoundary=function(p){},h.prototype.visitLookahead=function(p){},h.prototype.visitNegativeLookahead=function(p){},h.prototype.visitCharacter=function(p){},h.prototype.visitSet=function(p){},h.prototype.visitGroup=function(p){},h.prototype.visitGroupBackReference=function(p){},h.prototype.visitQuantifier=function(p){},{RegExpParser:r,BaseRegExpVisitor:h,VERSION:"0.5.0"}})});var GI=w(Ug=>{"use strict";Object.defineProperty(Ug,"__esModule",{value:!0});Ug.clearRegExpParserCache=Ug.getRegExpAst=void 0;var xme=UI(),HI={},Pme=new xme.RegExpParser;function Dme(r){var e=r.toString();if(HI.hasOwnProperty(e))return HI[e];var t=Pme.pattern(e);return HI[e]=t,t}Ug.getRegExpAst=Dme;function kme(){HI={}}Ug.clearRegExpParserCache=kme});var fY=w(pn=>{"use strict";var Rme=pn&&pn.__extends||function(){var r=function(e,t){return r=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(i,n){i.__proto__=n}||function(i,n){for(var s in n)Object.prototype.hasOwnProperty.call(n,s)&&(i[s]=n[s])},r(e,t)};return function(e,t){if(typeof t!="function"&&t!==null)throw new TypeError("Class extends value "+String(t)+" is not a constructor or null");r(e,t);function i(){this.constructor=e}e.prototype=t===null?Object.create(t):(i.prototype=t.prototype,new i)}}();Object.defineProperty(pn,"__esModule",{value:!0});pn.canMatchCharCode=pn.firstCharOptimizedIndices=pn.getOptimizedStartCodesIndices=pn.failedOptimizationPrefixMsg=void 0;var cY=UI(),as=Gt(),uY=GI(),ya=Cv(),gY="Complement Sets are not supported for first char optimization";pn.failedOptimizationPrefixMsg=`Unable to use "first char" lexer optimizations: -`;function Fme(r,e){e===void 0&&(e=!1);try{var t=(0,uY.getRegExpAst)(r),i=jI(t.value,{},t.flags.ignoreCase);return i}catch(s){if(s.message===gY)e&&(0,as.PRINT_WARNING)(""+pn.failedOptimizationPrefixMsg+(" Unable to optimize: < "+r.toString()+` > -`)+` Complement Sets cannot be automatically optimized. - This will disable the lexer's first char optimizations. - See: https://chevrotain.io/docs/guide/resolving_lexer_errors.html#COMPLEMENT for details.`);else{var n="";e&&(n=` - This will disable the lexer's first char optimizations. - See: https://chevrotain.io/docs/guide/resolving_lexer_errors.html#REGEXP_PARSING for details.`),(0,as.PRINT_ERROR)(pn.failedOptimizationPrefixMsg+` -`+(" Failed parsing: < "+r.toString()+` > -`)+(" Using the regexp-to-ast library version: "+cY.VERSION+` -`)+" Please open an issue at: https://github.com/bd82/regexp-to-ast/issues"+n)}}return[]}pn.getOptimizedStartCodesIndices=Fme;function jI(r,e,t){switch(r.type){case"Disjunction":for(var i=0;i=ya.minOptimizationVal)for(var f=u.from>=ya.minOptimizationVal?u.from:ya.minOptimizationVal,h=u.to,p=(0,ya.charCodeToOptimizedIndex)(f),C=(0,ya.charCodeToOptimizedIndex)(h),y=p;y<=C;y++)e[y]=y}}});break;case"Group":jI(o.value,e,t);break;default:throw Error("Non Exhaustive Match")}var a=o.quantifier!==void 0&&o.quantifier.atLeast===0;if(o.type==="Group"&&dv(o)===!1||o.type!=="Group"&&a===!1)break}break;default:throw Error("non exhaustive match!")}return(0,as.values)(e)}pn.firstCharOptimizedIndices=jI;function YI(r,e,t){var i=(0,ya.charCodeToOptimizedIndex)(r);e[i]=i,t===!0&&Nme(r,e)}function Nme(r,e){var t=String.fromCharCode(r),i=t.toUpperCase();if(i!==t){var n=(0,ya.charCodeToOptimizedIndex)(i.charCodeAt(0));e[n]=n}else{var s=t.toLowerCase();if(s!==t){var n=(0,ya.charCodeToOptimizedIndex)(s.charCodeAt(0));e[n]=n}}}function lY(r,e){return(0,as.find)(r.value,function(t){if(typeof t=="number")return(0,as.contains)(e,t);var i=t;return(0,as.find)(e,function(n){return i.from<=n&&n<=i.to})!==void 0})}function dv(r){return r.quantifier&&r.quantifier.atLeast===0?!0:r.value?(0,as.isArray)(r.value)?(0,as.every)(r.value,dv):dv(r.value):!1}var Lme=function(r){Rme(e,r);function e(t){var i=r.call(this)||this;return i.targetCharCodes=t,i.found=!1,i}return e.prototype.visitChildren=function(t){if(this.found!==!0){switch(t.type){case"Lookahead":this.visitLookahead(t);return;case"NegativeLookahead":this.visitNegativeLookahead(t);return}r.prototype.visitChildren.call(this,t)}},e.prototype.visitCharacter=function(t){(0,as.contains)(this.targetCharCodes,t.value)&&(this.found=!0)},e.prototype.visitSet=function(t){t.complement?lY(t,this.targetCharCodes)===void 0&&(this.found=!0):lY(t,this.targetCharCodes)!==void 0&&(this.found=!0)},e}(cY.BaseRegExpVisitor);function Tme(r,e){if(e instanceof RegExp){var t=(0,uY.getRegExpAst)(e),i=new Lme(r);return i.visit(t),i.found}else return(0,as.find)(e,function(n){return(0,as.contains)(r,n.charCodeAt(0))})!==void 0}pn.canMatchCharCode=Tme});var Cv=w(Ve=>{"use strict";var hY=Ve&&Ve.__extends||function(){var r=function(e,t){return r=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(i,n){i.__proto__=n}||function(i,n){for(var s in n)Object.prototype.hasOwnProperty.call(n,s)&&(i[s]=n[s])},r(e,t)};return function(e,t){if(typeof t!="function"&&t!==null)throw new TypeError("Class extends value "+String(t)+" is not a constructor or null");r(e,t);function i(){this.constructor=e}e.prototype=t===null?Object.create(t):(i.prototype=t.prototype,new i)}}();Object.defineProperty(Ve,"__esModule",{value:!0});Ve.charCodeToOptimizedIndex=Ve.minOptimizationVal=Ve.buildLineBreakIssueMessage=Ve.LineTerminatorOptimizedTester=Ve.isShortPattern=Ve.isCustomPattern=Ve.cloneEmptyGroups=Ve.performWarningRuntimeChecks=Ve.performRuntimeChecks=Ve.addStickyFlag=Ve.addStartOfInput=Ve.findUnreachablePatterns=Ve.findModesThatDoNotExist=Ve.findInvalidGroupType=Ve.findDuplicatePatterns=Ve.findUnsupportedFlags=Ve.findStartOfInputAnchor=Ve.findEmptyMatchRegExps=Ve.findEndOfInputAnchor=Ve.findInvalidPatterns=Ve.findMissingPatterns=Ve.validatePatterns=Ve.analyzeTokenTypes=Ve.enableSticky=Ve.disableSticky=Ve.SUPPORT_STICKY=Ve.MODES=Ve.DEFAULT_MODE=void 0;var pY=UI(),ir=gd(),xe=Gt(),Hg=fY(),dY=GI(),So="PATTERN";Ve.DEFAULT_MODE="defaultMode";Ve.MODES="modes";Ve.SUPPORT_STICKY=typeof new RegExp("(?:)").sticky=="boolean";function Ome(){Ve.SUPPORT_STICKY=!1}Ve.disableSticky=Ome;function Mme(){Ve.SUPPORT_STICKY=!0}Ve.enableSticky=Mme;function Kme(r,e){e=(0,xe.defaults)(e,{useSticky:Ve.SUPPORT_STICKY,debug:!1,safeMode:!1,positionTracking:"full",lineTerminatorCharacters:["\r",` -`],tracer:function(v,D){return D()}});var t=e.tracer;t("initCharCodeToOptimizedIndexMap",function(){Vme()});var i;t("Reject Lexer.NA",function(){i=(0,xe.reject)(r,function(v){return v[So]===ir.Lexer.NA})});var n=!1,s;t("Transform Patterns",function(){n=!1,s=(0,xe.map)(i,function(v){var D=v[So];if((0,xe.isRegExp)(D)){var L=D.source;return L.length===1&&L!=="^"&&L!=="$"&&L!=="."&&!D.ignoreCase?L:L.length===2&&L[0]==="\\"&&!(0,xe.contains)(["d","D","s","S","t","r","n","t","0","c","b","B","f","v","w","W"],L[1])?L[1]:e.useSticky?Iv(D):Ev(D)}else{if((0,xe.isFunction)(D))return n=!0,{exec:D};if((0,xe.has)(D,"exec"))return n=!0,D;if(typeof D=="string"){if(D.length===1)return D;var H=D.replace(/[\\^$.*+?()[\]{}|]/g,"\\$&"),j=new RegExp(H);return e.useSticky?Iv(j):Ev(j)}else throw Error("non exhaustive match")}})});var o,a,l,c,u;t("misc mapping",function(){o=(0,xe.map)(i,function(v){return v.tokenTypeIdx}),a=(0,xe.map)(i,function(v){var D=v.GROUP;if(D!==ir.Lexer.SKIPPED){if((0,xe.isString)(D))return D;if((0,xe.isUndefined)(D))return!1;throw Error("non exhaustive match")}}),l=(0,xe.map)(i,function(v){var D=v.LONGER_ALT;if(D){var L=(0,xe.isArray)(D)?(0,xe.map)(D,function(H){return(0,xe.indexOf)(i,H)}):[(0,xe.indexOf)(i,D)];return L}}),c=(0,xe.map)(i,function(v){return v.PUSH_MODE}),u=(0,xe.map)(i,function(v){return(0,xe.has)(v,"POP_MODE")})});var g;t("Line Terminator Handling",function(){var v=DY(e.lineTerminatorCharacters);g=(0,xe.map)(i,function(D){return!1}),e.positionTracking!=="onlyOffset"&&(g=(0,xe.map)(i,function(D){if((0,xe.has)(D,"LINE_BREAKS"))return D.LINE_BREAKS;if(xY(D,v)===!1)return(0,Hg.canMatchCharCode)(v,D.PATTERN)}))});var f,h,p,C;t("Misc Mapping #2",function(){f=(0,xe.map)(i,wv),h=(0,xe.map)(s,vY),p=(0,xe.reduce)(i,function(v,D){var L=D.GROUP;return(0,xe.isString)(L)&&L!==ir.Lexer.SKIPPED&&(v[L]=[]),v},{}),C=(0,xe.map)(s,function(v,D){return{pattern:s[D],longerAlt:l[D],canLineTerminator:g[D],isCustom:f[D],short:h[D],group:a[D],push:c[D],pop:u[D],tokenTypeIdx:o[D],tokenType:i[D]}})});var y=!0,B=[];return e.safeMode||t("First Char Optimization",function(){B=(0,xe.reduce)(i,function(v,D,L){if(typeof D.PATTERN=="string"){var H=D.PATTERN.charCodeAt(0),j=yv(H);mv(v,j,C[L])}else if((0,xe.isArray)(D.START_CHARS_HINT)){var $;(0,xe.forEach)(D.START_CHARS_HINT,function(W){var Z=typeof W=="string"?W.charCodeAt(0):W,A=yv(Z);$!==A&&($=A,mv(v,A,C[L]))})}else if((0,xe.isRegExp)(D.PATTERN))if(D.PATTERN.unicode)y=!1,e.ensureOptimizations&&(0,xe.PRINT_ERROR)(""+Hg.failedOptimizationPrefixMsg+(" Unable to analyze < "+D.PATTERN.toString()+` > pattern. -`)+` The regexp unicode flag is not currently supported by the regexp-to-ast library. - This will disable the lexer's first char optimizations. - For details See: https://chevrotain.io/docs/guide/resolving_lexer_errors.html#UNICODE_OPTIMIZE`);else{var V=(0,Hg.getOptimizedStartCodesIndices)(D.PATTERN,e.ensureOptimizations);(0,xe.isEmpty)(V)&&(y=!1),(0,xe.forEach)(V,function(W){mv(v,W,C[L])})}else e.ensureOptimizations&&(0,xe.PRINT_ERROR)(""+Hg.failedOptimizationPrefixMsg+(" TokenType: <"+D.name+`> is using a custom token pattern without providing parameter. -`)+` This will disable the lexer's first char optimizations. - For details See: https://chevrotain.io/docs/guide/resolving_lexer_errors.html#CUSTOM_OPTIMIZE`),y=!1;return v},[])}),t("ArrayPacking",function(){B=(0,xe.packArray)(B)}),{emptyGroups:p,patternIdxToConfig:C,charCodeToPatternIdxToConfig:B,hasCustom:n,canBeOptimized:y}}Ve.analyzeTokenTypes=Kme;function Ume(r,e){var t=[],i=CY(r);t=t.concat(i.errors);var n=mY(i.valid),s=n.valid;return t=t.concat(n.errors),t=t.concat(Hme(s)),t=t.concat(QY(s)),t=t.concat(bY(s,e)),t=t.concat(SY(s)),t}Ve.validatePatterns=Ume;function Hme(r){var e=[],t=(0,xe.filter)(r,function(i){return(0,xe.isRegExp)(i[So])});return e=e.concat(EY(t)),e=e.concat(yY(t)),e=e.concat(wY(t)),e=e.concat(BY(t)),e=e.concat(IY(t)),e}function CY(r){var e=(0,xe.filter)(r,function(n){return!(0,xe.has)(n,So)}),t=(0,xe.map)(e,function(n){return{message:"Token Type: ->"+n.name+"<- missing static 'PATTERN' property",type:ir.LexerDefinitionErrorType.MISSING_PATTERN,tokenTypes:[n]}}),i=(0,xe.difference)(r,e);return{errors:t,valid:i}}Ve.findMissingPatterns=CY;function mY(r){var e=(0,xe.filter)(r,function(n){var s=n[So];return!(0,xe.isRegExp)(s)&&!(0,xe.isFunction)(s)&&!(0,xe.has)(s,"exec")&&!(0,xe.isString)(s)}),t=(0,xe.map)(e,function(n){return{message:"Token Type: ->"+n.name+"<- static 'PATTERN' can only be a RegExp, a Function matching the {CustomPatternMatcherFunc} type or an Object matching the {ICustomPattern} interface.",type:ir.LexerDefinitionErrorType.INVALID_PATTERN,tokenTypes:[n]}}),i=(0,xe.difference)(r,e);return{errors:t,valid:i}}Ve.findInvalidPatterns=mY;var Gme=/[^\\][\$]/;function EY(r){var e=function(n){hY(s,n);function s(){var o=n!==null&&n.apply(this,arguments)||this;return o.found=!1,o}return s.prototype.visitEndAnchor=function(o){this.found=!0},s}(pY.BaseRegExpVisitor),t=(0,xe.filter)(r,function(n){var s=n[So];try{var o=(0,dY.getRegExpAst)(s),a=new e;return a.visit(o),a.found}catch{return Gme.test(s.source)}}),i=(0,xe.map)(t,function(n){return{message:`Unexpected RegExp Anchor Error: - Token Type: ->`+n.name+`<- static 'PATTERN' cannot contain end of input anchor '$' - See chevrotain.io/docs/guide/resolving_lexer_errors.html#ANCHORS for details.`,type:ir.LexerDefinitionErrorType.EOI_ANCHOR_FOUND,tokenTypes:[n]}});return i}Ve.findEndOfInputAnchor=EY;function IY(r){var e=(0,xe.filter)(r,function(i){var n=i[So];return n.test("")}),t=(0,xe.map)(e,function(i){return{message:"Token Type: ->"+i.name+"<- static 'PATTERN' must not match an empty string",type:ir.LexerDefinitionErrorType.EMPTY_MATCH_PATTERN,tokenTypes:[i]}});return t}Ve.findEmptyMatchRegExps=IY;var Yme=/[^\\[][\^]|^\^/;function yY(r){var e=function(n){hY(s,n);function s(){var o=n!==null&&n.apply(this,arguments)||this;return o.found=!1,o}return s.prototype.visitStartAnchor=function(o){this.found=!0},s}(pY.BaseRegExpVisitor),t=(0,xe.filter)(r,function(n){var s=n[So];try{var o=(0,dY.getRegExpAst)(s),a=new e;return a.visit(o),a.found}catch{return Yme.test(s.source)}}),i=(0,xe.map)(t,function(n){return{message:`Unexpected RegExp Anchor Error: - Token Type: ->`+n.name+`<- static 'PATTERN' cannot contain start of input anchor '^' - See https://chevrotain.io/docs/guide/resolving_lexer_errors.html#ANCHORS for details.`,type:ir.LexerDefinitionErrorType.SOI_ANCHOR_FOUND,tokenTypes:[n]}});return i}Ve.findStartOfInputAnchor=yY;function wY(r){var e=(0,xe.filter)(r,function(i){var n=i[So];return n instanceof RegExp&&(n.multiline||n.global)}),t=(0,xe.map)(e,function(i){return{message:"Token Type: ->"+i.name+"<- static 'PATTERN' may NOT contain global('g') or multiline('m')",type:ir.LexerDefinitionErrorType.UNSUPPORTED_FLAGS_FOUND,tokenTypes:[i]}});return t}Ve.findUnsupportedFlags=wY;function BY(r){var e=[],t=(0,xe.map)(r,function(s){return(0,xe.reduce)(r,function(o,a){return s.PATTERN.source===a.PATTERN.source&&!(0,xe.contains)(e,a)&&a.PATTERN!==ir.Lexer.NA&&(e.push(a),o.push(a)),o},[])});t=(0,xe.compact)(t);var i=(0,xe.filter)(t,function(s){return s.length>1}),n=(0,xe.map)(i,function(s){var o=(0,xe.map)(s,function(l){return l.name}),a=(0,xe.first)(s).PATTERN;return{message:"The same RegExp pattern ->"+a+"<-"+("has been used in all of the following Token Types: "+o.join(", ")+" <-"),type:ir.LexerDefinitionErrorType.DUPLICATE_PATTERNS_FOUND,tokenTypes:s}});return n}Ve.findDuplicatePatterns=BY;function QY(r){var e=(0,xe.filter)(r,function(i){if(!(0,xe.has)(i,"GROUP"))return!1;var n=i.GROUP;return n!==ir.Lexer.SKIPPED&&n!==ir.Lexer.NA&&!(0,xe.isString)(n)}),t=(0,xe.map)(e,function(i){return{message:"Token Type: ->"+i.name+"<- static 'GROUP' can only be Lexer.SKIPPED/Lexer.NA/A String",type:ir.LexerDefinitionErrorType.INVALID_GROUP_TYPE_FOUND,tokenTypes:[i]}});return t}Ve.findInvalidGroupType=QY;function bY(r,e){var t=(0,xe.filter)(r,function(n){return n.PUSH_MODE!==void 0&&!(0,xe.contains)(e,n.PUSH_MODE)}),i=(0,xe.map)(t,function(n){var s="Token Type: ->"+n.name+"<- static 'PUSH_MODE' value cannot refer to a Lexer Mode ->"+n.PUSH_MODE+"<-which does not exist";return{message:s,type:ir.LexerDefinitionErrorType.PUSH_MODE_DOES_NOT_EXIST,tokenTypes:[n]}});return i}Ve.findModesThatDoNotExist=bY;function SY(r){var e=[],t=(0,xe.reduce)(r,function(i,n,s){var o=n.PATTERN;return o===ir.Lexer.NA||((0,xe.isString)(o)?i.push({str:o,idx:s,tokenType:n}):(0,xe.isRegExp)(o)&&qme(o)&&i.push({str:o.source,idx:s,tokenType:n})),i},[]);return(0,xe.forEach)(r,function(i,n){(0,xe.forEach)(t,function(s){var o=s.str,a=s.idx,l=s.tokenType;if(n"+i.name+"<-")+`in the lexer's definition. -See https://chevrotain.io/docs/guide/resolving_lexer_errors.html#UNREACHABLE`;e.push({message:c,type:ir.LexerDefinitionErrorType.UNREACHABLE_PATTERN,tokenTypes:[i,l]})}})}),e}Ve.findUnreachablePatterns=SY;function jme(r,e){if((0,xe.isRegExp)(e)){var t=e.exec(r);return t!==null&&t.index===0}else{if((0,xe.isFunction)(e))return e(r,0,[],{});if((0,xe.has)(e,"exec"))return e.exec(r,0,[],{});if(typeof e=="string")return e===r;throw Error("non exhaustive match")}}function qme(r){var e=[".","\\","[","]","|","^","$","(",")","?","*","+","{"];return(0,xe.find)(e,function(t){return r.source.indexOf(t)!==-1})===void 0}function Ev(r){var e=r.ignoreCase?"i":"";return new RegExp("^(?:"+r.source+")",e)}Ve.addStartOfInput=Ev;function Iv(r){var e=r.ignoreCase?"iy":"y";return new RegExp(""+r.source,e)}Ve.addStickyFlag=Iv;function Jme(r,e,t){var i=[];return(0,xe.has)(r,Ve.DEFAULT_MODE)||i.push({message:"A MultiMode Lexer cannot be initialized without a <"+Ve.DEFAULT_MODE+`> property in its definition -`,type:ir.LexerDefinitionErrorType.MULTI_MODE_LEXER_WITHOUT_DEFAULT_MODE}),(0,xe.has)(r,Ve.MODES)||i.push({message:"A MultiMode Lexer cannot be initialized without a <"+Ve.MODES+`> property in its definition -`,type:ir.LexerDefinitionErrorType.MULTI_MODE_LEXER_WITHOUT_MODES_PROPERTY}),(0,xe.has)(r,Ve.MODES)&&(0,xe.has)(r,Ve.DEFAULT_MODE)&&!(0,xe.has)(r.modes,r.defaultMode)&&i.push({message:"A MultiMode Lexer cannot be initialized with a "+Ve.DEFAULT_MODE+": <"+r.defaultMode+`>which does not exist -`,type:ir.LexerDefinitionErrorType.MULTI_MODE_LEXER_DEFAULT_MODE_VALUE_DOES_NOT_EXIST}),(0,xe.has)(r,Ve.MODES)&&(0,xe.forEach)(r.modes,function(n,s){(0,xe.forEach)(n,function(o,a){(0,xe.isUndefined)(o)&&i.push({message:"A Lexer cannot be initialized using an undefined Token Type. Mode:"+("<"+s+"> at index: <"+a+`> -`),type:ir.LexerDefinitionErrorType.LEXER_DEFINITION_CANNOT_CONTAIN_UNDEFINED})})}),i}Ve.performRuntimeChecks=Jme;function Wme(r,e,t){var i=[],n=!1,s=(0,xe.compact)((0,xe.flatten)((0,xe.mapValues)(r.modes,function(l){return l}))),o=(0,xe.reject)(s,function(l){return l[So]===ir.Lexer.NA}),a=DY(t);return e&&(0,xe.forEach)(o,function(l){var c=xY(l,a);if(c!==!1){var u=PY(l,c),g={message:u,type:c.issue,tokenType:l};i.push(g)}else(0,xe.has)(l,"LINE_BREAKS")?l.LINE_BREAKS===!0&&(n=!0):(0,Hg.canMatchCharCode)(a,l.PATTERN)&&(n=!0)}),e&&!n&&i.push({message:`Warning: No LINE_BREAKS Found. - This Lexer has been defined to track line and column information, - But none of the Token Types can be identified as matching a line terminator. - See https://chevrotain.io/docs/guide/resolving_lexer_errors.html#LINE_BREAKS - for details.`,type:ir.LexerDefinitionErrorType.NO_LINE_BREAKS_FLAGS}),i}Ve.performWarningRuntimeChecks=Wme;function zme(r){var e={},t=(0,xe.keys)(r);return(0,xe.forEach)(t,function(i){var n=r[i];if((0,xe.isArray)(n))e[i]=[];else throw Error("non exhaustive match")}),e}Ve.cloneEmptyGroups=zme;function wv(r){var e=r.PATTERN;if((0,xe.isRegExp)(e))return!1;if((0,xe.isFunction)(e))return!0;if((0,xe.has)(e,"exec"))return!0;if((0,xe.isString)(e))return!1;throw Error("non exhaustive match")}Ve.isCustomPattern=wv;function vY(r){return(0,xe.isString)(r)&&r.length===1?r.charCodeAt(0):!1}Ve.isShortPattern=vY;Ve.LineTerminatorOptimizedTester={test:function(r){for(var e=r.length,t=this.lastIndex;t Token Type -`)+(" Root cause: "+e.errMsg+`. -`)+" For details See: https://chevrotain.io/docs/guide/resolving_lexer_errors.html#IDENTIFY_TERMINATOR";if(e.issue===ir.LexerDefinitionErrorType.CUSTOM_LINE_BREAK)return`Warning: A Custom Token Pattern should specify the option. -`+(" The problem is in the <"+r.name+`> Token Type -`)+" For details See: https://chevrotain.io/docs/guide/resolving_lexer_errors.html#CUSTOM_LINE_BREAK";throw Error("non exhaustive match")}Ve.buildLineBreakIssueMessage=PY;function DY(r){var e=(0,xe.map)(r,function(t){return(0,xe.isString)(t)&&t.length>0?t.charCodeAt(0):t});return e}function mv(r,e,t){r[e]===void 0?r[e]=[t]:r[e].push(t)}Ve.minOptimizationVal=256;var qI=[];function yv(r){return r255?255+~~(r/255):r}}});var Gg=w(Nt=>{"use strict";Object.defineProperty(Nt,"__esModule",{value:!0});Nt.isTokenType=Nt.hasExtendingTokensTypesMapProperty=Nt.hasExtendingTokensTypesProperty=Nt.hasCategoriesProperty=Nt.hasShortKeyProperty=Nt.singleAssignCategoriesToksMap=Nt.assignCategoriesMapProp=Nt.assignCategoriesTokensProp=Nt.assignTokenDefaultProps=Nt.expandCategories=Nt.augmentTokenTypes=Nt.tokenIdxToClass=Nt.tokenShortNameIdx=Nt.tokenStructuredMatcherNoCategories=Nt.tokenStructuredMatcher=void 0;var _r=Gt();function Xme(r,e){var t=r.tokenTypeIdx;return t===e.tokenTypeIdx?!0:e.isParent===!0&&e.categoryMatchesMap[t]===!0}Nt.tokenStructuredMatcher=Xme;function _me(r,e){return r.tokenTypeIdx===e.tokenTypeIdx}Nt.tokenStructuredMatcherNoCategories=_me;Nt.tokenShortNameIdx=1;Nt.tokenIdxToClass={};function Zme(r){var e=kY(r);RY(e),NY(e),FY(e),(0,_r.forEach)(e,function(t){t.isParent=t.categoryMatches.length>0})}Nt.augmentTokenTypes=Zme;function kY(r){for(var e=(0,_r.cloneArr)(r),t=r,i=!0;i;){t=(0,_r.compact)((0,_r.flatten)((0,_r.map)(t,function(s){return s.CATEGORIES})));var n=(0,_r.difference)(t,e);e=e.concat(n),(0,_r.isEmpty)(n)?i=!1:t=n}return e}Nt.expandCategories=kY;function RY(r){(0,_r.forEach)(r,function(e){LY(e)||(Nt.tokenIdxToClass[Nt.tokenShortNameIdx]=e,e.tokenTypeIdx=Nt.tokenShortNameIdx++),Bv(e)&&!(0,_r.isArray)(e.CATEGORIES)&&(e.CATEGORIES=[e.CATEGORIES]),Bv(e)||(e.CATEGORIES=[]),TY(e)||(e.categoryMatches=[]),OY(e)||(e.categoryMatchesMap={})})}Nt.assignTokenDefaultProps=RY;function FY(r){(0,_r.forEach)(r,function(e){e.categoryMatches=[],(0,_r.forEach)(e.categoryMatchesMap,function(t,i){e.categoryMatches.push(Nt.tokenIdxToClass[i].tokenTypeIdx)})})}Nt.assignCategoriesTokensProp=FY;function NY(r){(0,_r.forEach)(r,function(e){Qv([],e)})}Nt.assignCategoriesMapProp=NY;function Qv(r,e){(0,_r.forEach)(r,function(t){e.categoryMatchesMap[t.tokenTypeIdx]=!0}),(0,_r.forEach)(e.CATEGORIES,function(t){var i=r.concat(e);(0,_r.contains)(i,t)||Qv(i,t)})}Nt.singleAssignCategoriesToksMap=Qv;function LY(r){return(0,_r.has)(r,"tokenTypeIdx")}Nt.hasShortKeyProperty=LY;function Bv(r){return(0,_r.has)(r,"CATEGORIES")}Nt.hasCategoriesProperty=Bv;function TY(r){return(0,_r.has)(r,"categoryMatches")}Nt.hasExtendingTokensTypesProperty=TY;function OY(r){return(0,_r.has)(r,"categoryMatchesMap")}Nt.hasExtendingTokensTypesMapProperty=OY;function $me(r){return(0,_r.has)(r,"tokenTypeIdx")}Nt.isTokenType=$me});var bv=w(JI=>{"use strict";Object.defineProperty(JI,"__esModule",{value:!0});JI.defaultLexerErrorProvider=void 0;JI.defaultLexerErrorProvider={buildUnableToPopLexerModeMessage:function(r){return"Unable to pop Lexer Mode after encountering Token ->"+r.image+"<- The Mode Stack is empty"},buildUnexpectedCharactersMessage:function(r,e,t,i,n){return"unexpected character: ->"+r.charAt(e)+"<- at offset: "+e+","+(" skipped "+t+" characters.")}}});var gd=w(nc=>{"use strict";Object.defineProperty(nc,"__esModule",{value:!0});nc.Lexer=nc.LexerDefinitionErrorType=void 0;var zs=Cv(),nr=Gt(),eEe=Gg(),tEe=bv(),rEe=GI(),iEe;(function(r){r[r.MISSING_PATTERN=0]="MISSING_PATTERN",r[r.INVALID_PATTERN=1]="INVALID_PATTERN",r[r.EOI_ANCHOR_FOUND=2]="EOI_ANCHOR_FOUND",r[r.UNSUPPORTED_FLAGS_FOUND=3]="UNSUPPORTED_FLAGS_FOUND",r[r.DUPLICATE_PATTERNS_FOUND=4]="DUPLICATE_PATTERNS_FOUND",r[r.INVALID_GROUP_TYPE_FOUND=5]="INVALID_GROUP_TYPE_FOUND",r[r.PUSH_MODE_DOES_NOT_EXIST=6]="PUSH_MODE_DOES_NOT_EXIST",r[r.MULTI_MODE_LEXER_WITHOUT_DEFAULT_MODE=7]="MULTI_MODE_LEXER_WITHOUT_DEFAULT_MODE",r[r.MULTI_MODE_LEXER_WITHOUT_MODES_PROPERTY=8]="MULTI_MODE_LEXER_WITHOUT_MODES_PROPERTY",r[r.MULTI_MODE_LEXER_DEFAULT_MODE_VALUE_DOES_NOT_EXIST=9]="MULTI_MODE_LEXER_DEFAULT_MODE_VALUE_DOES_NOT_EXIST",r[r.LEXER_DEFINITION_CANNOT_CONTAIN_UNDEFINED=10]="LEXER_DEFINITION_CANNOT_CONTAIN_UNDEFINED",r[r.SOI_ANCHOR_FOUND=11]="SOI_ANCHOR_FOUND",r[r.EMPTY_MATCH_PATTERN=12]="EMPTY_MATCH_PATTERN",r[r.NO_LINE_BREAKS_FLAGS=13]="NO_LINE_BREAKS_FLAGS",r[r.UNREACHABLE_PATTERN=14]="UNREACHABLE_PATTERN",r[r.IDENTIFY_TERMINATOR=15]="IDENTIFY_TERMINATOR",r[r.CUSTOM_LINE_BREAK=16]="CUSTOM_LINE_BREAK"})(iEe=nc.LexerDefinitionErrorType||(nc.LexerDefinitionErrorType={}));var fd={deferDefinitionErrorsHandling:!1,positionTracking:"full",lineTerminatorsPattern:/\n|\r\n?/g,lineTerminatorCharacters:[` -`,"\r"],ensureOptimizations:!1,safeMode:!1,errorMessageProvider:tEe.defaultLexerErrorProvider,traceInitPerf:!1,skipValidations:!1};Object.freeze(fd);var nEe=function(){function r(e,t){var i=this;if(t===void 0&&(t=fd),this.lexerDefinition=e,this.lexerDefinitionErrors=[],this.lexerDefinitionWarning=[],this.patternIdxToConfig={},this.charCodeToPatternIdxToConfig={},this.modes=[],this.emptyGroups={},this.config=void 0,this.trackStartLines=!0,this.trackEndLines=!0,this.hasCustom=!1,this.canModeBeOptimized={},typeof t=="boolean")throw Error(`The second argument to the Lexer constructor is now an ILexerConfig Object. -a boolean 2nd argument is no longer supported`);this.config=(0,nr.merge)(fd,t);var n=this.config.traceInitPerf;n===!0?(this.traceInitMaxIdent=1/0,this.traceInitPerf=!0):typeof n=="number"&&(this.traceInitMaxIdent=n,this.traceInitPerf=!0),this.traceInitIndent=-1,this.TRACE_INIT("Lexer Constructor",function(){var s,o=!0;i.TRACE_INIT("Lexer Config handling",function(){if(i.config.lineTerminatorsPattern===fd.lineTerminatorsPattern)i.config.lineTerminatorsPattern=zs.LineTerminatorOptimizedTester;else if(i.config.lineTerminatorCharacters===fd.lineTerminatorCharacters)throw Error(`Error: Missing property on the Lexer config. - For details See: https://chevrotain.io/docs/guide/resolving_lexer_errors.html#MISSING_LINE_TERM_CHARS`);if(t.safeMode&&t.ensureOptimizations)throw Error('"safeMode" and "ensureOptimizations" flags are mutually exclusive.');i.trackStartLines=/full|onlyStart/i.test(i.config.positionTracking),i.trackEndLines=/full/i.test(i.config.positionTracking),(0,nr.isArray)(e)?(s={modes:{}},s.modes[zs.DEFAULT_MODE]=(0,nr.cloneArr)(e),s[zs.DEFAULT_MODE]=zs.DEFAULT_MODE):(o=!1,s=(0,nr.cloneObj)(e))}),i.config.skipValidations===!1&&(i.TRACE_INIT("performRuntimeChecks",function(){i.lexerDefinitionErrors=i.lexerDefinitionErrors.concat((0,zs.performRuntimeChecks)(s,i.trackStartLines,i.config.lineTerminatorCharacters))}),i.TRACE_INIT("performWarningRuntimeChecks",function(){i.lexerDefinitionWarning=i.lexerDefinitionWarning.concat((0,zs.performWarningRuntimeChecks)(s,i.trackStartLines,i.config.lineTerminatorCharacters))})),s.modes=s.modes?s.modes:{},(0,nr.forEach)(s.modes,function(u,g){s.modes[g]=(0,nr.reject)(u,function(f){return(0,nr.isUndefined)(f)})});var a=(0,nr.keys)(s.modes);if((0,nr.forEach)(s.modes,function(u,g){i.TRACE_INIT("Mode: <"+g+"> processing",function(){if(i.modes.push(g),i.config.skipValidations===!1&&i.TRACE_INIT("validatePatterns",function(){i.lexerDefinitionErrors=i.lexerDefinitionErrors.concat((0,zs.validatePatterns)(u,a))}),(0,nr.isEmpty)(i.lexerDefinitionErrors)){(0,eEe.augmentTokenTypes)(u);var f;i.TRACE_INIT("analyzeTokenTypes",function(){f=(0,zs.analyzeTokenTypes)(u,{lineTerminatorCharacters:i.config.lineTerminatorCharacters,positionTracking:t.positionTracking,ensureOptimizations:t.ensureOptimizations,safeMode:t.safeMode,tracer:i.TRACE_INIT.bind(i)})}),i.patternIdxToConfig[g]=f.patternIdxToConfig,i.charCodeToPatternIdxToConfig[g]=f.charCodeToPatternIdxToConfig,i.emptyGroups=(0,nr.merge)(i.emptyGroups,f.emptyGroups),i.hasCustom=f.hasCustom||i.hasCustom,i.canModeBeOptimized[g]=f.canBeOptimized}})}),i.defaultMode=s.defaultMode,!(0,nr.isEmpty)(i.lexerDefinitionErrors)&&!i.config.deferDefinitionErrorsHandling){var l=(0,nr.map)(i.lexerDefinitionErrors,function(u){return u.message}),c=l.join(`----------------------- -`);throw new Error(`Errors detected in definition of Lexer: -`+c)}(0,nr.forEach)(i.lexerDefinitionWarning,function(u){(0,nr.PRINT_WARNING)(u.message)}),i.TRACE_INIT("Choosing sub-methods implementations",function(){if(zs.SUPPORT_STICKY?(i.chopInput=nr.IDENTITY,i.match=i.matchWithTest):(i.updateLastIndex=nr.NOOP,i.match=i.matchWithExec),o&&(i.handleModes=nr.NOOP),i.trackStartLines===!1&&(i.computeNewColumn=nr.IDENTITY),i.trackEndLines===!1&&(i.updateTokenEndLineColumnLocation=nr.NOOP),/full/i.test(i.config.positionTracking))i.createTokenInstance=i.createFullToken;else if(/onlyStart/i.test(i.config.positionTracking))i.createTokenInstance=i.createStartOnlyToken;else if(/onlyOffset/i.test(i.config.positionTracking))i.createTokenInstance=i.createOffsetOnlyToken;else throw Error('Invalid config option: "'+i.config.positionTracking+'"');i.hasCustom?(i.addToken=i.addTokenUsingPush,i.handlePayload=i.handlePayloadWithCustom):(i.addToken=i.addTokenUsingMemberAccess,i.handlePayload=i.handlePayloadNoCustom)}),i.TRACE_INIT("Failed Optimization Warnings",function(){var u=(0,nr.reduce)(i.canModeBeOptimized,function(g,f,h){return f===!1&&g.push(h),g},[]);if(t.ensureOptimizations&&!(0,nr.isEmpty)(u))throw Error("Lexer Modes: < "+u.join(", ")+` > cannot be optimized. - Disable the "ensureOptimizations" lexer config flag to silently ignore this and run the lexer in an un-optimized mode. - Or inspect the console log for details on how to resolve these issues.`)}),i.TRACE_INIT("clearRegExpParserCache",function(){(0,rEe.clearRegExpParserCache)()}),i.TRACE_INIT("toFastProperties",function(){(0,nr.toFastProperties)(i)})})}return r.prototype.tokenize=function(e,t){if(t===void 0&&(t=this.defaultMode),!(0,nr.isEmpty)(this.lexerDefinitionErrors)){var i=(0,nr.map)(this.lexerDefinitionErrors,function(o){return o.message}),n=i.join(`----------------------- -`);throw new Error(`Unable to Tokenize because Errors detected in definition of Lexer: -`+n)}var s=this.tokenizeInternal(e,t);return s},r.prototype.tokenizeInternal=function(e,t){var i=this,n,s,o,a,l,c,u,g,f,h,p,C,y,B,v,D,L=e,H=L.length,j=0,$=0,V=this.hasCustom?0:Math.floor(e.length/10),W=new Array(V),Z=[],A=this.trackStartLines?1:void 0,ae=this.trackStartLines?1:void 0,ge=(0,zs.cloneEmptyGroups)(this.emptyGroups),re=this.trackStartLines,O=this.config.lineTerminatorsPattern,F=0,ue=[],he=[],ke=[],Fe=[];Object.freeze(Fe);var Ne=void 0;function oe(){return ue}function le(pr){var Ei=(0,zs.charCodeToOptimizedIndex)(pr),_n=he[Ei];return _n===void 0?Fe:_n}var we=function(pr){if(ke.length===1&&pr.tokenType.PUSH_MODE===void 0){var Ei=i.config.errorMessageProvider.buildUnableToPopLexerModeMessage(pr);Z.push({offset:pr.startOffset,line:pr.startLine!==void 0?pr.startLine:void 0,column:pr.startColumn!==void 0?pr.startColumn:void 0,length:pr.image.length,message:Ei})}else{ke.pop();var _n=(0,nr.last)(ke);ue=i.patternIdxToConfig[_n],he=i.charCodeToPatternIdxToConfig[_n],F=ue.length;var oa=i.canModeBeOptimized[_n]&&i.config.safeMode===!1;he&&oa?Ne=le:Ne=oe}};function fe(pr){ke.push(pr),he=this.charCodeToPatternIdxToConfig[pr],ue=this.patternIdxToConfig[pr],F=ue.length,F=ue.length;var Ei=this.canModeBeOptimized[pr]&&this.config.safeMode===!1;he&&Ei?Ne=le:Ne=oe}fe.call(this,t);for(var Ae;jc.length){c=a,u=g,Ae=tt;break}}}break}}if(c!==null){if(f=c.length,h=Ae.group,h!==void 0&&(p=Ae.tokenTypeIdx,C=this.createTokenInstance(c,j,p,Ae.tokenType,A,ae,f),this.handlePayload(C,u),h===!1?$=this.addToken(W,$,C):ge[h].push(C)),e=this.chopInput(e,f),j=j+f,ae=this.computeNewColumn(ae,f),re===!0&&Ae.canLineTerminator===!0){var It=0,Or=void 0,ii=void 0;O.lastIndex=0;do Or=O.test(c),Or===!0&&(ii=O.lastIndex-1,It++);while(Or===!0);It!==0&&(A=A+It,ae=f-ii,this.updateTokenEndLineColumnLocation(C,h,ii,It,A,ae,f))}this.handleModes(Ae,we,fe,C)}else{for(var gi=j,hr=A,fi=ae,ni=!1;!ni&&j <"+e+">");var n=(0,nr.timer)(t),s=n.time,o=n.value,a=s>10?console.warn:console.log;return this.traceInitIndent time: "+s+"ms"),this.traceInitIndent--,o}else return t()},r.SKIPPED="This marks a skipped Token pattern, this means each token identified by it willbe consumed and then thrown into oblivion, this can be used to for example to completely ignore whitespace.",r.NA=/NOT_APPLICABLE/,r}();nc.Lexer=nEe});var SA=w(Qi=>{"use strict";Object.defineProperty(Qi,"__esModule",{value:!0});Qi.tokenMatcher=Qi.createTokenInstance=Qi.EOF=Qi.createToken=Qi.hasTokenLabel=Qi.tokenName=Qi.tokenLabel=void 0;var Vs=Gt(),sEe=gd(),Sv=Gg();function oEe(r){return JY(r)?r.LABEL:r.name}Qi.tokenLabel=oEe;function aEe(r){return r.name}Qi.tokenName=aEe;function JY(r){return(0,Vs.isString)(r.LABEL)&&r.LABEL!==""}Qi.hasTokenLabel=JY;var AEe="parent",MY="categories",KY="label",UY="group",HY="push_mode",GY="pop_mode",YY="longer_alt",jY="line_breaks",qY="start_chars_hint";function WY(r){return lEe(r)}Qi.createToken=WY;function lEe(r){var e=r.pattern,t={};if(t.name=r.name,(0,Vs.isUndefined)(e)||(t.PATTERN=e),(0,Vs.has)(r,AEe))throw`The parent property is no longer supported. -See: https://github.com/chevrotain/chevrotain/issues/564#issuecomment-349062346 for details.`;return(0,Vs.has)(r,MY)&&(t.CATEGORIES=r[MY]),(0,Sv.augmentTokenTypes)([t]),(0,Vs.has)(r,KY)&&(t.LABEL=r[KY]),(0,Vs.has)(r,UY)&&(t.GROUP=r[UY]),(0,Vs.has)(r,GY)&&(t.POP_MODE=r[GY]),(0,Vs.has)(r,HY)&&(t.PUSH_MODE=r[HY]),(0,Vs.has)(r,YY)&&(t.LONGER_ALT=r[YY]),(0,Vs.has)(r,jY)&&(t.LINE_BREAKS=r[jY]),(0,Vs.has)(r,qY)&&(t.START_CHARS_HINT=r[qY]),t}Qi.EOF=WY({name:"EOF",pattern:sEe.Lexer.NA});(0,Sv.augmentTokenTypes)([Qi.EOF]);function cEe(r,e,t,i,n,s,o,a){return{image:e,startOffset:t,endOffset:i,startLine:n,endLine:s,startColumn:o,endColumn:a,tokenTypeIdx:r.tokenTypeIdx,tokenType:r}}Qi.createTokenInstance=cEe;function uEe(r,e){return(0,Sv.tokenStructuredMatcher)(r,e)}Qi.tokenMatcher=uEe});var dn=w(Wt=>{"use strict";var wa=Wt&&Wt.__extends||function(){var r=function(e,t){return r=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(i,n){i.__proto__=n}||function(i,n){for(var s in n)Object.prototype.hasOwnProperty.call(n,s)&&(i[s]=n[s])},r(e,t)};return function(e,t){if(typeof t!="function"&&t!==null)throw new TypeError("Class extends value "+String(t)+" is not a constructor or null");r(e,t);function i(){this.constructor=e}e.prototype=t===null?Object.create(t):(i.prototype=t.prototype,new i)}}();Object.defineProperty(Wt,"__esModule",{value:!0});Wt.serializeProduction=Wt.serializeGrammar=Wt.Terminal=Wt.Alternation=Wt.RepetitionWithSeparator=Wt.Repetition=Wt.RepetitionMandatoryWithSeparator=Wt.RepetitionMandatory=Wt.Option=Wt.Alternative=Wt.Rule=Wt.NonTerminal=Wt.AbstractProduction=void 0;var Ar=Gt(),gEe=SA(),vo=function(){function r(e){this._definition=e}return Object.defineProperty(r.prototype,"definition",{get:function(){return this._definition},set:function(e){this._definition=e},enumerable:!1,configurable:!0}),r.prototype.accept=function(e){e.visit(this),(0,Ar.forEach)(this.definition,function(t){t.accept(e)})},r}();Wt.AbstractProduction=vo;var zY=function(r){wa(e,r);function e(t){var i=r.call(this,[])||this;return i.idx=1,(0,Ar.assign)(i,(0,Ar.pick)(t,function(n){return n!==void 0})),i}return Object.defineProperty(e.prototype,"definition",{get:function(){return this.referencedRule!==void 0?this.referencedRule.definition:[]},set:function(t){},enumerable:!1,configurable:!0}),e.prototype.accept=function(t){t.visit(this)},e}(vo);Wt.NonTerminal=zY;var VY=function(r){wa(e,r);function e(t){var i=r.call(this,t.definition)||this;return i.orgText="",(0,Ar.assign)(i,(0,Ar.pick)(t,function(n){return n!==void 0})),i}return e}(vo);Wt.Rule=VY;var XY=function(r){wa(e,r);function e(t){var i=r.call(this,t.definition)||this;return i.ignoreAmbiguities=!1,(0,Ar.assign)(i,(0,Ar.pick)(t,function(n){return n!==void 0})),i}return e}(vo);Wt.Alternative=XY;var _Y=function(r){wa(e,r);function e(t){var i=r.call(this,t.definition)||this;return i.idx=1,(0,Ar.assign)(i,(0,Ar.pick)(t,function(n){return n!==void 0})),i}return e}(vo);Wt.Option=_Y;var ZY=function(r){wa(e,r);function e(t){var i=r.call(this,t.definition)||this;return i.idx=1,(0,Ar.assign)(i,(0,Ar.pick)(t,function(n){return n!==void 0})),i}return e}(vo);Wt.RepetitionMandatory=ZY;var $Y=function(r){wa(e,r);function e(t){var i=r.call(this,t.definition)||this;return i.idx=1,(0,Ar.assign)(i,(0,Ar.pick)(t,function(n){return n!==void 0})),i}return e}(vo);Wt.RepetitionMandatoryWithSeparator=$Y;var ej=function(r){wa(e,r);function e(t){var i=r.call(this,t.definition)||this;return i.idx=1,(0,Ar.assign)(i,(0,Ar.pick)(t,function(n){return n!==void 0})),i}return e}(vo);Wt.Repetition=ej;var tj=function(r){wa(e,r);function e(t){var i=r.call(this,t.definition)||this;return i.idx=1,(0,Ar.assign)(i,(0,Ar.pick)(t,function(n){return n!==void 0})),i}return e}(vo);Wt.RepetitionWithSeparator=tj;var rj=function(r){wa(e,r);function e(t){var i=r.call(this,t.definition)||this;return i.idx=1,i.ignoreAmbiguities=!1,i.hasPredicates=!1,(0,Ar.assign)(i,(0,Ar.pick)(t,function(n){return n!==void 0})),i}return Object.defineProperty(e.prototype,"definition",{get:function(){return this._definition},set:function(t){this._definition=t},enumerable:!1,configurable:!0}),e}(vo);Wt.Alternation=rj;var WI=function(){function r(e){this.idx=1,(0,Ar.assign)(this,(0,Ar.pick)(e,function(t){return t!==void 0}))}return r.prototype.accept=function(e){e.visit(this)},r}();Wt.Terminal=WI;function fEe(r){return(0,Ar.map)(r,hd)}Wt.serializeGrammar=fEe;function hd(r){function e(s){return(0,Ar.map)(s,hd)}if(r instanceof zY){var t={type:"NonTerminal",name:r.nonTerminalName,idx:r.idx};return(0,Ar.isString)(r.label)&&(t.label=r.label),t}else{if(r instanceof XY)return{type:"Alternative",definition:e(r.definition)};if(r instanceof _Y)return{type:"Option",idx:r.idx,definition:e(r.definition)};if(r instanceof ZY)return{type:"RepetitionMandatory",idx:r.idx,definition:e(r.definition)};if(r instanceof $Y)return{type:"RepetitionMandatoryWithSeparator",idx:r.idx,separator:hd(new WI({terminalType:r.separator})),definition:e(r.definition)};if(r instanceof tj)return{type:"RepetitionWithSeparator",idx:r.idx,separator:hd(new WI({terminalType:r.separator})),definition:e(r.definition)};if(r instanceof ej)return{type:"Repetition",idx:r.idx,definition:e(r.definition)};if(r instanceof rj)return{type:"Alternation",idx:r.idx,definition:e(r.definition)};if(r instanceof WI){var i={type:"Terminal",name:r.terminalType.name,label:(0,gEe.tokenLabel)(r.terminalType),idx:r.idx};(0,Ar.isString)(r.label)&&(i.terminalLabel=r.label);var n=r.terminalType.PATTERN;return r.terminalType.PATTERN&&(i.pattern=(0,Ar.isRegExp)(n)?n.source:n),i}else{if(r instanceof VY)return{type:"Rule",name:r.name,orgText:r.orgText,definition:e(r.definition)};throw Error("non exhaustive match")}}}Wt.serializeProduction=hd});var VI=w(zI=>{"use strict";Object.defineProperty(zI,"__esModule",{value:!0});zI.RestWalker=void 0;var vv=Gt(),Cn=dn(),hEe=function(){function r(){}return r.prototype.walk=function(e,t){var i=this;t===void 0&&(t=[]),(0,vv.forEach)(e.definition,function(n,s){var o=(0,vv.drop)(e.definition,s+1);if(n instanceof Cn.NonTerminal)i.walkProdRef(n,o,t);else if(n instanceof Cn.Terminal)i.walkTerminal(n,o,t);else if(n instanceof Cn.Alternative)i.walkFlat(n,o,t);else if(n instanceof Cn.Option)i.walkOption(n,o,t);else if(n instanceof Cn.RepetitionMandatory)i.walkAtLeastOne(n,o,t);else if(n instanceof Cn.RepetitionMandatoryWithSeparator)i.walkAtLeastOneSep(n,o,t);else if(n instanceof Cn.RepetitionWithSeparator)i.walkManySep(n,o,t);else if(n instanceof Cn.Repetition)i.walkMany(n,o,t);else if(n instanceof Cn.Alternation)i.walkOr(n,o,t);else throw Error("non exhaustive match")})},r.prototype.walkTerminal=function(e,t,i){},r.prototype.walkProdRef=function(e,t,i){},r.prototype.walkFlat=function(e,t,i){var n=t.concat(i);this.walk(e,n)},r.prototype.walkOption=function(e,t,i){var n=t.concat(i);this.walk(e,n)},r.prototype.walkAtLeastOne=function(e,t,i){var n=[new Cn.Option({definition:e.definition})].concat(t,i);this.walk(e,n)},r.prototype.walkAtLeastOneSep=function(e,t,i){var n=ij(e,t,i);this.walk(e,n)},r.prototype.walkMany=function(e,t,i){var n=[new Cn.Option({definition:e.definition})].concat(t,i);this.walk(e,n)},r.prototype.walkManySep=function(e,t,i){var n=ij(e,t,i);this.walk(e,n)},r.prototype.walkOr=function(e,t,i){var n=this,s=t.concat(i);(0,vv.forEach)(e.definition,function(o){var a=new Cn.Alternative({definition:[o]});n.walk(a,s)})},r}();zI.RestWalker=hEe;function ij(r,e,t){var i=[new Cn.Option({definition:[new Cn.Terminal({terminalType:r.separator})].concat(r.definition)})],n=i.concat(e,t);return n}});var Yg=w(XI=>{"use strict";Object.defineProperty(XI,"__esModule",{value:!0});XI.GAstVisitor=void 0;var xo=dn(),pEe=function(){function r(){}return r.prototype.visit=function(e){var t=e;switch(t.constructor){case xo.NonTerminal:return this.visitNonTerminal(t);case xo.Alternative:return this.visitAlternative(t);case xo.Option:return this.visitOption(t);case xo.RepetitionMandatory:return this.visitRepetitionMandatory(t);case xo.RepetitionMandatoryWithSeparator:return this.visitRepetitionMandatoryWithSeparator(t);case xo.RepetitionWithSeparator:return this.visitRepetitionWithSeparator(t);case xo.Repetition:return this.visitRepetition(t);case xo.Alternation:return this.visitAlternation(t);case xo.Terminal:return this.visitTerminal(t);case xo.Rule:return this.visitRule(t);default:throw Error("non exhaustive match")}},r.prototype.visitNonTerminal=function(e){},r.prototype.visitAlternative=function(e){},r.prototype.visitOption=function(e){},r.prototype.visitRepetition=function(e){},r.prototype.visitRepetitionMandatory=function(e){},r.prototype.visitRepetitionMandatoryWithSeparator=function(e){},r.prototype.visitRepetitionWithSeparator=function(e){},r.prototype.visitAlternation=function(e){},r.prototype.visitTerminal=function(e){},r.prototype.visitRule=function(e){},r}();XI.GAstVisitor=pEe});var dd=w(Oi=>{"use strict";var dEe=Oi&&Oi.__extends||function(){var r=function(e,t){return r=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(i,n){i.__proto__=n}||function(i,n){for(var s in n)Object.prototype.hasOwnProperty.call(n,s)&&(i[s]=n[s])},r(e,t)};return function(e,t){if(typeof t!="function"&&t!==null)throw new TypeError("Class extends value "+String(t)+" is not a constructor or null");r(e,t);function i(){this.constructor=e}e.prototype=t===null?Object.create(t):(i.prototype=t.prototype,new i)}}();Object.defineProperty(Oi,"__esModule",{value:!0});Oi.collectMethods=Oi.DslMethodsCollectorVisitor=Oi.getProductionDslName=Oi.isBranchingProd=Oi.isOptionalProd=Oi.isSequenceProd=void 0;var pd=Gt(),Qr=dn(),CEe=Yg();function mEe(r){return r instanceof Qr.Alternative||r instanceof Qr.Option||r instanceof Qr.Repetition||r instanceof Qr.RepetitionMandatory||r instanceof Qr.RepetitionMandatoryWithSeparator||r instanceof Qr.RepetitionWithSeparator||r instanceof Qr.Terminal||r instanceof Qr.Rule}Oi.isSequenceProd=mEe;function xv(r,e){e===void 0&&(e=[]);var t=r instanceof Qr.Option||r instanceof Qr.Repetition||r instanceof Qr.RepetitionWithSeparator;return t?!0:r instanceof Qr.Alternation?(0,pd.some)(r.definition,function(i){return xv(i,e)}):r instanceof Qr.NonTerminal&&(0,pd.contains)(e,r)?!1:r instanceof Qr.AbstractProduction?(r instanceof Qr.NonTerminal&&e.push(r),(0,pd.every)(r.definition,function(i){return xv(i,e)})):!1}Oi.isOptionalProd=xv;function EEe(r){return r instanceof Qr.Alternation}Oi.isBranchingProd=EEe;function IEe(r){if(r instanceof Qr.NonTerminal)return"SUBRULE";if(r instanceof Qr.Option)return"OPTION";if(r instanceof Qr.Alternation)return"OR";if(r instanceof Qr.RepetitionMandatory)return"AT_LEAST_ONE";if(r instanceof Qr.RepetitionMandatoryWithSeparator)return"AT_LEAST_ONE_SEP";if(r instanceof Qr.RepetitionWithSeparator)return"MANY_SEP";if(r instanceof Qr.Repetition)return"MANY";if(r instanceof Qr.Terminal)return"CONSUME";throw Error("non exhaustive match")}Oi.getProductionDslName=IEe;var nj=function(r){dEe(e,r);function e(){var t=r!==null&&r.apply(this,arguments)||this;return t.separator="-",t.dslMethods={option:[],alternation:[],repetition:[],repetitionWithSeparator:[],repetitionMandatory:[],repetitionMandatoryWithSeparator:[]},t}return e.prototype.reset=function(){this.dslMethods={option:[],alternation:[],repetition:[],repetitionWithSeparator:[],repetitionMandatory:[],repetitionMandatoryWithSeparator:[]}},e.prototype.visitTerminal=function(t){var i=t.terminalType.name+this.separator+"Terminal";(0,pd.has)(this.dslMethods,i)||(this.dslMethods[i]=[]),this.dslMethods[i].push(t)},e.prototype.visitNonTerminal=function(t){var i=t.nonTerminalName+this.separator+"Terminal";(0,pd.has)(this.dslMethods,i)||(this.dslMethods[i]=[]),this.dslMethods[i].push(t)},e.prototype.visitOption=function(t){this.dslMethods.option.push(t)},e.prototype.visitRepetitionWithSeparator=function(t){this.dslMethods.repetitionWithSeparator.push(t)},e.prototype.visitRepetitionMandatory=function(t){this.dslMethods.repetitionMandatory.push(t)},e.prototype.visitRepetitionMandatoryWithSeparator=function(t){this.dslMethods.repetitionMandatoryWithSeparator.push(t)},e.prototype.visitRepetition=function(t){this.dslMethods.repetition.push(t)},e.prototype.visitAlternation=function(t){this.dslMethods.alternation.push(t)},e}(CEe.GAstVisitor);Oi.DslMethodsCollectorVisitor=nj;var _I=new nj;function yEe(r){_I.reset(),r.accept(_I);var e=_I.dslMethods;return _I.reset(),e}Oi.collectMethods=yEe});var Dv=w(Po=>{"use strict";Object.defineProperty(Po,"__esModule",{value:!0});Po.firstForTerminal=Po.firstForBranching=Po.firstForSequence=Po.first=void 0;var ZI=Gt(),sj=dn(),Pv=dd();function $I(r){if(r instanceof sj.NonTerminal)return $I(r.referencedRule);if(r instanceof sj.Terminal)return Aj(r);if((0,Pv.isSequenceProd)(r))return oj(r);if((0,Pv.isBranchingProd)(r))return aj(r);throw Error("non exhaustive match")}Po.first=$I;function oj(r){for(var e=[],t=r.definition,i=0,n=t.length>i,s,o=!0;n&&o;)s=t[i],o=(0,Pv.isOptionalProd)(s),e=e.concat($I(s)),i=i+1,n=t.length>i;return(0,ZI.uniq)(e)}Po.firstForSequence=oj;function aj(r){var e=(0,ZI.map)(r.definition,function(t){return $I(t)});return(0,ZI.uniq)((0,ZI.flatten)(e))}Po.firstForBranching=aj;function Aj(r){return[r.terminalType]}Po.firstForTerminal=Aj});var kv=w(ey=>{"use strict";Object.defineProperty(ey,"__esModule",{value:!0});ey.IN=void 0;ey.IN="_~IN~_"});var fj=w(As=>{"use strict";var wEe=As&&As.__extends||function(){var r=function(e,t){return r=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(i,n){i.__proto__=n}||function(i,n){for(var s in n)Object.prototype.hasOwnProperty.call(n,s)&&(i[s]=n[s])},r(e,t)};return function(e,t){if(typeof t!="function"&&t!==null)throw new TypeError("Class extends value "+String(t)+" is not a constructor or null");r(e,t);function i(){this.constructor=e}e.prototype=t===null?Object.create(t):(i.prototype=t.prototype,new i)}}();Object.defineProperty(As,"__esModule",{value:!0});As.buildInProdFollowPrefix=As.buildBetweenProdsFollowPrefix=As.computeAllProdsFollows=As.ResyncFollowsWalker=void 0;var BEe=VI(),QEe=Dv(),lj=Gt(),cj=kv(),bEe=dn(),uj=function(r){wEe(e,r);function e(t){var i=r.call(this)||this;return i.topProd=t,i.follows={},i}return e.prototype.startWalking=function(){return this.walk(this.topProd),this.follows},e.prototype.walkTerminal=function(t,i,n){},e.prototype.walkProdRef=function(t,i,n){var s=gj(t.referencedRule,t.idx)+this.topProd.name,o=i.concat(n),a=new bEe.Alternative({definition:o}),l=(0,QEe.first)(a);this.follows[s]=l},e}(BEe.RestWalker);As.ResyncFollowsWalker=uj;function SEe(r){var e={};return(0,lj.forEach)(r,function(t){var i=new uj(t).startWalking();(0,lj.assign)(e,i)}),e}As.computeAllProdsFollows=SEe;function gj(r,e){return r.name+e+cj.IN}As.buildBetweenProdsFollowPrefix=gj;function vEe(r){var e=r.terminalType.name;return e+r.idx+cj.IN}As.buildInProdFollowPrefix=vEe});var Cd=w(Ba=>{"use strict";Object.defineProperty(Ba,"__esModule",{value:!0});Ba.defaultGrammarValidatorErrorProvider=Ba.defaultGrammarResolverErrorProvider=Ba.defaultParserErrorProvider=void 0;var jg=SA(),xEe=Gt(),Xs=Gt(),Rv=dn(),hj=dd();Ba.defaultParserErrorProvider={buildMismatchTokenMessage:function(r){var e=r.expected,t=r.actual,i=r.previous,n=r.ruleName,s=(0,jg.hasTokenLabel)(e),o=s?"--> "+(0,jg.tokenLabel)(e)+" <--":"token of type --> "+e.name+" <--",a="Expecting "+o+" but found --> '"+t.image+"' <--";return a},buildNotAllInputParsedMessage:function(r){var e=r.firstRedundant,t=r.ruleName;return"Redundant input, expecting EOF but found: "+e.image},buildNoViableAltMessage:function(r){var e=r.expectedPathsPerAlt,t=r.actual,i=r.previous,n=r.customUserDescription,s=r.ruleName,o="Expecting: ",a=(0,Xs.first)(t).image,l=` -but found: '`+a+"'";if(n)return o+n+l;var c=(0,Xs.reduce)(e,function(h,p){return h.concat(p)},[]),u=(0,Xs.map)(c,function(h){return"["+(0,Xs.map)(h,function(p){return(0,jg.tokenLabel)(p)}).join(", ")+"]"}),g=(0,Xs.map)(u,function(h,p){return" "+(p+1)+". "+h}),f=`one of these possible Token sequences: -`+g.join(` -`);return o+f+l},buildEarlyExitMessage:function(r){var e=r.expectedIterationPaths,t=r.actual,i=r.customUserDescription,n=r.ruleName,s="Expecting: ",o=(0,Xs.first)(t).image,a=` -but found: '`+o+"'";if(i)return s+i+a;var l=(0,Xs.map)(e,function(u){return"["+(0,Xs.map)(u,function(g){return(0,jg.tokenLabel)(g)}).join(",")+"]"}),c=`expecting at least one iteration which starts with one of these possible Token sequences:: - `+("<"+l.join(" ,")+">");return s+c+a}};Object.freeze(Ba.defaultParserErrorProvider);Ba.defaultGrammarResolverErrorProvider={buildRuleNotFoundError:function(r,e){var t="Invalid grammar, reference to a rule which is not defined: ->"+e.nonTerminalName+`<- -inside top level rule: ->`+r.name+"<-";return t}};Ba.defaultGrammarValidatorErrorProvider={buildDuplicateFoundError:function(r,e){function t(u){return u instanceof Rv.Terminal?u.terminalType.name:u instanceof Rv.NonTerminal?u.nonTerminalName:""}var i=r.name,n=(0,Xs.first)(e),s=n.idx,o=(0,hj.getProductionDslName)(n),a=t(n),l=s>0,c="->"+o+(l?s:"")+"<- "+(a?"with argument: ->"+a+"<-":"")+` - appears more than once (`+e.length+" times) in the top level rule: ->"+i+`<-. - For further details see: https://chevrotain.io/docs/FAQ.html#NUMERICAL_SUFFIXES - `;return c=c.replace(/[ \t]+/g," "),c=c.replace(/\s\s+/g,` -`),c},buildNamespaceConflictError:function(r){var e=`Namespace conflict found in grammar. -`+("The grammar has both a Terminal(Token) and a Non-Terminal(Rule) named: <"+r.name+`>. -`)+`To resolve this make sure each Terminal and Non-Terminal names are unique -This is easy to accomplish by using the convention that Terminal names start with an uppercase letter -and Non-Terminal names start with a lower case letter.`;return e},buildAlternationPrefixAmbiguityError:function(r){var e=(0,Xs.map)(r.prefixPath,function(n){return(0,jg.tokenLabel)(n)}).join(", "),t=r.alternation.idx===0?"":r.alternation.idx,i="Ambiguous alternatives: <"+r.ambiguityIndices.join(" ,")+`> due to common lookahead prefix -`+("in inside <"+r.topLevelRule.name+`> Rule, -`)+("<"+e+`> may appears as a prefix path in all these alternatives. -`)+`See: https://chevrotain.io/docs/guide/resolving_grammar_errors.html#COMMON_PREFIX -For Further details.`;return i},buildAlternationAmbiguityError:function(r){var e=(0,Xs.map)(r.prefixPath,function(n){return(0,jg.tokenLabel)(n)}).join(", "),t=r.alternation.idx===0?"":r.alternation.idx,i="Ambiguous Alternatives Detected: <"+r.ambiguityIndices.join(" ,")+"> in "+(" inside <"+r.topLevelRule.name+`> Rule, -`)+("<"+e+`> may appears as a prefix path in all these alternatives. -`);return i=i+`See: https://chevrotain.io/docs/guide/resolving_grammar_errors.html#AMBIGUOUS_ALTERNATIVES -For Further details.`,i},buildEmptyRepetitionError:function(r){var e=(0,hj.getProductionDslName)(r.repetition);r.repetition.idx!==0&&(e+=r.repetition.idx);var t="The repetition <"+e+"> within Rule <"+r.topLevelRule.name+`> can never consume any tokens. -This could lead to an infinite loop.`;return t},buildTokenNameError:function(r){return"deprecated"},buildEmptyAlternationError:function(r){var e="Ambiguous empty alternative: <"+(r.emptyChoiceIdx+1)+">"+(" in inside <"+r.topLevelRule.name+`> Rule. -`)+"Only the last alternative may be an empty alternative.";return e},buildTooManyAlternativesError:function(r){var e=`An Alternation cannot have more than 256 alternatives: -`+(" inside <"+r.topLevelRule.name+`> Rule. - has `+(r.alternation.definition.length+1)+" alternatives.");return e},buildLeftRecursionError:function(r){var e=r.topLevelRule.name,t=xEe.map(r.leftRecursionPath,function(s){return s.name}),i=e+" --> "+t.concat([e]).join(" --> "),n=`Left Recursion found in grammar. -`+("rule: <"+e+`> can be invoked from itself (directly or indirectly) -`)+(`without consuming any Tokens. The grammar path that causes this is: - `+i+` -`)+` To fix this refactor your grammar to remove the left recursion. -see: https://en.wikipedia.org/wiki/LL_parser#Left_Factoring.`;return n},buildInvalidRuleNameError:function(r){return"deprecated"},buildDuplicateRuleNameError:function(r){var e;r.topLevelRule instanceof Rv.Rule?e=r.topLevelRule.name:e=r.topLevelRule;var t="Duplicate definition, rule: ->"+e+"<- is already defined in the grammar: ->"+r.grammarName+"<-";return t}}});var Cj=w(vA=>{"use strict";var PEe=vA&&vA.__extends||function(){var r=function(e,t){return r=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(i,n){i.__proto__=n}||function(i,n){for(var s in n)Object.prototype.hasOwnProperty.call(n,s)&&(i[s]=n[s])},r(e,t)};return function(e,t){if(typeof t!="function"&&t!==null)throw new TypeError("Class extends value "+String(t)+" is not a constructor or null");r(e,t);function i(){this.constructor=e}e.prototype=t===null?Object.create(t):(i.prototype=t.prototype,new i)}}();Object.defineProperty(vA,"__esModule",{value:!0});vA.GastRefResolverVisitor=vA.resolveGrammar=void 0;var DEe=Hn(),pj=Gt(),kEe=Yg();function REe(r,e){var t=new dj(r,e);return t.resolveRefs(),t.errors}vA.resolveGrammar=REe;var dj=function(r){PEe(e,r);function e(t,i){var n=r.call(this)||this;return n.nameToTopRule=t,n.errMsgProvider=i,n.errors=[],n}return e.prototype.resolveRefs=function(){var t=this;(0,pj.forEach)((0,pj.values)(this.nameToTopRule),function(i){t.currTopLevel=i,i.accept(t)})},e.prototype.visitNonTerminal=function(t){var i=this.nameToTopRule[t.nonTerminalName];if(i)t.referencedRule=i;else{var n=this.errMsgProvider.buildRuleNotFoundError(this.currTopLevel,t);this.errors.push({message:n,type:DEe.ParserDefinitionErrorType.UNRESOLVED_SUBRULE_REF,ruleName:this.currTopLevel.name,unresolvedRefName:t.nonTerminalName})}},e}(kEe.GAstVisitor);vA.GastRefResolverVisitor=dj});var Ed=w(Nr=>{"use strict";var sc=Nr&&Nr.__extends||function(){var r=function(e,t){return r=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(i,n){i.__proto__=n}||function(i,n){for(var s in n)Object.prototype.hasOwnProperty.call(n,s)&&(i[s]=n[s])},r(e,t)};return function(e,t){if(typeof t!="function"&&t!==null)throw new TypeError("Class extends value "+String(t)+" is not a constructor or null");r(e,t);function i(){this.constructor=e}e.prototype=t===null?Object.create(t):(i.prototype=t.prototype,new i)}}();Object.defineProperty(Nr,"__esModule",{value:!0});Nr.nextPossibleTokensAfter=Nr.possiblePathsFrom=Nr.NextTerminalAfterAtLeastOneSepWalker=Nr.NextTerminalAfterAtLeastOneWalker=Nr.NextTerminalAfterManySepWalker=Nr.NextTerminalAfterManyWalker=Nr.AbstractNextTerminalAfterProductionWalker=Nr.NextAfterTokenWalker=Nr.AbstractNextPossibleTokensWalker=void 0;var mj=VI(),Kt=Gt(),FEe=Dv(),kt=dn(),Ej=function(r){sc(e,r);function e(t,i){var n=r.call(this)||this;return n.topProd=t,n.path=i,n.possibleTokTypes=[],n.nextProductionName="",n.nextProductionOccurrence=0,n.found=!1,n.isAtEndOfPath=!1,n}return e.prototype.startWalking=function(){if(this.found=!1,this.path.ruleStack[0]!==this.topProd.name)throw Error("The path does not start with the walker's top Rule!");return this.ruleStack=(0,Kt.cloneArr)(this.path.ruleStack).reverse(),this.occurrenceStack=(0,Kt.cloneArr)(this.path.occurrenceStack).reverse(),this.ruleStack.pop(),this.occurrenceStack.pop(),this.updateExpectedNext(),this.walk(this.topProd),this.possibleTokTypes},e.prototype.walk=function(t,i){i===void 0&&(i=[]),this.found||r.prototype.walk.call(this,t,i)},e.prototype.walkProdRef=function(t,i,n){if(t.referencedRule.name===this.nextProductionName&&t.idx===this.nextProductionOccurrence){var s=i.concat(n);this.updateExpectedNext(),this.walk(t.referencedRule,s)}},e.prototype.updateExpectedNext=function(){(0,Kt.isEmpty)(this.ruleStack)?(this.nextProductionName="",this.nextProductionOccurrence=0,this.isAtEndOfPath=!0):(this.nextProductionName=this.ruleStack.pop(),this.nextProductionOccurrence=this.occurrenceStack.pop())},e}(mj.RestWalker);Nr.AbstractNextPossibleTokensWalker=Ej;var NEe=function(r){sc(e,r);function e(t,i){var n=r.call(this,t,i)||this;return n.path=i,n.nextTerminalName="",n.nextTerminalOccurrence=0,n.nextTerminalName=n.path.lastTok.name,n.nextTerminalOccurrence=n.path.lastTokOccurrence,n}return e.prototype.walkTerminal=function(t,i,n){if(this.isAtEndOfPath&&t.terminalType.name===this.nextTerminalName&&t.idx===this.nextTerminalOccurrence&&!this.found){var s=i.concat(n),o=new kt.Alternative({definition:s});this.possibleTokTypes=(0,FEe.first)(o),this.found=!0}},e}(Ej);Nr.NextAfterTokenWalker=NEe;var md=function(r){sc(e,r);function e(t,i){var n=r.call(this)||this;return n.topRule=t,n.occurrence=i,n.result={token:void 0,occurrence:void 0,isEndOfRule:void 0},n}return e.prototype.startWalking=function(){return this.walk(this.topRule),this.result},e}(mj.RestWalker);Nr.AbstractNextTerminalAfterProductionWalker=md;var LEe=function(r){sc(e,r);function e(){return r!==null&&r.apply(this,arguments)||this}return e.prototype.walkMany=function(t,i,n){if(t.idx===this.occurrence){var s=(0,Kt.first)(i.concat(n));this.result.isEndOfRule=s===void 0,s instanceof kt.Terminal&&(this.result.token=s.terminalType,this.result.occurrence=s.idx)}else r.prototype.walkMany.call(this,t,i,n)},e}(md);Nr.NextTerminalAfterManyWalker=LEe;var TEe=function(r){sc(e,r);function e(){return r!==null&&r.apply(this,arguments)||this}return e.prototype.walkManySep=function(t,i,n){if(t.idx===this.occurrence){var s=(0,Kt.first)(i.concat(n));this.result.isEndOfRule=s===void 0,s instanceof kt.Terminal&&(this.result.token=s.terminalType,this.result.occurrence=s.idx)}else r.prototype.walkManySep.call(this,t,i,n)},e}(md);Nr.NextTerminalAfterManySepWalker=TEe;var OEe=function(r){sc(e,r);function e(){return r!==null&&r.apply(this,arguments)||this}return e.prototype.walkAtLeastOne=function(t,i,n){if(t.idx===this.occurrence){var s=(0,Kt.first)(i.concat(n));this.result.isEndOfRule=s===void 0,s instanceof kt.Terminal&&(this.result.token=s.terminalType,this.result.occurrence=s.idx)}else r.prototype.walkAtLeastOne.call(this,t,i,n)},e}(md);Nr.NextTerminalAfterAtLeastOneWalker=OEe;var MEe=function(r){sc(e,r);function e(){return r!==null&&r.apply(this,arguments)||this}return e.prototype.walkAtLeastOneSep=function(t,i,n){if(t.idx===this.occurrence){var s=(0,Kt.first)(i.concat(n));this.result.isEndOfRule=s===void 0,s instanceof kt.Terminal&&(this.result.token=s.terminalType,this.result.occurrence=s.idx)}else r.prototype.walkAtLeastOneSep.call(this,t,i,n)},e}(md);Nr.NextTerminalAfterAtLeastOneSepWalker=MEe;function Ij(r,e,t){t===void 0&&(t=[]),t=(0,Kt.cloneArr)(t);var i=[],n=0;function s(c){return c.concat((0,Kt.drop)(r,n+1))}function o(c){var u=Ij(s(c),e,t);return i.concat(u)}for(;t.length=0;ge--){var re=B.definition[ge],O={idx:p,def:re.definition.concat((0,Kt.drop)(h)),ruleStack:C,occurrenceStack:y};g.push(O),g.push(o)}else if(B instanceof kt.Alternative)g.push({idx:p,def:B.definition.concat((0,Kt.drop)(h)),ruleStack:C,occurrenceStack:y});else if(B instanceof kt.Rule)g.push(UEe(B,p,C,y));else throw Error("non exhaustive match")}}return u}Nr.nextPossibleTokensAfter=KEe;function UEe(r,e,t,i){var n=(0,Kt.cloneArr)(t);n.push(r.name);var s=(0,Kt.cloneArr)(i);return s.push(1),{idx:e,def:r.definition,ruleStack:n,occurrenceStack:s}}});var Id=w(_t=>{"use strict";var Bj=_t&&_t.__extends||function(){var r=function(e,t){return r=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(i,n){i.__proto__=n}||function(i,n){for(var s in n)Object.prototype.hasOwnProperty.call(n,s)&&(i[s]=n[s])},r(e,t)};return function(e,t){if(typeof t!="function"&&t!==null)throw new TypeError("Class extends value "+String(t)+" is not a constructor or null");r(e,t);function i(){this.constructor=e}e.prototype=t===null?Object.create(t):(i.prototype=t.prototype,new i)}}();Object.defineProperty(_t,"__esModule",{value:!0});_t.areTokenCategoriesNotUsed=_t.isStrictPrefixOfPath=_t.containsPath=_t.getLookaheadPathsForOptionalProd=_t.getLookaheadPathsForOr=_t.lookAheadSequenceFromAlternatives=_t.buildSingleAlternativeLookaheadFunction=_t.buildAlternativesLookAheadFunc=_t.buildLookaheadFuncForOptionalProd=_t.buildLookaheadFuncForOr=_t.getProdType=_t.PROD_TYPE=void 0;var sr=Gt(),yj=Ed(),HEe=VI(),ty=Gg(),xA=dn(),GEe=Yg(),oi;(function(r){r[r.OPTION=0]="OPTION",r[r.REPETITION=1]="REPETITION",r[r.REPETITION_MANDATORY=2]="REPETITION_MANDATORY",r[r.REPETITION_MANDATORY_WITH_SEPARATOR=3]="REPETITION_MANDATORY_WITH_SEPARATOR",r[r.REPETITION_WITH_SEPARATOR=4]="REPETITION_WITH_SEPARATOR",r[r.ALTERNATION=5]="ALTERNATION"})(oi=_t.PROD_TYPE||(_t.PROD_TYPE={}));function YEe(r){if(r instanceof xA.Option)return oi.OPTION;if(r instanceof xA.Repetition)return oi.REPETITION;if(r instanceof xA.RepetitionMandatory)return oi.REPETITION_MANDATORY;if(r instanceof xA.RepetitionMandatoryWithSeparator)return oi.REPETITION_MANDATORY_WITH_SEPARATOR;if(r instanceof xA.RepetitionWithSeparator)return oi.REPETITION_WITH_SEPARATOR;if(r instanceof xA.Alternation)return oi.ALTERNATION;throw Error("non exhaustive match")}_t.getProdType=YEe;function jEe(r,e,t,i,n,s){var o=bj(r,e,t),a=Lv(o)?ty.tokenStructuredMatcherNoCategories:ty.tokenStructuredMatcher;return s(o,i,a,n)}_t.buildLookaheadFuncForOr=jEe;function qEe(r,e,t,i,n,s){var o=Sj(r,e,n,t),a=Lv(o)?ty.tokenStructuredMatcherNoCategories:ty.tokenStructuredMatcher;return s(o[0],a,i)}_t.buildLookaheadFuncForOptionalProd=qEe;function JEe(r,e,t,i){var n=r.length,s=(0,sr.every)(r,function(l){return(0,sr.every)(l,function(c){return c.length===1})});if(e)return function(l){for(var c=(0,sr.map)(l,function(D){return D.GATE}),u=0;u{"use strict";var Tv=zt&&zt.__extends||function(){var r=function(e,t){return r=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(i,n){i.__proto__=n}||function(i,n){for(var s in n)Object.prototype.hasOwnProperty.call(n,s)&&(i[s]=n[s])},r(e,t)};return function(e,t){if(typeof t!="function"&&t!==null)throw new TypeError("Class extends value "+String(t)+" is not a constructor or null");r(e,t);function i(){this.constructor=e}e.prototype=t===null?Object.create(t):(i.prototype=t.prototype,new i)}}();Object.defineProperty(zt,"__esModule",{value:!0});zt.checkPrefixAlternativesAmbiguities=zt.validateSomeNonEmptyLookaheadPath=zt.validateTooManyAlts=zt.RepetionCollector=zt.validateAmbiguousAlternationAlternatives=zt.validateEmptyOrAlternative=zt.getFirstNoneTerminal=zt.validateNoLeftRecursion=zt.validateRuleIsOverridden=zt.validateRuleDoesNotAlreadyExist=zt.OccurrenceValidationCollector=zt.identifyProductionForDuplicates=zt.validateGrammar=void 0;var er=Gt(),br=Gt(),Do=Hn(),Ov=dd(),qg=Id(),_Ee=Ed(),_s=dn(),Mv=Yg();function ZEe(r,e,t,i,n){var s=er.map(r,function(h){return $Ee(h,i)}),o=er.map(r,function(h){return Kv(h,h,i)}),a=[],l=[],c=[];(0,br.every)(o,br.isEmpty)&&(a=(0,br.map)(r,function(h){return Rj(h,i)}),l=(0,br.map)(r,function(h){return Fj(h,e,i)}),c=Tj(r,e,i));var u=rIe(r,t,i),g=(0,br.map)(r,function(h){return Lj(h,i)}),f=(0,br.map)(r,function(h){return kj(h,r,n,i)});return er.flatten(s.concat(c,o,a,l,u,g,f))}zt.validateGrammar=ZEe;function $Ee(r,e){var t=new Dj;r.accept(t);var i=t.allProductions,n=er.groupBy(i,xj),s=er.pick(n,function(a){return a.length>1}),o=er.map(er.values(s),function(a){var l=er.first(a),c=e.buildDuplicateFoundError(r,a),u=(0,Ov.getProductionDslName)(l),g={message:c,type:Do.ParserDefinitionErrorType.DUPLICATE_PRODUCTIONS,ruleName:r.name,dslName:u,occurrence:l.idx},f=Pj(l);return f&&(g.parameter=f),g});return o}function xj(r){return(0,Ov.getProductionDslName)(r)+"_#_"+r.idx+"_#_"+Pj(r)}zt.identifyProductionForDuplicates=xj;function Pj(r){return r instanceof _s.Terminal?r.terminalType.name:r instanceof _s.NonTerminal?r.nonTerminalName:""}var Dj=function(r){Tv(e,r);function e(){var t=r!==null&&r.apply(this,arguments)||this;return t.allProductions=[],t}return e.prototype.visitNonTerminal=function(t){this.allProductions.push(t)},e.prototype.visitOption=function(t){this.allProductions.push(t)},e.prototype.visitRepetitionWithSeparator=function(t){this.allProductions.push(t)},e.prototype.visitRepetitionMandatory=function(t){this.allProductions.push(t)},e.prototype.visitRepetitionMandatoryWithSeparator=function(t){this.allProductions.push(t)},e.prototype.visitRepetition=function(t){this.allProductions.push(t)},e.prototype.visitAlternation=function(t){this.allProductions.push(t)},e.prototype.visitTerminal=function(t){this.allProductions.push(t)},e}(Mv.GAstVisitor);zt.OccurrenceValidationCollector=Dj;function kj(r,e,t,i){var n=[],s=(0,br.reduce)(e,function(a,l){return l.name===r.name?a+1:a},0);if(s>1){var o=i.buildDuplicateRuleNameError({topLevelRule:r,grammarName:t});n.push({message:o,type:Do.ParserDefinitionErrorType.DUPLICATE_RULE_NAME,ruleName:r.name})}return n}zt.validateRuleDoesNotAlreadyExist=kj;function eIe(r,e,t){var i=[],n;return er.contains(e,r)||(n="Invalid rule override, rule: ->"+r+"<- cannot be overridden in the grammar: ->"+t+"<-as it is not defined in any of the super grammars ",i.push({message:n,type:Do.ParserDefinitionErrorType.INVALID_RULE_OVERRIDE,ruleName:r})),i}zt.validateRuleIsOverridden=eIe;function Kv(r,e,t,i){i===void 0&&(i=[]);var n=[],s=yd(e.definition);if(er.isEmpty(s))return[];var o=r.name,a=er.contains(s,r);a&&n.push({message:t.buildLeftRecursionError({topLevelRule:r,leftRecursionPath:i}),type:Do.ParserDefinitionErrorType.LEFT_RECURSION,ruleName:o});var l=er.difference(s,i.concat([r])),c=er.map(l,function(u){var g=er.cloneArr(i);return g.push(u),Kv(r,u,t,g)});return n.concat(er.flatten(c))}zt.validateNoLeftRecursion=Kv;function yd(r){var e=[];if(er.isEmpty(r))return e;var t=er.first(r);if(t instanceof _s.NonTerminal)e.push(t.referencedRule);else if(t instanceof _s.Alternative||t instanceof _s.Option||t instanceof _s.RepetitionMandatory||t instanceof _s.RepetitionMandatoryWithSeparator||t instanceof _s.RepetitionWithSeparator||t instanceof _s.Repetition)e=e.concat(yd(t.definition));else if(t instanceof _s.Alternation)e=er.flatten(er.map(t.definition,function(o){return yd(o.definition)}));else if(!(t instanceof _s.Terminal))throw Error("non exhaustive match");var i=(0,Ov.isOptionalProd)(t),n=r.length>1;if(i&&n){var s=er.drop(r);return e.concat(yd(s))}else return e}zt.getFirstNoneTerminal=yd;var Uv=function(r){Tv(e,r);function e(){var t=r!==null&&r.apply(this,arguments)||this;return t.alternations=[],t}return e.prototype.visitAlternation=function(t){this.alternations.push(t)},e}(Mv.GAstVisitor);function Rj(r,e){var t=new Uv;r.accept(t);var i=t.alternations,n=er.reduce(i,function(s,o){var a=er.dropRight(o.definition),l=er.map(a,function(c,u){var g=(0,_Ee.nextPossibleTokensAfter)([c],[],null,1);return er.isEmpty(g)?{message:e.buildEmptyAlternationError({topLevelRule:r,alternation:o,emptyChoiceIdx:u}),type:Do.ParserDefinitionErrorType.NONE_LAST_EMPTY_ALT,ruleName:r.name,occurrence:o.idx,alternative:u+1}:null});return s.concat(er.compact(l))},[]);return n}zt.validateEmptyOrAlternative=Rj;function Fj(r,e,t){var i=new Uv;r.accept(i);var n=i.alternations;n=(0,br.reject)(n,function(o){return o.ignoreAmbiguities===!0});var s=er.reduce(n,function(o,a){var l=a.idx,c=a.maxLookahead||e,u=(0,qg.getLookaheadPathsForOr)(l,r,c,a),g=tIe(u,a,r,t),f=Oj(u,a,r,t);return o.concat(g,f)},[]);return s}zt.validateAmbiguousAlternationAlternatives=Fj;var Nj=function(r){Tv(e,r);function e(){var t=r!==null&&r.apply(this,arguments)||this;return t.allProductions=[],t}return e.prototype.visitRepetitionWithSeparator=function(t){this.allProductions.push(t)},e.prototype.visitRepetitionMandatory=function(t){this.allProductions.push(t)},e.prototype.visitRepetitionMandatoryWithSeparator=function(t){this.allProductions.push(t)},e.prototype.visitRepetition=function(t){this.allProductions.push(t)},e}(Mv.GAstVisitor);zt.RepetionCollector=Nj;function Lj(r,e){var t=new Uv;r.accept(t);var i=t.alternations,n=er.reduce(i,function(s,o){return o.definition.length>255&&s.push({message:e.buildTooManyAlternativesError({topLevelRule:r,alternation:o}),type:Do.ParserDefinitionErrorType.TOO_MANY_ALTS,ruleName:r.name,occurrence:o.idx}),s},[]);return n}zt.validateTooManyAlts=Lj;function Tj(r,e,t){var i=[];return(0,br.forEach)(r,function(n){var s=new Nj;n.accept(s);var o=s.allProductions;(0,br.forEach)(o,function(a){var l=(0,qg.getProdType)(a),c=a.maxLookahead||e,u=a.idx,g=(0,qg.getLookaheadPathsForOptionalProd)(u,n,l,c),f=g[0];if((0,br.isEmpty)((0,br.flatten)(f))){var h=t.buildEmptyRepetitionError({topLevelRule:n,repetition:a});i.push({message:h,type:Do.ParserDefinitionErrorType.NO_NON_EMPTY_LOOKAHEAD,ruleName:n.name})}})}),i}zt.validateSomeNonEmptyLookaheadPath=Tj;function tIe(r,e,t,i){var n=[],s=(0,br.reduce)(r,function(a,l,c){return e.definition[c].ignoreAmbiguities===!0||(0,br.forEach)(l,function(u){var g=[c];(0,br.forEach)(r,function(f,h){c!==h&&(0,qg.containsPath)(f,u)&&e.definition[h].ignoreAmbiguities!==!0&&g.push(h)}),g.length>1&&!(0,qg.containsPath)(n,u)&&(n.push(u),a.push({alts:g,path:u}))}),a},[]),o=er.map(s,function(a){var l=(0,br.map)(a.alts,function(u){return u+1}),c=i.buildAlternationAmbiguityError({topLevelRule:t,alternation:e,ambiguityIndices:l,prefixPath:a.path});return{message:c,type:Do.ParserDefinitionErrorType.AMBIGUOUS_ALTS,ruleName:t.name,occurrence:e.idx,alternatives:[a.alts]}});return o}function Oj(r,e,t,i){var n=[],s=(0,br.reduce)(r,function(o,a,l){var c=(0,br.map)(a,function(u){return{idx:l,path:u}});return o.concat(c)},[]);return(0,br.forEach)(s,function(o){var a=e.definition[o.idx];if(a.ignoreAmbiguities!==!0){var l=o.idx,c=o.path,u=(0,br.findAll)(s,function(f){return e.definition[f.idx].ignoreAmbiguities!==!0&&f.idx{"use strict";Object.defineProperty(Jg,"__esModule",{value:!0});Jg.validateGrammar=Jg.resolveGrammar=void 0;var Gv=Gt(),iIe=Cj(),nIe=Hv(),Mj=Cd();function sIe(r){r=(0,Gv.defaults)(r,{errMsgProvider:Mj.defaultGrammarResolverErrorProvider});var e={};return(0,Gv.forEach)(r.rules,function(t){e[t.name]=t}),(0,iIe.resolveGrammar)(e,r.errMsgProvider)}Jg.resolveGrammar=sIe;function oIe(r){return r=(0,Gv.defaults)(r,{errMsgProvider:Mj.defaultGrammarValidatorErrorProvider}),(0,nIe.validateGrammar)(r.rules,r.maxLookahead,r.tokenTypes,r.errMsgProvider,r.grammarName)}Jg.validateGrammar=oIe});var Wg=w(mn=>{"use strict";var wd=mn&&mn.__extends||function(){var r=function(e,t){return r=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(i,n){i.__proto__=n}||function(i,n){for(var s in n)Object.prototype.hasOwnProperty.call(n,s)&&(i[s]=n[s])},r(e,t)};return function(e,t){if(typeof t!="function"&&t!==null)throw new TypeError("Class extends value "+String(t)+" is not a constructor or null");r(e,t);function i(){this.constructor=e}e.prototype=t===null?Object.create(t):(i.prototype=t.prototype,new i)}}();Object.defineProperty(mn,"__esModule",{value:!0});mn.EarlyExitException=mn.NotAllInputParsedException=mn.NoViableAltException=mn.MismatchedTokenException=mn.isRecognitionException=void 0;var aIe=Gt(),Uj="MismatchedTokenException",Hj="NoViableAltException",Gj="EarlyExitException",Yj="NotAllInputParsedException",jj=[Uj,Hj,Gj,Yj];Object.freeze(jj);function AIe(r){return(0,aIe.contains)(jj,r.name)}mn.isRecognitionException=AIe;var ry=function(r){wd(e,r);function e(t,i){var n=this.constructor,s=r.call(this,t)||this;return s.token=i,s.resyncedTokens=[],Object.setPrototypeOf(s,n.prototype),Error.captureStackTrace&&Error.captureStackTrace(s,s.constructor),s}return e}(Error),lIe=function(r){wd(e,r);function e(t,i,n){var s=r.call(this,t,i)||this;return s.previousToken=n,s.name=Uj,s}return e}(ry);mn.MismatchedTokenException=lIe;var cIe=function(r){wd(e,r);function e(t,i,n){var s=r.call(this,t,i)||this;return s.previousToken=n,s.name=Hj,s}return e}(ry);mn.NoViableAltException=cIe;var uIe=function(r){wd(e,r);function e(t,i){var n=r.call(this,t,i)||this;return n.name=Yj,n}return e}(ry);mn.NotAllInputParsedException=uIe;var gIe=function(r){wd(e,r);function e(t,i,n){var s=r.call(this,t,i)||this;return s.previousToken=n,s.name=Gj,s}return e}(ry);mn.EarlyExitException=gIe});var jv=w(Mi=>{"use strict";Object.defineProperty(Mi,"__esModule",{value:!0});Mi.attemptInRepetitionRecovery=Mi.Recoverable=Mi.InRuleRecoveryException=Mi.IN_RULE_RECOVERY_EXCEPTION=Mi.EOF_FOLLOW_KEY=void 0;var iy=SA(),ls=Gt(),fIe=Wg(),hIe=kv(),pIe=Hn();Mi.EOF_FOLLOW_KEY={};Mi.IN_RULE_RECOVERY_EXCEPTION="InRuleRecoveryException";function Yv(r){this.name=Mi.IN_RULE_RECOVERY_EXCEPTION,this.message=r}Mi.InRuleRecoveryException=Yv;Yv.prototype=Error.prototype;var dIe=function(){function r(){}return r.prototype.initRecoverable=function(e){this.firstAfterRepMap={},this.resyncFollows={},this.recoveryEnabled=(0,ls.has)(e,"recoveryEnabled")?e.recoveryEnabled:pIe.DEFAULT_PARSER_CONFIG.recoveryEnabled,this.recoveryEnabled&&(this.attemptInRepetitionRecovery=qj)},r.prototype.getTokenToInsert=function(e){var t=(0,iy.createTokenInstance)(e,"",NaN,NaN,NaN,NaN,NaN,NaN);return t.isInsertedInRecovery=!0,t},r.prototype.canTokenTypeBeInsertedInRecovery=function(e){return!0},r.prototype.tryInRepetitionRecovery=function(e,t,i,n){for(var s=this,o=this.findReSyncTokenType(),a=this.exportLexerState(),l=[],c=!1,u=this.LA(1),g=this.LA(1),f=function(){var h=s.LA(0),p=s.errorMessageProvider.buildMismatchTokenMessage({expected:n,actual:u,previous:h,ruleName:s.getCurrRuleFullName()}),C=new fIe.MismatchedTokenException(p,u,s.LA(0));C.resyncedTokens=(0,ls.dropRight)(l),s.SAVE_ERROR(C)};!c;)if(this.tokenMatcher(g,n)){f();return}else if(i.call(this)){f(),e.apply(this,t);return}else this.tokenMatcher(g,o)?c=!0:(g=this.SKIP_TOKEN(),this.addToResyncTokens(g,l));this.importLexerState(a)},r.prototype.shouldInRepetitionRecoveryBeTried=function(e,t,i){return!(i===!1||e===void 0||t===void 0||this.tokenMatcher(this.LA(1),e)||this.isBackTracking()||this.canPerformInRuleRecovery(e,this.getFollowsForInRuleRecovery(e,t)))},r.prototype.getFollowsForInRuleRecovery=function(e,t){var i=this.getCurrentGrammarPath(e,t),n=this.getNextPossibleTokenTypes(i);return n},r.prototype.tryInRuleRecovery=function(e,t){if(this.canRecoverWithSingleTokenInsertion(e,t)){var i=this.getTokenToInsert(e);return i}if(this.canRecoverWithSingleTokenDeletion(e)){var n=this.SKIP_TOKEN();return this.consumeToken(),n}throw new Yv("sad sad panda")},r.prototype.canPerformInRuleRecovery=function(e,t){return this.canRecoverWithSingleTokenInsertion(e,t)||this.canRecoverWithSingleTokenDeletion(e)},r.prototype.canRecoverWithSingleTokenInsertion=function(e,t){var i=this;if(!this.canTokenTypeBeInsertedInRecovery(e)||(0,ls.isEmpty)(t))return!1;var n=this.LA(1),s=(0,ls.find)(t,function(o){return i.tokenMatcher(n,o)})!==void 0;return s},r.prototype.canRecoverWithSingleTokenDeletion=function(e){var t=this.tokenMatcher(this.LA(2),e);return t},r.prototype.isInCurrentRuleReSyncSet=function(e){var t=this.getCurrFollowKey(),i=this.getFollowSetFromFollowKey(t);return(0,ls.contains)(i,e)},r.prototype.findReSyncTokenType=function(){for(var e=this.flattenFollowSet(),t=this.LA(1),i=2;;){var n=t.tokenType;if((0,ls.contains)(e,n))return n;t=this.LA(i),i++}},r.prototype.getCurrFollowKey=function(){if(this.RULE_STACK.length===1)return Mi.EOF_FOLLOW_KEY;var e=this.getLastExplicitRuleShortName(),t=this.getLastExplicitRuleOccurrenceIndex(),i=this.getPreviousExplicitRuleShortName();return{ruleName:this.shortRuleNameToFullName(e),idxInCallingRule:t,inRule:this.shortRuleNameToFullName(i)}},r.prototype.buildFullFollowKeyStack=function(){var e=this,t=this.RULE_STACK,i=this.RULE_OCCURRENCE_STACK;return(0,ls.map)(t,function(n,s){return s===0?Mi.EOF_FOLLOW_KEY:{ruleName:e.shortRuleNameToFullName(n),idxInCallingRule:i[s],inRule:e.shortRuleNameToFullName(t[s-1])}})},r.prototype.flattenFollowSet=function(){var e=this,t=(0,ls.map)(this.buildFullFollowKeyStack(),function(i){return e.getFollowSetFromFollowKey(i)});return(0,ls.flatten)(t)},r.prototype.getFollowSetFromFollowKey=function(e){if(e===Mi.EOF_FOLLOW_KEY)return[iy.EOF];var t=e.ruleName+e.idxInCallingRule+hIe.IN+e.inRule;return this.resyncFollows[t]},r.prototype.addToResyncTokens=function(e,t){return this.tokenMatcher(e,iy.EOF)||t.push(e),t},r.prototype.reSyncTo=function(e){for(var t=[],i=this.LA(1);this.tokenMatcher(i,e)===!1;)i=this.SKIP_TOKEN(),this.addToResyncTokens(i,t);return(0,ls.dropRight)(t)},r.prototype.attemptInRepetitionRecovery=function(e,t,i,n,s,o,a){},r.prototype.getCurrentGrammarPath=function(e,t){var i=this.getHumanReadableRuleStack(),n=(0,ls.cloneArr)(this.RULE_OCCURRENCE_STACK),s={ruleStack:i,occurrenceStack:n,lastTok:e,lastTokOccurrence:t};return s},r.prototype.getHumanReadableRuleStack=function(){var e=this;return(0,ls.map)(this.RULE_STACK,function(t){return e.shortRuleNameToFullName(t)})},r}();Mi.Recoverable=dIe;function qj(r,e,t,i,n,s,o){var a=this.getKeyForAutomaticLookahead(i,n),l=this.firstAfterRepMap[a];if(l===void 0){var c=this.getCurrRuleFullName(),u=this.getGAstProductions()[c],g=new s(u,n);l=g.startWalking(),this.firstAfterRepMap[a]=l}var f=l.token,h=l.occurrence,p=l.isEndOfRule;this.RULE_STACK.length===1&&p&&f===void 0&&(f=iy.EOF,h=1),this.shouldInRepetitionRecoveryBeTried(f,h,o)&&this.tryInRepetitionRecovery(r,e,t,f)}Mi.attemptInRepetitionRecovery=qj});var ny=w(qt=>{"use strict";Object.defineProperty(qt,"__esModule",{value:!0});qt.getKeyForAutomaticLookahead=qt.AT_LEAST_ONE_SEP_IDX=qt.MANY_SEP_IDX=qt.AT_LEAST_ONE_IDX=qt.MANY_IDX=qt.OPTION_IDX=qt.OR_IDX=qt.BITS_FOR_ALT_IDX=qt.BITS_FOR_RULE_IDX=qt.BITS_FOR_OCCURRENCE_IDX=qt.BITS_FOR_METHOD_TYPE=void 0;qt.BITS_FOR_METHOD_TYPE=4;qt.BITS_FOR_OCCURRENCE_IDX=8;qt.BITS_FOR_RULE_IDX=12;qt.BITS_FOR_ALT_IDX=8;qt.OR_IDX=1<{"use strict";Object.defineProperty(sy,"__esModule",{value:!0});sy.LooksAhead=void 0;var Qa=Id(),Zs=Gt(),Jj=Hn(),ba=ny(),oc=dd(),mIe=function(){function r(){}return r.prototype.initLooksAhead=function(e){this.dynamicTokensEnabled=(0,Zs.has)(e,"dynamicTokensEnabled")?e.dynamicTokensEnabled:Jj.DEFAULT_PARSER_CONFIG.dynamicTokensEnabled,this.maxLookahead=(0,Zs.has)(e,"maxLookahead")?e.maxLookahead:Jj.DEFAULT_PARSER_CONFIG.maxLookahead,this.lookAheadFuncsCache=(0,Zs.isES2015MapSupported)()?new Map:[],(0,Zs.isES2015MapSupported)()?(this.getLaFuncFromCache=this.getLaFuncFromMap,this.setLaFuncCache=this.setLaFuncCacheUsingMap):(this.getLaFuncFromCache=this.getLaFuncFromObj,this.setLaFuncCache=this.setLaFuncUsingObj)},r.prototype.preComputeLookaheadFunctions=function(e){var t=this;(0,Zs.forEach)(e,function(i){t.TRACE_INIT(i.name+" Rule Lookahead",function(){var n=(0,oc.collectMethods)(i),s=n.alternation,o=n.repetition,a=n.option,l=n.repetitionMandatory,c=n.repetitionMandatoryWithSeparator,u=n.repetitionWithSeparator;(0,Zs.forEach)(s,function(g){var f=g.idx===0?"":g.idx;t.TRACE_INIT(""+(0,oc.getProductionDslName)(g)+f,function(){var h=(0,Qa.buildLookaheadFuncForOr)(g.idx,i,g.maxLookahead||t.maxLookahead,g.hasPredicates,t.dynamicTokensEnabled,t.lookAheadBuilderForAlternatives),p=(0,ba.getKeyForAutomaticLookahead)(t.fullRuleNameToShort[i.name],ba.OR_IDX,g.idx);t.setLaFuncCache(p,h)})}),(0,Zs.forEach)(o,function(g){t.computeLookaheadFunc(i,g.idx,ba.MANY_IDX,Qa.PROD_TYPE.REPETITION,g.maxLookahead,(0,oc.getProductionDslName)(g))}),(0,Zs.forEach)(a,function(g){t.computeLookaheadFunc(i,g.idx,ba.OPTION_IDX,Qa.PROD_TYPE.OPTION,g.maxLookahead,(0,oc.getProductionDslName)(g))}),(0,Zs.forEach)(l,function(g){t.computeLookaheadFunc(i,g.idx,ba.AT_LEAST_ONE_IDX,Qa.PROD_TYPE.REPETITION_MANDATORY,g.maxLookahead,(0,oc.getProductionDslName)(g))}),(0,Zs.forEach)(c,function(g){t.computeLookaheadFunc(i,g.idx,ba.AT_LEAST_ONE_SEP_IDX,Qa.PROD_TYPE.REPETITION_MANDATORY_WITH_SEPARATOR,g.maxLookahead,(0,oc.getProductionDslName)(g))}),(0,Zs.forEach)(u,function(g){t.computeLookaheadFunc(i,g.idx,ba.MANY_SEP_IDX,Qa.PROD_TYPE.REPETITION_WITH_SEPARATOR,g.maxLookahead,(0,oc.getProductionDslName)(g))})})})},r.prototype.computeLookaheadFunc=function(e,t,i,n,s,o){var a=this;this.TRACE_INIT(""+o+(t===0?"":t),function(){var l=(0,Qa.buildLookaheadFuncForOptionalProd)(t,e,s||a.maxLookahead,a.dynamicTokensEnabled,n,a.lookAheadBuilderForOptional),c=(0,ba.getKeyForAutomaticLookahead)(a.fullRuleNameToShort[e.name],i,t);a.setLaFuncCache(c,l)})},r.prototype.lookAheadBuilderForOptional=function(e,t,i){return(0,Qa.buildSingleAlternativeLookaheadFunction)(e,t,i)},r.prototype.lookAheadBuilderForAlternatives=function(e,t,i,n){return(0,Qa.buildAlternativesLookAheadFunc)(e,t,i,n)},r.prototype.getKeyForAutomaticLookahead=function(e,t){var i=this.getLastExplicitRuleShortName();return(0,ba.getKeyForAutomaticLookahead)(i,e,t)},r.prototype.getLaFuncFromCache=function(e){},r.prototype.getLaFuncFromMap=function(e){return this.lookAheadFuncsCache.get(e)},r.prototype.getLaFuncFromObj=function(e){return this.lookAheadFuncsCache[e]},r.prototype.setLaFuncCache=function(e,t){},r.prototype.setLaFuncCacheUsingMap=function(e,t){this.lookAheadFuncsCache.set(e,t)},r.prototype.setLaFuncUsingObj=function(e,t){this.lookAheadFuncsCache[e]=t},r}();sy.LooksAhead=mIe});var zj=w(ko=>{"use strict";Object.defineProperty(ko,"__esModule",{value:!0});ko.addNoneTerminalToCst=ko.addTerminalToCst=ko.setNodeLocationFull=ko.setNodeLocationOnlyOffset=void 0;function EIe(r,e){isNaN(r.startOffset)===!0?(r.startOffset=e.startOffset,r.endOffset=e.endOffset):r.endOffset{"use strict";Object.defineProperty(PA,"__esModule",{value:!0});PA.defineNameProp=PA.functionName=PA.classNameFromInstance=void 0;var BIe=Gt();function QIe(r){return Xj(r.constructor)}PA.classNameFromInstance=QIe;var Vj="name";function Xj(r){var e=r.name;return e||"anonymous"}PA.functionName=Xj;function bIe(r,e){var t=Object.getOwnPropertyDescriptor(r,Vj);return(0,BIe.isUndefined)(t)||t.configurable?(Object.defineProperty(r,Vj,{enumerable:!1,configurable:!0,writable:!1,value:e}),!0):!1}PA.defineNameProp=bIe});var tq=w(bi=>{"use strict";Object.defineProperty(bi,"__esModule",{value:!0});bi.validateRedundantMethods=bi.validateMissingCstMethods=bi.validateVisitor=bi.CstVisitorDefinitionError=bi.createBaseVisitorConstructorWithDefaults=bi.createBaseSemanticVisitorConstructor=bi.defaultVisit=void 0;var cs=Gt(),Bd=qv();function _j(r,e){for(var t=(0,cs.keys)(r),i=t.length,n=0;n: - `+(""+s.join(` - -`).replace(/\n/g,` - `)))}}};return t.prototype=i,t.prototype.constructor=t,t._RULE_NAMES=e,t}bi.createBaseSemanticVisitorConstructor=SIe;function vIe(r,e,t){var i=function(){};(0,Bd.defineNameProp)(i,r+"BaseSemanticsWithDefaults");var n=Object.create(t.prototype);return(0,cs.forEach)(e,function(s){n[s]=_j}),i.prototype=n,i.prototype.constructor=i,i}bi.createBaseVisitorConstructorWithDefaults=vIe;var Jv;(function(r){r[r.REDUNDANT_METHOD=0]="REDUNDANT_METHOD",r[r.MISSING_METHOD=1]="MISSING_METHOD"})(Jv=bi.CstVisitorDefinitionError||(bi.CstVisitorDefinitionError={}));function Zj(r,e){var t=$j(r,e),i=eq(r,e);return t.concat(i)}bi.validateVisitor=Zj;function $j(r,e){var t=(0,cs.map)(e,function(i){if(!(0,cs.isFunction)(r[i]))return{msg:"Missing visitor method: <"+i+"> on "+(0,Bd.functionName)(r.constructor)+" CST Visitor.",type:Jv.MISSING_METHOD,methodName:i}});return(0,cs.compact)(t)}bi.validateMissingCstMethods=$j;var xIe=["constructor","visit","validateVisitor"];function eq(r,e){var t=[];for(var i in r)(0,cs.isFunction)(r[i])&&!(0,cs.contains)(xIe,i)&&!(0,cs.contains)(e,i)&&t.push({msg:"Redundant visitor method: <"+i+"> on "+(0,Bd.functionName)(r.constructor)+` CST Visitor -There is no Grammar Rule corresponding to this method's name. -`,type:Jv.REDUNDANT_METHOD,methodName:i});return t}bi.validateRedundantMethods=eq});var iq=w(oy=>{"use strict";Object.defineProperty(oy,"__esModule",{value:!0});oy.TreeBuilder=void 0;var zg=zj(),Zr=Gt(),rq=tq(),PIe=Hn(),DIe=function(){function r(){}return r.prototype.initTreeBuilder=function(e){if(this.CST_STACK=[],this.outputCst=e.outputCst,this.nodeLocationTracking=(0,Zr.has)(e,"nodeLocationTracking")?e.nodeLocationTracking:PIe.DEFAULT_PARSER_CONFIG.nodeLocationTracking,!this.outputCst)this.cstInvocationStateUpdate=Zr.NOOP,this.cstFinallyStateUpdate=Zr.NOOP,this.cstPostTerminal=Zr.NOOP,this.cstPostNonTerminal=Zr.NOOP,this.cstPostRule=Zr.NOOP;else if(/full/i.test(this.nodeLocationTracking))this.recoveryEnabled?(this.setNodeLocationFromToken=zg.setNodeLocationFull,this.setNodeLocationFromNode=zg.setNodeLocationFull,this.cstPostRule=Zr.NOOP,this.setInitialNodeLocation=this.setInitialNodeLocationFullRecovery):(this.setNodeLocationFromToken=Zr.NOOP,this.setNodeLocationFromNode=Zr.NOOP,this.cstPostRule=this.cstPostRuleFull,this.setInitialNodeLocation=this.setInitialNodeLocationFullRegular);else if(/onlyOffset/i.test(this.nodeLocationTracking))this.recoveryEnabled?(this.setNodeLocationFromToken=zg.setNodeLocationOnlyOffset,this.setNodeLocationFromNode=zg.setNodeLocationOnlyOffset,this.cstPostRule=Zr.NOOP,this.setInitialNodeLocation=this.setInitialNodeLocationOnlyOffsetRecovery):(this.setNodeLocationFromToken=Zr.NOOP,this.setNodeLocationFromNode=Zr.NOOP,this.cstPostRule=this.cstPostRuleOnlyOffset,this.setInitialNodeLocation=this.setInitialNodeLocationOnlyOffsetRegular);else if(/none/i.test(this.nodeLocationTracking))this.setNodeLocationFromToken=Zr.NOOP,this.setNodeLocationFromNode=Zr.NOOP,this.cstPostRule=Zr.NOOP,this.setInitialNodeLocation=Zr.NOOP;else throw Error('Invalid config option: "'+e.nodeLocationTracking+'"')},r.prototype.setInitialNodeLocationOnlyOffsetRecovery=function(e){e.location={startOffset:NaN,endOffset:NaN}},r.prototype.setInitialNodeLocationOnlyOffsetRegular=function(e){e.location={startOffset:this.LA(1).startOffset,endOffset:NaN}},r.prototype.setInitialNodeLocationFullRecovery=function(e){e.location={startOffset:NaN,startLine:NaN,startColumn:NaN,endOffset:NaN,endLine:NaN,endColumn:NaN}},r.prototype.setInitialNodeLocationFullRegular=function(e){var t=this.LA(1);e.location={startOffset:t.startOffset,startLine:t.startLine,startColumn:t.startColumn,endOffset:NaN,endLine:NaN,endColumn:NaN}},r.prototype.cstInvocationStateUpdate=function(e,t){var i={name:e,children:{}};this.setInitialNodeLocation(i),this.CST_STACK.push(i)},r.prototype.cstFinallyStateUpdate=function(){this.CST_STACK.pop()},r.prototype.cstPostRuleFull=function(e){var t=this.LA(0),i=e.location;i.startOffset<=t.startOffset?(i.endOffset=t.endOffset,i.endLine=t.endLine,i.endColumn=t.endColumn):(i.startOffset=NaN,i.startLine=NaN,i.startColumn=NaN)},r.prototype.cstPostRuleOnlyOffset=function(e){var t=this.LA(0),i=e.location;i.startOffset<=t.startOffset?i.endOffset=t.endOffset:i.startOffset=NaN},r.prototype.cstPostTerminal=function(e,t){var i=this.CST_STACK[this.CST_STACK.length-1];(0,zg.addTerminalToCst)(i,t,e),this.setNodeLocationFromToken(i.location,t)},r.prototype.cstPostNonTerminal=function(e,t){var i=this.CST_STACK[this.CST_STACK.length-1];(0,zg.addNoneTerminalToCst)(i,t,e),this.setNodeLocationFromNode(i.location,e.location)},r.prototype.getBaseCstVisitorConstructor=function(){if((0,Zr.isUndefined)(this.baseCstVisitorConstructor)){var e=(0,rq.createBaseSemanticVisitorConstructor)(this.className,(0,Zr.keys)(this.gastProductionsCache));return this.baseCstVisitorConstructor=e,e}return this.baseCstVisitorConstructor},r.prototype.getBaseCstVisitorConstructorWithDefaults=function(){if((0,Zr.isUndefined)(this.baseCstVisitorWithDefaultsConstructor)){var e=(0,rq.createBaseVisitorConstructorWithDefaults)(this.className,(0,Zr.keys)(this.gastProductionsCache),this.getBaseCstVisitorConstructor());return this.baseCstVisitorWithDefaultsConstructor=e,e}return this.baseCstVisitorWithDefaultsConstructor},r.prototype.getLastExplicitRuleShortName=function(){var e=this.RULE_STACK;return e[e.length-1]},r.prototype.getPreviousExplicitRuleShortName=function(){var e=this.RULE_STACK;return e[e.length-2]},r.prototype.getLastExplicitRuleOccurrenceIndex=function(){var e=this.RULE_OCCURRENCE_STACK;return e[e.length-1]},r}();oy.TreeBuilder=DIe});var sq=w(ay=>{"use strict";Object.defineProperty(ay,"__esModule",{value:!0});ay.LexerAdapter=void 0;var nq=Hn(),kIe=function(){function r(){}return r.prototype.initLexerAdapter=function(){this.tokVector=[],this.tokVectorLength=0,this.currIdx=-1},Object.defineProperty(r.prototype,"input",{get:function(){return this.tokVector},set:function(e){if(this.selfAnalysisDone!==!0)throw Error("Missing invocation at the end of the Parser's constructor.");this.reset(),this.tokVector=e,this.tokVectorLength=e.length},enumerable:!1,configurable:!0}),r.prototype.SKIP_TOKEN=function(){return this.currIdx<=this.tokVector.length-2?(this.consumeToken(),this.LA(1)):nq.END_OF_FILE},r.prototype.LA=function(e){var t=this.currIdx+e;return t<0||this.tokVectorLength<=t?nq.END_OF_FILE:this.tokVector[t]},r.prototype.consumeToken=function(){this.currIdx++},r.prototype.exportLexerState=function(){return this.currIdx},r.prototype.importLexerState=function(e){this.currIdx=e},r.prototype.resetLexerState=function(){this.currIdx=-1},r.prototype.moveToTerminatedState=function(){this.currIdx=this.tokVector.length-1},r.prototype.getLexerPosition=function(){return this.exportLexerState()},r}();ay.LexerAdapter=kIe});var aq=w(Ay=>{"use strict";Object.defineProperty(Ay,"__esModule",{value:!0});Ay.RecognizerApi=void 0;var oq=Gt(),RIe=Wg(),Wv=Hn(),FIe=Cd(),NIe=Hv(),LIe=dn(),TIe=function(){function r(){}return r.prototype.ACTION=function(e){return e.call(this)},r.prototype.consume=function(e,t,i){return this.consumeInternal(t,e,i)},r.prototype.subrule=function(e,t,i){return this.subruleInternal(t,e,i)},r.prototype.option=function(e,t){return this.optionInternal(t,e)},r.prototype.or=function(e,t){return this.orInternal(t,e)},r.prototype.many=function(e,t){return this.manyInternal(e,t)},r.prototype.atLeastOne=function(e,t){return this.atLeastOneInternal(e,t)},r.prototype.CONSUME=function(e,t){return this.consumeInternal(e,0,t)},r.prototype.CONSUME1=function(e,t){return this.consumeInternal(e,1,t)},r.prototype.CONSUME2=function(e,t){return this.consumeInternal(e,2,t)},r.prototype.CONSUME3=function(e,t){return this.consumeInternal(e,3,t)},r.prototype.CONSUME4=function(e,t){return this.consumeInternal(e,4,t)},r.prototype.CONSUME5=function(e,t){return this.consumeInternal(e,5,t)},r.prototype.CONSUME6=function(e,t){return this.consumeInternal(e,6,t)},r.prototype.CONSUME7=function(e,t){return this.consumeInternal(e,7,t)},r.prototype.CONSUME8=function(e,t){return this.consumeInternal(e,8,t)},r.prototype.CONSUME9=function(e,t){return this.consumeInternal(e,9,t)},r.prototype.SUBRULE=function(e,t){return this.subruleInternal(e,0,t)},r.prototype.SUBRULE1=function(e,t){return this.subruleInternal(e,1,t)},r.prototype.SUBRULE2=function(e,t){return this.subruleInternal(e,2,t)},r.prototype.SUBRULE3=function(e,t){return this.subruleInternal(e,3,t)},r.prototype.SUBRULE4=function(e,t){return this.subruleInternal(e,4,t)},r.prototype.SUBRULE5=function(e,t){return this.subruleInternal(e,5,t)},r.prototype.SUBRULE6=function(e,t){return this.subruleInternal(e,6,t)},r.prototype.SUBRULE7=function(e,t){return this.subruleInternal(e,7,t)},r.prototype.SUBRULE8=function(e,t){return this.subruleInternal(e,8,t)},r.prototype.SUBRULE9=function(e,t){return this.subruleInternal(e,9,t)},r.prototype.OPTION=function(e){return this.optionInternal(e,0)},r.prototype.OPTION1=function(e){return this.optionInternal(e,1)},r.prototype.OPTION2=function(e){return this.optionInternal(e,2)},r.prototype.OPTION3=function(e){return this.optionInternal(e,3)},r.prototype.OPTION4=function(e){return this.optionInternal(e,4)},r.prototype.OPTION5=function(e){return this.optionInternal(e,5)},r.prototype.OPTION6=function(e){return this.optionInternal(e,6)},r.prototype.OPTION7=function(e){return this.optionInternal(e,7)},r.prototype.OPTION8=function(e){return this.optionInternal(e,8)},r.prototype.OPTION9=function(e){return this.optionInternal(e,9)},r.prototype.OR=function(e){return this.orInternal(e,0)},r.prototype.OR1=function(e){return this.orInternal(e,1)},r.prototype.OR2=function(e){return this.orInternal(e,2)},r.prototype.OR3=function(e){return this.orInternal(e,3)},r.prototype.OR4=function(e){return this.orInternal(e,4)},r.prototype.OR5=function(e){return this.orInternal(e,5)},r.prototype.OR6=function(e){return this.orInternal(e,6)},r.prototype.OR7=function(e){return this.orInternal(e,7)},r.prototype.OR8=function(e){return this.orInternal(e,8)},r.prototype.OR9=function(e){return this.orInternal(e,9)},r.prototype.MANY=function(e){this.manyInternal(0,e)},r.prototype.MANY1=function(e){this.manyInternal(1,e)},r.prototype.MANY2=function(e){this.manyInternal(2,e)},r.prototype.MANY3=function(e){this.manyInternal(3,e)},r.prototype.MANY4=function(e){this.manyInternal(4,e)},r.prototype.MANY5=function(e){this.manyInternal(5,e)},r.prototype.MANY6=function(e){this.manyInternal(6,e)},r.prototype.MANY7=function(e){this.manyInternal(7,e)},r.prototype.MANY8=function(e){this.manyInternal(8,e)},r.prototype.MANY9=function(e){this.manyInternal(9,e)},r.prototype.MANY_SEP=function(e){this.manySepFirstInternal(0,e)},r.prototype.MANY_SEP1=function(e){this.manySepFirstInternal(1,e)},r.prototype.MANY_SEP2=function(e){this.manySepFirstInternal(2,e)},r.prototype.MANY_SEP3=function(e){this.manySepFirstInternal(3,e)},r.prototype.MANY_SEP4=function(e){this.manySepFirstInternal(4,e)},r.prototype.MANY_SEP5=function(e){this.manySepFirstInternal(5,e)},r.prototype.MANY_SEP6=function(e){this.manySepFirstInternal(6,e)},r.prototype.MANY_SEP7=function(e){this.manySepFirstInternal(7,e)},r.prototype.MANY_SEP8=function(e){this.manySepFirstInternal(8,e)},r.prototype.MANY_SEP9=function(e){this.manySepFirstInternal(9,e)},r.prototype.AT_LEAST_ONE=function(e){this.atLeastOneInternal(0,e)},r.prototype.AT_LEAST_ONE1=function(e){return this.atLeastOneInternal(1,e)},r.prototype.AT_LEAST_ONE2=function(e){this.atLeastOneInternal(2,e)},r.prototype.AT_LEAST_ONE3=function(e){this.atLeastOneInternal(3,e)},r.prototype.AT_LEAST_ONE4=function(e){this.atLeastOneInternal(4,e)},r.prototype.AT_LEAST_ONE5=function(e){this.atLeastOneInternal(5,e)},r.prototype.AT_LEAST_ONE6=function(e){this.atLeastOneInternal(6,e)},r.prototype.AT_LEAST_ONE7=function(e){this.atLeastOneInternal(7,e)},r.prototype.AT_LEAST_ONE8=function(e){this.atLeastOneInternal(8,e)},r.prototype.AT_LEAST_ONE9=function(e){this.atLeastOneInternal(9,e)},r.prototype.AT_LEAST_ONE_SEP=function(e){this.atLeastOneSepFirstInternal(0,e)},r.prototype.AT_LEAST_ONE_SEP1=function(e){this.atLeastOneSepFirstInternal(1,e)},r.prototype.AT_LEAST_ONE_SEP2=function(e){this.atLeastOneSepFirstInternal(2,e)},r.prototype.AT_LEAST_ONE_SEP3=function(e){this.atLeastOneSepFirstInternal(3,e)},r.prototype.AT_LEAST_ONE_SEP4=function(e){this.atLeastOneSepFirstInternal(4,e)},r.prototype.AT_LEAST_ONE_SEP5=function(e){this.atLeastOneSepFirstInternal(5,e)},r.prototype.AT_LEAST_ONE_SEP6=function(e){this.atLeastOneSepFirstInternal(6,e)},r.prototype.AT_LEAST_ONE_SEP7=function(e){this.atLeastOneSepFirstInternal(7,e)},r.prototype.AT_LEAST_ONE_SEP8=function(e){this.atLeastOneSepFirstInternal(8,e)},r.prototype.AT_LEAST_ONE_SEP9=function(e){this.atLeastOneSepFirstInternal(9,e)},r.prototype.RULE=function(e,t,i){if(i===void 0&&(i=Wv.DEFAULT_RULE_CONFIG),(0,oq.contains)(this.definedRulesNames,e)){var n=FIe.defaultGrammarValidatorErrorProvider.buildDuplicateRuleNameError({topLevelRule:e,grammarName:this.className}),s={message:n,type:Wv.ParserDefinitionErrorType.DUPLICATE_RULE_NAME,ruleName:e};this.definitionErrors.push(s)}this.definedRulesNames.push(e);var o=this.defineRule(e,t,i);return this[e]=o,o},r.prototype.OVERRIDE_RULE=function(e,t,i){i===void 0&&(i=Wv.DEFAULT_RULE_CONFIG);var n=[];n=n.concat((0,NIe.validateRuleIsOverridden)(e,this.definedRulesNames,this.className)),this.definitionErrors=this.definitionErrors.concat(n);var s=this.defineRule(e,t,i);return this[e]=s,s},r.prototype.BACKTRACK=function(e,t){return function(){this.isBackTrackingStack.push(1);var i=this.saveRecogState();try{return e.apply(this,t),!0}catch(n){if((0,RIe.isRecognitionException)(n))return!1;throw n}finally{this.reloadRecogState(i),this.isBackTrackingStack.pop()}}},r.prototype.getGAstProductions=function(){return this.gastProductionsCache},r.prototype.getSerializedGastProductions=function(){return(0,LIe.serializeGrammar)((0,oq.values)(this.gastProductionsCache))},r}();Ay.RecognizerApi=TIe});var uq=w(cy=>{"use strict";Object.defineProperty(cy,"__esModule",{value:!0});cy.RecognizerEngine=void 0;var Pr=Gt(),Gn=ny(),ly=Wg(),Aq=Id(),Vg=Ed(),lq=Hn(),OIe=jv(),cq=SA(),Qd=Gg(),MIe=qv(),KIe=function(){function r(){}return r.prototype.initRecognizerEngine=function(e,t){if(this.className=(0,MIe.classNameFromInstance)(this),this.shortRuleNameToFull={},this.fullRuleNameToShort={},this.ruleShortNameIdx=256,this.tokenMatcher=Qd.tokenStructuredMatcherNoCategories,this.definedRulesNames=[],this.tokensMap={},this.isBackTrackingStack=[],this.RULE_STACK=[],this.RULE_OCCURRENCE_STACK=[],this.gastProductionsCache={},(0,Pr.has)(t,"serializedGrammar"))throw Error(`The Parser's configuration can no longer contain a property. - See: https://chevrotain.io/docs/changes/BREAKING_CHANGES.html#_6-0-0 - For Further details.`);if((0,Pr.isArray)(e)){if((0,Pr.isEmpty)(e))throw Error(`A Token Vocabulary cannot be empty. - Note that the first argument for the parser constructor - is no longer a Token vector (since v4.0).`);if(typeof e[0].startOffset=="number")throw Error(`The Parser constructor no longer accepts a token vector as the first argument. - See: https://chevrotain.io/docs/changes/BREAKING_CHANGES.html#_4-0-0 - For Further details.`)}if((0,Pr.isArray)(e))this.tokensMap=(0,Pr.reduce)(e,function(o,a){return o[a.name]=a,o},{});else if((0,Pr.has)(e,"modes")&&(0,Pr.every)((0,Pr.flatten)((0,Pr.values)(e.modes)),Qd.isTokenType)){var i=(0,Pr.flatten)((0,Pr.values)(e.modes)),n=(0,Pr.uniq)(i);this.tokensMap=(0,Pr.reduce)(n,function(o,a){return o[a.name]=a,o},{})}else if((0,Pr.isObject)(e))this.tokensMap=(0,Pr.cloneObj)(e);else throw new Error(" argument must be An Array of Token constructors, A dictionary of Token constructors or an IMultiModeLexerDefinition");this.tokensMap.EOF=cq.EOF;var s=(0,Pr.every)((0,Pr.values)(e),function(o){return(0,Pr.isEmpty)(o.categoryMatches)});this.tokenMatcher=s?Qd.tokenStructuredMatcherNoCategories:Qd.tokenStructuredMatcher,(0,Qd.augmentTokenTypes)((0,Pr.values)(this.tokensMap))},r.prototype.defineRule=function(e,t,i){if(this.selfAnalysisDone)throw Error("Grammar rule <"+e+`> may not be defined after the 'performSelfAnalysis' method has been called' -Make sure that all grammar rule definitions are done before 'performSelfAnalysis' is called.`);var n=(0,Pr.has)(i,"resyncEnabled")?i.resyncEnabled:lq.DEFAULT_RULE_CONFIG.resyncEnabled,s=(0,Pr.has)(i,"recoveryValueFunc")?i.recoveryValueFunc:lq.DEFAULT_RULE_CONFIG.recoveryValueFunc,o=this.ruleShortNameIdx<t},r.prototype.orInternal=function(e,t){var i=this.getKeyForAutomaticLookahead(Gn.OR_IDX,t),n=(0,Pr.isArray)(e)?e:e.DEF,s=this.getLaFuncFromCache(i),o=s.call(this,n);if(o!==void 0){var a=n[o];return a.ALT.call(this)}this.raiseNoAltException(t,e.ERR_MSG)},r.prototype.ruleFinallyStateUpdate=function(){if(this.RULE_STACK.pop(),this.RULE_OCCURRENCE_STACK.pop(),this.cstFinallyStateUpdate(),this.RULE_STACK.length===0&&this.isAtEndOfInput()===!1){var e=this.LA(1),t=this.errorMessageProvider.buildNotAllInputParsedMessage({firstRedundant:e,ruleName:this.getCurrRuleFullName()});this.SAVE_ERROR(new ly.NotAllInputParsedException(t,e))}},r.prototype.subruleInternal=function(e,t,i){var n;try{var s=i!==void 0?i.ARGS:void 0;return n=e.call(this,t,s),this.cstPostNonTerminal(n,i!==void 0&&i.LABEL!==void 0?i.LABEL:e.ruleName),n}catch(o){this.subruleInternalError(o,i,e.ruleName)}},r.prototype.subruleInternalError=function(e,t,i){throw(0,ly.isRecognitionException)(e)&&e.partialCstResult!==void 0&&(this.cstPostNonTerminal(e.partialCstResult,t!==void 0&&t.LABEL!==void 0?t.LABEL:i),delete e.partialCstResult),e},r.prototype.consumeInternal=function(e,t,i){var n;try{var s=this.LA(1);this.tokenMatcher(s,e)===!0?(this.consumeToken(),n=s):this.consumeInternalError(e,s,i)}catch(o){n=this.consumeInternalRecovery(e,t,o)}return this.cstPostTerminal(i!==void 0&&i.LABEL!==void 0?i.LABEL:e.name,n),n},r.prototype.consumeInternalError=function(e,t,i){var n,s=this.LA(0);throw i!==void 0&&i.ERR_MSG?n=i.ERR_MSG:n=this.errorMessageProvider.buildMismatchTokenMessage({expected:e,actual:t,previous:s,ruleName:this.getCurrRuleFullName()}),this.SAVE_ERROR(new ly.MismatchedTokenException(n,t,s))},r.prototype.consumeInternalRecovery=function(e,t,i){if(this.recoveryEnabled&&i.name==="MismatchedTokenException"&&!this.isBackTracking()){var n=this.getFollowsForInRuleRecovery(e,t);try{return this.tryInRuleRecovery(e,n)}catch(s){throw s.name===OIe.IN_RULE_RECOVERY_EXCEPTION?i:s}}else throw i},r.prototype.saveRecogState=function(){var e=this.errors,t=(0,Pr.cloneArr)(this.RULE_STACK);return{errors:e,lexerState:this.exportLexerState(),RULE_STACK:t,CST_STACK:this.CST_STACK}},r.prototype.reloadRecogState=function(e){this.errors=e.errors,this.importLexerState(e.lexerState),this.RULE_STACK=e.RULE_STACK},r.prototype.ruleInvocationStateUpdate=function(e,t,i){this.RULE_OCCURRENCE_STACK.push(i),this.RULE_STACK.push(e),this.cstInvocationStateUpdate(t,e)},r.prototype.isBackTracking=function(){return this.isBackTrackingStack.length!==0},r.prototype.getCurrRuleFullName=function(){var e=this.getLastExplicitRuleShortName();return this.shortRuleNameToFull[e]},r.prototype.shortRuleNameToFullName=function(e){return this.shortRuleNameToFull[e]},r.prototype.isAtEndOfInput=function(){return this.tokenMatcher(this.LA(1),cq.EOF)},r.prototype.reset=function(){this.resetLexerState(),this.isBackTrackingStack=[],this.errors=[],this.RULE_STACK=[],this.CST_STACK=[],this.RULE_OCCURRENCE_STACK=[]},r}();cy.RecognizerEngine=KIe});var fq=w(uy=>{"use strict";Object.defineProperty(uy,"__esModule",{value:!0});uy.ErrorHandler=void 0;var zv=Wg(),Vv=Gt(),gq=Id(),UIe=Hn(),HIe=function(){function r(){}return r.prototype.initErrorHandler=function(e){this._errors=[],this.errorMessageProvider=(0,Vv.has)(e,"errorMessageProvider")?e.errorMessageProvider:UIe.DEFAULT_PARSER_CONFIG.errorMessageProvider},r.prototype.SAVE_ERROR=function(e){if((0,zv.isRecognitionException)(e))return e.context={ruleStack:this.getHumanReadableRuleStack(),ruleOccurrenceStack:(0,Vv.cloneArr)(this.RULE_OCCURRENCE_STACK)},this._errors.push(e),e;throw Error("Trying to save an Error which is not a RecognitionException")},Object.defineProperty(r.prototype,"errors",{get:function(){return(0,Vv.cloneArr)(this._errors)},set:function(e){this._errors=e},enumerable:!1,configurable:!0}),r.prototype.raiseEarlyExitException=function(e,t,i){for(var n=this.getCurrRuleFullName(),s=this.getGAstProductions()[n],o=(0,gq.getLookaheadPathsForOptionalProd)(e,s,t,this.maxLookahead),a=o[0],l=[],c=1;c<=this.maxLookahead;c++)l.push(this.LA(c));var u=this.errorMessageProvider.buildEarlyExitMessage({expectedIterationPaths:a,actual:l,previous:this.LA(0),customUserDescription:i,ruleName:n});throw this.SAVE_ERROR(new zv.EarlyExitException(u,this.LA(1),this.LA(0)))},r.prototype.raiseNoAltException=function(e,t){for(var i=this.getCurrRuleFullName(),n=this.getGAstProductions()[i],s=(0,gq.getLookaheadPathsForOr)(e,n,this.maxLookahead),o=[],a=1;a<=this.maxLookahead;a++)o.push(this.LA(a));var l=this.LA(0),c=this.errorMessageProvider.buildNoViableAltMessage({expectedPathsPerAlt:s,actual:o,previous:l,customUserDescription:t,ruleName:this.getCurrRuleFullName()});throw this.SAVE_ERROR(new zv.NoViableAltException(c,this.LA(1),l))},r}();uy.ErrorHandler=HIe});var dq=w(gy=>{"use strict";Object.defineProperty(gy,"__esModule",{value:!0});gy.ContentAssist=void 0;var hq=Ed(),pq=Gt(),GIe=function(){function r(){}return r.prototype.initContentAssist=function(){},r.prototype.computeContentAssist=function(e,t){var i=this.gastProductionsCache[e];if((0,pq.isUndefined)(i))throw Error("Rule ->"+e+"<- does not exist in this grammar.");return(0,hq.nextPossibleTokensAfter)([i],t,this.tokenMatcher,this.maxLookahead)},r.prototype.getNextPossibleTokenTypes=function(e){var t=(0,pq.first)(e.ruleStack),i=this.getGAstProductions(),n=i[t],s=new hq.NextAfterTokenWalker(n,e).startWalking();return s},r}();gy.ContentAssist=GIe});var Qq=w(py=>{"use strict";Object.defineProperty(py,"__esModule",{value:!0});py.GastRecorder=void 0;var En=Gt(),Ro=dn(),YIe=gd(),Iq=Gg(),yq=SA(),jIe=Hn(),qIe=ny(),hy={description:"This Object indicates the Parser is during Recording Phase"};Object.freeze(hy);var Cq=!0,mq=Math.pow(2,qIe.BITS_FOR_OCCURRENCE_IDX)-1,wq=(0,yq.createToken)({name:"RECORDING_PHASE_TOKEN",pattern:YIe.Lexer.NA});(0,Iq.augmentTokenTypes)([wq]);var Bq=(0,yq.createTokenInstance)(wq,`This IToken indicates the Parser is in Recording Phase - See: https://chevrotain.io/docs/guide/internals.html#grammar-recording for details`,-1,-1,-1,-1,-1,-1);Object.freeze(Bq);var JIe={name:`This CSTNode indicates the Parser is in Recording Phase - See: https://chevrotain.io/docs/guide/internals.html#grammar-recording for details`,children:{}},WIe=function(){function r(){}return r.prototype.initGastRecorder=function(e){this.recordingProdStack=[],this.RECORDING_PHASE=!1},r.prototype.enableRecording=function(){var e=this;this.RECORDING_PHASE=!0,this.TRACE_INIT("Enable Recording",function(){for(var t=function(n){var s=n>0?n:"";e["CONSUME"+s]=function(o,a){return this.consumeInternalRecord(o,n,a)},e["SUBRULE"+s]=function(o,a){return this.subruleInternalRecord(o,n,a)},e["OPTION"+s]=function(o){return this.optionInternalRecord(o,n)},e["OR"+s]=function(o){return this.orInternalRecord(o,n)},e["MANY"+s]=function(o){this.manyInternalRecord(n,o)},e["MANY_SEP"+s]=function(o){this.manySepFirstInternalRecord(n,o)},e["AT_LEAST_ONE"+s]=function(o){this.atLeastOneInternalRecord(n,o)},e["AT_LEAST_ONE_SEP"+s]=function(o){this.atLeastOneSepFirstInternalRecord(n,o)}},i=0;i<10;i++)t(i);e.consume=function(n,s,o){return this.consumeInternalRecord(s,n,o)},e.subrule=function(n,s,o){return this.subruleInternalRecord(s,n,o)},e.option=function(n,s){return this.optionInternalRecord(s,n)},e.or=function(n,s){return this.orInternalRecord(s,n)},e.many=function(n,s){this.manyInternalRecord(n,s)},e.atLeastOne=function(n,s){this.atLeastOneInternalRecord(n,s)},e.ACTION=e.ACTION_RECORD,e.BACKTRACK=e.BACKTRACK_RECORD,e.LA=e.LA_RECORD})},r.prototype.disableRecording=function(){var e=this;this.RECORDING_PHASE=!1,this.TRACE_INIT("Deleting Recording methods",function(){for(var t=0;t<10;t++){var i=t>0?t:"";delete e["CONSUME"+i],delete e["SUBRULE"+i],delete e["OPTION"+i],delete e["OR"+i],delete e["MANY"+i],delete e["MANY_SEP"+i],delete e["AT_LEAST_ONE"+i],delete e["AT_LEAST_ONE_SEP"+i]}delete e.consume,delete e.subrule,delete e.option,delete e.or,delete e.many,delete e.atLeastOne,delete e.ACTION,delete e.BACKTRACK,delete e.LA})},r.prototype.ACTION_RECORD=function(e){},r.prototype.BACKTRACK_RECORD=function(e,t){return function(){return!0}},r.prototype.LA_RECORD=function(e){return jIe.END_OF_FILE},r.prototype.topLevelRuleRecord=function(e,t){try{var i=new Ro.Rule({definition:[],name:e});return i.name=e,this.recordingProdStack.push(i),t.call(this),this.recordingProdStack.pop(),i}catch(n){if(n.KNOWN_RECORDER_ERROR!==!0)try{n.message=n.message+` - This error was thrown during the "grammar recording phase" For more info see: - https://chevrotain.io/docs/guide/internals.html#grammar-recording`}catch{throw n}throw n}},r.prototype.optionInternalRecord=function(e,t){return bd.call(this,Ro.Option,e,t)},r.prototype.atLeastOneInternalRecord=function(e,t){bd.call(this,Ro.RepetitionMandatory,t,e)},r.prototype.atLeastOneSepFirstInternalRecord=function(e,t){bd.call(this,Ro.RepetitionMandatoryWithSeparator,t,e,Cq)},r.prototype.manyInternalRecord=function(e,t){bd.call(this,Ro.Repetition,t,e)},r.prototype.manySepFirstInternalRecord=function(e,t){bd.call(this,Ro.RepetitionWithSeparator,t,e,Cq)},r.prototype.orInternalRecord=function(e,t){return zIe.call(this,e,t)},r.prototype.subruleInternalRecord=function(e,t,i){if(fy(t),!e||(0,En.has)(e,"ruleName")===!1){var n=new Error(" argument is invalid"+(" expecting a Parser method reference but got: <"+JSON.stringify(e)+">")+(` - inside top level rule: <`+this.recordingProdStack[0].name+">"));throw n.KNOWN_RECORDER_ERROR=!0,n}var s=(0,En.peek)(this.recordingProdStack),o=e.ruleName,a=new Ro.NonTerminal({idx:t,nonTerminalName:o,label:i==null?void 0:i.LABEL,referencedRule:void 0});return s.definition.push(a),this.outputCst?JIe:hy},r.prototype.consumeInternalRecord=function(e,t,i){if(fy(t),!(0,Iq.hasShortKeyProperty)(e)){var n=new Error(" argument is invalid"+(" expecting a TokenType reference but got: <"+JSON.stringify(e)+">")+(` - inside top level rule: <`+this.recordingProdStack[0].name+">"));throw n.KNOWN_RECORDER_ERROR=!0,n}var s=(0,En.peek)(this.recordingProdStack),o=new Ro.Terminal({idx:t,terminalType:e,label:i==null?void 0:i.LABEL});return s.definition.push(o),Bq},r}();py.GastRecorder=WIe;function bd(r,e,t,i){i===void 0&&(i=!1),fy(t);var n=(0,En.peek)(this.recordingProdStack),s=(0,En.isFunction)(e)?e:e.DEF,o=new r({definition:[],idx:t});return i&&(o.separator=e.SEP),(0,En.has)(e,"MAX_LOOKAHEAD")&&(o.maxLookahead=e.MAX_LOOKAHEAD),this.recordingProdStack.push(o),s.call(this),n.definition.push(o),this.recordingProdStack.pop(),hy}function zIe(r,e){var t=this;fy(e);var i=(0,En.peek)(this.recordingProdStack),n=(0,En.isArray)(r)===!1,s=n===!1?r:r.DEF,o=new Ro.Alternation({definition:[],idx:e,ignoreAmbiguities:n&&r.IGNORE_AMBIGUITIES===!0});(0,En.has)(r,"MAX_LOOKAHEAD")&&(o.maxLookahead=r.MAX_LOOKAHEAD);var a=(0,En.some)(s,function(l){return(0,En.isFunction)(l.GATE)});return o.hasPredicates=a,i.definition.push(o),(0,En.forEach)(s,function(l){var c=new Ro.Alternative({definition:[]});o.definition.push(c),(0,En.has)(l,"IGNORE_AMBIGUITIES")?c.ignoreAmbiguities=l.IGNORE_AMBIGUITIES:(0,En.has)(l,"GATE")&&(c.ignoreAmbiguities=!0),t.recordingProdStack.push(c),l.ALT.call(t),t.recordingProdStack.pop()}),hy}function Eq(r){return r===0?"":""+r}function fy(r){if(r<0||r>mq){var e=new Error("Invalid DSL Method idx value: <"+r+`> - `+("Idx value must be a none negative value smaller than "+(mq+1)));throw e.KNOWN_RECORDER_ERROR=!0,e}}});var Sq=w(dy=>{"use strict";Object.defineProperty(dy,"__esModule",{value:!0});dy.PerformanceTracer=void 0;var bq=Gt(),VIe=Hn(),XIe=function(){function r(){}return r.prototype.initPerformanceTracer=function(e){if((0,bq.has)(e,"traceInitPerf")){var t=e.traceInitPerf,i=typeof t=="number";this.traceInitMaxIdent=i?t:1/0,this.traceInitPerf=i?t>0:t}else this.traceInitMaxIdent=0,this.traceInitPerf=VIe.DEFAULT_PARSER_CONFIG.traceInitPerf;this.traceInitIndent=-1},r.prototype.TRACE_INIT=function(e,t){if(this.traceInitPerf===!0){this.traceInitIndent++;var i=new Array(this.traceInitIndent+1).join(" ");this.traceInitIndent <"+e+">");var n=(0,bq.timer)(t),s=n.time,o=n.value,a=s>10?console.warn:console.log;return this.traceInitIndent time: "+s+"ms"),this.traceInitIndent--,o}else return t()},r}();dy.PerformanceTracer=XIe});var vq=w(Cy=>{"use strict";Object.defineProperty(Cy,"__esModule",{value:!0});Cy.applyMixins=void 0;function _Ie(r,e){e.forEach(function(t){var i=t.prototype;Object.getOwnPropertyNames(i).forEach(function(n){if(n!=="constructor"){var s=Object.getOwnPropertyDescriptor(i,n);s&&(s.get||s.set)?Object.defineProperty(r.prototype,n,s):r.prototype[n]=t.prototype[n]}})})}Cy.applyMixins=_Ie});var Hn=w(dr=>{"use strict";var Dq=dr&&dr.__extends||function(){var r=function(e,t){return r=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(i,n){i.__proto__=n}||function(i,n){for(var s in n)Object.prototype.hasOwnProperty.call(n,s)&&(i[s]=n[s])},r(e,t)};return function(e,t){if(typeof t!="function"&&t!==null)throw new TypeError("Class extends value "+String(t)+" is not a constructor or null");r(e,t);function i(){this.constructor=e}e.prototype=t===null?Object.create(t):(i.prototype=t.prototype,new i)}}();Object.defineProperty(dr,"__esModule",{value:!0});dr.EmbeddedActionsParser=dr.CstParser=dr.Parser=dr.EMPTY_ALT=dr.ParserDefinitionErrorType=dr.DEFAULT_RULE_CONFIG=dr.DEFAULT_PARSER_CONFIG=dr.END_OF_FILE=void 0;var Xi=Gt(),ZIe=fj(),xq=SA(),kq=Cd(),Pq=Kj(),$Ie=jv(),eye=Wj(),tye=iq(),rye=sq(),iye=aq(),nye=uq(),sye=fq(),oye=dq(),aye=Qq(),Aye=Sq(),lye=vq();dr.END_OF_FILE=(0,xq.createTokenInstance)(xq.EOF,"",NaN,NaN,NaN,NaN,NaN,NaN);Object.freeze(dr.END_OF_FILE);dr.DEFAULT_PARSER_CONFIG=Object.freeze({recoveryEnabled:!1,maxLookahead:3,dynamicTokensEnabled:!1,outputCst:!0,errorMessageProvider:kq.defaultParserErrorProvider,nodeLocationTracking:"none",traceInitPerf:!1,skipValidations:!1});dr.DEFAULT_RULE_CONFIG=Object.freeze({recoveryValueFunc:function(){},resyncEnabled:!0});var cye;(function(r){r[r.INVALID_RULE_NAME=0]="INVALID_RULE_NAME",r[r.DUPLICATE_RULE_NAME=1]="DUPLICATE_RULE_NAME",r[r.INVALID_RULE_OVERRIDE=2]="INVALID_RULE_OVERRIDE",r[r.DUPLICATE_PRODUCTIONS=3]="DUPLICATE_PRODUCTIONS",r[r.UNRESOLVED_SUBRULE_REF=4]="UNRESOLVED_SUBRULE_REF",r[r.LEFT_RECURSION=5]="LEFT_RECURSION",r[r.NONE_LAST_EMPTY_ALT=6]="NONE_LAST_EMPTY_ALT",r[r.AMBIGUOUS_ALTS=7]="AMBIGUOUS_ALTS",r[r.CONFLICT_TOKENS_RULES_NAMESPACE=8]="CONFLICT_TOKENS_RULES_NAMESPACE",r[r.INVALID_TOKEN_NAME=9]="INVALID_TOKEN_NAME",r[r.NO_NON_EMPTY_LOOKAHEAD=10]="NO_NON_EMPTY_LOOKAHEAD",r[r.AMBIGUOUS_PREFIX_ALTS=11]="AMBIGUOUS_PREFIX_ALTS",r[r.TOO_MANY_ALTS=12]="TOO_MANY_ALTS"})(cye=dr.ParserDefinitionErrorType||(dr.ParserDefinitionErrorType={}));function uye(r){return r===void 0&&(r=void 0),function(){return r}}dr.EMPTY_ALT=uye;var my=function(){function r(e,t){this.definitionErrors=[],this.selfAnalysisDone=!1;var i=this;if(i.initErrorHandler(t),i.initLexerAdapter(),i.initLooksAhead(t),i.initRecognizerEngine(e,t),i.initRecoverable(t),i.initTreeBuilder(t),i.initContentAssist(),i.initGastRecorder(t),i.initPerformanceTracer(t),(0,Xi.has)(t,"ignoredIssues"))throw new Error(`The IParserConfig property has been deprecated. - Please use the flag on the relevant DSL method instead. - See: https://chevrotain.io/docs/guide/resolving_grammar_errors.html#IGNORING_AMBIGUITIES - For further details.`);this.skipValidations=(0,Xi.has)(t,"skipValidations")?t.skipValidations:dr.DEFAULT_PARSER_CONFIG.skipValidations}return r.performSelfAnalysis=function(e){throw Error("The **static** `performSelfAnalysis` method has been deprecated. \nUse the **instance** method with the same name instead.")},r.prototype.performSelfAnalysis=function(){var e=this;this.TRACE_INIT("performSelfAnalysis",function(){var t;e.selfAnalysisDone=!0;var i=e.className;e.TRACE_INIT("toFastProps",function(){(0,Xi.toFastProperties)(e)}),e.TRACE_INIT("Grammar Recording",function(){try{e.enableRecording(),(0,Xi.forEach)(e.definedRulesNames,function(s){var o=e[s],a=o.originalGrammarAction,l=void 0;e.TRACE_INIT(s+" Rule",function(){l=e.topLevelRuleRecord(s,a)}),e.gastProductionsCache[s]=l})}finally{e.disableRecording()}});var n=[];if(e.TRACE_INIT("Grammar Resolving",function(){n=(0,Pq.resolveGrammar)({rules:(0,Xi.values)(e.gastProductionsCache)}),e.definitionErrors=e.definitionErrors.concat(n)}),e.TRACE_INIT("Grammar Validations",function(){if((0,Xi.isEmpty)(n)&&e.skipValidations===!1){var s=(0,Pq.validateGrammar)({rules:(0,Xi.values)(e.gastProductionsCache),maxLookahead:e.maxLookahead,tokenTypes:(0,Xi.values)(e.tokensMap),errMsgProvider:kq.defaultGrammarValidatorErrorProvider,grammarName:i});e.definitionErrors=e.definitionErrors.concat(s)}}),(0,Xi.isEmpty)(e.definitionErrors)&&(e.recoveryEnabled&&e.TRACE_INIT("computeAllProdsFollows",function(){var s=(0,ZIe.computeAllProdsFollows)((0,Xi.values)(e.gastProductionsCache));e.resyncFollows=s}),e.TRACE_INIT("ComputeLookaheadFunctions",function(){e.preComputeLookaheadFunctions((0,Xi.values)(e.gastProductionsCache))})),!r.DEFER_DEFINITION_ERRORS_HANDLING&&!(0,Xi.isEmpty)(e.definitionErrors))throw t=(0,Xi.map)(e.definitionErrors,function(s){return s.message}),new Error(`Parser Definition Errors detected: - `+t.join(` -------------------------------- -`))})},r.DEFER_DEFINITION_ERRORS_HANDLING=!1,r}();dr.Parser=my;(0,lye.applyMixins)(my,[$Ie.Recoverable,eye.LooksAhead,tye.TreeBuilder,rye.LexerAdapter,nye.RecognizerEngine,iye.RecognizerApi,sye.ErrorHandler,oye.ContentAssist,aye.GastRecorder,Aye.PerformanceTracer]);var gye=function(r){Dq(e,r);function e(t,i){i===void 0&&(i=dr.DEFAULT_PARSER_CONFIG);var n=this,s=(0,Xi.cloneObj)(i);return s.outputCst=!0,n=r.call(this,t,s)||this,n}return e}(my);dr.CstParser=gye;var fye=function(r){Dq(e,r);function e(t,i){i===void 0&&(i=dr.DEFAULT_PARSER_CONFIG);var n=this,s=(0,Xi.cloneObj)(i);return s.outputCst=!1,n=r.call(this,t,s)||this,n}return e}(my);dr.EmbeddedActionsParser=fye});var Fq=w(Ey=>{"use strict";Object.defineProperty(Ey,"__esModule",{value:!0});Ey.createSyntaxDiagramsCode=void 0;var Rq=pv();function hye(r,e){var t=e===void 0?{}:e,i=t.resourceBase,n=i===void 0?"https://unpkg.com/chevrotain@"+Rq.VERSION+"/diagrams/":i,s=t.css,o=s===void 0?"https://unpkg.com/chevrotain@"+Rq.VERSION+"/diagrams/diagrams.css":s,a=` - - - - - -`,l=` - -`,c=` - - - -
- + + + + + +
+ -
-
-
-
- -
-
-
-
-

- Custom YouTube Music Desktop App -

-

- Open source, cross-platform, unofficial YouTube Music Desktop - App with built-in ad blocker and - downloader -

-
- Download -
-
-
-
- YouTube Music -
-
-
-
-
+
+
+
+
+ +
+
+
+
+

+ Custom YouTube Music Desktop App +

+

+ Open source, cross-platform, unofficial YouTube Music Desktop + App with built-in ad blocker and + downloader +

+
+ Download +
+
+
+
+ YouTube Music +
+
+
+
+
-
-
-
-
-
-
- Adblocker +
+
+
+
+
+ Adblocker -
-
+
+
-

Built-in adblocker

-

Block all ads and tracking out of the box

-
-
-
-
- DownloaderBuilt-in adblocker +

Block all ads and tracking out of the box

+
+
+
+
+ Downloader -
-
-

Built-in downloader

-

- Download (like youtube-dl) to custom formats (mp3, opus, - etc) directly from the interface -

-
-
-
-
- PluginsBuilt-in downloader +

+ Download (like youtube-dl) to custom formats (mp3, opus, + etc) directly from the interface +

+
+
+
+
+ Plugins -
-
-

Many other plugins in one click

-

- Enhance your user experience with media keys, integrations - (Discord), cosmetic filters, notifications, TouchBar, - auto-unpause and many more! Every plugin can be enabled or - disabled in one click. -

-
-
-
-
- CodeMany other plugins in one click +

+ Enhance your user experience with media keys, integrations + (Discord), cosmetic filters, notifications, TouchBar, + auto-unpause and many more! Every plugin can be enabled or + disabled in one click. +

+
+
+
+
+ Code -
-
-

Open source & Cross platform

-

- Available for Windows (installer and portable), Mac and - Linux (AppImage, deb, etc) -

-
-
-
-
-
-
- -
-
-
+ > +

Open source & Cross platform

+

+ Available for Windows (installer and portable), Mac and + Linux (AppImage, deb, etc) +

+
+
+ + + +
+ +
+ + - - + + - - + + diff --git a/docs/js/main.js b/docs/js/main.js index ed47bfc1..d7587ce9 100644 --- a/docs/js/main.js +++ b/docs/js/main.js @@ -1,46 +1,49 @@ +/* eslint-disable */ + // Constants -const element = document.documentElement, - body = document.body, - revealOnScroll = (window.sr = ScrollReveal({ mobile: false })); +const element = document.documentElement; +const { body } = document; +const revealOnScroll = (window.sr = ScrollReveal({ mobile: false })); // Load animations -element.classList.remove("no-js"); -element.classList.add("js"); -window.addEventListener("load", function () { - body.classList.add("is-loaded"); +element.classList.remove('no-js'); +element.classList.add('js'); +window.addEventListener('load', () => { + body.classList.add('is-loaded'); }); -if (body.classList.contains("has-animations")) { - window.addEventListener("load", function () { - revealOnScroll.reveal(".feature-extended .device-mockup", { +if (body.classList.contains('has-animations')) { + window.addEventListener('load', () => { + revealOnScroll.reveal('.feature-extended .device-mockup', { duration: 600, - distance: "100px", - easing: "cubic-bezier(0.215, 0.61, 0.355, 1)", - origin: "bottom", + distance: '100px', + easing: 'cubic-bezier(0.215, 0.61, 0.355, 1)', + origin: 'bottom', viewFactor: 0.6, }); - revealOnScroll.reveal(".feature-extended .feature-extended-body", { + revealOnScroll.reveal('.feature-extended .feature-extended-body', { duration: 600, - distance: "40px", - easing: "cubic-bezier(0.215, 0.61, 0.355, 1)", - origin: "top", + distance: '40px', + easing: 'cubic-bezier(0.215, 0.61, 0.355, 1)', + origin: 'top', viewFactor: 0.6, }); }); } // Bubble canvas -let bubbleCanvas = function (t) { - let e = this; +const bubbleCanvas = function (t) { + const e = this; e.parentNode = t; e.setCanvasSize(); - window.addEventListener("resize", function () { + window.addEventListener('resize', () => { e.setCanvasSize(); }); e.mouseX = 0; e.mouseY = 0; - window.addEventListener("mousemove", function (t) { - (e.mouseX = t.clientX), (e.mouseY = t.clientY); + window.addEventListener('mousemove', (t) => { + e.mouseX = t.clientX; + e.mouseY = t.clientY; }); e.randomise(); }; @@ -55,15 +58,15 @@ bubbleCanvas.prototype.generateDecimalBetween = function (start, end) { }; bubbleCanvas.prototype.update = function () { - let t = this; - t.translateX = t.translateX - t.movementX; - t.translateY = t.translateY - t.movementY; + const t = this; + t.translateX -= t.movementX; + t.translateY -= t.movementY; t.posX += (t.mouseX / (t.staticity / t.magnetism) - t.posX) / t.smoothFactor; t.posY += (t.mouseY / (t.staticity / t.magnetism) - t.posY) / t.smoothFactor; if ( - t.translateY + t.posY < 0 || - t.translateX + t.posX < 0 || - t.translateX + t.posX > t.canvasWidth + t.translateY + t.posY < 0 + || t.translateX + t.posX < 0 + || t.translateX + t.posX > t.canvasWidth ) { t.randomise(); t.translateY = t.canvasHeight; @@ -71,7 +74,7 @@ bubbleCanvas.prototype.update = function () { }; bubbleCanvas.prototype.randomise = function () { - this.colors = ["195,53,46", "172,54,46"]; + this.colors = ['195,53,46', '172,54,46']; this.velocity = 20; this.smoothFactor = 50; @@ -88,17 +91,17 @@ bubbleCanvas.prototype.randomise = function () { this.translateY = this.generateDecimalBetween(0, this.canvasHeight); }; -let drawBubbleCanvas = function (t) { +const drawBubbleCanvas = function (t) { this.canvas = document.getElementById(t); - this.ctx = this.canvas.getContext("2d"); + this.ctx = this.canvas.getContext('2d'); this.dpr = window.devicePixelRatio; }; drawBubbleCanvas.prototype.start = function (bubbleDensity) { - let t = this; + const t = this; t.bubbleDensity = bubbleDensity; t.setCanvasSize(); - window.addEventListener("resize", function () { + window.addEventListener('resize', () => { t.setCanvasSize(); }); t.bubblesList = []; @@ -114,23 +117,24 @@ drawBubbleCanvas.prototype.setCanvasSize = function () { this.hdpi = this.h * this.dpr; this.canvas.width = this.wdpi; this.canvas.height = this.hdpi; - this.canvas.style.width = this.w + "px"; - this.canvas.style.height = this.h + "px"; + this.canvas.style.width = this.w + 'px'; + this.canvas.style.height = this.h + 'px'; this.ctx.scale(this.dpr, this.dpr); }; drawBubbleCanvas.prototype.animate = function () { - let t = this; + const t = this; t.ctx.clearRect(0, 0, t.canvas.clientWidth, t.canvas.clientHeight); - t.bubblesList.forEach(function (e) { + for (const e of t.bubblesList) { e.update(); t.ctx.translate(e.translateX, e.translateY); t.ctx.beginPath(); t.ctx.arc(e.posX, e.posY, e.size, 0, 2 * Math.PI); - t.ctx.fillStyle = "rgba(" + e.color + "," + e.alpha + ")"; + t.ctx.fillStyle = 'rgba(' + e.color + ',' + e.alpha + ')'; t.ctx.fill(); t.ctx.setTransform(t.dpr, 0, 0, t.dpr, 0, 0); - }); + } + requestAnimationFrame(this.animate.bind(this)); }; @@ -139,15 +143,16 @@ drawBubbleCanvas.prototype.addBubble = function (t) { }; drawBubbleCanvas.prototype.generateBubbles = function () { - let t = this; - for (let e = 0; e < t.bubbleDensity; e++) + const t = this; + for (let e = 0; e < t.bubbleDensity; e++) { t.addBubble(new bubbleCanvas(t.canvas.parentNode)); + } }; // Night sky with stars canvas -let starCanvas = function (t) { +const starCanvas = function (t) { this.canvas = document.getElementById(t); - this.ctx = this.canvas.getContext("2d"); + this.ctx = this.canvas.getContext('2d'); this.dpr = window.devicePixelRatio; }; @@ -156,17 +161,17 @@ starCanvas.prototype.start = function () { let h; const setCanvasExtents = () => { - w = this.canvas.parentNode.clientWidth; - h = this.canvas.parentNode.clientHeight; + w = this.canvas.parentNode.clientWidth; + h = this.canvas.parentNode.clientHeight; this.canvas.width = w; this.canvas.height = h; }; setCanvasExtents(); - window.onresize = () => { + window.addEventListener('resize', () => { setCanvasExtents(); - }; + }); const makeStars = (count) => { const out = []; @@ -178,19 +183,20 @@ starCanvas.prototype.start = function () { }; out.push(s); } + return out; }; - let stars = makeStars(10000); + const stars = makeStars(10_000); const clear = () => { - this.ctx.fillStyle = "#212121"; + this.ctx.fillStyle = '#212121'; this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height); }; const putPixel = (x, y, brightness) => { const intensity = brightness * 255; - const rgb = "rgb(" + intensity + "," + intensity + "," + intensity + ")"; + const rgb = 'rgb(' + intensity + ',' + intensity + ',' + intensity + ')'; this.ctx.beginPath(); this.ctx.arc(x, y, 0.9, 0, 2 * Math.PI); this.ctx.fillStyle = rgb; @@ -199,7 +205,7 @@ starCanvas.prototype.start = function () { const moveStars = (distance) => { const count = stars.length; - for (var i = 0; i < count; i++) { + for (let i = 0; i < count; i++) { const s = stars[i]; s.z -= distance; while (s.z <= 1) { @@ -208,15 +214,15 @@ starCanvas.prototype.start = function () { } }; - let prevTime; + let previousTime; const init = (time) => { - prevTime = time; + previousTime = time; requestAnimationFrame(tick); }; const tick = (time) => { - let elapsed = time - prevTime; - prevTime = time; + const elapsed = time - previousTime; + previousTime = time; moveStars(elapsed * 0.1); @@ -226,7 +232,7 @@ starCanvas.prototype.start = function () { const cy = h / 2; const count = stars.length; - for (var i = 0; i < count; i++) { + for (let i = 0; i < count; i++) { const star = stars[i]; const x = cx + star.x / (star.z * 0.001); @@ -236,7 +242,7 @@ starCanvas.prototype.start = function () { continue; } - const d = star.z / 1000.0; + const d = star.z / 1000; const b = 1 - d * d; putPixel(x, y, b); @@ -249,12 +255,12 @@ starCanvas.prototype.start = function () { }; // Start canvas animations -window.addEventListener("load", function () { +window.addEventListener('load', () => { // Stars - const headCanvas = new starCanvas("hero-particles"); + const headCanvas = new starCanvas('hero-particles'); // Bubbles - const footerCanvas = new drawBubbleCanvas("footer-particles"); - const mainCanvas = new drawBubbleCanvas("main-particles"); + const footerCanvas = new drawBubbleCanvas('footer-particles'); + const mainCanvas = new drawBubbleCanvas('main-particles'); headCanvas.start(); footerCanvas.start(30); diff --git a/docs/style/fonts.css b/docs/style/fonts.css index 8183c438..fac73089 100644 --- a/docs/style/fonts.css +++ b/docs/style/fonts.css @@ -6,6 +6,7 @@ src: url(https://fonts.gstatic.com/s/heebo/v9/NGS6v5_NC0k9P9H0TbFhsqMA6aw.woff2) format('woff2'); unicode-range: U+0590-05FF, U+20AA, U+25CC, U+FB1D-FB4F; } + /* latin */ @font-face { font-family: 'Heebo'; @@ -14,6 +15,7 @@ src: url(https://fonts.gstatic.com/s/heebo/v9/NGS6v5_NC0k9P9H2TbFhsqMA.woff2) format('woff2'); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; } + /* hebrew */ @font-face { font-family: 'Heebo'; @@ -22,6 +24,7 @@ src: url(https://fonts.gstatic.com/s/heebo/v9/NGS6v5_NC0k9P9H0TbFhsqMA6aw.woff2) format('woff2'); unicode-range: U+0590-05FF, U+20AA, U+25CC, U+FB1D-FB4F; } + /* latin */ @font-face { font-family: 'Heebo'; @@ -30,6 +33,7 @@ src: url(https://fonts.gstatic.com/s/heebo/v9/NGS6v5_NC0k9P9H2TbFhsqMA.woff2) format('woff2'); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; } + /* latin-ext */ @font-face { font-family: 'Oxygen'; @@ -38,6 +42,7 @@ src: url(https://fonts.gstatic.com/s/oxygen/v10/2sDcZG1Wl4LcnbuCNWgzZmW5Kb8VZBHR.woff2) format('woff2'); unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; } + /* latin */ @font-face { font-family: 'Oxygen'; diff --git a/docs/style/style.css b/docs/style/style.css index dea047b9..1106ca62 100644 --- a/docs/style/style.css +++ b/docs/style/style.css @@ -3,9 +3,11 @@ html { -ms-text-size-adjust: 100%; -webkit-text-size-adjust: 100%; } + body { margin: 0; } + article, aside, footer, @@ -14,61 +16,75 @@ nav, section { display: block; } + h1 { font-size: 2em; margin: 0.67em 0; } + figcaption, figure, main { display: block; } + figure { margin: 1em 40px; } + hr { box-sizing: content-box; height: 0; overflow: visible; } + pre { font-family: monospace, monospace; font-size: 1em; } + a { background-color: transparent; -webkit-text-decoration-skip: objects; } + abbr[title] { border-bottom: none; text-decoration: underline; -webkit-text-decoration: underline dotted; text-decoration: underline dotted; } + b, strong { font-weight: inherit; } + b, strong { font-weight: bolder; } + code, kbd, samp { font-family: monospace, monospace; font-size: 1em; } + dfn { font-style: italic; } + mark { background-color: #ff0; color: #000; } + small { font-size: 80%; } + sub, sup { font-size: 75%; @@ -76,26 +92,33 @@ sup { position: relative; vertical-align: baseline; } + sub { bottom: -0.25em; } + sup { top: -0.5em; } + audio, video { display: inline-block; } + audio:not([controls]) { display: none; height: 0; } + img { border-style: none; } + svg:not(:root) { overflow: hidden; } + button, input, optgroup, @@ -106,20 +129,24 @@ textarea { line-height: 1.15; margin: 0; } + button, input { overflow: visible; } + button, select { text-transform: none; } + button, html [type="button"], [type="reset"], [type="submit"] { -webkit-appearance: button; } + button::-moz-focus-inner, [type="button"]::-moz-focus-inner, [type="reset"]::-moz-focus-inner, @@ -127,15 +154,18 @@ button::-moz-focus-inner, border-style: none; padding: 0; } + button:-moz-focusring, [type="button"]:-moz-focusring, [type="reset"]:-moz-focusring, [type="submit"]:-moz-focusring { outline: 1px dotted ButtonText; } + fieldset { padding: 0.35em 0.75em 0.625em; } + legend { box-sizing: border-box; color: inherit; @@ -144,63 +174,79 @@ legend { padding: 0; white-space: normal; } + progress { display: inline-block; vertical-align: baseline; } + textarea { overflow: auto; } + [type="checkbox"], [type="radio"] { box-sizing: border-box; padding: 0; } + [type="number"]::-webkit-inner-spin-button, [type="number"]::-webkit-outer-spin-button { height: auto; } + [type="search"] { -webkit-appearance: textfield; outline-offset: -2px; } + [type="search"]::-webkit-search-cancel-button, [type="search"]::-webkit-search-decoration { -webkit-appearance: none; } + ::-webkit-file-upload-button { -webkit-appearance: button; font: inherit; } + details, menu { display: block; } + summary { display: list-item; } + canvas { display: inline-block; } + template { display: none; } + [hidden] { display: none; } + html { box-sizing: border-box; } + *, *:before, *:after { box-sizing: inherit; } + body { background: #3f4042; -moz-osx-font-smoothing: grayscale; -webkit-font-smoothing: antialiased; } + hr { border: 0; display: block; @@ -209,81 +255,101 @@ hr { margin-top: 24px; margin-bottom: 24px; } + ul, ol { margin-top: 0; margin-bottom: 24px; padding-left: 24px; } + ul { list-style: disc; } + ol { list-style: decimal; } + li > ul, li > ol { margin-bottom: 0; } + dl { margin-top: 0; margin-bottom: 24px; } + dt { font-weight: 600; } + dd { margin-left: 24px; margin-bottom: 24px; } + img { height: auto; max-width: 100%; vertical-align: middle; } + figure { margin: 24px 0; } + figcaption { font-size: 16px; line-height: 24px; padding: 8px 0; } + img, svg { display: block; } + table { border-collapse: collapse; margin-bottom: 24px; width: 100%; } + tr { border-bottom: 1px solid #e4e8ee; } + th { text-align: left; } + th, td { padding: 10px 16px; } + th:first-child, td:first-child { padding-left: 0; } + th:last-child, td:last-child { padding-right: 0; } + html { font-size: 20px; line-height: 30px; } + body { color: #b7bbc1; font-size: 1rem; } + body, button, input, @@ -291,15 +357,18 @@ select, textarea { font-family: "Heebo", sans-serif; } + a { color: #c3352e; text-decoration: none; } + a:hover, a:active { outline: 0; text-decoration: underline; } + h1, h2, h3, @@ -317,12 +386,14 @@ h6, font-family: "Oxygen", sans-serif; font-weight: 600; } + h1, .h1 { font-size: 38px; line-height: 48px; letter-spacing: 0px; } + @media (min-width: 641px) { h1, .h1 { @@ -331,12 +402,14 @@ h1, letter-spacing: 0px; } } + h2, .h2 { font-size: 32px; line-height: 42px; letter-spacing: 0px; } + @media (min-width: 641px) { h2, .h2 { @@ -345,6 +418,7 @@ h2, letter-spacing: 0px; } } + h3, .h3, blockquote { @@ -352,6 +426,7 @@ blockquote { line-height: 34px; letter-spacing: 0px; } + @media (min-width: 641px) { h3, .h3, @@ -361,12 +436,14 @@ blockquote { letter-spacing: 0px; } } + h4, .h4 { font-size: 28px; line-height: 34px; letter-spacing: 0px; } + h5, .h5, h6, @@ -375,27 +452,32 @@ h6, line-height: 30px; letter-spacing: -0.1px; } + @media (max-width: 640px) { .h1-mobile { font-size: 38px; line-height: 48px; letter-spacing: 0px; } + .h2-mobile { font-size: 32px; line-height: 42px; letter-spacing: 0px; } + .h3-mobile { font-size: 28px; line-height: 34px; letter-spacing: 0px; } + .h4-mobile { font-size: 28px; line-height: 34px; letter-spacing: 0px; } + .h5-mobile, .h6-mobile { font-size: 20px; @@ -403,12 +485,15 @@ h6, letter-spacing: -0.1px; } } + .text-light { color: #606483; } + .text-light a { color: #606483; } + .text-light h1, .text-light h2, .text-light h3, @@ -423,16 +508,19 @@ h6, .text-light .h6 { color: #fff !important; } + .text-sm { font-size: 18px; line-height: 27px; letter-spacing: -0.1px; } + .text-xs { font-size: 16px; line-height: 24px; letter-spacing: -0.1px; } + h1, h2, .h1, @@ -440,11 +528,13 @@ h2, margin-top: 48px; margin-bottom: 16px; } + h3, .h3 { margin-top: 36px; margin-bottom: 12px; } + h4, h5, h6, @@ -454,16 +544,19 @@ h6, margin-top: 24px; margin-bottom: 4px; } + p { margin-top: 0; margin-bottom: 24px; } + dfn, cite, em, i { font-style: italic; } + blockquote { color: #b7bbc1; font-style: italic; @@ -471,15 +564,19 @@ blockquote { margin-bottom: 24px; margin-left: 24px; } + blockquote::before { content: "\201C"; } + blockquote::after { content: "\201D"; } + blockquote p { display: inline; } + address { color: #b7bbc1; border-width: 1px 0; @@ -488,6 +585,7 @@ address { padding: 24px 0; margin: 0 0 24px; } + pre, pre h1, pre h2, @@ -503,6 +601,7 @@ pre .h5, pre .h6 { font-family: "Courier 10 Pitch", Courier, monospace; } + pre, code, kbd, @@ -510,6 +609,7 @@ tt, var { background: #f3f4ff; } + pre { font-size: 16px; line-height: 24px; @@ -520,6 +620,7 @@ pre { margin-top: 24px; margin-bottom: 24px; } + code, kbd, tt, @@ -528,23 +629,28 @@ var { font-size: 16px; padding: 2px 4px; } + abbr, acronym { cursor: help; } + mark, ins { text-decoration: none; } + small { font-size: 18px; line-height: 27px; letter-spacing: -0.1px; } + b, strong { font-weight: 600; } + button, input, select, @@ -553,6 +659,7 @@ label { font-size: 20px; line-height: 30px; } + .container, .container-sm { width: 100%; @@ -560,6 +667,7 @@ label { padding-left: 16px; padding-right: 16px; } + @media (min-width: 481px) { .container, .container-sm { @@ -567,17 +675,21 @@ label { padding-right: 24px; } } + .container { max-width: 1128px; } + .container-sm { max-width: 848px; } + .container .container-sm { max-width: 800px; padding-left: 0; padding-right: 0; } + .screen-reader-text { clip: rect(1px, 1px, 1px, 1px); position: absolute !important; @@ -586,6 +698,7 @@ label { overflow: hidden; word-wrap: normal !important; } + .screen-reader-text:focus { border-radius: 2px; box-shadow: 0 0 2px 2px rgba(0, 0, 0, 0.6); @@ -607,28 +720,36 @@ label { width: auto; z-index: 100000; } + .list-reset { list-style: none; padding: 0; } + .text-left { text-align: left; } + .text-center { text-align: center; } + .text-right { text-align: right; } + .text-primary { color: #c3352e; } + .text-secondary { color: #ff6c50; } + .has-top-divider { position: relative; } + .has-top-divider::before { content: ""; position: absolute; @@ -639,9 +760,11 @@ label { height: 1px; background: #e4e8ee; } + .has-bottom-divider { position: relative; } + .has-bottom-divider::after { content: ""; position: absolute; @@ -652,279 +775,371 @@ label { height: 1px; background: #e4e8ee; } + .m-0 { margin: 0; } + .mt-0 { margin-top: 0; } + .mr-0 { margin-right: 0; } + .mb-0 { margin-bottom: 0; } + .ml-0 { margin-left: 0; } + .m-8 { margin: 8px; } + .mt-8 { margin-top: 8px; } + .mr-8 { margin-right: 8px; } + .mb-8 { margin-bottom: 8px; } + .ml-8 { margin-left: 8px; } + .m-16 { margin: 16px; } + .mt-16 { margin-top: 16px; } + .mr-16 { margin-right: 16px; } + .mb-16 { margin-bottom: 16px; } + .ml-16 { margin-left: 16px; } + .m-24 { margin: 24px; } + .mt-24 { margin-top: 24px; } + .mr-24 { margin-right: 24px; } + .mb-24 { margin-bottom: 24px; } + .ml-24 { margin-left: 24px; } + .m-32 { margin: 32px; } + .mt-32 { margin-top: 32px; } + .mr-32 { margin-right: 32px; } + .mb-32 { margin-bottom: 32px; } + .ml-32 { margin-left: 32px; } + .m-40 { margin: 40px; } + .mt-40 { margin-top: 40px; } + .mr-40 { margin-right: 40px; } + .mb-40 { margin-bottom: 40px; } + .ml-40 { margin-left: 40px; } + .m-48 { margin: 48px; } + .mt-48 { margin-top: 48px; } + .mr-48 { margin-right: 48px; } + .mb-48 { margin-bottom: 48px; } + .ml-48 { margin-left: 48px; } + .m-56 { margin: 56px; } + .mt-56 { margin-top: 56px; } + .mr-56 { margin-right: 56px; } + .mb-56 { margin-bottom: 56px; } + .ml-56 { margin-left: 56px; } + .m-64 { margin: 64px; } + .mt-64 { margin-top: 64px; } + .mr-64 { margin-right: 64px; } + .mb-64 { margin-bottom: 64px; } + .ml-64 { margin-left: 64px; } + .p-0 { padding: 0; } + .pt-0 { padding-top: 0; } + .pr-0 { padding-right: 0; } + .pb-0 { padding-bottom: 0; } + .pl-0 { padding-left: 0; } + .p-8 { padding: 8px; } + .pt-8 { padding-top: 8px; } + .pr-8 { padding-right: 8px; } + .pb-8 { padding-bottom: 8px; } + .pl-8 { padding-left: 8px; } + .p-16 { padding: 16px; } + .pt-16 { padding-top: 16px; } + .pr-16 { padding-right: 16px; } + .pb-16 { padding-bottom: 16px; } + .pl-16 { padding-left: 16px; } + .p-24 { padding: 24px; } + .pt-24 { padding-top: 24px; } + .pr-24 { padding-right: 24px; } + .pb-24 { padding-bottom: 24px; } + .pl-24 { padding-left: 24px; } + .p-32 { padding: 32px; } + .pt-32 { padding-top: 32px; } + .pr-32 { padding-right: 32px; } + .pb-32 { padding-bottom: 32px; } + .pl-32 { padding-left: 32px; } + .p-40 { padding: 40px; } + .pt-40 { padding-top: 40px; } + .pr-40 { padding-right: 40px; } + .pb-40 { padding-bottom: 40px; } + .pl-40 { padding-left: 40px; } + .p-48 { padding: 48px; } + .pt-48 { padding-top: 48px; } + .pr-48 { padding-right: 48px; } + .pb-48 { padding-bottom: 48px; } + .pl-48 { padding-left: 48px; } + .p-56 { padding: 56px; } + .pt-56 { padding-top: 56px; } + .pr-56 { padding-right: 56px; } + .pb-56 { padding-bottom: 56px; } + .pl-56 { padding-left: 56px; } + .p-64 { padding: 64px; } + .pt-64 { padding-top: 64px; } + .pr-64 { padding-right: 64px; } + .pb-64 { padding-bottom: 64px; } + .pl-64 { padding-left: 64px; } + .sr .has-animations .is-revealing { visibility: hidden; } + .button { display: inline-flex; font-size: 14px; @@ -945,15 +1160,19 @@ label { text-align: center; white-space: nowrap; } + .button:active { outline: 0; } + .button::before { border-radius: 2px; } + .button-shadow { position: relative; } + .button-shadow::before { content: ""; position: absolute; @@ -965,70 +1184,90 @@ label { mix-blend-mode: multiply; transition: box-shadow 0.15s ease; } + .button-shadow:hover::before { box-shadow: 0 8px 16px rgba(22, 30, 42, 0.16); } + .button-sm { padding: 8px 24px; height: 32px; } + .button-sm.button-shadow::before { box-shadow: 0 4px 16px rgba(22, 30, 42, 0.12); } + .button-sm.button-shadow:hover::before { box-shadow: 0 4px 16px rgba(22, 30, 42, 0.16); } + .button-primary, .button-secondary { color: #fff !important; transition: background 0.15s ease; } + .button-primary { background: #c3352e; } + .button-primary:hover { background: #ac362e; } + .button-primary.button-shadow::before { box-shadow: 0 8px 16px rgba(66, 52, 248, 0.24); } + .button-primary.button-shadow:hover::before { box-shadow: 0 8px 16px rgba(66, 52, 248, 0.32); } + .button-primary .button-sm.button-shadow::before { box-shadow: 0 4px 16px rgba(66, 52, 248, 0.24); } + .button-primary .button-sm.button-shadow:hover::before { box-shadow: 0 4px 16px rgba(66, 52, 248, 0.32); } + .button-secondary { background: #ff6c50; } + .button-secondary:hover { background: #ac362e; } + .button-secondary.button-shadow::before { box-shadow: 0 8px 16px rgba(255, 108, 80, 0.24); } + .button-secondary.button-shadow:hover::before { box-shadow: 0 8px 16px rgba(255, 108, 80, 0.32); } + .button-secondary .button-sm.button-shadow::before { box-shadow: 0 4px 16px rgba(255, 108, 80, 0.24); } + .button-secondary .button-sm.button-shadow:hover::before { box-shadow: 0 4px 16px rgba(255, 108, 80, 0.32); } + .button-block { display: flex; width: 100%; } + @media (max-width: 640px) { .button-wide-mobile { width: 100%; max-width: 280px; } } + .site-header { padding: 24px 0; position: absolute; @@ -1037,18 +1276,22 @@ label { width: 100%; z-index: 1; } + .site-header-inner { position: relative; display: flex; justify-content: space-between; align-items: center; } + .header-links { display: inline-flex; } + .header-links li { display: inline-flex; } + .header-links a:not(.button) { font-size: 16px; line-height: 24px; @@ -1060,16 +1303,19 @@ label { line-height: 16px; padding: 8px 24px; } + .header-links a:not(.button):hover, .header-links a:not(.button):active { color: #fff; } + .hero { position: relative; padding-top: 128px; padding-bottom: 88px; z-index: 0; } + .hero .hero-bg { position: absolute; top: 0; @@ -1079,6 +1325,7 @@ label { background: #363636; z-index: -2; } + .hero .hero-particles-container { position: absolute; top: 0; @@ -1086,6 +1333,7 @@ label { left: 0; right: 0; } + .hero::before, .hero::after { content: ""; @@ -1094,52 +1342,63 @@ label { width: 720px; background-repeat: no-repeat; } + .hero::before { top: 0; height: 159px; background-image: url("../img/bg-top.svg"); background-size: 720px 159px; } + .hero::after { bottom: 42%; height: 173px; background-image: url("../img/bg-bottom.svg"); background-size: 720px 173px; } + .hero-inner { position: relative; z-index: 1; } + .hero-copy { position: relative; margin-bottom: 48px; } + @media (min-width: 641px) { .hero { padding-top: 160px; padding-bottom: 128px; } + .hero::before, .hero::after { left: calc(50% - 720px); width: 1440px; } + .hero::before { height: 318px; background-size: 1440px 318px; } + .hero::after { height: 347px; background-size: 1440px 347px; } + .hero-copy { margin-bottom: 88px; } + .hero-paragraph { padding-left: 72px; padding-right: 72px; } } + .has-animations .hero .hero-bg, .has-animations .hero::before, .has-animations .hero::after, @@ -1152,40 +1411,45 @@ label { .has-animations .hero .device-mockup { opacity: 0; } + .has-animations.is-loaded .hero .hero-bg { -webkit-animation: heroBg 0.6s cubic-bezier(0.215, 0.61, 0.355, 1) forwards; animation: heroBg 0.6s cubic-bezier(0.215, 0.61, 0.355, 1) forwards; } + .has-animations.is-loaded .hero::before, .has-animations.is-loaded .hero::after { -webkit-animation: heroFadeIn 0.6s ease forwards 0.45s; animation: heroFadeIn 0.6s ease forwards 0.45s; } + .has-animations.is-loaded .site-header, .has-animations.is-loaded .hero-particles-container, .has-animations.is-loaded .hero .mockup-bg { -webkit-animation: heroFadeIn 0.6s ease forwards 0.45s; animation: heroFadeIn 0.6s ease forwards 0.45s; } + .has-animations.is-loaded .hero-title { - -webkit-animation: heroContent 0.6s cubic-bezier(0.215, 0.61, 0.355, 1) - forwards 0.15s; + -webkit-animation: heroContent 0.6s cubic-bezier(0.215, 0.61, 0.355, 1) forwards 0.15s; animation: heroContent 0.6s cubic-bezier(0.215, 0.61, 0.355, 1) forwards 0.15s; } + .has-animations.is-loaded .hero-paragraph { - -webkit-animation: heroContent 0.6s cubic-bezier(0.215, 0.61, 0.355, 1) - forwards 0.3s; + -webkit-animation: heroContent 0.6s cubic-bezier(0.215, 0.61, 0.355, 1) forwards 0.3s; animation: heroContent 0.6s cubic-bezier(0.215, 0.61, 0.355, 1) forwards 0.3s; } + .has-animations.is-loaded .hero-cta { - -webkit-animation: heroContent 0.6s cubic-bezier(0.215, 0.61, 0.355, 1) - forwards 0.45s; + -webkit-animation: heroContent 0.6s cubic-bezier(0.215, 0.61, 0.355, 1) forwards 0.45s; animation: heroContent 0.6s cubic-bezier(0.215, 0.61, 0.355, 1) forwards 0.45s; } + .has-animations.is-loaded .hero .device-mockup { -webkit-animation: heroMockup 0.6s ease forwards 0.6s; animation: heroMockup 0.6s ease forwards 0.6s; } + @-webkit-keyframes heroBg { from { -webkit-transform: scaleY(0) scaleX(1.2) skewY(30deg); @@ -1198,6 +1462,7 @@ label { opacity: 1; } } + @keyframes heroBg { from { -webkit-transform: scaleY(0) scaleX(1.2) skewY(30deg); @@ -1210,6 +1475,7 @@ label { opacity: 1; } } + @-webkit-keyframes heroContent { from { -webkit-transform: translateY(40px) skewY(2deg); @@ -1222,6 +1488,7 @@ label { opacity: 1; } } + @keyframes heroContent { from { -webkit-transform: translateY(40px) skewY(2deg); @@ -1234,6 +1501,7 @@ label { opacity: 1; } } + @-webkit-keyframes heroMockup { from { -webkit-transform: translateY(80px); @@ -1246,6 +1514,7 @@ label { opacity: 1; } } + @keyframes heroMockup { from { -webkit-transform: translateY(80px); @@ -1258,6 +1527,7 @@ label { opacity: 1; } } + @-webkit-keyframes heroFadeIn { from { opacity: 0; @@ -1266,6 +1536,7 @@ label { opacity: 1; } } + @keyframes heroFadeIn { from { opacity: 0; @@ -1274,9 +1545,11 @@ label { opacity: 1; } } + .mockup-container { position: relative; } + #mockup-header-img { position: relative; height: 100%; @@ -1287,9 +1560,11 @@ label { -moz-border-radius: 5px; -webkit-border-radius: 5px; } + .mockup-bg { pointer-events: none; } + .mockup-bg img, .mockup-bg svg { position: absolute; @@ -1301,6 +1576,7 @@ label { height: auto; max-width: 300% !important; } + .device-mockup { position: relative; width: 350px; @@ -1308,34 +1584,43 @@ label { margin: 0 auto; z-index: 1; } + .has-animations .features-extended { opacity: 0; } + .has-animations.is-loaded .features-extended { opacity: 1; position: relative; } + .features-extended-header { margin-bottom: 32px; } + .features-extended-wrap { display: flex; flex-wrap: wrap; margin-top: -24px; } + .features-extended-wrap:last-of-type { margin-bottom: -24px; } + .features-extended-wrap:not(:last-of-type) { margin-bottom: 24px; } + .feature-extended { padding: 24px 0; } + .feature-extended-image { position: relative; margin-bottom: 32px; } + .feature-extended-image img, .feature-extended-image svg { width: 100%; @@ -1345,33 +1630,42 @@ label { margin-right: auto; overflow: visible; } + .feature-extended-body { text-align: center; } + @media (min-width: 641px) { .features-extended .container { max-width: 912px; } + .features-extended .section-inner { padding-bottom: 128px; } + .features-extended .section-paragraph { padding-left: 72px; padding-right: 72px; margin-bottom: 0; } + .features-extended-header { margin-bottom: 80px; } + .features-extended-wrap { margin-top: -64px; } + .features-extended-wrap:last-of-type { margin-bottom: -64px; } + .features-extended-wrap:not(:last-of-type) { margin-bottom: 64px; } + .feature-extended { display: flex; flex-wrap: nowrap; @@ -1379,27 +1673,33 @@ label { justify-content: flex-end; padding: 64px 0; } + .feature-extended .feature-extended-image { width: 440px; margin-right: 96px; margin-bottom: 0; } + .feature-extended .feature-extended-image img, .feature-extended .feature-extended-image svg { width: auto; } + .feature-extended .feature-extended-image img.device-mockup, .feature-extended .feature-extended-image svg.device-mockup { max-width: 200px; } + .feature-extended:nth-child(even) { justify-content: flex-start; } + .feature-extended:nth-child(even) .feature-extended-image { order: 1; margin-left: 96px; margin-right: 0; } + .feature-extended-body { display: flex; flex-direction: column; @@ -1409,23 +1709,29 @@ label { text-align: left; } } + @media (min-width: 1025px) { .features-extended .container { max-width: 944px; } + .feature-extended .feature-extended-image { margin-right: 64px; } + .feature-extended:nth-child(even) .feature-extended-image { margin-left: 64px; } + .feature-extended-body { width: 392px; } } + .cta .section-paragraph { margin-bottom: 32px; } + @media (min-width: 641px) { .cta .section-paragraph { margin-bottom: 32px; @@ -1433,35 +1739,42 @@ label { padding-right: 72px; } } + .body-wrap { overflow: hidden; display: flex; flex-direction: column; min-height: 100vh; } + .boxed-container { max-width: 1440px; margin: 0 auto; box-shadow: 0 20px 48px rgba(22, 30, 42, 0.16); } + main { flex: 1 0 auto; } + .section-inner { position: relative; padding-top: 48px; padding-bottom: 48px; } + @media (min-width: 641px) { .section-inner { padding-top: 88px; padding-bottom: 88px; } } + .site-footer { position: relative; background: #212121; } + .site-footer::before { content: ""; position: absolute; @@ -1473,6 +1786,7 @@ main { background-size: 720px 291px; background-repeat: no-repeat; } + .site-footer .footer-particles-container, .main-particles-container { position: absolute; @@ -1481,20 +1795,24 @@ main { left: 0; right: 0; } + .site-footer-bottom { font-size: 14px; line-height: 22px; letter-spacing: 0px; z-index: 1; } + .site-footer-bottom a { color: #606483; text-decoration: none; } + .site-footer-bottom a:hover, .site-footer-bottom a:active { text-decoration: underline; } + .site-footer-inner { position: relative; display: flex; @@ -1503,6 +1821,7 @@ main { padding-bottom: 48px; position: relative; } + .footer-brand, .footer-links, .footer-social-links, @@ -1512,21 +1831,26 @@ main { display: inline-flex; justify-content: center; } + .footer-brand, .footer-links, .footer-social-links { margin-bottom: 24px; } + .footer-links li + li, .footer-social-links li + li { margin-left: 16px; } + .footer-social-links li { display: inline-flex; } + .footer-social-links li a { padding: 8px; } + @media (min-width: 641px) { .site-footer::before { top: -152px; @@ -1535,25 +1859,30 @@ main { height: 582px; background-size: 1440px 582px; } + .site-footer-inner { justify-content: space-between; padding-top: 64px; padding-bottom: 64px; } + .footer-brand, .footer-links, .footer-social-links, .footer-copyright { flex: 50%; } + .footer-brand, .footer-copyright { justify-content: flex-start; } + .footer-links, .footer-social-links { justify-content: flex-end; } + .footer-links { order: 1; margin-bottom: 0; diff --git a/error.html b/error.html index 1008bc87..5aa9d552 100644 --- a/error.html +++ b/error.html @@ -1,50 +1,50 @@ - - - Cannot load YouTube Music - - + .button { + background: #065fd4; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + color: white; + font: inherit; + text-transform: uppercase; + text-decoration: none; + border-radius: 2px; + font-size: 16px; + font-weight: normal; + text-align: center; + padding: 8px 22px; + display: inline-block; + } + + - -
-

Cannot load YouTube Music… Internet disconnected?

- Retry -
- + +
+

Cannot load YouTube Music… Internet disconnected?

+ Retry +
+ diff --git a/index.js b/index.js deleted file mode 100644 index 0d403e00..00000000 --- a/index.js +++ /dev/null @@ -1,516 +0,0 @@ -"use strict"; -const path = require("path"); - -const electron = require("electron"); -const enhanceWebRequest = require("electron-better-web-request").default; -const is = require("electron-is"); -const unhandled = require("electron-unhandled"); -const { autoUpdater } = require("electron-updater"); - -const config = require("./config"); -const { setApplicationMenu } = require("./menu"); -const { fileExists, injectCSS } = require("./plugins/utils"); -const { isTesting } = require("./utils/testing"); -const { setUpTray } = require("./tray"); -const { setupSongInfo } = require("./providers/song-info"); -const { setupAppControls, restart } = require("./providers/app-controls"); -const { APP_PROTOCOL, setupProtocolHandler, handleProtocol } = require("./providers/protocol-handler"); - -// Catch errors and log them -unhandled({ - logger: console.error, - showDialog: false, -}); - -// Disable Node options if the env var is set -process.env.NODE_OPTIONS = ""; - -const app = electron.app; -// Prevent window being garbage collected -let mainWindow; -autoUpdater.autoDownload = false; - - -const gotTheLock = app.requestSingleInstanceLock(); -if (!gotTheLock) app.exit(); - -app.commandLine.appendSwitch("enable-features", "SharedArrayBuffer"); // Required for downloader -app.allowRendererProcessReuse = true; // https://github.com/electron/electron/issues/18397 -if (config.get("options.disableHardwareAcceleration")) { - if (is.dev()) { - console.log("Disabling hardware acceleration"); - } - app.disableHardwareAcceleration(); -} - -if (is.linux() && config.plugins.isEnabled("shortcuts")) { - //stops chromium from launching it's own mpris service - app.commandLine.appendSwitch('disable-features', 'MediaSessionService'); -} - -if (config.get("options.proxy")) { - app.commandLine.appendSwitch("proxy-server", config.get("options.proxy")); -} - -// Adds debug features like hotkeys for triggering dev tools and reload -require("electron-debug")({ - showDevTools: false //disable automatic devTools on new window -}); - -let icon = "assets/youtube-music.png"; -if (process.platform == "win32") { - icon = "assets/generated/icon.ico"; -} else if (process.platform == "darwin") { - icon = "assets/generated/icon.icns"; -} - -function onClosed() { - // Dereference the window - // For multiple windows store them in an array - mainWindow = null; -} - -/** @param {Electron.BrowserWindow} win */ -function loadPlugins(win) { - injectCSS(win.webContents, path.join(__dirname, "youtube-music.css")); - // Load user CSS - const themes = config.get("options.themes"); - if (Array.isArray(themes)) { - themes.forEach((cssFile) => { - fileExists( - cssFile, - () => { - injectCSS(win.webContents, cssFile); - }, - () => { - console.warn(`CSS file "${cssFile}" does not exist, ignoring`); - } - ); - }); - } - - win.webContents.once("did-finish-load", () => { - if (is.dev()) { - console.log("did finish load"); - win.webContents.openDevTools(); - } - }); - - config.plugins.getEnabled().forEach(([plugin, options]) => { - console.log("Loaded plugin - " + plugin); - const pluginPath = path.join(__dirname, "plugins", plugin, "back.js"); - fileExists(pluginPath, () => { - const handle = require(pluginPath); - handle(win, options); - }); - }); -} - -function createMainWindow() { - const windowSize = config.get("window-size"); - const windowMaximized = config.get("window-maximized"); - const windowPosition = config.get("window-position"); - const useInlineMenu = config.plugins.isEnabled("in-app-menu"); - - const win = new electron.BrowserWindow({ - icon: icon, - width: windowSize.width, - height: windowSize.height, - backgroundColor: "#000", - show: false, - webPreferences: { - // TODO: re-enable contextIsolation once it can work with ffmepg.wasm - // Possible bundling? https://github.com/ffmpegwasm/ffmpeg.wasm/issues/126 - contextIsolation: false, - preload: path.join(__dirname, "preload.js"), - nodeIntegrationInSubFrames: true, - affinity: "main-window", // main window, and addition windows should work in one process - ...(!isTesting() - ? { - // Sandbox is only enabled in tests for now - // See https://www.electronjs.org/docs/latest/tutorial/sandbox#preload-scripts - sandbox: false, - } - : undefined), - }, - frame: !is.macOS() && !useInlineMenu, - titleBarStyle: useInlineMenu - ? "hidden" - : is.macOS() - ? "hiddenInset" - : "default", - autoHideMenuBar: config.get("options.hideMenu"), - }); - loadPlugins(win); - - if (windowPosition) { - const { x, y } = windowPosition; - const winSize = win.getSize(); - const displaySize = - electron.screen.getDisplayNearestPoint(windowPosition).bounds; - if ( - x + winSize[0] < displaySize.x - 8 || - x - winSize[0] > displaySize.x + displaySize.width || - y < displaySize.y - 8 || - y > displaySize.y + displaySize.height - ) { - //Window is offscreen - if (is.dev()) { - console.log( - `Window tried to render offscreen, windowSize=${winSize}, displaySize=${displaySize}, position=${windowPosition}` - ); - } - } else { - win.setPosition(x, y); - } - } - if (windowMaximized) { - win.maximize(); - } - - if(config.get("options.alwaysOnTop")){ - win.setAlwaysOnTop(true); - } - - const urlToLoad = config.get("options.resumeOnStart") - ? config.get("url") - : config.defaultConfig.url; - win.webContents.loadURL(urlToLoad); - win.on("closed", onClosed); - - const setPiPOptions = config.plugins.isEnabled("picture-in-picture") - ? (key, value) => require("./plugins/picture-in-picture/back").setOptions({ [key]: value }) - : () => {}; - - win.on("move", () => { - if (win.isMaximized()) return; - let position = win.getPosition(); - const isPiPEnabled = - config.plugins.isEnabled("picture-in-picture") && - config.plugins.getOptions("picture-in-picture")["isInPiP"]; - if (!isPiPEnabled) { - lateSave("window-position", { x: position[0], y: position[1] }); - } else if(config.plugins.getOptions("picture-in-picture")["savePosition"]) { - lateSave("pip-position", position, setPiPOptions); - } - }); - - let winWasMaximized; - - win.on("resize", () => { - const windowSize = win.getSize(); - const isMaximized = win.isMaximized(); - - const isPiPEnabled = - config.plugins.isEnabled("picture-in-picture") && - config.plugins.getOptions("picture-in-picture")["isInPiP"]; - - if (!isPiPEnabled && winWasMaximized !== isMaximized) { - winWasMaximized = isMaximized; - config.set("window-maximized", isMaximized); - } - if (isMaximized) return; - - if (!isPiPEnabled) { - lateSave("window-size", { - width: windowSize[0], - height: windowSize[1], - }); - } else if(config.plugins.getOptions("picture-in-picture")["saveSize"]) { - lateSave("pip-size", windowSize, setPiPOptions); - } - }); - - let savedTimeouts = {}; - function lateSave(key, value, fn = config.set) { - if (savedTimeouts[key]) clearTimeout(savedTimeouts[key]); - - savedTimeouts[key] = setTimeout(() => { - fn(key, value); - savedTimeouts[key] = undefined; - }, 600); - } - - win.webContents.on("render-process-gone", (event, webContents, details) => { - showUnresponsiveDialog(win, details); - }); - - win.once("ready-to-show", () => { - if (config.get("options.appVisible")) { - win.show(); - } - }); - - removeContentSecurityPolicy(); - - return win; -} - -app.once("browser-window-created", (event, win) => { - if (config.get("options.overrideUserAgent")) { - // User agents are from https://developers.whatismybrowser.com/useragents/explore/ - const originalUserAgent = win.webContents.userAgent; - const userAgents = { - mac: "Mozilla/5.0 (Macintosh; Intel Mac OS X 12.1; rv:95.0) Gecko/20100101 Firefox/95.0", - windows: "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:95.0) Gecko/20100101 Firefox/95.0", - linux: "Mozilla/5.0 (Linux x86_64; rv:95.0) Gecko/20100101 Firefox/95.0", - } - - const updatedUserAgent = - is.macOS() ? userAgents.mac : - is.windows() ? userAgents.windows : - userAgents.linux; - - win.webContents.userAgent = updatedUserAgent; - app.userAgentFallback = updatedUserAgent; - - win.webContents.session.webRequest.onBeforeSendHeaders((details, cb) => { - // this will only happen if login failed, and "retry" was pressed - if (win.webContents.getURL().startsWith("https://accounts.google.com") && details.url.startsWith("https://accounts.google.com")) { - details.requestHeaders["User-Agent"] = originalUserAgent; - } - cb({ requestHeaders: details.requestHeaders }); - }); - } - - setupSongInfo(win); - setupAppControls(); - - win.webContents.on("did-fail-load", ( - _event, - errorCode, - errorDescription, - validatedURL, - isMainFrame, - frameProcessId, - frameRoutingId, - ) => { - const log = JSON.stringify({ - error: "did-fail-load", - errorCode, - errorDescription, - validatedURL, - isMainFrame, - frameProcessId, - frameRoutingId, - }, null, "\t"); - if (is.dev()) { - console.log(log); - } - if( !(config.plugins.isEnabled("in-app-menu") && errorCode === -3)) { // -3 is a false positive with in-app-menu - win.webContents.send("log", log); - win.webContents.loadFile(path.join(__dirname, "error.html")); - } - }); - - win.webContents.on("will-prevent-unload", (event) => { - event.preventDefault(); - }); -}); - -app.on("window-all-closed", () => { - if (process.platform !== "darwin") { - app.quit(); - } - - // Unregister all shortcuts. - electron.globalShortcut.unregisterAll(); -}); - -app.on("activate", () => { - // On OS X it's common to re-create a window in the app when the - // dock icon is clicked and there are no other windows open. - if (mainWindow === null) { - mainWindow = createMainWindow(); - } else if (!mainWindow.isVisible()) { - mainWindow.show(); - } -}); - -app.on("ready", () => { - if (config.get("options.autoResetAppCache")) { - // Clear cache after 20s - const clearCacheTimeout = setTimeout(() => { - if (is.dev()) { - console.log("Clearing app cache."); - } - electron.session.defaultSession.clearCache(); - clearTimeout(clearCacheTimeout); - }, 20000); - } - - // Register appID on windows - if (is.windows()) { - const appID = "com.github.th-ch.youtube-music"; - app.setAppUserModelId(appID); - const appLocation = process.execPath; - const appData = app.getPath("appData"); - // check shortcut validity if not in dev mode / running portable app - if (!is.dev() && !appLocation.startsWith(path.join(appData, "..", "Local", "Temp"))) { - const shortcutPath = path.join(appData, "Microsoft", "Windows", "Start Menu", "Programs", "YouTube Music.lnk"); - try { // check if shortcut is registered and valid - const shortcutDetails = electron.shell.readShortcutLink(shortcutPath); // throw error if doesn't exist yet - if ( - shortcutDetails.target !== appLocation || - shortcutDetails.appUserModelId !== appID - ) { - throw "needUpdate"; - } - } catch (error) { // if not valid -> Register shortcut - electron.shell.writeShortcutLink( - shortcutPath, - error === "needUpdate" ? "update" : "create", - { - target: appLocation, - cwd: path.dirname(appLocation), - description: "YouTube Music Desktop App - including custom plugins", - appUserModelId: appID, - } - ); - } - } - } - - mainWindow = createMainWindow(); - setApplicationMenu(mainWindow); - setUpTray(app, mainWindow); - - setupProtocolHandler(mainWindow); - - app.on('second-instance', (_event, commandLine, _workingDirectory) => { - const uri = `${APP_PROTOCOL}://`; - const protocolArgv = commandLine.find(arg => arg.startsWith(uri)); - if (protocolArgv) { - const lastIndex = protocolArgv.endsWith("/") ? -1 : undefined; - const command = protocolArgv.slice(uri.length, lastIndex); - if (is.dev()) console.debug(`Received command over protocol: "${command}"`); - handleProtocol(command); - return; - } - if (!mainWindow) return; - if (mainWindow.isMinimized()) mainWindow.restore(); - if (!mainWindow.isVisible()) mainWindow.show(); - mainWindow.focus(); - }); - - // Autostart at login - app.setLoginItemSettings({ - openAtLogin: config.get("options.startAtLogin"), - }); - - if (!is.dev() && config.get("options.autoUpdates")) { - const updateTimeout = setTimeout(() => { - autoUpdater.checkForUpdatesAndNotify(); - clearTimeout(updateTimeout); - }, 2000); - autoUpdater.on("update-available", () => { - const downloadLink = - "https://github.com/th-ch/youtube-music/releases/latest"; - const dialogOpts = { - type: "info", - buttons: ["OK", "Download", "Disable updates"], - title: "Application Update", - message: "A new version is available", - detail: `A new version is available and can be downloaded at ${downloadLink}`, - }; - electron.dialog.showMessageBox(dialogOpts).then((dialogOutput) => { - switch (dialogOutput.response) { - // Download - case 1: - electron.shell.openExternal(downloadLink); - break; - // Disable updates - case 2: - config.set("options.autoUpdates", false); - break; - default: - break; - } - }); - }); - } - - if (config.get("options.hideMenu") && !config.get("options.hideMenuWarned")) { - electron.dialog.showMessageBox(mainWindow, { - type: 'info', title: 'Hide Menu Enabled', - message: "Menu is hidden, use 'Alt' to show it (or 'Escape' if using in-app-menu)" - }); - config.set("options.hideMenuWarned", true); - } - - // Optimized for Mac OS X - if (is.macOS() && !config.get("options.appVisible")) { - app.dock.hide(); - } - - let forceQuit = false; - app.on("before-quit", () => { - forceQuit = true; - }); - - if (is.macOS() || config.get("options.tray")) { - mainWindow.on("close", (event) => { - // Hide the window instead of quitting (quit is available in tray options) - if (!forceQuit) { - event.preventDefault(); - mainWindow.hide(); - } - }); - } -}); - -function showUnresponsiveDialog(win, details) { - if (!!details) { - console.log("Unresponsive Error!\n"+JSON.stringify(details, null, "\t")) - } - electron.dialog.showMessageBox(win, { - type: "error", - title: "Window Unresponsive", - message: "The Application is Unresponsive", - details: "We are sorry for the inconvenience! please choose what to do:", - buttons: ["Wait", "Relaunch", "Quit"], - cancelId: 0 - }).then( result => { - switch (result.response) { - case 1: restart(); break; - case 2: app.quit(); break; - } - }); -} - -function removeContentSecurityPolicy( - session = electron.session.defaultSession -) { - // Allows defining multiple "onHeadersReceived" listeners - // by enhancing the session. - // Some plugins (e.g. adblocker) also define a "onHeadersReceived" listener - enhanceWebRequest(session); - - // Custom listener to tweak the content security policy - session.webRequest.onHeadersReceived(function (details, callback) { - details.responseHeaders ??= {} - - // Remove the content security policy - delete details.responseHeaders["content-security-policy-report-only"]; - delete details.responseHeaders["content-security-policy"]; - - callback({ cancel: false, responseHeaders: details.responseHeaders }); - }); - - // When multiple listeners are defined, apply them all - session.webRequest.setResolver("onHeadersReceived", (listeners) => { - const response = listeners.reduce( - async (accumulator, listener) => { - if (accumulator.cancel) { - return accumulator; - } - - const result = await listener.apply(); - return { ...accumulator, ...result }; - }, - { cancel: false } - ); - - return response; - }); -} diff --git a/index.ts b/index.ts new file mode 100644 index 00000000..38b0851d --- /dev/null +++ b/index.ts @@ -0,0 +1,564 @@ +import path from 'node:path'; + +import electron, { BrowserWindow } from 'electron'; +import enhanceWebRequest from 'electron-better-web-request'; +import is from 'electron-is'; +import unhandled from 'electron-unhandled'; +import { autoUpdater } from 'electron-updater'; +import electronDebug from 'electron-debug'; + +import { BetterWebRequest } from 'electron-better-web-request/lib/electron-better-web-request'; + +import config from './config'; +import { setApplicationMenu } from './menu'; +import { fileExists, injectCSS } from './plugins/utils'; +import { isTesting } from './utils/testing'; +import { setUpTray } from './tray'; +import { setupSongInfo } from './providers/song-info'; +import { restart, setupAppControls } from './providers/app-controls'; +import { APP_PROTOCOL, handleProtocol, setupProtocolHandler } from './providers/protocol-handler'; + + +// Catch errors and log them +unhandled({ + logger: console.error, + showDialog: false, +}); + +// Disable Node options if the env var is set +process.env.NODE_OPTIONS = ''; + +const { app } = electron; +// Prevent window being garbage collected +let mainWindow: Electron.BrowserWindow | null; +autoUpdater.autoDownload = false; + +const gotTheLock = app.requestSingleInstanceLock(); +if (!gotTheLock) { + app.exit(); +} + +app.commandLine.appendSwitch('enable-features', 'SharedArrayBuffer'); // Required for downloader +if (config.get('options.disableHardwareAcceleration')) { + if (is.dev()) { + console.log('Disabling hardware acceleration'); + } + + app.disableHardwareAcceleration(); +} + +if (is.linux() && config.plugins.isEnabled('shortcuts')) { + // Stops chromium from launching its own MPRIS service + app.commandLine.appendSwitch('disable-features', 'MediaSessionService'); +} + +if (config.get('options.proxy')) { + app.commandLine.appendSwitch('proxy-server', config.get('options.proxy')); +} + +// Adds debug features like hotkeys for triggering dev tools and reload +electronDebug({ + showDevTools: false, // Disable automatic devTools on new window +}); + +let icon = 'assets/youtube-music.png'; +if (process.platform === 'win32') { + icon = 'assets/generated/icon.ico'; +} else if (process.platform === 'darwin') { + icon = 'assets/generated/icon.icns'; +} + +function onClosed() { + // Dereference the window + // For multiple Windows store them in an array + mainWindow = null; +} + +function loadPlugins(win: BrowserWindow) { + injectCSS(win.webContents, path.join(__dirname, 'youtube-music.css')); + // Load user CSS + const themes: string[] = config.get('options.themes'); + if (Array.isArray(themes)) { + for (const cssFile of themes) { + fileExists( + cssFile, + () => { + injectCSS(win.webContents, cssFile); + }, + () => { + console.warn(`CSS file "${cssFile}" does not exist, ignoring`); + }, + ); + } + } + + win.webContents.once('did-finish-load', () => { + if (is.dev()) { + console.log('did finish load'); + win.webContents.openDevTools(); + } + }); + + for (const [plugin, options] of config.plugins.getEnabled()) { + console.log('Loaded plugin - ' + plugin); + const pluginPath = path.join(__dirname, 'plugins', plugin, 'back.js'); + fileExists(pluginPath, () => { + // eslint-disable-next-line @typescript-eslint/no-var-requires,@typescript-eslint/no-unsafe-member-access + const handle = require(pluginPath).default as (window: BrowserWindow, option: typeof options) => void; + handle(win, options); + }); + } +} + +function createMainWindow() { + const windowSize = config.get('window-size'); + const windowMaximized = config.get('window-maximized'); + const windowPosition: Electron.Point = config.get('window-position'); + const useInlineMenu = config.plugins.isEnabled('in-app-menu'); + + const win = new BrowserWindow({ + icon, + width: windowSize.width, + height: windowSize.height, + backgroundColor: '#000', + show: false, + webPreferences: { + // TODO: re-enable contextIsolation once it can work with FFMpeg.wasm + // Possible bundling? https://github.com/ffmpegwasm/ffmpeg.wasm/issues/126 + contextIsolation: false, + preload: path.join(__dirname, 'preload.js'), + nodeIntegrationInSubFrames: true, + ...(isTesting() + ? undefined + : { + // Sandbox is only enabled in tests for now + // See https://www.electronjs.org/docs/latest/tutorial/sandbox#preload-scripts + sandbox: false, + }), + }, + frame: !is.macOS() && !useInlineMenu, + titleBarStyle: useInlineMenu + ? 'hidden' + : (is.macOS() + ? 'hiddenInset' + : 'default'), + autoHideMenuBar: config.get('options.hideMenu'), + }); + loadPlugins(win); + + if (windowPosition) { + const { x, y } = windowPosition; + const winSize = win.getSize(); + const displaySize + = electron.screen.getDisplayNearestPoint(windowPosition).bounds; + if ( + x + winSize[0] < displaySize.x - 8 + || x - winSize[0] > displaySize.x + displaySize.width + || y < displaySize.y - 8 + || y > displaySize.y + displaySize.height + ) { + // Window is offscreen + if (is.dev()) { + console.log( + `Window tried to render offscreen, windowSize=${String(winSize)}, displaySize=${String(displaySize)}, position=${String(windowPosition)}`, + ); + } + } else { + win.setPosition(x, y); + } + } + + if (windowMaximized) { + win.maximize(); + } + + if (config.get('options.alwaysOnTop')) { + win.setAlwaysOnTop(true); + } + + const urlToLoad = config.get('options.resumeOnStart') + ? config.get('url') + : config.defaultConfig.url; + win.webContents.loadURL(urlToLoad); + win.on('closed', onClosed); + + type PiPOptions = typeof config.defaultConfig.plugins['picture-in-picture']; + const setPiPOptions = config.plugins.isEnabled('picture-in-picture') + // eslint-disable-next-line @typescript-eslint/no-var-requires + ? (key: string, value: unknown) => (require('./plugins/picture-in-picture/back') as typeof import('./plugins/picture-in-picture/back')) + .setOptions({ [key]: value }) + : () => {}; + + win.on('move', () => { + if (win.isMaximized()) { + return; + } + + const position = win.getPosition(); + const isPiPEnabled: boolean + = config.plugins.isEnabled('picture-in-picture') + && config.plugins.getOptions('picture-in-picture').isInPiP; + if (!isPiPEnabled) { + + lateSave('window-position', { x: position[0], y: position[1] }); + } else if (config.plugins.getOptions('picture-in-picture').savePosition) { + lateSave('pip-position', position, setPiPOptions); + } + }); + + let winWasMaximized: boolean; + + win.on('resize', () => { + const windowSize = win.getSize(); + const isMaximized = win.isMaximized(); + + const isPiPEnabled + = config.plugins.isEnabled('picture-in-picture') + && config.plugins.getOptions('picture-in-picture').isInPiP; + + if (!isPiPEnabled && winWasMaximized !== isMaximized) { + winWasMaximized = isMaximized; + config.set('window-maximized', isMaximized); + } + + if (isMaximized) { + return; + } + + if (!isPiPEnabled) { + lateSave('window-size', { + width: windowSize[0], + height: windowSize[1], + }); + } else if (config.plugins.getOptions('picture-in-picture').saveSize) { + lateSave('pip-size', windowSize, setPiPOptions); + } + }); + + const savedTimeouts: Record = {}; + + function lateSave(key: string, value: unknown, fn: (key: string, value: unknown) => void = config.set) { + if (savedTimeouts[key]) { + clearTimeout(savedTimeouts[key]); + } + + savedTimeouts[key] = setTimeout(() => { + fn(key, value); + savedTimeouts[key] = undefined; + }, 600); + } + + app.on('render-process-gone', (event, webContents, details) => { + showUnresponsiveDialog(win, details); + }); + + win.once('ready-to-show', () => { + if (config.get('options.appVisible')) { + win.show(); + } + }); + + removeContentSecurityPolicy(); + + return win; +} + +app.once('browser-window-created', (event, win) => { + if (config.get('options.overrideUserAgent')) { + // User agents are from https://developers.whatismybrowser.com/useragents/explore/ + const originalUserAgent = win.webContents.userAgent; + const userAgents = { + mac: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 12.1; rv:95.0) Gecko/20100101 Firefox/95.0', + windows: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:95.0) Gecko/20100101 Firefox/95.0', + linux: 'Mozilla/5.0 (Linux x86_64; rv:95.0) Gecko/20100101 Firefox/95.0', + }; + + const updatedUserAgent + = is.macOS() ? userAgents.mac + : (is.windows() ? userAgents.windows + : userAgents.linux); + + win.webContents.userAgent = updatedUserAgent; + app.userAgentFallback = updatedUserAgent; + + win.webContents.session.webRequest.onBeforeSendHeaders((details, cb) => { + // This will only happen if login failed, and "retry" was pressed + if (win.webContents.getURL().startsWith('https://accounts.google.com') && details.url.startsWith('https://accounts.google.com')) { + details.requestHeaders['User-Agent'] = originalUserAgent; + } + + cb({ requestHeaders: details.requestHeaders }); + }); + } + + setupSongInfo(win); + setupAppControls(); + + win.webContents.on('did-fail-load', ( + _event, + errorCode, + errorDescription, + validatedURL, + isMainFrame, + frameProcessId, + frameRoutingId, + ) => { + const log = JSON.stringify({ + error: 'did-fail-load', + errorCode, + errorDescription, + validatedURL, + isMainFrame, + frameProcessId, + frameRoutingId, + }, null, '\t'); + if (is.dev()) { + console.log(log); + } + + if (!(config.plugins.isEnabled('in-app-menu') && errorCode === -3)) { // -3 is a false positive with in-app-menu + win.webContents.send('log', log); + win.webContents.loadFile(path.join(__dirname, 'error.html')); + } + }); + + win.webContents.on('will-prevent-unload', (event) => { + event.preventDefault(); + }); +}); + +app.on('window-all-closed', () => { + if (process.platform !== 'darwin') { + app.quit(); + } + + // Unregister all shortcuts. + electron.globalShortcut.unregisterAll(); +}); + +app.on('activate', () => { + // On OS X it's common to re-create a window in the app when the + // dock icon is clicked and there are no other windows open. + if (mainWindow === null) { + mainWindow = createMainWindow(); + } else if (!mainWindow.isVisible()) { + mainWindow.show(); + } +}); + +app.on('ready', () => { + if (config.get('options.autoResetAppCache')) { + // Clear cache after 20s + const clearCacheTimeout = setTimeout(() => { + if (is.dev()) { + console.log('Clearing app cache.'); + } + + electron.session.defaultSession.clearCache(); + clearTimeout(clearCacheTimeout); + }, 20_000); + } + + // Register appID on windows + if (is.windows()) { + const appID = 'com.github.th-ch.youtube-music'; + app.setAppUserModelId(appID); + const appLocation = process.execPath; + const appData = app.getPath('appData'); + // Check shortcut validity if not in dev mode / running portable app + if (!is.dev() && !appLocation.startsWith(path.join(appData, '..', 'Local', 'Temp'))) { + const shortcutPath = path.join(appData, 'Microsoft', 'Windows', 'Start Menu', 'Programs', 'YouTube Music.lnk'); + try { // Check if shortcut is registered and valid + const shortcutDetails = electron.shell.readShortcutLink(shortcutPath); // Throw error if doesn't exist yet + if ( + shortcutDetails.target !== appLocation + || shortcutDetails.appUserModelId !== appID + ) { + throw 'needUpdate'; + } + } catch (error) { // If not valid -> Register shortcut + electron.shell.writeShortcutLink( + shortcutPath, + error === 'needUpdate' ? 'update' : 'create', + { + target: appLocation, + cwd: path.dirname(appLocation), + description: 'YouTube Music Desktop App - including custom plugins', + appUserModelId: appID, + }, + ); + } + } + } + + mainWindow = createMainWindow(); + setApplicationMenu(mainWindow); + setUpTray(app, mainWindow); + + setupProtocolHandler(mainWindow); + + app.on('second-instance', (_, commandLine) => { + const uri = `${APP_PROTOCOL}://`; + const protocolArgv = commandLine.find((arg) => arg.startsWith(uri)); + if (protocolArgv) { + const lastIndex = protocolArgv.endsWith('/') ? -1 : undefined; + const command = protocolArgv.slice(uri.length, lastIndex); + if (is.dev()) { + console.debug(`Received command over protocol: "${command}"`); + } + + handleProtocol(command); + return; + } + + if (!mainWindow) { + return; + } + + if (mainWindow.isMinimized()) { + mainWindow.restore(); + } + + if (!mainWindow.isVisible()) { + mainWindow.show(); + } + + mainWindow.focus(); + }); + + // Autostart at login + app.setLoginItemSettings({ + openAtLogin: config.get('options.startAtLogin'), + }); + + if (!is.dev() && config.get('options.autoUpdates')) { + const updateTimeout = setTimeout(() => { + autoUpdater.checkForUpdatesAndNotify(); + clearTimeout(updateTimeout); + }, 2000); + autoUpdater.on('update-available', () => { + const downloadLink + = 'https://github.com/th-ch/youtube-music/releases/latest'; + const dialogOptions: Electron.MessageBoxOptions = { + type: 'info', + buttons: ['OK', 'Download', 'Disable updates'], + title: 'Application Update', + message: 'A new version is available', + detail: `A new version is available and can be downloaded at ${downloadLink}`, + }; + electron.dialog.showMessageBox(dialogOptions).then((dialogOutput) => { + switch (dialogOutput.response) { + // Download + case 1: { + electron.shell.openExternal(downloadLink); + break; + } + + // Disable updates + case 2: { + config.set('options.autoUpdates', false); + break; + } + + default: { + break; + } + } + }); + }); + } + + if (config.get('options.hideMenu') && !config.get('options.hideMenuWarned')) { + electron.dialog.showMessageBox(mainWindow, { + type: 'info', title: 'Hide Menu Enabled', + message: "Menu is hidden, use 'Alt' to show it (or 'Escape' if using in-app-menu)", + }); + config.set('options.hideMenuWarned', true); + } + + // Optimized for Mac OS X + if (is.macOS() && !config.get('options.appVisible')) { + app.dock.hide(); + } + + let forceQuit = false; + app.on('before-quit', () => { + forceQuit = true; + }); + + if (is.macOS() || config.get('options.tray')) { + mainWindow.on('close', (event) => { + // Hide the window instead of quitting (quit is available in tray options) + if (!forceQuit) { + event.preventDefault(); + mainWindow!.hide(); + } + }); + } +}); + +function showUnresponsiveDialog(win: BrowserWindow, details: Electron.RenderProcessGoneDetails) { + if (details) { + console.log('Unresponsive Error!\n' + JSON.stringify(details, null, '\t')); + } + + electron.dialog.showMessageBox(win, { + type: 'error', + title: 'Window Unresponsive', + message: 'The Application is Unresponsive', + detail: 'We are sorry for the inconvenience! please choose what to do:', + buttons: ['Wait', 'Relaunch', 'Quit'], + cancelId: 0, + }).then((result) => { + switch (result.response) { + case 1: { + restart(); + break; + } + + case 2: { + app.quit(); + break; + } + } + }); +} + +// HACK: electron-better-web-request's typing is wrong +type BetterSession = Omit & { webRequest: BetterWebRequest & Electron.WebRequest }; +function removeContentSecurityPolicy( + session: BetterSession = electron.session.defaultSession as BetterSession, +) { + // Allows defining multiple "onHeadersReceived" listeners + // by enhancing the session. + // Some plugins (e.g. adblocker) also define a "onHeadersReceived" listener + enhanceWebRequest(session); + + // Custom listener to tweak the content security policy + session.webRequest.onHeadersReceived((details, callback) => { + details.responseHeaders ??= {}; + + // Remove the content security policy + delete details.responseHeaders['content-security-policy-report-only']; + delete details.responseHeaders['content-security-policy']; + + callback({ cancel: false, responseHeaders: details.responseHeaders }); + }); + + type ResolverListener = { apply: () => Promise>; context: unknown }; + // When multiple listeners are defined, apply them all + session.webRequest.setResolver('onHeadersReceived', async (listeners: ResolverListener[]) => { + return listeners.reduce>>( + async (accumulator: Promise>, listener: ResolverListener) => { + const acc = await accumulator; + if (acc.cancel) { + return acc; + } + + const result = await listener.apply(); + return { ...accumulator, ...result }; + }, + Promise.resolve({ cancel: false }), + ); + }); +} diff --git a/menu.js b/menu.js deleted file mode 100644 index 6aaad9f1..00000000 --- a/menu.js +++ /dev/null @@ -1,437 +0,0 @@ -const { existsSync } = require("fs"); -const path = require("path"); - -const { app, clipboard, Menu, dialog } = require("electron"); -const is = require("electron-is"); -const { restart } = require("./providers/app-controls"); - -const { getAllPlugins } = require("./plugins/utils"); -const config = require("./config"); -const { startingPages } = require("./providers/extracted-data"); - -const prompt = require("custom-electron-prompt"); -const promptOptions = require("./providers/prompt-options"); - -// true only if in-app-menu was loaded on launch -const inAppMenuActive = config.plugins.isEnabled("in-app-menu"); - -const pluginEnabledMenu = (plugin, label = "", hasSubmenu = false, refreshMenu = undefined) => ({ - label: label || plugin, - type: "checkbox", - checked: config.plugins.isEnabled(plugin), - click: (item) => { - if (item.checked) { - config.plugins.enable(plugin); - } else { - config.plugins.disable(plugin); - } - if (hasSubmenu) { - refreshMenu(); - } - }, -}); - -const mainMenuTemplate = (win) => { - const refreshMenu = () => { - this.setApplicationMenu(win); - if (inAppMenuActive) { - win.webContents.send("refreshMenu"); - } - } - return [ - { - label: "Plugins", - submenu: [ - ...getAllPlugins().map((plugin) => { - const pluginPath = path.join(__dirname, "plugins", plugin, "menu.js") - if (existsSync(pluginPath)) { - let pluginLabel = plugin; - if (pluginLabel === "crossfade") { - pluginLabel = "crossfade [beta]"; - } - if (!config.plugins.isEnabled(plugin)) { - return pluginEnabledMenu(plugin, pluginLabel, true, refreshMenu); - } - const getPluginMenu = require(pluginPath); - return { - label: pluginLabel, - submenu: [ - pluginEnabledMenu(plugin, "Enabled", true, refreshMenu), - { type: "separator" }, - ...getPluginMenu(win, config.plugins.getOptions(plugin), refreshMenu), - ], - }; - } - return pluginEnabledMenu(plugin); - }), - ], - }, - { - label: "Options", - submenu: [ - { - label: "Auto-update", - type: "checkbox", - checked: config.get("options.autoUpdates"), - click: (item) => { - config.setMenuOption("options.autoUpdates", item.checked); - }, - }, - { - label: "Resume last song when app starts", - type: "checkbox", - checked: config.get("options.resumeOnStart"), - click: (item) => { - config.setMenuOption("options.resumeOnStart", item.checked); - }, - }, - { - label: 'Starting page', - submenu: Object.keys(startingPages).map((name) => ({ - label: name, - type: 'radio', - checked: config.get('options.startingPage') === name, - click: () => { - config.set('options.startingPage', name); - }, - })) - }, - { - label: "Visual Tweaks", - submenu: [ - { - label: "Remove upgrade button", - type: "checkbox", - checked: config.get("options.removeUpgradeButton"), - click: (item) => { - config.setMenuOption("options.removeUpgradeButton", item.checked); - }, - }, - { - label: "Like buttons", - submenu: [ - { - label: "Default", - type: "radio", - checked: !config.get("options.likeButtons"), - click: () => { - config.set("options.likeButtons", ''); - }, - }, - { - label: "Force show", - type: "radio", - checked: config.get("options.likeButtons") === 'force', - click: () => { - config.set("options.likeButtons", 'force'); - } - }, - { - label: "Hide", - type: "radio", - checked: config.get("options.likeButtons") === 'hide', - click: () => { - config.set("options.likeButtons", 'hide'); - } - }, - ], - }, - { - label: "Theme", - submenu: [ - { - label: "No theme", - type: "radio", - checked: !config.get("options.themes"), // todo rename "themes" - click: () => { - config.set("options.themes", []); - }, - }, - { type: "separator" }, - { - label: "Import custom CSS file", - type: "radio", - checked: false, - click: async () => { - const { filePaths } = await dialog.showOpenDialog({ - filters: [{ name: "CSS Files", extensions: ["css"] }], - properties: ["openFile", "multiSelections"], - }); - if (filePaths) { - config.set("options.themes", filePaths); - } - }, - }, - ], - }, - ], - }, - { - label: "Single instance lock", - type: "checkbox", - checked: true, - click: (item) => { - if (!item.checked && app.hasSingleInstanceLock()) - app.releaseSingleInstanceLock(); - else if (item.checked && !app.hasSingleInstanceLock()) - app.requestSingleInstanceLock(); - }, - }, - { - label: "Always on top", - type: "checkbox", - checked: config.get("options.alwaysOnTop"), - click: (item) => { - config.setMenuOption("options.alwaysOnTop", item.checked); - win.setAlwaysOnTop(item.checked); - }, - }, - ...(is.windows() || is.linux() - ? [ - { - label: "Hide menu", - type: "checkbox", - checked: config.get("options.hideMenu"), - click: (item) => { - config.setMenuOption("options.hideMenu", item.checked); - if (item.checked && !config.get("options.hideMenuWarned")) { - dialog.showMessageBox(win, { - type: 'info', title: 'Hide Menu Enabled', - message: "Menu will be hidden on next launch, use [Alt] to show it (or backtick [`] if using in-app-menu)" - }); - } - }, - }, - ] - : []), - ...(is.windows() || is.macOS() - ? // Only works on Win/Mac - // https://www.electronjs.org/docs/api/app#appsetloginitemsettingssettings-macos-windows - [ - { - label: "Start at login", - type: "checkbox", - checked: config.get("options.startAtLogin"), - click: (item) => { - config.setMenuOption("options.startAtLogin", item.checked); - }, - }, - ] - : []), - { - label: "Tray", - submenu: [ - { - label: "Disabled", - type: "radio", - checked: !config.get("options.tray"), - click: () => { - config.setMenuOption("options.tray", false); - config.setMenuOption("options.appVisible", true); - }, - }, - { - label: "Enabled + app visible", - type: "radio", - checked: - config.get("options.tray") && config.get("options.appVisible"), - click: () => { - config.setMenuOption("options.tray", true); - config.setMenuOption("options.appVisible", true); - }, - }, - { - label: "Enabled + app hidden", - type: "radio", - checked: - config.get("options.tray") && !config.get("options.appVisible"), - click: () => { - config.setMenuOption("options.tray", true); - config.setMenuOption("options.appVisible", false); - }, - }, - { type: "separator" }, - { - label: "Play/Pause on click", - type: "checkbox", - checked: config.get("options.trayClickPlayPause"), - click: (item) => { - config.setMenuOption("options.trayClickPlayPause", item.checked); - }, - }, - ], - }, - { type: "separator" }, - { - label: "Advanced options", - submenu: [ - { - label: "Proxy", - type: "checkbox", - checked: !!config.get("options.proxy"), - click: (item) => { - setProxy(item, win); - }, - }, - { - label: "Override useragent", - type: "checkbox", - checked: config.get("options.overrideUserAgent"), - click: (item) => { - config.setMenuOption("options.overrideUserAgent", item.checked); - } - }, - { - label: "Disable hardware acceleration", - type: "checkbox", - checked: config.get("options.disableHardwareAcceleration"), - click: (item) => { - config.setMenuOption("options.disableHardwareAcceleration", item.checked); - }, - }, - { - label: "Restart on config changes", - type: "checkbox", - checked: config.get("options.restartOnConfigChanges"), - click: (item) => { - config.setMenuOption("options.restartOnConfigChanges", item.checked); - }, - }, - { - label: "Reset App cache when app starts", - type: "checkbox", - checked: config.get("options.autoResetAppCache"), - click: (item) => { - config.setMenuOption("options.autoResetAppCache", item.checked); - }, - }, - { type: "separator" }, - is.macOS() ? - { - label: "Toggle DevTools", - // Cannot use "toggleDevTools" role in MacOS - click: () => { - const { webContents } = win; - if (webContents.isDevToolsOpened()) { - webContents.closeDevTools(); - } else { - const devToolsOptions = {}; - webContents.openDevTools(devToolsOptions); - } - }, - } : - { role: "toggleDevTools" }, - { - label: "Edit config.json", - click: () => { - config.edit(); - }, - }, - ] - }, - ], - }, - { - label: "View", - submenu: [ - { role: "reload" }, - { role: "forceReload" }, - { type: "separator" }, - { role: "zoomIn" }, - { role: "zoomOut" }, - { role: "resetZoom" }, - { type: "separator" }, - { role: "togglefullscreen" }, - ], - }, - { - label: "Navigation", - submenu: [ - { - label: "Go back", - click: () => { - if (win.webContents.canGoBack()) { - win.webContents.goBack(); - } - }, - }, - { - label: "Go forward", - click: () => { - if (win.webContents.canGoForward()) { - win.webContents.goForward(); - } - }, - }, - { - label: "Copy current URL", - click: () => { - const currentURL = win.webContents.getURL(); - clipboard.writeText(currentURL); - }, - }, - { - label: "Restart App", - click: restart - }, - { role: "quit" }, - ], - }, - ]; -} - -module.exports.mainMenuTemplate = mainMenuTemplate; -module.exports.setApplicationMenu = (win) => { - const menuTemplate = [...mainMenuTemplate(win)]; - if (process.platform === "darwin") { - const name = app.name; - menuTemplate.unshift({ - label: name, - submenu: [ - { role: "about" }, - { type: "separator" }, - { role: "hide" }, - { role: "hideothers" }, - { role: "unhide" }, - { type: "separator" }, - { - label: "Select All", - accelerator: "CmdOrCtrl+A", - selector: "selectAll:", - }, - { label: "Cut", accelerator: "CmdOrCtrl+X", selector: "cut:" }, - { label: "Copy", accelerator: "CmdOrCtrl+C", selector: "copy:" }, - { label: "Paste", accelerator: "CmdOrCtrl+V", selector: "paste:" }, - { type: "separator" }, - { role: "minimize" }, - { role: "close" }, - { role: "quit" }, - ], - }); - } - - const menu = Menu.buildFromTemplate(menuTemplate); - Menu.setApplicationMenu(menu); -}; - -async function setProxy(item, win) { - const output = await prompt({ - title: 'Set Proxy', - label: 'Enter Proxy Address: (leave empty to disable)', - value: config.get("options.proxy"), - type: 'input', - inputAttrs: { - type: 'url', - placeholder: "Example: 'socks5://127.0.0.1:9999" - }, - width: 450, - ...promptOptions() - }, win); - - if (typeof output === "string") { - config.setMenuOption("options.proxy", output); - item.checked = output !== ""; - } else { //user pressed cancel - item.checked = !item.checked; //reset checkbox - } -} diff --git a/menu.ts b/menu.ts new file mode 100644 index 00000000..fca99e6d --- /dev/null +++ b/menu.ts @@ -0,0 +1,437 @@ +import { existsSync } from 'node:fs'; +import path from 'node:path'; + +import is from 'electron-is'; +import { app, BrowserWindow, clipboard, dialog, Menu } from 'electron'; +import prompt from 'custom-electron-prompt'; + +import { restart } from './providers/app-controls'; +import { getAllPlugins } from './plugins/utils'; +import config from './config'; +import { startingPages } from './providers/extracted-data'; +import promptOptions from './providers/prompt-options'; + +export type MenuTemplate = (Electron.MenuItemConstructorOptions | Electron.MenuItem)[]; + +// True only if in-app-menu was loaded on launch +const inAppMenuActive = config.plugins.isEnabled('in-app-menu'); + +const pluginEnabledMenu = (plugin: string, label = '', hasSubmenu = false, refreshMenu: (() => void ) | undefined = undefined): Electron.MenuItemConstructorOptions => ({ + label: label || plugin, + type: 'checkbox', + checked: config.plugins.isEnabled(plugin), + click(item: Electron.MenuItem) { + if (item.checked) { + config.plugins.enable(plugin); + } else { + config.plugins.disable(plugin); + } + + if (hasSubmenu) { + refreshMenu?.(); + } + }, +}); + +export const mainMenuTemplate = (win: BrowserWindow): MenuTemplate => { + const refreshMenu = () => { + setApplicationMenu(win); + if (inAppMenuActive) { + win.webContents.send('refreshMenu'); + } + }; + + return [ + { + label: 'Plugins', + submenu: + getAllPlugins().map((plugin) => { + const pluginPath = path.join(__dirname, 'plugins', plugin, 'menu.js'); + if (existsSync(pluginPath)) { + let pluginLabel = plugin; + if (pluginLabel === 'crossfade') { + pluginLabel = 'crossfade [beta]'; + } + + if (!config.plugins.isEnabled(plugin)) { + return pluginEnabledMenu(plugin, pluginLabel, true, refreshMenu); + } + + type PluginType = (window: BrowserWindow, plugins: string, func: () => void) => Electron.MenuItemConstructorOptions[]; + + // eslint-disable-next-line @typescript-eslint/no-var-requires,@typescript-eslint/no-unsafe-member-access + const getPluginMenu = require(pluginPath).default as PluginType; + return { + label: pluginLabel, + submenu: [ + pluginEnabledMenu(plugin, 'Enabled', true, refreshMenu), + { type: 'separator' }, + ...getPluginMenu(win, config.plugins.getOptions(plugin), refreshMenu), + ], + } satisfies Electron.MenuItemConstructorOptions; + } + + return pluginEnabledMenu(plugin); + }), + }, + { + label: 'Options', + submenu: [ + { + label: 'Auto-update', + type: 'checkbox', + checked: config.get('options.autoUpdates'), + click(item) { + config.setMenuOption('options.autoUpdates', item.checked); + }, + }, + { + label: 'Resume last song when app starts', + type: 'checkbox', + checked: config.get('options.resumeOnStart'), + click(item) { + config.setMenuOption('options.resumeOnStart', item.checked); + }, + }, + { + label: 'Starting page', + submenu: Object.keys(startingPages).map((name) => ({ + label: name, + type: 'radio', + checked: config.get('options.startingPage') === name, + click() { + config.set('options.startingPage', name); + }, + })), + }, + { + label: 'Visual Tweaks', + submenu: [ + { + label: 'Remove upgrade button', + type: 'checkbox', + checked: config.get('options.removeUpgradeButton'), + click(item) { + config.setMenuOption('options.removeUpgradeButton', item.checked); + }, + }, + { + label: 'Like buttons', + submenu: [ + { + label: 'Default', + type: 'radio', + checked: !config.get('options.likeButtons'), + click() { + config.set('options.likeButtons', ''); + }, + }, + { + label: 'Force show', + type: 'radio', + checked: config.get('options.likeButtons') === 'force', + click() { + config.set('options.likeButtons', 'force'); + }, + }, + { + label: 'Hide', + type: 'radio', + checked: config.get('options.likeButtons') === 'hide', + click() { + config.set('options.likeButtons', 'hide'); + }, + }, + ], + }, + { + label: 'Theme', + submenu: [ + { + label: 'No theme', + type: 'radio', + checked: !config.get('options.themes'), // Todo rename "themes" + click() { + config.set('options.themes', []); + }, + }, + { type: 'separator' }, + { + label: 'Import custom CSS file', + type: 'radio', + checked: false, + async click() { + const { filePaths } = await dialog.showOpenDialog({ + filters: [{ name: 'CSS Files', extensions: ['css'] }], + properties: ['openFile', 'multiSelections'], + }); + if (filePaths) { + config.set('options.themes', filePaths); + } + }, + }, + ], + }, + ], + }, + { + label: 'Single instance lock', + type: 'checkbox', + checked: true, + click(item) { + if (!item.checked && app.hasSingleInstanceLock()) { + app.releaseSingleInstanceLock(); + } else if (item.checked && !app.hasSingleInstanceLock()) { + app.requestSingleInstanceLock(); + } + }, + }, + { + label: 'Always on top', + type: 'checkbox', + checked: config.get('options.alwaysOnTop'), + click(item) { + config.setMenuOption('options.alwaysOnTop', item.checked); + win.setAlwaysOnTop(item.checked); + }, + }, + ...(is.windows() || is.linux() + ? [ + { + label: 'Hide menu', + type: 'checkbox', + checked: config.get('options.hideMenu'), + click(item) { + config.setMenuOption('options.hideMenu', item.checked); + if (item.checked && !config.get('options.hideMenuWarned')) { + dialog.showMessageBox(win, { + type: 'info', title: 'Hide Menu Enabled', + message: 'Menu will be hidden on next launch, use [Alt] to show it (or backtick [`] if using in-app-menu)', + }); + } + }, + }, + ] + : []) satisfies Electron.MenuItemConstructorOptions[], + ...(is.windows() || is.macOS() + ? // Only works on Win/Mac + // https://www.electronjs.org/docs/api/app#appsetloginitemsettingssettings-macos-windows + [ + { + label: 'Start at login', + type: 'checkbox', + checked: config.get('options.startAtLogin'), + click(item) { + config.setMenuOption('options.startAtLogin', item.checked); + }, + }, + ] + : []) satisfies Electron.MenuItemConstructorOptions[], + { + label: 'Tray', + submenu: [ + { + label: 'Disabled', + type: 'radio', + checked: !config.get('options.tray'), + click() { + config.setMenuOption('options.tray', false); + config.setMenuOption('options.appVisible', true); + }, + }, + { + label: 'Enabled + app visible', + type: 'radio', + checked: config.get('options.tray') && config.get('options.appVisible'), + click() { + config.setMenuOption('options.tray', true); + config.setMenuOption('options.appVisible', true); + }, + }, + { + label: 'Enabled + app hidden', + type: 'radio', + checked: config.get('options.tray') && !config.get('options.appVisible'), + click() { + config.setMenuOption('options.tray', true); + config.setMenuOption('options.appVisible', false); + }, + }, + { type: 'separator' }, + { + label: 'Play/Pause on click', + type: 'checkbox', + checked: config.get('options.trayClickPlayPause'), + click(item) { + config.setMenuOption('options.trayClickPlayPause', item.checked); + }, + }, + ], + }, + { type: 'separator' }, + { + label: 'Advanced options', + submenu: [ + { + label: 'Proxy', + type: 'checkbox', + checked: !!(config.get('options.proxy')), + click(item) { + setProxy(item, win); + }, + }, + { + label: 'Override useragent', + type: 'checkbox', + checked: config.get('options.overrideUserAgent'), + click(item) { + config.setMenuOption('options.overrideUserAgent', item.checked); + }, + }, + { + label: 'Disable hardware acceleration', + type: 'checkbox', + checked: config.get('options.disableHardwareAcceleration'), + click(item) { + config.setMenuOption('options.disableHardwareAcceleration', item.checked); + }, + }, + { + label: 'Restart on config changes', + type: 'checkbox', + checked: config.get('options.restartOnConfigChanges'), + click(item) { + config.setMenuOption('options.restartOnConfigChanges', item.checked); + }, + }, + { + label: 'Reset App cache when app starts', + type: 'checkbox', + checked: config.get('options.autoResetAppCache'), + click(item) { + config.setMenuOption('options.autoResetAppCache', item.checked); + }, + }, + { type: 'separator' }, + is.macOS() + ? { + label: 'Toggle DevTools', + // Cannot use "toggleDevTools" role in macOS + click() { + const { webContents } = win; + if (webContents.isDevToolsOpened()) { + webContents.closeDevTools(); + } else { + webContents.openDevTools(); + } + }, + } + : { role: 'toggleDevTools' }, + { + label: 'Edit config.json', + click() { + config.edit(); + }, + }, + ], + }, + ], + }, + { + label: 'View', + submenu: [ + { role: 'reload' }, + { role: 'forceReload' }, + { type: 'separator' }, + { role: 'zoomIn' }, + { role: 'zoomOut' }, + { role: 'resetZoom' }, + { type: 'separator' }, + { role: 'togglefullscreen' }, + ], + }, + { + label: 'Navigation', + submenu: [ + { + label: 'Go back', + click() { + if (win.webContents.canGoBack()) { + win.webContents.goBack(); + } + }, + }, + { + label: 'Go forward', + click() { + if (win.webContents.canGoForward()) { + win.webContents.goForward(); + } + }, + }, + { + label: 'Copy current URL', + click() { + const currentURL = win.webContents.getURL(); + clipboard.writeText(currentURL); + }, + }, + { + label: 'Restart App', + click: restart, + }, + { role: 'quit' }, + ], + }, + ]; +}; +export const setApplicationMenu = (win: Electron.BrowserWindow) => { + const menuTemplate: MenuTemplate = [...mainMenuTemplate(win)]; + if (process.platform === 'darwin') { + const { name } = app; + menuTemplate.unshift({ + label: name, + submenu: [ + { role: 'about' }, + { type: 'separator' }, + { role: 'hide' }, + { role: 'hideOthers' }, + { role: 'unhide' }, + { type: 'separator' }, + { role: 'selectAll' }, + { role: 'cut' }, + { role: 'copy' }, + { role: 'paste' }, + { type: 'separator' }, + { role: 'minimize' }, + { role: 'close' }, + { role: 'quit' }, + ], + }); + } + + const menu = Menu.buildFromTemplate(menuTemplate); + Menu.setApplicationMenu(menu); +}; + +async function setProxy(item: Electron.MenuItem, win: BrowserWindow) { + const output = await prompt({ + title: 'Set Proxy', + label: 'Enter Proxy Address: (leave empty to disable)', + value: config.get('options.proxy'), + type: 'input', + inputAttrs: { + type: 'url', + placeholder: "Example: 'socks5://127.0.0.1:9999", + }, + width: 450, + ...promptOptions(), + }, win); + + if (typeof output === 'string') { + config.setMenuOption('options.proxy', output); + item.checked = output !== ''; + } else { // User pressed cancel + item.checked = !item.checked; // Reset checkbox + } +} diff --git a/navigation.d.ts b/navigation.d.ts new file mode 100644 index 00000000..7d80de52 --- /dev/null +++ b/navigation.d.ts @@ -0,0 +1,88 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ + +interface NavigationOptions { + info: any; +} + +interface NavigationHistoryEntry extends EventTarget { + readonly url?: string; + readonly key: string; + readonly id: string; + readonly index: number; + readonly sameDocument: boolean; + getState(): any; + ondispose: ((this: NavigationHistoryEntry, ev: Event) => any) | null; +} + +interface NavigationTransition { + readonly navigationType: NavigationType; + readonly from: NavigationHistoryEntry; + readonly finished: Promise; +} + +interface NavigationResult { + committed: Promise; + finished: Promise; +} + +interface NavigationNavigateOptions extends NavigationOptions { + state: any; + history?: NavigationHistoryBehavior; +} + +interface NavigationReloadOptions extends NavigationOptions { + state: any; +} + +interface NavigationUpdateCurrentEntryOptions { + state: any; +} + +interface NavigationEventsMap { + currententrychange: NavigateEvent; + navigate: NavigateEvent; + navigateerror: NavigateEvent; + navigatesuccess: NavigateEvent; +} + +interface Navigation extends EventTarget { + entries(): Array; + readonly currentEntry?: NavigationHistoryEntry; + updateCurrentEntry(options: NavigationUpdateCurrentEntryOptions): undefined; + readonly transition?: NavigationTransition; + readonly canGoBack: boolean; + readonly canGoForward: boolean; + navigate(url: string, options?: NavigationNavigateOptions): NavigationResult; + reload(options?: NavigationReloadOptions): NavigationResult; + traverseTo(key: string, options?: NavigationOptions): NavigationResult; + back(options?: NavigationOptions): NavigationResult; + forward(options?: NavigationOptions): NavigationResult; + onnavigate: ((this: Navigation, ev: Event) => any) | null; + onnavigatesuccess: ((this: Navigation, ev: Event) => any) | null; + onnavigateerror: ((this: Navigation, ev: Event) => any) | null; + oncurrententrychange: ((this: Navigation, ev: Event) => any) | null; + + addEventListener(name: K, listener: (event: NavigationEventsMap[K]) => void); +} + +declare class NavigateEvent extends Event { + canIntercept: boolean; + destination: NavigationHistoryEntry; + downloadRequest: string | null; + formData: FormData; + hashChange: boolean; + info: Record; + navigationType: 'push' | 'reload' | 'replace' | 'traverse'; + signal: AbortSignal; + userInitiated: boolean; + + intercept(options?: Record): void; + scroll(): void; +} + +type NavigationHistoryBehavior = 'auto' | 'push' | 'replace'; + +declare const Navigation: { + prototype: Navigation; + new(): Navigation; +}; diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 00000000..62f29ac1 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,9344 @@ +{ + "name": "youtube-music", + "version": "1.20.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "youtube-music", + "version": "1.20.0", + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "@cliqz/adblocker-electron": "1.26.7", + "@ffmpeg.wasm/core-mt": "0.12.0", + "@ffmpeg.wasm/main": "0.12.0", + "@foobar404/wave": "2.0.4", + "@xhayper/discord-rpc": "1.0.23", + "async-mutex": "0.4.0", + "butterchurn": "2.6.7", + "butterchurn-presets": "2.4.7", + "conf": "10.2.0", + "custom-electron-prompt": "1.5.7", + "custom-electron-titlebar": "4.1.6", + "electron-better-web-request": "1.0.1", + "electron-debug": "3.2.0", + "electron-is": "3.0.0", + "electron-localshortcut": "3.2.1", + "electron-store": "8.1.0", + "electron-unhandled": "4.0.1", + "electron-updater": "6.1.4", + "filenamify": "4.3.0", + "howler": "2.2.4", + "html-to-text": "9.0.5", + "keyboardevent-from-electron-accelerator": "2.0.0", + "keyboardevents-areequal": "0.2.2", + "mpris-service": "2.1.2", + "node-id3": "0.2.6", + "simple-youtube-age-restriction-bypass": "git+https://github.com/MiepHD/Simple-YouTube-Age-Restriction-Bypass.git#v2.5.5", + "vudio": "2.1.1", + "youtubei.js": "6.4.1", + "ytpl": "2.3.0" + }, + "devDependencies": { + "@playwright/test": "1.38.1", + "@total-typescript/ts-reset": "0.5.1", + "@types/electron-localshortcut": "3.1.1", + "@types/howler": "2.2.9", + "@types/html-to-text": "9.0.2", + "@typescript-eslint/eslint-plugin": "6.7.4", + "auto-changelog": "2.4.0", + "copyfiles": "2.4.1", + "del-cli": "5.1.0", + "electron": "27.0.0-beta.9", + "electron-builder": "24.6.4", + "electron-devtools-installer": "3.2.0", + "eslint": "8.50.0", + "eslint-plugin-import": "2.28.1", + "eslint-plugin-prettier": "5.0.0", + "node-gyp": "9.4.0", + "playwright": "1.38.1", + "typescript": "5.2.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aashutoshrathi/word-wrap": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", + "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.22.13", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", + "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.22.13", + "chalk": "^2.4.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/code-frame/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/code-frame/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/code-frame/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/@babel/code-frame/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "node_modules/@babel/code-frame/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@babel/code-frame/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/code-frame/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz", + "integrity": "sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.22.13", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.13.tgz", + "integrity": "sha512-C/BaXcnnvBCmHTpz/VGZ8jgtE2aYlW4hxDhseJAWZb7gqGM/qtCK6iZUb0TyKFf7BOUsBH7Q7fkRsDRhg1XklQ==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.22.5", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/@babel/highlight/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "node_modules/@babel/highlight/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@babel/highlight/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/runtime": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.22.15.tgz", + "integrity": "sha512-T0O+aa+4w0u06iNmapipJXMV4HoUir03hpx3/YqXXhu9xim3w+dVphjFWl1OH8NbZHw5Lbm9k45drDkgq2VNNA==", + "dependencies": { + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/runtime/node_modules/regenerator-runtime": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz", + "integrity": "sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==" + }, + "node_modules/@cliqz/adblocker": { + "version": "1.26.7", + "resolved": "https://registry.npmjs.org/@cliqz/adblocker/-/adblocker-1.26.7.tgz", + "integrity": "sha512-UGjsDoAcmSoG2uGrpZVTWOxAxQJ2Ws9fDxmYrzR0yS/vtxd0t+Q8G8vTLKWkdU7BN53xTTCZMjgCALwdqZhycw==", + "dependencies": { + "@cliqz/adblocker-content": "^1.26.7", + "@cliqz/adblocker-extended-selectors": "^1.26.7", + "@remusao/guess-url-type": "^1.2.1", + "@remusao/small": "^1.2.1", + "@remusao/smaz": "^1.9.1", + "@types/chrome": "^0.0.246", + "@types/firefox-webext-browser": "^111.0.2", + "tldts-experimental": "^6.0.14" + } + }, + "node_modules/@cliqz/adblocker-content": { + "version": "1.26.7", + "resolved": "https://registry.npmjs.org/@cliqz/adblocker-content/-/adblocker-content-1.26.7.tgz", + "integrity": "sha512-9nCII7NcidGb16Tf49HV6QFbdDE6ZSTqhLS3vZFImunDRSOHfyCimHOsYEAUURpDi3mnDuK2Kq1yt1m+U4KyKw==", + "dependencies": { + "@cliqz/adblocker-extended-selectors": "^1.26.7" + } + }, + "node_modules/@cliqz/adblocker-electron": { + "version": "1.26.7", + "resolved": "https://registry.npmjs.org/@cliqz/adblocker-electron/-/adblocker-electron-1.26.7.tgz", + "integrity": "sha512-L11NgAGwFI4VnFRq6OrHnvzwVP2r6wyr5uNzj/L+bIAkUjGVqHgcJw4bzF6OdJkeye2trwol2gqONkJKMFlXPA==", + "dependencies": { + "@cliqz/adblocker": "^1.26.7", + "@cliqz/adblocker-electron-preload": "^1.26.7", + "tldts-experimental": "^6.0.14" + }, + "peerDependencies": { + "electron": ">11" + } + }, + "node_modules/@cliqz/adblocker-electron-preload": { + "version": "1.26.7", + "resolved": "https://registry.npmjs.org/@cliqz/adblocker-electron-preload/-/adblocker-electron-preload-1.26.7.tgz", + "integrity": "sha512-/A9HmfZDxo+4wgQuj80YwrTSzm2tb99K7uJ0ymN4/QUKwrSeNIjEeXztbXakS2QqZE5gDWV0opCkGDpV0FuCcg==", + "dependencies": { + "@cliqz/adblocker-content": "^1.26.7" + }, + "peerDependencies": { + "electron": ">11" + } + }, + "node_modules/@cliqz/adblocker-extended-selectors": { + "version": "1.26.7", + "resolved": "https://registry.npmjs.org/@cliqz/adblocker-extended-selectors/-/adblocker-extended-selectors-1.26.7.tgz", + "integrity": "sha512-J6IYdrWHvTy2U/iikMBB/nz0IbYHYomUgmwpOgDbzaesacrNShzr1evU06ncx7QFexKkUqYMqqt/JjUFnYn5qA==" + }, + "node_modules/@develar/schema-utils": { + "version": "2.6.5", + "resolved": "https://registry.npmjs.org/@develar/schema-utils/-/schema-utils-2.6.5.tgz", + "integrity": "sha512-0cp4PsWQ/9avqTVMCtZ+GirikIA36ikvjtHweU4/j8yLtgObI0+JUPhYFScgwlteveGB1rt3Cm8UhN04XayDig==", + "dev": true, + "dependencies": { + "ajv": "^6.12.0", + "ajv-keywords": "^3.4.1" + }, + "engines": { + "node": ">= 8.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/@electron/asar": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@electron/asar/-/asar-3.2.4.tgz", + "integrity": "sha512-lykfY3TJRRWFeTxccEKdf1I6BLl2Plw81H0bbp4Fc5iEc67foDCa5pjJQULVgo0wF+Dli75f3xVcdb/67FFZ/g==", + "dev": true, + "dependencies": { + "chromium-pickle-js": "^0.2.0", + "commander": "^5.0.0", + "glob": "^7.1.6", + "minimatch": "^3.0.4" + }, + "bin": { + "asar": "bin/asar.js" + }, + "engines": { + "node": ">=10.12.0" + } + }, + "node_modules/@electron/asar/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@electron/asar/node_modules/commander": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz", + "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@electron/asar/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@electron/get": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@electron/get/-/get-2.0.2.tgz", + "integrity": "sha512-eFZVFoRXb3GFGd7Ak7W4+6jBl9wBtiZ4AaYOse97ej6mKj5tkyO0dUnUChs1IhJZtx1BENo4/p4WUTXpi6vT+g==", + "dependencies": { + "debug": "^4.1.1", + "env-paths": "^2.2.0", + "fs-extra": "^8.1.0", + "got": "^11.8.5", + "progress": "^2.0.3", + "semver": "^6.2.0", + "sumchecker": "^3.0.1" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "global-agent": "^3.0.0" + } + }, + "node_modules/@electron/get/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@electron/notarize": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@electron/notarize/-/notarize-2.1.0.tgz", + "integrity": "sha512-Q02xem1D0sg4v437xHgmBLxI2iz/fc0D4K7fiVWHa/AnW8o7D751xyKNXgziA6HrTOme9ul1JfWN5ark8WH1xA==", + "dev": true, + "dependencies": { + "debug": "^4.1.1", + "fs-extra": "^9.0.1", + "promise-retry": "^2.0.1" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/@electron/notarize/node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@electron/notarize/node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/@electron/notarize/node_modules/universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "dev": true, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/@electron/osx-sign": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@electron/osx-sign/-/osx-sign-1.0.5.tgz", + "integrity": "sha512-k9ZzUQtamSoweGQDV2jILiRIHUu7lYlJ3c6IEmjv1hC17rclE+eb9U+f6UFlOOETo0JzY1HNlXy4YOlCvl+Lww==", + "dev": true, + "dependencies": { + "compare-version": "^0.1.2", + "debug": "^4.3.4", + "fs-extra": "^10.0.0", + "isbinaryfile": "^4.0.8", + "minimist": "^1.2.6", + "plist": "^3.0.5" + }, + "bin": { + "electron-osx-flat": "bin/electron-osx-flat.js", + "electron-osx-sign": "bin/electron-osx-sign.js" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@electron/osx-sign/node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@electron/osx-sign/node_modules/isbinaryfile": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-4.0.10.tgz", + "integrity": "sha512-iHrqe5shvBUcFbmZq9zOQHBoeOhZJu6RQGrDpBgenUm/Am+F3JM2MgQj+rK3Z601fzrL5gLZWtAPH2OBaSVcyw==", + "dev": true, + "engines": { + "node": ">= 8.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/gjtorikian/" + } + }, + "node_modules/@electron/osx-sign/node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/@electron/osx-sign/node_modules/universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "dev": true, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/@electron/universal": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@electron/universal/-/universal-1.4.2.tgz", + "integrity": "sha512-ymGwXYBUGFS1DuTqYJwZ0p1gIlELKOf21zPJefij/amzV66vTXRNJ2mAtW0uRsaHfV+pzYTJVrt5oco44DFOMg==", + "dev": true, + "dependencies": { + "@electron/asar": "^3.2.1", + "@malept/cross-spawn-promise": "^1.1.0", + "debug": "^4.3.1", + "dir-compare": "^3.0.0", + "fs-extra": "^9.0.1", + "minimatch": "^3.0.4", + "plist": "^3.0.4" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/@electron/universal/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@electron/universal/node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@electron/universal/node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/@electron/universal/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@electron/universal/node_modules/universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "dev": true, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.8.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.8.0.tgz", + "integrity": "sha512-JylOEEzDiOryeUnFbQz+oViCXS0KsvR1mvHkoMiu5+UiBvy+RYX7tzlIIIEstF/gVa2tj9AQXk3dgnxv6KxhFg==", + "dev": true, + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.2.tgz", + "integrity": "sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@eslint/eslintrc/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@eslint/js": { + "version": "8.50.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.50.0.tgz", + "integrity": "sha512-NCC3zz2+nvYd+Ckfh87rA47zfu2QsQpvc6k1yzTk+b9KzRj0wkGa8LSoGOXN6Zv4lRf/EIoZ80biDh9HOI+RNQ==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@ffmpeg.wasm/core-mt": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@ffmpeg.wasm/core-mt/-/core-mt-0.12.0.tgz", + "integrity": "sha512-M9pjL7JQX4AYl3WI8vGcPGPTz/O7JmhW8ac/fHA3oXTxoRAPwYSY/OsY1N9C0XahIM0+fxa1QSLN9Ekz8sBM/Q==" + }, + "node_modules/@ffmpeg.wasm/main": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@ffmpeg.wasm/main/-/main-0.12.0.tgz", + "integrity": "sha512-LILAKTrU3Rga2iXLsF9jeFxe2hNQFjWlrKuXPWSdCFeQ7Kg69fO4WwjNJ0CzjOyO6qtndRQMNKqf//N4fLYUBA==", + "dependencies": { + "is-url": "^1.2.4", + "node-fetch": "^2.6.9", + "regenerator-runtime": "^0.13.11" + }, + "engines": { + "node": ">=12.16.1" + } + }, + "node_modules/@foobar404/wave": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@foobar404/wave/-/wave-2.0.4.tgz", + "integrity": "sha512-FEyg37hDvQtrQVlFxbit7ov5e487BjsR32bZfJ4oAb5i+NnlbGaNyy6iYBZ8ocVHo8fgug+SL+mFdDTzqjvPww==" + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.11.11", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.11.tgz", + "integrity": "sha512-N2brEuAadi0CcdeMXUkhbZB84eskAc8MEX1By6qEchoVywSgXPIjou4rYsl0V3Hj0ZnuGycGCjdNgockbzeWNA==", + "dev": true, + "dependencies": { + "@humanwhocodes/object-schema": "^1.2.1", + "debug": "^4.1.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/config-array/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@humanwhocodes/config-array/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "dev": true + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, + "node_modules/@isaacs/cliui/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/@malept/cross-spawn-promise": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@malept/cross-spawn-promise/-/cross-spawn-promise-1.1.1.tgz", + "integrity": "sha512-RTBGWL5FWQcg9orDOCcp4LvItNzUPcyEU9bwaeJX0rJ1IQxzucC48Y0/sQLp/g6t99IQgAlGIaesJS+gTn7tVQ==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/malept" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/subscription/pkg/npm-.malept-cross-spawn-promise?utm_medium=referral&utm_source=npm_fund" + } + ], + "dependencies": { + "cross-spawn": "^7.0.1" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@malept/flatpak-bundler": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@malept/flatpak-bundler/-/flatpak-bundler-0.4.0.tgz", + "integrity": "sha512-9QOtNffcOF/c1seMCDnjckb3R9WHcG34tky+FHpNKKCW0wc/scYLwMtO+ptyGUfMW0/b/n4qRiALlaFHc9Oj7Q==", + "dev": true, + "dependencies": { + "debug": "^4.1.1", + "fs-extra": "^9.0.0", + "lodash": "^4.17.15", + "tmp-promise": "^3.0.2" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/@malept/flatpak-bundler/node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@malept/flatpak-bundler/node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/@malept/flatpak-bundler/node_modules/universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "dev": true, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nornagon/put": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/@nornagon/put/-/put-0.0.8.tgz", + "integrity": "sha512-ugvXJjwF5ldtUpa7D95kruNJ41yFQDEKyF5CW4TgKJnh+W/zmlBzXXeKTyqIgwMFrkePN2JqOBqcF0M0oOunow==", + "engines": { + "node": ">=0.3.0" + } + }, + "node_modules/@npmcli/fs": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-3.1.0.tgz", + "integrity": "sha512-7kZUAaLscfgbwBQRbvdMYaZOWyMEcPTH/tJjnyAWJ/dvvs9Ef+CERx/qJb9GExJpl1qipaDGn7KqHnFGGixd0w==", + "dev": true, + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@pkgr/utils": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/@pkgr/utils/-/utils-2.4.2.tgz", + "integrity": "sha512-POgTXhjrTfbTV63DiFXav4lBHiICLKKwDeaKn9Nphwj7WH6m0hMMCaJkMyRWjgtPFyRKRVoMXXjczsTQRDEhYw==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "fast-glob": "^3.3.0", + "is-glob": "^4.0.3", + "open": "^9.1.0", + "picocolors": "^1.0.0", + "tslib": "^2.6.0" + }, + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts" + } + }, + "node_modules/@pkgr/utils/node_modules/open": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/open/-/open-9.1.0.tgz", + "integrity": "sha512-OS+QTnw1/4vrf+9hh1jc1jnYjzSG4ttTBB8UxOwAnInG3Uo4ssetzC1ihqaIHjLJnA5GGlRl6QlZXOTQhRBUvg==", + "dev": true, + "dependencies": { + "default-browser": "^4.0.0", + "define-lazy-prop": "^3.0.0", + "is-inside-container": "^1.0.0", + "is-wsl": "^2.2.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@playwright/test": { + "version": "1.38.1", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.38.1.tgz", + "integrity": "sha512-NqRp8XMwj3AK+zKLbZShl0r/9wKgzqI/527bkptKXomtuo+dOjU9NdMASQ8DNC9z9zLOMbG53T4eihYr3XR+BQ==", + "dev": true, + "dependencies": { + "playwright": "1.38.1" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/@remusao/guess-url-type": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@remusao/guess-url-type/-/guess-url-type-1.2.1.tgz", + "integrity": "sha512-rbOqre2jW8STjheOsOaQHLgYBaBZ9Owbdt8NO7WvNZftJlaG3y/K9oOkl8ZUpuFBisIhmBuMEW6c+YrQl5inRA==" + }, + "node_modules/@remusao/small": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@remusao/small/-/small-1.2.1.tgz", + "integrity": "sha512-7MjoGt0TJMVw1GPKgWq6SJPws1SLsUXQRa43Umht+nkyw2jnpy3WpiLNqGdwo5rHr5Wp9B2W/Pm5RQp656UJdw==" + }, + "node_modules/@remusao/smaz": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@remusao/smaz/-/smaz-1.9.1.tgz", + "integrity": "sha512-e6BLuP8oaXCZ9+v46Is4ilAZ/Vq6YLgmBP204Ixgk1qTjXmqvFYG7+AS7v9nsZdGOy96r9DWGFbbDVgMxwu1rA==", + "dependencies": { + "@remusao/smaz-compress": "^1.9.1", + "@remusao/smaz-decompress": "^1.9.1" + } + }, + "node_modules/@remusao/smaz-compress": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@remusao/smaz-compress/-/smaz-compress-1.9.1.tgz", + "integrity": "sha512-E2f48TwloQu3r6BdLOGF2aczeH7bJ/32oJGqvzT9SKur0cuUnLcZ7ZXP874E2fwmdE+cXzfC7bKzp79cDnmeyw==", + "dependencies": { + "@remusao/trie": "^1.4.1" + } + }, + "node_modules/@remusao/smaz-decompress": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@remusao/smaz-decompress/-/smaz-decompress-1.9.1.tgz", + "integrity": "sha512-TfjKKprYe3n47od8auhvJ/Ikj9kQTbDTe71ynKlxslrvvUhlIV3VQSuwYuMWMbdz1fIs0H/fxCN1Z8/H3km6/A==" + }, + "node_modules/@remusao/trie": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@remusao/trie/-/trie-1.4.1.tgz", + "integrity": "sha512-yvwa+aCyYI/UjeD39BnpMypG8N06l86wIDW1/PAc6ihBRnodIfZDwccxQN3n1t74wduzaz74m4ZMHZnB06567Q==" + }, + "node_modules/@selderee/plugin-htmlparser2": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@selderee/plugin-htmlparser2/-/plugin-htmlparser2-0.11.0.tgz", + "integrity": "sha512-P33hHGdldxGabLFjPPpaTxVolMrzrcegejx+0GxjrIb9Zv48D8yAIA/QTDR2dFl7Uz7urX8aX6+5bCZslr+gWQ==", + "dependencies": { + "domhandler": "^5.0.3", + "selderee": "^0.11.0" + }, + "funding": { + "url": "https://ko-fi.com/killymxi" + } + }, + "node_modules/@sindresorhus/is": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz", + "integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/is?sponsor=1" + } + }, + "node_modules/@szmarczak/http-timer": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz", + "integrity": "sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==", + "dependencies": { + "defer-to-connect": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@tootallnate/once": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", + "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", + "dev": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@total-typescript/ts-reset": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@total-typescript/ts-reset/-/ts-reset-0.5.1.tgz", + "integrity": "sha512-AqlrT8YA1o7Ff5wPfMOL0pvL+1X+sw60NN6CcOCqs658emD6RfiXhF7Gu9QcfKBH7ELY2nInLhKSCWVoNL70MQ==", + "dev": true + }, + "node_modules/@types/cacheable-request": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.3.tgz", + "integrity": "sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==", + "dependencies": { + "@types/http-cache-semantics": "*", + "@types/keyv": "^3.1.4", + "@types/node": "*", + "@types/responselike": "^1.0.0" + } + }, + "node_modules/@types/chrome": { + "version": "0.0.246", + "resolved": "https://registry.npmjs.org/@types/chrome/-/chrome-0.0.246.tgz", + "integrity": "sha512-MxGxEomGxsJiL9xe/7ZwVgwdn8XVKWbPvxpVQl3nWOjrS0Ce63JsfzxUc4aU3GvRcUPYsfufHmJ17BFyKxeA4g==", + "dependencies": { + "@types/filesystem": "*", + "@types/har-format": "*" + } + }, + "node_modules/@types/debug": { + "version": "4.1.8", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.8.tgz", + "integrity": "sha512-/vPO1EPOs306Cvhwv7KfVfYvOJqA/S/AXjaHQiJboCZzcNDb+TIJFN9/2C9DZ//ijSKWioNyUxD792QmDJ+HKQ==", + "dev": true, + "dependencies": { + "@types/ms": "*" + } + }, + "node_modules/@types/electron-localshortcut": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@types/electron-localshortcut/-/electron-localshortcut-3.1.1.tgz", + "integrity": "sha512-wKmSZF2j+20/1SVbhcnqi0k+cLEMFjz4PPgNmUFjRdr+KiDRhX7f9hZd1wY56UhPtp9TJm4KAUQncrXcGfpGqw==", + "dev": true, + "dependencies": { + "electron": "*" + } + }, + "node_modules/@types/filesystem": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/@types/filesystem/-/filesystem-0.0.33.tgz", + "integrity": "sha512-2KedRPzwu2K528vFkoXnnWdsG0MtUwPjuA7pRy4vKxlxHEe8qUDZibYHXJKZZr2Cl/ELdCWYqyb/MKwsUuzBWw==", + "dependencies": { + "@types/filewriter": "*" + } + }, + "node_modules/@types/filewriter": { + "version": "0.0.30", + "resolved": "https://registry.npmjs.org/@types/filewriter/-/filewriter-0.0.30.tgz", + "integrity": "sha512-lB98tui0uxc7erbj0serZfJlHKLNJHwBltPnbmO1WRpL5T325GOHRiQfr2E29V2q+S1brDO63Fpdt6vb3bES9Q==" + }, + "node_modules/@types/firefox-webext-browser": { + "version": "111.0.2", + "resolved": "https://registry.npmjs.org/@types/firefox-webext-browser/-/firefox-webext-browser-111.0.2.tgz", + "integrity": "sha512-NS7izfYOnQI/Opf3YdZSKkI5Ox89SqEffJHK2zfGY2BYEVuWuM6pSwDRglGl4W0SM84oUQfvLyYH4X6EQZAJ2w==" + }, + "node_modules/@types/fs-extra": { + "version": "9.0.13", + "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-9.0.13.tgz", + "integrity": "sha512-nEnwB++1u5lVDM2UI4c1+5R+FYaKfaAzS4OococimjVm3nQw3TuzH5UNsocrcTBbhnerblyHj4A49qXbIiZdpA==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/har-format": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/@types/har-format/-/har-format-1.2.13.tgz", + "integrity": "sha512-PwBsCBD3lDODn4xpje3Y1di0aDJp4Ww7aSfMRVw6ysnxD4I7Wmq2mBkSKaDtN403hqH5sp6c9xQUvFYY3+lkBg==" + }, + "node_modules/@types/howler": { + "version": "2.2.9", + "resolved": "https://registry.npmjs.org/@types/howler/-/howler-2.2.9.tgz", + "integrity": "sha512-kNi8mBM+IAmMzo1xhFlR8pKUWqCz9kEtiT1Xp5hZW0ynQl2wUg0EAm+brsHvhahMzxlADt0Xhu0jV/NHmk/Ibg==", + "dev": true + }, + "node_modules/@types/html-to-text": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/@types/html-to-text/-/html-to-text-9.0.2.tgz", + "integrity": "sha512-cO9qsPwfIJ2GKFJ4AgpgmmFoUr0IulsN1clwOiPdChpsY/LVmbpGenUGrvZiYsSXSg/dWsj4NTzWZeIlv3D22w==", + "dev": true + }, + "node_modules/@types/http-cache-semantics": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.1.tgz", + "integrity": "sha512-SZs7ekbP8CN0txVG2xVRH6EgKmEm31BOxA07vkFaETzZz1xh+cbt8BcI0slpymvwhx5dlFnQG2rTlPVQn+iRPQ==" + }, + "node_modules/@types/json-schema": { + "version": "7.0.13", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.13.tgz", + "integrity": "sha512-RbSSoHliUbnXj3ny0CNFOoxrIDV6SUGyStHsvDqosw6CkdPV8TtWGlfecuK4ToyMEAql6pzNxgCFKanovUzlgQ==", + "dev": true + }, + "node_modules/@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", + "dev": true + }, + "node_modules/@types/keyv": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.4.tgz", + "integrity": "sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/minimist": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.2.tgz", + "integrity": "sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ==", + "dev": true + }, + "node_modules/@types/ms": { + "version": "0.7.31", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.31.tgz", + "integrity": "sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==", + "dev": true + }, + "node_modules/@types/node": { + "version": "20.5.7", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.5.7.tgz", + "integrity": "sha512-dP7f3LdZIysZnmvP3ANJYTSwg+wLLl8p7RqniVlV7j+oXSXAbt9h0WIBFmJy5inWZoX9wZN6eXx+YXd9Rh3RBA==" + }, + "node_modules/@types/normalize-package-data": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz", + "integrity": "sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==", + "dev": true + }, + "node_modules/@types/plist": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/plist/-/plist-3.0.2.tgz", + "integrity": "sha512-ULqvZNGMv0zRFvqn8/4LSPtnmN4MfhlPNtJCTpKuIIxGVGZ2rYWzFXrvEBoh9CVyqSE7D6YFRJ1hydLHI6kbWw==", + "dev": true, + "optional": true, + "dependencies": { + "@types/node": "*", + "xmlbuilder": ">=11.0.1" + } + }, + "node_modules/@types/responselike": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.0.tgz", + "integrity": "sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/semver": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.3.tgz", + "integrity": "sha512-OxepLK9EuNEIPxWNME+C6WwbRAOOI2o2BaQEGzz5Lu2e4Z5eDnEo+/aVEDMIXywoJitJ7xWd641wrGLZdtwRyw==", + "dev": true + }, + "node_modules/@types/verror": { + "version": "1.10.6", + "resolved": "https://registry.npmjs.org/@types/verror/-/verror-1.10.6.tgz", + "integrity": "sha512-NNm+gdePAX1VGvPcGZCDKQZKYSiAWigKhKaz5KF94hG6f2s8de9Ow5+7AbXoeKxL8gavZfk4UquSAygOF2duEQ==", + "dev": true, + "optional": true + }, + "node_modules/@types/yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha512-Cn6WYCm0tXv8p6k+A8PvbDG763EDpBoTzHdA+Q/MF6H3sapGjCm9NzoaJncJS9tUKSuCoDs9XHxYYsQDgxR6kw==", + "optional": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "6.7.4", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.7.4.tgz", + "integrity": "sha512-DAbgDXwtX+pDkAHwiGhqP3zWUGpW49B7eqmgpPtg+BKJXwdct79ut9+ifqOFPJGClGKSHXn2PTBatCnldJRUoA==", + "dev": true, + "dependencies": { + "@eslint-community/regexpp": "^4.5.1", + "@typescript-eslint/scope-manager": "6.7.4", + "@typescript-eslint/type-utils": "6.7.4", + "@typescript-eslint/utils": "6.7.4", + "@typescript-eslint/visitor-keys": "6.7.4", + "debug": "^4.3.4", + "graphemer": "^1.4.0", + "ignore": "^5.2.4", + "natural-compare": "^1.4.0", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^6.0.0 || ^6.0.0-alpha", + "eslint": "^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/scope-manager": { + "version": "6.7.4", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.7.4.tgz", + "integrity": "sha512-SdGqSLUPTXAXi7c3Ob7peAGVnmMoGzZ361VswK2Mqf8UOYcODiYvs8rs5ILqEdfvX1lE7wEZbLyELCW+Yrql1A==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.7.4", + "@typescript-eslint/visitor-keys": "6.7.4" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/types": { + "version": "6.7.4", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.7.4.tgz", + "integrity": "sha512-o9XWK2FLW6eSS/0r/tgjAGsYasLAnOWg7hvZ/dGYSSNjCh+49k5ocPN8OmG5aZcSJ8pclSOyVKP2x03Sj+RrCA==", + "dev": true, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/visitor-keys": { + "version": "6.7.4", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.7.4.tgz", + "integrity": "sha512-pOW37DUhlTZbvph50x5zZCkFn3xzwkGtNoJHzIM3svpiSkJzwOYr/kVBaXmf+RAQiUDs1AHEZVNPg6UJCJpwRA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.7.4", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.5.0.tgz", + "integrity": "sha512-LMAVtR5GN8nY0G0BadkG0XIe4AcNMeyEy3DyhKGAh9k4pLSMBO7rF29JvDBpZGCmp5Pgz5RLHP6eCpSYZJQDuQ==", + "dev": true, + "peer": true, + "dependencies": { + "@typescript-eslint/scope-manager": "6.5.0", + "@typescript-eslint/types": "6.5.0", + "@typescript-eslint/typescript-estree": "6.5.0", + "@typescript-eslint/visitor-keys": "6.5.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.5.0.tgz", + "integrity": "sha512-A8hZ7OlxURricpycp5kdPTH3XnjG85UpJS6Fn4VzeoH4T388gQJ/PGP4ole5NfKt4WDVhmLaQ/dBLNDC4Xl/Kw==", + "dev": true, + "peer": true, + "dependencies": { + "@typescript-eslint/types": "6.5.0", + "@typescript-eslint/visitor-keys": "6.5.0" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "6.7.4", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.7.4.tgz", + "integrity": "sha512-n+g3zi1QzpcAdHFP9KQF+rEFxMb2KxtnJGID3teA/nxKHOVi3ylKovaqEzGBbVY2pBttU6z85gp0D00ufLzViQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/typescript-estree": "6.7.4", + "@typescript-eslint/utils": "6.7.4", + "debug": "^4.3.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/types": { + "version": "6.7.4", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.7.4.tgz", + "integrity": "sha512-o9XWK2FLW6eSS/0r/tgjAGsYasLAnOWg7hvZ/dGYSSNjCh+49k5ocPN8OmG5aZcSJ8pclSOyVKP2x03Sj+RrCA==", + "dev": true, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/typescript-estree": { + "version": "6.7.4", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.7.4.tgz", + "integrity": "sha512-ty8b5qHKatlNYd9vmpHooQz3Vki3gG+3PchmtsA4TgrZBKWHNjWfkQid7K7xQogBqqc7/BhGazxMD5vr6Ha+iQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.7.4", + "@typescript-eslint/visitor-keys": "6.7.4", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/visitor-keys": { + "version": "6.7.4", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.7.4.tgz", + "integrity": "sha512-pOW37DUhlTZbvph50x5zZCkFn3xzwkGtNoJHzIM3svpiSkJzwOYr/kVBaXmf+RAQiUDs1AHEZVNPg6UJCJpwRA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.7.4", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils/node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@typescript-eslint/type-utils/node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.5.0.tgz", + "integrity": "sha512-eqLLOEF5/lU8jW3Bw+8auf4lZSbbljHR2saKnYqON12G/WsJrGeeDHWuQePoEf9ro22+JkbPfWQwKEC5WwLQ3w==", + "dev": true, + "peer": true, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.5.0.tgz", + "integrity": "sha512-q0rGwSe9e5Kk/XzliB9h2LBc9tmXX25G0833r7kffbl5437FPWb2tbpIV9wAATebC/018pGa9fwPDuvGN+LxWQ==", + "dev": true, + "peer": true, + "dependencies": { + "@typescript-eslint/types": "6.5.0", + "@typescript-eslint/visitor-keys": "6.5.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "peer": true, + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "6.7.4", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.7.4.tgz", + "integrity": "sha512-PRQAs+HUn85Qdk+khAxsVV+oULy3VkbH3hQ8hxLRJXWBEd7iI+GbQxH5SEUSH7kbEoTp6oT1bOwyga24ELALTA==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@types/json-schema": "^7.0.12", + "@types/semver": "^7.5.0", + "@typescript-eslint/scope-manager": "6.7.4", + "@typescript-eslint/types": "6.7.4", + "@typescript-eslint/typescript-estree": "6.7.4", + "semver": "^7.5.4" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/scope-manager": { + "version": "6.7.4", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.7.4.tgz", + "integrity": "sha512-SdGqSLUPTXAXi7c3Ob7peAGVnmMoGzZ361VswK2Mqf8UOYcODiYvs8rs5ILqEdfvX1lE7wEZbLyELCW+Yrql1A==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.7.4", + "@typescript-eslint/visitor-keys": "6.7.4" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/types": { + "version": "6.7.4", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.7.4.tgz", + "integrity": "sha512-o9XWK2FLW6eSS/0r/tgjAGsYasLAnOWg7hvZ/dGYSSNjCh+49k5ocPN8OmG5aZcSJ8pclSOyVKP2x03Sj+RrCA==", + "dev": true, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/typescript-estree": { + "version": "6.7.4", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.7.4.tgz", + "integrity": "sha512-ty8b5qHKatlNYd9vmpHooQz3Vki3gG+3PchmtsA4TgrZBKWHNjWfkQid7K7xQogBqqc7/BhGazxMD5vr6Ha+iQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.7.4", + "@typescript-eslint/visitor-keys": "6.7.4", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/visitor-keys": { + "version": "6.7.4", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.7.4.tgz", + "integrity": "sha512-pOW37DUhlTZbvph50x5zZCkFn3xzwkGtNoJHzIM3svpiSkJzwOYr/kVBaXmf+RAQiUDs1AHEZVNPg6UJCJpwRA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.7.4", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.5.0.tgz", + "integrity": "sha512-yCB/2wkbv3hPsh02ZS8dFQnij9VVQXJMN/gbQsaaY+zxALkZnxa/wagvLEFsAWMPv7d7lxQmNsIzGU1w/T/WyA==", + "dev": true, + "peer": true, + "dependencies": { + "@typescript-eslint/types": "6.5.0", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@xhayper/discord-rpc": { + "version": "1.0.23", + "resolved": "https://registry.npmjs.org/@xhayper/discord-rpc/-/discord-rpc-1.0.23.tgz", + "integrity": "sha512-C5J84PO0874QpBumc5z208y+Vn4OBDVjmnOKWavp/CAEkXjV6sLfgVFDnUjEPvQ08gv81lrxFNaU+jCqMFnNdQ==", + "dependencies": { + "axios": "^1.5.1", + "discord-api-types": "^0.37.58", + "ws": "^8.14.2" + }, + "engines": { + "node": ">=14.18.0" + } + }, + "node_modules/@xmldom/xmldom": { + "version": "0.8.10", + "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.10.tgz", + "integrity": "sha512-2WALfTl4xo2SkGCYRt6rDTFfk9R1czmBvUQy12gK2KuRKIpWEhcbbzy8EZXtz/jkRqHX8bFEc6FC1HjX4TUWYw==", + "dev": true, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/7zip-bin": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/7zip-bin/-/7zip-bin-5.1.1.tgz", + "integrity": "sha512-sAP4LldeWNz0lNzmTird3uWfFDWWTeg6V/MsmyyLR9X1idwKBWIgt/ZvinqQldJm3LecKEs1emkbquO6PCiLVQ==", + "dev": true + }, + "node_modules/abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "dev": true + }, + "node_modules/abstract-socket": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/abstract-socket/-/abstract-socket-2.1.1.tgz", + "integrity": "sha512-YZJizsvS1aBua5Gd01woe4zuyYBGgSMeqDOB6/ChwdTI904KP6QGtJswXl4hcqWxbz86hQBe++HWV0hF1aGUtA==", + "hasInstallScript": true, + "optional": true, + "os": [ + "linux" + ], + "dependencies": { + "bindings": "^1.2.1", + "nan": "^2.12.1" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/acorn": { + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", + "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/agentkeepalive": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.5.0.tgz", + "integrity": "sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew==", + "dev": true, + "dependencies": { + "humanize-ms": "^1.2.1" + }, + "engines": { + "node": ">= 8.0.0" + } + }, + "node_modules/aggregate-error": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-4.0.1.tgz", + "integrity": "sha512-0poP0T7el6Vq3rstR8Mn4V/IQrpBLO6POkUSrN7RhyY+GF/InCFShQzsQ39T25gkHhLgSLByyAz+Kjb+c2L98w==", + "dev": true, + "dependencies": { + "clean-stack": "^4.0.0", + "indent-string": "^5.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/aggregate-error/node_modules/clean-stack": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-4.2.0.tgz", + "integrity": "sha512-LYv6XPxoyODi36Dp976riBtSY27VmFo+MKqEU9QCCWyTrdEPDog+RWA7xQWHi6Vbp61j5c4cdzzX1NidnwtUWg==", + "dev": true, + "dependencies": { + "escape-string-regexp": "5.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/aggregate-error/node_modules/escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/ajv-formats/node_modules/ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + }, + "node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/app-builder-bin": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/app-builder-bin/-/app-builder-bin-4.0.0.tgz", + "integrity": "sha512-xwdG0FJPQMe0M0UA4Tz0zEB8rBJTRA5a476ZawAqiBkMv16GRK5xpXThOjMaEOFnZ6zabejjG4J3da0SXG63KA==", + "dev": true + }, + "node_modules/app-builder-lib": { + "version": "24.6.4", + "resolved": "https://registry.npmjs.org/app-builder-lib/-/app-builder-lib-24.6.4.tgz", + "integrity": "sha512-m9931WXb83teb32N0rKg+ulbn6+Hl8NV5SUpVDOVz9MWOXfhV6AQtTdftf51zJJvCQnQugGtSqoLvgw6mdF/Rg==", + "dev": true, + "dependencies": { + "@develar/schema-utils": "~2.6.5", + "@electron/notarize": "2.1.0", + "@electron/osx-sign": "1.0.5", + "@electron/universal": "1.4.1", + "@malept/flatpak-bundler": "^0.4.0", + "@types/fs-extra": "9.0.13", + "7zip-bin": "~5.1.1", + "async-exit-hook": "^2.0.1", + "bluebird-lst": "^1.0.9", + "builder-util": "24.5.0", + "builder-util-runtime": "9.2.1", + "chromium-pickle-js": "^0.2.0", + "debug": "^4.3.4", + "ejs": "^3.1.8", + "electron-publish": "24.5.0", + "form-data": "^4.0.0", + "fs-extra": "^10.1.0", + "hosted-git-info": "^4.1.0", + "is-ci": "^3.0.0", + "isbinaryfile": "^5.0.0", + "js-yaml": "^4.1.0", + "lazy-val": "^1.0.5", + "minimatch": "^5.1.1", + "read-config-file": "6.3.2", + "sanitize-filename": "^1.6.3", + "semver": "^7.3.8", + "tar": "^6.1.12", + "temp-file": "^3.4.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/app-builder-lib/node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/app-builder-lib/node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/app-builder-lib/node_modules/universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "dev": true, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/aproba": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", + "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==", + "dev": true + }, + "node_modules/are-we-there-yet": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-3.0.1.tgz", + "integrity": "sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==", + "dev": true, + "dependencies": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + }, + "node_modules/array-buffer-byte-length": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz", + "integrity": "sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "is-array-buffer": "^3.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-includes": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.6.tgz", + "integrity": "sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "get-intrinsic": "^1.1.3", + "is-string": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/array.prototype.findlastindex": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.3.tgz", + "integrity": "sha512-LzLoiOMAxvy+Gd3BAq3B7VeIgPdo+Q8hthvKtXybMvRV0jrXfJM/t8mw7nNlpEcVlVUnCnM2KSX4XU5HmpodOA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0", + "get-intrinsic": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flat": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.1.tgz", + "integrity": "sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flatmap": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.1.tgz", + "integrity": "sha512-8UGn9O1FDVvMNB0UlLv4voxRMze7+FpHyF5mSMRjWHUMlpoDViniy05870VlxhfgTnLbpuwTzvD76MTtWxB/mQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.1.tgz", + "integrity": "sha512-09x0ZWFEjj4WD8PDbykUwo3t9arLn8NIzmmYEJFpYekOAQjpkGSyrQhNoRTcwwcFRu+ycWF78QZ63oWTqSjBcw==", + "dev": true, + "dependencies": { + "array-buffer-byte-length": "^1.0.0", + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "get-intrinsic": "^1.2.1", + "is-array-buffer": "^3.0.2", + "is-shared-array-buffer": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", + "dev": true, + "optional": true, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "dev": true, + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/async": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz", + "integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==", + "dev": true + }, + "node_modules/async-exit-hook": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/async-exit-hook/-/async-exit-hook-2.0.1.tgz", + "integrity": "sha512-NW2cX8m1Q7KPA7a5M2ULQeZ2wR5qI5PAbw5L0UOMxdioVk9PMZ0h1TmyZEkPYrCvYjDlFICusOu1dlEKAAeXBw==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/async-mutex": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/async-mutex/-/async-mutex-0.4.0.tgz", + "integrity": "sha512-eJFZ1YhRR8UN8eBLoNzcDPcy/jqjsg6I1AP+KvWQX80BqOSW1oJPJXDylPUEeMr2ZQvHgnQ//Lp6f3RQ1zI7HA==", + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, + "node_modules/at-least-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", + "dev": true, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/atomically": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/atomically/-/atomically-1.7.0.tgz", + "integrity": "sha512-Xcz9l0z7y9yQ9rdDaxlmaI4uJHf/T8g9hOEzJcsEqX2SjCj4J20uK7+ldkDHMbpJDK76wF7xEIgxc/vSlsfw5w==", + "engines": { + "node": ">=10.12.0" + } + }, + "node_modules/auto-changelog": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/auto-changelog/-/auto-changelog-2.4.0.tgz", + "integrity": "sha512-vh17hko1c0ItsEcw6m7qPRf3m45u+XK5QyCrrBFViElZ8jnKrPC1roSznrd1fIB/0vR/zawdECCRJtTuqIXaJw==", + "dev": true, + "dependencies": { + "commander": "^7.2.0", + "handlebars": "^4.7.7", + "node-fetch": "^2.6.1", + "parse-github-url": "^1.0.2", + "semver": "^7.3.5" + }, + "bin": { + "auto-changelog": "src/index.js" + }, + "engines": { + "node": ">=8.3" + } + }, + "node_modules/available-typed-arrays": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", + "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/axios": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.5.1.tgz", + "integrity": "sha512-Q28iYCWzNHjAm+yEAot5QaAMxhMghWLFVf7rRdwhUI+c2jix2DUXjAHXVi+s1ibs3mjPO/cCgbA++3BjD0vP/A==", + "dependencies": { + "follow-redirects": "^1.15.0", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/babel-runtime": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", + "integrity": "sha512-ITKNuq2wKlW1fJg9sSW52eepoYgZBggvOAHC0u/CYu/qxQ9EVzThCgR69BnSXLHjy2f7SY5zaQ4yt7H9ZVxY2g==", + "dependencies": { + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" + } + }, + "node_modules/babel-runtime/node_modules/regenerator-runtime": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", + "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==" + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/big-integer": { + "version": "1.6.51", + "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.51.tgz", + "integrity": "sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==", + "dev": true, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/bindings": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", + "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "optional": true, + "dependencies": { + "file-uri-to-path": "1.0.0" + } + }, + "node_modules/bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", + "dev": true + }, + "node_modules/bluebird-lst": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/bluebird-lst/-/bluebird-lst-1.0.9.tgz", + "integrity": "sha512-7B1Rtx82hjnSD4PGLAjVWeYH3tHAcVUmChh85a3lltKQm6FresXh9ErQo6oAv6CqxttczC3/kEg8SY5NluPuUw==", + "dev": true, + "dependencies": { + "bluebird": "^3.5.5" + } + }, + "node_modules/boolean": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/boolean/-/boolean-3.2.0.tgz", + "integrity": "sha512-d0II/GO9uf9lfUHH2BQsjxzRJZBdsjgsBiW4BvhWk/3qoKwQFjIDVN19PfX8F2D/r9PCMTtLWjYVCFrpeYUzsw==", + "optional": true + }, + "node_modules/bplist-parser": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/bplist-parser/-/bplist-parser-0.2.0.tgz", + "integrity": "sha512-z0M+byMThzQmD9NILRniCUXYsYpjwnlO8N5uCFaCqIOpqRsJCrQL9NK3JsD67CN5a08nF5oIL2bD6loTdHOuKw==", + "dev": true, + "dependencies": { + "big-integer": "^1.6.44" + }, + "engines": { + "node": ">= 5.10.0" + } + }, + "node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "optional": true, + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", + "engines": { + "node": "*" + } + }, + "node_modules/buffer-equal": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal/-/buffer-equal-1.0.1.tgz", + "integrity": "sha512-QoV3ptgEaQpvVwbXdSO39iqPQTCxSF7A5U99AxbHYqUdCizL/lH2Z0A2y6nbZucxMEOtNyZfG2s6gsVugGpKkg==", + "dev": true, + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" + }, + "node_modules/builder-util": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/builder-util/-/builder-util-24.5.0.tgz", + "integrity": "sha512-STnBmZN/M5vGcv01u/K8l+H+kplTaq4PAIn3yeuufUKSpcdro0DhJWxPI81k5XcNfC//bjM3+n9nr8F9uV4uAQ==", + "dev": true, + "dependencies": { + "@types/debug": "^4.1.6", + "7zip-bin": "~5.1.1", + "app-builder-bin": "4.0.0", + "bluebird-lst": "^1.0.9", + "builder-util-runtime": "9.2.1", + "chalk": "^4.1.2", + "cross-spawn": "^7.0.3", + "debug": "^4.3.4", + "fs-extra": "^10.1.0", + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.1", + "is-ci": "^3.0.0", + "js-yaml": "^4.1.0", + "source-map-support": "^0.5.19", + "stat-mode": "^1.0.0", + "temp-file": "^3.4.0" + } + }, + "node_modules/builder-util-runtime": { + "version": "9.2.1", + "resolved": "https://registry.npmjs.org/builder-util-runtime/-/builder-util-runtime-9.2.1.tgz", + "integrity": "sha512-2rLv/uQD2x+dJ0J3xtsmI12AlRyk7p45TEbE/6o/fbb633e/S3pPgm+ct+JHsoY7r39dKHnGEFk/AASRFdnXmA==", + "dependencies": { + "debug": "^4.3.4", + "sax": "^1.2.4" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/builder-util/node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/builder-util/node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/builder-util/node_modules/universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "dev": true, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/bundle-name": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-3.0.0.tgz", + "integrity": "sha512-PKA4BeSvBpQKQ8iPOGCSiell+N8P+Tf1DlwqmYhpe2gAhKPHn8EYOxVT+ShuGmhg8lN8XiSlS80yiExKXrURlw==", + "dev": true, + "dependencies": { + "run-applescript": "^5.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/busboy": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", + "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", + "dependencies": { + "streamsearch": "^1.1.0" + }, + "engines": { + "node": ">=10.16.0" + } + }, + "node_modules/butterchurn": { + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/butterchurn/-/butterchurn-2.6.7.tgz", + "integrity": "sha512-BJiRA8L0L2+84uoG2SSfkp0kclBuN+vQKf217pK7pMlwEO2ZEg3MtO2/o+l8Qpr8Nbejg8tmL1ZHD1jmhiaaqg==", + "dependencies": { + "@babel/runtime": "^7.0.0", + "ecma-proposal-math-extensions": "0.0.2" + } + }, + "node_modules/butterchurn-presets": { + "version": "2.4.7", + "resolved": "https://registry.npmjs.org/butterchurn-presets/-/butterchurn-presets-2.4.7.tgz", + "integrity": "sha512-4MdM8ripz/VfH1BCldrIKdAc/1ryJFBDvqlyow6Ivo1frwj0H3duzvSMFC7/wIjAjxb1QpwVHVqGqS9uAFKhpg==", + "dependencies": { + "babel-runtime": "^6.26.0", + "ecma-proposal-math-extensions": "0.0.2", + "lodash": "^4.17.4" + } + }, + "node_modules/cacache": { + "version": "17.1.4", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-17.1.4.tgz", + "integrity": "sha512-/aJwG2l3ZMJ1xNAnqbMpA40of9dj/pIH3QfiuQSqjfPJF747VR0J/bHn+/KdNnHKc6XQcWt/AfRSBft82W1d2A==", + "dev": true, + "dependencies": { + "@npmcli/fs": "^3.1.0", + "fs-minipass": "^3.0.0", + "glob": "^10.2.2", + "lru-cache": "^7.7.1", + "minipass": "^7.0.3", + "minipass-collect": "^1.0.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "p-map": "^4.0.0", + "ssri": "^10.0.0", + "tar": "^6.1.11", + "unique-filename": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/cacache/node_modules/aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "dev": true, + "dependencies": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cacache/node_modules/glob": { + "version": "10.3.4", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.4.tgz", + "integrity": "sha512-6LFElP3A+i/Q8XQKEvZjkEWEOTgAIALR9AO2rwT8bgPhDd1anmqDJDZ6lLddI4ehxxxR1S5RIqKe1uapMQfYaQ==", + "dev": true, + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^2.0.3", + "minimatch": "^9.0.1", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", + "path-scurry": "^1.10.1" + }, + "bin": { + "glob": "dist/cjs/src/bin.js" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/cacache/node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/cacache/node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/cacache/node_modules/minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/cacache/node_modules/minipass": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.3.tgz", + "integrity": "sha512-LhbbwCfz3vsb12j/WkWQPZfKTsgqIe1Nf/ti1pKjYESGLHIVjWU96G9/ljLH4F9mWNVhlQOm0VySdAWzf05dpg==", + "dev": true, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/cacache/node_modules/p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "dev": true, + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cacheable-lookup": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz", + "integrity": "sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==", + "engines": { + "node": ">=10.6.0" + } + }, + "node_modules/cacheable-request": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.4.tgz", + "integrity": "sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg==", + "dependencies": { + "clone-response": "^1.0.2", + "get-stream": "^5.1.0", + "http-cache-semantics": "^4.0.0", + "keyv": "^4.0.0", + "lowercase-keys": "^2.0.0", + "normalize-url": "^6.0.1", + "responselike": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dependencies": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/camelcase-keys": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-7.0.2.tgz", + "integrity": "sha512-Rjs1H+A9R+Ig+4E/9oyB66UC5Mj9Xq3N//vcLf2WzgdTi/3gUu3Z9KoqmlrEG4VuuLK8wJHofxzdQXz/knhiYg==", + "dev": true, + "dependencies": { + "camelcase": "^6.3.0", + "map-obj": "^4.1.0", + "quick-lru": "^5.1.1", + "type-fest": "^1.2.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/camelcase-keys/node_modules/type-fest": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz", + "integrity": "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/chromium-pickle-js": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/chromium-pickle-js/-/chromium-pickle-js-0.2.0.tgz", + "integrity": "sha512-1R5Fho+jBq0DDydt+/vHWj5KJNJCKdARKOCwZUen84I5BreWoLqRLANH1U87eJy1tiASPtMnGqJJq0ZsLoRPOw==", + "dev": true + }, + "node_modules/ci-info": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.8.0.tgz", + "integrity": "sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "engines": { + "node": ">=8" + } + }, + "node_modules/clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "engines": { + "node": ">=6" + } + }, + "node_modules/cli-truncate": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-2.1.0.tgz", + "integrity": "sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==", + "dev": true, + "optional": true, + "dependencies": { + "slice-ansi": "^3.0.0", + "string-width": "^4.2.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/clone-response": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.3.tgz", + "integrity": "sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==", + "dependencies": { + "mimic-response": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/color-support": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", + "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", + "dev": true, + "bin": { + "color-support": "bin.js" + } + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "dev": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/compare-version": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/compare-version/-/compare-version-0.1.2.tgz", + "integrity": "sha512-pJDh5/4wrEnXX/VWRZvruAGHkzKdr46z11OlTPN+VrATlWWhSKewNCJ1futCO5C7eJB3nPMFZA1LeYtcFboZ2A==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "node_modules/conf": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/conf/-/conf-10.2.0.tgz", + "integrity": "sha512-8fLl9F04EJqjSqH+QjITQfJF8BrOVaYr1jewVgSRAEWePfxT0sku4w2hrGQ60BC/TNLGQ2pgxNlTbWQmMPFvXg==", + "dependencies": { + "ajv": "^8.6.3", + "ajv-formats": "^2.1.1", + "atomically": "^1.7.0", + "debounce-fn": "^4.0.0", + "dot-prop": "^6.0.1", + "env-paths": "^2.2.1", + "json-schema-typed": "^7.0.3", + "onetime": "^5.1.2", + "pkg-up": "^3.1.0", + "semver": "^7.3.5" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/conf/node_modules/ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/conf/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + }, + "node_modules/config-file-ts": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/config-file-ts/-/config-file-ts-0.2.4.tgz", + "integrity": "sha512-cKSW0BfrSaAUnxpgvpXPLaaW/umg4bqg4k3GO1JqlRfpx+d5W0GDXznCMkWotJQek5Mmz1MJVChQnz3IVaeMZQ==", + "dev": true, + "dependencies": { + "glob": "^7.1.6", + "typescript": "^4.0.2" + } + }, + "node_modules/config-file-ts/node_modules/typescript": { + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", + "dev": true + }, + "node_modules/copyfiles": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/copyfiles/-/copyfiles-2.4.1.tgz", + "integrity": "sha512-fereAvAvxDrQDOXybk3Qu3dPbOoKoysFMWtkY3mv5BsL8//OSZVL5DCLYqgRfY5cWirgRzlC+WSrxp6Bo3eNZg==", + "dev": true, + "dependencies": { + "glob": "^7.0.5", + "minimatch": "^3.0.3", + "mkdirp": "^1.0.4", + "noms": "0.0.0", + "through2": "^2.0.1", + "untildify": "^4.0.0", + "yargs": "^16.1.0" + }, + "bin": { + "copyfiles": "copyfiles", + "copyup": "copyfiles" + } + }, + "node_modules/copyfiles/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/copyfiles/node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/copyfiles/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/copyfiles/node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/core-js": { + "version": "2.6.12", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz", + "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==", + "deprecated": "core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js.", + "hasInstallScript": true + }, + "node_modules/core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==", + "dev": true + }, + "node_modules/crc": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/crc/-/crc-3.8.0.tgz", + "integrity": "sha512-iX3mfgcTMIq3ZKLIsVFAbv7+Mc10kxabAGQb8HvjA1o3T1PIYprbakQ65d3I+2HGHt6nSKkM9PYjgoJO2KcFBQ==", + "dev": true, + "optional": true, + "dependencies": { + "buffer": "^5.1.0" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/custom-electron-prompt": { + "version": "1.5.7", + "resolved": "https://registry.npmjs.org/custom-electron-prompt/-/custom-electron-prompt-1.5.7.tgz", + "integrity": "sha512-ptRPJr6CpT06GWLMtg3GD2Lr7gWfXdWI+hR1S39eq+m/mUa2E118YmX6mPCbHdg5QB/W9UVhSpRqBM8FUh1G8w==", + "peerDependencies": { + "electron": ">=10.0.0" + } + }, + "node_modules/custom-electron-titlebar": { + "version": "4.1.6", + "resolved": "https://registry.npmjs.org/custom-electron-titlebar/-/custom-electron-titlebar-4.1.6.tgz", + "integrity": "sha512-AGULUZMxhEZDpl0Z1jfZzXgQEdhAPe8YET0dYQA/19t8oCrTFzF2PzdvJNCmxGU4Ai3jPWVeCPKg4vM7ffU0Mg==", + "peerDependencies": { + "electron": ">20" + } + }, + "node_modules/dbus-next": { + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/dbus-next/-/dbus-next-0.9.2.tgz", + "integrity": "sha512-tzQq/+wrTZ2yU+U5PoeXc97KABhX2v55C/T0finH3tSKYuI8H/SqppIFymBBrUHcK13LvEGY3vdj3ikPPenL5g==", + "dependencies": { + "@nornagon/put": "0.0.8", + "event-stream": "3.3.4", + "hexy": "^0.2.10", + "jsbi": "^2.0.5", + "long": "^4.0.0", + "safe-buffer": "^5.1.1", + "xml2js": "^0.4.17" + }, + "optionalDependencies": { + "abstract-socket": "^2.0.0" + } + }, + "node_modules/debounce-fn": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/debounce-fn/-/debounce-fn-4.0.0.tgz", + "integrity": "sha512-8pYCQiL9Xdcg0UPSD3d+0KMlOjp+KGU5EPwYddgzQ7DATsg4fuUDjQtsYLmWjnk2obnNHgV3vE2Y4jejSOJVBQ==", + "dependencies": { + "mimic-fn": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/debounce-fn/node_modules/mimic-fn": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-3.1.0.tgz", + "integrity": "sha512-Ysbi9uYW9hFyfrThdDEQuykN4Ey6BuwPD2kpI5ES/nFTDn/98yxYNLZJcgUAKPT/mcrLLKaGzJR9YVxJrIdASQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decamelize": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-5.0.1.tgz", + "integrity": "sha512-VfxadyCECXgQlkoEAjeghAr5gY3Hf+IKjKb+X8tGVDtveCjN+USwprd2q3QXBR9T1+x2DG0XZF5/w+7HAtSaXA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/decamelize-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.1.tgz", + "integrity": "sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg==", + "dev": true, + "dependencies": { + "decamelize": "^1.1.0", + "map-obj": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/decamelize-keys/node_modules/decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/decamelize-keys/node_modules/map-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", + "integrity": "sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "dependencies": { + "mimic-response": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/decompress-response/node_modules/mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/deep-equal": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.1.tgz", + "integrity": "sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g==", + "dependencies": { + "is-arguments": "^1.0.4", + "is-date-object": "^1.0.1", + "is-regex": "^1.0.4", + "object-is": "^1.0.1", + "object-keys": "^1.1.1", + "regexp.prototype.flags": "^1.2.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/default-browser": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-4.0.0.tgz", + "integrity": "sha512-wX5pXO1+BrhMkSbROFsyxUm0i/cJEScyNhA4PPxc41ICuv05ZZB/MX28s8aZx6xjmatvebIapF6hLEKEcpneUA==", + "dev": true, + "dependencies": { + "bundle-name": "^3.0.0", + "default-browser-id": "^3.0.0", + "execa": "^7.1.1", + "titleize": "^3.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-browser-id": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-3.0.0.tgz", + "integrity": "sha512-OZ1y3y0SqSICtE8DE4S8YOE9UZOJ8wO16fKWVP5J1Qz42kV9jcnMVFrEE/noXb/ss3Q4pZIH79kxofzyNNtUNA==", + "dev": true, + "dependencies": { + "bplist-parser": "^0.2.0", + "untildify": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/defer-to-connect": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", + "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==", + "engines": { + "node": ">=10" + } + }, + "node_modules/define-lazy-prop": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", + "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/define-properties": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.0.tgz", + "integrity": "sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==", + "dependencies": { + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/del": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/del/-/del-7.1.0.tgz", + "integrity": "sha512-v2KyNk7efxhlyHpjEvfyxaAihKKK0nWCuf6ZtqZcFFpQRG0bJ12Qsr0RpvsICMjAAZ8DOVCxrlqpxISlMHC4Kg==", + "dev": true, + "dependencies": { + "globby": "^13.1.2", + "graceful-fs": "^4.2.10", + "is-glob": "^4.0.3", + "is-path-cwd": "^3.0.0", + "is-path-inside": "^4.0.0", + "p-map": "^5.5.0", + "rimraf": "^3.0.2", + "slash": "^4.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/del-cli": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/del-cli/-/del-cli-5.1.0.tgz", + "integrity": "sha512-xwMeh2acluWeccsfzE7VLsG3yTr7nWikbfw+xhMnpRrF15pGSkw+3/vJZWlGoE4I86UiLRNHicmKt4tkIX9Jtg==", + "dev": true, + "dependencies": { + "del": "^7.1.0", + "meow": "^10.1.3" + }, + "bin": { + "del": "cli.js", + "del-cli": "cli.js" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", + "dev": true + }, + "node_modules/detect-node": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", + "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", + "optional": true + }, + "node_modules/dir-compare": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/dir-compare/-/dir-compare-3.3.0.tgz", + "integrity": "sha512-J7/et3WlGUCxjdnD3HAAzQ6nsnc0WL6DD7WcwJb7c39iH1+AWfg+9OqzJNaI6PkBwBvm1mhZNL9iY/nRiZXlPg==", + "dev": true, + "dependencies": { + "buffer-equal": "^1.0.0", + "minimatch": "^3.0.4" + } + }, + "node_modules/dir-compare/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/dir-compare/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/discord-api-types": { + "version": "0.37.59", + "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.37.59.tgz", + "integrity": "sha512-75CxNb6dtxlgsIa3mD2ohoDLIZLMv/upsadRCYlqv2UgPTJ/p2MzSSbrH2AGBvL90/fAsB6fj8hCPOWzBkPkZQ==" + }, + "node_modules/dmg-builder": { + "version": "24.6.4", + "resolved": "https://registry.npmjs.org/dmg-builder/-/dmg-builder-24.6.4.tgz", + "integrity": "sha512-BNcHRc9CWEuI9qt0E655bUBU/j/3wUCYBVKGu1kVpbN5lcUdEJJJeiO0NHK3dgKmra6LUUZlo+mWqc+OCbi0zw==", + "dev": true, + "dependencies": { + "app-builder-lib": "24.6.4", + "builder-util": "24.5.0", + "builder-util-runtime": "9.2.1", + "fs-extra": "^10.1.0", + "iconv-lite": "^0.6.2", + "js-yaml": "^4.1.0" + }, + "optionalDependencies": { + "dmg-license": "^1.0.11" + } + }, + "node_modules/dmg-builder/node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/dmg-builder/node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/dmg-builder/node_modules/universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "dev": true, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/dmg-license": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/dmg-license/-/dmg-license-1.0.11.tgz", + "integrity": "sha512-ZdzmqwKmECOWJpqefloC5OJy1+WZBBse5+MR88z9g9Zn4VY+WYUkAyojmhzJckH5YbbZGcYIuGAkY5/Ys5OM2Q==", + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "dependencies": { + "@types/plist": "^3.0.1", + "@types/verror": "^1.10.3", + "ajv": "^6.10.0", + "crc": "^3.8.0", + "iconv-corefoundation": "^1.1.7", + "plist": "^3.0.4", + "smart-buffer": "^4.0.2", + "verror": "^1.10.0" + }, + "bin": { + "dmg-license": "bin/dmg-license.js" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ] + }, + "node_modules/domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "dependencies": { + "domelementtype": "^2.3.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", + "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", + "dependencies": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/dot-prop": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-6.0.1.tgz", + "integrity": "sha512-tE7ztYzXHIeyvc7N+hR3oi7FIbf/NIjVP9hmAt3yMXzrQ072/fpjGLx2GxNxGxUl5V73MEqYzioOMoVhGMJ5cA==", + "dependencies": { + "is-obj": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/dotenv": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-9.0.2.tgz", + "integrity": "sha512-I9OvvrHp4pIARv4+x9iuewrWycX6CcZtoAu1XrzPxc5UygMJXJZYmBsynku8IkrJwgypE5DGNjDPmPRhDCptUg==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/dotenv-expand": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-5.1.0.tgz", + "integrity": "sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA==", + "dev": true + }, + "node_modules/duplexer": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", + "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==" + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true + }, + "node_modules/ecma-proposal-math-extensions": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/ecma-proposal-math-extensions/-/ecma-proposal-math-extensions-0.0.2.tgz", + "integrity": "sha512-80BnDp2Fn7RxXlEr5HHZblniY4aQ97MOAicdWWpSo0vkQiISSE9wLR4SqxKsu4gCtXFBIPPzy8JMhay4NWRg/Q==" + }, + "node_modules/ejs": { + "version": "3.1.9", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.9.tgz", + "integrity": "sha512-rC+QVNMJWv+MtPgkt0y+0rVEIdbtxVADApW9JXrUVlzHetgcyczP/E7DJmWJ4fJCZF2cPcBk0laWO9ZHMG3DmQ==", + "dev": true, + "dependencies": { + "jake": "^10.8.5" + }, + "bin": { + "ejs": "bin/cli.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/electron": { + "version": "27.0.0-beta.9", + "resolved": "https://registry.npmjs.org/electron/-/electron-27.0.0-beta.9.tgz", + "integrity": "sha512-4h78B843eYU2oh2yMjrwYtl5aVMiFdpurIwtoZvXpfTwyuKiEOQaylmLbi4+sPg1rCmqW/VLv9hfVlOqHDNj/Q==", + "hasInstallScript": true, + "dependencies": { + "@electron/get": "^2.0.0", + "@types/node": "^18.11.18", + "extract-zip": "^2.0.1" + }, + "bin": { + "electron": "cli.js" + }, + "engines": { + "node": ">= 12.20.55" + } + }, + "node_modules/electron-better-web-request": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/electron-better-web-request/-/electron-better-web-request-1.0.1.tgz", + "integrity": "sha512-euwLeL82k6fbVODfH5Uz9c4BN047/XyYKfsZcaFhdWfqx05JPu2J0xE7nciJ/1Bb0sTClU1FDLW5H2zQWBB5Gw==", + "dependencies": { + "url-match-patterns": "^0.2.0", + "uuid": "^3.3.2" + } + }, + "node_modules/electron-builder": { + "version": "24.6.4", + "resolved": "https://registry.npmjs.org/electron-builder/-/electron-builder-24.6.4.tgz", + "integrity": "sha512-uNWQoU7pE7qOaIQ6CJHpBi44RJFVG8OHRBIadUxrsDJVwLLo8Nma3K/EEtx5/UyWAQYdcK4nVPYKoRqBb20hbA==", + "dev": true, + "dependencies": { + "app-builder-lib": "24.6.4", + "builder-util": "24.5.0", + "builder-util-runtime": "9.2.1", + "chalk": "^4.1.2", + "dmg-builder": "24.6.4", + "fs-extra": "^10.1.0", + "is-ci": "^3.0.0", + "lazy-val": "^1.0.5", + "read-config-file": "6.3.2", + "simple-update-notifier": "2.0.0", + "yargs": "^17.6.2" + }, + "bin": { + "electron-builder": "cli.js", + "install-app-deps": "install-app-deps.js" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/electron-builder/node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/electron-builder/node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/electron-builder/node_modules/universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "dev": true, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/electron-debug": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/electron-debug/-/electron-debug-3.2.0.tgz", + "integrity": "sha512-7xZh+LfUvJ52M9rn6N+tPuDw6oRAjxUj9SoxAZfJ0hVCXhZCsdkrSt7TgXOiWiEOBgEV8qwUIO/ScxllsPS7ow==", + "dependencies": { + "electron-is-dev": "^1.1.0", + "electron-localshortcut": "^3.1.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/electron-devtools-installer": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/electron-devtools-installer/-/electron-devtools-installer-3.2.0.tgz", + "integrity": "sha512-t3UczsYugm4OAbqvdImMCImIMVdFzJAHgbwHpkl5jmfu1izVgUcP/mnrPqJIpEeCK1uZGpt+yHgWEN+9EwoYhQ==", + "dev": true, + "dependencies": { + "rimraf": "^3.0.2", + "semver": "^7.2.1", + "tslib": "^2.1.0", + "unzip-crx-3": "^0.2.0" + } + }, + "node_modules/electron-is": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/electron-is/-/electron-is-3.0.0.tgz", + "integrity": "sha512-aQv1y3WrDZ+mtO8acbhiiip/8fa0Et7cvZyvlqJm2H7fih4hiJWEFRyYxzLgDG2kmiLdF8l3y5tbek5JFOPQkQ==", + "dependencies": { + "electron-is-dev": "^0.3.0", + "semver": "^5.5.0" + } + }, + "node_modules/electron-is-accelerator": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/electron-is-accelerator/-/electron-is-accelerator-0.1.2.tgz", + "integrity": "sha512-fLGSAjXZtdn1sbtZxx52+krefmtNuVwnJCV2gNiVt735/ARUboMl8jnNC9fZEqQdlAv2ZrETfmBUsoQci5evJA==" + }, + "node_modules/electron-is-dev": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/electron-is-dev/-/electron-is-dev-1.2.0.tgz", + "integrity": "sha512-R1oD5gMBPS7PVU8gJwH6CtT0e6VSoD0+SzSnYpNm+dBkcijgA+K7VAMHDfnRq/lkKPZArpzplTW6jfiMYosdzw==" + }, + "node_modules/electron-is/node_modules/electron-is-dev": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/electron-is-dev/-/electron-is-dev-0.3.0.tgz", + "integrity": "sha512-jLttuuq8QK67n3mXmIe9pkrO7IH3LGIk12xJkhTmc852U2sCJaRAOpRGPSh+1Xnzck5v9escd9YXzuze9nGejg==" + }, + "node_modules/electron-is/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/electron-localshortcut": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/electron-localshortcut/-/electron-localshortcut-3.2.1.tgz", + "integrity": "sha512-DWvhKv36GsdXKnaFFhEiK8kZZA+24/yFLgtTwJJHc7AFgDjNRIBJZ/jq62Y/dWv9E4ypYwrVWN2bVrCYw1uv7Q==", + "dependencies": { + "debug": "^4.0.1", + "electron-is-accelerator": "^0.1.0", + "keyboardevent-from-electron-accelerator": "^2.0.0", + "keyboardevents-areequal": "^0.2.1" + } + }, + "node_modules/electron-publish": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/electron-publish/-/electron-publish-24.5.0.tgz", + "integrity": "sha512-zwo70suH15L15B4ZWNDoEg27HIYoPsGJUF7xevLJLSI7JUPC8l2yLBdLGwqueJ5XkDL7ucYyRZzxJVR8ElV9BA==", + "dev": true, + "dependencies": { + "@types/fs-extra": "^9.0.11", + "builder-util": "24.5.0", + "builder-util-runtime": "9.2.1", + "chalk": "^4.1.2", + "fs-extra": "^10.1.0", + "lazy-val": "^1.0.5", + "mime": "^2.5.2" + } + }, + "node_modules/electron-publish/node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/electron-publish/node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/electron-publish/node_modules/universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "dev": true, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/electron-store": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/electron-store/-/electron-store-8.1.0.tgz", + "integrity": "sha512-2clHg/juMjOH0GT9cQ6qtmIvK183B39ZXR0bUoPwKwYHJsEF3quqyDzMFUAu+0OP8ijmN2CbPRAelhNbWUbzwA==", + "dependencies": { + "conf": "^10.2.0", + "type-fest": "^2.17.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/electron-unhandled": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/electron-unhandled/-/electron-unhandled-4.0.1.tgz", + "integrity": "sha512-6BsLnBg+i96eUnbaIFZyYdyfNX3f80/Nlfqy34YEMxXT9JP3ddNsNnUeiOF8ezN4+et4t4D37gjghKTP0V3jyw==", + "dependencies": { + "clean-stack": "^2.1.0", + "electron-is-dev": "^2.0.0", + "ensure-error": "^2.0.0", + "lodash.debounce": "^4.0.8", + "serialize-error": "^8.1.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/electron-unhandled/node_modules/electron-is-dev": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/electron-is-dev/-/electron-is-dev-2.0.0.tgz", + "integrity": "sha512-3X99K852Yoqu9AcW50qz3ibYBWY79/pBhlMCab8ToEWS48R0T9tyxRiQhwylE7zQdXrMnx2JKqUJyMPmt5FBqA==", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/electron-updater": { + "version": "6.1.4", + "resolved": "https://registry.npmjs.org/electron-updater/-/electron-updater-6.1.4.tgz", + "integrity": "sha512-yYAJc6RQjjV4WtInZVn+ZcLyXRhbVXoomKEfUUwDqIk5s2wxzLhWaor7lrNgxODyODhipjg4SVPMhJHi5EnsCA==", + "dependencies": { + "builder-util-runtime": "9.2.1", + "fs-extra": "^10.1.0", + "js-yaml": "^4.1.0", + "lazy-val": "^1.0.5", + "lodash.escaperegexp": "^4.1.2", + "lodash.isequal": "^4.5.0", + "semver": "^7.3.8", + "tiny-typed-emitter": "^2.1.0" + } + }, + "node_modules/electron-updater/node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/electron-updater/node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/electron-updater/node_modules/universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/electron/node_modules/@types/node": { + "version": "18.17.12", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.17.12.tgz", + "integrity": "sha512-d6xjC9fJ/nSnfDeU0AMDsaJyb1iHsqCSOdi84w4u+SlN/UgQdY5tRhpMzaFYsI4mnpvgTivEaQd0yOUhAtOnEQ==" + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/encoding": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", + "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", + "optional": true, + "dependencies": { + "iconv-lite": "^0.6.2" + } + }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/ensure-error": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ensure-error/-/ensure-error-2.1.0.tgz", + "integrity": "sha512-+BMSJHw9gxiJAAp2ZR1E0TNcL09dD3lOvkl7WVm4+Y6xnes/pMetP/TzCHiDduh8ihNDjbGfuYxl7l4PA1xZ8A==", + "engines": { + "node": ">=8" + } + }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "engines": { + "node": ">=6" + } + }, + "node_modules/err-code": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", + "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", + "dev": true + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-abstract": { + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.1.tgz", + "integrity": "sha512-ioRRcXMO6OFyRpyzV3kE1IIBd4WG5/kltnzdxSCqoP8CMGs/Li+M1uF5o7lOkZVFjDs+NLesthnF66Pg/0q0Lw==", + "dev": true, + "dependencies": { + "array-buffer-byte-length": "^1.0.0", + "arraybuffer.prototype.slice": "^1.0.1", + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "es-set-tostringtag": "^2.0.1", + "es-to-primitive": "^1.2.1", + "function.prototype.name": "^1.1.5", + "get-intrinsic": "^1.2.1", + "get-symbol-description": "^1.0.0", + "globalthis": "^1.0.3", + "gopd": "^1.0.1", + "has": "^1.0.3", + "has-property-descriptors": "^1.0.0", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.5", + "is-array-buffer": "^3.0.2", + "is-callable": "^1.2.7", + "is-negative-zero": "^2.0.2", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "is-string": "^1.0.7", + "is-typed-array": "^1.1.10", + "is-weakref": "^1.0.2", + "object-inspect": "^1.12.3", + "object-keys": "^1.1.1", + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.5.0", + "safe-array-concat": "^1.0.0", + "safe-regex-test": "^1.0.0", + "string.prototype.trim": "^1.2.7", + "string.prototype.trimend": "^1.0.6", + "string.prototype.trimstart": "^1.0.6", + "typed-array-buffer": "^1.0.0", + "typed-array-byte-length": "^1.0.0", + "typed-array-byte-offset": "^1.0.0", + "typed-array-length": "^1.0.4", + "unbox-primitive": "^1.0.2", + "which-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz", + "integrity": "sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.3", + "has": "^1.0.3", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-shim-unscopables": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz", + "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==", + "dev": true, + "dependencies": { + "has": "^1.0.3" + } + }, + "node_modules/es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "dependencies": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es6-error": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", + "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", + "optional": true + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "devOptional": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "8.50.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.50.0.tgz", + "integrity": "sha512-FOnOGSuFuFLv/Sa+FDVRZl4GGVAAFFi8LecRsI5a1tMO5HIE8nCm4ivAlzt4dT3ol/PaaGC0rJEEXQmHJBGoOg==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.2", + "@eslint/js": "8.50.0", + "@humanwhocodes/config-array": "^0.11.11", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", + "esquery": "^1.4.2", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-import-resolver-node": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", + "integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==", + "dev": true, + "dependencies": { + "debug": "^3.2.7", + "is-core-module": "^2.13.0", + "resolve": "^1.22.4" + } + }, + "node_modules/eslint-import-resolver-node/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-module-utils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.0.tgz", + "integrity": "sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==", + "dev": true, + "dependencies": { + "debug": "^3.2.7" + }, + "engines": { + "node": ">=4" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } + } + }, + "node_modules/eslint-module-utils/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-import": { + "version": "2.28.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.28.1.tgz", + "integrity": "sha512-9I9hFlITvOV55alzoKBI+K9q74kv0iKMeY6av5+umsNwayt59fz692daGyjR+oStBQgx6nwR9rXldDev3Clw+A==", + "dev": true, + "dependencies": { + "array-includes": "^3.1.6", + "array.prototype.findlastindex": "^1.2.2", + "array.prototype.flat": "^1.3.1", + "array.prototype.flatmap": "^1.3.1", + "debug": "^3.2.7", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.7", + "eslint-module-utils": "^2.8.0", + "has": "^1.0.3", + "is-core-module": "^2.13.0", + "is-glob": "^4.0.3", + "minimatch": "^3.1.2", + "object.fromentries": "^2.0.6", + "object.groupby": "^1.0.0", + "object.values": "^1.1.6", + "semver": "^6.3.1", + "tsconfig-paths": "^3.14.2" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" + } + }, + "node_modules/eslint-plugin-import/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint-plugin-import/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-import/node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-plugin-import/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/eslint-plugin-import/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/eslint-plugin-prettier": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.0.0.tgz", + "integrity": "sha512-AgaZCVuYDXHUGxj/ZGu1u8H8CYgDY3iG6w5kUFw4AzMVXzB7VvbKgYR4nATIN+OvUrghMbiDLeimVjVY5ilq3w==", + "dev": true, + "dependencies": { + "prettier-linter-helpers": "^1.0.0", + "synckit": "^0.8.5" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/prettier" + }, + "peerDependencies": { + "@types/eslint": ">=8.0.0", + "eslint": ">=8.0.0", + "prettier": ">=3.0.0" + }, + "peerDependenciesMeta": { + "@types/eslint": { + "optional": true + }, + "eslint-config-prettier": { + "optional": true + } + } + }, + "node_modules/eslint-scope": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint/node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "dev": true, + "dependencies": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/event-stream": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/event-stream/-/event-stream-3.3.4.tgz", + "integrity": "sha512-QHpkERcGsR0T7Qm3HNJSyXKEEj8AHNxkY3PK8TS2KJvQ7NiSHe3DDpwVKKtoYprL/AreyzFBeIkBIWChAqn60g==", + "dependencies": { + "duplexer": "~0.1.1", + "from": "~0", + "map-stream": "~0.1.0", + "pause-stream": "0.0.11", + "split": "0.3", + "stream-combiner": "~0.0.4", + "through": "~2.3.1" + } + }, + "node_modules/execa": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-7.2.0.tgz", + "integrity": "sha512-UduyVP7TLB5IcAQl+OzLyLcS/l32W/GLg+AhHJ+ow40FOk2U3SAllPwR44v4vmdFwIWqpdwxxpQbF1n5ta9seA==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.1", + "human-signals": "^4.3.0", + "is-stream": "^3.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^5.1.0", + "onetime": "^6.0.0", + "signal-exit": "^3.0.7", + "strip-final-newline": "^3.0.0" + }, + "engines": { + "node": "^14.18.0 || ^16.14.0 || >=18.0.0" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/execa/node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/execa/node_modules/onetime": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", + "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", + "dev": true, + "dependencies": { + "mimic-fn": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/exponential-backoff": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.1.tgz", + "integrity": "sha512-dX7e/LHVJ6W3DE1MHWi9S1EYzDESENfLrYohG2G++ovZrYOkm4Knwa0mc1cn84xJOR4KEU0WSchhLbd0UklbHw==", + "dev": true + }, + "node_modules/extract-zip": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", + "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", + "dependencies": { + "debug": "^4.1.1", + "get-stream": "^5.1.0", + "yauzl": "^2.10.0" + }, + "bin": { + "extract-zip": "cli.js" + }, + "engines": { + "node": ">= 10.17.0" + }, + "optionalDependencies": { + "@types/yauzl": "^2.9.1" + } + }, + "node_modules/extsprintf": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.4.1.tgz", + "integrity": "sha512-Wrk35e8ydCKDj/ArClo1VrPVmN8zph5V4AtHwIuHhvMXsKf73UT3BOD+azBIW+3wOJ4FhEH7zyaJCFvChjYvMA==", + "dev": true, + "engines": [ + "node >=0.6.0" + ], + "optional": true + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + }, + "node_modules/fast-diff": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", + "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", + "dev": true + }, + "node_modules/fast-glob": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz", + "integrity": "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "node_modules/fastq": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", + "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fd-slicer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", + "dependencies": { + "pend": "~1.2.0" + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", + "optional": true + }, + "node_modules/filelist": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz", + "integrity": "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==", + "dev": true, + "dependencies": { + "minimatch": "^5.0.1" + } + }, + "node_modules/filename-reserved-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/filename-reserved-regex/-/filename-reserved-regex-2.0.0.tgz", + "integrity": "sha512-lc1bnsSr4L4Bdif8Xb/qrtokGbq5zlsms/CYH8PP+WtCkGNF65DPiQY8vG3SakEdRn8Dlnm+gW/qWKKjS5sZzQ==", + "engines": { + "node": ">=4" + } + }, + "node_modules/filenamify": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/filenamify/-/filenamify-4.3.0.tgz", + "integrity": "sha512-hcFKyUG57yWGAzu1CMt/dPzYZuv+jAJUT85bL8mrXvNe6hWj6yEHEc4EdcgiA6Z3oi1/9wXJdZPXF2dZNgwgOg==", + "dependencies": { + "filename-reserved-regex": "^2.0.0", + "strip-outer": "^1.0.1", + "trim-repeated": "^1.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.1.0.tgz", + "integrity": "sha512-OHx4Qwrrt0E4jEIcI5/Xb+f+QmJYNj2rrK8wiIdQOIrB9WrrJL8cjZvXdXuBTkkEwEqLycb5BeZDV1o2i9bTew==", + "dev": true, + "dependencies": { + "flatted": "^3.2.7", + "keyv": "^4.5.3", + "rimraf": "^3.0.2" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", + "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", + "dev": true + }, + "node_modules/follow-redirects": { + "version": "1.15.3", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.3.tgz", + "integrity": "sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dev": true, + "dependencies": { + "is-callable": "^1.1.3" + } + }, + "node_modules/foreground-child": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", + "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/foreground-child/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/from": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/from/-/from-0.1.7.tgz", + "integrity": "sha512-twe20eF1OxVxp/ML/kq2p1uc6KvFK/+vs8WjEbeKmV2He22MKm7YF2ANIt+EOqhJ5L3K/SuuPhk0hWQDjOM23g==" + }, + "node_modules/fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/fs-minipass": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-3.0.3.tgz", + "integrity": "sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw==", + "dev": true, + "dependencies": { + "minipass": "^7.0.3" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/fs-minipass/node_modules/minipass": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.3.tgz", + "integrity": "sha512-LhbbwCfz3vsb12j/WkWQPZfKTsgqIe1Nf/ti1pKjYESGLHIVjWU96G9/ljLH4F9mWNVhlQOm0VySdAWzf05dpg==", + "dev": true, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "node_modules/function.prototype.name": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz", + "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "functions-have-names": "^1.2.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gauge": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-4.0.4.tgz", + "integrity": "sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==", + "dev": true, + "dependencies": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.3", + "console-control-strings": "^1.1.0", + "has-unicode": "^2.0.1", + "signal-exit": "^3.0.7", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.5" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz", + "integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==", + "dependencies": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-symbol-description": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", + "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/glob/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/global-agent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/global-agent/-/global-agent-3.0.0.tgz", + "integrity": "sha512-PT6XReJ+D07JvGoxQMkT6qji/jVNfX/h364XHZOWeRzy64sSFr+xJ5OX7LI3b4MPQzdL4H8Y8M0xzPpsVMwA8Q==", + "optional": true, + "dependencies": { + "boolean": "^3.0.1", + "es6-error": "^4.1.1", + "matcher": "^3.0.0", + "roarr": "^2.15.3", + "semver": "^7.3.2", + "serialize-error": "^7.0.1" + }, + "engines": { + "node": ">=10.0" + } + }, + "node_modules/global-agent/node_modules/serialize-error": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-7.0.1.tgz", + "integrity": "sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw==", + "optional": true, + "dependencies": { + "type-fest": "^0.13.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/global-agent/node_modules/type-fest": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.13.1.tgz", + "integrity": "sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==", + "optional": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globals": { + "version": "13.21.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.21.0.tgz", + "integrity": "sha512-ybyme3s4yy/t/3s35bewwXKOf7cvzfreG2lH0lZl0JB7I4GxRP2ghxOK/Nb9EkRXdbBXZLfq/p/0W2JUONB/Gg==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globals/node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globalthis": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", + "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", + "devOptional": true, + "dependencies": { + "define-properties": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/globby": { + "version": "13.2.2", + "resolved": "https://registry.npmjs.org/globby/-/globby-13.2.2.tgz", + "integrity": "sha512-Y1zNGV+pzQdh7H39l9zgB4PJqjRNqydvdYCDG4HFXM4XuvSaQQlEc91IU1yALL8gUTDomgBAfz3XJdmUS+oo0w==", + "dev": true, + "dependencies": { + "dir-glob": "^3.0.1", + "fast-glob": "^3.3.0", + "ignore": "^5.2.4", + "merge2": "^1.4.1", + "slash": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/got": { + "version": "11.8.6", + "resolved": "https://registry.npmjs.org/got/-/got-11.8.6.tgz", + "integrity": "sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==", + "dependencies": { + "@sindresorhus/is": "^4.0.0", + "@szmarczak/http-timer": "^4.0.5", + "@types/cacheable-request": "^6.0.1", + "@types/responselike": "^1.0.0", + "cacheable-lookup": "^5.0.3", + "cacheable-request": "^7.0.2", + "decompress-response": "^6.0.0", + "http2-wrapper": "^1.0.0-beta.5.2", + "lowercase-keys": "^2.0.0", + "p-cancelable": "^2.0.0", + "responselike": "^2.0.0" + }, + "engines": { + "node": ">=10.19.0" + }, + "funding": { + "url": "https://github.com/sindresorhus/got?sponsor=1" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true + }, + "node_modules/handlebars": { + "version": "4.7.8", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz", + "integrity": "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==", + "dev": true, + "dependencies": { + "minimist": "^1.2.5", + "neo-async": "^2.6.2", + "source-map": "^0.6.1", + "wordwrap": "^1.0.0" + }, + "bin": { + "handlebars": "bin/handlebars" + }, + "engines": { + "node": ">=0.4.7" + }, + "optionalDependencies": { + "uglify-js": "^3.1.4" + } + }, + "node_modules/hard-rejection": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz", + "integrity": "sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-bigints": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", + "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", + "dependencies": { + "get-intrinsic": "^1.1.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", + "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", + "dev": true + }, + "node_modules/hexy": { + "version": "0.2.11", + "resolved": "https://registry.npmjs.org/hexy/-/hexy-0.2.11.tgz", + "integrity": "sha512-ciq6hFsSG/Bpt2DmrZJtv+56zpPdnq+NQ4ijEFrveKN0ZG1mhl/LdT1NQZ9se6ty1fACcI4d4vYqC9v8EYpH2A==", + "bin": { + "hexy": "bin/hexy_cmd.js" + } + }, + "node_modules/hosted-git-info": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", + "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/howler": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/howler/-/howler-2.2.4.tgz", + "integrity": "sha512-iARIBPgcQrwtEr+tALF+rapJ8qSc+Set2GJQl7xT1MQzWaVkFebdJhR3alVlSiUf5U7nAANKuj3aWpwerocD5w==" + }, + "node_modules/html-to-text": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/html-to-text/-/html-to-text-9.0.5.tgz", + "integrity": "sha512-qY60FjREgVZL03vJU6IfMV4GDjGBIoOyvuFdpBDIX9yTlDw0TjxVBQp+P8NvpdIXNJvfWBTNul7fsAQJq2FNpg==", + "dependencies": { + "@selderee/plugin-htmlparser2": "^0.11.0", + "deepmerge": "^4.3.1", + "dom-serializer": "^2.0.0", + "htmlparser2": "^8.0.2", + "selderee": "^0.11.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/htmlparser2": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz", + "integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==", + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1", + "entities": "^4.4.0" + } + }, + "node_modules/http-cache-semantics": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", + "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==" + }, + "node_modules/http-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", + "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", + "dev": true, + "dependencies": { + "@tootallnate/once": "2", + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/http2-wrapper": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-1.0.3.tgz", + "integrity": "sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==", + "dependencies": { + "quick-lru": "^5.1.1", + "resolve-alpn": "^1.0.0" + }, + "engines": { + "node": ">=10.19.0" + } + }, + "node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "dev": true, + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/human-signals": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-4.3.1.tgz", + "integrity": "sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ==", + "dev": true, + "engines": { + "node": ">=14.18.0" + } + }, + "node_modules/humanize-ms": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", + "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", + "dev": true, + "dependencies": { + "ms": "^2.0.0" + } + }, + "node_modules/iconv-corefoundation": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/iconv-corefoundation/-/iconv-corefoundation-1.1.7.tgz", + "integrity": "sha512-T10qvkw0zz4wnm560lOEg0PovVqUXuOFhhHAkixw8/sycy7TJt7v/RrkEKEQnAw2viPSJu6iAkErxnzR0g8PpQ==", + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "dependencies": { + "cli-truncate": "^2.1.0", + "node-addon-api": "^1.6.3" + }, + "engines": { + "node": "^8.11.2 || >=10" + } + }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "devOptional": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "optional": true + }, + "node_modules/ignore": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", + "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/immediate": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", + "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==", + "dev": true + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/indent-string": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-5.0.0.tgz", + "integrity": "sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "node_modules/internal-slot": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.5.tgz", + "integrity": "sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.2.0", + "has": "^1.0.3", + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ip": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz", + "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==", + "dev": true + }, + "node_modules/is-arguments": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", + "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-array-buffer": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz", + "integrity": "sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.0", + "is-typed-array": "^1.1.10" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true + }, + "node_modules/is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "dev": true, + "dependencies": { + "has-bigints": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-ci": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-3.0.1.tgz", + "integrity": "sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==", + "dev": true, + "dependencies": { + "ci-info": "^3.2.0" + }, + "bin": { + "is-ci": "bin.js" + } + }, + "node_modules/is-core-module": { + "version": "2.13.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.0.tgz", + "integrity": "sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ==", + "dev": true, + "dependencies": { + "has": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "dev": true, + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-inside-container": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", + "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", + "dev": true, + "dependencies": { + "is-docker": "^3.0.0" + }, + "bin": { + "is-inside-container": "cli.js" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-inside-container/node_modules/is-docker": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", + "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", + "dev": true, + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-lambda": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", + "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==", + "dev": true + }, + "node_modules/is-negative-zero": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", + "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-number-object": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-path-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-3.0.0.tgz", + "integrity": "sha512-kyiNFFLU0Ampr6SDZitD/DwUo4Zs1nSdnygUBqsu3LooL00Qvb5j+UnvApUn/TTj1J3OuE6BTdQ5rudKmU2ZaA==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-path-inside": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-4.0.0.tgz", + "integrity": "sha512-lJJV/5dYS+RcL8uQdBDW9c9uWFLLBNRyFhnAKXw5tVqLlKZ4RMGZKv+YQ/IA3OhD+RpbJa1LLFM1FQPGyIXvOA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-plain-obj": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", + "integrity": "sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", + "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.12.tgz", + "integrity": "sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==", + "dev": true, + "dependencies": { + "which-typed-array": "^1.1.11" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-url": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/is-url/-/is-url-1.2.4.tgz", + "integrity": "sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww==" + }, + "node_modules/is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dev": true, + "dependencies": { + "is-docker": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true + }, + "node_modules/isbinaryfile": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-5.0.0.tgz", + "integrity": "sha512-UDdnyGvMajJUWCkib7Cei/dvyJrrvo4FIrsvSFWdPpXSUorzXrDJ0S+X5Q4ZlasfPjca4yqCNNsjbCeiy8FFeg==", + "dev": true, + "engines": { + "node": ">= 14.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/gjtorikian/" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/jackspeak": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.1.tgz", + "integrity": "sha512-4iSY3Bh1Htv+kLhiiZunUhQ+OYXIn0ze3ulq8JeWrFKmhPAJSySV2+kdtRh2pGcCeF0s6oR8Oc+pYZynJj4t8A==", + "dev": true, + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/jake": { + "version": "10.8.7", + "resolved": "https://registry.npmjs.org/jake/-/jake-10.8.7.tgz", + "integrity": "sha512-ZDi3aP+fG/LchyBzUM804VjddnwfSfsdeYkwt8NcbKRvo4rFkjhs456iLFn3k2ZUWvNe4i48WACDbza8fhq2+w==", + "dev": true, + "dependencies": { + "async": "^3.2.3", + "chalk": "^4.0.2", + "filelist": "^1.0.4", + "minimatch": "^3.1.2" + }, + "bin": { + "jake": "bin/cli.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jake/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/jake/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/jintr": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/jintr/-/jintr-1.1.0.tgz", + "integrity": "sha512-Tu9wk3BpN2v+kb8yT6YBtue+/nbjeLFv4vvVC4PJ7oCidHKbifWhvORrAbQfxVIQZG+67am/mDagpiGSVtvrZg==", + "funding": [ + "https://github.com/sponsors/LuanRT" + ], + "dependencies": { + "acorn": "^8.8.0" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsbi": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/jsbi/-/jsbi-2.0.5.tgz", + "integrity": "sha512-TzO/62Hxeb26QMb4IGlI/5X+QLr9Uqp1FPkwp2+KOICW+Q+vSuFj61c8pkT6wAns4WcK56X7CmSHhJeDGWOqxQ==" + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==" + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/json-schema-typed": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/json-schema-typed/-/json-schema-typed-7.0.3.tgz", + "integrity": "sha512-7DE8mpG+/fVw+dTpjbxnx47TaMnDfOI1jwft9g1VybltZCduyRQPJPvc+zzKY9WPHxhPWczyFuYa6I8Mw4iU5A==" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, + "node_modules/json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", + "optional": true + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jszip": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz", + "integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==", + "dev": true, + "dependencies": { + "lie": "~3.3.0", + "pako": "~1.0.2", + "readable-stream": "~2.3.6", + "setimmediate": "^1.0.5" + } + }, + "node_modules/jszip/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true + }, + "node_modules/jszip/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/jszip/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "node_modules/jszip/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/keyboardevent-from-electron-accelerator": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/keyboardevent-from-electron-accelerator/-/keyboardevent-from-electron-accelerator-2.0.0.tgz", + "integrity": "sha512-iQcmNA0M4ETMNi0kG/q0h/43wZk7rMeKYrXP7sqKIJbHkTU8Koowgzv+ieR/vWJbOwxx5nDC3UnudZ0aLSu4VA==" + }, + "node_modules/keyboardevents-areequal": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/keyboardevents-areequal/-/keyboardevents-areequal-0.2.2.tgz", + "integrity": "sha512-Nv+Kr33T0mEjxR500q+I6IWisOQ0lK1GGOncV0kWE6n4KFmpcu7RUX5/2B0EUtX51Cb0HjZ9VJsSY3u4cBa0kw==" + }, + "node_modules/keyv": { + "version": "4.5.3", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.3.tgz", + "integrity": "sha512-QCiSav9WaX1PgETJ+SpNnx2PRRapJ/oRSXM4VO5OGYGSjrxbKPVFVhB3l2OCbLCk329N8qyAtsJjSjvVBWzEug==", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/lazy-val": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/lazy-val/-/lazy-val-1.0.5.tgz", + "integrity": "sha512-0/BnGCCfyUMkBpeDgWihanIAF9JmZhHBgUhEqzvf+adhNGLoP6TaiI5oF8oyb3I45P+PcnrqihSf01M0l0G5+Q==" + }, + "node_modules/leac": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/leac/-/leac-0.6.0.tgz", + "integrity": "sha512-y+SqErxb8h7nE/fiEX07jsbuhrpO9lL8eca7/Y1nuWV2moNlXhyd59iDGcRf6moVyDMbmTNzL40SUyrFU/yDpg==", + "funding": { + "url": "https://ko-fi.com/killymxi" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lie": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", + "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", + "dev": true, + "dependencies": { + "immediate": "~3.0.5" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "node_modules/lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==" + }, + "node_modules/lodash.escaperegexp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.escaperegexp/-/lodash.escaperegexp-4.1.2.tgz", + "integrity": "sha512-TM9YBvyC84ZxE3rgfefxUWiQKLilstD6k7PTGt6wfbtXF8ixIJLOL3VYyV/z+ZiPLsVxAsKAFVwWlWeb2Y8Yyw==" + }, + "node_modules/lodash.isequal": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", + "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==" + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "node_modules/long": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", + "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" + }, + "node_modules/lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", + "engines": { + "node": ">=8" + } + }, + "node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/make-fetch-happen": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-11.1.1.tgz", + "integrity": "sha512-rLWS7GCSTcEujjVBs2YqG7Y4643u8ucvCJeSRqiLYhesrDuzeuFIk37xREzAsfQaqzl8b9rNCE4m6J8tvX4Q8w==", + "dev": true, + "dependencies": { + "agentkeepalive": "^4.2.1", + "cacache": "^17.0.0", + "http-cache-semantics": "^4.1.1", + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.0", + "is-lambda": "^1.0.1", + "lru-cache": "^7.7.1", + "minipass": "^5.0.0", + "minipass-fetch": "^3.0.0", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.3", + "promise-retry": "^2.0.1", + "socks-proxy-agent": "^7.0.0", + "ssri": "^10.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/make-fetch-happen/node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/map-obj": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.3.0.tgz", + "integrity": "sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/map-stream": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.1.0.tgz", + "integrity": "sha512-CkYQrPYZfWnu/DAmVCpTSX/xHpKZ80eKh2lAkyA6AJTef6bW+6JpbQZN5rofum7da+SyN1bi5ctTm+lTfcCW3g==" + }, + "node_modules/matcher": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/matcher/-/matcher-3.0.0.tgz", + "integrity": "sha512-OkeDaAZ/bQCxeFAozM55PKcKU0yJMPGifLwV4Qgjitu+5MoAfSQN4lsLJeXZ1b8w0x+/Emda6MZgXS1jvsapng==", + "optional": true, + "dependencies": { + "escape-string-regexp": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/meow": { + "version": "10.1.5", + "resolved": "https://registry.npmjs.org/meow/-/meow-10.1.5.tgz", + "integrity": "sha512-/d+PQ4GKmGvM9Bee/DPa8z3mXs/pkvJE2KEThngVNOqtmljC6K7NMPxtc2JeZYTmpWb9k/TmxjeL18ez3h7vCw==", + "dev": true, + "dependencies": { + "@types/minimist": "^1.2.2", + "camelcase-keys": "^7.0.0", + "decamelize": "^5.0.0", + "decamelize-keys": "^1.1.0", + "hard-rejection": "^2.1.0", + "minimist-options": "4.1.0", + "normalize-package-data": "^3.0.2", + "read-pkg-up": "^8.0.0", + "redent": "^4.0.0", + "trim-newlines": "^4.0.2", + "type-fest": "^1.2.2", + "yargs-parser": "^20.2.9" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/meow/node_modules/type-fest": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz", + "integrity": "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", + "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", + "dev": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", + "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mimic-response": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", + "engines": { + "node": ">=4" + } + }, + "node_modules/min-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", + "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/miniget": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/miniget/-/miniget-4.2.3.tgz", + "integrity": "sha512-SjbDPDICJ1zT+ZvQwK0hUcRY4wxlhhNpHL9nJOB2MEAXRGagTljsO8MEDzQMTFf0Q8g4QNi8P9lEm/g7e+qgzA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minimist-options": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/minimist-options/-/minimist-options-4.1.0.tgz", + "integrity": "sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==", + "dev": true, + "dependencies": { + "arrify": "^1.0.1", + "is-plain-obj": "^1.1.0", + "kind-of": "^6.0.3" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/minipass": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-collect": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz", + "integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minipass-collect/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-fetch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.4.tgz", + "integrity": "sha512-jHAqnA728uUpIaFm7NWsCnqKT6UqZz7GcI/bDpPATuwYyKwJwW0remxSCxUlKiEty+eopHGa3oc8WxgQ1FFJqg==", + "dev": true, + "dependencies": { + "minipass": "^7.0.3", + "minipass-sized": "^1.0.3", + "minizlib": "^2.1.2" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + }, + "optionalDependencies": { + "encoding": "^0.1.13" + } + }, + "node_modules/minipass-fetch/node_modules/minipass": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.3.tgz", + "integrity": "sha512-LhbbwCfz3vsb12j/WkWQPZfKTsgqIe1Nf/ti1pKjYESGLHIVjWU96G9/ljLH4F9mWNVhlQOm0VySdAWzf05dpg==", + "dev": true, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/minipass-flush": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", + "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minipass-flush/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-pipeline": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", + "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-pipeline/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-sized": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", + "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-sized/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minizlib/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true, + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/mpris-service": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/mpris-service/-/mpris-service-2.1.2.tgz", + "integrity": "sha512-AC6WepCnFWwOME9OWplHZ8ps/BB+g9QrEpUKCv7wX82fDPzR3nPrypOFmL/Fm0JloEAu6QTWSfDLLc6mM/jinw==", + "dependencies": { + "dbus-next": "^0.9.2", + "deep-equal": "^1.0.1", + "source-map-support": "^0.5.11" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/nan": { + "version": "2.17.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.17.0.tgz", + "integrity": "sha512-2ZTgtl0nJsO0KQCjEpxcIr5D+Yv90plTitZt9JBfQvVJDS5seMl3FOvsh3+9CoYWXf/1l5OaZzzF6nDm4cagaQ==", + "optional": true + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true + }, + "node_modules/node-addon-api": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-1.7.2.tgz", + "integrity": "sha512-ibPK3iA+vaY1eEjESkQkM0BbCqFOaZMiXRTtdB0u7b4djtY6JnsjvPdUHVMg6xQt3B8fpTTWHI9A+ADjM9frzg==", + "dev": true, + "optional": true + }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-gyp": { + "version": "9.4.0", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-9.4.0.tgz", + "integrity": "sha512-dMXsYP6gc9rRbejLXmTbVRYjAHw7ppswsKyMxuxJxxOHzluIO1rGp9TOQgjFJ+2MCqcOcQTOPB/8Xwhr+7s4Eg==", + "dev": true, + "dependencies": { + "env-paths": "^2.2.0", + "exponential-backoff": "^3.1.1", + "glob": "^7.1.4", + "graceful-fs": "^4.2.6", + "make-fetch-happen": "^11.0.3", + "nopt": "^6.0.0", + "npmlog": "^6.0.0", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "tar": "^6.1.2", + "which": "^2.0.2" + }, + "bin": { + "node-gyp": "bin/node-gyp.js" + }, + "engines": { + "node": "^12.13 || ^14.13 || >=16" + } + }, + "node_modules/node-id3": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/node-id3/-/node-id3-0.2.6.tgz", + "integrity": "sha512-w8GuKXLlPpDjTxLowCt/uYMhRQzED3cg2GdSG1i6RSGKeDzPvxlXeLQuQInKljahPZ0aDnmyX7FX8BbJOM7REg==", + "dependencies": { + "iconv-lite": "0.6.2" + } + }, + "node_modules/node-id3/node_modules/iconv-lite": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.2.tgz", + "integrity": "sha512-2y91h5OpQlolefMPmUlivelittSWy0rP+oYVpn6A7GwVHNE8AWzoYOBNmlwks3LobaJxgHCYZAnyNo2GgpNRNQ==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/noms": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/noms/-/noms-0.0.0.tgz", + "integrity": "sha512-lNDU9VJaOPxUmXcLb+HQFeUgQQPtMI24Gt6hgfuMHRJgMRHMF/qZ4HJD3GDru4sSw9IQl2jPjAYnQrdIeLbwow==", + "dev": true, + "dependencies": { + "inherits": "^2.0.1", + "readable-stream": "~1.0.31" + } + }, + "node_modules/noms/node_modules/isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", + "dev": true + }, + "node_modules/noms/node_modules/readable-stream": { + "version": "1.0.34", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", + "integrity": "sha512-ok1qVCJuRkNmvebYikljxJA/UEsKwLl2nI1OmaqAu4/UE+h0wKCHok4XkL/gvi39OacXvw59RJUOFUkDib2rHg==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "node_modules/noms/node_modules/string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==", + "dev": true + }, + "node_modules/nopt": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-6.0.0.tgz", + "integrity": "sha512-ZwLpbTgdhuZUnZzjd7nb1ZV+4DoiC6/sfiVKok72ym/4Tlf+DFdlHYmT2JPmcNNWV6Pi3SDf1kT+A4r9RTuT9g==", + "dev": true, + "dependencies": { + "abbrev": "^1.0.0" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/normalize-package-data": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.3.tgz", + "integrity": "sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==", + "dev": true, + "dependencies": { + "hosted-git-info": "^4.0.1", + "is-core-module": "^2.5.0", + "semver": "^7.3.4", + "validate-npm-package-license": "^3.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/normalize-url": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", + "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm-run-path": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.1.0.tgz", + "integrity": "sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==", + "dev": true, + "dependencies": { + "path-key": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm-run-path/node_modules/path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npmlog": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-6.0.2.tgz", + "integrity": "sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==", + "dev": true, + "dependencies": { + "are-we-there-yet": "^3.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^4.0.3", + "set-blocking": "^2.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/object-inspect": { + "version": "1.12.3", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", + "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-is": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz", + "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", + "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.fromentries": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.7.tgz", + "integrity": "sha512-UPbPHML6sL8PI/mOqPwsH4G6iyXcCGzLin8KvEPenOZN5lpCNBZZQ+V62vdjB1mQHrmqGQt5/OJzemUA+KJmEA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.groupby": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.1.tgz", + "integrity": "sha512-HqaQtqLnp/8Bn4GL16cj+CUYbnpe1bh0TtEaWvybszDG4tgxCJuRpV8VGuvNaI1fAnI4lUJzDG55MXcOH4JZcQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "get-intrinsic": "^1.2.1" + } + }, + "node_modules/object.values": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.7.tgz", + "integrity": "sha512-aU6xnDFYT3x17e/f0IiiwlGPTy2jzMySGfUB4fq6z7CV8l85CWHDk5ErhyhpfDHhrOMwGFhSQkhMGHaIotA6Ng==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/onetime/node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "engines": { + "node": ">=6" + } + }, + "node_modules/optionator": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", + "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", + "dev": true, + "dependencies": { + "@aashutoshrathi/word-wrap": "^1.2.3", + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-cancelable": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz", + "integrity": "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-map": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-5.5.0.tgz", + "integrity": "sha512-VFqfGDHlx87K66yZrNdI4YGtD70IRyd+zSvgks6mzHPRNkoKy+9EKP4SFC77/vTTQYmRmti7dvqC+m5jBrBAcg==", + "dev": true, + "dependencies": { + "aggregate-error": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", + "dev": true + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-github-url": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/parse-github-url/-/parse-github-url-1.0.2.tgz", + "integrity": "sha512-kgBf6avCbO3Cn6+RnzRGLkUsv4ZVqv/VfAYkRsyBcgkshNvVBkRn1FEZcW0Jb+npXQWm2vHPnnOqFteZxRRGNw==", + "dev": true, + "bin": { + "parse-github-url": "cli.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parseley": { + "version": "0.12.1", + "resolved": "https://registry.npmjs.org/parseley/-/parseley-0.12.1.tgz", + "integrity": "sha512-e6qHKe3a9HWr0oMRVDTRhKce+bRO8VGQR3NyVwcjwrbhMmFCX9KszEV35+rn4AdilFAq9VPxP/Fe1wC9Qjd2lw==", + "dependencies": { + "leac": "^0.6.0", + "peberminta": "^0.9.0" + }, + "funding": { + "url": "https://ko-fi.com/killymxi" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "node_modules/path-scurry": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.1.tgz", + "integrity": "sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==", + "dev": true, + "dependencies": { + "lru-cache": "^9.1.1 || ^10.0.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.0.1.tgz", + "integrity": "sha512-IJ4uwUTi2qCccrioU6g9g/5rvvVl13bsdczUUcqbciD9iLr095yj8DQKdObriEvuNSx325N1rV1O0sJFszx75g==", + "dev": true, + "engines": { + "node": "14 || >=16.14" + } + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/pause-stream": { + "version": "0.0.11", + "resolved": "https://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz", + "integrity": "sha512-e3FBlXLmN/D1S+zHzanP4E/4Z60oFAa3O051qt1pxa7DEJWKAyil6upYVXCWadEnuoqa4Pkc9oUx9zsxYeRv8A==", + "dependencies": { + "through": "~2.3" + } + }, + "node_modules/peberminta": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/peberminta/-/peberminta-0.9.0.tgz", + "integrity": "sha512-XIxfHpEuSJbITd1H3EeQwpcZbTLHc+VVr8ANI9t5sit565tsI4/xK3KWTUFE2e6QiangUkh3B0jihzmGnNrRsQ==", + "funding": { + "url": "https://ko-fi.com/killymxi" + } + }, + "node_modules/pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==" + }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pkg-up": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-3.1.0.tgz", + "integrity": "sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA==", + "dependencies": { + "find-up": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-up/node_modules/find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dependencies": { + "locate-path": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/pkg-up/node_modules/locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dependencies": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/pkg-up/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-up/node_modules/p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dependencies": { + "p-limit": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/pkg-up/node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", + "engines": { + "node": ">=4" + } + }, + "node_modules/playwright": { + "version": "1.38.1", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.38.1.tgz", + "integrity": "sha512-oRMSJmZrOu1FP5iu3UrCx8JEFRIMxLDM0c/3o4bpzU5Tz97BypefWf7TuTNPWeCe279TPal5RtPPZ+9lW/Qkow==", + "dev": true, + "dependencies": { + "playwright-core": "1.38.1" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=16" + }, + "optionalDependencies": { + "fsevents": "2.3.2" + } + }, + "node_modules/playwright-core": { + "version": "1.38.1", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.38.1.tgz", + "integrity": "sha512-tQqNFUKa3OfMf4b2jQ7aGLB8o9bS3bOY0yMEtldtC2+spf8QXG9zvXLTXUeRsoNuxEYMgLYR+NXfAa1rjKRcrg==", + "dev": true, + "bin": { + "playwright-core": "cli.js" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/plist": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/plist/-/plist-3.1.0.tgz", + "integrity": "sha512-uysumyrvkUX0rX/dEVqt8gC3sTBzd4zoWfLeS29nb53imdaXVvLINYXTI2GNqzaMuvacNx4uJQ8+b3zXR0pkgQ==", + "dev": true, + "dependencies": { + "@xmldom/xmldom": "^0.8.8", + "base64-js": "^1.5.1", + "xmlbuilder": "^15.1.1" + }, + "engines": { + "node": ">=10.4.0" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.0.3.tgz", + "integrity": "sha512-L/4pUDMxcNa8R/EthV08Zt42WBO4h1rarVtK0K+QJG0X187OLo7l699jWw0GKuwzkPQ//jMFA/8Xm6Fh3J/DAg==", + "dev": true, + "peer": true, + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/prettier-linter-helpers": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", + "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", + "dev": true, + "dependencies": { + "fast-diff": "^1.1.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true + }, + "node_modules/progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/promise-retry": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", + "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", + "dev": true, + "dependencies": { + "err-code": "^2.0.2", + "retry": "^0.12.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, + "node_modules/pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/punycode": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", + "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/quick-lru": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", + "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/read-config-file": { + "version": "6.3.2", + "resolved": "https://registry.npmjs.org/read-config-file/-/read-config-file-6.3.2.tgz", + "integrity": "sha512-M80lpCjnE6Wt6zb98DoW8WHR09nzMSpu8XHtPkiTHrJ5Az9CybfeQhTJ8D7saeBHpGhLPIVyA8lcL6ZmdKwY6Q==", + "dev": true, + "dependencies": { + "config-file-ts": "^0.2.4", + "dotenv": "^9.0.2", + "dotenv-expand": "^5.1.0", + "js-yaml": "^4.1.0", + "json5": "^2.2.0", + "lazy-val": "^1.0.4" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/read-pkg": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-6.0.0.tgz", + "integrity": "sha512-X1Fu3dPuk/8ZLsMhEj5f4wFAF0DWoK7qhGJvgaijocXxBmSToKfbFtqbxMO7bVjNA1dmE5huAzjXj/ey86iw9Q==", + "dev": true, + "dependencies": { + "@types/normalize-package-data": "^2.4.0", + "normalize-package-data": "^3.0.2", + "parse-json": "^5.2.0", + "type-fest": "^1.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/read-pkg-up": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-8.0.0.tgz", + "integrity": "sha512-snVCqPczksT0HS2EC+SxUndvSzn6LRCwpfSvLrIfR5BKDQQZMaI6jPRC9dYvYFDRAuFEAnkwww8kBBNE/3VvzQ==", + "dev": true, + "dependencies": { + "find-up": "^5.0.0", + "read-pkg": "^6.0.0", + "type-fest": "^1.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/read-pkg-up/node_modules/type-fest": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz", + "integrity": "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/read-pkg/node_modules/type-fest": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz", + "integrity": "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/redent": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-4.0.0.tgz", + "integrity": "sha512-tYkDkVVtYkSVhuQ4zBgfvciymHaeuel+zFKXShfDnFP5SyVEP7qo70Rf1jTOTCx3vGNAbnEi/xFkcfQVMIBWag==", + "dev": true, + "dependencies": { + "indent-string": "^5.0.0", + "strip-indent": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.13.11", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", + "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==" + }, + "node_modules/regexp.prototype.flags": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.0.tgz", + "integrity": "sha512-0SutC3pNudRKgquxGoRGIz946MZVHqbNfPjBdxeOhBrdgDKlRoXmYLQN9xRbrR09ZXWeGAdPuif7egofn6v5LA==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "functions-have-names": "^1.2.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve": { + "version": "1.22.4", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.4.tgz", + "integrity": "sha512-PXNdCiPqDqeUou+w1C2eTQbNfxKSuMxqTCuvlmmMsk1NWHL5fRrhY6Pl0qEYYc6+QqGClco1Qj8XnjPego4wfg==", + "dev": true, + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-alpn": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz", + "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==" + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/responselike": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.1.tgz", + "integrity": "sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==", + "dependencies": { + "lowercase-keys": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/roarr": { + "version": "2.15.4", + "resolved": "https://registry.npmjs.org/roarr/-/roarr-2.15.4.tgz", + "integrity": "sha512-CHhPh+UNHD2GTXNYhPWLnU8ONHdI+5DI+4EYIAOaiD63rHeYlZvyh8P+in5999TTSFgUYuKUAjzRI4mdh/p+2A==", + "optional": true, + "dependencies": { + "boolean": "^3.0.1", + "detect-node": "^2.0.4", + "globalthis": "^1.0.1", + "json-stringify-safe": "^5.0.1", + "semver-compare": "^1.0.0", + "sprintf-js": "^1.1.2" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/run-applescript": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-5.0.0.tgz", + "integrity": "sha512-XcT5rBksx1QdIhlFOCtgZkB99ZEouFZ1E2Kc2LHqNW13U3/74YGdkQRmThTwxy4QIyookibDKYZOPqX//6BlAg==", + "dev": true, + "dependencies": { + "execa": "^5.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/run-applescript/node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/run-applescript/node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/run-applescript/node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true, + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/run-applescript/node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/run-applescript/node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/run-applescript/node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-array-concat": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.0.0.tgz", + "integrity": "sha512-9dVEFruWIsnie89yym+xWTAYASdpw3CJV7Li/6zBewGf9z2i1j31rP6jnY0pHEO4QZh6N0K11bFjWmdR8UGdPQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.0", + "has-symbols": "^1.0.3", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/safe-regex-test": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", + "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "is-regex": "^1.1.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "node_modules/sanitize-filename": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/sanitize-filename/-/sanitize-filename-1.6.3.tgz", + "integrity": "sha512-y/52Mcy7aw3gRm7IrcGDFx/bCk4AhRh2eI9luHOQM86nZsqwiRkkq2GekHXBBD+SmPidc8i2PqtYZl+pWJ8Oeg==", + "dev": true, + "dependencies": { + "truncate-utf8-bytes": "^1.0.0" + } + }, + "node_modules/sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" + }, + "node_modules/selderee": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/selderee/-/selderee-0.11.0.tgz", + "integrity": "sha512-5TF+l7p4+OsnP8BCCvSyZiSPc4x4//p5uPwK8TCnVPJYRmU2aYKMpOXvw8zM5a5JvuuCGN1jmsMwuU2W02ukfA==", + "dependencies": { + "parseley": "^0.12.0" + }, + "funding": { + "url": "https://ko-fi.com/killymxi" + } + }, + "node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver-compare": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz", + "integrity": "sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==", + "optional": true + }, + "node_modules/serialize-error": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-8.1.0.tgz", + "integrity": "sha512-3NnuWfM6vBYoy5gZFvHiYsVbafvI9vZv/+jlIigFn4oP4zjNPK3LhcY0xSCgeb1a5L8jO71Mit9LlNoi2UfDDQ==", + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/serialize-error/node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", + "dev": true + }, + "node_modules/setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", + "dev": true + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, + "node_modules/simple-update-notifier": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz", + "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==", + "dev": true, + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/simple-youtube-age-restriction-bypass": { + "version": "2.5.9", + "resolved": "git+ssh://git@github.com/MiepHD/Simple-YouTube-Age-Restriction-Bypass.git#79b9456c290df42f35f081413e18dc336d340724", + "license": "MIT", + "workspaces": [ + "account-proxy" + ], + "engines": { + "node": ">=18.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/slash": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", + "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/slice-ansi": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-3.0.0.tgz", + "integrity": "sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==", + "dev": true, + "optional": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "dev": true, + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.1.tgz", + "integrity": "sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==", + "dev": true, + "dependencies": { + "ip": "^2.0.0", + "smart-buffer": "^4.2.0" + }, + "engines": { + "node": ">= 10.13.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks-proxy-agent": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-7.0.0.tgz", + "integrity": "sha512-Fgl0YPZ902wEsAyiQ+idGd1A7rSFx/ayC1CQVMw5P+EQx2V0SgpGtf6OKFhVjPflPUl9YMmEOnmfjCdMUsygww==", + "dev": true, + "dependencies": { + "agent-base": "^6.0.2", + "debug": "^4.3.3", + "socks": "^2.6.2" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/spdx-correct": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", + "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", + "dev": true, + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-exceptions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", + "dev": true + }, + "node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.13.tgz", + "integrity": "sha512-XkD+zwiqXHikFZm4AX/7JSCXA98U5Db4AFd5XUg/+9UNtnH75+Z9KxtpYiJZx36mUDVOwH83pl7yvCer6ewM3w==", + "dev": true + }, + "node_modules/split": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/split/-/split-0.3.3.tgz", + "integrity": "sha512-wD2AeVmxXRBoX44wAycgjVpMhvbwdI2aZjCkvfNcH1YqHQvJVa1duWc73OyVGJUc05fhFaTZeQ/PYsrmyH0JVA==", + "dependencies": { + "through": "2" + }, + "engines": { + "node": "*" + } + }, + "node_modules/sprintf-js": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.2.tgz", + "integrity": "sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==", + "optional": true + }, + "node_modules/ssri": { + "version": "10.0.5", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-10.0.5.tgz", + "integrity": "sha512-bSf16tAFkGeRlUNDjXu8FzaMQt6g2HZJrun7mtMbIPOddxt3GLMSz5VWUWcqTJUPfLEaDIepGxv+bYQW49596A==", + "dev": true, + "dependencies": { + "minipass": "^7.0.3" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/ssri/node_modules/minipass": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.3.tgz", + "integrity": "sha512-LhbbwCfz3vsb12j/WkWQPZfKTsgqIe1Nf/ti1pKjYESGLHIVjWU96G9/ljLH4F9mWNVhlQOm0VySdAWzf05dpg==", + "dev": true, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/stat-mode": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/stat-mode/-/stat-mode-1.0.0.tgz", + "integrity": "sha512-jH9EhtKIjuXZ2cWxmXS8ZP80XyC3iasQxMDV8jzhNJpfDb7VbQLVW4Wvsxz9QZvzV+G4YoSfBUVKDOyxLzi/sg==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/stream-combiner": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/stream-combiner/-/stream-combiner-0.0.4.tgz", + "integrity": "sha512-rT00SPnTVyRsaSz5zgSPma/aHSOic5U1prhYdRy5HS2kTZviFpmDgzilbtsJsxiroqACmayynDN/9VzIbX5DOw==", + "dependencies": { + "duplexer": "~0.1.1" + } + }, + "node_modules/streamsearch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", + "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string.prototype.trim": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.7.tgz", + "integrity": "sha512-p6TmeT1T3411M8Cgg9wBTMRtY2q9+PNy9EV1i2lIXUN/btt763oIfxwN3RR8VU6wHX8j/1CFy0L+YuThm6bgOg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz", + "integrity": "sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz", + "integrity": "sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-final-newline": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", + "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strip-indent": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-4.0.0.tgz", + "integrity": "sha512-mnVSV2l+Zv6BLpSD/8V87CW/y9EmmbYzGCIavsnsI6/nwn26DwffM/yztm30Z/I2DY9wdS3vXVCMnHDgZaVNoA==", + "dev": true, + "dependencies": { + "min-indent": "^1.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strip-outer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/strip-outer/-/strip-outer-1.0.1.tgz", + "integrity": "sha512-k55yxKHwaXnpYGsOzg4Vl8+tDrWylxDEpknGjhTiZB8dFRU5rTo9CAzeycivxV3s+zlTKwrs6WxMxR95n26kwg==", + "dependencies": { + "escape-string-regexp": "^1.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/strip-outer/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/sumchecker": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/sumchecker/-/sumchecker-3.0.1.tgz", + "integrity": "sha512-MvjXzkz/BOfyVDkG0oFOtBxHX2u3gKbMHIF/dXblZsgD3BWOFLmHovIpZY7BykJdAjcqRCBi1WYBNdEC9yI7vg==", + "dependencies": { + "debug": "^4.1.0" + }, + "engines": { + "node": ">= 8.0" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/synckit": { + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.8.5.tgz", + "integrity": "sha512-L1dapNV6vu2s/4Sputv8xGsCdAVlb5nRDMFU/E27D44l5U6cw1g0dGd45uLc+OXjNMmF4ntiMdCimzcjFKQI8Q==", + "dev": true, + "dependencies": { + "@pkgr/utils": "^2.3.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts" + } + }, + "node_modules/tar": { + "version": "6.1.15", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.15.tgz", + "integrity": "sha512-/zKt9UyngnxIT/EAGYuxaMYgOIJiP81ab9ZfkILq4oNLPFX50qyYmu7jRj9qeXoxmJHjGlbH0+cm2uy1WCs10A==", + "dev": true, + "dependencies": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^5.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/tar/node_modules/fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/tar/node_modules/fs-minipass/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/temp-file": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/temp-file/-/temp-file-3.4.0.tgz", + "integrity": "sha512-C5tjlC/HCtVUOi3KWVokd4vHVViOmGjtLwIh4MuzPo/nMYTV/p1urt3RnMz2IWXDdKEGJH3k5+KPxtqRsUYGtg==", + "dev": true, + "dependencies": { + "async-exit-hook": "^2.0.1", + "fs-extra": "^10.0.0" + } + }, + "node_modules/temp-file/node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/temp-file/node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/temp-file/node_modules/universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "dev": true, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, + "node_modules/through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==" + }, + "node_modules/through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "dev": true, + "dependencies": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "node_modules/through2/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true + }, + "node_modules/through2/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/through2/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "node_modules/through2/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/tiny-typed-emitter": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tiny-typed-emitter/-/tiny-typed-emitter-2.1.0.tgz", + "integrity": "sha512-qVtvMxeXbVej0cQWKqVSSAHmKZEHAvxdF8HEUBFWts8h+xEo5m/lEiPakuyZ3BnCBjOD8i24kzNOiOLLgsSxhA==" + }, + "node_modules/titleize": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/titleize/-/titleize-3.0.0.tgz", + "integrity": "sha512-KxVu8EYHDPBdUYdKZdKtU2aj2XfEx9AfjXxE/Aj0vT06w2icA09Vus1rh6eSu1y01akYg6BjIK/hxyLJINoMLQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/tldts-core": { + "version": "6.0.14", + "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-6.0.14.tgz", + "integrity": "sha512-ESYhU/bgs6jiHlnl5h029f+0dB7EKRiTaxM/jHLZ6powScbmsgsrFcFjmyrjDgCvI/BRY79TEBBClmqLNEPyjQ==" + }, + "node_modules/tldts-experimental": { + "version": "6.0.14", + "resolved": "https://registry.npmjs.org/tldts-experimental/-/tldts-experimental-6.0.14.tgz", + "integrity": "sha512-q9tVxHEotaG1buC8E4k+1iGecpM9iLD9FqWzWUKMilUoCpK8uJcO20iDA9ORCojqZdsMXgPgBlSetwiw5ML0tg==", + "dependencies": { + "tldts-core": "^6.0.14" + } + }, + "node_modules/tmp-promise": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/tmp-promise/-/tmp-promise-3.0.3.tgz", + "integrity": "sha512-RwM7MoPojPxsOBYnyd2hy0bxtIlVrihNs9pj5SUvY8Zz1sQcQG2tG1hSr8PDxfgEB8RNKDhqbIlroIarSNDNsQ==", + "dev": true, + "dependencies": { + "tmp": "^0.2.0" + } + }, + "node_modules/tmp-promise/node_modules/tmp": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz", + "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==", + "dev": true, + "dependencies": { + "rimraf": "^3.0.0" + }, + "engines": { + "node": ">=8.17.0" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, + "node_modules/trim-newlines": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-4.1.1.tgz", + "integrity": "sha512-jRKj0n0jXWo6kh62nA5TEh3+4igKDXLvzBJcPpiizP7oOolUrYIxmVBG9TOtHYFHoddUk6YvAkGeGoSVTXfQXQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/trim-repeated": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/trim-repeated/-/trim-repeated-1.0.0.tgz", + "integrity": "sha512-pkonvlKk8/ZuR0D5tLW8ljt5I8kmxp2XKymhepUeOdCEfKpZaktSArkLHZt76OB1ZvO9bssUsDty4SWhLvZpLg==", + "dependencies": { + "escape-string-regexp": "^1.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/trim-repeated/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/truncate-utf8-bytes": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/truncate-utf8-bytes/-/truncate-utf8-bytes-1.0.2.tgz", + "integrity": "sha512-95Pu1QXQvruGEhv62XCMO3Mm90GscOCClvrIUwCM0PYOXK3kaF3l3sIHxx71ThJfcbM2O5Au6SO3AWCSEfW4mQ==", + "dev": true, + "dependencies": { + "utf8-byte-length": "^1.0.1" + } + }, + "node_modules/ts-api-utils": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.0.2.tgz", + "integrity": "sha512-Cbu4nIqnEdd+THNEsBdkolnOXhg0I8XteoHaEKgvsxpsbWda4IsUut2c187HxywQCvveojow0Dgw/amxtSKVkQ==", + "dev": true, + "engines": { + "node": ">=16.13.0" + }, + "peerDependencies": { + "typescript": ">=4.2.0" + } + }, + "node_modules/tsconfig-paths": { + "version": "3.14.2", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.2.tgz", + "integrity": "sha512-o/9iXgCYc5L/JxCHPe3Hvh8Q/2xm5Z+p18PESBU6Ff33695QnCHBEjcytY2q19ua7Mbl/DavtBOLq+oG0RCL+g==", + "dev": true, + "dependencies": { + "@types/json5": "^0.0.29", + "json5": "^1.0.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + } + }, + "node_modules/tsconfig-paths/node_modules/json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "dev": true, + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-fest": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", + "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typed-array-buffer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.0.tgz", + "integrity": "sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.1", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/typed-array-byte-length": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.0.tgz", + "integrity": "sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "has-proto": "^1.0.1", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-byte-offset": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.0.tgz", + "integrity": "sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg==", + "dev": true, + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "has-proto": "^1.0.1", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-length": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz", + "integrity": "sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "is-typed-array": "^1.1.9" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typescript": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", + "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/uglify-js": { + "version": "3.17.4", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.4.tgz", + "integrity": "sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==", + "dev": true, + "optional": true, + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/unbox-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", + "which-boxed-primitive": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/undici": { + "version": "5.23.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.23.0.tgz", + "integrity": "sha512-1D7w+fvRsqlQ9GscLBwcAJinqcZGHUKjbOmXdlE/v8BvEGXjeWAax+341q44EuTcHXXnfyKNbKRq4Lg7OzhMmg==", + "dependencies": { + "busboy": "^1.6.0" + }, + "engines": { + "node": ">=14.0" + } + }, + "node_modules/unique-filename": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-3.0.0.tgz", + "integrity": "sha512-afXhuC55wkAmZ0P18QsVE6kp8JaxrEokN2HGIoIVv2ijHQd419H0+6EigAFcIzXeMIkcIkNBpB3L/DXB3cTS/g==", + "dev": true, + "dependencies": { + "unique-slug": "^4.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/unique-slug": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-4.0.0.tgz", + "integrity": "sha512-WrcA6AyEfqDX5bWige/4NQfPZMtASNVxdmWR76WESYQVAACSgWcR6e9i0mofqqBxYFtL4oAxPIptY73/0YE1DQ==", + "dev": true, + "dependencies": { + "imurmurhash": "^0.1.4" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/untildify": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz", + "integrity": "sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/unzip-crx-3": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/unzip-crx-3/-/unzip-crx-3-0.2.0.tgz", + "integrity": "sha512-0+JiUq/z7faJ6oifVB5nSwt589v1KCduqIJupNVDoWSXZtWDmjDGO3RAEOvwJ07w90aoXoP4enKsR7ecMrJtWQ==", + "dev": true, + "dependencies": { + "jszip": "^3.1.0", + "mkdirp": "^0.5.1", + "yaku": "^0.16.6" + } + }, + "node_modules/unzip-crx-3/node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dev": true, + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/url-match-patterns": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/url-match-patterns/-/url-match-patterns-0.2.0.tgz", + "integrity": "sha512-vtaWyxq+CyrQP4/dapGddkSGwGypQOD2qjHcsqp9ahsjRWzGtjqm+ANxApH46OfWQfpkL6cuyPwsm80386jdjQ==", + "dependencies": { + "lodash": "^4.3.0" + } + }, + "node_modules/utf8-byte-length": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/utf8-byte-length/-/utf8-byte-length-1.0.4.tgz", + "integrity": "sha512-4+wkEYLBbWxqTahEsWrhxepcoVOJ+1z5PGIjPZxRkytcdSUaNjIjBM7Xn8E+pdSuV7SzvWovBFA54FO0JSoqhA==", + "dev": true + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true + }, + "node_modules/uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", + "bin": { + "uuid": "bin/uuid" + } + }, + "node_modules/validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "node_modules/verror": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.1.tgz", + "integrity": "sha512-veufcmxri4e3XSrT0xwfUR7kguIkaxBeosDg00yDWhk49wdwkSUrvvsm7nc75e1PUyvIeZj6nS8VQRYz2/S4Xg==", + "dev": true, + "optional": true, + "dependencies": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + }, + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/vudio": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/vudio/-/vudio-2.1.1.tgz", + "integrity": "sha512-VkFQcFt/b/kpF5Eg5Sq+oXUo1Zp5aRFF4BSmIrOzau5o+5WMWwX9ae/EGJZstCyZFiCTU5iw1Y+u2BCGW6Y6Jw==" + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dev": true, + "dependencies": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.11.tgz", + "integrity": "sha512-qe9UWWpkeG5yzZ0tNYxDmd7vo58HDBc39mZ0xWWpolAGADdFOzkfamWLDxkOWcvHQKVmdTyQdLD4NOfjLWTKew==", + "dev": true, + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/wide-align": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", + "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", + "dev": true, + "dependencies": { + "string-width": "^1.0.2 || 2 || 3 || 4" + } + }, + "node_modules/wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", + "dev": true + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + }, + "node_modules/ws": { + "version": "8.14.2", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.14.2.tgz", + "integrity": "sha512-wEBG1ftX4jcglPxgFCMJmZ2PLtSbJ2Peg6TmpJFTbe9GZYOQCDPdMYu/Tm0/bGZkw8paZnJY45J4K2PZrLYq8g==", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xml2js": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.6.2.tgz", + "integrity": "sha512-T4rieHaC1EXcES0Kxxj4JWgaUQHDk+qwHcYOCFHfiwKz7tOVPLq7Hjq9dM1WCMhylqMEfP7hMcOIChvotiZegA==", + "dependencies": { + "sax": ">=0.6.0", + "xmlbuilder": "~11.0.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/xml2js/node_modules/xmlbuilder": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", + "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/xmlbuilder": { + "version": "15.1.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-15.1.1.tgz", + "integrity": "sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==", + "dev": true, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "dev": true, + "engines": { + "node": ">=0.4" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yaku": { + "version": "0.16.7", + "resolved": "https://registry.npmjs.org/yaku/-/yaku-0.16.7.tgz", + "integrity": "sha512-Syu3IB3rZvKvYk7yTiyl1bo/jiEFaaStrgv1V2TIJTqYPStSMQVO8EQjg/z+DRzLq/4LIIharNT3iH1hylEIRw==", + "dev": true + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs/node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", + "dependencies": { + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/youtubei.js": { + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/youtubei.js/-/youtubei.js-6.4.1.tgz", + "integrity": "sha512-GVrDkJmF5t378SeDiZPEAoegZ1pxjbEzNyXTuiQnL5LzPSZKA3IoJwL8lBNlRMKyksI5RbieoHzULsEt4AIbFw==", + "funding": [ + "https://github.com/sponsors/LuanRT" + ], + "dependencies": { + "jintr": "^1.1.0", + "tslib": "^2.5.0", + "undici": "^5.19.1" + } + }, + "node_modules/ytpl": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/ytpl/-/ytpl-2.3.0.tgz", + "integrity": "sha512-Cfw2rxq3PFK6qgWr2Z8gsRefVahEzbn9XEuiJldqdXHE6GhO7kTfEvbZKdfXing1SmgW635uJ/UL2g8r0fvu2Q==", + "dependencies": { + "miniget": "^4.2.2" + }, + "engines": { + "node": ">=8" + } + } + } +} diff --git a/package.json b/package.json index 3e525829..6c3fdff5 100644 --- a/package.json +++ b/package.json @@ -1,178 +1,197 @@ { - "name": "youtube-music", - "productName": "YouTube Music", - "version": "1.20.0", - "description": "YouTube Music Desktop App - including custom plugins", - "license": "MIT", - "repository": "th-ch/youtube-music", - "author": { - "name": "th-ch", - "email": "th-ch@users.noreply.github.com", - "url": "https://github.com/th-ch/youtube-music" - }, - "build": { - "appId": "com.github.th-ch.youtube-music", - "productName": "YouTube Music", - "mac": { - "identity": null, - "files": [ - "!plugins/taskbar-mediacontrol${/*}" - ], - "target": [ - { - "target": "dmg", - "arch": [ - "x64", - "arm64" - ] - } - ], - "icon": "assets/generated/icons/mac/icon.icns" - }, - "win": { - "icon": "assets/generated/icons/win/icon.ico", - "files": [ - "!plugins/touchbar${/*}" - ], - "target": [ - { - "target": "nsis", - "arch": [ - "x64", - "arm64" - ] - }, - { - "target": "portable", - "arch": [ - "x64", - "arm64" - ] - } - ] - }, - "nsis": { - "runAfterFinish": false - }, - "linux": { - "icon": "assets/generated/icons/png", - "files": [ - "!plugins/{touchbar,taskbar-mediacontrol}${/*}" - ], - "category": "AudioVideo", - "target": [ - "AppImage", - "snap", - "freebsd", - "deb", - "rpm" - ] - }, - "snap": { - "slots": [ - { - "mpris": { - "interface": "mpris" - } - } - ] - } - }, - "scripts": { - "test": "playwright test", - "test:debug": "DEBUG=pw:browser* playwright test", - "start": "electron .", - "start:debug": "ELECTRON_ENABLE_LOGGING=1 electron .", - "generate:package": "node utils/generate-package-json.js", - "postinstall": "yarn run plugins", - "clean": "del-cli dist", - "build": "yarn run clean && electron-builder --win --mac --linux -p never", - "build:linux": "yarn run clean && electron-builder --linux -p never", - "build:mac": "yarn run clean && electron-builder --mac dmg:x64 -p never", - "build:mac:arm64": "yarn run clean && electron-builder --mac dmg:arm64 -p never", - "build:win": "yarn run clean && electron-builder --win -p never", - "lint": "xo", - "changelog": "auto-changelog", - "plugins": "yarn run plugin:adblocker && yarn run plugin:bypass-age-restrictions", - "plugin:adblocker": "del-cli plugins/adblocker/ad-blocker-engine.bin && node plugins/adblocker/blocker.js", - "plugin:bypass-age-restrictions": "del-cli node_modules/simple-youtube-age-restriction-bypass/package.json && yarn run generate:package simple-youtube-age-restriction-bypass", - "release:linux": "yarn run clean && electron-builder --linux -p always -c.snap.publish=github", - "release:mac": "yarn run clean && electron-builder --mac -p always", - "release:win": "yarn run clean && electron-builder --win -p always" - }, - "engines": { - "node": ">=16.0.0", - "npm": "Please use yarn instead" - }, - "dependencies": { - "@cliqz/adblocker-electron": "^1.26.5", - "@ffmpeg/core": "^0.11.0", - "@ffmpeg/ffmpeg": "^0.11.6", - "@foobar404/wave": "^2.0.4", - "@xhayper/discord-rpc": "^1.0.16", - "async-mutex": "^0.4.0", - "browser-id3-writer": "^5.0.0", - "butterchurn": "^2.6.7", - "butterchurn-presets": "^2.4.7", - "custom-electron-prompt": "^1.5.7", - "custom-electron-titlebar": "^4.1.6", - "electron-better-web-request": "^1.0.1", - "electron-debug": "^3.2.0", - "electron-is": "^3.0.0", - "electron-localshortcut": "^3.2.1", - "electron-store": "^8.1.0", - "electron-unhandled": "^4.0.1", - "electron-updater": "^5.3.0", - "filenamify": "^4.3.0", - "howler": "^2.2.3", - "html-to-text": "^9.0.5", - "keyboardevent-from-electron-accelerator": "^2.0.0", - "keyboardevents-areequal": "^0.2.2", - "md5": "^2.3.0", - "mpris-service": "^2.1.2", - "node-fetch": "^2.6.9", - "simple-youtube-age-restriction-bypass": "https://gitpkg.now.sh/api/pkg.tgz?url=MiepHD/Simple-YouTube-Age-Restriction-Bypass&commit=v2.5.5", - "vudio": "^2.1.1", - "youtubei.js": "^4.3.0", - "ytpl": "^2.3.0" - }, - "resolutions": { - "xml2js": "^0.5.0", - "@electron/universal": "^1.3.4", - "electron-is-dev": "patch:electron-is-dev@npm%3A2.0.0#./.yarn/patches/electron-is-dev-npm-2.0.0-9d41637d91.patch" - }, - "devDependencies": { - "@playwright/test": "^1.29.2", - "auto-changelog": "^2.4.0", - "del-cli": "^5.0.0", - "electron": "^22.3.6", - "electron-builder": "^23.6.0", - "electron-devtools-installer": "^3.2.0", - "node-gyp": "^9.3.1", - "playwright": "^1.29.2", - "xo": "^0.53.1" - }, - "auto-changelog": { - "hideCredit": true, - "package": true, - "unreleased": true, - "output": "changelog.md" - }, - "xo": { - "envs": [ - "node", - "browser" - ], - "rules": { - "quotes": [ - "error", - "double", - { - "avoidEscape": true, - "allowTemplateLiterals": true - } - ] - } - }, - "packageManager": "yarn@3.4.1" + "name": "youtube-music", + "productName": "YouTube Music", + "version": "1.20.0", + "description": "YouTube Music Desktop App - including custom plugins", + "main": "./dist/index.js", + "license": "MIT", + "repository": "th-ch/youtube-music", + "author": { + "name": "th-ch", + "email": "th-ch@users.noreply.github.com", + "url": "https://github.com/th-ch/youtube-music" + }, + "build": { + "appId": "com.github.th-ch.youtube-music", + "productName": "YouTube Music", + "mac": { + "identity": null, + "files": [ + "!*", + "dist", + "!dist/plugins/taskbar-mediacontrol${/*}", + "license", + "node_modules", + "package.json", + "tests" + ], + "target": [ + { + "target": "dmg", + "arch": [ + "x64", + "arm64" + ] + } + ], + "icon": "assets/generated/icons/mac/icon.icns" + }, + "win": { + "icon": "assets/generated/icons/win/icon.ico", + "files": [ + "!*", + "dist", + "!dist/plugins/touchbar${/*}", + "license", + "node_modules", + "package.json", + "tests" + ], + "target": [ + { + "target": "nsis", + "arch": [ + "x64", + "arm64" + ] + }, + { + "target": "portable", + "arch": [ + "x64", + "arm64" + ] + } + ] + }, + "nsis": { + "runAfterFinish": false + }, + "linux": { + "icon": "assets/generated/icons/png", + "files": [ + "!*", + "dist", + "!dist/plugins/{touchbar,taskbar-mediacontrol}${/*}", + "license", + "node_modules", + "package.json", + "tests" + ], + "category": "AudioVideo", + "target": [ + "AppImage", + "snap", + "freebsd", + "deb", + "rpm" + ] + }, + "snap": { + "slots": [ + { + "mpris": { + "interface": "mpris" + } + } + ] + }, + "directories": { + "output": "./pack/" + } + }, + "scripts": { + "test": "playwright test", + "test:debug": "DEBUG=pw:browser* playwright test", + "start": "npm run tsc-and-copy && electron ./dist/index.js", + "start:debug": "ELECTRON_ENABLE_LOGGING=1 electron ./dist/index.js", + "generate:package": "node utils/generate-package-json.js", + "postinstall": "npm run plugins", + "clean": "del-cli dist && del-cli pack", + "ytm-resource-copy-files": "copyfiles error.html youtube-music.css assets/**/* dist/", + "copy-files": "copyfiles -u 1 plugins/**/*.html plugins/**/*.css plugins/**/*.bin plugins/**/*.js dist/plugins/", + "tsc-and-copy": "tsc && npm run plugin:adblocker-without-tsc && npm run ytm-resource-copy-files && npm run copy-files", + "build": "npm run clean && npm run tsc-and-copy && electron-builder --win --mac --linux -p never", + "build:linux": "npm run clean && npm run tsc-and-copy && electron-builder --linux -p never", + "build:mac": "npm run clean && npm run tsc-and-copy && electron-builder --mac dmg:x64 -p never", + "build:mac:arm64": "npm run clean && npm run tsc-and-copy && electron-builder --mac dmg:arm64 -p never", + "build:win": "npm run clean && npm run tsc-and-copy && electron-builder --win -p never", + "build:win:x64": "npm run clean && npm run tsc-and-copy && electron-builder --win nsis:x64 -p never", + "lint": "eslint .", + "changelog": "auto-changelog", + "plugins": "npm run plugin:adblocker && npm run plugin:bypass-age-restrictions", + "plugin:adblocker-without-tsc": "del-cli plugins/adblocker/ad-blocker-engine.bin && node dist/plugins/adblocker/blocker.js", + "plugin:adblocker": "del-cli plugins/adblocker/ad-blocker-engine.bin && tsc && node dist/plugins/adblocker/blocker.js", + "plugin:bypass-age-restrictions": "del-cli node_modules/simple-youtube-age-restriction-bypass/package.json && npm run generate:package simple-youtube-age-restriction-bypass", + "release:linux": "npm run clean && npm run tsc-and-copy && electron-builder --linux -p always -c.snap.publish=github", + "release:mac": "npm run clean && npm run tsc-and-copy && electron-builder --mac -p always", + "release:win": "npm run clean && npm run tsc-and-copy && electron-builder --win -p always", + "typecheck": "tsc -p tsconfig.json --noEmit" + }, + "engines": { + "node": ">=16.0.0" + }, + "dependencies": { + "@cliqz/adblocker-electron": "1.26.7", + "@ffmpeg.wasm/core-mt": "0.12.0", + "@ffmpeg.wasm/main": "0.12.0", + "@foobar404/wave": "2.0.4", + "@xhayper/discord-rpc": "1.0.23", + "async-mutex": "0.4.0", + "butterchurn": "2.6.7", + "butterchurn-presets": "2.4.7", + "conf": "10.2.0", + "custom-electron-prompt": "1.5.7", + "custom-electron-titlebar": "4.1.6", + "electron-better-web-request": "1.0.1", + "electron-debug": "3.2.0", + "electron-is": "3.0.0", + "electron-localshortcut": "3.2.1", + "electron-store": "8.1.0", + "electron-unhandled": "4.0.1", + "electron-updater": "6.1.4", + "filenamify": "4.3.0", + "howler": "2.2.4", + "html-to-text": "9.0.5", + "keyboardevent-from-electron-accelerator": "2.0.0", + "keyboardevents-areequal": "0.2.2", + "mpris-service": "2.1.2", + "node-id3": "0.2.6", + "simple-youtube-age-restriction-bypass": "git+https://github.com/MiepHD/Simple-YouTube-Age-Restriction-Bypass.git#v2.5.5", + "vudio": "2.1.1", + "youtubei.js": "6.4.1", + "ytpl": "2.3.0" + }, + "overrides": { + "xml2js": "0.6.2", + "node-fetch": "2.7.0", + "@electron/universal": "1.4.2", + "electron": "27.0.0-beta.9" + }, + "devDependencies": { + "@playwright/test": "1.38.1", + "@total-typescript/ts-reset": "0.5.1", + "@types/electron-localshortcut": "3.1.1", + "@types/howler": "2.2.9", + "@types/html-to-text": "9.0.2", + "@typescript-eslint/eslint-plugin": "6.7.4", + "auto-changelog": "2.4.0", + "copyfiles": "2.4.1", + "del-cli": "5.1.0", + "electron": "27.0.0-beta.9", + "electron-builder": "24.6.4", + "electron-devtools-installer": "3.2.0", + "eslint": "8.50.0", + "eslint-plugin-import": "2.28.1", + "eslint-plugin-prettier": "5.0.0", + "node-gyp": "9.4.0", + "playwright": "1.38.1", + "typescript": "5.2.2" + }, + "auto-changelog": { + "hideCredit": true, + "package": true, + "unreleased": true, + "output": "changelog.md" + } } diff --git a/plugins/adblocker/back.js b/plugins/adblocker/back.js deleted file mode 100644 index d15aa695..00000000 --- a/plugins/adblocker/back.js +++ /dev/null @@ -1,13 +0,0 @@ -const { loadAdBlockerEngine } = require("./blocker"); -const config = require("./config"); - -module.exports = async (win, options) => { - if (await config.shouldUseBlocklists()) { - loadAdBlockerEngine( - win.webContents.session, - options.cache, - options.additionalBlockLists, - options.disableDefaultLists, - ); - } -}; diff --git a/plugins/adblocker/back.ts b/plugins/adblocker/back.ts new file mode 100644 index 00000000..d33771ae --- /dev/null +++ b/plugins/adblocker/back.ts @@ -0,0 +1,19 @@ +import { BrowserWindow } from 'electron'; + +import { loadAdBlockerEngine } from './blocker'; +import { shouldUseBlocklists } from './config'; + +import type { ConfigType } from '../../config/dynamic'; + +type AdBlockOptions = ConfigType<'adblocker'>; + +export default async (win: BrowserWindow, options: AdBlockOptions) => { + if (await shouldUseBlocklists()) { + loadAdBlockerEngine( + win.webContents.session, + options.cache, + options.additionalBlockLists, + options.disableDefaultLists, + ); + } +}; diff --git a/plugins/adblocker/blocker.js b/plugins/adblocker/blocker.js deleted file mode 100644 index e62b1919..00000000 --- a/plugins/adblocker/blocker.js +++ /dev/null @@ -1,60 +0,0 @@ -const { promises } = require("fs"); // used for caching -const path = require("path"); - -const { ElectronBlocker } = require("@cliqz/adblocker-electron"); -const fetch = require("node-fetch"); - -const SOURCES = [ - "https://raw.githubusercontent.com/kbinani/adblock-youtube-ads/master/signed.txt", - // uBlock Origin - "https://raw.githubusercontent.com/uBlockOrigin/uAssets/master/filters/filters.txt", - "https://raw.githubusercontent.com/uBlockOrigin/uAssets/master/filters/filters-2021.txt", - // Fanboy Annoyances - "https://secure.fanboy.co.nz/fanboy-annoyance_ubo.txt", -]; - -const loadAdBlockerEngine = ( - session = undefined, - cache = true, - additionalBlockLists = [], - disableDefaultLists = false -) => { - // Only use cache if no additional blocklists are passed - const cachingOptions = - cache && additionalBlockLists.length === 0 - ? { - path: path.resolve(__dirname, "ad-blocker-engine.bin"), - read: promises.readFile, - write: promises.writeFile, - } - : undefined; - const lists = [ - ...(disableDefaultLists ? [] : SOURCES), - ...additionalBlockLists, - ]; - - ElectronBlocker.fromLists( - fetch, - lists, - { - // when generating the engine for caching, do not load network filters - // So that enhancing the session works as expected - // Allowing to define multiple webRequest listeners - loadNetworkFilters: session !== undefined, - }, - cachingOptions - ) - .then((blocker) => { - if (session) { - blocker.enableBlockingInSession(session); - } else { - console.log("Successfully generated adBlocker engine."); - } - }) - .catch((err) => console.log("Error loading adBlocker engine", err)); -}; - -module.exports = { loadAdBlockerEngine }; -if (require.main === module) { - loadAdBlockerEngine(); // Generate the engine without enabling it -} diff --git a/plugins/adblocker/blocker.ts b/plugins/adblocker/blocker.ts new file mode 100644 index 00000000..9fd0d5e6 --- /dev/null +++ b/plugins/adblocker/blocker.ts @@ -0,0 +1,63 @@ +// Used for caching +import path from 'node:path'; +import { promises } from 'node:fs'; + +import { ElectronBlocker } from '@cliqz/adblocker-electron'; + +const SOURCES = [ + 'https://raw.githubusercontent.com/kbinani/adblock-youtube-ads/master/signed.txt', + // UBlock Origin + 'https://raw.githubusercontent.com/uBlockOrigin/uAssets/master/filters/filters.txt', + 'https://raw.githubusercontent.com/uBlockOrigin/uAssets/master/filters/filters-2020.txt', + 'https://raw.githubusercontent.com/uBlockOrigin/uAssets/master/filters/filters-2021.txt', + 'https://raw.githubusercontent.com/uBlockOrigin/uAssets/master/filters/filters-2022.txt', + 'https://raw.githubusercontent.com/uBlockOrigin/uAssets/master/filters/filters-2023.txt', + // Fanboy Annoyances + 'https://secure.fanboy.co.nz/fanboy-annoyance_ubo.txt', +]; + +export const loadAdBlockerEngine = ( + session: Electron.Session | undefined = undefined, + cache = true, + additionalBlockLists = [], + disableDefaultLists: boolean | string[] = false, +) => { + // Only use cache if no additional blocklists are passed + const cachingOptions + = cache && additionalBlockLists.length === 0 + ? { + path: path.resolve(__dirname, 'ad-blocker-engine.bin'), + read: promises.readFile, + write: promises.writeFile, + } + : undefined; + const lists = [ + ...(disableDefaultLists ? [] : SOURCES), + ...additionalBlockLists, + ]; + + ElectronBlocker.fromLists( + fetch, + lists, + { + // When generating the engine for caching, do not load network filters + // So that enhancing the session works as expected + // Allowing to define multiple webRequest listeners + loadNetworkFilters: session !== undefined, + }, + cachingOptions, + ) + .then((blocker) => { + if (session) { + blocker.enableBlockingInSession(session); + } else { + console.log('Successfully generated adBlocker engine.'); + } + }) + .catch((error) => console.log('Error loading adBlocker engine', error)); +}; + +export default { loadAdBlockerEngine }; +if (require.main === module) { + loadAdBlockerEngine(); // Generate the engine without enabling it +} diff --git a/plugins/adblocker/config.js b/plugins/adblocker/config.js deleted file mode 100644 index 5c17a03a..00000000 --- a/plugins/adblocker/config.js +++ /dev/null @@ -1,13 +0,0 @@ -const { PluginConfig } = require("../../config/dynamic"); - -const config = new PluginConfig("adblocker", { enableFront: true }); - -const blockers = { - WithBlocklists: "With blocklists", - InPlayer: "In player", -}; - -const shouldUseBlocklists = async () => - (await config.get("blocker")) !== blockers.InPlayer; - -module.exports = { shouldUseBlocklists, blockers, ...config }; diff --git a/plugins/adblocker/config.ts b/plugins/adblocker/config.ts new file mode 100644 index 00000000..e8bad5a5 --- /dev/null +++ b/plugins/adblocker/config.ts @@ -0,0 +1,18 @@ +/* eslint-disable @typescript-eslint/await-thenable */ +/* renderer */ + +import { PluginConfig } from '../../config/dynamic'; + +const config = new PluginConfig('adblocker', { enableFront: true }); + +export const blockers = { + WithBlocklists: 'With blocklists', + InPlayer: 'In player', +}; + +export const shouldUseBlocklists = async () => await config.get('blocker') !== blockers.InPlayer; + +export default Object.assign(config, { + shouldUseBlocklists, + blockers, +}); diff --git a/plugins/adblocker/inject.js b/plugins/adblocker/inject.js index e296236f..513bc960 100644 --- a/plugins/adblocker/inject.js +++ b/plugins/adblocker/inject.js @@ -1,289 +1,434 @@ +/* eslint-disable */ + // Source: https://addons.mozilla.org/en-US/firefox/addon/adblock-for-youtube/ // https://robwu.nl/crxviewer/?crx=https%3A%2F%2Faddons.mozilla.org%2Fen-US%2Ffirefox%2Faddon%2Fadblock-for-youtube%2F /* - Parts of this code is derived from set-constant.js: - https://github.com/gorhill/uBlock/blob/5de0ce975753b7565759ac40983d31978d1f84ca/assets/resources/scriptlets.js#L704 - */ + Parts of this code is derived from set-constant.js: + https://github.com/gorhill/uBlock/blob/5de0ce975753b7565759ac40983d31978d1f84ca/assets/resources/scriptlets.js#L704 + */ { - let pruner = function (o) { - delete o.playerAds; - delete o.adPlacements; - // - if (o.playerResponse) { - delete o.playerResponse.playerAds; - delete o.playerResponse.adPlacements; - } - // - return o; - }; + const pruner = function (o) { + delete o.playerAds; + delete o.adPlacements; + // + if (o.playerResponse) { + delete o.playerResponse.playerAds; + delete o.playerResponse.adPlacements; + } - JSON.parse = new Proxy(JSON.parse, { - apply: function () { - return pruner(Reflect.apply(...arguments)); - }, - }); + // + return o; + }; - Response.prototype.json = new Proxy(Response.prototype.json, { - apply: function () { - return Reflect.apply(...arguments).then((o) => pruner(o)); - }, - }); + JSON.parse = new Proxy(JSON.parse, { + apply() { + return pruner(Reflect.apply(...arguments)); + }, + }); + + Response.prototype.json = new Proxy(Response.prototype.json, { + apply() { + return Reflect.apply(...arguments).then((o) => pruner(o)); + }, + }); } (function () { - let cValue = "undefined"; - const chain = "playerResponse.adPlacements"; - const thisScript = document.currentScript; - // - if (cValue === "null") cValue = null; - else if (cValue === "''") cValue = ""; - else if (cValue === "true") cValue = true; - else if (cValue === "false") cValue = false; - else if (cValue === "undefined") cValue = undefined; - else if (cValue === "noopFunc") cValue = function () {}; - else if (cValue === "trueFunc") - cValue = function () { - return true; - }; - else if (cValue === "falseFunc") - cValue = function () { - return false; - }; - else if (/^\d+$/.test(cValue)) { - cValue = parseFloat(cValue); - // - if (isNaN(cValue)) return; - if (Math.abs(cValue) > 0x7fff) return; - } else { - return; - } - // - let aborted = false; - const mustAbort = function (v) { - if (aborted) return true; - aborted = - v !== undefined && - v !== null && - cValue !== undefined && - cValue !== null && - typeof v !== typeof cValue; - return aborted; - }; + let cValue = 'undefined'; + const chain = 'playerResponse.adPlacements'; + const thisScript = document.currentScript; + // + switch (cValue) { + case 'null': { + cValue = null; + break; + } - /* - Support multiple trappers for the same property: - https://github.com/uBlockOrigin/uBlock-issues/issues/156 + case "''": { + cValue = ''; + break; + } + + case 'true': { + cValue = true; + break; + } + + case 'false': { + cValue = false; + break; + } + + case 'undefined': { + cValue = undefined; + break; + } + + case 'noopFunc': { + cValue = function () { + }; + + break; + } + + case 'trueFunc': { + cValue = function () { + return true; + }; + + break; + } + + case 'falseFunc': { + cValue = function () { + return false; + }; + + break; + } + + default: { + if (/^\d+$/.test(cValue)) { + cValue = Number.parseFloat(cValue); + // + if (isNaN(cValue)) { + return; + } + + if (Math.abs(cValue) > 0x7F_FF) { + return; + } + } else { + return; + } + } + } + + // + let aborted = false; + const mustAbort = function (v) { + if (aborted) { + return true; + } + + aborted + = v !== undefined + && v !== null + && cValue !== undefined + && cValue !== null + && typeof v !== typeof cValue; + return aborted; + }; + + /* + Support multiple trappers for the same property: + https://github.com/uBlockOrigin/uBlock-issues/issues/156 */ - const trapProp = function (owner, prop, configurable, handler) { - if (handler.init(owner[prop]) === false) { - return; - } - // - const odesc = Object.getOwnPropertyDescriptor(owner, prop); - let prevGetter, prevSetter; - if (odesc instanceof Object) { - if (odesc.configurable === false) return; - if (odesc.get instanceof Function) prevGetter = odesc.get; - if (odesc.set instanceof Function) prevSetter = odesc.set; - } - // - Object.defineProperty(owner, prop, { - configurable, - get() { - if (prevGetter !== undefined) { - prevGetter(); - } - // - return handler.getter(); - }, - set(a) { - if (prevSetter !== undefined) { - prevSetter(a); - } - // - handler.setter(a); - }, - }); - }; + const trapProp = function (owner, prop, configurable, handler) { + if (handler.init(owner[prop]) === false) { + return; + } - const trapChain = function (owner, chain) { - const pos = chain.indexOf("."); - if (pos === -1) { - trapProp(owner, chain, false, { - v: undefined, - getter: function () { - return document.currentScript === thisScript ? this.v : cValue; - }, - setter: function (a) { - if (mustAbort(a) === false) return; - cValue = a; - }, - init: function (v) { - if (mustAbort(v)) return false; - // - this.v = v; - return true; - }, - }); - // - return; - } - // - const prop = chain.slice(0, pos); - const v = owner[prop]; - // - chain = chain.slice(pos + 1); - if (v instanceof Object || (typeof v === "object" && v !== null)) { - trapChain(v, chain); - return; - } - // - trapProp(owner, prop, true, { - v: undefined, - getter: function () { - return this.v; - }, - setter: function (a) { - this.v = a; - if (a instanceof Object) trapChain(a, chain); - }, - init: function (v) { - this.v = v; - return true; - }, - }); - }; - // - trapChain(window, chain); + // + const odesc = Object.getOwnPropertyDescriptor(owner, prop); + let previousGetter; + let previousSetter; + if (odesc instanceof Object) { + if (odesc.configurable === false) { + return; + } + + if (odesc.get instanceof Function) { + previousGetter = odesc.get; + } + + if (odesc.set instanceof Function) { + previousSetter = odesc.set; + } + } + + // + Object.defineProperty(owner, prop, { + configurable, + get() { + if (previousGetter !== undefined) { + previousGetter(); + } + + // + return handler.getter(); + }, + set(a) { + if (previousSetter !== undefined) { + previousSetter(a); + } + + // + handler.setter(a); + }, + }); + }; + + const trapChain = function (owner, chain) { + const pos = chain.indexOf('.'); + if (pos === -1) { + trapProp(owner, chain, false, { + v: undefined, + getter() { + return document.currentScript === thisScript ? this.v : cValue; + }, + setter(a) { + if (mustAbort(a) === false) { + return; + } + + cValue = a; + }, + init(v) { + if (mustAbort(v)) { + return false; + } + + // + this.v = v; + return true; + }, + }); + // + return; + } + + // + const prop = chain.slice(0, pos); + const v = owner[prop]; + // + chain = chain.slice(pos + 1); + if (v instanceof Object || (typeof v === 'object' && v !== null)) { + trapChain(v, chain); + return; + } + + // + trapProp(owner, prop, true, { + v: undefined, + getter() { + return this.v; + }, + setter(a) { + this.v = a; + if (a instanceof Object) { + trapChain(a, chain); + } + }, + init(v) { + this.v = v; + return true; + }, + }); + }; + + // + trapChain(window, chain); })(); (function () { - let cValue = "undefined"; - const thisScript = document.currentScript; - const chain = "ytInitialPlayerResponse.adPlacements"; - // - if (cValue === "null") cValue = null; - else if (cValue === "''") cValue = ""; - else if (cValue === "true") cValue = true; - else if (cValue === "false") cValue = false; - else if (cValue === "undefined") cValue = undefined; - else if (cValue === "noopFunc") cValue = function () {}; - else if (cValue === "trueFunc") - cValue = function () { - return true; - }; - else if (cValue === "falseFunc") - cValue = function () { - return false; - }; - else if (/^\d+$/.test(cValue)) { - cValue = parseFloat(cValue); - // - if (isNaN(cValue)) return; - if (Math.abs(cValue) > 0x7fff) return; - } else { - return; - } - // - let aborted = false; - const mustAbort = function (v) { - if (aborted) return true; - aborted = - v !== undefined && - v !== null && - cValue !== undefined && - cValue !== null && - typeof v !== typeof cValue; - return aborted; - }; + let cValue = 'undefined'; + const thisScript = document.currentScript; + const chain = 'ytInitialPlayerResponse.adPlacements'; + // + switch (cValue) { + case 'null': { + cValue = null; + break; + } - /* - Support multiple trappers for the same property: - https://github.com/uBlockOrigin/uBlock-issues/issues/156 + case "''": { + cValue = ''; + break; + } + + case 'true': { + cValue = true; + break; + } + + case 'false': { + cValue = false; + break; + } + + case 'undefined': { + cValue = undefined; + break; + } + + case 'noopFunc': { + cValue = function () { + }; + + break; + } + + case 'trueFunc': { + cValue = function () { + return true; + }; + + break; + } + + case 'falseFunc': { + cValue = function () { + return false; + }; + + break; + } + + default: { + if (/^\d+$/.test(cValue)) { + cValue = Number.parseFloat(cValue); + // + if (isNaN(cValue)) { + return; + } + + if (Math.abs(cValue) > 0x7F_FF) { + return; + } + } else { + return; + } + } + } + + // + let aborted = false; + const mustAbort = function (v) { + if (aborted) { + return true; + } + + aborted + = v !== undefined + && v !== null + && cValue !== undefined + && cValue !== null + && typeof v !== typeof cValue; + return aborted; + }; + + /* + Support multiple trappers for the same property: + https://github.com/uBlockOrigin/uBlock-issues/issues/156 */ - const trapProp = function (owner, prop, configurable, handler) { - if (handler.init(owner[prop]) === false) { - return; - } - // - const odesc = Object.getOwnPropertyDescriptor(owner, prop); - let prevGetter, prevSetter; - if (odesc instanceof Object) { - if (odesc.configurable === false) return; - if (odesc.get instanceof Function) prevGetter = odesc.get; - if (odesc.set instanceof Function) prevSetter = odesc.set; - } - // - Object.defineProperty(owner, prop, { - configurable, - get() { - if (prevGetter !== undefined) { - prevGetter(); - } - // - return handler.getter(); - }, - set(a) { - if (prevSetter !== undefined) { - prevSetter(a); - } - // - handler.setter(a); - }, - }); - }; + const trapProp = function (owner, prop, configurable, handler) { + if (handler.init(owner[prop]) === false) { + return; + } - const trapChain = function (owner, chain) { - const pos = chain.indexOf("."); - if (pos === -1) { - trapProp(owner, chain, false, { - v: undefined, - getter: function () { - return document.currentScript === thisScript ? this.v : cValue; - }, - setter: function (a) { - if (mustAbort(a) === false) return; - cValue = a; - }, - init: function (v) { - if (mustAbort(v)) return false; - // - this.v = v; - return true; - }, - }); - // - return; - } - // - const prop = chain.slice(0, pos); - const v = owner[prop]; - // - chain = chain.slice(pos + 1); - if (v instanceof Object || (typeof v === "object" && v !== null)) { - trapChain(v, chain); - return; - } - // - trapProp(owner, prop, true, { - v: undefined, - getter: function () { - return this.v; - }, - setter: function (a) { - this.v = a; - if (a instanceof Object) trapChain(a, chain); - }, - init: function (v) { - this.v = v; - return true; - }, - }); - }; - // - trapChain(window, chain); + // + const odesc = Object.getOwnPropertyDescriptor(owner, prop); + let previousGetter; + let previousSetter; + if (odesc instanceof Object) { + if (odesc.configurable === false) { + return; + } + + if (odesc.get instanceof Function) { + previousGetter = odesc.get; + } + + if (odesc.set instanceof Function) { + previousSetter = odesc.set; + } + } + + // + Object.defineProperty(owner, prop, { + configurable, + get() { + if (previousGetter !== undefined) { + previousGetter(); + } + + // + return handler.getter(); + }, + set(a) { + if (previousSetter !== undefined) { + previousSetter(a); + } + + // + handler.setter(a); + }, + }); + }; + + const trapChain = function (owner, chain) { + const pos = chain.indexOf('.'); + if (pos === -1) { + trapProp(owner, chain, false, { + v: undefined, + getter() { + return document.currentScript === thisScript ? this.v : cValue; + }, + setter(a) { + if (mustAbort(a) === false) { + return; + } + + cValue = a; + }, + init(v) { + if (mustAbort(v)) { + return false; + } + + // + this.v = v; + return true; + }, + }); + // + return; + } + + // + const prop = chain.slice(0, pos); + const v = owner[prop]; + // + chain = chain.slice(pos + 1); + if (v instanceof Object || (typeof v === 'object' && v !== null)) { + trapChain(v, chain); + return; + } + + // + trapProp(owner, prop, true, { + v: undefined, + getter() { + return this.v; + }, + setter(a) { + this.v = a; + if (a instanceof Object) { + trapChain(a, chain); + } + }, + init(v) { + this.v = v; + return true; + }, + }); + }; + + // + trapChain(window, chain); })(); diff --git a/plugins/adblocker/menu.js b/plugins/adblocker/menu.js deleted file mode 100644 index 1622df9a..00000000 --- a/plugins/adblocker/menu.js +++ /dev/null @@ -1,15 +0,0 @@ -const config = require("./config"); - -module.exports = () => [ - { - label: "Blocker", - submenu: Object.values(config.blockers).map((blocker) => ({ - label: blocker, - type: "radio", - checked: (config.get("blocker") || config.blockers.WithBlocklists) === blocker, - click: () => { - config.set("blocker", blocker); - }, - })), - }, -]; diff --git a/plugins/adblocker/menu.ts b/plugins/adblocker/menu.ts new file mode 100644 index 00000000..1e8f43e0 --- /dev/null +++ b/plugins/adblocker/menu.ts @@ -0,0 +1,17 @@ +import config, { blockers } from './config'; + +export default () => { + return [ + { + label: 'Blocker', + submenu: Object.values(blockers).map((blocker: string) => ({ + label: blocker, + type: 'radio', + checked: (config.get('blocker') || blockers.WithBlocklists) === blocker, + click() { + config.set('blocker', blocker); + }, + })), + }, + ]; +}; diff --git a/plugins/adblocker/preload.js b/plugins/adblocker/preload.js deleted file mode 100644 index e7650d05..00000000 --- a/plugins/adblocker/preload.js +++ /dev/null @@ -1,10 +0,0 @@ -const config = require("./config"); - -module.exports = async () => { - if (await config.shouldUseBlocklists()) { - // Preload adblocker to inject scripts/styles - require("@cliqz/adblocker-electron-preload"); - } else if ((await config.get("blocker")) === config.blockers.InPlayer) { - require("./inject"); - } -}; diff --git a/plugins/adblocker/preload.ts b/plugins/adblocker/preload.ts new file mode 100644 index 00000000..33cb6b14 --- /dev/null +++ b/plugins/adblocker/preload.ts @@ -0,0 +1,11 @@ +import config from './config'; + +export default async () => { + if (await config.shouldUseBlocklists()) { + // Preload adblocker to inject scripts/styles + require('@cliqz/adblocker-electron-preload'); + // eslint-disable-next-line @typescript-eslint/await-thenable + } else if ((await config.get('blocker')) === config.blockers.InPlayer) { + require('./inject.js'); + } +}; diff --git a/plugins/audio-compressor/front.js b/plugins/audio-compressor/front.js deleted file mode 100644 index 9c3c4ab6..00000000 --- a/plugins/audio-compressor/front.js +++ /dev/null @@ -1,19 +0,0 @@ -const applyCompressor = (e) => { - const audioContext = e.detail.audioContext; - - const compressor = audioContext.createDynamicsCompressor(); - compressor.threshold.value = -50; - compressor.ratio.value = 12; - compressor.knee.value = 40; - compressor.attack.value = 0; - compressor.release.value = 0.25; - - e.detail.audioSource.connect(compressor); - compressor.connect(audioContext.destination); -}; - -module.exports = () => - document.addEventListener("audioCanPlay", applyCompressor, { - once: true, // Only create the audio compressor once, not on each video - passive: true, - }); diff --git a/plugins/audio-compressor/front.ts b/plugins/audio-compressor/front.ts new file mode 100644 index 00000000..66fd94dd --- /dev/null +++ b/plugins/audio-compressor/front.ts @@ -0,0 +1,17 @@ +export default () => + document.addEventListener('audioCanPlay', (e) => { + const { audioContext } = e.detail; + + const compressor = audioContext.createDynamicsCompressor(); + compressor.threshold.value = -50; + compressor.ratio.value = 12; + compressor.knee.value = 40; + compressor.attack.value = 0; + compressor.release.value = 0.25; + + e.detail.audioSource.connect(compressor); + compressor.connect(audioContext.destination); + }, { + once: true, // Only create the audio compressor once, not on each video + passive: true, + }); diff --git a/plugins/blur-nav-bar/back.js b/plugins/blur-nav-bar/back.js deleted file mode 100644 index 1c95289f..00000000 --- a/plugins/blur-nav-bar/back.js +++ /dev/null @@ -1,6 +0,0 @@ -const path = require("path"); -const { injectCSS } = require("../utils"); - -module.exports = win => { - injectCSS(win.webContents, path.join(__dirname, "style.css")); -}; diff --git a/plugins/blur-nav-bar/back.ts b/plugins/blur-nav-bar/back.ts new file mode 100644 index 00000000..5634e5ef --- /dev/null +++ b/plugins/blur-nav-bar/back.ts @@ -0,0 +1,9 @@ +import path from 'node:path'; + +import { BrowserWindow } from 'electron'; + +import { injectCSS } from '../utils'; + +export default (win: BrowserWindow) => { + injectCSS(win.webContents, path.join(__dirname, 'style.css')); +}; diff --git a/plugins/blur-nav-bar/style.css b/plugins/blur-nav-bar/style.css index 26ad4182..22f32a13 100644 --- a/plugins/blur-nav-bar/style.css +++ b/plugins/blur-nav-bar/style.css @@ -1,10 +1,10 @@ #nav-bar-background, #header.ytmusic-item-section-renderer, ytmusic-tabs { - background: rgba(0, 0, 0, 0.3) !important; - backdrop-filter: blur(8px) !important; + background: rgba(0, 0, 0, 0.3) !important; + backdrop-filter: blur(8px) !important; } #nav-bar-divider { - display: none !important; + display: none !important; } diff --git a/plugins/bypass-age-restrictions/front.js b/plugins/bypass-age-restrictions/front.js deleted file mode 100644 index 1ec536f6..00000000 --- a/plugins/bypass-age-restrictions/front.js +++ /dev/null @@ -1,4 +0,0 @@ -module.exports = () => { - // See https://github.com/zerodytrash/Simple-YouTube-Age-Restriction-Bypass#userscript - require("simple-youtube-age-restriction-bypass/dist/Simple-YouTube-Age-Restriction-Bypass.user.js"); -}; diff --git a/plugins/bypass-age-restrictions/front.ts b/plugins/bypass-age-restrictions/front.ts new file mode 100644 index 00000000..21dcab69 --- /dev/null +++ b/plugins/bypass-age-restrictions/front.ts @@ -0,0 +1,4 @@ +export default () => { + // See https://github.com/zerodytrash/Simple-YouTube-Age-Restriction-Bypass#userscript + require('simple-youtube-age-restriction-bypass/dist/Simple-YouTube-Age-Restriction-Bypass.user.js'); +}; diff --git a/plugins/captions-selector/back.js b/plugins/captions-selector/back.js deleted file mode 100644 index 59bb3802..00000000 --- a/plugins/captions-selector/back.js +++ /dev/null @@ -1,21 +0,0 @@ -const { ipcMain } = require("electron"); - -const prompt = require("custom-electron-prompt"); -const promptOptions = require("../../providers/prompt-options"); - -module.exports = (win) => { - ipcMain.handle("captionsSelector", async (_, captionLabels, currentIndex) => { - return await prompt( - { - title: "Choose Caption", - label: `Current Caption: ${captionLabels[currentIndex] || "None"}`, - type: "select", - value: currentIndex, - selectOptions: captionLabels, - resizable: true, - ...promptOptions(), - }, - win - ); - }); -}; diff --git a/plugins/captions-selector/back.ts b/plugins/captions-selector/back.ts new file mode 100644 index 00000000..8073ddde --- /dev/null +++ b/plugins/captions-selector/back.ts @@ -0,0 +1,19 @@ +import { BrowserWindow, ipcMain } from 'electron'; +import prompt from 'custom-electron-prompt'; + +import promptOptions from '../../providers/prompt-options'; + +export default (win: BrowserWindow) => { + ipcMain.handle('captionsSelector', async (_, captionLabels: Record, currentIndex: string) => await prompt( + { + title: 'Choose Caption', + label: `Current Caption: ${captionLabels[currentIndex] || 'None'}`, + type: 'select', + value: currentIndex, + selectOptions: captionLabels, + resizable: true, + ...promptOptions(), + }, + win, + )); +}; diff --git a/plugins/captions-selector/config.js b/plugins/captions-selector/config.js deleted file mode 100644 index 2dcd4add..00000000 --- a/plugins/captions-selector/config.js +++ /dev/null @@ -1,3 +0,0 @@ -const { PluginConfig } = require("../../config/dynamic"); -const config = new PluginConfig("captions-selector", { enableFront: true }); -module.exports = { ...config }; diff --git a/plugins/captions-selector/config.ts b/plugins/captions-selector/config.ts new file mode 100644 index 00000000..f7878eb9 --- /dev/null +++ b/plugins/captions-selector/config.ts @@ -0,0 +1,4 @@ +import { PluginConfig } from '../../config/dynamic'; + +const config = new PluginConfig('captions-selector', { enableFront: true }); +export default config; diff --git a/plugins/captions-selector/front.js b/plugins/captions-selector/front.js deleted file mode 100644 index 99cd52f0..00000000 --- a/plugins/captions-selector/front.js +++ /dev/null @@ -1,77 +0,0 @@ -const { ElementFromFile, templatePath } = require("../utils"); -const { ipcRenderer } = require("electron"); - -const configProvider = require("./config"); -let config; - -function $(selector) { return document.querySelector(selector); } - -const captionsSettingsButton = ElementFromFile( - templatePath(__dirname, "captions-settings-template.html") -); - -module.exports = async () => { - config = await configProvider.getAll(); - - configProvider.subscribeAll((newConfig) => { - config = newConfig; - }); - document.addEventListener('apiLoaded', (event) => setup(event.detail), { once: true, passive: true }); -} - -function setup(api) { - $(".right-controls-buttons").append(captionsSettingsButton); - - let captionTrackList = api.getOption("captions", "tracklist"); - - $("video").addEventListener("srcChanged", async () => { - if (config.disableCaptions) { - setTimeout(() => api.unloadModule("captions"), 100); - captionsSettingsButton.style.display = "none"; - return; - } - - api.loadModule("captions"); - - setTimeout(async () => { - captionTrackList = api.getOption("captions", "tracklist"); - - if (config.autoload && config.lastCaptionsCode) { - api.setOption("captions", "track", { - languageCode: config.lastCaptionsCode, - }); - } - - captionsSettingsButton.style.display = captionTrackList?.length - ? "inline-block" - : "none"; - }, 250); - }); - - captionsSettingsButton.onclick = async () => { - if (captionTrackList?.length) { - const currentCaptionTrack = api.getOption("captions", "track"); - let currentIndex = !currentCaptionTrack ? - null : - captionTrackList.indexOf(captionTrackList.find(track => track.languageCode === currentCaptionTrack.languageCode)); - - const captionLabels = [ - ...captionTrackList.map(track => track.displayName), - 'None' - ]; - - currentIndex = await ipcRenderer.invoke('captionsSelector', captionLabels, currentIndex) - if (currentIndex === null) return; - - const newCaptions = captionTrackList[currentIndex]; - configProvider.set('lastCaptionsCode', newCaptions?.languageCode); - if (newCaptions) { - api.setOption("captions", "track", { languageCode: newCaptions.languageCode }); - } else { - api.setOption("captions", "track", {}); - } - - setTimeout(() => api.playVideo()); - } - } -} diff --git a/plugins/captions-selector/front.ts b/plugins/captions-selector/front.ts new file mode 100644 index 00000000..bba57e0a --- /dev/null +++ b/plugins/captions-selector/front.ts @@ -0,0 +1,101 @@ +/* eslint-disable @typescript-eslint/await-thenable */ +/* renderer */ + +import { ipcRenderer } from 'electron'; + +import configProvider from './config'; + +import { ElementFromFile, templatePath } from '../utils'; +import { YoutubePlayer } from '../../types/youtube-player'; + +import type { ConfigType } from '../../config/dynamic'; + +interface LanguageOptions { + displayName: string; + id: string | null; + is_default: boolean; + is_servable: boolean; + is_translateable: boolean; + kind: string; + languageCode: string; // 2 length + languageName: string; + name: string | null; + vss_id: string; +} + +let config: ConfigType<'captions-selector'>; + +const $ = (selector: string): Element => document.querySelector(selector)!; + +const captionsSettingsButton = ElementFromFile( + templatePath(__dirname, 'captions-settings-template.html'), +); + +export default async () => { + // RENDERER + config = await configProvider.getAll(); + + configProvider.subscribeAll((newConfig) => { + config = newConfig; + }); + document.addEventListener('apiLoaded', (event) => setup(event.detail), { once: true, passive: true }); +}; + +function setup(api: YoutubePlayer) { + $('.right-controls-buttons').append(captionsSettingsButton); + + let captionTrackList = api.getOption('captions', 'tracklist') ?? []; + + $('video').addEventListener('srcChanged', () => { + if (config.disableCaptions) { + setTimeout(() => api.unloadModule('captions'), 100); + captionsSettingsButton.style.display = 'none'; + return; + } + + api.loadModule('captions'); + + setTimeout(() => { + captionTrackList = api.getOption('captions', 'tracklist') ?? []; + + if (config.autoload && config.lastCaptionsCode) { + api.setOption('captions', 'track', { + languageCode: config.lastCaptionsCode, + }); + } + + captionsSettingsButton.style.display = captionTrackList?.length + ? 'inline-block' + : 'none'; + }, 250); + }); + + captionsSettingsButton.addEventListener('click', async () => { + if (captionTrackList?.length) { + const currentCaptionTrack = api.getOption('captions', 'track')!; + let currentIndex = currentCaptionTrack + ? captionTrackList.indexOf(captionTrackList.find((track) => track.languageCode === currentCaptionTrack.languageCode)!) + : null; + + const captionLabels = [ + ...captionTrackList.map((track) => track.displayName), + 'None', + ]; + + currentIndex = await ipcRenderer.invoke('captionsSelector', captionLabels, currentIndex) as number; + if (currentIndex === null) { + return; + } + + const newCaptions = captionTrackList[currentIndex]; + configProvider.set('lastCaptionsCode', newCaptions?.languageCode); + if (newCaptions) { + api.setOption('captions', 'track', { languageCode: newCaptions.languageCode }); + } else { + api.setOption('captions', 'track', {}); + } + + setTimeout(() => api.playVideo()); + } + }); +} diff --git a/plugins/captions-selector/menu.js b/plugins/captions-selector/menu.js deleted file mode 100644 index 4b9e205f..00000000 --- a/plugins/captions-selector/menu.js +++ /dev/null @@ -1,20 +0,0 @@ -const config = require("./config"); - -module.exports = () => [ - { - label: "Automatically select last used caption", - type: "checkbox", - checked: config.get("autoload"), - click: (item) => { - config.set('autoload', item.checked); - } - }, - { - label: "No captions by default", - type: "checkbox", - checked: config.get("disabledCaptions"), - click: (item) => { - config.set('disableCaptions', item.checked); - }, - } -]; diff --git a/plugins/captions-selector/menu.ts b/plugins/captions-selector/menu.ts new file mode 100644 index 00000000..e5880cea --- /dev/null +++ b/plugins/captions-selector/menu.ts @@ -0,0 +1,22 @@ +import config from './config'; + +import { MenuTemplate } from '../../menu'; + +export default (): MenuTemplate => [ + { + label: 'Automatically select last used caption', + type: 'checkbox', + checked: config.get('autoload'), + click(item) { + config.set('autoload', item.checked); + }, + }, + { + label: 'No captions by default', + type: 'checkbox', + checked: config.get('disabledCaptions'), + click(item) { + config.set('disableCaptions', item.checked); + }, + }, +]; diff --git a/plugins/captions-selector/templates/captions-settings-template.html b/plugins/captions-selector/templates/captions-settings-template.html index 16c1b2b6..682a6cbb 100644 --- a/plugins/captions-selector/templates/captions-settings-template.html +++ b/plugins/captions-selector/templates/captions-settings-template.html @@ -1,13 +1,17 @@ - - - - - - - + + + + + + + + diff --git a/plugins/compact-sidebar/front.js b/plugins/compact-sidebar/front.js deleted file mode 100644 index a45e5f72..00000000 --- a/plugins/compact-sidebar/front.js +++ /dev/null @@ -1,10 +0,0 @@ -module.exports = () => { - const compactSidebar = document.querySelector("#mini-guide"); - const isCompactSidebarDisabled = - compactSidebar === null || - window.getComputedStyle(compactSidebar).display === "none"; - - if (isCompactSidebarDisabled) { - document.querySelector("#button").click(); - } -}; diff --git a/plugins/compact-sidebar/front.ts b/plugins/compact-sidebar/front.ts new file mode 100644 index 00000000..ad2aab97 --- /dev/null +++ b/plugins/compact-sidebar/front.ts @@ -0,0 +1,10 @@ +export default () => { + const compactSidebar = document.querySelector('#mini-guide'); + const isCompactSidebarDisabled + = compactSidebar === null + || window.getComputedStyle(compactSidebar).display === 'none'; + + if (isCompactSidebarDisabled) { + document.querySelector('#button')?.click(); + } +}; diff --git a/plugins/crossfade/back.js b/plugins/crossfade/back.js deleted file mode 100644 index 0443c95a..00000000 --- a/plugins/crossfade/back.js +++ /dev/null @@ -1,15 +0,0 @@ -const { ipcMain } = require("electron"); -const { Innertube } = require("youtubei.js"); - -require("./config"); - -module.exports = async () => { - const yt = await Innertube.create(); - - ipcMain.handle("audio-url", async (_, videoID) => { - const info = await yt.getBasicInfo(videoID); - const url = info.streaming_data?.formats[0].decipher(yt.session.player); - - return url; - }); -}; diff --git a/plugins/crossfade/back.ts b/plugins/crossfade/back.ts new file mode 100644 index 00000000..56a1355f --- /dev/null +++ b/plugins/crossfade/back.ts @@ -0,0 +1,11 @@ +import { ipcMain } from 'electron'; +import { Innertube } from 'youtubei.js'; + +export default async () => { + const yt = await Innertube.create(); + + ipcMain.handle('audio-url', async (_, videoID: string) => { + const info = await yt.getBasicInfo(videoID); + return info.streaming_data?.formats[0].decipher(yt.session.player); + }); +}; diff --git a/plugins/crossfade/config.js b/plugins/crossfade/config.js deleted file mode 100644 index 6db3c562..00000000 --- a/plugins/crossfade/config.js +++ /dev/null @@ -1,3 +0,0 @@ -const { PluginConfig } = require("../../config/dynamic"); -const config = new PluginConfig("crossfade", { enableFront: true }); -module.exports = { ...config }; diff --git a/plugins/crossfade/config.ts b/plugins/crossfade/config.ts new file mode 100644 index 00000000..ffe2232d --- /dev/null +++ b/plugins/crossfade/config.ts @@ -0,0 +1,4 @@ +import { PluginConfig } from '../../config/dynamic'; + +const config = new PluginConfig('crossfade', { enableFront: true }); +export default config; diff --git a/plugins/crossfade/fader.js b/plugins/crossfade/fader.js deleted file mode 100644 index 410bf7ad..00000000 --- a/plugins/crossfade/fader.js +++ /dev/null @@ -1,360 +0,0 @@ -/** - * VolumeFader - * Sophisticated Media Volume Fading - * - * Requires browser support for: - * - HTMLMediaElement - * - requestAnimationFrame() - * - ES6 - * - * Does not depend on any third-party library. - * - * License: MIT - * - * Nick Schwarzenberg - * v0.2.0, 07/2016 - */ - -(function (root) { - "use strict"; - - // internal utility: check if value is a valid volume level and throw if not - let validateVolumeLevel = (value) => { - // number between 0 and 1? - if (!Number.isNaN(value) && value >= 0 && value <= 1) { - // yup, that's fine - return; - } else { - // abort and throw an exception - throw new TypeError("Number between 0 and 1 expected as volume!"); - } - }; - - // main class - class VolumeFader { - /** - * VolumeFader Constructor - * - * @param media {HTMLMediaElement} - audio or video element to be controlled - * @param options {Object} - an object with optional settings - * @throws {TypeError} if options.initialVolume or options.fadeDuration are invalid - * - * options: - * .logger: {Function} logging `function(stuff, …)` for execution information (default: no logging) - * .fadeScaling: {Mixed} either 'linear', 'logarithmic' or a positive number in dB (default: logarithmic) - * .initialVolume: {Number} media volume 0…1 to apply during setup (volume not touched by default) - * .fadeDuration: {Number} time in milliseconds to complete a fade (default: 1000 ms) - */ - constructor(media, options) { - // passed media element of correct type? - if (media instanceof HTMLMediaElement) { - // save reference to media element - this.media = media; - } else { - // abort and throw an exception - throw new TypeError("Media element expected!"); - } - - // make sure options is an object - options = options || {}; - - // log function passed? - if (typeof options.logger == "function") { - // set log function to the one specified - this.logger = options.logger; - } else { - // set log function explicitly to false - this.logger = false; - } - - // linear volume fading? - if (options.fadeScaling == "linear") { - // pass levels unchanged - this.scale = { - internalToVolume: (level) => level, - volumeToInternal: (level) => level, - }; - - // log setting - this.logger && this.logger("Using linear fading."); - } - // no linear, but logarithmic fading… - else { - let dynamicRange; - - // default dynamic range? - if ( - options.fadeScaling === undefined || - options.fadeScaling == "logarithmic" - ) { - // set default of 60 dB - dynamicRange = 3; - } - // custom dynamic range? - else if ( - !Number.isNaN(options.fadeScaling) && - options.fadeScaling > 0 - ) { - // turn amplitude dB into a multiple of 10 power dB - dynamicRange = options.fadeScaling / 2 / 10; - } - // unsupported value - else { - // abort and throw exception - throw new TypeError( - "Expected 'linear', 'logarithmic' or a positive number as fade scaling preference!" - ); - } - - // use exponential/logarithmic scaler for expansion/compression - this.scale = { - internalToVolume: (level) => - this.exponentialScaler(level, dynamicRange), - volumeToInternal: (level) => - this.logarithmicScaler(level, dynamicRange), - }; - - // log setting if not default - options.fadeScaling && - this.logger && - this.logger( - "Using logarithmic fading with " + - String(10 * dynamicRange) + - " dB dynamic range." - ); - } - - // set initial volume? - if (options.initialVolume !== undefined) { - // validate volume level and throw if invalid - validateVolumeLevel(options.initialVolume); - - // set initial volume - this.media.volume = options.initialVolume; - - // log setting - this.logger && - this.logger( - "Set initial volume to " + String(this.media.volume) + "." - ); - } - - // fade duration given? - if (options.fadeDuration !== undefined) { - // try to set given fade duration (will log if successful and throw if not) - this.setFadeDuration(options.fadeDuration); - } else { - // set default fade duration (1000 ms) - this.fadeDuration = 1000; - } - - // indicate that fader is not active yet - this.active = false; - - // initialization done - this.logger && this.logger("Initialized for", this.media); - } - - /** - * Re(start) the update cycle. - * (this.active must be truthy for volume updates to take effect) - * - * @return {Object} VolumeFader instance for chaining - */ - start() { - // set fader to be active - this.active = true; - - // start by running the update method - this.updateVolume(); - - // return instance for chaining - return this; - } - - /** - * Stop the update cycle. - * (interrupting any fade) - * - * @return {Object} VolumeFader instance for chaining - */ - stop() { - // set fader to be inactive - this.active = false; - - // return instance for chaining - return this; - } - - /** - * Set fade duration. - * (used for future calls to fadeTo) - * - * @param {Number} fadeDuration - fading length in milliseconds - * @throws {TypeError} if fadeDuration is not a number greater than zero - * @return {Object} VolumeFader instance for chaining - */ - setFadeDuration(fadeDuration) { - // if duration is a valid number > 0… - if (!Number.isNaN(fadeDuration) && fadeDuration > 0) { - // set fade duration - this.fadeDuration = fadeDuration; - - // log setting - this.logger && - this.logger("Set fade duration to " + String(fadeDuration) + " ms."); - } else { - // abort and throw an exception - throw new TypeError("Positive number expected as fade duration!"); - } - - // return instance for chaining - return this; - } - - /** - * Define a new fade and start fading. - * - * @param {Number} targetVolume - level to fade to in the range 0…1 - * @param {Function} callback - (optional) function to be called when fade is complete - * @throws {TypeError} if targetVolume is not in the range 0…1 - * @return {Object} VolumeFader instance for chaining - */ - fadeTo(targetVolume, callback) { - // validate volume and throw if invalid - validateVolumeLevel(targetVolume); - - // define new fade - this.fade = { - // volume start and end point on internal fading scale - volume: { - start: this.scale.volumeToInternal(this.media.volume), - end: this.scale.volumeToInternal(targetVolume), - }, - // time start and end point - time: { - start: Date.now(), - end: Date.now() + this.fadeDuration, - }, - // optional callback function - callback: callback, - }; - - // start fading - this.start(); - - // log new fade - this.logger && this.logger("New fade started:", this.fade); - - // return instance for chaining - return this; - } - - // convenience shorthand methods for common fades - fadeIn(callback) { - this.fadeTo(1, callback); - } - fadeOut(callback) { - this.fadeTo(0, callback); - } - - /** - * Internal: Update media volume. - * (calls itself through requestAnimationFrame) - * - * @param {Number} targetVolume - linear level to fade to (0…1) - * @param {Function} callback - (optional) function to be called when fade is complete - */ - updateVolume() { - // fader active and fade available to process? - if (this.active && this.fade) { - // get current time - let now = Date.now(); - - // time left for fading? - if (now < this.fade.time.end) { - // compute current fade progress - let progress = - (now - this.fade.time.start) / - (this.fade.time.end - this.fade.time.start); - - // compute current level on internal scale - let level = - progress * (this.fade.volume.end - this.fade.volume.start) + - this.fade.volume.start; - - // map fade level to volume level and apply it to media element - this.media.volume = this.scale.internalToVolume(level); - - // schedule next update - root.requestAnimationFrame(this.updateVolume.bind(this)); - } else { - // log end of fade - this.logger && - this.logger( - "Fade to " + String(this.fade.volume.end) + " complete." - ); - - // time is up, jump to target volume - this.media.volume = this.scale.internalToVolume(this.fade.volume.end); - - // set fader to be inactive - this.active = false; - - // done, call back (if callable) - typeof this.fade.callback == "function" && this.fade.callback(); - - // clear fade - this.fade = undefined; - } - } - } - - /** - * Internal: Exponential scaler with dynamic range limit. - * - * @param {Number} input - logarithmic input level to be expanded (float, 0…1) - * @param {Number} dynamicRange - expanded output range, in multiples of 10 dB (float, 0…∞) - * @return {Number} - expanded level (float, 0…1) - */ - exponentialScaler(input, dynamicRange) { - // special case: make zero (or any falsy input) return zero - if (input == 0) { - // since the dynamic range is limited, - // allow a zero to produce a plain zero instead of a small faction - // (audio would not be recognized as silent otherwise) - return 0; - } else { - // scale 0…1 to minus something × 10 dB - input = (input - 1) * dynamicRange; - - // compute power of 10 - return Math.pow(10, input); - } - } - - /** - * Internal: Logarithmic scaler with dynamic range limit. - * - * @param {Number} input - exponential input level to be compressed (float, 0…1) - * @param {Number} dynamicRange - coerced input range, in multiples of 10 dB (float, 0…∞) - * @return {Number} - compressed level (float, 0…1) - */ - logarithmicScaler(input, dynamicRange) { - // special case: make zero (or any falsy input) return zero - if (input == 0) { - // logarithm of zero would be -∞, which would map to zero anyway - return 0; - } else { - // compute base-10 logarithm - input = Math.log10(input); - - // scale minus something × 10 dB to 0…1 (clipping at 0) - return Math.max(1 + input / dynamicRange, 0); - } - } - } - - // export class to root scope - root.VolumeFader = VolumeFader; -})(window); diff --git a/plugins/crossfade/fader.ts b/plugins/crossfade/fader.ts new file mode 100644 index 00000000..c9442ba0 --- /dev/null +++ b/plugins/crossfade/fader.ts @@ -0,0 +1,395 @@ +/** + * VolumeFader + * Sophisticated Media Volume Fading + * + * Requires browser support for: + * - HTMLMediaElement + * - requestAnimationFrame() + * - ES6 + * + * Does not depend on any third-party library. + * + * License: MIT + * + * Nick Schwarzenberg + * v0.2.0, 07/2016 + */ + +'use strict'; + +// Internal utility: check if value is a valid volume level and throw if not +const validateVolumeLevel = (value: number) => { + // Number between 0 and 1? + if (!Number.isNaN(value) && value >= 0 && value <= 1) { + // Yup, that's fine + + } else { + // Abort and throw an exception + throw new TypeError('Number between 0 and 1 expected as volume!'); + } +}; + +type VolumeLogger = (message: string, ...args: Params) => void; +interface VolumeFaderOptions { + /** + * logging `function(stuff, …)` for execution information (default: no logging) + */ + logger?: VolumeLogger; + /** + * either 'linear', 'logarithmic' or a positive number in dB (default: logarithmic) + */ + fadeScaling?: string | number; + /** + * media volume 0…1 to apply during setup (volume not touched by default) + */ + initialVolume?: number; + /** + * time in milliseconds to complete a fade (default: 1000 ms) + */ + fadeDuration?: number; +} + +interface VolumeFade { + volume: { + start: number; + end: number; + }; + time: { + start: number; + end: number; + }; + callback?: () => void; +} + +// Main class +export class VolumeFader { + private readonly media: HTMLMediaElement; + private readonly logger: VolumeLogger | false; + private scale: { + internalToVolume: (level: number) => number; + volumeToInternal: (level: number) => number; + }; + private fadeDuration: number = 1000; + private active: boolean = false; + private fade: VolumeFade | undefined; + + + /** + * VolumeFader Constructor + * + * @param media {HTMLMediaElement} - audio or video element to be controlled + * @param options {Object} - an object with optional settings + * @throws {TypeError} if options.initialVolume or options.fadeDuration are invalid + * + */ + constructor(media: HTMLMediaElement, options: VolumeFaderOptions) { + // Passed media element of correct type? + if (media instanceof HTMLMediaElement) { + // Save reference to media element + this.media = media; + } else { + // Abort and throw an exception + throw new TypeError('Media element expected!'); + } + + // Make sure options is an object + options = options || {}; + + // Log function passed? + if (typeof options.logger === 'function') { + // Set log function to the one specified + this.logger = options.logger; + } else { + // Set log function explicitly to false + this.logger = false; + } + + // Linear volume fading? + if (options.fadeScaling === 'linear') { + // Pass levels unchanged + this.scale = { + internalToVolume: (level: number) => level, + volumeToInternal: (level: number) => level, + }; + + // Log setting + this.logger && this.logger('Using linear fading.'); + } + // No linear, but logarithmic fading… + else { + let dynamicRange: number; + + // Default dynamic range? + if ( + options.fadeScaling === undefined + || options.fadeScaling === 'logarithmic' + ) { + // Set default of 60 dB + dynamicRange = 3; + } + // Custom dynamic range? + else if ( + typeof options.fadeScaling === 'number' + && !Number.isNaN(options.fadeScaling) + && options.fadeScaling > 0 + ) { + // Turn amplitude dB into a multiple of 10 power dB + dynamicRange = options.fadeScaling / 2 / 10; + } + // Unsupported value + else { + // Abort and throw exception + throw new TypeError( + "Expected 'linear', 'logarithmic' or a positive number as fade scaling preference!", + ); + } + + // Use exponential/logarithmic scaler for expansion/compression + this.scale = { + internalToVolume: (level: number) => + this.exponentialScaler(level, dynamicRange), + volumeToInternal: (level: number) => + this.logarithmicScaler(level, dynamicRange), + }; + + // Log setting if not default + options.fadeScaling + && this.logger + && this.logger( + 'Using logarithmic fading with ' + + String(10 * dynamicRange) + + ' dB dynamic range.', + ); + } + + // Set initial volume? + if (options.initialVolume !== undefined) { + // Validate volume level and throw if invalid + validateVolumeLevel(options.initialVolume); + + // Set initial volume + this.media.volume = options.initialVolume; + + // Log setting + this.logger + && this.logger( + 'Set initial volume to ' + String(this.media.volume) + '.', + ); + } + + // Fade duration given? + if (options.fadeDuration === undefined) { + // Set default fade duration (1000 ms) + this.fadeDuration = 1000; + } else { + // Try to set given fade duration (will log if successful and throw if not) + this.setFadeDuration(options.fadeDuration); + } + + // Indicate that fader is not active yet + this.active = false; + + // Initialization done + this.logger && this.logger('Initialized for', this.media); + } + + /** + * Re(start) the update cycle. + * (this.active must be truthy for volume updates to take effect) + * + * @return {Object} VolumeFader instance for chaining + */ + start() { + // Set fader to be active + this.active = true; + + // Start by running the update method + this.updateVolume(); + + // Return instance for chaining + return this; + } + + /** + * Stop the update cycle. + * (interrupting any fade) + * + * @return {Object} VolumeFader instance for chaining + */ + stop() { + // Set fader to be inactive + this.active = false; + + // Return instance for chaining + return this; + } + + /** + * Set fade duration. + * (used for future calls to fadeTo) + * + * @param {Number} fadeDuration - fading length in milliseconds + * @throws {TypeError} if fadeDuration is not a number greater than zero + * @return {Object} VolumeFader instance for chaining + */ + setFadeDuration(fadeDuration: number) { + // If duration is a valid number > 0… + if (!Number.isNaN(fadeDuration) && fadeDuration > 0) { + // Set fade duration + this.fadeDuration = fadeDuration; + + // Log setting + this.logger + && this.logger('Set fade duration to ' + String(fadeDuration) + ' ms.'); + } else { + // Abort and throw an exception + throw new TypeError('Positive number expected as fade duration!'); + } + + // Return instance for chaining + return this; + } + + /** + * Define a new fade and start fading. + * + * @param {Number} targetVolume - level to fade to in the range 0…1 + * @param {Function} callback - (optional) function to be called when fade is complete + * @throws {TypeError} if targetVolume is not in the range 0…1 + * @return {Object} VolumeFader instance for chaining + */ + fadeTo(targetVolume: number, callback?: () => void) { + // Validate volume and throw if invalid + validateVolumeLevel(targetVolume); + + // Define new fade + this.fade = { + // Volume start and end point on internal fading scale + volume: { + start: this.scale.volumeToInternal(this.media.volume), + end: this.scale.volumeToInternal(targetVolume), + }, + // Time start and end point + time: { + start: Date.now(), + end: Date.now() + this.fadeDuration, + }, + // Optional callback function + callback, + }; + + // Start fading + this.start(); + + // Log new fade + this.logger && this.logger('New fade started:', this.fade); + + // Return instance for chaining + return this; + } + + // Convenience shorthand methods for common fades + fadeIn(callback: () => void) { + this.fadeTo(1, callback); + } + + fadeOut(callback: () => void) { + this.fadeTo(0, callback); + } + + /** + * Internal: Update media volume. + * (calls itself through requestAnimationFrame) + */ + updateVolume() { + // Fader active and fade available to process? + if (this.active && this.fade) { + // Get current time + const now = Date.now(); + + // Time left for fading? + if (now < this.fade.time.end) { + // Compute current fade progress + const progress + = (now - this.fade.time.start) + / (this.fade.time.end - this.fade.time.start); + + // Compute current level on internal scale + const level + = (progress * (this.fade.volume.end - this.fade.volume.start)) + this.fade.volume.start; + + // Map fade level to volume level and apply it to media element + this.media.volume = this.scale.internalToVolume(level); + + // Schedule next update + window.requestAnimationFrame(this.updateVolume.bind(this)); + } else { + // Log end of fade + this.logger + && this.logger( + 'Fade to ' + String(this.fade.volume.end) + ' complete.', + ); + + // Time is up, jump to target volume + this.media.volume = this.scale.internalToVolume(this.fade.volume.end); + + // Set fader to be inactive + this.active = false; + + // Done, call back (if callable) + typeof this.fade.callback === 'function' && this.fade.callback(); + + // Clear fade + this.fade = undefined; + } + } + } + + /** + * Internal: Exponential scaler with dynamic range limit. + * + * @param {Number} input - logarithmic input level to be expanded (float, 0…1) + * @param {Number} dynamicRange - expanded output range, in multiples of 10 dB (float, 0…∞) + * @return {Number} - expanded level (float, 0…1) + */ + exponentialScaler(input: number, dynamicRange: number) { + // Special case: make zero (or any falsy input) return zero + if (input === 0) { + // Since the dynamic range is limited, + // allow a zero to produce a plain zero instead of a small faction + // (audio would not be recognized as silent otherwise) + return 0; + } + + // Scale 0…1 to minus something × 10 dB + input = (input - 1) * dynamicRange; + + // Compute power of 10 + return 10 ** input; + } + + /** + * Internal: Logarithmic scaler with dynamic range limit. + * + * @param {Number} input - exponential input level to be compressed (float, 0…1) + * @param {Number} dynamicRange - coerced input range, in multiples of 10 dB (float, 0…∞) + * @return {Number} - compressed level (float, 0…1) + */ + logarithmicScaler(input: number, dynamicRange: number) { + // Special case: make zero (or any falsy input) return zero + if (input === 0) { + // Logarithm of zero would be -∞, which would map to zero anyway + return 0; + } + + // Compute base-10 logarithm + input = Math.log10(input); + + // Scale minus something × 10 dB to 0…1 (clipping at 0) + return Math.max(1 + (input / dynamicRange), 0); + } +} + +export default { + VolumeFader +}; diff --git a/plugins/crossfade/front.js b/plugins/crossfade/front.js deleted file mode 100644 index 4107619f..00000000 --- a/plugins/crossfade/front.js +++ /dev/null @@ -1,158 +0,0 @@ -const { ipcRenderer } = require("electron"); -const { Howl } = require("howler"); - -// Extracted from https://github.com/bitfasching/VolumeFader -require("./fader"); - -let transitionAudio; // Howler audio used to fade out the current music -let firstVideo = true; -let waitForTransition; - -const defaultConfig = require("../../config/defaults").plugins.crossfade; - -const configProvider = require("./config"); -let config; - -const configGetNum = (key) => Number(config[key]) || defaultConfig[key]; - -const getStreamURL = async (videoID) => { - const url = await ipcRenderer.invoke("audio-url", videoID); - return url; -}; - -const getVideoIDFromURL = (url) => { - return new URLSearchParams(url.split("?")?.at(-1)).get("v"); -}; - -const isReadyToCrossfade = () => { - return transitionAudio && transitionAudio.state() === "loaded"; -}; - -const watchVideoIDChanges = (cb) => { - navigation.addEventListener("navigate", (event) => { - const currentVideoID = getVideoIDFromURL( - event.currentTarget.currentEntry.url, - ); - const nextVideoID = getVideoIDFromURL(event.destination.url); - - if ( - nextVideoID && - currentVideoID && - (firstVideo || nextVideoID !== currentVideoID) - ) { - if (isReadyToCrossfade()) { - crossfade(() => { - cb(nextVideoID); - }); - } else { - cb(nextVideoID); - firstVideo = false; - } - } - }); -}; - -const createAudioForCrossfade = async (url) => { - if (transitionAudio) { - transitionAudio.unload(); - } - transitionAudio = new Howl({ - src: url, - html5: true, - volume: 0, - }); - await syncVideoWithTransitionAudio(); -}; - -const syncVideoWithTransitionAudio = async () => { - const video = document.querySelector("video"); - - const videoFader = new VolumeFader(video, { - fadeScaling: configGetNum("fadeScaling"), - fadeDuration: configGetNum("fadeInDuration"), - }); - - await transitionAudio.play(); - await transitionAudio.seek(video.currentTime); - - video.onseeking = () => { - transitionAudio.seek(video.currentTime); - }; - video.onpause = () => { - transitionAudio.pause(); - }; - video.onplay = async () => { - await transitionAudio.play(); - await transitionAudio.seek(video.currentTime); - - // Fade in - const videoVolume = video.volume; - video.volume = 0; - videoFader.fadeTo(videoVolume); - }; - - // Exit just before the end for the transition - const transitionBeforeEnd = () => { - if ( - video.currentTime >= video.duration - configGetNum("secondsBeforeEnd") && - isReadyToCrossfade() - ) { - video.removeEventListener("timeupdate", transitionBeforeEnd); - - // Go to next video - XXX: does not support "repeat 1" mode - document.querySelector(".next-button").click(); - } - }; - video.ontimeupdate = transitionBeforeEnd; -}; - -const onApiLoaded = () => { - watchVideoIDChanges(async (videoID) => { - await waitForTransition; - const url = await getStreamURL(videoID); - if (!url) { - return; - } - await createAudioForCrossfade(url); - }); -}; - -const crossfade = async (cb) => { - if (!isReadyToCrossfade()) { - cb(); - return; - } - - let resolveTransition; - waitForTransition = new Promise(function (resolve, reject) { - resolveTransition = resolve; - }); - - const video = document.querySelector("video"); - - const fader = new VolumeFader(transitionAudio._sounds[0]._node, { - initialVolume: video.volume, - fadeScaling: configGetNum("fadeScaling"), - fadeDuration: configGetNum("fadeOutDuration"), - }); - - // Fade out the music - video.volume = 0; - fader.fadeOut(() => { - resolveTransition(); - cb(); - }); -}; - -module.exports = async () => { - config = await configProvider.getAll(); - - configProvider.subscribeAll((newConfig) => { - config = newConfig; - }); - - document.addEventListener("apiLoaded", onApiLoaded, { - once: true, - passive: true, - }); -}; diff --git a/plugins/crossfade/front.ts b/plugins/crossfade/front.ts new file mode 100644 index 00000000..a38cd713 --- /dev/null +++ b/plugins/crossfade/front.ts @@ -0,0 +1,164 @@ +/* eslint-disable @typescript-eslint/await-thenable */ +/* renderer */ + +import { ipcRenderer } from 'electron'; +import { Howl } from 'howler'; + +// Extracted from https://github.com/bitfasching/VolumeFader +import { VolumeFader } from './fader'; + +import configProvider from './config'; + +import defaultConfigs from '../../config/defaults'; + +import type { ConfigType } from '../../config/dynamic'; + +let transitionAudio: Howl; // Howler audio used to fade out the current music +let firstVideo = true; +let waitForTransition: Promise; + +const defaultConfig = defaultConfigs.plugins.crossfade; + +let config: ConfigType<'crossfade'>; + +const configGetNumber = (key: keyof ConfigType<'crossfade'>): number => Number(config[key]) || (defaultConfig[key] as number); + +const getStreamURL = async (videoID: string) => ipcRenderer.invoke('audio-url', videoID) as Promise; + +const getVideoIDFromURL = (url: string) => new URLSearchParams(url.split('?')?.at(-1)).get('v'); + +const isReadyToCrossfade = () => transitionAudio && transitionAudio.state() === 'loaded'; + +const watchVideoIDChanges = (cb: (id: string) => void) => { + window.navigation.addEventListener('navigate', (event) => { + const currentVideoID = getVideoIDFromURL( + (event.currentTarget as Navigation).currentEntry?.url ?? '', + ); + const nextVideoID = getVideoIDFromURL(event.destination.url ?? ''); + + if ( + nextVideoID + && currentVideoID + && (firstVideo || nextVideoID !== currentVideoID) + ) { + if (isReadyToCrossfade()) { + crossfade(() => { + cb(nextVideoID); + }); + } else { + cb(nextVideoID); + firstVideo = false; + } + } + }); +}; + +const createAudioForCrossfade = (url: string) => { + if (transitionAudio) { + transitionAudio.unload(); + } + + transitionAudio = new Howl({ + src: url, + html5: true, + volume: 0, + }); + syncVideoWithTransitionAudio(); +}; + +const syncVideoWithTransitionAudio = () => { + const video = document.querySelector('video')!; + + const videoFader = new VolumeFader(video, { + fadeScaling: configGetNumber('fadeScaling'), + fadeDuration: configGetNumber('fadeInDuration'), + }); + + transitionAudio.play(); + transitionAudio.seek(video.currentTime); + + video.addEventListener('seeking', () => { + transitionAudio.seek(video.currentTime); + }); + + video.addEventListener('pause', () => { + transitionAudio.pause(); + }); + + video.addEventListener('play', () => { + transitionAudio.play(); + transitionAudio.seek(video.currentTime); + + // Fade in + const videoVolume = video.volume; + video.volume = 0; + videoFader.fadeTo(videoVolume); + }); + + // Exit just before the end for the transition + const transitionBeforeEnd = () => { + if ( + video.currentTime >= video.duration - configGetNumber('secondsBeforeEnd') + && isReadyToCrossfade() + ) { + video.removeEventListener('timeupdate', transitionBeforeEnd); + + // Go to next video - XXX: does not support "repeat 1" mode + document.querySelector('.next-button')?.click(); + } + }; + + video.addEventListener('timeupdate', transitionBeforeEnd); +}; + +const onApiLoaded = () => { + watchVideoIDChanges(async (videoID) => { + await waitForTransition; + const url = await getStreamURL(videoID); + if (!url) { + return; + } + + await createAudioForCrossfade(url); + }); +}; + +const crossfade = (cb: () => void) => { + if (!isReadyToCrossfade()) { + cb(); + return; + } + + let resolveTransition: () => void; + waitForTransition = new Promise((resolve) => { + resolveTransition = resolve; + }); + + const video = document.querySelector('video')!; + + const fader = new VolumeFader(transitionAudio._sounds[0]._node, { + initialVolume: video.volume, + fadeScaling: configGetNumber('fadeScaling'), + fadeDuration: configGetNumber('fadeOutDuration'), + }); + + // Fade out the music + video.volume = 0; + fader.fadeOut(() => { + resolveTransition(); + cb(); + }); +}; + +export default async () => { + config = await configProvider.getAll(); + + configProvider.subscribeAll((newConfig) => { + config = newConfig; + }); + + document.addEventListener('apiLoaded', onApiLoaded, { + once: true, + passive: true, + }); +}; diff --git a/plugins/crossfade/menu.js b/plugins/crossfade/menu.js deleted file mode 100644 index 5ee728c7..00000000 --- a/plugins/crossfade/menu.js +++ /dev/null @@ -1,72 +0,0 @@ -const config = require("./config"); -const defaultOptions = require("../../config/defaults").plugins.crossfade; - -const prompt = require("custom-electron-prompt"); -const promptOptions = require("../../providers/prompt-options"); - -module.exports = (win) => [ - { - label: "Advanced", - click: async () => { - const newOptions = await promptCrossfadeValues(win, config.getAll()); - if (newOptions) config.setAll(newOptions); - }, - }, -]; - -async function promptCrossfadeValues(win, options) { - const res = await prompt( - { - title: "Crossfade Options", - type: "multiInput", - multiInputOptions: [ - { - label: "Fade in duration (ms)", - value: options.fadeInDuration || defaultOptions.fadeInDuration, - inputAttrs: { - type: "number", - required: true, - min: 0, - step: 100, - }, - }, - { - label: "Fade out duration (ms)", - value: options.fadeOutDuration || defaultOptions.fadeOutDuration, - inputAttrs: { - type: "number", - required: true, - min: 0, - step: 100, - }, - }, - { - label: "Crossfade x seconds before end", - value: - options.secondsBeforeEnd || defaultOptions.secondsBeforeEnd, - inputAttrs: { - type: "number", - required: true, - min: 0, - }, - }, - { - label: "Fade scaling", - selectOptions: { linear: "Linear", logarithmic: "Logarithmic" }, - value: options.fadeScaling || defaultOptions.fadeScaling, - }, - ], - resizable: true, - height: 360, - ...promptOptions(), - }, - win, - ).catch(console.error); - if (!res) return undefined; - return { - fadeInDuration: Number(res[0]), - fadeOutDuration: Number(res[1]), - secondsBeforeEnd: Number(res[2]), - fadeScaling: res[3], - }; -} diff --git a/plugins/crossfade/menu.ts b/plugins/crossfade/menu.ts new file mode 100644 index 00000000..fbfa4f0b --- /dev/null +++ b/plugins/crossfade/menu.ts @@ -0,0 +1,84 @@ +import prompt from 'custom-electron-prompt'; + +import { BrowserWindow } from 'electron'; + +import config from './config'; + +import promptOptions from '../../providers/prompt-options'; +import configOptions from '../../config/defaults'; + +import type { ConfigType } from '../../config/dynamic'; + +const defaultOptions = configOptions.plugins.crossfade; + +export default (win: BrowserWindow) => [ + { + label: 'Advanced', + async click() { + const newOptions = await promptCrossfadeValues(win, config.getAll()); + if (newOptions) { + config.setAll(newOptions); + } + }, + }, +]; + +async function promptCrossfadeValues(win: BrowserWindow, options: ConfigType<'crossfade'>): Promise> | undefined> { + const res = await prompt( + { + title: 'Crossfade Options', + type: 'multiInput', + multiInputOptions: [ + { + label: 'Fade in duration (ms)', + value: options.fadeInDuration || defaultOptions.fadeInDuration, + inputAttrs: { + type: 'number', + required: true, + min: '0', + step: '100', + }, + }, + { + label: 'Fade out duration (ms)', + value: options.fadeOutDuration || defaultOptions.fadeOutDuration, + inputAttrs: { + type: 'number', + required: true, + min: '0', + step: '100', + }, + }, + { + label: 'Crossfade x seconds before end', + value: + options.secondsBeforeEnd || defaultOptions.secondsBeforeEnd, + inputAttrs: { + type: 'number', + required: true, + min: '0', + }, + }, + { + label: 'Fade scaling', + selectOptions: { linear: 'Linear', logarithmic: 'Logarithmic' }, + value: options.fadeScaling || defaultOptions.fadeScaling, + }, + ], + resizable: true, + height: 360, + ...promptOptions(), + }, + win, + ).catch(console.error); + if (!res) { + return undefined; + } + + return { + fadeInDuration: Number(res[0]), + fadeOutDuration: Number(res[1]), + secondsBeforeEnd: Number(res[2]), + fadeScaling: res[3], + }; +} diff --git a/plugins/disable-autoplay/front.js b/plugins/disable-autoplay/front.js deleted file mode 100644 index c34a453a..00000000 --- a/plugins/disable-autoplay/front.js +++ /dev/null @@ -1,14 +0,0 @@ -module.exports = () => { - document.addEventListener('apiLoaded', apiEvent => { - apiEvent.detail.addEventListener('videodatachange', name => { - if (name === 'dataloaded') { - apiEvent.detail.pauseVideo(); - document.querySelector('video').ontimeupdate = e => { - e.target.pause(); - } - } else { - document.querySelector('video').ontimeupdate = null; - } - }) - }, { once: true, passive: true }) -}; diff --git a/plugins/disable-autoplay/front.ts b/plugins/disable-autoplay/front.ts new file mode 100644 index 00000000..176c6bcf --- /dev/null +++ b/plugins/disable-autoplay/front.ts @@ -0,0 +1,18 @@ +export default () => { + const timeUpdateListener = (e: Event) => { + if (e.target instanceof HTMLVideoElement) { + e.target.pause(); + } + }; + + document.addEventListener('apiLoaded', (apiEvent) => { + apiEvent.detail.addEventListener('videodatachange', (name: string) => { + if (name === 'dataloaded') { + apiEvent.detail.pauseVideo(); + document.querySelector('video')?.addEventListener('timeupdate', timeUpdateListener); + } else { + document.querySelector('video')?.removeEventListener('timeupdate', timeUpdateListener); + } + }); + }, { once: true, passive: true }); +}; diff --git a/plugins/discord/back.js b/plugins/discord/back.js deleted file mode 100644 index a8a75986..00000000 --- a/plugins/discord/back.js +++ /dev/null @@ -1,171 +0,0 @@ -"use strict"; -const Discord = require("@xhayper/discord-rpc"); -const { dev } = require("electron-is"); -const { dialog, app } = require("electron"); - -const registerCallback = require("../../providers/song-info"); - -// Application ID registered by @Zo-Bro-23 -const clientId = "1043858434585526382"; - -/** - * @typedef {Object} Info - * @property {import('@xhayper/discord-rpc').Client} rpc - * @property {boolean} ready - * @property {boolean} autoReconnect - * @property {import('../../providers/song-info').SongInfo} lastSongInfo - */ -/** - * @type {Info} - */ -const info = { - rpc: new Discord.Client({ - clientId - }), - ready: false, - autoReconnect: true, - lastSongInfo: null, -}; - -/** - * @type {(() => void)[]} - */ -const refreshCallbacks = []; - -const resetInfo = () => { - info.ready = false; - clearTimeout(clearActivity); - if (dev()) console.log("discord disconnected"); - refreshCallbacks.forEach(cb => cb()); -}; - -info.rpc.on("connected", () => { - if (dev()) console.log("discord connected"); - refreshCallbacks.forEach(cb => cb()); -}); - -info.rpc.on("ready", () => { - info.ready = true; - if (info.lastSongInfo) updateActivity(info.lastSongInfo) -}); - -info.rpc.on("disconnected", () => { - resetInfo(); - - if (info.autoReconnect) { - connectTimeout(); - } -}); - -const connectTimeout = () => new Promise((resolve, reject) => setTimeout(() => { - if (!info.autoReconnect || info.rpc.isConnected) return; - info.rpc.login().then(resolve).catch(reject); -}, 5000)); - -const connectRecursive = () => { - if (!info.autoReconnect || info.rpc.isConnected) return; - connectTimeout().catch(connectRecursive); -} - -let window; -const connect = (showErr = false) => { - if (info.rpc.isConnected) { - if (dev()) - console.log('Attempted to connect with active connection'); - return; - } - - info.ready = false; - - // Startup the rpc client - info.rpc.login({ clientId }).catch(err => { - resetInfo(); - if (dev()) console.error(err); - if (info.autoReconnect) { - connectRecursive(); - } - else if (showErr) dialog.showMessageBox(window, { title: 'Connection failed', message: err.message || String(err), type: 'error' }); - }); -}; - -let clearActivity; -/** - * @type {import('../../providers/song-info').songInfoCallback} - */ -let updateActivity; - -module.exports = (win, { autoReconnect, activityTimoutEnabled, activityTimoutTime, listenAlong, hideDurationLeft }) => { - info.autoReconnect = autoReconnect; - - window = win; - // We get multiple events - // Next song: PAUSE(n), PAUSE(n+1), PLAY(n+1) - // Skip time: PAUSE(N), PLAY(N) - updateActivity = songInfo => { - if (songInfo.title.length === 0 && songInfo.artist.length === 0) { - return; - } - info.lastSongInfo = songInfo; - - // stop the clear activity timout - clearTimeout(clearActivity); - - // stop early if discord connection is not ready - // do this after clearTimeout to avoid unexpected clears - if (!info.rpc || !info.ready) { - return; - } - - // clear directly if timeout is 0 - if (songInfo.isPaused && activityTimoutEnabled && activityTimoutTime === 0) { - info.rpc.user?.clearActivity().catch(console.error); - return; - } - - // Song information changed, so lets update the rich presence - // @see https://discord.com/developers/docs/topics/gateway#activity-object - // not all options are transfered through https://github.com/discordjs/RPC/blob/6f83d8d812c87cb7ae22064acd132600407d7d05/src/client.js#L518-530 - const activityInfo = { - details: songInfo.title, - state: songInfo.artist, - largeImageKey: songInfo.imageSrc, - largeImageText: songInfo.album, - buttons: listenAlong ? [ - { label: "Listen Along", url: songInfo.url }, - ] : undefined, - }; - - if (songInfo.isPaused) { - // Add a paused icon to show that the song is paused - activityInfo.smallImageKey = "paused"; - activityInfo.smallImageText = "Paused"; - // Set start the timer so the activity gets cleared after a while if enabled - if (activityTimoutEnabled) - clearActivity = setTimeout(() => info.rpc.user?.clearActivity().catch(console.error), activityTimoutTime ?? 10000); - } else if (!hideDurationLeft) { - // Add the start and end time of the song - const songStartTime = Date.now() - songInfo.elapsedSeconds * 1000; - activityInfo.startTimestamp = songStartTime; - activityInfo.endTimestamp = - songStartTime + songInfo.songDuration * 1000; - } - - info.rpc.user?.setActivity(activityInfo).catch(console.error); - }; - - // If the page is ready, register the callback - win.once("ready-to-show", () => { - registerCallback(updateActivity); - connect(); - }); - app.on('window-all-closed', module.exports.clear) -}; - -module.exports.clear = () => { - if (info.rpc) info.rpc.user?.clearActivity(); - clearTimeout(clearActivity); -}; - -module.exports.connect = connect; -module.exports.registerRefresh = (cb) => refreshCallbacks.push(cb); -module.exports.isConnected = () => info.rpc !== null; diff --git a/plugins/discord/back.ts b/plugins/discord/back.ts new file mode 100644 index 00000000..35947c00 --- /dev/null +++ b/plugins/discord/back.ts @@ -0,0 +1,205 @@ +import { app, dialog } from 'electron'; +import { Client as DiscordClient } from '@xhayper/discord-rpc'; +import { dev } from 'electron-is'; + +import { SetActivity } from '@xhayper/discord-rpc/dist/structures/ClientUser'; + +import registerCallback from '../../providers/song-info'; + +import type { ConfigType } from '../../config/dynamic'; + +// Application ID registered by @Zo-Bro-23 +const clientId = '1043858434585526382'; + +export interface Info { + rpc: DiscordClient; + ready: boolean; + autoReconnect: boolean; + lastSongInfo?: import('../../providers/song-info').SongInfo; +} + +const info: Info = { + rpc: new DiscordClient({ + clientId, + }), + ready: false, + autoReconnect: true, + lastSongInfo: undefined, +}; + +/** + * @type {(() => void)[]} + */ +const refreshCallbacks: (() => void)[] = []; + +const resetInfo = () => { + info.ready = false; + clearTimeout(clearActivity); + if (dev()) { + console.log('discord disconnected'); + } + + for (const cb of refreshCallbacks) { + cb(); + } +}; + +info.rpc.on('connected', () => { + if (dev()) { + console.log('discord connected'); + } + + for (const cb of refreshCallbacks) { + cb(); + } +}); + +info.rpc.on('ready', () => { + info.ready = true; + if (info.lastSongInfo) { + updateActivity(info.lastSongInfo); + } +}); + +info.rpc.on('disconnected', () => { + resetInfo(); + + if (info.autoReconnect) { + connectTimeout(); + } +}); + +const connectTimeout = () => new Promise((resolve, reject) => setTimeout(() => { + if (!info.autoReconnect || info.rpc.isConnected) { + return; + } + + info.rpc.login().then(resolve).catch(reject); +}, 5000)); + +const connectRecursive = () => { + if (!info.autoReconnect || info.rpc.isConnected) { + return; + } + + connectTimeout().catch(connectRecursive); +}; + +let window: Electron.BrowserWindow; +export const connect = (showError = false) => { + if (info.rpc.isConnected) { + if (dev()) { + console.log('Attempted to connect with active connection'); + } + + return; + } + + info.ready = false; + + // Startup the rpc client + info.rpc.login().catch((error: Error) => { + resetInfo(); + if (dev()) { + console.error(error); + } + + if (info.autoReconnect) { + connectRecursive(); + } else if (showError) { + dialog.showMessageBox(window, { + title: 'Connection failed', + message: error.message || String(error), + type: 'error', + }); + } + }); +}; + +let clearActivity: NodeJS.Timeout | undefined; +let updateActivity: import('../../providers/song-info').SongInfoCallback; + +type DiscordOptions = ConfigType<'discord'>; + +export default ( + win: Electron.BrowserWindow, + options: DiscordOptions, +) => { + info.autoReconnect = options.autoReconnect; + + window = win; + // We get multiple events + // Next song: PAUSE(n), PAUSE(n+1), PLAY(n+1) + // Skip time: PAUSE(N), PLAY(N) + updateActivity = (songInfo) => { + if (songInfo.title.length === 0 && songInfo.artist.length === 0) { + return; + } + + info.lastSongInfo = songInfo; + + // Stop the clear activity timout + clearTimeout(clearActivity); + + // Stop early if discord connection is not ready + // do this after clearTimeout to avoid unexpected clears + if (!info.rpc || !info.ready) { + return; + } + + // Clear directly if timeout is 0 + if (songInfo.isPaused && options.activityTimoutEnabled && options.activityTimoutTime === 0) { + info.rpc.user?.clearActivity().catch(console.error); + return; + } + + // Song information changed, so lets update the rich presence + // @see https://discord.com/developers/docs/topics/gateway#activity-object + // not all options are transfered through https://github.com/discordjs/RPC/blob/6f83d8d812c87cb7ae22064acd132600407d7d05/src/client.js#L518-530 + const activityInfo: SetActivity = { + details: songInfo.title, + state: songInfo.artist, + largeImageKey: songInfo.imageSrc ?? '', + largeImageText: songInfo.album ?? '', + buttons: options.listenAlong ? [ + { label: 'Listen Along', url: songInfo.url ?? '' }, + ] : undefined, + }; + + if (songInfo.isPaused) { + // Add a paused icon to show that the song is paused + activityInfo.smallImageKey = 'paused'; + activityInfo.smallImageText = 'Paused'; + // Set start the timer so the activity gets cleared after a while if enabled + if (options.activityTimoutEnabled) { + clearActivity = setTimeout(() => info.rpc.user?.clearActivity().catch(console.error), options.activityTimoutTime ?? 10_000); + } + } else if (!options.hideDurationLeft) { + // Add the start and end time of the song + const songStartTime = Date.now() - ((songInfo.elapsedSeconds ?? 0) * 1000); + activityInfo.startTimestamp = songStartTime; + activityInfo.endTimestamp + = songStartTime + (songInfo.songDuration * 1000); + } + + info.rpc.user?.setActivity(activityInfo).catch(console.error); + }; + + // If the page is ready, register the callback + win.once('ready-to-show', () => { + registerCallback(updateActivity); + connect(); + }); + app.on('window-all-closed', clear); +}; + +export const clear = () => { + if (info.rpc) { + info.rpc.user?.clearActivity(); + } + + clearTimeout(clearActivity); +}; + +export const registerRefresh = (cb: () => void) => refreshCallbacks.push(cb); +export const isConnected = () => info.rpc !== null; diff --git a/plugins/discord/menu.js b/plugins/discord/menu.js deleted file mode 100644 index 78d45e0e..00000000 --- a/plugins/discord/menu.js +++ /dev/null @@ -1,84 +0,0 @@ -const prompt = require("custom-electron-prompt"); - -const { setMenuOptions } = require("../../config/plugins"); -const promptOptions = require("../../providers/prompt-options"); -const { clear, connect, registerRefresh, isConnected } = require("./back"); - -const { singleton } = require("../../providers/decorators") - -const registerRefreshOnce = singleton((refreshMenu) => { - registerRefresh(refreshMenu); -}); - -module.exports = (win, options, refreshMenu) => { - registerRefreshOnce(refreshMenu); - - return [ - { - label: isConnected() ? "Connected" : "Reconnect", - enabled: !isConnected(), - click: connect, - }, - { - label: "Auto reconnect", - type: "checkbox", - checked: options.autoReconnect, - click: (item) => { - options.autoReconnect = item.checked; - setMenuOptions('discord', options); - }, - }, - { - label: "Clear activity", - click: clear, - }, - { - label: "Clear activity after timeout", - type: "checkbox", - checked: options.activityTimoutEnabled, - click: (item) => { - options.activityTimoutEnabled = item.checked; - setMenuOptions('discord', options); - }, - }, - { - label: "Listen Along", - type: "checkbox", - checked: options.listenAlong, - click: (item) => { - options.listenAlong = item.checked; - setMenuOptions('discord', options); - }, - }, - { - label: "Hide duration left", - type: "checkbox", - checked: options.hideDurationLeft, - click: (item) => { - options.hideDurationLeft = item.checked; - setMenuOptions('discord', options); - } - }, - { - label: "Set inactivity timeout", - click: () => setInactivityTimeout(win, options), - }, - ]; -}; - -async function setInactivityTimeout(win, options) { - let output = await prompt({ - title: 'Set Inactivity Timeout', - label: 'Enter inactivity timeout in seconds:', - value: Math.round((options.activityTimoutTime ?? 0) / 1e3), - type: "counter", - counterOptions: { minimum: 0, multiFire: true }, - width: 450, - ...promptOptions() - }, win) - - if (output) { - options.activityTimoutTime = Math.round(output * 1e3); - setMenuOptions("discord", options); - } -} diff --git a/plugins/discord/menu.ts b/plugins/discord/menu.ts new file mode 100644 index 00000000..a8ea14c6 --- /dev/null +++ b/plugins/discord/menu.ts @@ -0,0 +1,90 @@ +import prompt from 'custom-electron-prompt'; + +import { Electron } from 'playwright'; + +import { clear, connect, isConnected, registerRefresh } from './back'; + +import { setMenuOptions } from '../../config/plugins'; +import promptOptions from '../../providers/prompt-options'; +import { singleton } from '../../providers/decorators'; + +import type { ConfigType } from '../../config/dynamic'; + +const registerRefreshOnce = singleton((refreshMenu: () => void) => { + registerRefresh(refreshMenu); +}); + +type DiscordOptions = ConfigType<'discord'>; + +export default (win: Electron.BrowserWindow, options: DiscordOptions, refreshMenu: () => void) => { + registerRefreshOnce(refreshMenu); + + return [ + { + label: isConnected() ? 'Connected' : 'Reconnect', + enabled: !isConnected(), + click: connect, + }, + { + label: 'Auto reconnect', + type: 'checkbox', + checked: options.autoReconnect, + click(item: Electron.MenuItem) { + options.autoReconnect = item.checked; + setMenuOptions('discord', options); + }, + }, + { + label: 'Clear activity', + click: clear, + }, + { + label: 'Clear activity after timeout', + type: 'checkbox', + checked: options.activityTimoutEnabled, + click(item: Electron.MenuItem) { + options.activityTimoutEnabled = item.checked; + setMenuOptions('discord', options); + }, + }, + { + label: 'Listen Along', + type: 'checkbox', + checked: options.listenAlong, + click(item: Electron.MenuItem) { + options.listenAlong = item.checked; + setMenuOptions('discord', options); + }, + }, + { + label: 'Hide duration left', + type: 'checkbox', + checked: options.hideDurationLeft, + click(item: Electron.MenuItem) { + options.hideDurationLeft = item.checked; + setMenuOptions('discord', options); + }, + }, + { + label: 'Set inactivity timeout', + click: () => setInactivityTimeout(win, options), + }, + ]; +}; + +async function setInactivityTimeout(win: Electron.BrowserWindow, options: DiscordOptions) { + const output = await prompt({ + title: 'Set Inactivity Timeout', + label: 'Enter inactivity timeout in seconds:', + value: String(Math.round((options.activityTimoutTime ?? 0) / 1e3)), + type: 'counter', + counterOptions: { minimum: 0, multiFire: true }, + width: 450, + ...promptOptions(), + }, win); + + if (output) { + options.activityTimoutTime = Math.round(~~output * 1e3); + setMenuOptions('discord', options); + } +} diff --git a/plugins/downloader/back.js b/plugins/downloader/back.js deleted file mode 100644 index 8a9ae116..00000000 --- a/plugins/downloader/back.js +++ /dev/null @@ -1,519 +0,0 @@ -const { - existsSync, - mkdirSync, - createWriteStream, - writeFileSync, -} = require('fs'); -const { join } = require('path'); - -const { fetchFromGenius } = require('../lyrics-genius/back'); -const { isEnabled } = require('../../config/plugins'); -const { getImage, cleanupName } = require('../../providers/song-info'); -const { injectCSS } = require('../utils'); -const { cache } = require("../../providers/decorators") -const { - presets, - cropMaxWidth, - getFolder, - setBadge, - sendFeedback: sendFeedback_, -} = require('./utils'); - -const { ipcMain, app, dialog } = require('electron'); -const is = require('electron-is'); -const { Innertube, UniversalCache, Utils, ClientType } = require('youtubei.js'); -const ytpl = require('ytpl'); // REPLACE with youtubei getplaylist https://github.com/LuanRT/YouTube.js#getplaylistid - -const filenamify = require('filenamify'); -const ID3Writer = require('browser-id3-writer'); -const { randomBytes } = require('crypto'); -const Mutex = require('async-mutex').Mutex; -const ffmpeg = require('@ffmpeg/ffmpeg').createFFmpeg({ - log: false, - logger: () => {}, // console.log, - progress: () => {}, // console.log, -}); -const ffmpegMutex = new Mutex(); - -const config = require('./config'); - -/** @type {Innertube} */ -let yt; -let win; -let playingUrl = undefined; - -const sendError = (error, source) => { - win.setProgressBar(-1); // close progress bar - setBadge(0); // close badge - sendFeedback_(win); // reset feedback - - const songNameMessage = source ? `\nin ${source}` : ''; - const cause = error.cause ? `\n\n${error.cause.toString()}` : ''; - const message = `${error.toString()}${songNameMessage}${cause}`; - - console.error(message); - dialog.showMessageBox({ - type: 'info', - buttons: ['OK'], - title: 'Error in download!', - message: 'Argh! Apologies, download failed…', - detail: message, - }); -}; - -module.exports = async (win_) => { - win = win_; - injectCSS(win.webContents, join(__dirname, 'style.css')); - - yt = await Innertube.create({ - cache: new UniversalCache(false), - generate_session_locally: true, - }); - ipcMain.on('download-song', (_, url) => downloadSong(url)); - ipcMain.on('video-src-changed', async (_, data) => { - playingUrl = - JSON.parse(data)?.microformat?.microformatDataRenderer?.urlCanonical; - }); - ipcMain.on('download-playlist-request', async (_event, url) => - downloadPlaylist(url), - ); -}; - -module.exports.downloadSong = downloadSong; -module.exports.downloadPlaylist = downloadPlaylist; - -async function downloadSong( - url, - playlistFolder = undefined, - trackId = undefined, - increasePlaylistProgress = () => {}, -) { - let resolvedName = undefined; - try { - await downloadSongUnsafe( - url, - name=>resolvedName=name, - playlistFolder, - trackId, - increasePlaylistProgress, - ); - } catch (error) { - sendError(error, resolvedName || url); - } -} - -async function downloadSongUnsafe( - url, - setName, - playlistFolder = undefined, - trackId = undefined, - increasePlaylistProgress = () => {}, -) { - const sendFeedback = (message, progress) => { - if (!playlistFolder) { - sendFeedback_(win, message); - if (!isNaN(progress)) { - win.setProgressBar(progress); - } - } - }; - - sendFeedback('Downloading...', 2); - - const id = getVideoId(url); - let info = await yt.music.getInfo(id); - - if (!info) { - throw new Error('Video not found'); - } - - const metadata = getMetadata(info); - if (metadata.album === 'N/A') metadata.album = ''; - metadata.trackId = trackId; - - const dir = - playlistFolder || config.get('downloadFolder') || app.getPath('downloads'); - const name = `${metadata.artist ? `${metadata.artist} - ` : ''}${ - metadata.title - }`; - setName(name); - - let playabilityStatus = info.playability_status; - let bypassedResult = null; - if (playabilityStatus.status === "LOGIN_REQUIRED") { - // try to bypass the age restriction - bypassedResult = await getAndroidTvInfo(id); - playabilityStatus = bypassedResult.playability_status; - - if (playabilityStatus.status === "LOGIN_REQUIRED") { - throw new Error( - `[${playabilityStatus.status}] ${playabilityStatus.reason}`, - ); - } - - info = bypassedResult; - } - - if (playabilityStatus.status === "UNPLAYABLE") { - /** - * @typedef {import('youtubei.js/dist/src/parser/classes/PlayerErrorMessage').default} PlayerErrorMessage - * @type {PlayerErrorMessage} - */ - const errorScreen = playabilityStatus.error_screen; - throw new Error( - `[${playabilityStatus.status}] ${errorScreen.reason.text}: ${errorScreen.subreason.text}`, - ); - } - - const extension = presets[config.get('preset')]?.extension || 'mp3'; - - const filename = filenamify(`${name}.${extension}`, { - replacement: '_', - maxLength: 255, - }); - const filePath = join(dir, filename); - - if (config.get('skipExisting') && existsSync(filePath)) { - sendFeedback(null, -1); - return; - } - - const download_options = { - type: 'audio', // audio, video or video+audio - quality: 'best', // best, bestefficiency, 144p, 240p, 480p, 720p and so on. - format: 'any', // media container format - }; - - const format = info.chooseFormat(download_options); - const stream = await info.download(download_options); - - console.info( - `Downloading ${metadata.artist} - ${metadata.title} [${metadata.id}]`, - ); - - const iterableStream = Utils.streamToIterable(stream); - - if (!existsSync(dir)) { - mkdirSync(dir); - } - - if (!presets[config.get('preset')]) { - const fileBuffer = await iterableStreamToMP3( - iterableStream, - metadata, - format.content_length, - sendFeedback, - increasePlaylistProgress, - ); - writeFileSync(filePath, await writeID3(fileBuffer, metadata, sendFeedback)); - } else { - const file = createWriteStream(filePath); - let downloaded = 0; - const total = format.content_length; - - for await (const chunk of iterableStream) { - downloaded += chunk.length; - const ratio = downloaded / total; - const progress = Math.floor(ratio * 100); - sendFeedback(`Download: ${progress}%`, ratio); - increasePlaylistProgress(ratio); - file.write(chunk); - } - await ffmpegWriteTags( - filePath, - metadata, - presets[config.get('preset')]?.ffmpegArgs, - ); - sendFeedback(null, -1); - } - - sendFeedback(null, -1); - console.info(`Done: "${filePath}"`); -} - -async function iterableStreamToMP3( - stream, - metadata, - content_length, - sendFeedback, - increasePlaylistProgress = () => {}, -) { - const chunks = []; - let downloaded = 0; - const total = content_length; - for await (const chunk of stream) { - downloaded += chunk.length; - chunks.push(chunk); - const ratio = downloaded / total; - const progress = Math.floor(ratio * 100); - sendFeedback(`Download: ${progress}%`, ratio); - // 15% for download, 85% for conversion - // This is a very rough estimate, trying to make the progress bar look nice - increasePlaylistProgress(ratio * 0.15); - } - sendFeedback('Loading…', 2); // indefinite progress bar after download - - const buffer = Buffer.concat(chunks); - const safeVideoName = randomBytes(32).toString('hex'); - const releaseFFmpegMutex = await ffmpegMutex.acquire(); - - try { - if (!ffmpeg.isLoaded()) { - await ffmpeg.load(); - } - - sendFeedback('Preparing file…'); - ffmpeg.FS('writeFile', safeVideoName, buffer); - - sendFeedback('Converting…'); - - ffmpeg.setProgress(({ ratio }) => { - sendFeedback(`Converting: ${Math.floor(ratio * 100)}%`, ratio); - increasePlaylistProgress(0.15 + ratio * 0.85); - }); - - await ffmpeg.run( - '-i', - safeVideoName, - ...getFFmpegMetadataArgs(metadata), - `${safeVideoName}.mp3`, - ); - - sendFeedback('Saving…'); - - return ffmpeg.FS('readFile', `${safeVideoName}.mp3`); - } catch (e) { - sendError(e, safeVideoName); - } finally { - releaseFFmpegMutex(); - } -} - -const getCoverBuffer = cache(async (url) => { - const nativeImage = cropMaxWidth(await getImage(url)); - return nativeImage && !nativeImage.isEmpty() ? nativeImage.toPNG() : null; -}); - -async function writeID3(buffer, metadata, sendFeedback) { - try { - sendFeedback('Writing ID3 tags...'); - - const coverBuffer = await getCoverBuffer(metadata.image); - - const writer = new ID3Writer(buffer); - - // Create the metadata tags - writer.setFrame('TIT2', metadata.title).setFrame('TPE1', [metadata.artist]); - if (metadata.album) { - writer.setFrame('TALB', metadata.album); - } - if (coverBuffer) { - writer.setFrame('APIC', { - type: 3, - data: coverBuffer, - description: '', - }); - } - if (isEnabled('lyrics-genius')) { - const lyrics = await fetchFromGenius(metadata); - if (lyrics) { - writer.setFrame('USLT', { - description: '', - lyrics: lyrics, - }); - } - } - if (metadata.trackId) { - writer.setFrame('TRCK', metadata.trackId); - } - writer.addTag(); - return Buffer.from(writer.arrayBuffer); - } catch (e) { - sendError(e, `${metadata.artist} - ${metadata.title}`); - } -} - -async function downloadPlaylist(givenUrl) { - try { - givenUrl = new URL(givenUrl); - } catch { - givenUrl = undefined; - } - const playlistId = - getPlaylistID(givenUrl) || - getPlaylistID(new URL(win.webContents.getURL())) || - getPlaylistID(new URL(playingUrl)); - - if (!playlistId) { - sendError(new Error('No playlist ID found')); - return; - } - - const sendFeedback = (message) => sendFeedback_(win, message); - - console.log(`trying to get playlist ID: '${playlistId}'`); - sendFeedback('Getting playlist info…'); - let playlist; - try { - playlist = await ytpl(playlistId, { - limit: config.get('playlistMaxItems') || Infinity, - }); - } catch (e) { - sendError( - `Error getting playlist info: make sure it isn\'t a private or "Mixed for you" playlist\n\n${e}`, - ); - return; - } - if (playlist.items.length === 0) sendError(new Error('Playlist is empty')); - if (playlist.items.length === 1) { - sendFeedback('Playlist has only one item, downloading it directly'); - await downloadSong(playlist.items[0].url); - return; - } - const isAlbum = playlist.title.startsWith('Album - '); - if (isAlbum) { - playlist.title = playlist.title.slice(8); - } - const safePlaylistTitle = filenamify(playlist.title, { replacement: ' ' }); - - const folder = getFolder(config.get('downloadFolder')); - const playlistFolder = join(folder, safePlaylistTitle); - if (existsSync(playlistFolder)) { - if (!config.get('skipExisting')) { - sendError(new Error(`The folder ${playlistFolder} already exists`)); - return; - } - } else { - mkdirSync(playlistFolder, { recursive: true }); - } - - dialog.showMessageBox({ - type: 'info', - buttons: ['OK'], - title: 'Started Download', - message: `Downloading Playlist "${playlist.title}"`, - detail: `(${playlist.items.length} songs)`, - }); - - if (is.dev()) { - console.log( - `Downloading playlist "${playlist.title}" - ${playlist.items.length} songs (${playlistId})`, - ); - } - - win.setProgressBar(2); // starts with indefinite bar - - setBadge(playlist.items.length); - - let counter = 1; - - const progressStep = 1 / playlist.items.length; - - const increaseProgress = (itemPercentage) => { - const currentProgress = (counter - 1) / playlist.items.length; - const newProgress = currentProgress + progressStep * itemPercentage; - win.setProgressBar(newProgress); - }; - - try { - for (const song of playlist.items) { - sendFeedback(`Downloading ${counter}/${playlist.items.length}...`); - const trackId = isAlbum ? counter : undefined; - await downloadSong( - song.url, - playlistFolder, - trackId, - increaseProgress, - ).catch((e) => - sendError( - `Error downloading "${song.author.name} - ${song.title}":\n ${e}`, - ), - ); - - win.setProgressBar(counter / playlist.items.length); - setBadge(playlist.items.length - counter); - counter++; - } - } catch (e) { - sendError(e); - } finally { - win.setProgressBar(-1); // close progress bar - setBadge(0); // close badge counter - sendFeedback(); // clear feedback - } -} - -async function ffmpegWriteTags(filePath, metadata, ffmpegArgs = []) { - const releaseFFmpegMutex = await ffmpegMutex.acquire(); - - try { - if (!ffmpeg.isLoaded()) { - await ffmpeg.load(); - } - - await ffmpeg.run( - '-i', - filePath, - ...getFFmpegMetadataArgs(metadata), - ...ffmpegArgs, - filePath, - ); - } catch (e) { - sendError(e); - } finally { - releaseFFmpegMutex(); - } -} - -function getFFmpegMetadataArgs(metadata) { - if (!metadata) { - return; - } - - return [ - ...(metadata.title ? ['-metadata', `title=${metadata.title}`] : []), - ...(metadata.artist ? ['-metadata', `artist=${metadata.artist}`] : []), - ...(metadata.album ? ['-metadata', `album=${metadata.album}`] : []), - ...(metadata.trackId ? ['-metadata', `track=${metadata.trackId}`] : []), - ]; -} - -// Playlist radio modifier needs to be cut from playlist ID -const INVALID_PLAYLIST_MODIFIER = 'RDAMPL'; - -const getPlaylistID = (aURL) => { - const result = - aURL?.searchParams.get('list') || aURL?.searchParams.get('playlist'); - if (result?.startsWith(INVALID_PLAYLIST_MODIFIER)) { - return result.slice(INVALID_PLAYLIST_MODIFIER.length); - } - return result; -}; - -const getVideoId = (url) => { - if (typeof url === 'string') { - url = new URL(url); - } - return url.searchParams.get('v'); -}; - -const getMetadata = (info) => ({ - id: info.basic_info.id, - title: cleanupName(info.basic_info.title), - artist: cleanupName(info.basic_info.author), - album: info.player_overlays?.browser_media_session?.album?.text, - image: info.basic_info.thumbnail?.find((t) => !t.url.endsWith('.webp'))?.url, -}); - -// This is used to bypass age restrictions -const getAndroidTvInfo = async (id) => { - const innertube = await Innertube.create({ - clientType: ClientType.TV_EMBEDDED, - generate_session_locally: true, - retrieve_player: true, - }); - const info = await innertube.getBasicInfo(id, 'TV_EMBEDDED'); - // getInfo 404s with the bypass, so we use getBasicInfo instead - // that's fine as we only need the streaming data - return info; -} diff --git a/plugins/downloader/back.ts b/plugins/downloader/back.ts new file mode 100644 index 00000000..958fd6aa --- /dev/null +++ b/plugins/downloader/back.ts @@ -0,0 +1,571 @@ +import { createWriteStream, existsSync, mkdirSync, writeFileSync, } from 'node:fs'; +import { join } from 'node:path'; +import { randomBytes } from 'node:crypto'; + +import { app, BrowserWindow, dialog, ipcMain } from 'electron'; +import { ClientType, Innertube, UniversalCache, Utils } from 'youtubei.js'; +import is from 'electron-is'; +import ytpl from 'ytpl'; +// REPLACE with youtubei getplaylist https://github.com/LuanRT/YouTube.js#getplaylistid +import filenamify from 'filenamify'; +import { Mutex } from 'async-mutex'; +import { createFFmpeg } from '@ffmpeg.wasm/main'; + +import NodeID3, { TagConstants } from 'node-id3'; + +import PlayerErrorMessage from 'youtubei.js/dist/src/parser/classes/PlayerErrorMessage'; +import { FormatOptions } from 'youtubei.js/dist/src/types/FormatUtils'; + +import TrackInfo from 'youtubei.js/dist/src/parser/ytmusic/TrackInfo'; + +import { VideoInfo } from 'youtubei.js/dist/src/parser/youtube'; + +import { cropMaxWidth, getFolder, presets, sendFeedback as sendFeedback_, setBadge } from './utils'; + +import config from './config'; + +import { fetchFromGenius } from '../lyrics-genius/back'; +import { isEnabled } from '../../config/plugins'; +import { cleanupName, getImage, SongInfo } from '../../providers/song-info'; +import { injectCSS } from '../utils'; +import { cache } from '../../providers/decorators'; + +import type { GetPlayerResponse } from '../../types/get-player-response'; + +type CustomSongInfo = SongInfo & { trackId?: string }; + +const ffmpeg = createFFmpeg({ + log: false, + logger() { + }, // Console.log, + progress() { + }, // Console.log, +}); +const ffmpegMutex = new Mutex(); + +let yt: Innertube; +let win: BrowserWindow; +let playingUrl: string; + +const sendError = (error: Error, source?: string) => { + win.setProgressBar(-1); // Close progress bar + setBadge(0); // Close badge + sendFeedback_(win); // Reset feedback + + const songNameMessage = source ? `\nin ${source}` : ''; + const cause = error.cause ? `\n\n${String(error.cause)}` : ''; + const message = `${error.toString()}${songNameMessage}${cause}`; + + console.error(message, error, error?.stack); + dialog.showMessageBox({ + type: 'info', + buttons: ['OK'], + title: 'Error in download!', + message: 'Argh! Apologies, download failed…', + detail: message, + }); +}; + +export default async (win_: BrowserWindow) => { + win = win_; + injectCSS(win.webContents, join(__dirname, 'style.css')); + + const cookie = (await win.webContents.session.cookies.get({ url: 'https://music.youtube.com' })).map((it) => + it.name + '=' + it.value + ';' + ).join(''); + yt = await Innertube.create({ + cache: new UniversalCache(false), + cookie, + generate_session_locally: true, + }); + ipcMain.on('download-song', (_, url: string) => downloadSong(url)); + ipcMain.on('video-src-changed', (_, data: GetPlayerResponse) => { + playingUrl = data.microformat.microformatDataRenderer.urlCanonical; + }); + ipcMain.on('download-playlist-request', async (_event, url: string) => + downloadPlaylist(url), + ); +}; + +export async function downloadSong( + url: string, + playlistFolder: string | undefined = undefined, + trackId: string | undefined = undefined, + increasePlaylistProgress: (value: number) => void = () => { + }, +) { + let resolvedName; + try { + await downloadSongUnsafe( + url, + (name: string) => resolvedName = name, + playlistFolder, + trackId, + increasePlaylistProgress, + ); + } catch (error: unknown) { + sendError(error as Error, resolvedName || url); + } +} + +async function downloadSongUnsafe( + url: string, + setName: (name: string) => void, + playlistFolder: string | undefined = undefined, + trackId: string | undefined = undefined, + increasePlaylistProgress: (value: number) => void = () => { + }, +) { + const sendFeedback = (message: unknown, progress?: number) => { + if (!playlistFolder) { + sendFeedback_(win, message); + if (progress && !isNaN(progress)) { + win.setProgressBar(progress); + } + } + }; + + sendFeedback('Downloading...', 2); + + const id = getVideoId(url); + if (typeof id !== 'string') throw new Error('Video not found'); + + let info: TrackInfo | VideoInfo = await yt.music.getInfo(id); + + if (!info) { + throw new Error('Video not found'); + } + + const metadata = getMetadata(info); + if (metadata.album === 'N/A') { + metadata.album = ''; + } + + metadata.trackId = trackId; + + const dir + = playlistFolder || config.get('downloadFolder') || app.getPath('downloads'); + const name = `${metadata.artist ? `${metadata.artist} - ` : ''}${ + metadata.title + }`; + setName(name); + + let playabilityStatus = info.playability_status; + let bypassedResult = null; + if (playabilityStatus.status === 'LOGIN_REQUIRED') { + // Try to bypass the age restriction + bypassedResult = await getAndroidTvInfo(id); + playabilityStatus = bypassedResult.playability_status; + + if (playabilityStatus.status === 'LOGIN_REQUIRED') { + throw new Error( + `[${playabilityStatus.status}] ${playabilityStatus.reason}`, + ); + } + + info = bypassedResult; + } + + if (playabilityStatus.status === 'UNPLAYABLE') { + const errorScreen = playabilityStatus.error_screen as PlayerErrorMessage | null; + throw new Error( + `[${playabilityStatus.status}] ${errorScreen?.reason.text}: ${errorScreen?.subreason.text}`, + ); + } + + const preset = config.get('preset') ?? 'mp3'; + let presetSetting: { extension: string; ffmpegArgs: string[] } | null = null; + if (preset === 'opus') { + presetSetting = presets[preset]; + } + + const filename = filenamify(`${name}.${presetSetting?.extension ?? 'mp3'}`, { + replacement: '_', + maxLength: 255, + }); + const filePath = join(dir, filename); + + if (config.get('skipExisting') && existsSync(filePath)) { + sendFeedback(null, -1); + return; + } + + const downloadOptions: FormatOptions = { + type: 'audio', // Audio, video or video+audio + quality: 'best', // Best, bestefficiency, 144p, 240p, 480p, 720p and so on. + format: 'any', // Media container format + }; + + const format = info.chooseFormat(downloadOptions); + const stream = await info.download(downloadOptions); + + console.info( + `Downloading ${metadata.artist} - ${metadata.title} [${metadata.videoId}]`, + ); + + const iterableStream = Utils.streamToIterable(stream); + + if (!existsSync(dir)) { + mkdirSync(dir); + } + + const ffmpegArgs = config.get('ffmpegArgs'); + + if (presetSetting && presetSetting?.extension !== 'mp3') { + const file = createWriteStream(filePath); + let downloaded = 0; + const total: number = format.content_length ?? 1; + + for await (const chunk of iterableStream) { + downloaded += chunk.length; + const ratio = downloaded / total; + const progress = Math.floor(ratio * 100); + sendFeedback(`Download: ${progress}%`, ratio); + increasePlaylistProgress(ratio); + file.write(chunk); + } + + await ffmpegWriteTags( + filePath, + metadata, + presetSetting.ffmpegArgs, + ffmpegArgs, + ); + sendFeedback(null, -1); + } else { + const fileBuffer = await iterableStreamToMP3( + iterableStream, + metadata, + ffmpegArgs, + format.content_length ?? 0, + sendFeedback, + increasePlaylistProgress, + ); + if (fileBuffer) { + const buffer = await writeID3(Buffer.from(fileBuffer), metadata, sendFeedback); + if (buffer) { + writeFileSync(filePath, buffer); + } + } + } + + sendFeedback(null, -1); + console.info(`Done: "${filePath}"`); +} + +async function iterableStreamToMP3( + stream: AsyncGenerator, + metadata: CustomSongInfo, + ffmpegArgs: string[], + contentLength: number, + sendFeedback: (str: string, value?: number) => void, + increasePlaylistProgress: (value: number) => void = () => { + }, +) { + const chunks = []; + let downloaded = 0; + for await (const chunk of stream) { + downloaded += chunk.length; + chunks.push(chunk); + const ratio = downloaded / contentLength; + const progress = Math.floor(ratio * 100); + sendFeedback(`Download: ${progress}%`, ratio); + // 15% for download, 85% for conversion + // This is a very rough estimate, trying to make the progress bar look nice + increasePlaylistProgress(ratio * 0.15); + } + + sendFeedback('Loading…', 2); // Indefinite progress bar after download + + const buffer = Buffer.concat(chunks); + const safeVideoName = randomBytes(32).toString('hex'); + const releaseFFmpegMutex = await ffmpegMutex.acquire(); + + try { + if (!ffmpeg.isLoaded()) { + await ffmpeg.load(); + } + + sendFeedback('Preparing file…'); + ffmpeg.FS('writeFile', safeVideoName, buffer); + + sendFeedback('Converting…'); + + ffmpeg.setProgress(({ ratio }) => { + sendFeedback(`Converting: ${Math.floor(ratio * 100)}%`, ratio); + increasePlaylistProgress(0.15 + (ratio * 0.85)); + }); + + try { + await ffmpeg.run( + '-i', + safeVideoName, + ...ffmpegArgs, + ...getFFmpegMetadataArgs(metadata), + `${safeVideoName}.mp3`, + ); + } finally { + ffmpeg.FS('unlink', safeVideoName); + } + + sendFeedback('Saving…'); + + try { + return ffmpeg.FS('readFile', `${safeVideoName}.mp3`); + } finally { + ffmpeg.FS('unlink', `${safeVideoName}.mp3`); + } + } catch (error: unknown) { + sendError(error as Error, safeVideoName); + } finally { + releaseFFmpegMutex(); + } +} + +const getCoverBuffer = cache(async (url: string) => { + const nativeImage = cropMaxWidth(await getImage(url)); + return nativeImage && !nativeImage.isEmpty() ? nativeImage.toPNG() : null; +}); + +async function writeID3(buffer: Buffer, metadata: CustomSongInfo, sendFeedback: (str: string, value?: number) => void) { + try { + sendFeedback('Writing ID3 tags...'); + const tags: NodeID3.Tags = {}; + + // Create the metadata tags + tags.title = metadata.title; + tags.artist = metadata.artist; + + if (metadata.album) { + tags.album = metadata.album; + } + + const coverBuffer = await getCoverBuffer(metadata.imageSrc ?? ''); + if (coverBuffer) { + tags.image = { + mime: 'image/png', + type: { + id: TagConstants.AttachedPicture.PictureType.FRONT_COVER, + }, + description: 'thumbnail', + imageBuffer: coverBuffer, + }; + } + + if (isEnabled('lyrics-genius')) { + const lyrics = await fetchFromGenius(metadata); + if (lyrics) { + tags.unsynchronisedLyrics = { + language: '', + text: lyrics, + }; + } + } + + if (metadata.trackId) { + tags.trackNumber = metadata.trackId; + } + + return NodeID3.write(tags, buffer); + } catch (error: unknown) { + sendError(error as Error, `${metadata.artist} - ${metadata.title}`); + return null; + } +} + +export async function downloadPlaylist(givenUrl?: string | URL) { + try { + givenUrl = new URL(givenUrl ?? ''); + } catch { + return; + } + + const playlistId + = getPlaylistID(givenUrl) + || getPlaylistID(new URL(win.webContents.getURL())) + || getPlaylistID(new URL(playingUrl)); + + if (!playlistId) { + sendError(new Error('No playlist ID found')); + return; + } + + const sendFeedback = (message?: unknown) => sendFeedback_(win, message); + + console.log(`trying to get playlist ID: '${playlistId}'`); + sendFeedback('Getting playlist info…'); + let playlist: ytpl.Result; + try { + playlist = await ytpl(playlistId, { + limit: config.get('playlistMaxItems') || Number.POSITIVE_INFINITY, + }); + } catch (error: unknown) { + sendError( + Error(`Error getting playlist info: make sure it isn't a private or "Mixed for you" playlist\n\n${String(error)}`), + ); + return; + } + + if (playlist.items.length === 0) { + sendError(new Error('Playlist is empty')); + } + + if (playlist.items.length === 1) { + sendFeedback('Playlist has only one item, downloading it directly'); + await downloadSong(playlist.items[0].url); + return; + } + + const isAlbum = playlist.title.startsWith('Album - '); + if (isAlbum) { + playlist.title = playlist.title.slice(8); + } + + const safePlaylistTitle = filenamify(playlist.title, { replacement: ' ' }); + + const folder = getFolder(config.get('downloadFolder') ?? ''); + const playlistFolder = join(folder, safePlaylistTitle); + if (existsSync(playlistFolder)) { + if (!config.get('skipExisting')) { + sendError(new Error(`The folder ${playlistFolder} already exists`)); + return; + } + } else { + mkdirSync(playlistFolder, { recursive: true }); + } + + dialog.showMessageBox({ + type: 'info', + buttons: ['OK'], + title: 'Started Download', + message: `Downloading Playlist "${playlist.title}"`, + detail: `(${playlist.items.length} songs)`, + }); + + if (is.dev()) { + console.log( + `Downloading playlist "${playlist.title}" - ${playlist.items.length} songs (${playlistId})`, + ); + } + + win.setProgressBar(2); // Starts with indefinite bar + + setBadge(playlist.items.length); + + let counter = 1; + + const progressStep = 1 / playlist.items.length; + + const increaseProgress = (itemPercentage: number) => { + const currentProgress = (counter - 1) / (playlist.items.length ?? 1); + const newProgress = currentProgress + (progressStep * itemPercentage); + win.setProgressBar(newProgress); + }; + + try { + for (const song of playlist.items) { + sendFeedback(`Downloading ${counter}/${playlist.items.length}...`); + const trackId = isAlbum ? counter : undefined; + await downloadSong( + song.url, + playlistFolder, + trackId?.toString(), + increaseProgress, + ).catch((error) => + sendError( + new Error(`Error downloading "${song.author.name} - ${song.title}":\n ${error}`) + ), + ); + + win.setProgressBar(counter / playlist.items.length); + setBadge(playlist.items.length - counter); + counter++; + } + } catch (error: unknown) { + sendError(error as Error); + } finally { + win.setProgressBar(-1); // Close progress bar + setBadge(0); // Close badge counter + sendFeedback(); // Clear feedback + } +} + +async function ffmpegWriteTags(filePath: string, metadata: CustomSongInfo, presetFFmpegArgs: string[] = [], ffmpegArgs: string[] = []) { + const releaseFFmpegMutex = await ffmpegMutex.acquire(); + + try { + if (!ffmpeg.isLoaded()) { + await ffmpeg.load(); + } + + await ffmpeg.run( + '-i', + filePath, + ...getFFmpegMetadataArgs(metadata), + ...presetFFmpegArgs, + ...ffmpegArgs, + filePath, + ); + } catch (error: unknown) { + sendError(error as Error); + } finally { + releaseFFmpegMutex(); + } +} + +function getFFmpegMetadataArgs(metadata: CustomSongInfo) { + if (!metadata) { + return []; + } + + return [ + ...(metadata.title ? ['-metadata', `title=${metadata.title}`] : []), + ...(metadata.artist ? ['-metadata', `artist=${metadata.artist}`] : []), + ...(metadata.album ? ['-metadata', `album=${metadata.album}`] : []), + ...(metadata.trackId ? ['-metadata', `track=${metadata.trackId}`] : []), + ]; +} + +// Playlist radio modifier needs to be cut from playlist ID +const INVALID_PLAYLIST_MODIFIER = 'RDAMPL'; + +const getPlaylistID = (aURL: URL) => { + const result + = aURL?.searchParams.get('list') || aURL?.searchParams.get('playlist'); + if (result?.startsWith(INVALID_PLAYLIST_MODIFIER)) { + return result.slice(INVALID_PLAYLIST_MODIFIER.length); + } + + return result; +}; + +const getVideoId = (url: URL | string): string | null => { + if (typeof url === 'string') { + url = new URL(url); + } + + return url.searchParams.get('v'); +}; + +const getMetadata = (info: TrackInfo): CustomSongInfo => ({ + videoId: info.basic_info.id!, + title: cleanupName(info.basic_info.title!), + artist: cleanupName(info.basic_info.author!), + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access,@typescript-eslint/no-explicit-any + album: (info.player_overlays?.browser_media_session as any)?.album?.text as string | undefined, + imageSrc: info.basic_info.thumbnail?.find((t) => !t.url.endsWith('.webp'))?.url, + views: info.basic_info.view_count!, + songDuration: info.basic_info.duration!, +}); + +// This is used to bypass age restrictions +const getAndroidTvInfo = async (id: string): Promise => { + const innertube = await Innertube.create({ + client_type: ClientType.TV_EMBEDDED, + generate_session_locally: true, + retrieve_player: true, + }); + // GetInfo 404s with the bypass, so we use getBasicInfo instead + // that's fine as we only need the streaming data + return await innertube.getBasicInfo(id, 'TV_EMBEDDED'); +}; diff --git a/plugins/downloader/config.js b/plugins/downloader/config.js deleted file mode 100644 index 12c0384e..00000000 --- a/plugins/downloader/config.js +++ /dev/null @@ -1,3 +0,0 @@ -const { PluginConfig } = require('../../config/dynamic'); -const config = new PluginConfig('downloader'); -module.exports = { ...config }; diff --git a/plugins/downloader/config.ts b/plugins/downloader/config.ts new file mode 100644 index 00000000..69b1cb78 --- /dev/null +++ b/plugins/downloader/config.ts @@ -0,0 +1,4 @@ +import { PluginConfig } from '../../config/dynamic'; + +const config = new PluginConfig('downloader'); +export default config; diff --git a/plugins/downloader/front.js b/plugins/downloader/front.js deleted file mode 100644 index e0ab119f..00000000 --- a/plugins/downloader/front.js +++ /dev/null @@ -1,69 +0,0 @@ -const { ipcRenderer } = require("electron"); - -const { defaultConfig } = require("../../config"); -const { getSongMenu } = require("../../providers/dom-elements"); -const { ElementFromFile, templatePath } = require("../utils"); - -let menu = null; -let progress = null; -const downloadButton = ElementFromFile( - templatePath(__dirname, "download.html") -); - -let doneFirstLoad = false; - -const menuObserver = new MutationObserver(() => { - if (!menu) { - menu = getSongMenu(); - if (!menu) return; - } - if (menu.contains(downloadButton)) return; - const menuUrl = document.querySelector('tp-yt-paper-listbox [tabindex="0"] #navigation-endpoint')?.href; - if (!menuUrl?.includes('watch?') && doneFirstLoad) return; - - menu.prepend(downloadButton); - progress = document.querySelector("#ytmcustom-download"); - - if (doneFirstLoad) return; - setTimeout(() => doneFirstLoad ||= true, 500); -}); - -// TODO: re-enable once contextIsolation is set to true -// contextBridge.exposeInMainWorld("downloader", { -// download: () => { -global.download = () => { - let videoUrl = getSongMenu() - // selector of first button which is always "Start Radio" - ?.querySelector('ytmusic-menu-navigation-item-renderer[tabindex="0"] #navigation-endpoint') - ?.getAttribute("href"); - if (videoUrl) { - if (videoUrl.startsWith('watch?')) { - videoUrl = defaultConfig.url + "/" + videoUrl; - } - if (videoUrl.includes('?playlist=')) { - ipcRenderer.send('download-playlist-request', videoUrl); - return; - } - } else { - videoUrl = global.songInfo.url || window.location.href; - } - - ipcRenderer.send('download-song', videoUrl); -}; - -module.exports = () => { - document.addEventListener('apiLoaded', () => { - menuObserver.observe(document.querySelector('ytmusic-popup-container'), { - childList: true, - subtree: true, - }); - }, { once: true, passive: true }) - - ipcRenderer.on('downloader-feedback', (_, feedback) => { - if (!progress) { - console.warn("Cannot update progress"); - } else { - progress.innerHTML = feedback || "Download"; - } - }); -}; diff --git a/plugins/downloader/front.ts b/plugins/downloader/front.ts new file mode 100644 index 00000000..29d9d1cc --- /dev/null +++ b/plugins/downloader/front.ts @@ -0,0 +1,83 @@ +import { ipcRenderer } from 'electron'; + +import defaultConfig from '../../config/defaults'; +import { getSongMenu } from '../../providers/dom-elements'; +import { ElementFromFile, templatePath } from '../utils'; +import { getSongInfo } from '../../providers/song-info-front'; + +let menu: Element | null = null; +let progress: Element | null = null; +const downloadButton = ElementFromFile( + templatePath(__dirname, 'download.html'), +); + +let doneFirstLoad = false; + +const menuObserver = new MutationObserver(() => { + if (!menu) { + menu = getSongMenu(); + if (!menu) { + return; + } + } + + if (menu.contains(downloadButton)) { + return; + } + + const menuUrl = document.querySelector('tp-yt-paper-listbox [tabindex="0"] #navigation-endpoint')?.href; + if (!menuUrl?.includes('watch?') && doneFirstLoad) { + return; + } + + menu.prepend(downloadButton); + progress = document.querySelector('#ytmcustom-download'); + + if (doneFirstLoad) { + return; + } + + setTimeout(() => doneFirstLoad ||= true, 500); +}); + +// TODO: re-enable once contextIsolation is set to true +// contextBridge.exposeInMainWorld("downloader", { +// download: () => { +// eslint-disable-next-line @typescript-eslint/no-explicit-any,@typescript-eslint/no-unsafe-member-access +(global as any).download = () => { + let videoUrl = getSongMenu() + // Selector of first button which is always "Start Radio" + ?.querySelector('ytmusic-menu-navigation-item-renderer[tabindex="0"] #navigation-endpoint') + ?.getAttribute('href'); + if (videoUrl) { + if (videoUrl.startsWith('watch?')) { + videoUrl = defaultConfig.url + '/' + videoUrl; + } + + if (videoUrl.includes('?playlist=')) { + ipcRenderer.send('download-playlist-request', videoUrl); + return; + } + } else { + videoUrl = getSongInfo().url || window.location.href; + } + + ipcRenderer.send('download-song', videoUrl); +}; + +export default () => { + document.addEventListener('apiLoaded', () => { + menuObserver.observe(document.querySelector('ytmusic-popup-container')!, { + childList: true, + subtree: true, + }); + }, { once: true, passive: true }); + + ipcRenderer.on('downloader-feedback', (_, feedback: string) => { + if (progress) { + progress.innerHTML = feedback || 'Download'; + } else { + console.warn('Cannot update progress'); + } + }); +}; diff --git a/plugins/downloader/menu.js b/plugins/downloader/menu.js deleted file mode 100644 index 6d58bbf2..00000000 --- a/plugins/downloader/menu.js +++ /dev/null @@ -1,45 +0,0 @@ -const { dialog } = require("electron"); - -const { downloadPlaylist } = require("./back"); -const { defaultMenuDownloadLabel, getFolder, presets } = require("./utils"); -const config = require("./config"); - -module.exports = () => { - return [ - { - label: defaultMenuDownloadLabel, - click: () => downloadPlaylist(), - }, - { - label: "Choose download folder", - click: () => { - const result = dialog.showOpenDialogSync({ - properties: ["openDirectory", "createDirectory"], - defaultPath: getFolder(config.get("downloadFolder")), - }); - if (result) { - config.set("downloadFolder", result[0]); - } // else = user pressed cancel - }, - }, - { - label: "Presets", - submenu: Object.keys(presets).map((preset) => ({ - label: preset, - type: "radio", - checked: config.get("preset") === preset, - click: () => { - config.set("preset", preset); - }, - })), - }, - { - label: "Skip existing files", - type: "checkbox", - checked: config.get("skipExisting"), - click: (item) => { - config.set("skipExisting", item.checked); - }, - }, - ]; -}; diff --git a/plugins/downloader/menu.ts b/plugins/downloader/menu.ts new file mode 100644 index 00000000..c49a6389 --- /dev/null +++ b/plugins/downloader/menu.ts @@ -0,0 +1,45 @@ +import { dialog } from 'electron'; + +import { downloadPlaylist } from './back'; +import { defaultMenuDownloadLabel, getFolder, presets } from './utils'; +import config from './config'; + +import { MenuTemplate } from '../../menu'; + +export default (): MenuTemplate => [ + { + label: defaultMenuDownloadLabel, + click: () => downloadPlaylist(), + }, + { + label: 'Choose download folder', + click() { + const result = dialog.showOpenDialogSync({ + properties: ['openDirectory', 'createDirectory'], + defaultPath: getFolder(config.get('downloadFolder') ?? ''), + }); + if (result) { + config.set('downloadFolder', result[0]); + } // Else = user pressed cancel + }, + }, + { + label: 'Presets', + submenu: Object.keys(presets).map((preset) => ({ + label: preset, + type: 'radio', + checked: config.get('preset') === preset, + click() { + config.set('preset', preset); + }, + })), + }, + { + label: 'Skip existing files', + type: 'checkbox', + checked: config.get('skipExisting'), + click(item) { + config.set('skipExisting', item.checked); + }, + }, +]; diff --git a/plugins/downloader/style.css b/plugins/downloader/style.css index 6f29fc6b..ea721f30 100644 --- a/plugins/downloader/style.css +++ b/plugins/downloader/style.css @@ -1,21 +1,21 @@ .menu-item { - display: var(--ytmusic-menu-item_-_display); - height: var(--ytmusic-menu-item_-_height); - align-items: var(--ytmusic-menu-item_-_align-items); - padding: var(--ytmusic-menu-item_-_padding); - cursor: pointer; + display: var(--ytmusic-menu-item_-_display); + height: var(--ytmusic-menu-item_-_height); + align-items: var(--ytmusic-menu-item_-_align-items); + padding: var(--ytmusic-menu-item_-_padding); + cursor: pointer; } .menu-item > .yt-simple-endpoint:hover { - background-color: var(--ytmusic-menu-item-hover-background-color); + background-color: var(--ytmusic-menu-item-hover-background-color); } .menu-icon { - flex: var(--ytmusic-menu-item-icon_-_flex); - margin: var(--ytmusic-menu-item-icon_-_margin); - fill: var(--ytmusic-menu-item-icon_-_fill); - stroke: var(--iron-icon-stroke-color, none); - width: var(--iron-icon-width, 24px); - height: var(--iron-icon-height, 24px); - animation: var(--iron-icon_-_animation); + flex: var(--ytmusic-menu-item-icon_-_flex); + margin: var(--ytmusic-menu-item-icon_-_margin); + fill: var(--ytmusic-menu-item-icon_-_fill); + stroke: var(--iron-icon-stroke-color, none); + width: var(--iron-icon-width, 24px); + height: var(--iron-icon-height, 24px); + animation: var(--iron-icon_-_animation); } diff --git a/plugins/downloader/templates/download.html b/plugins/downloader/templates/download.html index ede5ec02..4079a4f5 100644 --- a/plugins/downloader/templates/download.html +++ b/plugins/downloader/templates/download.html @@ -1,45 +1,45 @@ diff --git a/plugins/downloader/utils.js b/plugins/downloader/utils.js deleted file mode 100644 index 6b9c449b..00000000 --- a/plugins/downloader/utils.js +++ /dev/null @@ -1,38 +0,0 @@ -const { app } = require("electron"); -const is = require('electron-is'); - -module.exports.getFolder = customFolder => customFolder || app.getPath("downloads"); -module.exports.defaultMenuDownloadLabel = "Download playlist"; - -module.exports.sendFeedback = (win, message) => { - win.webContents.send("downloader-feedback", message); -}; - -module.exports.cropMaxWidth = (image) => { - const imageSize = image.getSize(); - // standart youtube artwork width with margins from both sides is 280 + 720 + 280 - if (imageSize.width === 1280 && imageSize.height === 720) { - return image.crop({ - x: 280, - y: 0, - width: 720, - height: 720 - }); - } - return image; -} - -// Presets for FFmpeg -module.exports.presets = { - "None (defaults to mp3)": undefined, - opus: { - extension: "opus", - ffmpegArgs: ["-acodec", "libopus"], - }, -}; - -module.exports.setBadge = n => { - if (is.linux() || is.macOS()) { - app.setBadgeCount(n); - } -} diff --git a/plugins/downloader/utils.ts b/plugins/downloader/utils.ts new file mode 100644 index 00000000..7de1f096 --- /dev/null +++ b/plugins/downloader/utils.ts @@ -0,0 +1,39 @@ +import { app, BrowserWindow } from 'electron'; +import is from 'electron-is'; + +export const getFolder = (customFolder: string) => customFolder || app.getPath('downloads'); +export const defaultMenuDownloadLabel = 'Download playlist'; + +export const sendFeedback = (win: BrowserWindow, message?: unknown) => { + win.webContents.send('downloader-feedback', message); +}; + +export const cropMaxWidth = (image: Electron.NativeImage) => { + const imageSize = image.getSize(); + // Standart youtube artwork width with margins from both sides is 280 + 720 + 280 + if (imageSize.width === 1280 && imageSize.height === 720) { + return image.crop({ + x: 280, + y: 0, + width: 720, + height: 720, + }); + } + + return image; +}; + +// Presets for FFmpeg +export const presets = { + 'None (defaults to mp3)': undefined, + 'opus': { + extension: 'opus', + ffmpegArgs: ['-acodec', 'libopus'], + }, +}; + +export const setBadge = (n: number) => { + if (is.linux() || is.macOS()) { + app.setBadgeCount(n); + } +}; diff --git a/plugins/exponential-volume/front.js b/plugins/exponential-volume/front.js deleted file mode 100644 index ad50d237..00000000 --- a/plugins/exponential-volume/front.js +++ /dev/null @@ -1,47 +0,0 @@ -// "Youtube Music fix volume ratio 0.4" by Marco Pfeiffer -// https://greasyfork.org/en/scripts/397686-youtube-music-fix-volume-ratio/ - -const exponentialVolume = () => { - // manipulation exponent, higher value = lower volume - // 3 is the value used by pulseaudio, which Barteks2x figured out this gist here: https://gist.github.com/Barteks2x/a4e189a36a10c159bb1644ffca21c02a - // 0.05 (or 5%) is the lowest you can select in the UI which with an exponent of 3 becomes 0.000125 or 0.0125% - const EXPONENT = 3; - - const storedOriginalVolumes = new WeakMap(); - const { get, set } = Object.getOwnPropertyDescriptor( - HTMLMediaElement.prototype, - "volume" - ); - Object.defineProperty(HTMLMediaElement.prototype, "volume", { - get() { - const lowVolume = get.call(this); - const calculatedOriginalVolume = lowVolume ** (1 / EXPONENT); - - // The calculated value has some accuracy issues which can lead to problems for implementations that expect exact values. - // To avoid this, I'll store the unmodified volume to return it when read here. - // This mostly solves the issue, but the initial read has no stored value and the volume can also change though external influences. - // To avoid ill effects, I check if the stored volume is somewhere in the same range as the calculated volume. - const storedOriginalVolume = storedOriginalVolumes.get(this); - const storedDeviation = Math.abs( - storedOriginalVolume - calculatedOriginalVolume - ); - - const originalVolume = - storedDeviation < 0.01 - ? storedOriginalVolume - : calculatedOriginalVolume; - return originalVolume; - }, - set(originalVolume) { - const lowVolume = originalVolume ** EXPONENT; - storedOriginalVolumes.set(this, originalVolume); - set.call(this, lowVolume); - }, - }); -}; - -module.exports = () => - document.addEventListener("apiLoaded", exponentialVolume, { - once: true, - passive: true, - }); diff --git a/plugins/exponential-volume/front.ts b/plugins/exponential-volume/front.ts new file mode 100644 index 00000000..3f2c5d0c --- /dev/null +++ b/plugins/exponential-volume/front.ts @@ -0,0 +1,45 @@ +// "YouTube Music fix volume ratio 0.4" by Marco Pfeiffer +// https://greasyfork.org/en/scripts/397686-youtube-music-fix-volume-ratio/ + +const exponentialVolume = () => { + // Manipulation exponent, higher value = lower volume + // 3 is the value used by pulseaudio, which Barteks2x figured out this gist here: https://gist.github.com/Barteks2x/a4e189a36a10c159bb1644ffca21c02a + // 0.05 (or 5%) is the lowest you can select in the UI which with an exponent of 3 becomes 0.000125 or 0.0125% + const EXPONENT = 3; + + const storedOriginalVolumes = new WeakMap(); + const propertyDescriptor = Object.getOwnPropertyDescriptor( + HTMLMediaElement.prototype, + 'volume', + ); + Object.defineProperty(HTMLMediaElement.prototype, 'volume', { + get(this: HTMLMediaElement) { + const lowVolume = propertyDescriptor?.get?.call(this) as number ?? 0; + const calculatedOriginalVolume = lowVolume ** (1 / EXPONENT); + + // The calculated value has some accuracy issues which can lead to problems for implementations that expect exact values. + // To avoid this, I'll store the unmodified volume to return it when read here. + // This mostly solves the issue, but the initial read has no stored value and the volume can also change though external influences. + // To avoid ill effects, I check if the stored volume is somewhere in the same range as the calculated volume. + const storedOriginalVolume = storedOriginalVolumes.get(this) ?? 0; + const storedDeviation = Math.abs( + storedOriginalVolume - calculatedOriginalVolume, + ); + + return storedDeviation < 0.01 + ? storedOriginalVolume + : calculatedOriginalVolume; + }, + set(this: HTMLMediaElement, originalVolume: number) { + const lowVolume = originalVolume ** EXPONENT; + storedOriginalVolumes.set(this, originalVolume); + propertyDescriptor?.set?.call(this, lowVolume); + }, + }); +}; + +export default () => + document.addEventListener('apiLoaded', exponentialVolume, { + once: true, + passive: true, + }); diff --git a/plugins/in-app-menu/back.js b/plugins/in-app-menu/back.js deleted file mode 100644 index d0a54605..00000000 --- a/plugins/in-app-menu/back.js +++ /dev/null @@ -1,23 +0,0 @@ -const path = require("path"); - -const electronLocalshortcut = require("electron-localshortcut"); - -const { injectCSS } = require("../utils"); - -const { setupTitlebar, attachTitlebarToWindow } = require('custom-electron-titlebar/main'); -setupTitlebar(); - -//tracks menu visibility - -module.exports = (win) => { - // css for custom scrollbar + disable drag area(was causing bugs) - injectCSS(win.webContents, path.join(__dirname, "style.css")); - - win.once("ready-to-show", () => { - attachTitlebarToWindow(win); - - electronLocalshortcut.register(win, "`", () => { - win.webContents.send("toggleMenu"); - }); - }); -}; diff --git a/plugins/in-app-menu/back.ts b/plugins/in-app-menu/back.ts new file mode 100644 index 00000000..61a00cbd --- /dev/null +++ b/plugins/in-app-menu/back.ts @@ -0,0 +1,27 @@ +import path from 'node:path'; + +import { register } from 'electron-localshortcut'; +// eslint-disable-next-line import/no-unresolved +import { attachTitlebarToWindow, setupTitlebar } from 'custom-electron-titlebar/main'; + +import { BrowserWindow } from 'electron'; + +import { injectCSS } from '../utils'; + + +setupTitlebar(); + +// Tracks menu visibility + +export default (win: BrowserWindow) => { + // Css for custom scrollbar + disable drag area(was causing bugs) + injectCSS(win.webContents, path.join(__dirname, 'style.css')); + + win.once('ready-to-show', () => { + attachTitlebarToWindow(win); + + register(win, '`', () => { + win.webContents.send('toggleMenu'); + }); + }); +}; diff --git a/plugins/in-app-menu/custom-electron-titlebar.d.ts b/plugins/in-app-menu/custom-electron-titlebar.d.ts new file mode 100644 index 00000000..f724278d --- /dev/null +++ b/plugins/in-app-menu/custom-electron-titlebar.d.ts @@ -0,0 +1,9 @@ +declare module 'custom-electron-titlebar' { + // eslint-disable-next-line import/no-unresolved + import OriginalTitlebar from 'custom-electron-titlebar/dist/titlebar'; + // eslint-disable-next-line import/no-unresolved + import { Color as OriginalColor } from 'custom-electron-titlebar/dist/vs/base/common/color'; + + export const Color: typeof OriginalColor; + export const Titlebar: typeof OriginalTitlebar; +} diff --git a/plugins/in-app-menu/front.js b/plugins/in-app-menu/front.js deleted file mode 100644 index e0fcfded..00000000 --- a/plugins/in-app-menu/front.js +++ /dev/null @@ -1,74 +0,0 @@ -const { ipcRenderer } = require("electron"); -const config = require("../../config"); -const { Titlebar, Color } = require("custom-electron-titlebar"); -const { isEnabled } = require("../../config/plugins"); -function $(selector) { return document.querySelector(selector); } - -module.exports = (options) => { - let visible = () => !!$('.cet-menubar').firstChild; - const bar = new Titlebar({ - icon: "https://cdn-icons-png.flaticon.com/512/5358/5358672.png", - backgroundColor: Color.fromHex("#050505"), - itemBackgroundColor: Color.fromHex("#1d1d1d"), - svgColor: Color.WHITE, - menu: config.get("options.hideMenu") ? null : undefined - }); - bar.updateTitle(" "); - document.title = "Youtube Music"; - - const toggleMenu = () => { - if (visible()) { - bar.updateMenu(null); - } else { - bar.refreshMenu(); - } - }; - - $('.cet-window-icon').addEventListener('click', toggleMenu); - ipcRenderer.on("toggleMenu", toggleMenu); - - ipcRenderer.on("refreshMenu", () => { - if (visible()) { - bar.refreshMenu(); - } - }); - - if (isEnabled("picture-in-picture")) { - ipcRenderer.on("pip-toggle", (_, pipEnabled) => { - bar.refreshMenu(); - }); - } - - // Increases the right margin of Navbar background when the scrollbar is visible to avoid blocking it (z-index doesn't affect it) - document.addEventListener('apiLoaded', () => { - setNavbarMargin(); - const playPageObserver = new MutationObserver(setNavbarMargin); - playPageObserver.observe($('ytmusic-app-layout'), { attributeFilter: ['player-page-open_', 'playerPageOpen_'] }) - setupSearchOpenObserver(); - setupMenuOpenObserver(); - }, { once: true, passive: true }) -}; - -function setupSearchOpenObserver() { - const searchOpenObserver = new MutationObserver(mutations => { - $('#nav-bar-background').style.webkitAppRegion = - mutations[0].target.opened ? 'no-drag' : 'drag'; - }); - searchOpenObserver.observe($('ytmusic-search-box'), { attributeFilter: ["opened"] }) -} - -function setupMenuOpenObserver() { - const menuOpenObserver = new MutationObserver(mutations => { - $('#nav-bar-background').style.webkitAppRegion = - Array.from($('.cet-menubar').childNodes).some(c => c.classList.contains('open')) ? - 'no-drag' : 'drag'; - }); - menuOpenObserver.observe($('.cet-menubar'), { subtree: true, attributeFilter: ["class"] }) -} - -function setNavbarMargin() { - $('#nav-bar-background').style.right = - $('ytmusic-app-layout').playerPageOpen_ ? - '0px' : - '12px'; -} diff --git a/plugins/in-app-menu/front.ts b/plugins/in-app-menu/front.ts new file mode 100644 index 00000000..fc7640ce --- /dev/null +++ b/plugins/in-app-menu/front.ts @@ -0,0 +1,104 @@ +import { ipcRenderer, Menu } from 'electron'; +// eslint-disable-next-line import/no-unresolved +import { Color, Titlebar } from 'custom-electron-titlebar'; + +import config from '../../config'; +import { isEnabled } from '../../config/plugins'; + +type ElectronCSSStyleDeclaration = CSSStyleDeclaration & { webkitAppRegion: 'drag' | 'no-drag' }; +type ElectronHTMLElement = HTMLElement & { style: ElectronCSSStyleDeclaration }; + +function $(selector: string) { + return document.querySelector(selector); +} + +export default () => { + const visible = () => !!($('.cet-menubar')?.firstChild); + const bar = new Titlebar({ + icon: 'https://cdn-icons-png.flaticon.com/512/5358/5358672.png', + backgroundColor: Color.fromHex('#050505'), + itemBackgroundColor: Color.fromHex('#1d1d1d') , + svgColor: Color.WHITE, + menu: config.get('options.hideMenu') ? null as unknown as Menu : undefined, + }); + bar.updateTitle(' '); + document.title = 'Youtube Music'; + + const toggleMenu = () => { + if (visible()) { + bar.updateMenu(null as unknown as Menu); + } else { + bar.refreshMenu(); + } + }; + + $('.cet-window-icon')?.addEventListener('click', toggleMenu); + ipcRenderer.on('toggleMenu', toggleMenu); + + ipcRenderer.on('refreshMenu', () => { + if (visible()) { + bar.refreshMenu(); + } + }); + + if (isEnabled('picture-in-picture')) { + ipcRenderer.on('pip-toggle', () => { + bar.refreshMenu(); + }); + } + + // Increases the right margin of Navbar background when the scrollbar is visible to avoid blocking it (z-index doesn't affect it) + document.addEventListener('apiLoaded', () => { + setNavbarMargin(); + const playPageObserver = new MutationObserver(setNavbarMargin); + const appLayout = $('ytmusic-app-layout'); + if (appLayout) { + playPageObserver.observe(appLayout, { attributeFilter: ['player-page-open_', 'playerPageOpen_'] }); + } + setupSearchOpenObserver(); + setupMenuOpenObserver(); + }, { once: true, passive: true }); +}; + +function setupSearchOpenObserver() { + const searchOpenObserver = new MutationObserver((mutations) => { + const navBarBackground = $('#nav-bar-background'); + if (navBarBackground) { + navBarBackground.style.webkitAppRegion = (mutations[0].target as HTMLElement & { opened: boolean }).opened ? 'no-drag' : 'drag'; + } + }); + const searchBox = $('ytmusic-search-box'); + if (searchBox) { + searchOpenObserver.observe(searchBox, { attributeFilter: ['opened'] }); + } +} + +function setupMenuOpenObserver() { + const cetMenubar = $('.cet-menubar'); + if (cetMenubar) { + const menuOpenObserver = new MutationObserver(() => { + let isOpen = false; + for (const child of cetMenubar.children) { + if (child.classList.contains('open')) { + isOpen = true; + break; + } + } + const navBarBackground = $('#nav-bar-background'); + if (navBarBackground) { + navBarBackground.style.webkitAppRegion = isOpen ? 'no-drag' : 'drag'; + } + }); + menuOpenObserver.observe(cetMenubar, { subtree: true, attributeFilter: ['class'] }); + } +} + +function setNavbarMargin() { + const navBarBackground = $('#nav-bar-background'); + if (navBarBackground) { + navBarBackground.style.right + = $('ytmusic-app-layout')?.playerPageOpen_ + ? '0px' + : '12px'; + } +} diff --git a/plugins/in-app-menu/style.css b/plugins/in-app-menu/style.css index f0f31ed8..7cfa4486 100644 --- a/plugins/in-app-menu/style.css +++ b/plugins/in-app-menu/style.css @@ -1,105 +1,107 @@ /* increase font size for menu and menuItems */ .titlebar, .menubar-menu-container .action-label { - font-size: 14px !important; + font-size: 14px !important; } /* fixes nav-bar-background opacity bug, reposition it, and allows clicking scrollbar through it */ #nav-bar-background { - opacity: 1 !important; - pointer-events: none !important; - top: 30px !important; - height: 75px !important; + opacity: 1 !important; + pointer-events: none !important; + top: 30px !important; + height: 75px !important; } /* fix top gap between nav-bar and browse-page */ #browse-page { - padding-top: 0 !important; + padding-top: 0 !important; } /* fix navbar hiding library items */ ytmusic-section-list-renderer[page-type="MUSIC_PAGE_TYPE_LIBRARY_CONTENT_LANDING_PAGE"], ytmusic-section-list-renderer[page-type="MUSIC_PAGE_TYPE_PRIVATELY_OWNED_CONTENT_LANDING_PAGE"] { - top: 50px; - position: relative; + top: 50px; + position: relative; } /* remove window dragging for nav bar (conflict with titlebar drag) */ ytmusic-nav-bar, .tab-titleiron-icon, ytmusic-pivot-bar-item-renderer { - -webkit-app-region: unset !important; + -webkit-app-region: unset !important; } /* move up item selection renderers */ ytmusic-item-section-renderer.stuck #header.ytmusic-item-section-renderer, ytmusic-tabs.stuck { - top: calc(var(--ytmusic-nav-bar-height) - 15px) !important; + top: calc(var(--ytmusic-nav-bar-height) - 15px) !important; } /* fix weird positioning in search screen*/ ytmusic-header-renderer.ytmusic-search-page { - position: unset !important; + position: unset !important; } /* Move navBar downwards */ ytmusic-nav-bar[slot="nav-bar"] { - top: 17px !important; + top: 17px !important; } /* fix page progress bar position*/ yt-page-navigation-progress, #progress.yt-page-navigation-progress { - top: 30px !important; + top: 30px !important; } /* custom scrollbar */ ::-webkit-scrollbar { - width: 12px; - background-color: #030303; - border-radius: 100px; - -moz-border-radius: 100px; - -webkit-border-radius: 100px; + width: 12px; + background-color: #030303; + border-radius: 100px; + -moz-border-radius: 100px; + -webkit-border-radius: 100px; } + /* hover effect for both scrollbar area, and scrollbar 'thumb' */ ::-webkit-scrollbar:hover { - background-color: rgba(15, 15, 15, 0.699); + background-color: rgba(15, 15, 15, 0.699); } /* the scrollbar 'thumb' ...that marque oval shape in a scrollbar */ ::-webkit-scrollbar-thumb:vertical { - border: 2px solid rgba(0, 0, 0, 0); + border: 2px solid rgba(0, 0, 0, 0); - background: #3a3a3a; - background-clip: padding-box; - border-radius: 100px; - -moz-border-radius: 100px; - -webkit-border-radius: 100px; + background: #3a3a3a; + background-clip: padding-box; + border-radius: 100px; + -moz-border-radius: 100px; + -webkit-border-radius: 100px; } + ::-webkit-scrollbar-thumb:vertical:active { - background: #4d4c4c; /* some darker color when you click it */ - border-radius: 100px; - -moz-border-radius: 100px; - -webkit-border-radius: 100px; + background: #4d4c4c; /* some darker color when you click it */ + border-radius: 100px; + -moz-border-radius: 100px; + -webkit-border-radius: 100px; } .cet-menubar-menu-container .cet-action-item { - background-color: inherit + background-color: inherit } /** hideMenu toggler **/ .cet-window-icon { - -webkit-app-region: no-drag; + -webkit-app-region: no-drag; } .cet-window-icon img { - -webkit-user-drag: none; - filter: invert(50%); + -webkit-user-drag: none; + filter: invert(50%); } /** make navbar draggable **/ #nav-bar-background { - -webkit-app-region: drag; + -webkit-app-region: drag; } ytmusic-nav-bar input, @@ -107,5 +109,5 @@ ytmusic-nav-bar span, ytmusic-nav-bar [role="button"], ytmusic-nav-bar yt-icon, tp-yt-iron-dropdown { - -webkit-app-region: no-drag; + -webkit-app-region: no-drag; } diff --git a/plugins/last-fm/back.js b/plugins/last-fm/back.js deleted file mode 100644 index a0533d17..00000000 --- a/plugins/last-fm/back.js +++ /dev/null @@ -1,161 +0,0 @@ -const fetch = require('node-fetch'); -const md5 = require('md5'); -const { shell } = require('electron'); -const { setOptions } = require('../../config/plugins'); -const registerCallback = require('../../providers/song-info'); -const defaultConfig = require('../../config/defaults'); - -const createFormData = params => { - // creates the body for in the post request - const formData = new URLSearchParams(); - for (const key in params) { - formData.append(key, params[key]); - } - return formData; -} -const createQueryString = (params, api_sig) => { - // creates a querystring - const queryData = []; - params.api_sig = api_sig; - for (const key in params) { - queryData.push(`${encodeURIComponent(key)}=${encodeURIComponent(params[key])}`); - } - return '?'+queryData.join('&'); -} - -const createApiSig = (params, secret) => { - // this function creates the api signature, see: https://www.last.fm/api/authspec - const keys = []; - for (const key in params) { - keys.push(key); - } - keys.sort(); - let sig = ''; - for (const key of keys) { - if (String(key) === 'format') - continue - sig += `${key}${params[key]}`; - } - sig += secret; - sig = md5(sig); - return sig; -} - -const createToken = async ({ api_key, api_root, secret }) => { - // creates and stores the auth token - const data = { - method: 'auth.gettoken', - api_key: api_key, - format: 'json' - }; - const api_sig = createApiSig(data, secret); - let response = await fetch(`${api_root}${createQueryString(data, api_sig)}`); - response = await response.json(); - return response?.token; -} - -const authenticate = async config => { - // asks the user for authentication - config.token = await createToken(config); - setOptions('last-fm', config); - shell.openExternal(`https://www.last.fm/api/auth/?api_key=${config.api_key}&token=${config.token}`); - return config; -} - -const getAndSetSessionKey = async config => { - // get and store the session key - const data = { - api_key: config.api_key, - format: 'json', - method: 'auth.getsession', - token: config.token, - }; - const api_sig = createApiSig(data, config.secret); - let res = await fetch(`${config.api_root}${createQueryString(data, api_sig)}`); - res = await res.json(); - if (res.error) - await authenticate(config); - config.session_key = res?.session?.key; - setOptions('last-fm', config); - return config; -} - -const postSongDataToAPI = async (songInfo, config, data) => { - // this sends a post request to the api, and adds the common data - if (!config.session_key) - await getAndSetSessionKey(config); - - const postData = { - track: songInfo.title, - duration: songInfo.songDuration, - artist: songInfo.artist, - ...(songInfo.album ? { album: songInfo.album } : undefined), // will be undefined if current song is a video - api_key: config.api_key, - sk: config.session_key, - format: 'json', - ...data, - }; - - postData.api_sig = createApiSig(postData, config.secret); - fetch('https://ws.audioscrobbler.com/2.0/', {method: 'POST', body: createFormData(postData)}) - .catch(res => { - if (res.response.data.error == 9) { - // session key is invalid, so remove it from the config and reauthenticate - config.session_key = undefined; - setOptions('last-fm', config); - authenticate(config); - } - }); -} - -const addScrobble = (songInfo, config) => { - // this adds one scrobbled song to last.fm - const data = { - method: 'track.scrobble', - timestamp: ~~((Date.now() - songInfo.elapsedSeconds) / 1000), - }; - postSongDataToAPI(songInfo, config, data); -} - -const setNowPlaying = (songInfo, config) => { - // this sets the now playing status in last.fm - const data = { - method: 'track.updateNowPlaying', - }; - postSongDataToAPI(songInfo, config, data); -} - - -// this will store the timeout that will trigger addScrobble -let scrobbleTimer = undefined; - -const lastfm = async (_win, config) => { - if (!config.api_root) { - // settings are not present, creating them with the default values - config = defaultConfig.plugins['last-fm']; - config.enabled = true; - setOptions('last-fm', config); - } - - if (!config.session_key) { - // not authenticated - config = await getAndSetSessionKey(config); - } - - registerCallback( songInfo => { - // set remove the old scrobble timer - clearTimeout(scrobbleTimer); - if (!songInfo.isPaused) { - setNowPlaying(songInfo, config); - // scrobble when the song is half way through, or has passed the 4 minute mark - const scrobbleTime = Math.min(Math.ceil(songInfo.songDuration / 2), 4 * 60); - if (scrobbleTime > songInfo.elapsedSeconds) { - // scrobble still needs to happen - const timeToWait = (scrobbleTime - songInfo.elapsedSeconds) * 1000; - scrobbleTimer = setTimeout(addScrobble, timeToWait, songInfo, config); - } - } - }); -} - -module.exports = lastfm; diff --git a/plugins/last-fm/back.ts b/plugins/last-fm/back.ts new file mode 100644 index 00000000..e5826356 --- /dev/null +++ b/plugins/last-fm/back.ts @@ -0,0 +1,189 @@ +import crypto from 'node:crypto'; + +import { BrowserWindow, net, shell } from 'electron'; + +import { setOptions } from '../../config/plugins'; +import registerCallback, { SongInfo } from '../../providers/song-info'; +import defaultConfig from '../../config/defaults'; + +import type { ConfigType } from '../../config/dynamic'; + +type LastFMOptions = ConfigType<'last-fm'>; + +interface LastFmData { + method: string, + timestamp?: number, +} + +const createFormData = (parameters: Record) => { + // Creates the body for in the post request + const formData = new URLSearchParams(); + for (const key in parameters) { + formData.append(key, String(parameters[key])); + } + + return formData; +}; + +const createQueryString = (parameters: Record, apiSignature: string) => { + // Creates a querystring + const queryData = []; + parameters.api_sig = apiSignature; + for (const key in parameters) { + queryData.push(`${encodeURIComponent(key)}=${encodeURIComponent(String(parameters[key]))}`); + } + + return '?' + queryData.join('&'); +}; + +const createApiSig = (parameters: Record, secret: string) => { + // This function creates the api signature, see: https://www.last.fm/api/authspec + const keys = Object.keys(parameters); + + keys.sort(); + let sig = ''; + for (const key of keys) { + if (String(key) === 'format') { + continue; + } + + sig += `${key}${String(parameters[key])}`; + } + + sig += secret; + sig = crypto.createHash('md5').update(sig, 'utf-8').digest('hex'); + return sig; +}; + +const createToken = async ({ api_key: apiKey, api_root: apiRoot, secret }: LastFMOptions) => { + // Creates and stores the auth token + const data = { + method: 'auth.gettoken', + apiKey, + format: 'json', + }; + const apiSigature = createApiSig(data, secret); + const response = await net.fetch(`${apiRoot}${createQueryString(data, apiSigature)}`); + const json = await response.json() as Record; + return json?.token; +}; + +const authenticateAndGetToken = async (config: LastFMOptions) => { + // Asks the user for authentication + await shell.openExternal(`https://www.last.fm/api/auth/?api_key=${config.api_key}&token=${config.token}`); + return await createToken(config); +}; + +const getAndSetSessionKey = async (config: LastFMOptions) => { + // Get and store the session key + const data = { + api_key: config.api_key, + format: 'json', + method: 'auth.getsession', + token: config.token, + }; + const apiSignature = createApiSig(data, config.secret); + const response = await net.fetch(`${config.api_root}${createQueryString(data, apiSignature)}`); + const json = await response.json() as { + error?: string, + session?: { + key: string, + } + }; + if (json.error) { + config.token = await authenticateAndGetToken(config); + setOptions('last-fm', config); + } + if (json.session) { + config.session_key = json?.session?.key; + setOptions('last-fm', config); + } + return config; +}; + +const postSongDataToAPI = async (songInfo: SongInfo, config: LastFMOptions, data: LastFmData) => { + // This sends a post request to the api, and adds the common data + if (!config.session_key) { + await getAndSetSessionKey(config); + } + + const postData = { + track: songInfo.title, + duration: songInfo.songDuration, + artist: songInfo.artist, + ...(songInfo.album ? { album: songInfo.album } : undefined), // Will be undefined if current song is a video + api_key: config.api_key, + api_sig: '', + sk: config.session_key, + format: 'json', + ...data, + }; + + postData.api_sig = createApiSig(postData, config.secret); + net.fetch('https://ws.audioscrobbler.com/2.0/', { method: 'POST', body: createFormData(postData) }) + .catch(async (error: { + response?: { + data?: { + error: number, + } + } + }) => { + if (error?.response?.data?.error === 9) { + // Session key is invalid, so remove it from the config and reauthenticate + config.session_key = undefined; + config.token = await authenticateAndGetToken(config); + setOptions('last-fm', config); + } + }); +}; + +const addScrobble = (songInfo: SongInfo, config: LastFMOptions) => { + // This adds one scrobbled song to last.fm + const data = { + method: 'track.scrobble', + timestamp: Math.trunc((Date.now() - (songInfo.elapsedSeconds ?? 0)) / 1000), + }; + postSongDataToAPI(songInfo, config, data); +}; + +const setNowPlaying = (songInfo: SongInfo, config: LastFMOptions) => { + // This sets the now playing status in last.fm + const data = { + method: 'track.updateNowPlaying', + }; + postSongDataToAPI(songInfo, config, data); +}; + +// This will store the timeout that will trigger addScrobble +let scrobbleTimer: NodeJS.Timeout | undefined; + +const lastfm = async (_win: BrowserWindow, config: LastFMOptions) => { + if (!config.api_root) { + // Settings are not present, creating them with the default values + config = defaultConfig.plugins['last-fm']; + config.enabled = true; + setOptions('last-fm', config); + } + + if (!config.session_key) { + // Not authenticated + config = await getAndSetSessionKey(config); + } + + registerCallback((songInfo) => { + // Set remove the old scrobble timer + clearTimeout(scrobbleTimer); + if (!songInfo.isPaused) { + setNowPlaying(songInfo, config); + // Scrobble when the song is halfway through, or has passed the 4-minute mark + const scrobbleTime = Math.min(Math.ceil(songInfo.songDuration / 2), 4 * 60); + if (scrobbleTime > (songInfo.elapsedSeconds ?? 0)) { + // Scrobble still needs to happen + const timeToWait = (scrobbleTime - (songInfo.elapsedSeconds ?? 0)) * 1000; + scrobbleTimer = setTimeout(addScrobble, timeToWait, songInfo, config); + } + } + }); +}; + +export default lastfm; diff --git a/plugins/lyrics-genius/back.js b/plugins/lyrics-genius/back.js deleted file mode 100644 index cb781ca8..00000000 --- a/plugins/lyrics-genius/back.js +++ /dev/null @@ -1,117 +0,0 @@ -const { join } = require("path"); - -const { ipcMain } = require("electron"); -const is = require("electron-is"); -const { convert } = require("html-to-text"); -const fetch = require("node-fetch"); - -const { cleanupName } = require("../../providers/song-info"); -const { injectCSS } = require("../utils"); -let eastAsianChars = /\p{Script=Han}|\p{Script=Katakana}|\p{Script=Hiragana}|\p{Script=Hangul}|\p{Script=Han}/u; -let revRomanized = false; - -module.exports = async (win, options) => { - if(options.romanizedLyrics) { - revRomanized = true; - } - injectCSS(win.webContents, join(__dirname, "style.css")); - - ipcMain.on("search-genius-lyrics", async (event, extractedSongInfo) => { - const metadata = JSON.parse(extractedSongInfo); - event.returnValue = await fetchFromGenius(metadata); - }); -}; - -const toggleRomanized = () => { - revRomanized = !revRomanized; -}; - -const fetchFromGenius = async (metadata) => { - const songTitle = `${cleanupName(metadata.title)}`; - const songArtist = `${cleanupName(metadata.artist)}`; - let lyrics; - - /* Uses Regex to test the title and artist first for said characters if romanization is enabled. Otherwise normal - Genius Lyrics behavior is observed. - */ - let hasAsianChars = false; - if (revRomanized && (eastAsianChars.test(songTitle) || eastAsianChars.test(songArtist))) { - lyrics = await getLyricsList(`${songArtist} ${songTitle} Romanized`); - hasAsianChars = true; - } else { - lyrics = await getLyricsList(`${songArtist} ${songTitle}`); - } - - /* If the romanization toggle is on, and we did not detect any characters in the title or artist, we do a check - for characters in the lyrics themselves. If this check proves true, we search for Romanized lyrics. - */ - if(revRomanized && !hasAsianChars && eastAsianChars.test(lyrics)) { - lyrics = await getLyricsList(`${songArtist} ${songTitle} Romanized`); - } - return lyrics; -}; - -/** - * Fetches a JSON of songs which is then parsed and passed into getLyrics to get the lyrical content of the first song - * @param {*} queryString - * @returns The lyrics of the first song found using the Genius-Lyrics API - */ -const getLyricsList = async (queryString) => { - let response = await fetch( - `https://genius.com/api/search/multi?per_page=5&q=${encodeURIComponent(queryString)}` - ); - if (!response.ok) { - return null; - } - - /* Fetch the first URL with the api, giving a collection of song results. - Pick the first song, parsing the json given by the API. - */ - const info = await response.json(); - let url = ""; - try { - url = info.response.sections.filter((section) => section.type === "song")[0] - .hits[0].result.url; - } catch { - return null; - } - let lyrics = await getLyrics(url); - return lyrics; -} - -/** - * - * @param {*} url - * @returns The lyrics of the song URL provided, null if none - */ -const getLyrics = async (url) => { - response = await fetch(url); - if (!response.ok) { - return null; - } - if (is.dev()) { - console.log("Fetching lyrics from Genius:", url); - } - const html = await response.text(); - const lyrics = convert(html, { - baseElements: { - selectors: ['[class^="Lyrics__Container"]', ".lyrics"], - }, - selectors: [ - { - selector: "a", - format: "linkFormatter", - }, - ], - formatters: { - // Remove links by keeping only the content - linkFormatter: (elem, walk, builder) => { - walk(elem.children, builder); - }, - }, - }); - return lyrics; -}; - -module.exports.toggleRomanized = toggleRomanized; -module.exports.fetchFromGenius = fetchFromGenius; \ No newline at end of file diff --git a/plugins/lyrics-genius/back.ts b/plugins/lyrics-genius/back.ts new file mode 100644 index 00000000..a4da0d3d --- /dev/null +++ b/plugins/lyrics-genius/back.ts @@ -0,0 +1,125 @@ +import { join } from 'node:path'; + +import { BrowserWindow, ipcMain, net } from 'electron'; +import is from 'electron-is'; +import { convert } from 'html-to-text'; + +import { GetGeniusLyric } from './types'; + +import { cleanupName, SongInfo } from '../../providers/song-info'; + +import { injectCSS } from '../utils'; + +import type { ConfigType } from '../../config/dynamic'; + +const eastAsianChars = /\p{Script=Katakana}|\p{Script=Hiragana}|\p{Script=Hangul}|\p{Script=Han}/u; +let revRomanized = false; + +export type LyricGeniusType = ConfigType<'lyric-genius'>; + +export default (win: BrowserWindow, options: LyricGeniusType) => { + if (options.romanizedLyrics) { + revRomanized = true; + } + + injectCSS(win.webContents, join(__dirname, 'style.css')); + + ipcMain.handle('search-genius-lyrics', async (_, extractedSongInfo: SongInfo) => { + const metadata = extractedSongInfo; + return await fetchFromGenius(metadata); + }); +}; + +export const toggleRomanized = () => { + revRomanized = !revRomanized; +}; + +export const fetchFromGenius = async (metadata: SongInfo) => { + const songTitle = `${cleanupName(metadata.title)}`; + const songArtist = `${cleanupName(metadata.artist)}`; + let lyrics: string | null; + + /* Uses Regex to test the title and artist first for said characters if romanization is enabled. Otherwise normal + Genius Lyrics behavior is observed. + */ + let hasAsianChars = false; + if (revRomanized && (eastAsianChars.test(songTitle) || eastAsianChars.test(songArtist))) { + lyrics = await getLyricsList(`${songArtist} ${songTitle} Romanized`); + hasAsianChars = true; + } else { + lyrics = await getLyricsList(`${songArtist} ${songTitle}`); + } + + /* If the romanization toggle is on, and we did not detect any characters in the title or artist, we do a check + for characters in the lyrics themselves. If this check proves true, we search for Romanized lyrics. + */ + if (revRomanized && !hasAsianChars && lyrics && eastAsianChars.test(lyrics)) { + lyrics = await getLyricsList(`${songArtist} ${songTitle} Romanized`); + } + + return lyrics; +}; + +/** + * Fetches a JSON of songs which is then parsed and passed into getLyrics to get the lyrical content of the first song + * @param {*} queryString + * @returns The lyrics of the first song found using the Genius-Lyrics API + */ +const getLyricsList = async (queryString: string): Promise => { + const response = await net.fetch( + `https://genius.com/api/search/multi?per_page=5&q=${encodeURIComponent(queryString)}`, + ); + if (!response.ok) { + return null; + } + + /* Fetch the first URL with the api, giving a collection of song results. + Pick the first song, parsing the json given by the API. + */ + const info = await response.json() as GetGeniusLyric; + const url = info + ?.response + ?.sections + ?.find((section) => section.type === 'song')?.hits[0]?.result?.url; + + if (url) { + return await getLyrics(url); + } else { + return null; + } +}; + +/** + * + * @param {*} url + * @returns The lyrics of the song URL provided, null if none + */ +const getLyrics = async (url: string): Promise => { + const response = await net.fetch(url); + if (!response.ok) { + return null; + } + + if (is.dev()) { + console.log('Fetching lyrics from Genius:', url); + } + + const html = await response.text(); + return convert(html, { + baseElements: { + selectors: ['[class^="Lyrics__Container"]', '.lyrics'], + }, + selectors: [ + { + selector: 'a', + format: 'linkFormatter', + }, + ], + formatters: { + // Remove links by keeping only the content + linkFormatter(element, walk, builder) { + walk(element.children, builder); + }, + }, + }); +}; diff --git a/plugins/lyrics-genius/front.js b/plugins/lyrics-genius/front.js deleted file mode 100644 index 5725d1e1..00000000 --- a/plugins/lyrics-genius/front.js +++ /dev/null @@ -1,94 +0,0 @@ -const { ipcRenderer } = require("electron"); -const is = require("electron-is"); - -module.exports = () => { - ipcRenderer.on("update-song-info", (_, extractedSongInfo) => setTimeout(() => { - const tabList = document.querySelectorAll("tp-yt-paper-tab"); - const tabs = { - upNext: tabList[0], - lyrics: tabList[1], - discover: tabList[2], - } - - // Check if disabled - if (!tabs.lyrics?.hasAttribute("disabled")) { - return; - } - - let hasLyrics = true; - - const lyrics = ipcRenderer.sendSync( - "search-genius-lyrics", - extractedSongInfo - ); - if (!lyrics) { - // Delete previous lyrics if tab is open and couldn't get new lyrics - checkLyricsContainer(() => { - hasLyrics = false; - setTabsOnclick(undefined); - }); - return; - } - - if (is.dev()) { - console.log("Fetched lyrics from Genius"); - } - - enableLyricsTab(); - - setTabsOnclick(enableLyricsTab); - - checkLyricsContainer(); - - tabs.lyrics.onclick = () => { - const tabContainer = document.querySelector("ytmusic-tab-renderer"); - const observer = new MutationObserver((_, observer) => { - checkLyricsContainer(() => observer.disconnect()); - }); - observer.observe(tabContainer, { - attributes: true, - childList: true, - subtree: true, - }); - }; - - function checkLyricsContainer(callback = () => {}) { - const lyricsContainer = document.querySelector( - '[page-type="MUSIC_PAGE_TYPE_TRACK_LYRICS"] > ytmusic-message-renderer' - ); - if (lyricsContainer) { - callback(); - setLyrics(lyricsContainer) - } - } - - function setLyrics(lyricsContainer) { - lyricsContainer.innerHTML = `
- ${ - hasLyrics - ? lyrics.replace(/(?:\r\n|\r|\n)/g, "
") - : "Could not retrieve lyrics from genius" - } - -
- `; - if (hasLyrics) { - lyricsContainer.querySelector('.footer').textContent = 'Source: Genius'; - enableLyricsTab(); - } - } - - function setTabsOnclick(callback) { - for (const tab of [tabs.upNext, tabs.discover]) { - if (tab) { - tab.onclick = callback; - } - } - } - - function enableLyricsTab() { - tabs.lyrics.removeAttribute("disabled"); - tabs.lyrics.removeAttribute("aria-disabled"); - } - }, 500)); -}; diff --git a/plugins/lyrics-genius/front.ts b/plugins/lyrics-genius/front.ts new file mode 100644 index 00000000..8e54ac94 --- /dev/null +++ b/plugins/lyrics-genius/front.ts @@ -0,0 +1,106 @@ +import { ipcRenderer } from 'electron'; +import is from 'electron-is'; + +import type { SongInfo } from '../../providers/song-info'; + +export default () => { + ipcRenderer.on('update-song-info', (_, extractedSongInfo: SongInfo) => setTimeout(async () => { + const tabList = document.querySelectorAll('tp-yt-paper-tab'); + const tabs = { + upNext: tabList[0], + lyrics: tabList[1], + discover: tabList[2], + }; + + // Check if disabled + if (!tabs.lyrics?.hasAttribute('disabled')) { + return; + } + + let hasLyrics = true; + + const lyrics = await ipcRenderer.invoke( + 'search-genius-lyrics', + extractedSongInfo, + ) as string; + if (!lyrics) { + // Delete previous lyrics if tab is open and couldn't get new lyrics + checkLyricsContainer(() => { + hasLyrics = false; + setTabsOnclick(undefined); + }); + return; + } + + if (is.dev()) { + console.log('Fetched lyrics from Genius'); + } + + enableLyricsTab(); + + setTabsOnclick(enableLyricsTab); + + checkLyricsContainer(); + + const lyricsTabHandler = () => { + const tabContainer = document.querySelector('ytmusic-tab-renderer'); + if (tabContainer) { + const observer = new MutationObserver((_, observer) => { + checkLyricsContainer(() => observer.disconnect()); + }); + observer.observe(tabContainer, { + attributes: true, + childList: true, + subtree: true, + }); + } + }; + + tabs.lyrics.addEventListener('click', lyricsTabHandler); + + function checkLyricsContainer(callback = () => { + }) { + const lyricsContainer = document.querySelector( + '[page-type="MUSIC_PAGE_TYPE_TRACK_LYRICS"] > ytmusic-message-renderer', + ); + if (lyricsContainer) { + callback(); + setLyrics(lyricsContainer); + } + } + + function setLyrics(lyricsContainer: Element) { + lyricsContainer.innerHTML = `
+ ${ + hasLyrics + ? lyrics.replaceAll(/\r\n|\r|\n/g, '
') + : 'Could not retrieve lyrics from genius' + } + +
+ `; + if (hasLyrics) { + const footer = lyricsContainer.querySelector('.footer'); + if (footer) { + footer.textContent = 'Source: Genius'; + enableLyricsTab(); + } + } + } + + const defaultHandler = () => {}; + + function setTabsOnclick(callback: EventListenerOrEventListenerObject | undefined) { + for (const tab of [tabs.upNext, tabs.discover]) { + if (tab) { + tab.addEventListener('click', callback ?? defaultHandler); + } + } + } + + function enableLyricsTab() { + tabs.lyrics.removeAttribute('disabled'); + tabs.lyrics.removeAttribute('aria-disabled'); + } + }, 500)); +}; diff --git a/plugins/lyrics-genius/menu.js b/plugins/lyrics-genius/menu.js deleted file mode 100644 index 5d8c390e..00000000 --- a/plugins/lyrics-genius/menu.js +++ /dev/null @@ -1,17 +0,0 @@ -const { setOptions } = require("../../config/plugins"); -const { toggleRomanized } = require("./back"); - -module.exports = (win, options, refreshMenu) => { - return [ - { - label: "Romanized Lyrics", - type: "checkbox", - checked: options.romanizedLyrics, - click: (item) => { - options.romanizedLyrics = item.checked; - setOptions('lyrics-genius', options); - toggleRomanized(); - }, - }, - ]; -}; \ No newline at end of file diff --git a/plugins/lyrics-genius/menu.ts b/plugins/lyrics-genius/menu.ts new file mode 100644 index 00000000..9e5eb9dc --- /dev/null +++ b/plugins/lyrics-genius/menu.ts @@ -0,0 +1,18 @@ +import { BrowserWindow, MenuItem } from 'electron'; + +import { LyricGeniusType, toggleRomanized } from './back'; + +import { setOptions } from '../../config/plugins'; + +export default (_: BrowserWindow, options: LyricGeniusType) => [ + { + label: 'Romanized Lyrics', + type: 'checkbox', + checked: options.romanizedLyrics, + click(item: MenuItem) { + options.romanizedLyrics = item.checked; + setOptions('lyrics-genius', options); + toggleRomanized(); + }, + }, +]; diff --git a/plugins/lyrics-genius/style.css b/plugins/lyrics-genius/style.css index d2d6c79f..65412b96 100644 --- a/plugins/lyrics-genius/style.css +++ b/plugins/lyrics-genius/style.css @@ -1,12 +1,12 @@ /* Disable links in Genius lyrics */ .genius-lyrics a { - color: var(--ytmusic-text-primary); - display: inline-block; - pointer-events: none; - text-decoration: none; + color: var(--ytmusic-text-primary); + display: inline-block; + pointer-events: none; + text-decoration: none; } .description { - font-size: clamp(1.4rem, 1.1vmax, 3rem) !important; - text-align: center !important; + font-size: clamp(1.4rem, 1.1vmax, 3rem) !important; + text-align: center !important; } diff --git a/plugins/lyrics-genius/types.ts b/plugins/lyrics-genius/types.ts new file mode 100644 index 00000000..fac46ada --- /dev/null +++ b/plugins/lyrics-genius/types.ts @@ -0,0 +1,121 @@ +export interface GetGeniusLyric { + meta: Meta; + response: Response; +} + +export interface Meta { + status: number; +} + +export interface Response { + sections: Section[]; +} + +export interface Section { + type: string; + hits: Hit[]; +} + +export interface Hit { + highlights: Highlight[]; + index: Index; + type: Index; + result: Result; +} + +export interface Highlight { + property: string; + value: string; + snippet: boolean; + ranges: Range[]; +} + +export interface Range { + start: number; + end: number; +} + +export enum Index { + Album = 'album', + Lyric = 'lyric', + Song = 'song', +} + +export interface Result { + _type: Index; + annotation_count?: number; + api_path: string; + artist_names?: string; + full_title: string; + header_image_thumbnail_url?: string; + header_image_url?: string; + id: number; + instrumental?: boolean; + lyrics_owner_id?: number; + lyrics_state?: LyricsState; + lyrics_updated_at?: number; + path?: string; + pyongs_count?: number | null; + relationships_index_url?: string; + release_date_components: ReleaseDateComponents; + release_date_for_display: string; + release_date_with_abbreviated_month_for_display?: string; + song_art_image_thumbnail_url?: string; + song_art_image_url?: string; + stats?: Stats; + title?: string; + title_with_featured?: string; + updated_by_human_at?: number; + url: string; + featured_artists?: string[]; + primary_artist?: Artist; + cover_art_thumbnail_url?: string; + cover_art_url?: string; + name?: string; + name_with_artist?: string; + artist?: Artist; +} + +export interface Artist { + _type: Type; + api_path: string; + header_image_url: string; + id: number; + image_url: string; + index_character: IndexCharacter; + is_meme_verified: boolean; + is_verified: boolean; + name: string; + slug: string; + url: string; + iq?: number; +} + +// TODO: Add more types +export enum Type { + Artist = 'artist', +} + +// TODO: Add more index characters +export enum IndexCharacter { + G = 'g', + Y = 'y', +} + +// TODO: Add more states +export enum LyricsState { + Complete = 'complete', +} + +export interface ReleaseDateComponents { + year: number; + month: number; + day: number | null; +} + +export interface Stats { + unreviewed_annotations: number; + concurrents?: number; + hot: boolean; + pageviews?: number; +} diff --git a/plugins/navigation/actions.js b/plugins/navigation/actions.js deleted file mode 100644 index 69c8536b..00000000 --- a/plugins/navigation/actions.js +++ /dev/null @@ -1,24 +0,0 @@ -const { triggerAction } = require("../utils"); - -const CHANNEL = "navigation"; -const ACTIONS = { - NEXT: "next", - BACK: "back", -}; - -function goToNextPage() { - triggerAction(CHANNEL, ACTIONS.NEXT); -} - -function goToPreviousPage() { - triggerAction(CHANNEL, ACTIONS.BACK); -} - -module.exports = { - CHANNEL: CHANNEL, - ACTIONS: ACTIONS, - actions: { - goToNextPage: goToNextPage, - goToPreviousPage: goToPreviousPage, - }, -}; diff --git a/plugins/navigation/actions.ts b/plugins/navigation/actions.ts new file mode 100644 index 00000000..32813956 --- /dev/null +++ b/plugins/navigation/actions.ts @@ -0,0 +1,27 @@ +import { Actions, triggerAction } from '../utils'; + +export const CHANNEL = 'navigation'; +export const ACTIONS = Actions; + +export function goToNextPage() { + triggerAction(CHANNEL, Actions.NEXT); +} +// for HTML +// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access,@typescript-eslint/no-explicit-any +(global as any).goToNextPage = goToNextPage; + +export function goToPreviousPage() { + triggerAction(CHANNEL, Actions.BACK); +} +// for HTML +// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access,@typescript-eslint/no-explicit-any +(global as any).goToPreviousPage = goToPreviousPage; + +export default { + CHANNEL, + ACTIONS, + actions: { + goToNextPage, + goToPreviousPage, + }, +}; diff --git a/plugins/navigation/back.js b/plugins/navigation/back.js deleted file mode 100644 index 4c3e00dc..00000000 --- a/plugins/navigation/back.js +++ /dev/null @@ -1,29 +0,0 @@ -const path = require("path"); - -const { injectCSS, listenAction } = require("../utils"); -const { ACTIONS, CHANNEL } = require("./actions.js"); - -function handle(win) { - injectCSS(win.webContents, path.join(__dirname, "style.css"), () => { - win.webContents.send("navigation-css-ready"); - }); - - listenAction(CHANNEL, (event, action) => { - switch (action) { - case ACTIONS.NEXT: - if (win.webContents.canGoForward()) { - win.webContents.goForward(); - } - break; - case ACTIONS.BACK: - if (win.webContents.canGoBack()) { - win.webContents.goBack(); - } - break; - default: - console.log("Unknown action: " + action); - } - }); -} - -module.exports = handle; diff --git a/plugins/navigation/back.ts b/plugins/navigation/back.ts new file mode 100644 index 00000000..bdf7e77d --- /dev/null +++ b/plugins/navigation/back.ts @@ -0,0 +1,39 @@ +import path from 'node:path'; + +import { BrowserWindow } from 'electron'; + +import { ACTIONS, CHANNEL } from './actions'; + +import { injectCSS, listenAction } from '../utils'; + +export function handle(win: BrowserWindow) { + injectCSS(win.webContents, path.join(__dirname, 'style.css'), () => { + win.webContents.send('navigation-css-ready'); + }); + + listenAction(CHANNEL, (_, action) => { + switch (action) { + case ACTIONS.NEXT: { + if (win.webContents.canGoForward()) { + win.webContents.goForward(); + } + + break; + } + + case ACTIONS.BACK: { + if (win.webContents.canGoBack()) { + win.webContents.goBack(); + } + + break; + } + + default: { + console.log('Unknown action: ' + action); + } + } + }); +} + +export default handle; diff --git a/plugins/navigation/front.js b/plugins/navigation/front.js deleted file mode 100644 index 4874c3d5..00000000 --- a/plugins/navigation/front.js +++ /dev/null @@ -1,19 +0,0 @@ -const { ipcRenderer } = require("electron"); - -const { ElementFromFile, templatePath } = require("../utils"); - -function run() { - ipcRenderer.on("navigation-css-ready", () => { - const forwardButton = ElementFromFile( - templatePath(__dirname, "forward.html") - ); - const backButton = ElementFromFile(templatePath(__dirname, "back.html")); - const menu = document.querySelector("#right-content"); - - if (menu) { - menu.prepend(backButton, forwardButton); - } - }); -} - -module.exports = run; diff --git a/plugins/navigation/front.ts b/plugins/navigation/front.ts new file mode 100644 index 00000000..d4ffe80c --- /dev/null +++ b/plugins/navigation/front.ts @@ -0,0 +1,19 @@ +import { ipcRenderer } from 'electron'; + +import { ElementFromFile, templatePath } from '../utils'; + +export function run() { + ipcRenderer.on('navigation-css-ready', () => { + const forwardButton = ElementFromFile( + templatePath(__dirname, 'forward.html'), + ); + const backButton = ElementFromFile(templatePath(__dirname, 'back.html')); + const menu = document.querySelector('#right-content'); + + if (menu) { + menu.prepend(backButton, forwardButton); + } + }); +} + +export default run; diff --git a/plugins/navigation/style.css b/plugins/navigation/style.css index 520befea..5b3988b9 100644 --- a/plugins/navigation/style.css +++ b/plugins/navigation/style.css @@ -1,35 +1,35 @@ .navigation-item { - font-family: Roboto, Noto Naskh Arabic UI, Arial, sans-serif; - font-size: 20px; - line-height: var(--ytmusic-title-1_-_line-height); - font-weight: 500; - --yt-endpoint-color: #fff; - --yt-endpoint-hover-color: #fff; - --yt-endpoint-visited-color: #fff; - display: inline-flex; - align-items: center; - color: rgba(255, 255, 255, 0.5); - cursor: pointer; - margin: 0 var(--ytd-rich-grid-item-margin); + font-family: Roboto, Noto Naskh Arabic UI, Arial, sans-serif; + font-size: 20px; + line-height: var(--ytmusic-title-1_-_line-height); + font-weight: 500; + --yt-endpoint-color: #fff; + --yt-endpoint-hover-color: #fff; + --yt-endpoint-visited-color: #fff; + display: inline-flex; + align-items: center; + color: rgba(255, 255, 255, 0.5); + cursor: pointer; + margin: 0 var(--ytd-rich-grid-item-margin); } .navigation-item:hover { - color: #fff; + color: #fff; } .navigation-icon { - display: inline-flex; - -ms-flex-align: center; - -webkit-align-items: center; - align-items: center; - -ms-flex-pack: center; - -webkit-justify-content: center; - justify-content: center; - position: relative; - vertical-align: middle; - fill: var(--iron-icon-fill-color, currentcolor); - stroke: none; - width: var(--iron-icon-width, 24px); - height: var(--iron-icon-height, 24px); - animation: var(--iron-icon_-_animation); + display: inline-flex; + -ms-flex-align: center; + -webkit-align-items: center; + align-items: center; + -ms-flex-pack: center; + -webkit-justify-content: center; + justify-content: center; + position: relative; + vertical-align: middle; + fill: var(--iron-icon-fill-color, currentcolor); + stroke: none; + width: var(--iron-icon-width, 24px); + height: var(--iron-icon-height, 24px); + animation: var(--iron-icon_-_animation); } diff --git a/plugins/navigation/templates/back.html b/plugins/navigation/templates/back.html index b872ada5..083cf380 100644 --- a/plugins/navigation/templates/back.html +++ b/plugins/navigation/templates/back.html @@ -1,33 +1,33 @@ diff --git a/plugins/navigation/templates/forward.html b/plugins/navigation/templates/forward.html index b3837b36..84c717be 100644 --- a/plugins/navigation/templates/forward.html +++ b/plugins/navigation/templates/forward.html @@ -1,35 +1,35 @@ diff --git a/plugins/no-google-login/back.js b/plugins/no-google-login/back.js deleted file mode 100644 index fa96b863..00000000 --- a/plugins/no-google-login/back.js +++ /dev/null @@ -1,6 +0,0 @@ -const { injectCSS } = require("../utils"); -const path = require("path"); - -module.exports = win => { - injectCSS(win.webContents, path.join(__dirname, "style.css")); -}; diff --git a/plugins/no-google-login/back.ts b/plugins/no-google-login/back.ts new file mode 100644 index 00000000..5634e5ef --- /dev/null +++ b/plugins/no-google-login/back.ts @@ -0,0 +1,9 @@ +import path from 'node:path'; + +import { BrowserWindow } from 'electron'; + +import { injectCSS } from '../utils'; + +export default (win: BrowserWindow) => { + injectCSS(win.webContents, path.join(__dirname, 'style.css')); +}; diff --git a/plugins/no-google-login/front.js b/plugins/no-google-login/front.js deleted file mode 100644 index bd364ae5..00000000 --- a/plugins/no-google-login/front.js +++ /dev/null @@ -1,37 +0,0 @@ -function removeLoginElements() { - const elementsToRemove = [ - ".sign-in-link.ytmusic-nav-bar", - '.ytmusic-pivot-bar-renderer[tab-id="FEmusic_liked"]', - ]; - - elementsToRemove.forEach((selector) => { - const node = document.querySelector(selector); - if (node) { - node.remove(); - } - }); - - // Remove the library button - const libraryIconPath = - "M16,6v2h-2v5c0,1.1-0.9,2-2,2s-2-0.9-2-2s0.9-2,2-2c0.37,0,0.7,0.11,1,0.28V6H16z M18,20H4V6H3v15h15V20z M21,3H6v15h15V3z M7,4h13v13H7V4z"; - const observer = new MutationObserver(() => { - menuEntries = document.querySelectorAll( - "#items ytmusic-guide-entry-renderer" - ); - menuEntries.forEach((item) => { - const icon = item.querySelector("path"); - if (icon) { - observer.disconnect(); - if (icon.getAttribute("d") === libraryIconPath) { - item.remove(); - } - } - }); - }); - observer.observe(document.documentElement, { - childList: true, - subtree: true, - }); -} - -module.exports = removeLoginElements; diff --git a/plugins/no-google-login/front.ts b/plugins/no-google-login/front.ts new file mode 100644 index 00000000..b0f4158d --- /dev/null +++ b/plugins/no-google-login/front.ts @@ -0,0 +1,37 @@ +function removeLoginElements() { + const elementsToRemove = [ + '.sign-in-link.ytmusic-nav-bar', + '.ytmusic-pivot-bar-renderer[tab-id="FEmusic_liked"]', + ]; + + for (const selector of elementsToRemove) { + const node = document.querySelector(selector); + if (node) { + node.remove(); + } + } + + // Remove the library button + const libraryIconPath + = 'M16,6v2h-2v5c0,1.1-0.9,2-2,2s-2-0.9-2-2s0.9-2,2-2c0.37,0,0.7,0.11,1,0.28V6H16z M18,20H4V6H3v15h15V20z M21,3H6v15h15V3z M7,4h13v13H7V4z'; + const observer = new MutationObserver(() => { + const menuEntries = document.querySelectorAll( + '#items ytmusic-guide-entry-renderer', + ); + menuEntries.forEach((item) => { + const icon = item.querySelector('path'); + if (icon) { + observer.disconnect(); + if (icon.getAttribute('d') === libraryIconPath) { + item.remove(); + } + } + }); + }); + observer.observe(document.documentElement, { + childList: true, + subtree: true, + }); +} + +export default removeLoginElements; diff --git a/plugins/no-google-login/style.css b/plugins/no-google-login/style.css index 09f09013..e9c80f14 100644 --- a/plugins/no-google-login/style.css +++ b/plugins/no-google-login/style.css @@ -2,5 +2,5 @@ ytmusic-guide-signin-promo-renderer, a[href="/music_premium"], .sign-in-link { - display: none !important; + display: none !important; } diff --git a/plugins/notifications/back.js b/plugins/notifications/back.js deleted file mode 100644 index 385ecca7..00000000 --- a/plugins/notifications/back.js +++ /dev/null @@ -1,46 +0,0 @@ -const { Notification } = require("electron"); -const is = require("electron-is"); -const registerCallback = require("../../providers/song-info"); -const { notificationImage } = require("./utils"); -const config = require("./config"); - -const notify = (info) => { - - // Fill the notification with content - const notification = { - title: info.title || "Playing", - body: info.artist, - icon: notificationImage(info), - silent: true, - urgency: config.get('urgency'), - }; - - // Send the notification - const currentNotification = new Notification(notification); - currentNotification.show() - - return currentNotification; -}; - -const setup = () => { - let oldNotification; - let currentUrl; - - registerCallback(songInfo => { - if (!songInfo.isPaused && (songInfo.url !== currentUrl || config.get('unpauseNotification'))) { - // Close the old notification - oldNotification?.close(); - currentUrl = songInfo.url; - // This fixes a weird bug that would cause the notification to be updated instead of showing - setTimeout(() => { oldNotification = notify(songInfo) }, 10); - } - }); -} - -/** @param {Electron.BrowserWindow} win */ -module.exports = (win, options) => { - // Register the callback for new song information - is.windows() && options.interactive ? - require("./interactive")(win) : - setup(); -}; diff --git a/plugins/notifications/back.ts b/plugins/notifications/back.ts new file mode 100644 index 00000000..bc73819d --- /dev/null +++ b/plugins/notifications/back.ts @@ -0,0 +1,51 @@ +import { BrowserWindow, Notification } from 'electron'; + +import is from 'electron-is'; + +import { notificationImage } from './utils'; +import config from './config'; +import interactive from './interactive'; + +import registerCallback, { SongInfo } from '../../providers/song-info'; + +import type { ConfigType } from '../../config/dynamic'; + +type NotificationOptions = ConfigType<'notifications'>; + +const notify = (info: SongInfo) => { + // Send the notification + const currentNotification = new Notification({ + title: info.title || 'Playing', + body: info.artist, + icon: notificationImage(info), + silent: true, + urgency: config.get('urgency') as 'normal' | 'critical' | 'low', + }); + currentNotification.show(); + + return currentNotification; +}; + +const setup = () => { + let oldNotification: Notification; + let currentUrl: string | undefined; + + registerCallback((songInfo: SongInfo) => { + if (!songInfo.isPaused && (songInfo.url !== currentUrl || config.get('unpauseNotification'))) { + // Close the old notification + oldNotification?.close(); + currentUrl = songInfo.url; + // This fixes a weird bug that would cause the notification to be updated instead of showing + setTimeout(() => { + oldNotification = notify(songInfo); + }, 10); + } + }); +}; + +export default (win: BrowserWindow, options: NotificationOptions) => { + // Register the callback for new song information + is.windows() && options.interactive + ? interactive(win) + : setup(); +}; diff --git a/plugins/notifications/config.js b/plugins/notifications/config.js deleted file mode 100644 index d0898dc3..00000000 --- a/plugins/notifications/config.js +++ /dev/null @@ -1,5 +0,0 @@ -const { PluginConfig } = require("../../config/dynamic"); - -const config = new PluginConfig("notifications"); - -module.exports = { ...config }; diff --git a/plugins/notifications/config.ts b/plugins/notifications/config.ts new file mode 100644 index 00000000..91605f7a --- /dev/null +++ b/plugins/notifications/config.ts @@ -0,0 +1,5 @@ +import { PluginConfig } from '../../config/dynamic'; + +const config = new PluginConfig('notifications'); + +export default config; diff --git a/plugins/notifications/interactive.js b/plugins/notifications/interactive.js deleted file mode 100644 index 7bda6944..00000000 --- a/plugins/notifications/interactive.js +++ /dev/null @@ -1,235 +0,0 @@ -const { notificationImage, icons, save_temp_icons, secondsToMinutes, ToastStyles } = require("./utils"); -const getSongControls = require('../../providers/song-controls'); -const registerCallback = require("../../providers/song-info"); -const { changeProtocolHandler } = require("../../providers/protocol-handler"); -const { setTrayOnClick, setTrayOnDoubleClick } = require("../../tray"); - -const { Notification, app, ipcMain } = require("electron"); -const path = require('path'); - -const config = require("./config"); - -let songControls; -let savedNotification; - -/** @param {Electron.BrowserWindow} win */ -module.exports = (win) => { - songControls = getSongControls(win); - - let currentSeconds = 0; - ipcMain.on('apiLoaded', () => win.webContents.send('setupTimeChangedListener')); - - ipcMain.on('timeChanged', (_, t) => currentSeconds = t); - - if (app.isPackaged) save_temp_icons(); - - let savedSongInfo; - let lastUrl; - - // Register songInfoCallback - registerCallback(songInfo => { - if (!songInfo.artist && !songInfo.title) return; - savedSongInfo = { ...songInfo }; - if (!songInfo.isPaused && - (songInfo.url !== lastUrl || config.get("unpauseNotification")) - ) { - lastUrl = songInfo.url - sendNotification(songInfo); - } - }); - - if (config.get("trayControls")) { - setTrayOnClick(() => { - if (savedNotification) { - savedNotification.close(); - savedNotification = undefined; - } else if (savedSongInfo) { - sendNotification({ - ...savedSongInfo, - elapsedSeconds: currentSeconds - }) - } - }); - - setTrayOnDoubleClick(() => { - if (win.isVisible()) { - win.hide(); - } else win.show(); - }) - } - - - app.once("before-quit", () => { - savedNotification?.close(); - }); - - - changeProtocolHandler( - (cmd) => { - if (Object.keys(songControls).includes(cmd)) { - songControls[cmd](); - if (config.get("refreshOnPlayPause") && ( - cmd === 'pause' || - (cmd === 'play' && !config.get("unpauseNotification")) - ) - ) { - setImmediate(() => - sendNotification({ - ...savedSongInfo, - isPaused: cmd === 'pause', - elapsedSeconds: currentSeconds - }) - ); - } - } - } - ) -} - -function sendNotification(songInfo) { - const iconSrc = notificationImage(songInfo); - - savedNotification?.close(); - - savedNotification = new Notification({ - title: songInfo.title || "Playing", - body: songInfo.artist, - icon: iconSrc, - silent: true, - // https://learn.microsoft.com/en-us/uwp/schemas/tiles/toastschema/schema-root - // https://learn.microsoft.com/en-us/windows/apps/design/shell/tiles-and-notifications/toast-schema - // https://learn.microsoft.com/en-us/windows/apps/design/shell/tiles-and-notifications/adaptive-interactive-toasts?tabs=xml - // https://learn.microsoft.com/en-us/uwp/api/windows.ui.notifications.toasttemplatetype - toastXml: get_xml(songInfo, iconSrc), - }); - - savedNotification.on("close", (_) => { - savedNotification = undefined; - }); - - savedNotification.show(); -} - -const get_xml = (songInfo, iconSrc) => { - switch (config.get("toastStyle")) { - default: - case ToastStyles.logo: - case ToastStyles.legacy: - return xml_logo(songInfo, iconSrc); - case ToastStyles.banner_top_custom: - return xml_banner_top_custom(songInfo, iconSrc); - case ToastStyles.hero: - return xml_hero(songInfo, iconSrc); - case ToastStyles.banner_bottom: - return xml_banner_bottom(songInfo, iconSrc); - case ToastStyles.banner_centered_bottom: - return xml_banner_centered_bottom(songInfo, iconSrc); - case ToastStyles.banner_centered_top: - return xml_banner_centered_top(songInfo, iconSrc); - }; -} - -const iconLocation = app.isPackaged ? - path.resolve(app.getPath("userData"), 'icons') : - path.resolve(__dirname, '..', '..', 'assets/media-icons-black'); - -const display = (kind) => { - if (config.get("toastStyle") === ToastStyles.legacy) { - return `content="${icons[kind]}"`; - } else { - return `\ - content="${config.get("hideButtonText") ? "" : kind.charAt(0).toUpperCase() + kind.slice(1)}"\ - imageUri="file:///${path.resolve(__dirname, iconLocation, `${kind}.png`)}" - `; - } -} - -const getButton = (kind) => - ``; - -const getButtons = (isPaused) => `\ - - ${getButton('previous')} - ${isPaused ? getButton('play') : getButton('pause')} - ${getButton('next')} - \ -`; - -const toast = (content, isPaused) => `\ - - `; - -const xml_image = ({ title, artist, isPaused }, imgSrc, placement) => toast(`\ - - ${title} - ${artist}\ -`, isPaused); - - -const xml_logo = (songInfo, imgSrc) => xml_image(songInfo, imgSrc, 'placement="appLogoOverride"'); - -const xml_hero = (songInfo, imgSrc) => xml_image(songInfo, imgSrc, 'placement="hero"'); - -const xml_banner_bottom = (songInfo, imgSrc) => xml_image(songInfo, imgSrc, ''); - -const xml_banner_top_custom = (songInfo, imgSrc) => toast(`\ - - - - - ${songInfo.title} - ${songInfo.artist} - - ${xml_more_data(songInfo)} - \ -`, songInfo.isPaused); - -const xml_more_data = ({ album, elapsedSeconds, songDuration }) => `\ - - ${album ? - `${album}` : ''} - ${secondsToMinutes(elapsedSeconds)} / ${secondsToMinutes(songDuration)} -\ -`; - -const xml_banner_centered_bottom = ({ title, artist, isPaused }, imgSrc) => toast(`\ - - - - ${title} - ${artist} - - - \ -`, isPaused); - -const xml_banner_centered_top = ({ title, artist, isPaused }, imgSrc) => toast(`\ - - - - - ${title} - ${artist} - - \ -`, isPaused); - -const titleFontPicker = (title) => { - if (title.length <= 13) { - return 'Header'; - } else if (title.length <= 22) { - return 'Subheader'; - } else if (title.length <= 26) { - return 'Title'; - } else { - return 'Subtitle'; - } -} diff --git a/plugins/notifications/interactive.ts b/plugins/notifications/interactive.ts new file mode 100644 index 00000000..ab724ba2 --- /dev/null +++ b/plugins/notifications/interactive.ts @@ -0,0 +1,261 @@ +import path from 'node:path'; + +import { app, BrowserWindow, ipcMain, Notification } from 'electron'; + +import { icons, notificationImage, saveTempIcon, secondsToMinutes, ToastStyles } from './utils'; +import config from './config'; + +import getSongControls from '../../providers/song-controls'; +import registerCallback, { SongInfo } from '../../providers/song-info'; +import { changeProtocolHandler } from '../../providers/protocol-handler'; +import { setTrayOnClick, setTrayOnDoubleClick } from '../../tray'; + +let songControls: ReturnType; +let savedNotification: Notification | undefined; + +export default (win: BrowserWindow) => { + songControls = getSongControls(win); + + let currentSeconds = 0; + ipcMain.on('apiLoaded', () => win.webContents.send('setupTimeChangedListener')); + + ipcMain.on('timeChanged', (_, t: number) => currentSeconds = t); + + if (app.isPackaged) { + saveTempIcon(); + } + + let savedSongInfo: SongInfo; + let lastUrl: string | undefined; + + // Register songInfoCallback + registerCallback((songInfo) => { + if (!songInfo.artist && !songInfo.title) { + return; + } + + savedSongInfo = { ...songInfo }; + if (!songInfo.isPaused + && (songInfo.url !== lastUrl || config.get('unpauseNotification')) + ) { + lastUrl = songInfo.url; + sendNotification(songInfo); + } + }); + + if (config.get('trayControls')) { + setTrayOnClick(() => { + if (savedNotification) { + savedNotification.close(); + savedNotification = undefined; + } else if (savedSongInfo) { + sendNotification({ + ...savedSongInfo, + elapsedSeconds: currentSeconds, + }); + } + }); + + setTrayOnDoubleClick(() => { + if (win.isVisible()) { + win.hide(); + } else { + win.show(); + } + }); + } + + app.once('before-quit', () => { + savedNotification?.close(); + }); + + changeProtocolHandler( + (cmd) => { + if (Object.keys(songControls).includes(cmd)) { + songControls[cmd as keyof typeof songControls](); + if (config.get('refreshOnPlayPause') && ( + cmd === 'pause' + || (cmd === 'play' && !config.get('unpauseNotification')) + ) + ) { + setImmediate(() => + sendNotification({ + ...savedSongInfo, + isPaused: cmd === 'pause', + elapsedSeconds: currentSeconds, + }), + ); + } + } + }, + ); +}; + +function sendNotification(songInfo: SongInfo) { + const iconSrc = notificationImage(songInfo); + + savedNotification?.close(); + + let icon: string; + if (typeof iconSrc === 'object') { + icon = iconSrc.toDataURL(); + } else { + icon = iconSrc; + } + + savedNotification = new Notification({ + title: songInfo.title || 'Playing', + body: songInfo.artist, + icon: iconSrc, + silent: true, + // https://learn.microsoft.com/en-us/uwp/schemas/tiles/toastschema/schema-root + // https://learn.microsoft.com/en-us/windows/apps/design/shell/tiles-and-notifications/toast-schema + // https://learn.microsoft.com/en-us/windows/apps/design/shell/tiles-and-notifications/adaptive-interactive-toasts?tabs=xml + // https://learn.microsoft.com/en-us/uwp/api/windows.ui.notifications.toasttemplatetype + toastXml: getXml(songInfo, icon), + }); + + savedNotification.on('close', () => { + savedNotification = undefined; + }); + + savedNotification.show(); +} + +const getXml = (songInfo: SongInfo, iconSrc: string) => { + switch (config.get('toastStyle')) { + default: + case ToastStyles.logo: + case ToastStyles.legacy: { + return xmlLogo(songInfo, iconSrc); + } + + case ToastStyles.banner_top_custom: { + return xmlBannerTopCustom(songInfo, iconSrc); + } + + case ToastStyles.hero: { + return xmlHero(songInfo, iconSrc); + } + + case ToastStyles.banner_bottom: { + return xmlBannerBottom(songInfo, iconSrc); + } + + case ToastStyles.banner_centered_bottom: { + return xmlBannerCenteredBottom(songInfo, iconSrc); + } + + case ToastStyles.banner_centered_top: { + return xmlBannerCenteredTop(songInfo, iconSrc); + } + } +}; + +const iconLocation = app.isPackaged + ? path.resolve(app.getPath('userData'), 'icons') + : path.resolve(__dirname, '..', '..', 'assets/media-icons-black'); + +const display = (kind: keyof typeof icons) => { + if (config.get('toastStyle') === ToastStyles.legacy) { + return `content="${icons[kind]}"`; + } + + return `\ + content="${config.get('hideButtonText') ? '' : kind.charAt(0).toUpperCase() + kind.slice(1)}"\ + imageUri="file:///${path.resolve(__dirname, iconLocation, `${kind}.png`)}" + `; +}; + +const getButton = (kind: keyof typeof icons) => + ``; + +const getButtons = (isPaused: boolean) => `\ + + ${getButton('previous')} + ${isPaused ? getButton('play') : getButton('pause')} + ${getButton('next')} + \ +`; + +const toast = (content: string, isPaused: boolean) => `\ + + `; + +const xmlImage = ({ title, artist, isPaused }: SongInfo, imgSrc: string, placement: string) => toast(`\ + + ${title} + ${artist}\ +`, isPaused ?? false); + +const xmlLogo = (songInfo: SongInfo, imgSrc: string) => xmlImage(songInfo, imgSrc, 'placement="appLogoOverride"'); + +const xmlHero = (songInfo: SongInfo, imgSrc: string) => xmlImage(songInfo, imgSrc, 'placement="hero"'); + +const xmlBannerBottom = (songInfo: SongInfo, imgSrc: string) => xmlImage(songInfo, imgSrc, ''); + +const xmlBannerTopCustom = (songInfo: SongInfo, imgSrc: string) => toast(`\ + + + + + ${songInfo.title} + ${songInfo.artist} + + ${xmlMoreData(songInfo)} + \ +`, songInfo.isPaused ?? false); + +const xmlMoreData = ({ album, elapsedSeconds, songDuration }: SongInfo) => `\ + + ${album + ? `${album}` : ''} + ${secondsToMinutes(elapsedSeconds ?? 0)} / ${secondsToMinutes(songDuration)} +\ +`; + +const xmlBannerCenteredBottom = ({ title, artist, isPaused }: SongInfo, imgSrc: string) => toast(`\ + + + + ${title} + ${artist} + + + \ +`, isPaused ?? false); + +const xmlBannerCenteredTop = ({ title, artist, isPaused }: SongInfo, imgSrc: string) => toast(`\ + + + + + ${title} + ${artist} + + \ +`, isPaused ?? false); + +const titleFontPicker = (title: string) => { + if (title.length <= 13) { + return 'Header'; + } + + if (title.length <= 22) { + return 'Subheader'; + } + + if (title.length <= 26) { + return 'Title'; + } + + return 'Subtitle'; +}; diff --git a/plugins/notifications/menu.js b/plugins/notifications/menu.js deleted file mode 100644 index 014be184..00000000 --- a/plugins/notifications/menu.js +++ /dev/null @@ -1,80 +0,0 @@ -const { urgencyLevels, ToastStyles, snakeToCamel } = require("./utils"); -const is = require("electron-is"); -const config = require("./config"); - -module.exports = (_win, options) => [ - ...(is.linux() - ? [ - { - label: "Notification Priority", - submenu: urgencyLevels.map((level) => ({ - label: level.name, - type: "radio", - checked: options.urgency === level.value, - click: () => config.set("urgency", level.value), - })), - }, - ] - : []), - ...(is.windows() - ? [ - { - label: "Interactive Notifications", - type: "checkbox", - checked: options.interactive, - // doesn't update until restart - click: (item) => config.setAndMaybeRestart("interactive", item.checked), - }, - { - // submenu with settings for interactive notifications (name shouldn't be too long) - label: "Interactive Settings", - submenu: [ - { - label: "Open/Close on tray click", - type: "checkbox", - checked: options.trayControls, - click: (item) => config.set("trayControls", item.checked), - }, - { - label: "Hide Button Text", - type: "checkbox", - checked: options.hideButtonText, - click: (item) => config.set("hideButtonText", item.checked), - }, - { - label: "Refresh on Play/Pause", - type: "checkbox", - checked: options.refreshOnPlayPause, - click: (item) => config.set("refreshOnPlayPause", item.checked), - } - ] - }, - { - label: "Style", - submenu: getToastStyleMenuItems(options) - }, - ] - : []), - { - label: "Show notification on unpause", - type: "checkbox", - checked: options.unpauseNotification, - click: (item) => config.set("unpauseNotification", item.checked), - }, -]; - -function getToastStyleMenuItems(options) { - const arr = new Array(Object.keys(ToastStyles).length); - - // ToastStyles index starts from 1 - for (const [name, index] of Object.entries(ToastStyles)) { - arr[index - 1] = { - label: snakeToCamel(name), - type: "radio", - checked: options.toastStyle === index, - click: () => config.set("toastStyle", index), - }; - } - - return arr; -} diff --git a/plugins/notifications/menu.ts b/plugins/notifications/menu.ts new file mode 100644 index 00000000..127d287a --- /dev/null +++ b/plugins/notifications/menu.ts @@ -0,0 +1,86 @@ +import is from 'electron-is'; + +import { BrowserWindow, MenuItem } from 'electron'; + +import { snakeToCamel, ToastStyles, urgencyLevels } from './utils'; + +import config from './config'; + +import type { ConfigType } from '../../config/dynamic'; + +export default (_win: BrowserWindow, options: ConfigType<'notifications'>) => [ + ...(is.linux() + ? [ + { + label: 'Notification Priority', + submenu: urgencyLevels.map((level) => ({ + label: level.name, + type: 'radio', + checked: options.urgency === level.value, + click: () => config.set('urgency', level.value), + })), + }, + ] + : []), + ...(is.windows() + ? [ + { + label: 'Interactive Notifications', + type: 'checkbox', + checked: options.interactive, + // Doesn't update until restart + click: (item: MenuItem) => config.setAndMaybeRestart('interactive', item.checked), + }, + { + // Submenu with settings for interactive notifications (name shouldn't be too long) + label: 'Interactive Settings', + submenu: [ + { + label: 'Open/Close on tray click', + type: 'checkbox', + checked: options.trayControls, + click: (item: MenuItem) => config.set('trayControls', item.checked), + }, + { + label: 'Hide Button Text', + type: 'checkbox', + checked: options.hideButtonText, + click: (item: MenuItem) => config.set('hideButtonText', item.checked), + }, + { + label: 'Refresh on Play/Pause', + type: 'checkbox', + checked: options.refreshOnPlayPause, + click: (item: MenuItem) => config.set('refreshOnPlayPause', item.checked), + }, + ], + }, + { + label: 'Style', + submenu: getToastStyleMenuItems(options), + }, + ] + : []), + { + label: 'Show notification on unpause', + type: 'checkbox', + checked: options.unpauseNotification, + click: (item: MenuItem) => config.set('unpauseNotification', item.checked), + }, +]; + +export function getToastStyleMenuItems(options: ConfigType<'notifications'>) { + const array = Array.from({ length: Object.keys(ToastStyles).length }); + + // ToastStyles index starts from 1 + for (const [name, index] of Object.entries(ToastStyles)) { + array[index - 1] = { + label: snakeToCamel(name), + type: 'radio', + checked: options.toastStyle === index, + click: () => config.set('toastStyle', index), + }; + } + + return array; +} diff --git a/plugins/notifications/utils.js b/plugins/notifications/utils.js deleted file mode 100644 index cb472969..00000000 --- a/plugins/notifications/utils.js +++ /dev/null @@ -1,93 +0,0 @@ -const path = require("path"); -const { app } = require("electron"); -const fs = require("fs"); -const config = require("./config"); - -const icon = "assets/youtube-music.png"; -const userData = app.getPath("userData"); -const tempIcon = path.join(userData, "tempIcon.png"); -const tempBanner = path.join(userData, "tempBanner.png"); - -const { cache } = require("../../providers/decorators") - -module.exports.ToastStyles = { - logo: 1, - banner_centered_top: 2, - hero: 3, - banner_top_custom: 4, - banner_centered_bottom: 5, - banner_bottom: 6, - legacy: 7 -} - -module.exports.icons = { - play: "\u{1405}", // ᐅ - pause: "\u{2016}", // ‖ - next: "\u{1433}", // ᐳ - previous: "\u{1438}" // ᐸ -} - -module.exports.urgencyLevels = [ - { name: "Low", value: "low" }, - { name: "Normal", value: "normal" }, - { name: "High", value: "critical" }, -]; - -const nativeImageToLogo = cache((nativeImage) => { - const tempImage = nativeImage.resize({ height: 256 }); - const margin = Math.max(tempImage.getSize().width - 256, 0); - - return tempImage.crop({ - x: Math.round(margin / 2), - y: 0, - width: 256, - height: 256, - }); -}); - -module.exports.notificationImage = (songInfo) => { - if (!songInfo.image) return icon; - if (!config.get("interactive")) return nativeImageToLogo(songInfo.image); - - switch (config.get("toastStyle")) { - case module.exports.ToastStyles.logo: - case module.exports.ToastStyles.legacy: - return this.saveImage(nativeImageToLogo(songInfo.image), tempIcon); - default: - return this.saveImage(songInfo.image, tempBanner); - }; -}; - -module.exports.saveImage = cache((img, save_path) => { - try { - fs.writeFileSync(save_path, img.toPNG()); - } catch (err) { - console.log(`Error writing song icon to disk:\n${err.toString()}`) - return icon; - } - return save_path; -}); - -module.exports.save_temp_icons = () => { - for (const kind of Object.keys(module.exports.icons)) { - const destinationPath = path.join(userData, 'icons', `${kind}.png`); - if (fs.existsSync(destinationPath)) continue; - const iconPath = path.resolve(__dirname, "../../assets/media-icons-black", `${kind}.png`); - fs.mkdirSync(path.dirname(destinationPath), { recursive: true }); - fs.copyFile(iconPath, destinationPath, () => { }); - } -}; - -module.exports.snakeToCamel = (str) => { - return str.replace(/([-_][a-z]|^[a-z])/g, (group) => - group.toUpperCase() - .replace('-', ' ') - .replace('_', ' ') - ); -} - -module.exports.secondsToMinutes = (seconds) => { - const minutes = Math.floor(seconds / 60); - const secondsLeft = seconds % 60; - return `${minutes}:${secondsLeft < 10 ? '0' : ''}${secondsLeft}`; -} diff --git a/plugins/notifications/utils.ts b/plugins/notifications/utils.ts new file mode 100644 index 00000000..7870730c --- /dev/null +++ b/plugins/notifications/utils.ts @@ -0,0 +1,108 @@ +import path from 'node:path'; +import fs from 'node:fs'; + +import { app, NativeImage } from 'electron'; + +import config from './config'; + +import { cache } from '../../providers/decorators'; +import { SongInfo } from '../../providers/song-info'; + +const icon = 'assets/youtube-music.png'; +const userData = app.getPath('userData'); +const temporaryIcon = path.join(userData, 'tempIcon.png'); +const temporaryBanner = path.join(userData, 'tempBanner.png'); + + +export const ToastStyles = { + logo: 1, + banner_centered_top: 2, + hero: 3, + banner_top_custom: 4, + banner_centered_bottom: 5, + banner_bottom: 6, + legacy: 7, +}; + +export const icons = { + play: '\u{1405}', // ᐅ + pause: '\u{2016}', // ‖ + next: '\u{1433}', // ᐳ + previous: '\u{1438}', // ᐸ +}; + +export const urgencyLevels = [ + { name: 'Low', value: 'low' }, + { name: 'Normal', value: 'normal' }, + { name: 'High', value: 'critical' }, +]; + +const nativeImageToLogo = cache((nativeImage: NativeImage) => { + const temporaryImage = nativeImage.resize({ height: 256 }); + const margin = Math.max(temporaryImage.getSize().width - 256, 0); + + return temporaryImage.crop({ + x: Math.round(margin / 2), + y: 0, + width: 256, + height: 256, + }); +}); + +export const notificationImage = (songInfo: SongInfo) => { + if (!songInfo.image) { + return icon; + } + + if (!config.get('interactive')) { + return nativeImageToLogo(songInfo.image); + } + + switch (config.get('toastStyle')) { + case ToastStyles.logo: + case ToastStyles.legacy: { + return saveImage(nativeImageToLogo(songInfo.image), temporaryIcon); + } + + default: { + return saveImage(songInfo.image, temporaryBanner); + } + } +}; + +export const saveImage = cache((img: NativeImage, savePath: string) => { + try { + fs.writeFileSync(savePath, img.toPNG()); + } catch (error: unknown) { + console.log(`Error writing song icon to disk:\n${String(error)}`); + return icon; + } + + return savePath; +}); + +export const saveTempIcon = () => { + for (const kind of Object.keys(icons)) { + const destinationPath = path.join(userData, 'icons', `${kind}.png`); + if (fs.existsSync(destinationPath)) { + continue; + } + + const iconPath = path.resolve(__dirname, '../../assets/media-icons-black', `${kind}.png`); + fs.mkdirSync(path.dirname(destinationPath), { recursive: true }); + fs.copyFile(iconPath, destinationPath, () => { + }); + } +}; + +export const snakeToCamel = (string_: string) => string_.replaceAll(/([-_][a-z]|^[a-z])/g, (group) => + group.toUpperCase() + .replace('-', ' ') + .replace('_', ' '), +); + +export const secondsToMinutes = (seconds: number) => { + const minutes = Math.floor(seconds / 60); + const secondsLeft = seconds % 60; + return `${minutes}:${secondsLeft < 10 ? '0' : ''}${secondsLeft}`; +}; diff --git a/plugins/picture-in-picture/back.js b/plugins/picture-in-picture/back.js deleted file mode 100644 index 0bfdfa36..00000000 --- a/plugins/picture-in-picture/back.js +++ /dev/null @@ -1,97 +0,0 @@ -const path = require("path"); - -const { app, ipcMain } = require("electron"); -const electronLocalshortcut = require("electron-localshortcut"); - -const { setOptions } = require("../../config/plugins"); -const { injectCSS } = require("../utils"); - -let isInPiP = false; -let originalPosition; -let originalSize; -let originalFullScreen; -let originalMaximized; - -let win; -let options; - -const pipPosition = () => (options.savePosition && options["pip-position"]) || [10, 10]; -const pipSize = () => (options.saveSize && options["pip-size"]) || [450, 275]; - -const setLocalOptions = (_options) => { - options = { ...options, ..._options }; - setOptions("picture-in-picture", _options); -} - -const togglePiP = async () => { - isInPiP = !isInPiP; - setLocalOptions({ isInPiP }); - - if (isInPiP) { - originalFullScreen = win.isFullScreen(); - if (originalFullScreen) win.setFullScreen(false); - originalMaximized = win.isMaximized(); - if (originalMaximized) win.unmaximize(); - - originalPosition = win.getPosition(); - originalSize = win.getSize(); - - win.webContents.on("before-input-event", blockShortcutsInPiP); - - win.setMaximizable(false); - win.setFullScreenable(false); - - win.webContents.send("pip-toggle", true); - - app.dock?.hide(); - win.setVisibleOnAllWorkspaces(true, { - visibleOnFullScreen: true, - }); - app.dock?.show(); - if (options.alwaysOnTop) { - win.setAlwaysOnTop(true, "screen-saver", 1); - } - } else { - win.webContents.removeListener("before-input-event", blockShortcutsInPiP); - win.setMaximizable(true); - win.setFullScreenable(true); - - win.webContents.send("pip-toggle", false); - - win.setVisibleOnAllWorkspaces(false); - win.setAlwaysOnTop(false); - - if (originalFullScreen) win.setFullScreen(true); - if (originalMaximized) win.maximize(); - } - - const [x, y] = isInPiP ? pipPosition() : originalPosition; - const [w, h] = isInPiP ? pipSize() : originalSize; - win.setPosition(x, y); - win.setSize(w, h); - - win.setWindowButtonVisibility?.(!isInPiP); -}; - -const blockShortcutsInPiP = (event, input) => { - const key = input.key.toLowerCase(); - - if (key === "f") { - event.preventDefault(); - } else if (key === 'escape') { - togglePiP(); - event.preventDefault(); - }; -}; - -module.exports = (_win, _options) => { - options ??= _options; - win ??= _win; - setLocalOptions({ isInPiP }); - injectCSS(win.webContents, path.join(__dirname, "style.css")); - ipcMain.on("picture-in-picture", async () => { - await togglePiP(); - }); -}; - -module.exports.setOptions = setLocalOptions; diff --git a/plugins/picture-in-picture/back.ts b/plugins/picture-in-picture/back.ts new file mode 100644 index 00000000..2041e404 --- /dev/null +++ b/plugins/picture-in-picture/back.ts @@ -0,0 +1,111 @@ +import path from 'node:path'; + +import { app, BrowserWindow, ipcMain } from 'electron'; + +import { setOptions as setPluginOptions } from '../../config/plugins'; +import { injectCSS } from '../utils'; + +import type { ConfigType } from '../../config/dynamic'; + +let isInPiP = false; +let originalPosition: number[]; +let originalSize: number[]; +let originalFullScreen: boolean; +let originalMaximized: boolean; + +let win: BrowserWindow; + +type PiPOptions = ConfigType<'picture-in-picture'>; + +let options: Partial; + +const pipPosition = () => (options.savePosition && options['pip-position']) || [10, 10]; +const pipSize = () => (options.saveSize && options['pip-size']) || [450, 275]; + +const setLocalOptions = (_options: Partial) => { + options = { ...options, ..._options }; + setPluginOptions('picture-in-picture', _options); +}; + +const togglePiP = () => { + isInPiP = !isInPiP; + setLocalOptions({ isInPiP }); + + if (isInPiP) { + originalFullScreen = win.isFullScreen(); + if (originalFullScreen) { + win.setFullScreen(false); + } + + originalMaximized = win.isMaximized(); + if (originalMaximized) { + win.unmaximize(); + } + + originalPosition = win.getPosition(); + originalSize = win.getSize(); + + win.webContents.on('before-input-event', blockShortcutsInPiP); + + win.setMaximizable(false); + win.setFullScreenable(false); + + win.webContents.send('pip-toggle', true); + + app.dock?.hide(); + win.setVisibleOnAllWorkspaces(true, { + visibleOnFullScreen: true, + }); + app.dock?.show(); + if (options.alwaysOnTop) { + win.setAlwaysOnTop(true, 'screen-saver', 1); + } + } else { + win.webContents.removeListener('before-input-event', blockShortcutsInPiP); + win.setMaximizable(true); + win.setFullScreenable(true); + + win.webContents.send('pip-toggle', false); + + win.setVisibleOnAllWorkspaces(false); + win.setAlwaysOnTop(false); + + if (originalFullScreen) { + win.setFullScreen(true); + } + + if (originalMaximized) { + win.maximize(); + } + } + + const [x, y] = isInPiP ? pipPosition() : originalPosition; + const [w, h] = isInPiP ? pipSize() : originalSize; + win.setPosition(x, y); + win.setSize(w, h); + + win.setWindowButtonVisibility?.(!isInPiP); +}; + +const blockShortcutsInPiP = (event: Electron.Event, input: Electron.Input) => { + const key = input.key.toLowerCase(); + + if (key === 'f') { + event.preventDefault(); + } else if (key === 'escape') { + togglePiP(); + event.preventDefault(); + } +}; + +export default (_win: BrowserWindow, _options: PiPOptions) => { + options ??= _options; + win ??= _win; + setLocalOptions({ isInPiP }); + injectCSS(win.webContents, path.join(__dirname, 'style.css')); + ipcMain.on('picture-in-picture', () => { + togglePiP(); + }); +}; + +export const setOptions = setLocalOptions; diff --git a/plugins/picture-in-picture/front.js b/plugins/picture-in-picture/front.js deleted file mode 100644 index 27600641..00000000 --- a/plugins/picture-in-picture/front.js +++ /dev/null @@ -1,140 +0,0 @@ -const { ipcRenderer } = require("electron"); - -const { toKeyEvent } = require("keyboardevent-from-electron-accelerator"); -const keyEventAreEqual = require("keyboardevents-areequal"); - -const { getSongMenu } = require("../../providers/dom-elements"); -const { ElementFromFile, templatePath } = require("../utils"); - -function $(selector) { return document.querySelector(selector); } - -let useNativePiP = false; -let menu = null; -const pipButton = ElementFromFile( - templatePath(__dirname, "picture-in-picture.html") -); - -// will also clone -function replaceButton(query, button) { - const svg = button.querySelector("#icon svg").cloneNode(true); - button.replaceWith(button.cloneNode(true)); - button.remove(); - const newButton = $(query); - newButton.querySelector("#icon").appendChild(svg); - return newButton; -} - -function cloneButton(query) { - replaceButton(query, $(query)); - return $(query); -} - -const observer = new MutationObserver(() => { - if (!menu) { - menu = getSongMenu(); - if (!menu) return; - } - if (menu.contains(pipButton) || !menu.parentElement.eventSink_?.matches('ytmusic-menu-renderer.ytmusic-player-bar')) return; - const menuUrl = $( - 'tp-yt-paper-listbox [tabindex="0"] #navigation-endpoint' - )?.href; - if (menuUrl && !menuUrl.includes("watch?")) return; - - menu.prepend(pipButton); -}); - -global.togglePictureInPicture = async () => { - if (useNativePiP) { - const isInPiP = document.pictureInPictureElement !== null; - const video = $("video"); - const togglePiP = () => - isInPiP - ? document.exitPictureInPicture.call(document) - : video.requestPictureInPicture.call(video); - - try { - await togglePiP(); - $("#icon").click(); // Close the menu - return true; - } catch {} - } - - ipcRenderer.send("picture-in-picture"); - return false; -}; - -const listenForToggle = () => { - const originalExitButton = $(".exit-fullscreen-button"); - const appLayout = $("ytmusic-app-layout"); - const expandMenu = $('#expanding-menu'); - const middleControls = $('.middle-controls'); - const playerPage = $("ytmusic-player-page"); - const togglePlayerPageButton = $(".toggle-player-page-button"); - const fullScreenButton = $(".fullscreen-button"); - const player = $('#player'); - const onPlayerDblClick = player.onDoubleClick_; - - const titlebar = $(".cet-titlebar"); - - ipcRenderer.on("pip-toggle", (_, isPip) => { - if (isPip) { - replaceButton(".exit-fullscreen-button", originalExitButton).onclick = - () => togglePictureInPicture(); - player.onDoubleClick_ = () => {}; - expandMenu.onmouseleave = () => middleControls.click(); - if (!playerPage.playerPageOpen_) { - togglePlayerPageButton.click(); - } - fullScreenButton.click(); - appLayout.classList.add("pip"); - if (titlebar) titlebar.style.display = "none"; - } else { - $(".exit-fullscreen-button").replaceWith(originalExitButton); - player.onDoubleClick_ = onPlayerDblClick; - expandMenu.onmouseleave = undefined; - originalExitButton.click(); - appLayout.classList.remove("pip"); - if (titlebar) titlebar.style.display = "flex"; - } - }); -} - -function observeMenu(options) { - useNativePiP = options.useNativePiP; - document.addEventListener( - "apiLoaded", - () => { - listenForToggle(); - - cloneButton(".player-minimize-button").onclick = async () => { - await global.togglePictureInPicture(); - setTimeout(() => $("#player").click()); - }; - - // allows easily closing the menu by programmatically clicking outside of it - $("#expanding-menu").removeAttribute("no-cancel-on-outside-click"); - // TODO: think about wether an additional button in songMenu is needed - observer.observe($("ytmusic-popup-container"), { - childList: true, - subtree: true, - }); - }, - { once: true, passive: true } - ); -} - -module.exports = (options) => { - observeMenu(options); - - if (options.hotkey) { - const hotkeyEvent = toKeyEvent(options.hotkey); - window.addEventListener("keydown", (event) => { - if ( - keyEventAreEqual(event, hotkeyEvent) && - !$("ytmusic-search-box").opened - ) { - togglePictureInPicture(); - } - }); - } -}; diff --git a/plugins/picture-in-picture/front.ts b/plugins/picture-in-picture/front.ts new file mode 100644 index 00000000..7bc9d2c5 --- /dev/null +++ b/plugins/picture-in-picture/front.ts @@ -0,0 +1,179 @@ +import { ipcRenderer } from 'electron'; +import { toKeyEvent } from 'keyboardevent-from-electron-accelerator'; +import keyEventAreEqual from 'keyboardevents-areequal'; + +import { getSongMenu } from '../../providers/dom-elements'; + +import { ElementFromFile, templatePath } from '../utils'; + +import type { ConfigType } from '../../config/dynamic'; + +type PiPOptions = ConfigType<'picture-in-picture'>; + +function $(selector: string) { + return document.querySelector(selector); +} + +let useNativePiP = false; +let menu: Element | null = null; +const pipButton = ElementFromFile( + templatePath(__dirname, 'picture-in-picture.html'), +); + +// Will also clone +function replaceButton(query: string, button: Element) { + const svg = button.querySelector('#icon svg')?.cloneNode(true); + if (svg) { + button.replaceWith(button.cloneNode(true)); + button.remove(); + const newButton = $(query); + if (newButton) { + newButton.querySelector('#icon')?.append(svg); + } + return newButton; + } + return null; +} + +function cloneButton(query: string) { + const button = $(query); + if (button) { + replaceButton(query, button); + } + return $(query); +} + +const observer = new MutationObserver(() => { + if (!menu) { + menu = getSongMenu(); + if (!menu) { + return; + } + } + + if ( + menu.contains(pipButton) || + !(menu.parentElement as (HTMLElement & { eventSink_: Element }) | null) + ?.eventSink_ + ?.matches('ytmusic-menu-renderer.ytmusic-player-bar') + ) { + return; + } + + const menuUrl = $('tp-yt-paper-listbox [tabindex="0"] #navigation-endpoint')?.href; + if (!menuUrl?.includes('watch?')) { + return; + } + + menu.prepend(pipButton); +}); + +const togglePictureInPicture = async () => { + if (useNativePiP) { + const isInPiP = document.pictureInPictureElement !== null; + const video = $('video'); + const togglePiP = () => + isInPiP + ? document.exitPictureInPicture.call(document) + : video?.requestPictureInPicture?.call(video); + + try { + await togglePiP(); + $('#icon')?.click(); // Close the menu + return true; + } catch { + } + } + + ipcRenderer.send('picture-in-picture'); + return false; +}; +// For UI (HTML) +// eslint-disable-next-line @typescript-eslint/no-explicit-any,@typescript-eslint/no-unsafe-member-access +(global as any).togglePictureInPicture = togglePictureInPicture; + +const listenForToggle = () => { + const originalExitButton = $('.exit-fullscreen-button'); + const appLayout = $('ytmusic-app-layout'); + const expandMenu = $('#expanding-menu'); + const middleControls = $('.middle-controls'); + const playerPage = $('ytmusic-player-page'); + const togglePlayerPageButton = $('.toggle-player-page-button'); + const fullScreenButton = $('.fullscreen-button'); + const player = $ void) | undefined }>('#player'); + const onPlayerDblClick = player?.onDoubleClick_; + const mouseLeaveEventListener = () => middleControls?.click(); + + const titlebar = $('.cet-titlebar'); + + ipcRenderer.on('pip-toggle', (_, isPip: boolean) => { + if (originalExitButton && player) { + if (isPip) { + replaceButton('.exit-fullscreen-button', originalExitButton)?.addEventListener('click', () => togglePictureInPicture()); + player.onDoubleClick_ = () => { + }; + + expandMenu?.addEventListener('mouseleave', mouseLeaveEventListener); + if (!playerPage?.playerPageOpen_) { + togglePlayerPageButton?.click(); + } + + fullScreenButton?.click(); + appLayout?.classList.add('pip'); + if (titlebar) { + titlebar.style.display = 'none'; + } + } else { + $('.exit-fullscreen-button')?.replaceWith(originalExitButton); + player.onDoubleClick_ = onPlayerDblClick; + expandMenu?.removeEventListener('mouseleave', mouseLeaveEventListener); + originalExitButton.click(); + appLayout?.classList.remove('pip'); + if (titlebar) { + titlebar.style.display = 'flex'; + } + } + } + }); +}; + +function observeMenu(options: PiPOptions) { + useNativePiP = options.useNativePiP; + document.addEventListener( + 'apiLoaded', + () => { + listenForToggle(); + + cloneButton('.player-minimize-button')?.addEventListener('click', async () => { + await togglePictureInPicture(); + setTimeout(() => $('#player')?.click()); + }); + + // Allows easily closing the menu by programmatically clicking outside of it + $('#expanding-menu')?.removeAttribute('no-cancel-on-outside-click'); + // TODO: think about wether an additional button in songMenu is needed + const popupContainer = $('ytmusic-popup-container'); + if (popupContainer) observer.observe(popupContainer, { + childList: true, + subtree: true, + }); + }, + { once: true, passive: true }, + ); +} + +export default (options: PiPOptions) => { + observeMenu(options); + + if (options.hotkey) { + const hotkeyEvent = toKeyEvent(options.hotkey); + window.addEventListener('keydown', (event) => { + if ( + keyEventAreEqual(event, hotkeyEvent) + && !$('ytmusic-search-box')?.opened + ) { + togglePictureInPicture(); + } + }); + } +}; diff --git a/plugins/picture-in-picture/keyboardevent-from-electron-accelerator.d.ts b/plugins/picture-in-picture/keyboardevent-from-electron-accelerator.d.ts new file mode 100644 index 00000000..67af6f51 --- /dev/null +++ b/plugins/picture-in-picture/keyboardevent-from-electron-accelerator.d.ts @@ -0,0 +1,12 @@ +declare module 'keyboardevent-from-electron-accelerator' { + interface KeyboardEvent { + key?: string; + code?: string; + metaKey?: boolean; + altKey?: boolean; + ctrlKey?: boolean; + shiftKey?: boolean; + } + + export const toKeyEvent: (accelerator: string) => KeyboardEvent; +} diff --git a/plugins/picture-in-picture/keyboardevents-areequal.d.ts b/plugins/picture-in-picture/keyboardevents-areequal.d.ts new file mode 100644 index 00000000..ac219b1f --- /dev/null +++ b/plugins/picture-in-picture/keyboardevents-areequal.d.ts @@ -0,0 +1,14 @@ +declare module 'keyboardevents-areequal' { + interface KeyboardEvent { + key?: string; + code?: string; + metaKey?: boolean; + altKey?: boolean; + ctrlKey?: boolean; + shiftKey?: boolean; + } + + const areEqual: (event1: KeyboardEvent, event2: KeyboardEvent) => boolean; + + export default areEqual; +} diff --git a/plugins/picture-in-picture/menu.js b/plugins/picture-in-picture/menu.js deleted file mode 100644 index 61014c22..00000000 --- a/plugins/picture-in-picture/menu.js +++ /dev/null @@ -1,68 +0,0 @@ -const prompt = require("custom-electron-prompt"); - -const promptOptions = require("../../providers/prompt-options"); -const { setOptions } = require("./back.js"); - -module.exports = (win, options) => [ - { - label: "Always on top", - type: "checkbox", - checked: options.alwaysOnTop, - click: (item) => { - setOptions({ alwaysOnTop: item.checked }); - win.setAlwaysOnTop(item.checked); - }, - }, - { - label: "Save window position", - type: "checkbox", - checked: options.savePosition, - click: (item) => { - setOptions({ savePosition: item.checked }); - }, - }, - { - label: "Save window size", - type: "checkbox", - checked: options.saveSize, - click: (item) => { - setOptions({ saveSize: item.checked }); - }, - }, - { - label: "Hotkey", - type: "checkbox", - checked: options.hotkey, - click: async (item) => { - const output = await prompt({ - title: "Picture in Picture Hotkey", - label: "Choose a hotkey for toggling Picture in Picture", - type: "keybind", - keybindOptions: [{ - value: "hotkey", - label: "Hotkey", - default: options.hotkey - }], - ...promptOptions() - }, win) - - if (output) { - const { value, accelerator } = output[0]; - setOptions({ [value]: accelerator }); - - item.checked = !!accelerator; - } else { - // Reset checkbox if prompt was canceled - item.checked = !item.checked; - } - }, - }, - { - label: "Use native PiP", - type: "checkbox", - checked: options.useNativePiP, - click: (item) => { - setOptions({ useNativePiP: item.checked }); - }, - } -]; diff --git a/plugins/picture-in-picture/menu.ts b/plugins/picture-in-picture/menu.ts new file mode 100644 index 00000000..e8f877d6 --- /dev/null +++ b/plugins/picture-in-picture/menu.ts @@ -0,0 +1,75 @@ +import prompt from 'custom-electron-prompt'; + +import { BrowserWindow } from 'electron'; + +import { setOptions } from './back'; + +import promptOptions from '../../providers/prompt-options'; + +import { MenuTemplate } from '../../menu'; + +import type { ConfigType } from '../../config/dynamic'; + +export default (win: BrowserWindow, options: ConfigType<'picture-in-picture'>): MenuTemplate => [ + { + label: 'Always on top', + type: 'checkbox', + checked: options.alwaysOnTop, + click(item) { + setOptions({ alwaysOnTop: item.checked }); + win.setAlwaysOnTop(item.checked); + }, + }, + { + label: 'Save window position', + type: 'checkbox', + checked: options.savePosition, + click(item) { + setOptions({ savePosition: item.checked }); + }, + }, + { + label: 'Save window size', + type: 'checkbox', + checked: options.saveSize, + click(item) { + setOptions({ saveSize: item.checked }); + }, + }, + { + label: 'Hotkey', + type: 'checkbox', + checked: !!options.hotkey, + async click(item) { + const output = await prompt({ + title: 'Picture in Picture Hotkey', + label: 'Choose a hotkey for toggling Picture in Picture', + type: 'keybind', + keybindOptions: [{ + value: 'hotkey', + label: 'Hotkey', + default: options.hotkey, + }], + ...promptOptions(), + }, win); + + if (output) { + const { value, accelerator } = output[0]; + setOptions({ [value]: accelerator }); + + item.checked = !!accelerator; + } else { + // Reset checkbox if prompt was canceled + item.checked = !item.checked; + } + }, + }, + { + label: 'Use native PiP', + type: 'checkbox', + checked: options.useNativePiP, + click(item) { + setOptions({ useNativePiP: item.checked }); + }, + }, +]; diff --git a/plugins/picture-in-picture/style.css b/plugins/picture-in-picture/style.css index a7430739..ab79307f 100644 --- a/plugins/picture-in-picture/style.css +++ b/plugins/picture-in-picture/style.css @@ -3,41 +3,41 @@ ytmusic-app-layout.pip ytmusic-player-bar svg, ytmusic-app-layout.pip ytmusic-player-bar .time-info, ytmusic-app-layout.pip ytmusic-player-bar yt-formatted-string, ytmusic-app-layout.pip ytmusic-player-bar .yt-formatted-string { - filter: drop-shadow(2px 4px 6px black); - color: white !important; - fill: white !important; + filter: drop-shadow(2px 4px 6px black); + color: white !important; + fill: white !important; } /* improve the style of the player bar expanding menu */ ytmusic-app-layout.pip ytmusic-player-expanding-menu { - border-radius: 30px; - background-color: rgba(0, 0, 0, 0.3); - backdrop-filter: blur(5px) brightness(20%); + border-radius: 30px; + background-color: rgba(0, 0, 0, 0.3); + backdrop-filter: blur(5px) brightness(20%); } /* fix volumeHud position when both in-app-menu and PiP are active */ .cet-container ytmusic-app-layout.pip #volumeHud { - top: 22px !important; + top: 22px !important; } /* make player-bar not draggable if in-app-menu is enabled */ .cet-container ytmusic-app-layout.pip ytmusic-player-bar { - -webkit-app-region: no-drag !important; + -webkit-app-region: no-drag !important; } /* make player draggable if in-app-menu is enabled */ .cet-container ytmusic-app-layout.pip #player { - -webkit-app-region: drag !important; + -webkit-app-region: drag !important; } /* remove info, thumbnail and menu from player-bar */ ytmusic-app-layout.pip ytmusic-player-bar .content-info-wrapper, ytmusic-app-layout.pip ytmusic-player-bar .thumbnail-image-wrapper, ytmusic-app-layout.pip ytmusic-player-bar ytmusic-menu-renderer { - display: none !important; + display: none !important; } /* disable the video-toggle button when in PiP mode */ ytmusic-app-layout.pip .video-switch-button { - display: none !important; + display: none !important; } diff --git a/plugins/picture-in-picture/templates/picture-in-picture.html b/plugins/picture-in-picture/templates/picture-in-picture.html index 6dd0440c..733a29bb 100644 --- a/plugins/picture-in-picture/templates/picture-in-picture.html +++ b/plugins/picture-in-picture/templates/picture-in-picture.html @@ -1,51 +1,50 @@ diff --git a/plugins/playback-speed/front.js b/plugins/playback-speed/front.js deleted file mode 100644 index e776923c..00000000 --- a/plugins/playback-speed/front.js +++ /dev/null @@ -1,90 +0,0 @@ -const { getSongMenu } = require("../../providers/dom-elements"); -const { ElementFromFile, templatePath } = require("../utils"); -const { singleton } = require("../../providers/decorators") - -function $(selector) { return document.querySelector(selector); } - -const slider = ElementFromFile(templatePath(__dirname, "slider.html")); - -const roundToTwo = n => Math.round(n * 1e2) / 1e2; - -const MIN_PLAYBACK_SPEED = 0.07; -const MAX_PLAYBACK_SPEED = 16; - -let playbackSpeed = 1; - -const updatePlayBackSpeed = () => { - $('video').playbackRate = playbackSpeed; - - const playbackSpeedElement = $("#playback-speed-value"); - if (playbackSpeedElement) { - playbackSpeedElement.innerHTML = playbackSpeed; - } -}; - -let menu; - -const setupSliderListener = singleton(() => { - $('#playback-speed-slider').addEventListener('immediate-value-changed', e => { - playbackSpeed = e.detail.value || MIN_PLAYBACK_SPEED; - if (isNaN(playbackSpeed)) { - playbackSpeed = 1; - } - updatePlayBackSpeed(); - }) -}); - -const observePopupContainer = () => { - const observer = new MutationObserver(() => { - if (!menu) { - menu = getSongMenu(); - } - - if (menu && menu.parentElement.eventSink_?.matches('ytmusic-menu-renderer.ytmusic-player-bar') && !menu.contains(slider)) { - menu.prepend(slider); - setupSliderListener(); - } - }); - - observer.observe($('ytmusic-popup-container'), { - childList: true, - subtree: true, - }); -}; - -const observeVideo = () => { - $('video').addEventListener('ratechange', forcePlaybackRate) - $('video').addEventListener('srcChanged', forcePlaybackRate) -} - -const setupWheelListener = () => { - slider.addEventListener('wheel', e => { - e.preventDefault(); - if (isNaN(playbackSpeed)) { - playbackSpeed = 1; - } - // e.deltaY < 0 means wheel-up - playbackSpeed = roundToTwo(e.deltaY < 0 ? - Math.min(playbackSpeed + 0.01, MAX_PLAYBACK_SPEED) : - Math.max(playbackSpeed - 0.01, MIN_PLAYBACK_SPEED) - ); - - updatePlayBackSpeed(); - // update slider position - $('#playback-speed-slider').value = playbackSpeed; - }) -} - -function forcePlaybackRate(e) { - if (e.target.playbackRate !== playbackSpeed) { - e.target.playbackRate = playbackSpeed - } -} - -module.exports = () => { - document.addEventListener('apiLoaded', () => { - observePopupContainer(); - observeVideo(); - setupWheelListener(); - }, { once: true, passive: true }) -}; diff --git a/plugins/playback-speed/front.ts b/plugins/playback-speed/front.ts new file mode 100644 index 00000000..17c873c2 --- /dev/null +++ b/plugins/playback-speed/front.ts @@ -0,0 +1,115 @@ +import { getSongMenu } from '../../providers/dom-elements'; +import { ElementFromFile, templatePath } from '../utils'; +import { singleton } from '../../providers/decorators'; + + +function $(selector: string) { + return document.querySelector(selector); +} + +const slider = ElementFromFile(templatePath(__dirname, 'slider.html')); + +const roundToTwo = (n: number) => Math.round(n * 1e2) / 1e2; + +const MIN_PLAYBACK_SPEED = 0.07; +const MAX_PLAYBACK_SPEED = 16; + +let playbackSpeed = 1; + +const updatePlayBackSpeed = () => { + const videoElement = $('video'); + if (videoElement) { + videoElement.playbackRate = playbackSpeed; + } + + const playbackSpeedElement = $('#playback-speed-value'); + if (playbackSpeedElement) { + playbackSpeedElement.innerHTML = String(playbackSpeed); + } +}; + +let menu: Element | null = null; + +const setupSliderListener = singleton(() => { + $('#playback-speed-slider')?.addEventListener('immediate-value-changed', (e) => { + playbackSpeed = (e as CustomEvent<{ value: number; }>).detail.value || MIN_PLAYBACK_SPEED; + if (isNaN(playbackSpeed)) { + playbackSpeed = 1; + } + + updatePlayBackSpeed(); + }); +}); + +const observePopupContainer = () => { + const observer = new MutationObserver(() => { + if (!menu) { + menu = getSongMenu(); + } + + if ( + menu && + (menu.parentElement as HTMLElement & { eventSink_: Element | null }) + ?.eventSink_ + ?.matches('ytmusic-menu-renderer.ytmusic-player-bar')&& !menu.contains(slider) + ) { + menu.prepend(slider); + setupSliderListener(); + } + }); + + const popupContainer = $('ytmusic-popup-container'); + if (popupContainer) { + observer.observe(popupContainer, { + childList: true, + subtree: true, + }); + } +}; + +const observeVideo = () => { + const video = $('video'); + if (video) { + video.addEventListener('ratechange', forcePlaybackRate); + video.addEventListener('srcChanged', forcePlaybackRate); + } +}; + +const setupWheelListener = () => { + slider.addEventListener('wheel', (e) => { + e.preventDefault(); + if (isNaN(playbackSpeed)) { + playbackSpeed = 1; + } + + // E.deltaY < 0 means wheel-up + playbackSpeed = roundToTwo(e.deltaY < 0 + ? Math.min(playbackSpeed + 0.01, MAX_PLAYBACK_SPEED) + : Math.max(playbackSpeed - 0.01, MIN_PLAYBACK_SPEED), + ); + + updatePlayBackSpeed(); + // Update slider position + const playbackSpeedSilder = $('#playback-speed-slider'); + if (playbackSpeedSilder) { + playbackSpeedSilder.value = playbackSpeed; + } + }); +}; + +function forcePlaybackRate(e: Event) { + if (e.target instanceof HTMLVideoElement) { + const videoElement = e.target; + if (videoElement.playbackRate !== playbackSpeed) { + videoElement.playbackRate = playbackSpeed; + } + } +} + +export default () => { + document.addEventListener('apiLoaded', () => { + observePopupContainer(); + observeVideo(); + setupWheelListener(); + }, { once: true, passive: true }); +}; diff --git a/plugins/playback-speed/templates/slider.html b/plugins/playback-speed/templates/slider.html index ebd98537..38526289 100644 --- a/plugins/playback-speed/templates/slider.html +++ b/plugins/playback-speed/templates/slider.html @@ -1,88 +1,93 @@ diff --git a/plugins/precise-volume/back.js b/plugins/precise-volume/back.js deleted file mode 100644 index c33f23bb..00000000 --- a/plugins/precise-volume/back.js +++ /dev/null @@ -1,24 +0,0 @@ -const { injectCSS } = require("../utils"); -const path = require("path"); - -/* -This is used to determine if plugin is actually active -(not if its only enabled in options) -*/ -let enabled = false; - -const { globalShortcut } = require('electron'); - -module.exports = (win, options) => { - enabled = true; - injectCSS(win.webContents, path.join(__dirname, "volume-hud.css")); - - if (options.globalShortcuts?.volumeUp) { - globalShortcut.register((options.globalShortcuts.volumeUp), () => win.webContents.send('changeVolume', true)); - } - if (options.globalShortcuts?.volumeDown) { - globalShortcut.register((options.globalShortcuts.volumeDown), () => win.webContents.send('changeVolume', false)); - } -} - -module.exports.enabled = () => enabled; diff --git a/plugins/precise-volume/back.ts b/plugins/precise-volume/back.ts new file mode 100644 index 00000000..2e8ea70a --- /dev/null +++ b/plugins/precise-volume/back.ts @@ -0,0 +1,28 @@ +import path from 'node:path'; + +import { globalShortcut, BrowserWindow } from 'electron'; + +import { injectCSS } from '../utils'; + +import type { ConfigType } from '../../config/dynamic'; + +/* +This is used to determine if plugin is actually active +(not if it's only enabled in options) +*/ +let isEnabled = false; + +export const enabled = () => isEnabled; + +export default (win: BrowserWindow, options: ConfigType<'precise-volume'>) => { + isEnabled = true; + injectCSS(win.webContents, path.join(__dirname, 'volume-hud.css')); + + if (options.globalShortcuts?.volumeUp) { + globalShortcut.register((options.globalShortcuts.volumeUp), () => win.webContents.send('changeVolume', true)); + } + + if (options.globalShortcuts?.volumeDown) { + globalShortcut.register((options.globalShortcuts.volumeDown), () => win.webContents.send('changeVolume', false)); + } +}; diff --git a/plugins/precise-volume/front.js b/plugins/precise-volume/front.js deleted file mode 100644 index 13bc4746..00000000 --- a/plugins/precise-volume/front.js +++ /dev/null @@ -1,232 +0,0 @@ -const { ipcRenderer } = require("electron"); - -const { setOptions, setMenuOptions, isEnabled } = require("../../config/plugins"); - -function $(selector) { return document.querySelector(selector); } - -const { debounce } = require("../../providers/decorators"); - -let api, options; - -module.exports = (_options) => { - options = _options; - document.addEventListener('apiLoaded', e => { - api = e.detail; - ipcRenderer.on('changeVolume', (_, toIncrease) => changeVolume(toIncrease)); - ipcRenderer.on('setVolume', (_, value) => setVolume(value)); - firstRun(); - }, { once: true, passive: true }) -}; - -//without this function it would rewrite config 20 time when volume change by 20 -const writeOptions = debounce(() => { - setOptions("precise-volume", options); -}, 1000); - -module.exports.moveVolumeHud = debounce((showVideo) => { - const volumeHud = $("#volumeHud"); - if (!volumeHud) return; - volumeHud.style.top = showVideo - ? `${($("ytmusic-player").clientHeight - $("video").clientHeight) / 2}px` - : 0; -}, 250); - -const hideVolumeHud = debounce((volumeHud) => { - volumeHud.style.opacity = 0; -}, 2000); - -const hideVolumeSlider = debounce((slider) => { - slider.classList.remove("on-hover"); -}, 2500); - - -/** Restore saved volume and setup tooltip */ -function firstRun() { - if (typeof options.savedVolume === "number") { - // Set saved volume as tooltip - setTooltip(options.savedVolume); - - if (api.getVolume() !== options.savedVolume) { - api.setVolume(options.savedVolume); - } - } - - setupPlaybar(); - - setupLocalArrowShortcuts(); - - const noVid = $("#main-panel")?.computedStyleMap().get("display").value === "none"; - injectVolumeHud(noVid); - if (!noVid) { - setupVideoPlayerOnwheel(); - if (!isEnabled('video-toggle')) { - //video-toggle handles hud positioning on its own - const videoMode = () => api.getPlayerResponse().videoDetails?.musicVideoType !== 'MUSIC_VIDEO_TYPE_ATV'; - $("video").addEventListener("srcChanged", () => moveVolumeHud(videoMode())); - } - } - - // Change options from renderer to keep sync - ipcRenderer.on("setOptions", (_event, newOptions = {}) => { - Object.assign(options, newOptions) - setMenuOptions("precise-volume", options); - }); -} - -function injectVolumeHud(noVid) { - if (noVid) { - const position = "top: 18px; right: 60px;"; - const mainStyle = "font-size: xx-large;"; - - $(".center-content.ytmusic-nav-bar").insertAdjacentHTML("beforeend", - ``) - } else { - const position = `top: 10px; left: 10px;`; - const mainStyle = "font-size: xxx-large; webkit-text-stroke: 1px black; font-weight: 600;"; - - $("#song-video").insertAdjacentHTML('afterend', - ``) - } -} - -function showVolumeHud(volume) { - const volumeHud = $("#volumeHud"); - if (!volumeHud) return; - - volumeHud.textContent = `${volume}%`; - volumeHud.style.opacity = 1; - - hideVolumeHud(volumeHud); -} - -/** Add onwheel event to video player */ -function setupVideoPlayerOnwheel() { - $("#main-panel").addEventListener("wheel", event => { - event.preventDefault(); - // Event.deltaY < 0 means wheel-up - changeVolume(event.deltaY < 0); - }); -} - -function saveVolume(volume) { - options.savedVolume = volume; - writeOptions(); -} - -/** Add onwheel event to play bar and also track if play bar is hovered*/ -function setupPlaybar() { - const playerbar = $("ytmusic-player-bar"); - - playerbar.addEventListener("wheel", event => { - event.preventDefault(); - // Event.deltaY < 0 means wheel-up - changeVolume(event.deltaY < 0); - }); - - // Keep track of mouse position for showVolumeSlider() - playerbar.addEventListener("mouseenter", () => { - playerbar.classList.add("on-hover"); - }); - - playerbar.addEventListener("mouseleave", () => { - playerbar.classList.remove("on-hover"); - }); - - setupSliderObserver(); -} - -/** Save volume + Update the volume tooltip when volume-slider is manually changed */ -function setupSliderObserver() { - const sliderObserver = new MutationObserver(mutations => { - for (const mutation of mutations) { - // This checks that volume-slider was manually set - if (mutation.oldValue !== mutation.target.value && - (typeof options.savedVolume !== "number" || Math.abs(options.savedVolume - mutation.target.value) > 4)) { - // Diff>4 means it was manually set - setTooltip(mutation.target.value); - saveVolume(mutation.target.value); - } - } - }); - - // Observing only changes in 'value' of volume-slider - sliderObserver.observe($("#volume-slider"), { - attributeFilter: ["value"], - attributeOldValue: true - }); -} - -function setVolume(value) { - api.setVolume(value); - // Save the new volume - saveVolume(value); - - // change slider position (important) - updateVolumeSlider(); - - // Change tooltips to new value - setTooltip(value); - // Show volume slider - showVolumeSlider(); - // Show volume HUD - showVolumeHud(value); -} - -/** if (toIncrease = false) then volume decrease */ -function changeVolume(toIncrease) { - // Apply volume change if valid - const steps = Number(options.steps || 1); - setVolume(toIncrease ? - Math.min(api.getVolume() + steps, 100) : - Math.max(api.getVolume() - steps, 0)); -} - -function updateVolumeSlider() { - // Slider value automatically rounds to multiples of 5 - for (const slider of ["#volume-slider", "#expand-volume-slider"]) { - $(slider).value = - options.savedVolume > 0 && options.savedVolume < 5 - ? 5 - : options.savedVolume; - } -} - -function showVolumeSlider() { - const slider = $("#volume-slider"); - // This class display the volume slider if not in minimized mode - slider.classList.add("on-hover"); - - hideVolumeSlider(slider); -} - -// Set new volume as tooltip for volume slider and icon + expanding slider (appears when window size is small) -const tooltipTargets = [ - "#volume-slider", - "tp-yt-paper-icon-button.volume", - "#expand-volume-slider", - "#expand-volume" -]; - -function setTooltip(volume) { - for (target of tooltipTargets) { - $(target).title = `${volume}%`; - } -} - -function setupLocalArrowShortcuts() { - if (options.arrowsShortcut) { - window.addEventListener('keydown', (event) => { - if ($('ytmusic-search-box').opened) return; - switch (event.code) { - case "ArrowUp": - event.preventDefault(); - changeVolume(true); - break; - case "ArrowDown": - event.preventDefault(); - changeVolume(false); - break; - } - }); - } -} diff --git a/plugins/precise-volume/front.ts b/plugins/precise-volume/front.ts new file mode 100644 index 00000000..0acc7583 --- /dev/null +++ b/plugins/precise-volume/front.ts @@ -0,0 +1,270 @@ +import { ipcRenderer } from 'electron'; + +import { setOptions, setMenuOptions, isEnabled } from '../../config/plugins'; +import { debounce } from '../../providers/decorators'; + +import { YoutubePlayer } from '../../types/youtube-player'; + +import type { ConfigType } from '../../config/dynamic'; + +function $(selector: string) { + return document.querySelector(selector); +} + +let api: YoutubePlayer; +let options: ConfigType<'precise-volume'>; + +export default (_options: ConfigType<'precise-volume'>) => { + options = _options; + document.addEventListener('apiLoaded', (e) => { + api = e.detail; + ipcRenderer.on('changeVolume', (_, toIncrease: boolean) => changeVolume(toIncrease)); + ipcRenderer.on('setVolume', (_, value: number) => setVolume(value)); + firstRun(); + }, { once: true, passive: true }); +}; + +// Without this function it would rewrite config 20 time when volume change by 20 +const writeOptions = debounce(() => { + setOptions('precise-volume', options); +}, 1000); + +export const moveVolumeHud = debounce((showVideo: boolean) => { + const volumeHud = $('#volumeHud'); + if (!volumeHud) { + return; + } + + volumeHud.style.top = showVideo + ? `${($('ytmusic-player')!.clientHeight - $('video')!.clientHeight) / 2}px` + : '0'; +}, 250); + +const hideVolumeHud = debounce((volumeHud: HTMLElement) => { + volumeHud.style.opacity = '0'; +}, 2000); + +const hideVolumeSlider = debounce((slider: HTMLElement) => { + slider.classList.remove('on-hover'); +}, 2500); + +/** Restore saved volume and setup tooltip */ +function firstRun() { + if (typeof options.savedVolume === 'number') { + // Set saved volume as tooltip + setTooltip(options.savedVolume); + + if (api.getVolume() !== options.savedVolume) { + api.setVolume(options.savedVolume); + } + } + + setupPlaybar(); + + setupLocalArrowShortcuts(); + + // Workaround: computedStyleMap().get(string) returns CSSKeywordValue instead of CSSStyleValue + const noVid = ($('#main-panel')?.computedStyleMap().get('display') as CSSKeywordValue)?.value === 'none'; + injectVolumeHud(noVid); + if (!noVid) { + setupVideoPlayerOnwheel(); + if (!isEnabled('video-toggle')) { + // Video-toggle handles hud positioning on its own + const videoMode = () => api.getPlayerResponse().videoDetails?.musicVideoType !== 'MUSIC_VIDEO_TYPE_ATV'; + $('video')?.addEventListener('srcChanged', () => moveVolumeHud(videoMode())); + } + } + + // Change options from renderer to keep sync + ipcRenderer.on('setOptions', (_event, newOptions = {}) => { + Object.assign(options, newOptions); + setMenuOptions('precise-volume', options); + }); +} + +function injectVolumeHud(noVid: boolean) { + if (noVid) { + const position = 'top: 18px; right: 60px;'; + const mainStyle = 'font-size: xx-large;'; + + $('.center-content.ytmusic-nav-bar')?.insertAdjacentHTML( + 'beforeend', + ``, + ); + } else { + const position = 'top: 10px; left: 10px;'; + const mainStyle = 'font-size: xxx-large; webkit-text-stroke: 1px black; font-weight: 600;'; + + $('#song-video')?.insertAdjacentHTML( + 'afterend', + ``, + ); + } +} + +function showVolumeHud(volume: number) { + const volumeHud = $('#volumeHud'); + if (!volumeHud) { + return; + } + + volumeHud.textContent = `${volume}%`; + volumeHud.style.opacity = '1'; + + hideVolumeHud(volumeHud); +} + +/** Add onwheel event to video player */ +function setupVideoPlayerOnwheel() { + const panel = $('#main-panel'); + if (!panel) return; + + panel.addEventListener('wheel', (event) => { + event.preventDefault(); + // Event.deltaY < 0 means wheel-up + changeVolume(event.deltaY < 0); + }); +} + +function saveVolume(volume: number) { + options.savedVolume = volume; + writeOptions(); +} + +/** Add onwheel event to play bar and also track if play bar is hovered */ +function setupPlaybar() { + const playerbar = $('ytmusic-player-bar'); + if (!playerbar) return; + + playerbar.addEventListener('wheel', (event) => { + event.preventDefault(); + // Event.deltaY < 0 means wheel-up + changeVolume(event.deltaY < 0); + }); + + // Keep track of mouse position for showVolumeSlider() + playerbar.addEventListener('mouseenter', () => { + playerbar.classList.add('on-hover'); + }); + + playerbar.addEventListener('mouseleave', () => { + playerbar.classList.remove('on-hover'); + }); + + setupSliderObserver(); +} + +/** Save volume + Update the volume tooltip when volume-slider is manually changed */ +function setupSliderObserver() { + const sliderObserver = new MutationObserver((mutations) => { + for (const mutation of mutations) { + if (mutation.target instanceof HTMLInputElement) { + // This checks that volume-slider was manually set + const target = mutation.target; + const targetValueNumeric = Number(target.value); + if (mutation.oldValue !== target.value + && (typeof options.savedVolume !== 'number' || Math.abs(options.savedVolume - targetValueNumeric) > 4)) { + // Diff>4 means it was manually set + setTooltip(targetValueNumeric); + saveVolume(targetValueNumeric); + } + } + } + }); + + const slider = $('#volume-slider'); + if (!slider) return; + + // Observing only changes in 'value' of volume-slider + sliderObserver.observe(slider, { + attributeFilter: ['value'], + attributeOldValue: true, + }); +} + +function setVolume(value: number) { + api.setVolume(value); + // Save the new volume + saveVolume(value); + + // Change slider position (important) + updateVolumeSlider(); + + // Change tooltips to new value + setTooltip(value); + // Show volume slider + showVolumeSlider(); + // Show volume HUD + showVolumeHud(value); +} + +/** If (toIncrease = false) then volume decrease */ +function changeVolume(toIncrease: boolean) { + // Apply volume change if valid + const steps = Number(options.steps || 1); + setVolume(toIncrease + ? Math.min(api.getVolume() + steps, 100) + : Math.max(api.getVolume() - steps, 0)); +} + +function updateVolumeSlider() { + const savedVolume = options.savedVolume ?? 0; + // Slider value automatically rounds to multiples of 5 + for (const slider of ['#volume-slider', '#expand-volume-slider']) { + const silderElement = $(slider); + if (silderElement) { + silderElement.value = String(savedVolume > 0 && savedVolume < 5 ? 5 : savedVolume); + } + } +} + +function showVolumeSlider() { + const slider = $('#volume-slider'); + if (!slider) return; + + // This class display the volume slider if not in minimized mode + slider.classList.add('on-hover'); + + hideVolumeSlider(slider); +} + +// Set new volume as tooltip for volume slider and icon + expanding slider (appears when window size is small) +const tooltipTargets = [ + '#volume-slider', + 'tp-yt-paper-icon-button.volume', + '#expand-volume-slider', + '#expand-volume', +]; + +function setTooltip(volume: number) { + for (const target of tooltipTargets) { + const tooltipTargetElement = $(target); + if (tooltipTargetElement) { + tooltipTargetElement.title = `${volume}%`; + } + } +} + +function setupLocalArrowShortcuts() { + if (options.arrowsShortcut) { + window.addEventListener('keydown', (event) => { + if ($('ytmusic-search-box')?.opened) { + return; + } + + switch (event.code) { + case 'ArrowUp': { + event.preventDefault(); + changeVolume(true); + break; + } + + case 'ArrowDown': { + event.preventDefault(); + changeVolume(false); + break; + } + } + }); + } +} diff --git a/plugins/precise-volume/menu.js b/plugins/precise-volume/menu.js deleted file mode 100644 index 74f7b14a..00000000 --- a/plugins/precise-volume/menu.js +++ /dev/null @@ -1,82 +0,0 @@ -const { enabled } = require("./back"); -const { setMenuOptions } = require("../../config/plugins"); -const prompt = require("custom-electron-prompt"); -const promptOptions = require("../../providers/prompt-options"); - -function changeOptions(changedOptions, options, win) { - for (option in changedOptions) { - options[option] = changedOptions[option]; - } - // Dynamically change setting if plugin is enabled - if (enabled()) { - win.webContents.send("setOptions", changedOptions); - } else { // Fallback to usual method if disabled - setMenuOptions("precise-volume", options); - } -} - -module.exports = (win, options) => [ - { - label: "Local Arrowkeys Controls", - type: "checkbox", - checked: !!options.arrowsShortcut, - click: item => { - changeOptions({ arrowsShortcut: item.checked }, options, win); - } - }, - { - label: "Global Hotkeys", - type: "checkbox", - checked: !!options.globalShortcuts.volumeUp || !!options.globalShortcuts.volumeDown, - click: item => promptGlobalShortcuts(win, options, item) - }, - { - label: "Set Custom Volume Steps", - click: () => promptVolumeSteps(win, options) - } -]; - -// Helper function for globalShortcuts prompt -const kb = (label_, value_, default_) => { return { value: value_, label: label_, default: default_ || undefined }; }; - -async function promptVolumeSteps(win, options) { - const output = await prompt({ - title: "Volume Steps", - label: "Choose Volume Increase/Decrease Steps", - value: options.steps || 1, - type: "counter", - counterOptions: { minimum: 0, maximum: 100, multiFire: true }, - width: 380, - ...promptOptions() - }, win) - - if (output || output === 0) { // 0 is somewhat valid - changeOptions({ steps: output}, options, win); - } -} - -async function promptGlobalShortcuts(win, options, item) { - const output = await prompt({ - title: "Global Volume Keybinds", - label: "Choose Global Volume Keybinds:", - type: "keybind", - keybindOptions: [ - kb("Increase Volume", "volumeUp", options.globalShortcuts?.volumeUp), - kb("Decrease Volume", "volumeDown", options.globalShortcuts?.volumeDown) - ], - ...promptOptions() - }, win) - - if (output) { - let newGlobalShortcuts = {}; - for (const { value, accelerator } of output) { - newGlobalShortcuts[value] = accelerator; - } - changeOptions({ globalShortcuts: newGlobalShortcuts }, options, win); - - item.checked = !!options.globalShortcuts.volumeUp || !!options.globalShortcuts.volumeDown; - } else { - // Reset checkbox if prompt was canceled - item.checked = !item.checked; - } -} diff --git a/plugins/precise-volume/menu.ts b/plugins/precise-volume/menu.ts new file mode 100644 index 00000000..de6dfceb --- /dev/null +++ b/plugins/precise-volume/menu.ts @@ -0,0 +1,94 @@ +import prompt, { KeybindOptions } from 'custom-electron-prompt'; + +import { BrowserWindow, MenuItem } from 'electron'; + +import { enabled } from './back'; + +import { setMenuOptions } from '../../config/plugins'; +import promptOptions from '../../providers/prompt-options'; +import { MenuTemplate } from '../../menu'; + +import type { ConfigType } from '../../config/dynamic'; + +function changeOptions(changedOptions: Partial>, options: ConfigType<'precise-volume'>, win: BrowserWindow) { + for (const option in changedOptions) { + // HACK: Weird TypeScript error + (options as Record)[option] = (changedOptions as Record)[option]; + } + // Dynamically change setting if plugin is enabled + if (enabled()) { + win.webContents.send('setOptions', changedOptions); + } else { // Fallback to usual method if disabled + setMenuOptions('precise-volume', options); + } +} + +export default (win: BrowserWindow, options: ConfigType<'precise-volume'>): MenuTemplate => [ + { + label: 'Local Arrowkeys Controls', + type: 'checkbox', + checked: Boolean(options.arrowsShortcut), + click(item) { + changeOptions({ arrowsShortcut: item.checked }, options, win); + }, + }, + { + label: 'Global Hotkeys', + type: 'checkbox', + checked: Boolean(options.globalShortcuts.volumeUp) || Boolean(options.globalShortcuts.volumeDown), + click: (item) => promptGlobalShortcuts(win, options, item), + }, + { + label: 'Set Custom Volume Steps', + click: () => promptVolumeSteps(win, options), + }, +]; + +// Helper function for globalShortcuts prompt +const kb = (label_: string, value_: string, default_: string): KeybindOptions => ({ 'value': value_, 'label': label_, 'default': default_ || undefined }); + +async function promptVolumeSteps(win: BrowserWindow, options: ConfigType<'precise-volume'>) { + const output = await prompt({ + title: 'Volume Steps', + label: 'Choose Volume Increase/Decrease Steps', + value: options.steps || 1, + type: 'counter', + counterOptions: { minimum: 0, maximum: 100, multiFire: true }, + width: 380, + ...promptOptions(), + }, win); + + if (output || output === 0) { // 0 is somewhat valid + changeOptions({ steps: output }, options, win); + } +} + +async function promptGlobalShortcuts(win: BrowserWindow, options: ConfigType<'precise-volume'>, item: MenuItem) { + const output = await prompt({ + title: 'Global Volume Keybinds', + label: 'Choose Global Volume Keybinds:', + type: 'keybind', + keybindOptions: [ + kb('Increase Volume', 'volumeUp', options.globalShortcuts?.volumeUp), + kb('Decrease Volume', 'volumeDown', options.globalShortcuts?.volumeDown), + ], + ...promptOptions(), + }, win); + + if (output) { + const newGlobalShortcuts: { + volumeUp: string; + volumeDown: string; + } = { volumeUp: '', volumeDown: '' }; + for (const { value, accelerator } of output) { + newGlobalShortcuts[value as keyof typeof newGlobalShortcuts] = accelerator; + } + + changeOptions({ globalShortcuts: newGlobalShortcuts }, options, win); + + item.checked = Boolean(options.globalShortcuts.volumeUp) || Boolean(options.globalShortcuts.volumeDown); + } else { + // Reset checkbox if prompt was canceled + item.checked = !item.checked; + } +} diff --git a/plugins/precise-volume/preload.js b/plugins/precise-volume/preload.js deleted file mode 100644 index 31ae2f84..00000000 --- a/plugins/precise-volume/preload.js +++ /dev/null @@ -1,32 +0,0 @@ -const is = require("electron-is"); - -let ignored = { - id: ["volume-slider", "expand-volume-slider"], - types: ["mousewheel", "keydown", "keyup"] -}; - -function overrideAddEventListener() { - // Save native addEventListener - Element.prototype._addEventListener = Element.prototype.addEventListener; - // Override addEventListener to Ignore specific events in volume-slider - Element.prototype.addEventListener = function (type, listener, useCapture = false) { - if (!( - ignored.id.includes(this.id) && - ignored.types.includes(type) - )) { - this._addEventListener(type, listener, useCapture); - } else if (is.dev()) { - console.log(`Ignoring event: "${this.id}.${type}()"`); - } - }; -} - -module.exports = () => { - overrideAddEventListener(); - // Restore original function after finished loading to avoid keeping Element.prototype altered - window.addEventListener('load', () => { - Element.prototype.addEventListener = Element.prototype._addEventListener; - Element.prototype._addEventListener = undefined; - ignored = undefined; - }, { once: true }); -}; diff --git a/plugins/precise-volume/preload.ts b/plugins/precise-volume/preload.ts new file mode 100644 index 00000000..363ee527 --- /dev/null +++ b/plugins/precise-volume/preload.ts @@ -0,0 +1,41 @@ +/* what */ +/* eslint-disable @typescript-eslint/ban-ts-comment */ + +import is from 'electron-is'; + +const ignored = { + id: ['volume-slider', 'expand-volume-slider'], + types: ['mousewheel', 'keydown', 'keyup'], +}; + +function overrideAddEventListener() { + // YO WHAT ARE YOU DOING NOW?!?! + // Save native addEventListener + // @ts-ignore + // eslint-disable-next-line @typescript-eslint/unbound-method + Element.prototype._addEventListener = Element.prototype.addEventListener; + // Override addEventListener to Ignore specific events in volume-slider + Element.prototype.addEventListener = function (type: string, listener: (event: Event) => void, useCapture = false) { + if (!( + ignored.id.includes(this.id) + && ignored.types.includes(type) + )) { + // eslint-disable-next-line @typescript-eslint/no-explicit-any,@typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-member-access + (this as any)._addEventListener(type, listener, useCapture); + } else if (is.dev()) { + console.log(`Ignoring event: "${this.id}.${type}()"`); + } + }; +} + +export default () => { + overrideAddEventListener(); + // Restore original function after finished loading to avoid keeping Element.prototype altered + window.addEventListener('load', () => { + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment,@typescript-eslint/no-explicit-any,@typescript-eslint/no-unsafe-member-access + Element.prototype.addEventListener = (Element.prototype as any)._addEventListener; + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment,@typescript-eslint/no-explicit-any,@typescript-eslint/no-unsafe-member-access + (Element.prototype as any)._addEventListener = undefined; + + }, { once: true }); +}; diff --git a/plugins/precise-volume/volume-hud.css b/plugins/precise-volume/volume-hud.css index 618b94fc..71cc2c4e 100644 --- a/plugins/precise-volume/volume-hud.css +++ b/plugins/precise-volume/volume-hud.css @@ -1,11 +1,11 @@ #volumeHud { - z-index: 999; - position: absolute; - transition: opacity 0.6s; - pointer-events: none; - padding: 10px; + z-index: 999; + position: absolute; + transition: opacity 0.6s; + pointer-events: none; + padding: 10px; } ytmusic-player[player-ui-state_="MINIPLAYER"] #volumeHud { - top: 0 !important; + top: 0 !important; } diff --git a/plugins/quality-changer/back.js b/plugins/quality-changer/back.js deleted file mode 100644 index d46b8675..00000000 --- a/plugins/quality-changer/back.js +++ /dev/null @@ -1,15 +0,0 @@ -const { ipcMain, dialog } = require("electron"); - -module.exports = () => { - ipcMain.handle('qualityChanger', async (_, qualityLabels, currentIndex) => { - return await dialog.showMessageBox({ - type: "question", - buttons: qualityLabels, - defaultId: currentIndex, - title: "Choose Video Quality", - message: "Choose Video Quality:", - detail: `Current Quality: ${qualityLabels[currentIndex]}`, - cancelId: -1 - }) - }) -}; diff --git a/plugins/quality-changer/back.ts b/plugins/quality-changer/back.ts new file mode 100644 index 00000000..957320dd --- /dev/null +++ b/plugins/quality-changer/back.ts @@ -0,0 +1,13 @@ +import { ipcMain, dialog } from 'electron'; + +export default () => { + ipcMain.handle('qualityChanger', async (_, qualityLabels: string[], currentIndex: number) => await dialog.showMessageBox({ + type: 'question', + buttons: qualityLabels, + defaultId: currentIndex, + title: 'Choose Video Quality', + message: 'Choose Video Quality:', + detail: `Current Quality: ${qualityLabels[currentIndex]}`, + cancelId: -1, + })); +}; diff --git a/plugins/quality-changer/front.js b/plugins/quality-changer/front.js deleted file mode 100644 index 2b746d15..00000000 --- a/plugins/quality-changer/front.js +++ /dev/null @@ -1,34 +0,0 @@ -const { ElementFromFile, templatePath } = require("../utils"); -const { ipcRenderer } = require("electron"); - -function $(selector) { return document.querySelector(selector); } - -const qualitySettingsButton = ElementFromFile( - templatePath(__dirname, "qualitySettingsTemplate.html") -); - - -module.exports = () => { - document.addEventListener('apiLoaded', setup, { once: true, passive: true }); -} - -function setup(event) { - const api = event.detail; - - $('.top-row-buttons.ytmusic-player').prepend(qualitySettingsButton); - - qualitySettingsButton.onclick = function chooseQuality() { - setTimeout(() => $('#player').click()); - - const qualityLevels = api.getAvailableQualityLevels(); - - const currentIndex = qualityLevels.indexOf(api.getPlaybackQuality()); - - ipcRenderer.invoke('qualityChanger', api.getAvailableQualityLabels(), currentIndex).then(promise => { - if (promise.response === -1) return; - const newQuality = qualityLevels[promise.response]; - api.setPlaybackQualityRange(newQuality); - api.setPlaybackQuality(newQuality) - }); - } -} diff --git a/plugins/quality-changer/front.ts b/plugins/quality-changer/front.ts new file mode 100644 index 00000000..dd47a87b --- /dev/null +++ b/plugins/quality-changer/front.ts @@ -0,0 +1,40 @@ +import { ipcRenderer } from 'electron'; + +import { ElementFromFile, templatePath } from '../utils'; +import { YoutubePlayer } from '../../types/youtube-player'; + +function $(selector: string): HTMLElement | null { + return document.querySelector(selector); +} + +const qualitySettingsButton = ElementFromFile( + templatePath(__dirname, 'qualitySettingsTemplate.html'), +); + +function setup(event: CustomEvent) { + const api = event.detail; + + $('.top-row-buttons.ytmusic-player')?.prepend(qualitySettingsButton); + + qualitySettingsButton.addEventListener('click', function chooseQuality() { + setTimeout(() => $('#player')?.click()); + + const qualityLevels = api.getAvailableQualityLevels(); + + const currentIndex = qualityLevels.indexOf(api.getPlaybackQuality()); + + ipcRenderer.invoke('qualityChanger', api.getAvailableQualityLabels(), currentIndex).then((promise: { response: number }) => { + if (promise.response === -1) { + return; + } + + const newQuality = qualityLevels[promise.response]; + api.setPlaybackQualityRange(newQuality); + api.setPlaybackQuality(newQuality); + }); + }); +} + +export default () => { + document.addEventListener('apiLoaded', setup, { once: true, passive: true }); +}; diff --git a/plugins/quality-changer/templates/qualitySettingsTemplate.html b/plugins/quality-changer/templates/qualitySettingsTemplate.html index 64c012fe..1b7d5b1f 100644 --- a/plugins/quality-changer/templates/qualitySettingsTemplate.html +++ b/plugins/quality-changer/templates/qualitySettingsTemplate.html @@ -1,13 +1,16 @@ - - - - - - - - \ No newline at end of file + + + + + + + + + diff --git a/plugins/shortcuts/back.js b/plugins/shortcuts/back.js deleted file mode 100644 index 06d899d7..00000000 --- a/plugins/shortcuts/back.js +++ /dev/null @@ -1,62 +0,0 @@ -const { globalShortcut } = require("electron"); -const is = require("electron-is"); -const electronLocalshortcut = require("electron-localshortcut"); -const getSongControls = require("../../providers/song-controls"); -const registerMPRIS = require("./mpris"); - -function _registerGlobalShortcut(webContents, shortcut, action) { - globalShortcut.register(shortcut, () => { - action(webContents); - }); -} - -function _registerLocalShortcut(win, shortcut, action) { - electronLocalshortcut.register(win, shortcut, () => { - action(win.webContents); - }); -} - -function registerShortcuts(win, options) { - const songControls = getSongControls(win); - const { playPause, next, previous, search } = songControls; - - if (options.overrideMediaKeys) { - _registerGlobalShortcut(win.webContents, "MediaPlayPause", playPause); - _registerGlobalShortcut(win.webContents, "MediaNextTrack", next); - _registerGlobalShortcut(win.webContents, "MediaPreviousTrack", previous); - } - - _registerLocalShortcut(win, "CommandOrControl+F", search); - _registerLocalShortcut(win, "CommandOrControl+L", search); - - if (is.linux()) registerMPRIS(win); - - const { global, local } = options; - const shortcutOptions = { global, local }; - - for (const optionType in shortcutOptions) { - registerAllShortcuts(shortcutOptions[optionType], optionType); - } - - function registerAllShortcuts(container, type) { - for (const action in container) { - if (!container[action]) { - continue; // Action accelerator is empty - } - - console.debug(`Registering ${type} shortcut`, container[action], ":", action); - if (!songControls[action]) { - console.warn("Invalid action", action); - continue; - } - - if (type === "global") { - _registerGlobalShortcut(win.webContents, container[action], songControls[action]); - } else { // type === "local" - _registerLocalShortcut(win, local[action], songControls[action]); - } - } - } -} - -module.exports = registerShortcuts; diff --git a/plugins/shortcuts/back.ts b/plugins/shortcuts/back.ts new file mode 100644 index 00000000..8447092f --- /dev/null +++ b/plugins/shortcuts/back.ts @@ -0,0 +1,69 @@ +import { BrowserWindow, globalShortcut } from 'electron'; +import is from 'electron-is'; +import electronLocalshortcut from 'electron-localshortcut'; + +import registerMPRIS from './mpris'; + +import getSongControls from '../../providers/song-controls'; + +import type { ConfigType } from '../../config/dynamic'; + +function _registerGlobalShortcut(webContents: Electron.WebContents, shortcut: string, action: (webContents: Electron.WebContents) => void) { + globalShortcut.register(shortcut, () => { + action(webContents); + }); +} + +function _registerLocalShortcut(win: BrowserWindow, shortcut: string, action: (webContents: Electron.WebContents) => void) { + electronLocalshortcut.register(win, shortcut, () => { + action(win.webContents); + }); +} + +function registerShortcuts(win: BrowserWindow, options: ConfigType<'shortcuts'>) { + const songControls = getSongControls(win); + const { playPause, next, previous, search } = songControls; + + if (options.overrideMediaKeys) { + _registerGlobalShortcut(win.webContents, 'MediaPlayPause', playPause); + _registerGlobalShortcut(win.webContents, 'MediaNextTrack', next); + _registerGlobalShortcut(win.webContents, 'MediaPreviousTrack', previous); + } + + _registerLocalShortcut(win, 'CommandOrControl+F', search); + _registerLocalShortcut(win, 'CommandOrControl+L', search); + + if (is.linux()) { + registerMPRIS(win); + } + + const { global, local } = options; + const shortcutOptions = { global, local }; + + for (const optionType in shortcutOptions) { + registerAllShortcuts(shortcutOptions[optionType as 'global' | 'local'], optionType); + } + + function registerAllShortcuts(container: Record, type: string) { + for (const action in container) { + if (!container[action]) { + continue; // Action accelerator is empty + } + + console.debug(`Registering ${type} shortcut`, container[action], ':', action); + const actionCallback: () => void = songControls[action as keyof typeof songControls]; + if (typeof actionCallback !== 'function') { + console.warn('Invalid action', action); + continue; + } + + if (type === 'global') { + _registerGlobalShortcut(win.webContents, container[action], actionCallback); + } else { // Type === "local" + _registerLocalShortcut(win, local[action], actionCallback); + } + } + } +} + +export default registerShortcuts; diff --git a/plugins/shortcuts/menu.js b/plugins/shortcuts/menu.js deleted file mode 100644 index df9db161..00000000 --- a/plugins/shortcuts/menu.js +++ /dev/null @@ -1,53 +0,0 @@ -const { setMenuOptions } = require("../../config/plugins"); -const prompt = require("custom-electron-prompt"); -const promptOptions = require("../../providers/prompt-options"); - -module.exports = (win, options) => [ - { - label: "Set Global Song Controls", - click: () => promptKeybind(options, win) - }, - { - label: "Override MediaKeys", - type: "checkbox", - checked: options.overrideMediaKeys, - click: item => setOption(options, "overrideMediaKeys", item.checked) - } -]; - -function setOption(options, key = null, newValue = null) { - if (key && newValue !== null) { - options[key] = newValue; - } - - setMenuOptions("shortcuts", options); -} - -// Helper function for keybind prompt -const kb = (label_, value_, default_) => { return { value: value_, label: label_, default: default_ }; }; - -async function promptKeybind(options, win) { - const output = await prompt({ - title: "Global Keybinds", - label: "Choose Global Keybinds for Songs Control:", - type: "keybind", - keybindOptions: [ // If default=undefined then no default is used - kb("Previous", "previous", options.global?.previous), - kb("Play / Pause", "playPause", options.global?.playPause), - kb("Next", "next", options.global?.next) - ], - height: 270, - ...promptOptions() - }, win); - - if (output) { - if (!options.global) { - options.global = {}; - } - for (const { value, accelerator } of output) { - options.global[value] = accelerator; - } - setOption(options); - } - // else -> pressed cancel -} diff --git a/plugins/shortcuts/menu.ts b/plugins/shortcuts/menu.ts new file mode 100644 index 00000000..68854fe7 --- /dev/null +++ b/plugins/shortcuts/menu.ts @@ -0,0 +1,67 @@ +import prompt, { KeybindOptions } from 'custom-electron-prompt'; + +import { BrowserWindow } from 'electron'; + +import { setMenuOptions } from '../../config/plugins'; + + +import promptOptions from '../../providers/prompt-options'; +import { MenuTemplate } from '../../menu'; + +import type { ConfigType } from '../../config/dynamic'; + +export default (win: BrowserWindow, options: ConfigType<'shortcuts'>): MenuTemplate => [ + { + label: 'Set Global Song Controls', + click: () => promptKeybind(options, win), + }, + { + label: 'Override MediaKeys', + type: 'checkbox', + checked: options.overrideMediaKeys, + click: (item) => setOption(options, 'overrideMediaKeys', item.checked), + }, +]; + +function setOption = keyof ConfigType<'shortcuts'>>( + options: ConfigType<'shortcuts'>, + key: Key | null = null, + newValue: ConfigType<'shortcuts'>[Key] | null = null, +) { + if (key && newValue !== null) { + options[key] = newValue; + } + + setMenuOptions('shortcuts', options); +} + +// Helper function for keybind prompt +const kb = (label_: string, value_: string, default_: string): KeybindOptions => ({ value: value_, label: label_, default: default_ }); + +async function promptKeybind(options: ConfigType<'shortcuts'>, win: BrowserWindow) { + const output = await prompt({ + title: 'Global Keybinds', + label: 'Choose Global Keybinds for Songs Control:', + type: 'keybind', + keybindOptions: [ // If default=undefined then no default is used + kb('Previous', 'previous', options.global?.previous), + kb('Play / Pause', 'playPause', options.global?.playPause), + kb('Next', 'next', options.global?.next), + ], + height: 270, + ...promptOptions(), + }, win); + + if (output) { + if (!options.global) { + options.global = {}; + } + + for (const { value, accelerator } of output) { + options.global[value] = accelerator; + } + + setOption(options); + } + // Else -> pressed cancel +} diff --git a/plugins/shortcuts/mpris-service.d.ts b/plugins/shortcuts/mpris-service.d.ts new file mode 100644 index 00000000..3f9ceff8 --- /dev/null +++ b/plugins/shortcuts/mpris-service.d.ts @@ -0,0 +1,129 @@ +declare module 'mpris-service' { + import { EventEmitter } from 'events'; + + import dbus from 'dbus-next'; + + + interface RootInterfaceOptions { + identity: string; + supportedUriSchemes: string[]; + supportedMimeTypes: string[]; + desktopEntry: string; + } + + export interface Track { + 'mpris:trackid'?: string; + 'mpris:length'?: number; + 'mpris:artUrl'?: string; + 'xesam:album'?: string; + 'xesam:albumArtist'?: string[]; + 'xesam:artist'?: string[]; + 'xesam:asText'?: string; + 'xesam:audioBPM'?: number; + 'xesam:autoRating'?: number; + 'xesam:comment'?: string[]; + 'xesam:composer'?: string[]; + 'xesam:contentCreated'?: string; + 'xesam:discNumber'?: number; + 'xesam:firstUsed'?: string; + 'xesam:genre'?: string[]; + 'xesam:lastUsed'?: string; + 'xesam:lyricist'?: string[]; + 'xesam:title'?: string; + 'xesam:trackNumber'?: number; + 'xesam:url'?: string; + 'xesam:useCount'?: number; + 'xesam:userRating'?: number; + } + + declare class Player extends EventEmitter { + constructor(opts: { + name: string; + identity: string; + supportedMimeTypes?: string[]; + supportedInterfaces?: string[]; + }); + + name: string; + identity: string; + fullscreen: boolean; + supportedUriSchemes: string[]; + supportedMimeTypes: string[]; + canQuit: boolean; + canRaise: boolean; + canSetFullscreen: boolean; + hasTrackList: boolean; + desktopEntry: string; + playbackStatus: string; + loopStatus: string; + shuffle: boolean; + metadata: object; + volume: number; + canControl: boolean; + canPause: boolean; + canPlay: boolean; + canSeek: boolean; + canGoNext: boolean; + canGoPrevious: boolean; + rate: number; + minimumRate: number; + maximumRate: number; + playlists: unknown[]; + activePlaylist: string; + + init(opts: RootInterfaceOptions): void; + + objectPath(subpath?: string): string; + + seeked(position: number): void; + + getTrackIndex(trackId: string): number; + + getTrack(trackId: string): Track; + + addTrack(track: Track): void; + + removeTrack(trackId: string): void; + + getPlaylistIndex(playlistId: string): number; + + setPlaylists(playlists: Track[]): void; + + setActivePlaylist(playlistId: string): void; + + static PLAYBACK_STATUS_PLAYING: 'Playing'; + static PLAYBACK_STATUS_PAUSED: 'Paused'; + static PLAYBACK_STATUS_STOPPED: 'Stopped'; + static LOOP_STATUS_NONE: 'None'; + static LOOP_STATUS_TRACK: 'Track'; + static LOOP_STATUS_PLAYLIST: 'Playlist'; + } + + interface MprisInterface extends dbus.interface.Interface { + setProperty(property: string, valuePlain: unknown): void; + } + + interface RootInterface { + } + + interface PlayerInterface { + } + + interface TracklistInterface { + + TrackListReplaced(tracks: Track[]): void; + + TrackAdded(afterTrack: string): void; + + TrackRemoved(trackId: string): void; + } + + interface PlaylistsInterface { + + PlaylistChanged(playlist: unknown[]): void; + + setActivePlaylistId(playlistId: string): void; + } + + export default Player; +} diff --git a/plugins/shortcuts/mpris.js b/plugins/shortcuts/mpris.js deleted file mode 100644 index 8b8aeb9f..00000000 --- a/plugins/shortcuts/mpris.js +++ /dev/null @@ -1,164 +0,0 @@ -const mpris = require("mpris-service"); -const { ipcMain } = require("electron"); -const registerCallback = require("../../providers/song-info"); -const getSongControls = require("../../providers/song-controls"); -const config = require("../../config"); - -function setupMPRIS() { - const player = mpris({ - name: "youtube-music", - identity: "YouTube Music", - canRaise: true, - supportedUriSchemes: ["https"], - supportedMimeTypes: ["audio/mpeg"], - supportedInterfaces: ["player"], - desktopEntry: "youtube-music", - }); - - return player; -} - -/** @param {Electron.BrowserWindow} win */ -function registerMPRIS(win) { - const songControls = getSongControls(win); - const { playPause, next, previous, volumeMinus10, volumePlus10, shuffle } = songControls; - try { - const secToMicro = n => Math.round(Number(n) * 1e6); - const microToSec = n => Math.round(Number(n) / 1e6); - - const seekTo = e => win.webContents.send("seekTo", microToSec(e.position)); - const seekBy = o => win.webContents.send("seekBy", microToSec(o)); - - const player = setupMPRIS(); - - ipcMain.on("apiLoaded", () => { - win.webContents.send("setupSeekedListener", "mpris"); - win.webContents.send("setupTimeChangedListener", "mpris"); - win.webContents.send("setupRepeatChangedListener", "mpris"); - win.webContents.send("setupVolumeChangedListener", "mpris"); - }); - - ipcMain.on('seeked', (_, t) => player.seeked(secToMicro(t))); - - let currentSeconds = 0; - ipcMain.on('timeChanged', (_, t) => currentSeconds = t); - - ipcMain.on("repeatChanged", (_, mode) => { - if (mode === "NONE") - player.loopStatus = mpris.LOOP_STATUS_NONE; - else if (mode === "ONE") //MPRIS Playlist and Track Codes are switched to look the same as yt-music icons - player.loopStatus = mpris.LOOP_STATUS_PLAYLIST; - else if (mode === "ALL") - player.loopStatus = mpris.LOOP_STATUS_TRACK; - }); - player.on("loopStatus", (status) => { - // switchRepeat cycles between states in that order - const switches = [mpris.LOOP_STATUS_NONE, mpris.LOOP_STATUS_PLAYLIST, mpris.LOOP_STATUS_TRACK]; - const currentIndex = switches.indexOf(player.loopStatus); - const targetIndex = switches.indexOf(status); - - // Get a delta in the range [0,2] - const delta = (targetIndex - currentIndex + 3) % 3; - songControls.switchRepeat(delta); - }) - - player.getPosition = () => secToMicro(currentSeconds) - - player.on("raise", () => { - win.setSkipTaskbar(false); - win.show(); - }); - - player.on("play", () => { - if (player.playbackStatus !== mpris.PLAYBACK_STATUS_PLAYING) { - player.playbackStatus = mpris.PLAYBACK_STATUS_PLAYING; - playPause() - } - }); - player.on("pause", () => { - if (player.playbackStatus !== mpris.PLAYBACK_STATUS_PAUSED) { - player.playbackStatus = mpris.PLAYBACK_STATUS_PAUSED; - playPause() - } - }); - player.on("playpause", () => { - player.playbackStatus = player.playbackStatus === mpris.PLAYBACK_STATUS_PLAYING ? mpris.PLAYBACK_STATUS_PAUSED : mpris.PLAYBACK_STATUS_PLAYING; - playPause(); - }); - - player.on("next", next); - player.on("previous", previous); - - player.on('seek', seekBy); - player.on('position', seekTo); - - player.on('shuffle', (enableShuffle) => { - shuffle(); - }); - - let mprisVolNewer = false; - let autoUpdate = false; - ipcMain.on('volumeChanged', (_, newVol) => { - if (parseInt(player.volume * 100) !== newVol) { - if (mprisVolNewer) { - mprisVolNewer = false; - autoUpdate = false; - } else { - autoUpdate = true; - player.volume = parseFloat((newVol / 100).toFixed(2)); - mprisVolNewer = false; - autoUpdate = false; - } - } - }); - - player.on('volume', (newVolume) => { - if (config.plugins.isEnabled('precise-volume')) { - // With precise volume we can set the volume to the exact value. - let newVol = parseInt(newVolume * 100); - if (parseInt(player.volume * 100) !== newVol) { - if (!autoUpdate) { - mprisVolNewer = true; - autoUpdate = false; - win.webContents.send('setVolume', newVol); - } - } - } else { - // With keyboard shortcuts we can only change the volume in increments of 10, so round it. - let deltaVolume = Math.round((newVolume - player.volume) * 10); - while (deltaVolume !== 0 && deltaVolume > 0) { - volumePlus10(); - player.volume = player.volume + 0.1; - deltaVolume--; - } - while (deltaVolume !== 0 && deltaVolume < 0) { - volumeMinus10(); - player.volume = player.volume - 0.1; - deltaVolume++; - } - } - }); - - registerCallback(songInfo => { - if (player) { - const data = { - 'mpris:length': secToMicro(songInfo.songDuration), - 'mpris:artUrl': songInfo.imageSrc, - 'xesam:title': songInfo.title, - 'xesam:url': songInfo.url, - 'xesam:artist': [songInfo.artist], - 'mpris:trackid': '/' - }; - if (songInfo.album) data['xesam:album'] = songInfo.album; - player.metadata = data; - player.seeked(secToMicro(songInfo.elapsedSeconds)); - player.playbackStatus = songInfo.isPaused ? mpris.PLAYBACK_STATUS_PAUSED : mpris.PLAYBACK_STATUS_PLAYING; - } - }) - - } catch (e) { - console.warn("Error in MPRIS", e); - } -} - -module.exports = registerMPRIS; diff --git a/plugins/shortcuts/mpris.ts b/plugins/shortcuts/mpris.ts new file mode 100644 index 00000000..5c7d3dad --- /dev/null +++ b/plugins/shortcuts/mpris.ts @@ -0,0 +1,180 @@ +import { BrowserWindow, ipcMain } from 'electron'; + +import mpris, { Track } from 'mpris-service'; + +import registerCallback from '../../providers/song-info'; +import getSongControls from '../../providers/song-controls'; +import config from '../../config'; + +function setupMPRIS() { + const instance = new mpris({ + name: 'youtube-music', + identity: 'YouTube Music', + supportedMimeTypes: ['audio/mpeg'], + supportedInterfaces: ['player'], + }); + instance.canRaise = true; + instance.supportedUriSchemes = ['https']; + instance.desktopEntry = 'youtube-music'; + return instance; +} + +function registerMPRIS(win: BrowserWindow) { + const songControls = getSongControls(win); + const { playPause, next, previous, volumeMinus10, volumePlus10, shuffle } = songControls; + try { + // TODO: "Typing" for this arguments + const secToMicro = (n: unknown) => Math.round(Number(n) * 1e6); + const microToSec = (n: unknown) => Math.round(Number(n) / 1e6); + + const seekTo = (e: { position: unknown }) => win.webContents.send('seekTo', microToSec(e.position)); + const seekBy = (o: unknown) => win.webContents.send('seekBy', microToSec(o)); + + const player = setupMPRIS(); + + ipcMain.on('apiLoaded', () => { + win.webContents.send('setupSeekedListener', 'mpris'); + win.webContents.send('setupTimeChangedListener', 'mpris'); + win.webContents.send('setupRepeatChangedListener', 'mpris'); + win.webContents.send('setupVolumeChangedListener', 'mpris'); + }); + + ipcMain.on('seeked', (_, t: number) => player.seeked(secToMicro(t))); + + let currentSeconds = 0; + ipcMain.on('timeChanged', (_, t: number) => currentSeconds = t); + + ipcMain.on('repeatChanged', (_, mode: string) => { + switch (mode) { + case 'NONE': { + player.loopStatus = mpris.LOOP_STATUS_NONE; + break; + } + + case 'ONE': { + player.loopStatus = mpris.LOOP_STATUS_PLAYLIST; + break; + } + + case 'ALL': { + { + player.loopStatus = mpris.LOOP_STATUS_TRACK; + // No default + } + + break; + } + } + }); + player.on('loopStatus', (status: string) => { + // SwitchRepeat cycles between states in that order + const switches = [mpris.LOOP_STATUS_NONE, mpris.LOOP_STATUS_PLAYLIST, mpris.LOOP_STATUS_TRACK]; + const currentIndex = switches.indexOf(player.loopStatus); + const targetIndex = switches.indexOf(status); + + // Get a delta in the range [0,2] + const delta = (targetIndex - currentIndex + 3) % 3; + songControls.switchRepeat(delta); + }); + + player.on('raise', () => { + win.setSkipTaskbar(false); + win.show(); + }); + + player.on('play', () => { + if (player.playbackStatus !== mpris.PLAYBACK_STATUS_PLAYING) { + player.playbackStatus = mpris.PLAYBACK_STATUS_PLAYING; + playPause(); + } + }); + player.on('pause', () => { + if (player.playbackStatus !== mpris.PLAYBACK_STATUS_PAUSED) { + player.playbackStatus = mpris.PLAYBACK_STATUS_PAUSED; + playPause(); + } + }); + player.on('playpause', () => { + player.playbackStatus = player.playbackStatus === mpris.PLAYBACK_STATUS_PLAYING ? mpris.PLAYBACK_STATUS_PAUSED : mpris.PLAYBACK_STATUS_PLAYING; + playPause(); + }); + + player.on('next', next); + player.on('previous', previous); + + player.on('seek', seekBy); + player.on('position', seekTo); + + player.on('shuffle', (enableShuffle) => { + if (enableShuffle) { + shuffle(); + } + }); + + let mprisVolNewer = false; + let autoUpdate = false; + ipcMain.on('volumeChanged', (_, newVol) => { + if (~~(player.volume * 100) !== newVol) { + if (mprisVolNewer) { + mprisVolNewer = false; + autoUpdate = false; + } else { + autoUpdate = true; + player.volume = Number.parseFloat((newVol / 100).toFixed(2)); + mprisVolNewer = false; + autoUpdate = false; + } + } + }); + + player.on('volume', (newVolume) => { + if (config.plugins.isEnabled('precise-volume')) { + // With precise volume we can set the volume to the exact value. + const newVol = ~~(newVolume * 100); + if (~~(player.volume * 100) !== newVol && !autoUpdate) { + mprisVolNewer = true; + autoUpdate = false; + win.webContents.send('setVolume', newVol); + } + } else { + // With keyboard shortcuts we can only change the volume in increments of 10, so round it. + let deltaVolume = Math.round((newVolume - player.volume) * 10); + while (deltaVolume !== 0 && deltaVolume > 0) { + volumePlus10(); + player.volume += 0.1; + deltaVolume--; + } + + while (deltaVolume !== 0 && deltaVolume < 0) { + volumeMinus10(); + player.volume -= 0.1; + deltaVolume++; + } + } + }); + + registerCallback((songInfo) => { + if (player) { + const data: Track = { + 'mpris:length': secToMicro(songInfo.songDuration), + 'mpris:artUrl': songInfo.imageSrc ?? undefined, + 'xesam:title': songInfo.title, + 'xesam:url': songInfo.url, + 'xesam:artist': [songInfo.artist], + 'mpris:trackid': '/', + }; + if (songInfo.album) { + data['xesam:album'] = songInfo.album; + } + + player.metadata = data; + player.seeked(secToMicro(songInfo.elapsedSeconds)); + player.playbackStatus = songInfo.isPaused ? mpris.PLAYBACK_STATUS_PAUSED : mpris.PLAYBACK_STATUS_PLAYING; + } + }); + } catch (error) { + console.warn('Error in MPRIS', error); + } +} + +export default registerMPRIS; diff --git a/plugins/skip-silences/front.js b/plugins/skip-silences/front.js deleted file mode 100644 index 69a6e919..00000000 --- a/plugins/skip-silences/front.js +++ /dev/null @@ -1,112 +0,0 @@ -module.exports = (options) => { - let isSilent = false; - let hasAudioStarted = false; - - const smoothing = 0.1; - const threshold = -100; // dB (-100 = absolute silence, 0 = loudest) - const interval = 2; // ms - const history = 10; - const speakingHistory = Array(history).fill(0); - - document.addEventListener( - "audioCanPlay", - (e) => { - const video = document.querySelector("video"); - const audioContext = e.detail.audioContext; - const sourceNode = e.detail.audioSource; - - // Use an audio analyser similar to Hark - // https://github.com/otalk/hark/blob/master/hark.bundle.js - const analyser = audioContext.createAnalyser(); - analyser.fftSize = 512; - analyser.smoothingTimeConstant = smoothing; - const fftBins = new Float32Array(analyser.frequencyBinCount); - - sourceNode.connect(analyser); - analyser.connect(audioContext.destination); - - const looper = () => { - setTimeout(() => { - const currentVolume = getMaxVolume(analyser, fftBins); - - let history = 0; - if (currentVolume > threshold && isSilent) { - // trigger quickly, short history - for ( - let i = speakingHistory.length - 3; - i < speakingHistory.length; - i++ - ) { - history += speakingHistory[i]; - } - if (history >= 2) { - // Not silent - isSilent = false; - hasAudioStarted = true; - } - } else if (currentVolume < threshold && !isSilent) { - for (let i = 0; i < speakingHistory.length; i++) { - history += speakingHistory[i]; - } - if (history == 0) { - // Silent - if ( - !( - video.paused || - video.seeking || - video.ended || - video.muted || - video.volume === 0 - ) - ) { - isSilent = true; - skipSilence(); - } - } - } - speakingHistory.shift(); - speakingHistory.push(0 + (currentVolume > threshold)); - - looper(); - }, interval); - }; - looper(); - - const skipSilence = () => { - if (options.onlySkipBeginning && hasAudioStarted) { - return; - } - - if (isSilent && !video.paused) { - video.currentTime += 0.2; // in s - } - }; - - video.addEventListener("play", function () { - hasAudioStarted = false; - skipSilence(); - }); - - video.addEventListener("seeked", function () { - hasAudioStarted = false; - skipSilence(); - }); - }, - { - passive: true, - } - ); -}; - -function getMaxVolume(analyser, fftBins) { - var maxVolume = -Infinity; - analyser.getFloatFrequencyData(fftBins); - - for (var i = 4, ii = fftBins.length; i < ii; i++) { - if (fftBins[i] > maxVolume && fftBins[i] < 0) { - maxVolume = fftBins[i]; - } - } - - return maxVolume; -} diff --git a/plugins/skip-silences/front.ts b/plugins/skip-silences/front.ts new file mode 100644 index 00000000..b1db4199 --- /dev/null +++ b/plugins/skip-silences/front.ts @@ -0,0 +1,120 @@ +import type { ConfigType } from '../../config/dynamic'; + +type SkipSilencesOptions = ConfigType<'skip-silences'>; + +export default (options: SkipSilencesOptions) => { + let isSilent = false; + let hasAudioStarted = false; + + const smoothing = 0.1; + const threshold = -100; // DB (-100 = absolute silence, 0 = loudest) + const interval = 2; // Ms + const history = 10; + const speakingHistory = Array.from({ length: history }).fill(0) as number[]; + + document.addEventListener( + 'audioCanPlay', + (e) => { + const video = document.querySelector('video'); + const { audioContext } = e.detail; + const sourceNode = e.detail.audioSource; + + // Use an audio analyser similar to Hark + // https://github.com/otalk/hark/blob/master/hark.bundle.js + const analyser = audioContext.createAnalyser(); + analyser.fftSize = 512; + analyser.smoothingTimeConstant = smoothing; + const fftBins = new Float32Array(analyser.frequencyBinCount); + + sourceNode.connect(analyser); + analyser.connect(audioContext.destination); + + const looper = () => { + setTimeout(() => { + const currentVolume = getMaxVolume(analyser, fftBins); + + let history = 0; + if (currentVolume > threshold && isSilent) { + // Trigger quickly, short history + for ( + let i = speakingHistory.length - 3; + i < speakingHistory.length; + i++ + ) { + history += speakingHistory[i]; + } + + if (history >= 2) { + // Not silent + isSilent = false; + hasAudioStarted = true; + } + } else if (currentVolume < threshold && !isSilent) { + for (const element of speakingHistory) { + history += element; + } + + if (history == 0 // Silent + + && !( + video && ( + video.paused + || video.seeking + || video.ended + || video.muted + || video.volume === 0 + ) + ) + ) { + isSilent = true; + skipSilence(); + } + } + + speakingHistory.shift(); + speakingHistory.push(Number(currentVolume > threshold)); + + looper(); + }, interval); + }; + + looper(); + + const skipSilence = () => { + if (options.onlySkipBeginning && hasAudioStarted) { + return; + } + + if (isSilent && video && !video.paused) { + video.currentTime += 0.2; // In s + } + }; + + video?.addEventListener('play', () => { + hasAudioStarted = false; + skipSilence(); + }); + + video?.addEventListener('seeked', () => { + hasAudioStarted = false; + skipSilence(); + }); + }, + { + passive: true, + }, + ); +}; + +function getMaxVolume(analyser: AnalyserNode, fftBins: Float32Array) { + let maxVolume = Number.NEGATIVE_INFINITY; + analyser.getFloatFrequencyData(fftBins); + + for (let i = 4, ii = fftBins.length; i < ii; i++) { + if (fftBins[i] > maxVolume && fftBins[i] < 0) { + maxVolume = fftBins[i]; + } + } + + return maxVolume; +} diff --git a/plugins/sponsorblock/back.js b/plugins/sponsorblock/back.js deleted file mode 100644 index 04667b85..00000000 --- a/plugins/sponsorblock/back.js +++ /dev/null @@ -1,51 +0,0 @@ -const fetch = require("node-fetch"); -const is = require("electron-is"); -const { ipcMain } = require("electron"); - -const defaultConfig = require("../../config/defaults"); -const { sortSegments } = require("./segments"); - -let videoID; - -module.exports = (win, options) => { - const { apiURL, categories } = { - ...defaultConfig.plugins.sponsorblock, - ...options, - }; - - ipcMain.on("video-src-changed", async (_, data) => { - videoID = JSON.parse(data)?.videoDetails?.videoId; - const segments = await fetchSegments(apiURL, categories); - win.webContents.send("sponsorblock-skip", segments); - }); -}; - - -const fetchSegments = async (apiURL, categories) => { - const sponsorBlockURL = `${apiURL}/api/skipSegments?videoID=${videoID}&categories=${JSON.stringify( - categories - )}`; - try { - const resp = await fetch(sponsorBlockURL, { - method: "GET", - headers: { - "Content-Type": "application/json", - }, - redirect: "follow", - }); - if (resp.status !== 200) { - return []; - } - const segments = await resp.json(); - const sortedSegments = sortSegments( - segments.map((submission) => submission.segment) - ); - - return sortedSegments; - } catch (e) { - if (is.dev()) { - console.log('error on sponsorblock request:', e); - } - return []; - } -}; diff --git a/plugins/sponsorblock/back.ts b/plugins/sponsorblock/back.ts new file mode 100644 index 00000000..cd3e49d0 --- /dev/null +++ b/plugins/sponsorblock/back.ts @@ -0,0 +1,55 @@ +import { BrowserWindow, ipcMain } from 'electron'; +import is from 'electron-is'; + +import { sortSegments } from './segments'; + +import { SkipSegment } from './types'; + +import defaultConfig from '../../config/defaults'; + +import type { GetPlayerResponse } from '../../types/get-player-response'; +import type { ConfigType } from '../../config/dynamic'; + +let videoID: string; + +export default (win: BrowserWindow, options: ConfigType<'sponsorblock'>) => { + const { apiURL, categories } = { + ...defaultConfig.plugins.sponsorblock, + ...options, + }; + + ipcMain.on('video-src-changed', async (_, data: GetPlayerResponse) => { + videoID = data?.videoDetails?.videoId; + const segments = await fetchSegments(apiURL, categories); + win.webContents.send('sponsorblock-skip', segments); + }); +}; + +const fetchSegments = async (apiURL: string, categories: string[]) => { + const sponsorBlockURL = `${apiURL}/api/skipSegments?videoID=${videoID}&categories=${JSON.stringify( + categories, + )}`; + try { + const resp = await fetch(sponsorBlockURL, { + method: 'GET', + headers: { + 'Content-Type': 'application/json', + }, + redirect: 'follow', + }); + if (resp.status !== 200) { + return []; + } + + const segments = await resp.json() as SkipSegment[]; + return sortSegments( + segments.map((submission) => submission.segment), + ); + } catch (error) { + if (is.dev()) { + console.log('error on sponsorblock request:', error); + } + + return []; + } +}; diff --git a/plugins/sponsorblock/front.js b/plugins/sponsorblock/front.js deleted file mode 100644 index c4b32869..00000000 --- a/plugins/sponsorblock/front.js +++ /dev/null @@ -1,31 +0,0 @@ -const { ipcRenderer } = require("electron"); - -const is = require("electron-is"); - -let currentSegments = []; - -module.exports = () => { - ipcRenderer.on("sponsorblock-skip", (_, segments) => { - currentSegments = segments; - }); - - document.addEventListener('apiLoaded', () => { - const video = document.querySelector('video'); - - video.addEventListener('timeupdate', e => { - currentSegments.forEach((segment) => { - if ( - e.target.currentTime >= segment[0] && - e.target.currentTime < segment[1] - ) { - e.target.currentTime = segment[1]; - if (is.dev()) { - console.log("SponsorBlock: skipping segment", segment); - } - } - }); - }) - // Reset segments on song end - video.addEventListener('emptied', () => currentSegments = []); - }, { once: true, passive: true }) -}; diff --git a/plugins/sponsorblock/front.ts b/plugins/sponsorblock/front.ts new file mode 100644 index 00000000..ccb2f808 --- /dev/null +++ b/plugins/sponsorblock/front.ts @@ -0,0 +1,37 @@ +import { ipcRenderer } from 'electron'; +import is from 'electron-is'; + +import { Segment } from './types'; + +let currentSegments: Segment[] = []; + +export default () => { + ipcRenderer.on('sponsorblock-skip', (_, segments: Segment[]) => { + currentSegments = segments; + }); + + document.addEventListener('apiLoaded', () => { + const video = document.querySelector('video'); + if (!video) return; + + video.addEventListener('timeupdate', (e) => { + if (e.target instanceof HTMLVideoElement) { + const target = e.target; + + for (const segment of currentSegments) { + if ( + target.currentTime >= segment[0] + && target.currentTime < segment[1] + ) { + target.currentTime = segment[1]; + if (is.dev()) { + console.log('SponsorBlock: skipping segment', segment); + } + } + } + } + }); + // Reset segments on song end + video.addEventListener('emptied', () => currentSegments = []); + }, { once: true, passive: true }); +}; diff --git a/plugins/sponsorblock/segments.js b/plugins/sponsorblock/segments.js deleted file mode 100644 index c12a9e88..00000000 --- a/plugins/sponsorblock/segments.js +++ /dev/null @@ -1,29 +0,0 @@ -// Segments are an array [ [start, end], … ] -module.exports.sortSegments = (segments) => { - segments.sort((segment1, segment2) => - segment1[0] === segment2[0] - ? segment1[1] - segment2[1] - : segment1[0] - segment2[0] - ); - - const compiledSegments = []; - let currentSegment; - - segments.forEach((segment) => { - if (!currentSegment) { - currentSegment = segment; - return; - } - - if (currentSegment[1] < segment[0]) { - compiledSegments.push(currentSegment); - currentSegment = segment; - return; - } - - currentSegment[1] = Math.max(currentSegment[1], segment[1]); - }); - compiledSegments.push(currentSegment); - - return compiledSegments; -}; diff --git a/plugins/sponsorblock/segments.ts b/plugins/sponsorblock/segments.ts new file mode 100644 index 00000000..e6d38666 --- /dev/null +++ b/plugins/sponsorblock/segments.ts @@ -0,0 +1,34 @@ +// Segments are an array [ [start, end], … ] +import { Segment } from './types'; + +export const sortSegments = (segments: Segment[]) => { + segments.sort((segment1, segment2) => + segment1[0] === segment2[0] + ? segment1[1] - segment2[1] + : segment1[0] - segment2[0], + ); + + const compiledSegments: Segment[] = []; + let currentSegment: Segment | undefined; + + for (const segment of segments) { + if (!currentSegment) { + currentSegment = segment; + continue; + } + + if (currentSegment[1] < segment[0]) { + compiledSegments.push(currentSegment); + currentSegment = segment; + continue; + } + + currentSegment[1] = Math.max(currentSegment[1], segment[1]); + } + + if (currentSegment) { + compiledSegments.push(currentSegment); + } + + return compiledSegments; +}; diff --git a/plugins/sponsorblock/tests/segments.test.js b/plugins/sponsorblock/tests/segments.test.js index 39859608..002bff8f 100644 --- a/plugins/sponsorblock/tests/segments.test.js +++ b/plugins/sponsorblock/tests/segments.test.js @@ -1,36 +1,36 @@ -const { test, expect } = require("@playwright/test"); +const { test, expect } = require('@playwright/test'); -const { sortSegments } = require("../segments"); +const { sortSegments } = require('../segments'); -test("Segment sorting", () => { - expect( - sortSegments([ - [0, 3], - [7, 8], - [5, 6], - ]) - ).toEqual([ - [0, 3], - [5, 6], - [7, 8], - ]); +test('Segment sorting', () => { + expect( + sortSegments([ + [0, 3], + [7, 8], + [5, 6], + ]), + ).toEqual([ + [0, 3], + [5, 6], + [7, 8], + ]); - expect( - sortSegments([ - [0, 5], - [6, 8], - [4, 6], - ]) - ).toEqual([[0, 8]]); + expect( + sortSegments([ + [0, 5], + [6, 8], + [4, 6], + ]), + ).toEqual([[0, 8]]); - expect( - sortSegments([ - [0, 6], - [7, 8], - [4, 6], - ]) - ).toEqual([ - [0, 6], - [7, 8], - ]); + expect( + sortSegments([ + [0, 6], + [7, 8], + [4, 6], + ]), + ).toEqual([ + [0, 6], + [7, 8], + ]); }); diff --git a/plugins/sponsorblock/types.ts b/plugins/sponsorblock/types.ts new file mode 100644 index 00000000..4bfe7e36 --- /dev/null +++ b/plugins/sponsorblock/types.ts @@ -0,0 +1,12 @@ +export type Segment = [number, number]; + +export interface SkipSegment { // Array of this object + segment: Segment; //[0, 15.23] start and end time in seconds + UUID: string, + category: string, // [1] + videoDuration: number // Duration of video when submission occurred (to be used to determine when a submission is out of date). 0 when unknown. +- 1 second + actionType: string, // [3] + locked: number, // if submission is locked + votes: number, // Votes on segment + description: string, // title for chapters, empty string for other segments +} diff --git a/plugins/taskbar-mediacontrol/back.js b/plugins/taskbar-mediacontrol/back.js deleted file mode 100644 index dce9a6b3..00000000 --- a/plugins/taskbar-mediacontrol/back.js +++ /dev/null @@ -1,53 +0,0 @@ -const getSongControls = require('../../providers/song-controls'); -const registerCallback = require('../../providers/song-info'); -const path = require('path'); - -let controls; -let currentSongInfo; - -module.exports = win => { - const { playPause, next, previous } = getSongControls(win); - controls = { playPause, next, previous }; - - registerCallback(songInfo => { - //update currentsonginfo for win.on('show') - currentSongInfo = songInfo; - // update thumbar - setThumbar(win, songInfo); - }); - - // need to set thumbar again after win.show - win.on("show", () => { - setThumbar(win, currentSongInfo) - }) -}; - -function setThumbar(win, songInfo) { - // Wait for song to start before setting thumbar - if (!songInfo?.title) { - return; - } - - // Win32 require full rewrite of components - win.setThumbarButtons([ - { - tooltip: 'Previous', - icon: get('previous'), - click() { controls.previous(win.webContents); } - }, { - tooltip: 'Play/Pause', - // Update icon based on play state - icon: songInfo.isPaused ? get('play') : get('pause'), - click() { controls.playPause(win.webContents); } - }, { - tooltip: 'Next', - icon: get('next'), - click() { controls.next(win.webContents); } - } - ]); -} - -// Util -function get(kind) { - return path.join(__dirname, "../../assets/media-icons-black", `${kind}.png`); -} diff --git a/plugins/taskbar-mediacontrol/back.ts b/plugins/taskbar-mediacontrol/back.ts new file mode 100644 index 00000000..ea411b23 --- /dev/null +++ b/plugins/taskbar-mediacontrol/back.ts @@ -0,0 +1,67 @@ +import path from 'node:path'; + +import { BrowserWindow, nativeImage } from 'electron'; + +import getSongControls from '../../providers/song-controls'; +import registerCallback, { SongInfo } from '../../providers/song-info'; + + +let controls: { + playPause: () => void; + next: () => void; + previous: () => void; +}; +let currentSongInfo: SongInfo; + +export default (win: BrowserWindow) => { + const { playPause, next, previous } = getSongControls(win); + controls = { playPause, next, previous }; + + registerCallback((songInfo) => { + // Update currentsonginfo for win.on('show') + currentSongInfo = songInfo; + // Update thumbar + setThumbar(win, songInfo); + }); + + // Need to set thumbar again after win.show + win.on('show', () => { + setThumbar(win, currentSongInfo); + }); +}; + +function setThumbar(win: BrowserWindow, songInfo: SongInfo) { + // Wait for song to start before setting thumbar + if (!songInfo?.title) { + return; + } + + // Win32 require full rewrite of components + win.setThumbarButtons([ + { + tooltip: 'Previous', + icon: nativeImage.createFromPath(get('previous')), + click() { + controls.previous(); + }, + }, { + tooltip: 'Play/Pause', + // Update icon based on play state + icon: nativeImage.createFromPath(songInfo.isPaused ? get('play') : get('pause')), + click() { + controls.playPause(); + }, + }, { + tooltip: 'Next', + icon: nativeImage.createFromPath(get('next')), + click() { + controls.next(); + }, + }, + ]); +} + +// Util +function get(kind: string) { + return path.join(__dirname, '../../assets/media-icons-black', `${kind}.png`); +} diff --git a/plugins/touchbar/back.js b/plugins/touchbar/back.js deleted file mode 100644 index 02b28cc1..00000000 --- a/plugins/touchbar/back.js +++ /dev/null @@ -1,86 +0,0 @@ -const { TouchBar } = require("electron"); -const { - TouchBarButton, - TouchBarLabel, - TouchBarSpacer, - TouchBarSegmentedControl, - TouchBarScrubber, -} = TouchBar; - -const registerCallback = require("../../providers/song-info"); -const getSongControls = require("../../providers/song-controls"); - -// Songtitle label -const songTitle = new TouchBarLabel({ - label: "", -}); -// This will store the song controls once available -let controls = []; - -// This will store the song image once available -const songImage = {}; - -// Pause/play button -const pausePlayButton = new TouchBarButton(); - -// The song control buttons (control functions are in the same order) -const buttons = new TouchBarSegmentedControl({ - mode: "buttons", - segments: [ - new TouchBarButton({ - label: "⏮", - }), - pausePlayButton, - new TouchBarButton({ - label: "⏭", - }), - new TouchBarButton({ - label: "👎", - }), - new TouchBarButton({ - label: "👍", - }), - ], - change: (i) => controls[i](), -}); - -// This is the touchbar object, this combines everything with proper layout -const touchBar = new TouchBar({ - items: [ - new TouchBarScrubber({ - items: [songImage, songTitle], - continuous: false, - }), - new TouchBarSpacer({ - size: "flexible", - }), - buttons, - ], -}); - -module.exports = (win) => { - const { playPause, next, previous, dislike, like } = getSongControls(win); - - // If the page is ready, register the callback - win.once("ready-to-show", () => { - controls = [previous, playPause, next, dislike, like]; - - // Register the callback - registerCallback((songInfo) => { - // Song information changed, so lets update the touchBar - - // Set the song title - songTitle.label = songInfo.title; - - // Changes the pause button if paused - pausePlayButton.label = songInfo.isPaused ? "▶️" : "⏸"; - - // Get image source - songImage.icon = songInfo.image - ? songInfo.image.resize({ height: 23 }) - : null; - - win.setTouchBar(touchBar); - }); - }); -}; diff --git a/plugins/touchbar/back.ts b/plugins/touchbar/back.ts new file mode 100644 index 00000000..bbfea578 --- /dev/null +++ b/plugins/touchbar/back.ts @@ -0,0 +1,89 @@ +import { TouchBar, NativeImage, BrowserWindow } from 'electron'; + +import registerCallback from '../../providers/song-info'; +import getSongControls from '../../providers/song-controls'; + +const { + TouchBarButton, + TouchBarLabel, + TouchBarSpacer, + TouchBarSegmentedControl, + TouchBarScrubber, +} = TouchBar; + +// Songtitle label +const songTitle = new TouchBarLabel({ + label: '', +}); +// This will store the song controls once available +let controls: (() => void)[] = []; + +// This will store the song image once available +const songImage: { + icon?: NativeImage; +} = {}; + +// Pause/play button +const pausePlayButton = new TouchBarButton({}); + +// The song control buttons (control functions are in the same order) +const buttons = new TouchBarSegmentedControl({ + mode: 'buttons', + segments: [ + new TouchBarButton({ + label: '⏮', + }), + pausePlayButton, + new TouchBarButton({ + label: '⏭', + }), + new TouchBarButton({ + label: '👎', + }), + new TouchBarButton({ + label: '👍', + }), + ], + change: (i) => controls[i](), +}); + +// This is the touchbar object, this combines everything with proper layout +const touchBar = new TouchBar({ + items: [ + new TouchBarScrubber({ + items: [songImage, songTitle], + continuous: false, + }), + new TouchBarSpacer({ + size: 'flexible', + }), + buttons, + ], +}); + +export default (win: BrowserWindow) => { + const { playPause, next, previous, dislike, like } = getSongControls(win); + + // If the page is ready, register the callback + win.once('ready-to-show', () => { + controls = [previous, playPause, next, dislike, like]; + + // Register the callback + registerCallback((songInfo) => { + // Song information changed, so lets update the touchBar + + // Set the song title + songTitle.label = songInfo.title; + + // Changes the pause button if paused + pausePlayButton.label = songInfo.isPaused ? '▶️' : '⏸'; + + // Get image source + songImage.icon = songInfo.image + ? songInfo.image.resize({ height: 23 }) + : undefined; + + win.setTouchBar(touchBar); + }); + }); +}; diff --git a/plugins/tuna-obs/back.js b/plugins/tuna-obs/back.js deleted file mode 100644 index 5b3eec65..00000000 --- a/plugins/tuna-obs/back.js +++ /dev/null @@ -1,56 +0,0 @@ -const { ipcMain } = require("electron"); -const fetch = require('node-fetch'); - -const registerCallback = require("../../providers/song-info"); - -const secToMilisec = t => Math.round(Number(t) * 1e3); -const data = { - cover: '', - cover_url: '', - title: '', - artists: [], - status: '', - progress: 0, - duration: 0, - album_url: '', - album: undefined -}; - -const post = async (data) => { - const port = 1608; - headers = { - 'Content-Type': 'application/json', - 'Accept': 'application/json', - 'Access-Control-Allow-Headers': '*', - 'Access-Control-Allow-Origin': '*' - } - const url = `http://localhost:${port}/`; - fetch(url, { method: 'POST', headers, body: JSON.stringify({ data }) }).catch(e => console.log(`Error: '${e.code || e.errno}' - when trying to access obs-tuna webserver at port ${port}`)); -} - -/** @param {Electron.BrowserWindow} win */ -module.exports = async (win) => { - ipcMain.on('apiLoaded', () => win.webContents.send('setupTimeChangedListener')); - ipcMain.on('timeChanged', async (_, t) => { - if (!data.title) return; - data.progress = secToMilisec(t); - post(data); - }); - - registerCallback((songInfo) => { - if (!songInfo.title && !songInfo.artist) { - return; - } - - data.duration = secToMilisec(songInfo.songDuration) - data.progress = secToMilisec(songInfo.elapsedSeconds) - data.cover = songInfo.imageSrc; - data.cover_url = songInfo.imageSrc; - data.album_url = songInfo.imageSrc; - data.title = songInfo.title; - data.artists = [songInfo.artist]; - data.status = songInfo.isPaused ? 'stopped' : 'playing'; - data.album = songInfo.album; - post(data); - }) -} diff --git a/plugins/tuna-obs/back.ts b/plugins/tuna-obs/back.ts new file mode 100644 index 00000000..c01b6557 --- /dev/null +++ b/plugins/tuna-obs/back.ts @@ -0,0 +1,74 @@ +import { ipcMain, net, BrowserWindow } from 'electron'; + +import registerCallback from '../../providers/song-info'; + +const secToMilisec = (t: number) => Math.round(Number(t) * 1e3); + +interface Data { + album: string | null | undefined; + album_url: string; + artists: string[]; + cover: string; + cover_url: string; + duration: number; + progress: number; + status: string; + title: string; +} + +const data: Data = { + cover: '', + cover_url: '', + title: '', + artists: [] as string[], + status: '', + progress: 0, + duration: 0, + album_url: '', + album: undefined, +}; + +const post = (data: Data) => { + const port = 1608; + const headers = { + 'Content-Type': 'application/json', + 'Accept': 'application/json', + 'Access-Control-Allow-Headers': '*', + 'Access-Control-Allow-Origin': '*', + }; + const url = `http://127.0.0.1:${port}/`; + net.fetch(url, { + method: 'POST', + headers, + body: JSON.stringify({ data }), + }).catch((error: { code: number, errno: number }) => console.log(`Error: '${error.code || error.errno}' - when trying to access obs-tuna webserver at port ${port}`)); +}; + +export default (win: BrowserWindow) => { + ipcMain.on('apiLoaded', () => win.webContents.send('setupTimeChangedListener')); + ipcMain.on('timeChanged', (_, t: number) => { + if (!data.title) { + return; + } + + data.progress = secToMilisec(t); + post(data); + }); + + registerCallback((songInfo) => { + if (!songInfo.title && !songInfo.artist) { + return; + } + + data.duration = secToMilisec(songInfo.songDuration); + data.progress = secToMilisec(songInfo.elapsedSeconds ?? 0); + data.cover = songInfo.imageSrc ?? ''; + data.cover_url = songInfo.imageSrc ?? ''; + data.album_url = songInfo.imageSrc ?? ''; + data.title = songInfo.title; + data.artists = [songInfo.artist]; + data.status = songInfo.isPaused ? 'stopped' : 'playing'; + data.album = songInfo.album; + post(data); + }); +}; diff --git a/plugins/utils.js b/plugins/utils.js deleted file mode 100644 index 5ccf1839..00000000 --- a/plugins/utils.js +++ /dev/null @@ -1,75 +0,0 @@ -const fs = require("fs"); -const path = require("path"); - -const { ipcMain, ipcRenderer } = require("electron"); - -// Creates a DOM element from a HTML string -module.exports.ElementFromHtml = (html) => { - var template = document.createElement("template"); - html = html.trim(); // Never return a text node of whitespace as the result - template.innerHTML = html; - return template.content.firstChild; -}; - -// Creates a DOM element from a HTML file -module.exports.ElementFromFile = (filepath) => { - return module.exports.ElementFromHtml(fs.readFileSync(filepath, "utf8")); -}; - -module.exports.templatePath = (pluginPath, name) => { - return path.join(pluginPath, "templates", name); -}; - -module.exports.triggerAction = (channel, action, ...args) => { - return ipcRenderer.send(channel, action, ...args); -}; - -module.exports.triggerActionSync = (channel, action, ...args) => { - return ipcRenderer.sendSync(channel, action, ...args); -}; - -module.exports.listenAction = (channel, callback) => { - return ipcMain.on(channel, callback); -}; - -module.exports.fileExists = ( - path, - callbackIfExists, - callbackIfError = undefined -) => { - fs.access(path, fs.F_OK, (err) => { - if (err) { - if (callbackIfError) { - callbackIfError(); - } - return; - } - - callbackIfExists(); - }); -}; - -const cssToInject = new Map(); -module.exports.injectCSS = (webContents, filepath, cb = undefined) => { - if (!cssToInject.size) setupCssInjection(webContents); - - cssToInject.set(filepath, cb); -}; - -const setupCssInjection = (webContents) => { - webContents.on("did-finish-load", () => { - cssToInject.forEach(async (cb, filepath) => { - await webContents.insertCSS(fs.readFileSync(filepath, "utf8")); - cb?.(); - }) - }); -} - -module.exports.getAllPlugins = () => { - const isDirectory = (source) => fs.lstatSync(source).isDirectory(); - return fs - .readdirSync(__dirname) - .map((name) => path.join(__dirname, name)) - .filter(isDirectory) - .map((name) => path.basename(name)); -}; diff --git a/plugins/utils.ts b/plugins/utils.ts new file mode 100644 index 00000000..73df857a --- /dev/null +++ b/plugins/utils.ts @@ -0,0 +1,74 @@ +import fs from 'node:fs'; +import path from 'node:path'; + +import { ipcMain, ipcRenderer } from 'electron'; + +import { ValueOf } from '../utils/type-utils'; + +// Creates a DOM element from an HTML string +export const ElementFromHtml = (html: string): HTMLElement => { + const template = document.createElement('template'); + html = html.trim(); // Never return a text node of whitespace as the result + template.innerHTML = html; + + return template.content.firstElementChild as HTMLElement; +}; + +// Creates a DOM element from a HTML file +export const ElementFromFile = (filepath: fs.PathOrFileDescriptor) => ElementFromHtml(fs.readFileSync(filepath, 'utf8')); + +export const templatePath = (pluginPath: string, name: string) => path.join(pluginPath, 'templates', name); + +export const Actions = { + NEXT: 'next', + BACK: 'back', +}; + +export const triggerAction = (channel: string, action: ValueOf, ...args: Parameters) => ipcRenderer.send(channel, action, ...args); + +export const triggerActionSync = (channel: string, action: ValueOf, ...args: Parameters): unknown => ipcRenderer.sendSync(channel, action, ...args); + +export const listenAction = (channel: string, callback: (event: Electron.IpcMainEvent, action: string) => void) => ipcMain.on(channel, callback); + +export const fileExists = ( + path: fs.PathLike, + callbackIfExists: { (): void; (): void; (): void; }, + callbackIfError: (() => void) | undefined = undefined, +) => { + fs.access(path, fs.constants.F_OK, (error) => { + if (error) { + callbackIfError?.(); + + return; + } + + callbackIfExists(); + }); +}; + +const cssToInject = new Map(); +export const injectCSS = (webContents: Electron.WebContents, filepath: unknown, cb: (() => void) | undefined = undefined) => { + if (cssToInject.size === 0) { + setupCssInjection(webContents); + } + + cssToInject.set(filepath, cb); +}; + +const setupCssInjection = (webContents: Electron.WebContents) => { + webContents.on('did-finish-load', () => { + cssToInject.forEach(async (callback: () => void | undefined, filepath: fs.PathOrFileDescriptor) => { + await webContents.insertCSS(fs.readFileSync(filepath, 'utf8')); + callback?.(); + }); + }); +}; + +export const getAllPlugins = () => { + const isDirectory = (source: fs.PathLike) => fs.lstatSync(source).isDirectory(); + return fs + .readdirSync(__dirname) + .map((name) => path.join(__dirname, name)) + .filter(isDirectory) + .map((name) => path.basename(name)); +}; diff --git a/plugins/video-toggle/back.js b/plugins/video-toggle/back.js deleted file mode 100644 index b57f0722..00000000 --- a/plugins/video-toggle/back.js +++ /dev/null @@ -1,10 +0,0 @@ -const { injectCSS } = require("../utils"); -const path = require("path"); - -module.exports = (win, options) => { - if (options.forceHide) { - injectCSS(win.webContents, path.join(__dirname, "force-hide.css")); - } else if (!options.mode || options.mode === "custom") { - injectCSS(win.webContents, path.join(__dirname, "button-switcher.css")); - } -}; diff --git a/plugins/video-toggle/back.ts b/plugins/video-toggle/back.ts new file mode 100644 index 00000000..1fe17d6c --- /dev/null +++ b/plugins/video-toggle/back.ts @@ -0,0 +1,15 @@ +import path from 'node:path'; + +import { BrowserWindow } from 'electron'; + +import { injectCSS } from '../utils'; + +import type { ConfigType } from '../../config/dynamic'; + +export default (win: BrowserWindow, options: ConfigType<'video-toggle'>) => { + if (options.forceHide) { + injectCSS(win.webContents, path.join(__dirname, 'force-hide.css')); + } else if (!options.mode || options.mode === 'custom') { + injectCSS(win.webContents, path.join(__dirname, 'button-switcher.css')); + } +}; diff --git a/plugins/video-toggle/button-switcher.css b/plugins/video-toggle/button-switcher.css index 3bae2fc6..92c052e2 100644 --- a/plugins/video-toggle/button-switcher.css +++ b/plugins/video-toggle/button-switcher.css @@ -1,86 +1,86 @@ #main-panel.ytmusic-player-page { - align-items: unset !important; + align-items: unset !important; } #main-panel { - position: relative; + position: relative; } .video-switch-button { - z-index: 999; - box-sizing: border-box; - padding: 0; - margin-top: 20px; - margin-left: 10px; - background: rgba(33, 33, 33, 0.4); - border-radius: 30px; - overflow: hidden; - width: 240px; - text-align: center; - font-size: 18px; - letter-spacing: 1px; - color: #fff; - padding-right: 120px; - position: absolute; + z-index: 999; + box-sizing: border-box; + padding: 0; + margin-top: 20px; + margin-left: 10px; + background: rgba(33, 33, 33, 0.4); + border-radius: 30px; + overflow: hidden; + width: 240px; + text-align: center; + font-size: 18px; + letter-spacing: 1px; + color: #fff; + padding-right: 120px; + position: absolute; } .video-switch-button:before { - content: "Video"; - position: absolute; - top: 0; - bottom: 0; - right: 0; - width: 120px; - display: flex; - align-items: center; - justify-content: center; - z-index: 3; - pointer-events: none; + content: "Video"; + position: absolute; + top: 0; + bottom: 0; + right: 0; + width: 120px; + display: flex; + align-items: center; + justify-content: center; + z-index: 3; + pointer-events: none; } .video-switch-button-checkbox { - cursor: pointer; - position: absolute; - top: 0; - left: 0; - bottom: 0; - width: 100%; - height: 100%; - opacity: 0; - z-index: 2; + cursor: pointer; + position: absolute; + top: 0; + left: 0; + bottom: 0; + width: 100%; + height: 100%; + opacity: 0; + z-index: 2; } .video-switch-button-label-span { - position: relative; + position: relative; } -.video-switch-button-checkbox:checked+.video-switch-button-label:before { - transform: translateX(120px); - transition: transform 300ms linear; +.video-switch-button-checkbox:checked + .video-switch-button-label:before { + transform: translateX(120px); + transition: transform 300ms linear; } -.video-switch-button-checkbox+.video-switch-button-label { - position: relative; - padding: 15px 0; - display: block; - user-select: none; - pointer-events: none; +.video-switch-button-checkbox + .video-switch-button-label { + position: relative; + padding: 15px 0; + display: block; + user-select: none; + pointer-events: none; } -.video-switch-button-checkbox+.video-switch-button-label:before { - content: ""; - background: rgba(60, 60, 60, 0.4); - height: 100%; - width: 100%; - position: absolute; - left: 0; - top: 0; - border-radius: 30px; - transform: translateX(0); - transition: transform 300ms; +.video-switch-button-checkbox + .video-switch-button-label:before { + content: ""; + background: rgba(60, 60, 60, 0.4); + height: 100%; + width: 100%; + position: absolute; + left: 0; + top: 0; + border-radius: 30px; + transform: translateX(0); + transition: transform 300ms; } /* disable the native toggler */ #av-id { - display: none; + display: none; } diff --git a/plugins/video-toggle/force-hide.css b/plugins/video-toggle/force-hide.css index b65f0c69..36f47f08 100644 --- a/plugins/video-toggle/force-hide.css +++ b/plugins/video-toggle/force-hide.css @@ -1,11 +1,11 @@ /* Hide the video player */ #main-panel { - display: none !important; + display: none !important; } /* Make the side-panel full width */ .side-panel.ytmusic-player-page { - max-width: 100% !important; - width: 100% !important; - margin: 0 !important; + max-width: 100% !important; + width: 100% !important; + margin: 0 !important; } diff --git a/plugins/video-toggle/front.js b/plugins/video-toggle/front.js deleted file mode 100644 index 482df3c5..00000000 --- a/plugins/video-toggle/front.js +++ /dev/null @@ -1,147 +0,0 @@ -const { ElementFromFile, templatePath } = require("../utils"); - -const { setOptions, isEnabled } = require("../../config/plugins"); - -const moveVolumeHud = isEnabled("precise-volume") ? require("../precise-volume/front").moveVolumeHud : ()=>{}; - -function $(selector) { return document.querySelector(selector); } - -let options, player, video, api; - -const switchButtonDiv = ElementFromFile( - templatePath(__dirname, "button_template.html") -); - -module.exports = (_options) => { - if (_options.forceHide) return; - switch (_options.mode) { - case "native": { - $("ytmusic-player-page").setAttribute("has-av-switcher"); - $("ytmusic-player").setAttribute("has-av-switcher"); - return; - } - case "disabled": { - $("ytmusic-player-page").removeAttribute("has-av-switcher"); - $("ytmusic-player").removeAttribute("has-av-switcher"); - return; - } - default: - case "custom": { - options = _options; - document.addEventListener("apiLoaded", setup, { once: true, passive: true }); - } - } -}; - -function setup(e) { - api = e.detail; - player = $('ytmusic-player'); - video = $('video'); - - $('#player').prepend(switchButtonDiv); - - if (options.hideVideo) { - $('.video-switch-button-checkbox').checked = false; - changeDisplay(false); - forcePlaybackMode(); - // fix black video - video.style.height = "auto"; - } - - //Prevents bubbling to the player which causes it to stop or resume - switchButtonDiv.addEventListener('click', (e) => { - e.stopPropagation(); - }); - - // button checked = show video - switchButtonDiv.addEventListener('change', (e) => { - options.hideVideo = !e.target.checked; - changeDisplay(e.target.checked); - setOptions("video-toggle", options); - }) - - video.addEventListener('srcChanged', videoStarted); - - observeThumbnail(); - - switch (options.align) { - case "right": { - switchButtonDiv.style.left = "calc(100% - 240px)"; - return; - } - case "middle": { - switchButtonDiv.style.left = "calc(50% - 120px)"; - return; - } - default: - case "left": { - switchButtonDiv.style.left = "0px"; - } - } -} - -function changeDisplay(showVideo) { - player.style.margin = showVideo ? '' : 'auto 0px'; - player.setAttribute('playback-mode', showVideo ? 'OMV_PREFERRED' : 'ATV_PREFERRED'); - - $('#song-video.ytmusic-player').style.display = showVideo ? 'block' : 'none'; - $('#song-image').style.display = showVideo ? 'none' : 'block'; - - if (showVideo && !video.style.top) { - video.style.top = `${(player.clientHeight - video.clientHeight) / 2}px`; - } - moveVolumeHud(showVideo); -} - -function videoStarted() { - if (api.getPlayerResponse().videoDetails.musicVideoType !== 'MUSIC_VIDEO_TYPE_ATV') { - // switch to high res thumbnail - forceThumbnail($('#song-image img')); - // show toggle button - switchButtonDiv.style.display = "initial"; - // change display to video mode if video exist & video is hidden & option.hideVideo = false - if (!options.hideVideo && $('#song-video.ytmusic-player').style.display === "none") { - changeDisplay(true); - } else { - moveVolumeHud(!options.hideVideo); - } - } else { - // video doesn't exist -> switch to song mode - changeDisplay(false); - // hide toggle button - switchButtonDiv.style.display = "none"; - } -} - -// on load, after a delay, the page overrides the playback-mode to 'OMV_PREFERRED' which causes weird aspect ratio in the image container -// this function fix the problem by overriding that override :) -function forcePlaybackMode() { - const playbackModeObserver = new MutationObserver(mutations => { - mutations.forEach(mutation => { - if (mutation.target.getAttribute('playback-mode') !== "ATV_PREFERRED") { - playbackModeObserver.disconnect(); - mutation.target.setAttribute('playback-mode', "ATV_PREFERRED"); - } - }); - }); - playbackModeObserver.observe(player, { attributeFilter: ["playback-mode"] }); -} - -function observeThumbnail() { - const playbackModeObserver = new MutationObserver(mutations => { - if (!player.videoMode_) return; - - mutations.forEach(mutation => { - if (!mutation.target.src.startsWith('data:')) return; - forceThumbnail(mutation.target) - }); - }); - playbackModeObserver.observe($('#song-image img'), { attributeFilter: ["src"] }) -} - -function forceThumbnail(img) { - const thumbnails = $('#movie_player').getPlayerResponse()?.videoDetails?.thumbnail?.thumbnails; - if (thumbnails && thumbnails.length > 0) { - img.src = thumbnails[thumbnails.length - 1].url.split("?")[0]; - } -} diff --git a/plugins/video-toggle/front.ts b/plugins/video-toggle/front.ts new file mode 100644 index 00000000..49a3ecd1 --- /dev/null +++ b/plugins/video-toggle/front.ts @@ -0,0 +1,192 @@ +import { ElementFromFile, templatePath } from '../utils'; +import { setOptions, isEnabled } from '../../config/plugins'; + +import { moveVolumeHud as preciseVolumeMoveVolumeHud } from '../precise-volume/front'; + +import { YoutubePlayer } from '../../types/youtube-player'; +import { ThumbnailElement } from '../../types/get-player-response'; + +import type { ConfigType } from '../../config/dynamic'; + +const moveVolumeHud = isEnabled('precise-volume') ? preciseVolumeMoveVolumeHud : () => {}; + +function $(selector: string): E | null { + return document.querySelector(selector); +} + +let options: ConfigType<'video-toggle'>; +let player: HTMLElement & { videoMode_: boolean } | null; +let video: HTMLVideoElement | null; +let api: YoutubePlayer; + +const switchButtonDiv = ElementFromFile( + templatePath(__dirname, 'button_template.html'), +); + +export default (_options: ConfigType<'video-toggle'>) => { + if (_options.forceHide) { + return; + } + + switch (_options.mode) { + case 'native': { + $('ytmusic-player-page')?.setAttribute('has-av-switcher', ''); + $('ytmusic-player')?.setAttribute('has-av-switcher', ''); + return; + } + + case 'disabled': { + $('ytmusic-player-page')?.removeAttribute('has-av-switcher'); + $('ytmusic-player')?.removeAttribute('has-av-switcher'); + return; + } + + default: + case 'custom': { + options = _options; + document.addEventListener('apiLoaded', setup, { once: true, passive: true }); + } + } +}; + +function setup(e: CustomEvent) { + api = e.detail; + player = $<(HTMLElement & { videoMode_: boolean; })>('ytmusic-player'); + video = $('video'); + + $('#player')?.prepend(switchButtonDiv); + + if (options.hideVideo) { + const checkbox = $('.video-switch-button-checkbox'); + if (checkbox) { + checkbox.checked = false; + } + changeDisplay(false); + forcePlaybackMode(); + // Fix black video + if (video) { + video.style.height = 'auto'; + } + } + + //Prevents bubbling to the player which causes it to stop or resume + switchButtonDiv.addEventListener('click', (e) => { + e.stopPropagation(); + }); + + // Button checked = show video + switchButtonDiv.addEventListener('change', (e) => { + const target = e.target as HTMLInputElement; + options.hideVideo = target.checked; + changeDisplay(target.checked); + setOptions('video-toggle', options); + }); + + video?.addEventListener('srcChanged', videoStarted); + + observeThumbnail(); + + switch (options.align) { + case 'right': { + switchButtonDiv.style.left = 'calc(100% - 240px)'; + return; + } + + case 'middle': { + switchButtonDiv.style.left = 'calc(50% - 120px)'; + return; + } + + default: + case 'left': { + switchButtonDiv.style.left = '0px'; + } + } +} + +function changeDisplay(showVideo: boolean) { + if (player) { + player.style.margin = showVideo ? '' : 'auto 0px'; + player.setAttribute('playback-mode', showVideo ? 'OMV_PREFERRED' : 'ATV_PREFERRED'); + + $('#song-video.ytmusic-player')!.style.display = showVideo ? 'block' : 'none'; + $('#song-image')!.style.display = showVideo ? 'none' : 'block'; + + if (showVideo && video && !video.style.top) { + video.style.top = `${(player.clientHeight - video.clientHeight) / 2}px`; + } + + moveVolumeHud(showVideo); + } +} + +function videoStarted() { + if (api.getPlayerResponse().videoDetails.musicVideoType === 'MUSIC_VIDEO_TYPE_ATV') { + // Video doesn't exist -> switch to song mode + changeDisplay(false); + // Hide toggle button + switchButtonDiv.style.display = 'none'; + } else { + const songImage = $('#song-image img'); + if (!songImage) { + return; + } + // Switch to high-res thumbnail + forceThumbnail(songImage); + // Show toggle button + switchButtonDiv.style.display = 'initial'; + // Change display to video mode if video exist & video is hidden & option.hideVideo = false + if (!options.hideVideo && $('#song-video.ytmusic-player')?.style.display === 'none') { + changeDisplay(true); + } else { + moveVolumeHud(!options.hideVideo); + } + } +} + +// On load, after a delay, the page overrides the playback-mode to 'OMV_PREFERRED' which causes weird aspect ratio in the image container +// this function fix the problem by overriding that override :) +function forcePlaybackMode() { + if (player) { + const playbackModeObserver = new MutationObserver((mutations) => { + for (const mutation of mutations) { + if (mutation.target instanceof HTMLElement) { + const target = mutation.target; + if (target.getAttribute('playback-mode') !== 'ATV_PREFERRED') { + playbackModeObserver.disconnect(); + target.setAttribute('playback-mode', 'ATV_PREFERRED'); + } + } + } + }); + playbackModeObserver.observe(player, { attributeFilter: ['playback-mode'] }); + } +} + +function observeThumbnail() { + const playbackModeObserver = new MutationObserver((mutations) => { + if (!player?.videoMode_) { + return; + } + + for (const mutation of mutations) { + if (mutation.target instanceof HTMLImageElement) { + const target = mutation.target; + if (!target.src.startsWith('data:')) { + continue; + } + + forceThumbnail(target); + } + } + }); + playbackModeObserver.observe($('#song-image img')!, { attributeFilter: ['src'] }); +} + +function forceThumbnail(img: HTMLImageElement) { + const thumbnails: ThumbnailElement[] = ($('#movie_player') as unknown as YoutubePlayer).getPlayerResponse()?.videoDetails?.thumbnail?.thumbnails ?? []; + if (thumbnails && thumbnails.length > 0) { + const thumbnail = thumbnails.at(-1)?.url.split('?')[0]; + if (typeof thumbnail === 'string') img.src = thumbnail; + } +} diff --git a/plugins/video-toggle/menu.js b/plugins/video-toggle/menu.js deleted file mode 100644 index 059aa963..00000000 --- a/plugins/video-toggle/menu.js +++ /dev/null @@ -1,77 +0,0 @@ -const { setMenuOptions } = require("../../config/plugins"); - -module.exports = (win, options) => [ - { - label: "Mode", - submenu: [ - { - label: "Custom toggle", - type: "radio", - checked: options.mode === 'custom', - click: () => { - options.mode = 'custom'; - setMenuOptions("video-toggle", options); - } - }, - { - label: "Native toggle", - type: "radio", - checked: options.mode === 'native', - click: () => { - options.mode = 'native'; - setMenuOptions("video-toggle", options); - } - }, - { - label: "Disabled", - type: "radio", - checked: options.mode === 'disabled', - click: () => { - options.mode = 'disabled'; - setMenuOptions("video-toggle", options); - } - }, - ] - }, - { - label: "Alignment", - submenu: [ - { - label: "Left", - type: "radio", - checked: options.align === 'left', - click: () => { - options.align = 'left'; - setMenuOptions("video-toggle", options); - } - }, - { - label: "Middle", - type: "radio", - checked: options.align === 'middle', - click: () => { - options.align = 'middle'; - setMenuOptions("video-toggle", options); - } - }, - { - label: "Right", - type: "radio", - checked: options.align === 'right', - click: () => { - options.align = 'right'; - setMenuOptions("video-toggle", options); - } - }, - ] - }, - { - label: "Force Remove Video Tab", - type: "checkbox", - checked: options.forceHide, - click: item => { - options.forceHide = item.checked; - setMenuOptions("video-toggle", options); - } - } -]; diff --git a/plugins/video-toggle/menu.ts b/plugins/video-toggle/menu.ts new file mode 100644 index 00000000..2013d58f --- /dev/null +++ b/plugins/video-toggle/menu.ts @@ -0,0 +1,83 @@ +import { BrowserWindow } from 'electron'; + +import { setMenuOptions } from '../../config/plugins'; + +import { MenuTemplate } from '../../menu'; + +import type { ConfigType } from '../../config/dynamic'; + +export default (win: BrowserWindow, options: ConfigType<'video-toggle'>): MenuTemplate => [ + { + label: 'Mode', + submenu: [ + { + label: 'Custom toggle', + type: 'radio', + checked: options.mode === 'custom', + click() { + options.mode = 'custom'; + setMenuOptions('video-toggle', options); + }, + }, + { + label: 'Native toggle', + type: 'radio', + checked: options.mode === 'native', + click() { + options.mode = 'native'; + setMenuOptions('video-toggle', options); + }, + }, + { + label: 'Disabled', + type: 'radio', + checked: options.mode === 'disabled', + click() { + options.mode = 'disabled'; + setMenuOptions('video-toggle', options); + }, + }, + ], + }, + { + label: 'Alignment', + submenu: [ + { + label: 'Left', + type: 'radio', + checked: options.align === 'left', + click() { + options.align = 'left'; + setMenuOptions('video-toggle', options); + }, + }, + { + label: 'Middle', + type: 'radio', + checked: options.align === 'middle', + click() { + options.align = 'middle'; + setMenuOptions('video-toggle', options); + }, + }, + { + label: 'Right', + type: 'radio', + checked: options.align === 'right', + click() { + options.align = 'right'; + setMenuOptions('video-toggle', options); + }, + }, + ], + }, + { + label: 'Force Remove Video Tab', + type: 'checkbox', + checked: options.forceHide, + click(item) { + options.forceHide = item.checked; + setMenuOptions('video-toggle', options); + }, + }, +]; diff --git a/plugins/video-toggle/templates/button_template.html b/plugins/video-toggle/templates/button_template.html index 9f22bbf5..5b86cd75 100644 --- a/plugins/video-toggle/templates/button_template.html +++ b/plugins/video-toggle/templates/button_template.html @@ -1,4 +1,4 @@
- - + +
diff --git a/plugins/visualizer/back.js b/plugins/visualizer/back.js deleted file mode 100644 index b0f8c42b..00000000 --- a/plugins/visualizer/back.js +++ /dev/null @@ -1,6 +0,0 @@ -const { injectCSS } = require("../utils"); -const path = require("path"); - -module.exports = (win, options) => { - injectCSS(win.webContents, path.join(__dirname, "empty-player.css")); -}; diff --git a/plugins/visualizer/back.ts b/plugins/visualizer/back.ts new file mode 100644 index 00000000..a66e9ded --- /dev/null +++ b/plugins/visualizer/back.ts @@ -0,0 +1,9 @@ +import path from 'node:path'; + +import { BrowserWindow } from 'electron'; + +import { injectCSS } from '../utils'; + +export default (win: BrowserWindow) => { + injectCSS(win.webContents, path.join(__dirname, 'empty-player.css')); +}; diff --git a/plugins/visualizer/butterchurn.d.ts b/plugins/visualizer/butterchurn.d.ts new file mode 100644 index 00000000..bd8df9e5 --- /dev/null +++ b/plugins/visualizer/butterchurn.d.ts @@ -0,0 +1,53 @@ +declare module 'butterchurn' { + interface VisualizerOptions { + width?: number; + height?: number; + meshWidth?: number; + meshHeight?: number; + pixelRatio?: number; + textureRatio?: number; + outputFXAA?: boolean; + } + + class Visualizer { + constructor(audioContext: AudioContext, canvas: HTMLCanvasElement, opts: ButterchurnOptions); + loseGLContext(): void; + connectAudio(audioNode: AudioNode): void; + disconnectAudio(audioNode: AudioNode): void; + static overrideDefaultVars(baseValsDefaults: unknown, baseVals: unknown): unknown; + createQVars(): Record; + createTVars(): Record; + createPerFramePool(baseVals: unknown): Record; + createPerPixelPool(baseVals: unknown): Record; + createCustomShapePerFramePool(baseVals: unknown): Record; + createCustomWavePerFramePool(baseVals: unknown): Record; + static makeShapeResetPool(pool: Record, variables: string[], idx: number): Record; + static base64ToArrayBuffer(base64: string): ArrayBuffer; + loadPreset(presetMap: unknown, blendTime?: number): Promise; + async loadWASMPreset(preset: unknown, blendTime: number): Promise; + loadJSPreset(preset: unknown, blendTime: number): void; + loadExtraImages(imageData: unknown): void; + setRendererSize(width: number, height: number, opts?: VisualizerOptions): void; + setInternalMeshSize(width: number, height: number): void; + setOutputAA(useAA: boolean): void; + setCanvas(canvas: HTMLCanvasElement): void; + render(opts?: VisualizerOptions): unknown; + launchSongTitleAnim(text: string): void; + toDataURL(): string; + warpBufferToDataURL(): string; + } + + interface ButterchurnOptions { + width?: number; + height?: number; + onlyUseWASM?: boolean; + } + + export default class Butterchurn { + static createVisualizer(audioContext: AudioContext, canvas: HTMLCanvasElement, options?: ButterchurnOptions): Visualizer; + } +} + +declare module 'butterchurn-presets' { + export function getPresets(): Record; +} diff --git a/plugins/visualizer/empty-player.css b/plugins/visualizer/empty-player.css index dc94788a..15b4043b 100644 --- a/plugins/visualizer/empty-player.css +++ b/plugins/visualizer/empty-player.css @@ -1,9 +1,9 @@ #player { - margin: 0 !important; - background: black; + margin: 0 !important; + background: black; } #song-image, #song-video { - display: none !important; + display: none !important; } diff --git a/plugins/visualizer/front.js b/plugins/visualizer/front.js deleted file mode 100644 index 47522422..00000000 --- a/plugins/visualizer/front.js +++ /dev/null @@ -1,61 +0,0 @@ -const defaultConfig = require("../../config/defaults"); - -module.exports = (options) => { - const optionsWithDefaults = { - ...defaultConfig.plugins.visualizer, - ...options, - }; - const VisualizerType = require(`./visualizers/${optionsWithDefaults.type}`); - - document.addEventListener( - "audioCanPlay", - (e) => { - const video = document.querySelector("video"); - const visualizerContainer = document.querySelector("#player"); - - let canvas = document.getElementById("visualizer"); - if (!canvas) { - canvas = document.createElement("canvas"); - canvas.id = "visualizer"; - canvas.style.position = "absolute"; - canvas.style.background = "black"; - visualizerContainer.append(canvas); - } - - const resizeCanvas = () => { - canvas.width = visualizerContainer.clientWidth; - canvas.height = visualizerContainer.clientHeight; - }; - resizeCanvas(); - - const gainNode = e.detail.audioContext.createGain(); - gainNode.gain.value = 1.25; - e.detail.audioSource.connect(gainNode); - - const visualizer = new VisualizerType( - e.detail.audioContext, - e.detail.audioSource, - visualizerContainer, - canvas, - gainNode, - video.captureStream(), - optionsWithDefaults[optionsWithDefaults.type] - ); - - const resizeVisualizer = (width, height) => { - resizeCanvas(); - visualizer.resize(width, height); - }; - resizeVisualizer(canvas.width, canvas.height); - const visualizerContainerObserver = new ResizeObserver((entries) => { - entries.forEach((entry) => { - resizeVisualizer(entry.contentRect.width, entry.contentRect.height); - }); - }); - visualizerContainerObserver.observe(visualizerContainer); - - visualizer.render(); - }, - { passive: true } - ); -}; diff --git a/plugins/visualizer/front.ts b/plugins/visualizer/front.ts new file mode 100644 index 00000000..7720d9ed --- /dev/null +++ b/plugins/visualizer/front.ts @@ -0,0 +1,88 @@ +import { Visualizer } from './visualizers/visualizer'; + +import vudio from './visualizers/vudio'; +import wave from './visualizers/wave'; +import butterchurn from './visualizers/butterchurn'; + +import defaultConfig from '../../config/defaults'; + +import type { ConfigType } from '../../config/dynamic'; + +export default (options: ConfigType<'visualizer'>) => { + const optionsWithDefaults = { + ...defaultConfig.plugins.visualizer, + ...options, + }; + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + let visualizerType: { new(...args: any[]): Visualizer } = vudio; + + if (optionsWithDefaults.type === 'wave') { + visualizerType = wave; + } else if (optionsWithDefaults.type === 'butterchurn') { + visualizerType = butterchurn; + } + + document.addEventListener( + 'audioCanPlay', + (e) => { + const video = document.querySelector('video'); + if (!video) { + return; + } + + const visualizerContainer = document.querySelector('#player'); + if (!visualizerContainer) { + return; + } + + let canvas = document.querySelector('#visualizer'); + if (!canvas) { + canvas = document.createElement('canvas'); + canvas.id = 'visualizer'; + canvas.style.position = 'absolute'; + canvas.style.background = 'black'; + visualizerContainer?.append(canvas); + } + + const resizeCanvas = () => { + if (canvas) { + canvas.width = visualizerContainer.clientWidth; + canvas.height = visualizerContainer.clientHeight; + } + }; + + resizeCanvas(); + + const gainNode = e.detail.audioContext.createGain(); + gainNode.gain.value = 1.25; + e.detail.audioSource.connect(gainNode); + + const visualizer = new visualizerType( + e.detail.audioContext, + e.detail.audioSource, + visualizerContainer, + canvas, + gainNode, + video.captureStream(), + optionsWithDefaults, + ); + + const resizeVisualizer = (width: number, height: number) => { + resizeCanvas(); + visualizer.resize(width, height); + }; + + resizeVisualizer(canvas.width, canvas.height); + const visualizerContainerObserver = new ResizeObserver((entries) => { + for (const entry of entries) { + resizeVisualizer(entry.contentRect.width, entry.contentRect.height); + } + }); + visualizerContainerObserver.observe(visualizerContainer); + + visualizer.render(); + }, + { passive: true }, + ); +}; diff --git a/plugins/visualizer/menu.js b/plugins/visualizer/menu.js deleted file mode 100644 index 181a71e7..00000000 --- a/plugins/visualizer/menu.js +++ /dev/null @@ -1,23 +0,0 @@ -const { readdirSync } = require("fs"); -const path = require("path"); - -const { setMenuOptions } = require("../../config/plugins"); - -const visualizerTypes = readdirSync(path.join(__dirname, "visualizers")).map( - (filename) => path.parse(filename).name -); - -module.exports = (win, options) => [ - { - label: "Type", - submenu: visualizerTypes.map((visualizerType) => ({ - label: visualizerType, - type: "radio", - checked: options.type === visualizerType, - click: () => { - options.type = visualizerType; - setMenuOptions("visualizer", options); - }, - })), - }, -]; diff --git a/plugins/visualizer/menu.ts b/plugins/visualizer/menu.ts new file mode 100644 index 00000000..4a0f54b6 --- /dev/null +++ b/plugins/visualizer/menu.ts @@ -0,0 +1,29 @@ +import { readdirSync } from 'node:fs'; +import path from 'node:path'; + +import { BrowserWindow } from 'electron'; + +import { setMenuOptions } from '../../config/plugins'; + +import { MenuTemplate } from '../../menu'; + +import type { ConfigType } from '../../config/dynamic'; + +const visualizerTypes = readdirSync(path.join(__dirname, 'visualizers')) + .map((filename) => path.parse(filename).name) + .filter((filename) => filename !== 'visualizer'); + +export default (win: BrowserWindow, options: ConfigType<'visualizer'>): MenuTemplate => [ + { + label: 'Type', + submenu: visualizerTypes.map((visualizerType) => ({ + label: visualizerType, + type: 'radio', + checked: options.type === visualizerType, + click() { + options.type = visualizerType; + setMenuOptions('visualizer', options); + }, + })), + }, +]; diff --git a/plugins/visualizer/visualizers/butterchurn.js b/plugins/visualizer/visualizers/butterchurn.js deleted file mode 100644 index 1c30355d..00000000 --- a/plugins/visualizer/visualizers/butterchurn.js +++ /dev/null @@ -1,46 +0,0 @@ -const butterchurn = require("butterchurn"); -const butterchurnPresets = require("butterchurn-presets"); - -const presets = butterchurnPresets.getPresets(); - -class ButterchurnVisualizer { - constructor( - audioContext, - audioSource, - visualizerContainer, - canvas, - audioNode, - stream, - options - ) { - this.visualizer = butterchurn.default.createVisualizer( - audioContext, - canvas, - { - width: canvas.width, - height: canvas.height, - } - ); - - const preset = presets[options.preset]; - this.visualizer.loadPreset(preset, options.blendTimeInSeconds); - - this.visualizer.connectAudio(audioNode); - - this.renderingFrequencyInMs = options.renderingFrequencyInMs; - } - - resize(width, height) { - this.visualizer.setRendererSize(width, height); - } - - render() { - const renderVisualizer = () => { - requestAnimationFrame(() => renderVisualizer()); - this.visualizer.render(); - }; - setTimeout(renderVisualizer(), this.renderingFrequencyInMs); - } -} - -module.exports = ButterchurnVisualizer; diff --git a/plugins/visualizer/visualizers/butterchurn.ts b/plugins/visualizer/visualizers/butterchurn.ts new file mode 100644 index 00000000..de9b8058 --- /dev/null +++ b/plugins/visualizer/visualizers/butterchurn.ts @@ -0,0 +1,63 @@ +import Butterchurn from 'butterchurn'; +import ButterchurnPresets from 'butterchurn-presets'; + +import { Visualizer } from './visualizer'; + +import { ConfigType } from '../../../config/dynamic'; + +const presets = ButterchurnPresets.getPresets(); + +class ButterchurnVisualizer extends Visualizer { + visualizer: ReturnType; + private readonly renderingFrequencyInMs: number; + + constructor( + audioContext: AudioContext, + audioSource: MediaElementAudioSourceNode, + visualizerContainer: HTMLElement, + canvas: HTMLCanvasElement, + audioNode: GainNode, + stream: MediaStream, + options: ConfigType<'visualizer'>, + ) { + super( + audioContext, + audioSource, + visualizerContainer, + canvas, + audioNode, + stream, + options, + ); + + this.visualizer = Butterchurn.createVisualizer( + audioContext, + canvas, + { + width: canvas.width, + height: canvas.height, + } + ); + + const preset = presets[options.butterchurn.preset]; + this.visualizer.loadPreset(preset, options.butterchurn.blendTimeInSeconds); + + this.visualizer.connectAudio(audioNode); + + this.renderingFrequencyInMs = options.butterchurn.renderingFrequencyInMs; + } + + resize(width: number, height: number) { + this.visualizer.setRendererSize(width, height); + } + + render() { + const renderVisualizer = () => { + requestAnimationFrame(renderVisualizer); + this.visualizer.render(); + }; + setTimeout(renderVisualizer, this.renderingFrequencyInMs); + } +} + +export default ButterchurnVisualizer; diff --git a/plugins/visualizer/visualizers/visualizer.ts b/plugins/visualizer/visualizers/visualizer.ts new file mode 100644 index 00000000..38555ca4 --- /dev/null +++ b/plugins/visualizer/visualizers/visualizer.ts @@ -0,0 +1,18 @@ +import type { ConfigType } from '../../../config/dynamic'; + +export abstract class Visualizer { + abstract visualizer: T; + + protected constructor( + audioContext: AudioContext, + audioSource: MediaElementAudioSourceNode, + visualizerContainer: HTMLElement, + canvas: HTMLCanvasElement, + audioNode: GainNode, + stream: MediaStream, + options: ConfigType<'visualizer'>, + ) {} + + abstract resize(width: number, height: number): void; + abstract render(): void; +} diff --git a/plugins/visualizer/visualizers/vudio.js b/plugins/visualizer/visualizers/vudio.js deleted file mode 100644 index 36cdf2a2..00000000 --- a/plugins/visualizer/visualizers/vudio.js +++ /dev/null @@ -1,33 +0,0 @@ -const Vudio = require("vudio/umd/vudio"); - -class VudioVisualizer { - constructor( - audioContext, - audioSource, - visualizerContainer, - canvas, - audioNode, - stream, - options - ) { - this.visualizer = new Vudio(stream, canvas, { - width: canvas.width, - height: canvas.height, - // Visualizer config - ...options, - }); - } - - resize(width, height) { - this.visualizer.setOption({ - width: width, - height: height, - }); - } - - render() { - this.visualizer.dance(); - } -} - -module.exports = VudioVisualizer; diff --git a/plugins/visualizer/visualizers/vudio.ts b/plugins/visualizer/visualizers/vudio.ts new file mode 100644 index 00000000..32f5eab3 --- /dev/null +++ b/plugins/visualizer/visualizers/vudio.ts @@ -0,0 +1,50 @@ +import Vudio from 'vudio/umd/vudio'; + +import { Visualizer } from './visualizer'; + +import type { ConfigType } from '../../../config/dynamic'; + +class VudioVisualizer extends Visualizer { + visualizer: Vudio; + + constructor( + audioContext: AudioContext, + audioSource: MediaElementAudioSourceNode, + visualizerContainer: HTMLElement, + canvas: HTMLCanvasElement, + audioNode: GainNode, + stream: MediaStream, + options: ConfigType<'visualizer'>, + ) { + super( + audioContext, + audioSource, + visualizerContainer, + canvas, + audioNode, + stream, + options, + ); + + this.visualizer = new Vudio(stream, canvas, { + width: canvas.width, + height: canvas.height, + // Visualizer config + ...options, + }); + + this.visualizer.dance(); + } + + resize(width: number, height: number) { + this.visualizer.setOption({ + width, + height, + }); + } + + render() { + } +} + +export default VudioVisualizer; diff --git a/plugins/visualizer/visualizers/wave.js b/plugins/visualizer/visualizers/wave.js deleted file mode 100644 index 70db7f2a..00000000 --- a/plugins/visualizer/visualizers/wave.js +++ /dev/null @@ -1,31 +0,0 @@ -const { Wave } = require("@foobar404/wave"); - -class WaveVisualizer { - constructor( - audioContext, - audioSource, - visualizerContainer, - canvas, - audioNode, - stream, - options - ) { - this.visualizer = new Wave( - { context: audioContext, source: audioSource }, - canvas - ); - options.animations.forEach((animation) => { - this.visualizer.addAnimation( - eval(`new this.visualizer.animations.${animation.type}( - ${JSON.stringify(animation.config)} - )`) - ); - }); - } - - resize(width, height) {} - - render() {} -} - -module.exports = WaveVisualizer; diff --git a/plugins/visualizer/visualizers/wave.ts b/plugins/visualizer/visualizers/wave.ts new file mode 100644 index 00000000..21a4005e --- /dev/null +++ b/plugins/visualizer/visualizers/wave.ts @@ -0,0 +1,49 @@ +import { Wave } from '@foobar404/wave'; + +import { Visualizer } from './visualizer'; + +import type { ConfigType } from '../../../config/dynamic'; + +class WaveVisualizer extends Visualizer { + visualizer: Wave; + + constructor( + audioContext: AudioContext, + audioSource: MediaElementAudioSourceNode, + visualizerContainer: HTMLElement, + canvas: HTMLCanvasElement, + audioNode: GainNode, + stream: MediaStream, + options: ConfigType<'visualizer'>, + ) { + super( + audioContext, + audioSource, + visualizerContainer, + canvas, + audioNode, + stream, + options, + ); + + this.visualizer = new Wave( + { context: audioContext, source: audioSource }, + canvas, + ); + for (const animation of options.wave.animations) { + const TargetVisualizer = this.visualizer.animations[animation.type as keyof typeof this.visualizer.animations]; + + this.visualizer.addAnimation( + new TargetVisualizer(animation.config as never), // Magic of Typescript + ); + } + } + + resize(_: number, __: number) { + } + + render() { + } +} + +export default WaveVisualizer; diff --git a/plugins/visualizer/vudio.d.ts b/plugins/visualizer/vudio.d.ts new file mode 100644 index 00000000..4964951b --- /dev/null +++ b/plugins/visualizer/vudio.d.ts @@ -0,0 +1,34 @@ +declare module 'vudio/umd/vudio' { + interface NoneWaveformOptions { + maxHeight?: number; + minHeight?: number; + spacing?: number; + color?: string | string[]; + shadowBlur?: number; + shadowColor?: string; + fadeSide?: boolean; + } + + interface WaveformOptions extends NoneWaveformOptions{ + horizontalAlign: 'left' | 'center' | 'right'; + verticalAlign: 'top' | 'middle' | 'bottom'; + } + + interface VudioOptions { + effect?: 'waveform' | 'circlewave' | 'circlebar' | 'lighting'; + accuracy?: number; + width?: number; + height?: number; + waveform?: WaveformOptions + } + + class Vudio { + constructor(audio: HTMLAudioElement | MediaStream, canvas: HTMLCanvasElement, options: VudioOptions = {}); + + dance(): void; + pause(): void; + setOption(options: VudioOptions): void; + } + + export default Vudio; +} diff --git a/preload.js b/preload.js deleted file mode 100644 index 84f7272b..00000000 --- a/preload.js +++ /dev/null @@ -1,164 +0,0 @@ -const config = require("./config"); -const { fileExists } = require("./plugins/utils"); -const setupSongInfo = require("./providers/song-info-front"); -const { setupSongControls } = require("./providers/song-controls-front"); -const { ipcRenderer } = require("electron"); -const is = require("electron-is"); - -const { startingPages } = require("./providers/extracted-data"); - -const plugins = config.plugins.getEnabled(); - -const $ = document.querySelector.bind(document); - -let api; - -plugins.forEach(async ([plugin, options]) => { - const preloadPath = await ipcRenderer.invoke( - "getPath", - __dirname, - "plugins", - plugin, - "preload.js" - ); - fileExists(preloadPath, () => { - const run = require(preloadPath); - run(options); - }); - - const actionPath = await ipcRenderer.invoke( - "getPath", - __dirname, - "plugins", - plugin, - "actions.js" - ); - fileExists(actionPath, () => { - const actions = require(actionPath).actions || {}; - - // TODO: re-enable once contextIsolation is set to true - // contextBridge.exposeInMainWorld(plugin + "Actions", actions); - Object.keys(actions).forEach((actionName) => { - global[actionName] = actions[actionName]; - }); - }); -}); - -document.addEventListener("DOMContentLoaded", () => { - plugins.forEach(async ([plugin, options]) => { - const pluginPath = await ipcRenderer.invoke( - "getPath", - __dirname, - "plugins", - plugin, - "front.js" - ); - fileExists(pluginPath, () => { - const run = require(pluginPath); - run(options); - }); - }); - - // wait for complete load of youtube api - listenForApiLoad(); - - // inject song-info provider - setupSongInfo(); - - // inject song-controls - setupSongControls(); - - // Add action for reloading - global.reload = () => ipcRenderer.send('reload'); - - // Blocks the "Are You Still There?" popup by setting the last active time to Date.now every 15min - setInterval(() => window._lact = Date.now(), 900000); - - // setup back to front logger - if (is.dev()) { - ipcRenderer.on("log", (_event, log) => { - console.log(JSON.parse(log)); - }); - } -}); - -function listenForApiLoad() { - api = $('#movie_player'); - if (api) { - onApiLoaded(); - return; - } - - const observer = new MutationObserver(() => { - api = $('#movie_player'); - if (api) { - observer.disconnect(); - onApiLoaded(); - } - }) - - observer.observe(document.documentElement, { childList: true, subtree: true }); -} - -function onApiLoaded() { - const video = $("video"); - const audioContext = new AudioContext(); - const audioSource = audioContext.createMediaElementSource(video); - audioSource.connect(audioContext.destination); - - video.addEventListener( - "loadstart", - () => { - // Emit "audioCanPlay" for each video - video.addEventListener( - "canplaythrough", - () => { - document.dispatchEvent( - new CustomEvent("audioCanPlay", { - detail: { - audioContext: audioContext, - audioSource: audioSource, - }, - }) - ); - }, - { once: true } - ); - }, - { passive: true } - ); - - document.dispatchEvent(new CustomEvent('apiLoaded', { detail: api })); - ipcRenderer.send('apiLoaded'); - - // Navigate to "Starting page" - const startingPage = config.get("options.startingPage"); - if (startingPage && startingPages[startingPage]) { - $('ytmusic-app')?.navigate_(startingPages[startingPage]); - } - - // Remove upgrade button - if (config.get("options.removeUpgradeButton")) { - const styles = document.createElement("style"); - styles.innerHTML = ` - ytmusic-guide-section-renderer #items ytmusic-guide-entry-renderer:last-child { - display: none; - } - `; - document.head.appendChild(styles); - } - - - // Hide / Force show like buttons - const likeButtonsOptions = config.get("options.likeButtons"); - if (likeButtonsOptions) { - const likeButtons = $("ytmusic-like-button-renderer"); - if (likeButtons) { - likeButtons.style.display = - { - hide: "none", - force: "inherit", - }[likeButtonsOptions] || ""; - } - } -} diff --git a/preload.ts b/preload.ts new file mode 100644 index 00000000..9cbc11d7 --- /dev/null +++ b/preload.ts @@ -0,0 +1,177 @@ +import { ipcRenderer } from 'electron'; +import is from 'electron-is'; + +import config from './config'; +import { fileExists } from './plugins/utils'; +import setupSongInfo from './providers/song-info-front'; +import { setupSongControls } from './providers/song-controls-front'; +import { startingPages } from './providers/extracted-data'; + + +const plugins = config.plugins.getEnabled(); + +const $ = document.querySelector.bind(document); + +let api: Element | null = null; + +interface Actions { + CHANNEL: string; + ACTIONS: Record, + actions: Record void>, +} + +plugins.forEach(async ([plugin, options]) => { + const preloadPath = await ipcRenderer.invoke( + 'getPath', + __dirname, + 'plugins', + plugin, + 'preload.js', + ) as string; + fileExists(preloadPath, () => { + // eslint-disable-next-line @typescript-eslint/no-var-requires,@typescript-eslint/no-unsafe-member-access + const run = require(preloadPath).default as (config: typeof options) => Promise; + run(options); + }); + + const actionPath = await ipcRenderer.invoke( + 'getPath', + __dirname, + 'plugins', + plugin, + 'actions.js', + ) as string; + fileExists(actionPath, () => { + // eslint-disable-next-line @typescript-eslint/no-var-requires + const actions = (require(actionPath) as Actions).actions ?? {}; + + // TODO: re-enable once contextIsolation is set to true + // contextBridge.exposeInMainWorld(plugin + "Actions", actions); + for (const actionName of Object.keys(actions)) { + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access,@typescript-eslint/no-explicit-any + (global as any)[actionName] = actions[actionName]; + } + }); +}); + +document.addEventListener('DOMContentLoaded', () => { + plugins.forEach(async ([plugin, options]) => { + const pluginPath = await ipcRenderer.invoke( + 'getPath', + __dirname, + 'plugins', + plugin, + 'front.js', + ) as string; + fileExists(pluginPath, () => { + // eslint-disable-next-line @typescript-eslint/no-var-requires,@typescript-eslint/no-unsafe-member-access + const run = require(pluginPath).default as (config: typeof options) => Promise; + run(options); + }); + }); + + // Wait for complete load of youtube api + listenForApiLoad(); + + // Inject song-info provider + setupSongInfo(); + + // Inject song-controls + setupSongControls(); + + // Add action for reloading + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access,@typescript-eslint/no-explicit-any + (global as any).reload = () => ipcRenderer.send('reload'); + + // Blocks the "Are You Still There?" popup by setting the last active time to Date.now every 15min + setInterval(() => window._lact = Date.now(), 900_000); + + // Setup back to front logger + if (is.dev()) { + ipcRenderer.on('log', (_event, log: string) => { + console.log(JSON.parse(log)); + }); + } +}); + +function listenForApiLoad() { + api = $('#movie_player'); + if (api) { + onApiLoaded(); + return; + } + + const observer = new MutationObserver(() => { + api = $('#movie_player'); + if (api) { + observer.disconnect(); + onApiLoaded(); + } + }); + + observer.observe(document.documentElement, { childList: true, subtree: true }); +} + +interface YouTubeMusicAppElement extends HTMLElement { + navigate_(page: string): void; +} + +function onApiLoaded() { + const video = $('video')!; + const audioContext = new AudioContext(); + const audioSource = audioContext.createMediaElementSource(video); + audioSource.connect(audioContext.destination); + + video.addEventListener( + 'loadstart', + () => { + // Emit "audioCanPlay" for each video + video.addEventListener( + 'canplaythrough', + () => { + document.dispatchEvent( + new CustomEvent('audioCanPlay', { + detail: { + audioContext, + audioSource, + }, + }), + ); + }, + { once: true }, + ); + }, + { passive: true }, + );! + + document.dispatchEvent(new CustomEvent('apiLoaded', { detail: api })); + ipcRenderer.send('apiLoaded'); + + // Navigate to "Starting page" + const startingPage: string = config.get('options.startingPage'); + if (startingPage && startingPages[startingPage]) { + $('ytmusic-app')?.navigate_(startingPages[startingPage]); + } + + // Remove upgrade button + if (config.get('options.removeUpgradeButton')) { + const styles = document.createElement('style'); + styles.innerHTML = `ytmusic-guide-section-renderer #items ytmusic-guide-entry-renderer:last-child { + display: none; + }`; + document.head.appendChild(styles); + } + + // Hide / Force show like buttons + const likeButtonsOptions: string = config.get('options.likeButtons'); + if (likeButtonsOptions) { + const likeButtons: HTMLElement | null = $('ytmusic-like-button-renderer'); + if (likeButtons) { + likeButtons.style.display + = { + hide: 'none', + force: 'inherit', + }[likeButtonsOptions] || ''; + } + } +} diff --git a/providers/app-controls.js b/providers/app-controls.js deleted file mode 100644 index bed99157..00000000 --- a/providers/app-controls.js +++ /dev/null @@ -1,34 +0,0 @@ -const path = require("path"); - -const { app, BrowserWindow, ipcMain, ipcRenderer } = require("electron"); -const config = require("../config"); - -module.exports.restart = () => { - process.type === 'browser' ? restart() : ipcRenderer.send('restart'); -}; - -module.exports.setupAppControls = () => { - ipcMain.on('restart', restart); - ipcMain.handle('getDownloadsFolder', () => app.getPath("downloads")); - ipcMain.on('reload', () => BrowserWindow.getFocusedWindow().webContents.loadURL(config.get("url"))); - ipcMain.handle('getPath', (_, ...args) => path.join(...args)); -} - -function restart() { - app.relaunch({ execPath: process.env.PORTABLE_EXECUTABLE_FILE }); - // execPath will be undefined if not running portable app, resulting in default behavior - app.quit(); -} - -function sendToFront(channel, ...args) { - BrowserWindow.getAllWindows().forEach(win => { - win.webContents.send(channel, ...args); - }); -} - -module.exports.sendToFront = - process.type === 'browser' - ? sendToFront - : () => { - console.error('sendToFront called from renderer'); - }; diff --git a/providers/app-controls.ts b/providers/app-controls.ts new file mode 100644 index 00000000..6137871e --- /dev/null +++ b/providers/app-controls.ts @@ -0,0 +1,35 @@ +import path from 'node:path'; + +import { app, BrowserWindow, ipcMain, ipcRenderer } from 'electron'; + +import config from '../config'; + +export const restart = () => { + process.type === 'browser' ? restartInternal() : ipcRenderer.send('restart'); +}; + +export const setupAppControls = () => { + ipcMain.on('restart', restart); + ipcMain.handle('getDownloadsFolder', () => app.getPath('downloads')); + ipcMain.on('reload', () => BrowserWindow.getFocusedWindow()?.webContents.loadURL(config.get('url'))); + ipcMain.handle('getPath', (_, ...args: string[]) => path.join(...args)); +}; + +function restartInternal() { + app.relaunch({ execPath: process.env.PORTABLE_EXECUTABLE_FILE }); + // ExecPath will be undefined if not running portable app, resulting in default behavior + app.quit(); +} + +function sendToFrontInternal(channel: string, ...args: unknown[]) { + for (const win of BrowserWindow.getAllWindows()) { + win.webContents.send(channel, ...args); + } +} + +export const sendToFront + = process.type === 'browser' + ? sendToFrontInternal + : () => { + console.error('sendToFront called from renderer'); + }; diff --git a/providers/decorators.js b/providers/decorators.js deleted file mode 100644 index 63ba22cb..00000000 --- a/providers/decorators.js +++ /dev/null @@ -1,113 +0,0 @@ -module.exports = { - singleton, - debounce, - cache, - throttle, - memoize, - retry, -}; - -/** - * @template T - * @param {T} fn - * @returns {T} - */ -function singleton(fn) { - let called = false; - return (...args) => { - if (called) return; - called = true; - return fn(...args); - }; -} - -/** - * @template T - * @param {T} fn - * @param {number} delay - * @returns {T} - */ -function debounce(fn, delay) { - let timeout; - return (...args) => { - clearTimeout(timeout); - timeout = setTimeout(() => fn(...args), delay); - }; -} - -/** - * @template T - * @param {T} fn - * @returns {T} - */ -function cache(fn) { - let lastArgs; - let lastResult; - return (...args) => { - if ( - args.length !== lastArgs?.length || - args.some((arg, i) => arg !== lastArgs[i]) - ) { - lastArgs = args; - lastResult = fn(...args); - } - return lastResult; - }; -} - -/* - the following are currently unused, but potentially useful in the future -*/ - -/** - * @template T - * @param {T} fn - * @param {number} delay - * @returns {T} - */ -function throttle(fn, delay) { - let timeout; - return (...args) => { - if (timeout) return; - timeout = setTimeout(() => { - timeout = undefined; - fn(...args); - }, delay); - }; -} - -/** - * @template T - * @param {T} fn - * @returns {T} - */ -function memoize(fn) { - const cache = new Map(); - return (...args) => { - const key = JSON.stringify(args); - if (!cache.has(key)) { - cache.set(key, fn(...args)); - } - return cache.get(key); - }; -} - -/** - * @template T - * @param {T} fn - * @returns {T} - */ -function retry(fn, { retries = 3, delay = 1000 } = {}) { - return (...args) => { - try { - return fn(...args); - } catch (e) { - if (retries > 0) { - retries--; - setTimeout(() => retry(fn, { retries, delay })(...args), delay); - } else { - throw e; - } - } - }; -} diff --git a/providers/decorators.ts b/providers/decorators.ts new file mode 100644 index 00000000..3b59e8a8 --- /dev/null +++ b/providers/decorators.ts @@ -0,0 +1,91 @@ +export function singleton unknown>(fn: T): T { + let called = false; + + return ((...args) => { + if (called) { + return; + } + + called = true; + return fn(...args); + }) as T; +} + +export function debounce unknown>(fn: T, delay: number): T { + let timeout: NodeJS.Timeout; + return ((...args) => { + clearTimeout(timeout); + timeout = setTimeout(() => fn(...args), delay); + }) as T; +} + +export function cache R, P extends never[], R>(fn: T): T { + let lastArgs: P; + let lastResult: R; + return ((...args: P) => { + if ( + args.length !== lastArgs?.length + || args.some((arg, i) => arg !== lastArgs[i]) + ) { + lastArgs = args; + lastResult = fn(...args); + } + + return lastResult; + }) as T; +} + +/* + The following are currently unused, but potentially useful in the future +*/ + +export function throttle unknown>(fn: T, delay: number): T { + let timeout: NodeJS.Timeout | undefined; + return ((...args) => { + if (timeout) { + return; + } + + timeout = setTimeout(() => { + timeout = undefined; + fn(...args); + }, delay); + }) as T; +} + +function memoize unknown>(fn: T): T { + const cache = new Map(); + + return ((...args) => { + const key = JSON.stringify(args); + if (!cache.has(key)) { + cache.set(key, fn(...args)); + } + + return cache.get(key) as unknown; + }) as T; +} + +function retry unknown>(fn: T, { retries = 3, delay = 1000 } = {}): T { + return ((...args) => { + try { + return fn(...args); + } catch (error) { + if (retries > 0) { + retries--; + setTimeout(() => retry(fn, { retries, delay })(...args), delay); + } else { + throw error; + } + } + }) as T; +} + +export default { + singleton, + debounce, + cache, + throttle, + memoize, + retry, +}; diff --git a/providers/dom-elements.js b/providers/dom-elements.js deleted file mode 100644 index 1750d4d7..00000000 --- a/providers/dom-elements.js +++ /dev/null @@ -1,4 +0,0 @@ -const getSongMenu = () => - document.querySelector("ytmusic-menu-popup-renderer tp-yt-paper-listbox"); - -module.exports = { getSongMenu }; diff --git a/providers/dom-elements.ts b/providers/dom-elements.ts new file mode 100644 index 00000000..6e86d78b --- /dev/null +++ b/providers/dom-elements.ts @@ -0,0 +1,4 @@ +export const getSongMenu = () => + document.querySelector('ytmusic-menu-popup-renderer tp-yt-paper-listbox'); + +export default { getSongMenu }; diff --git a/providers/extracted-data.js b/providers/extracted-data.js deleted file mode 100644 index a7020a0d..00000000 --- a/providers/extracted-data.js +++ /dev/null @@ -1,23 +0,0 @@ -const startingPages = { - Default: '', - Home: 'FEmusic_home', - Explore: 'FEmusic_explore', - 'New Releases': 'FEmusic_new_releases', - Charts: 'FEmusic_charts', - 'Moods & Genres': 'FEmusic_moods_and_genres', - Library: 'FEmusic_library_landing', - Playlists: 'FEmusic_liked_playlists', - Songs: 'FEmusic_liked_videos', - Albums: 'FEmusic_liked_albums', - Artists: 'FEmusic_library_corpus_track_artists', - 'Subscribed Artists': 'FEmusic_library_corpus_artists', - Uploads: 'FEmusic_library_privately_owned_landing', - 'Uploaded Playlists': 'FEmusic_liked_playlists', - 'Uploaded Songs': 'FEmusic_library_privately_owned_tracks', - 'Uploaded Albums': 'FEmusic_library_privately_owned_releases', - 'Uploaded Artists': 'FEmusic_library_privately_owned_artists', -}; - -module.exports = { - startingPages, -}; diff --git a/providers/extracted-data.ts b/providers/extracted-data.ts new file mode 100644 index 00000000..f1afa096 --- /dev/null +++ b/providers/extracted-data.ts @@ -0,0 +1,23 @@ +export const startingPages: Record = { + 'Default': '', + 'Home': 'FEmusic_home', + 'Explore': 'FEmusic_explore', + 'New Releases': 'FEmusic_new_releases', + 'Charts': 'FEmusic_charts', + 'Moods & Genres': 'FEmusic_moods_and_genres', + 'Library': 'FEmusic_library_landing', + 'Playlists': 'FEmusic_liked_playlists', + 'Songs': 'FEmusic_liked_videos', + 'Albums': 'FEmusic_liked_albums', + 'Artists': 'FEmusic_library_corpus_track_artists', + 'Subscribed Artists': 'FEmusic_library_corpus_artists', + 'Uploads': 'FEmusic_library_privately_owned_landing', + 'Uploaded Playlists': 'FEmusic_liked_playlists', + 'Uploaded Songs': 'FEmusic_library_privately_owned_tracks', + 'Uploaded Albums': 'FEmusic_library_privately_owned_releases', + 'Uploaded Artists': 'FEmusic_library_privately_owned_artists', +}; + +export default { + startingPages, +}; diff --git a/providers/prompt-custom-titlebar.js b/providers/prompt-custom-titlebar.js deleted file mode 100644 index 222a6bd6..00000000 --- a/providers/prompt-custom-titlebar.js +++ /dev/null @@ -1,14 +0,0 @@ -const { Titlebar, Color } = require("custom-electron-titlebar"); - -module.exports = () => { - new Titlebar({ - backgroundColor: Color.fromHex("#050505"), - minimizable: false, - maximizable: false, - menu: null - }); - const mainStyle = document.querySelector("#container").style; - mainStyle.width = "100%"; - mainStyle.position = "fixed"; - mainStyle.border = "unset"; -}; diff --git a/providers/prompt-custom-titlebar.ts b/providers/prompt-custom-titlebar.ts new file mode 100644 index 00000000..5068745c --- /dev/null +++ b/providers/prompt-custom-titlebar.ts @@ -0,0 +1,21 @@ +// eslint-disable-next-line import/no-unresolved +import { Titlebar, Color } from 'custom-electron-titlebar'; + +const customTitlebarFunction = () => { + new Titlebar({ + backgroundColor: Color.fromHex('#050505'), + minimizable: false, + maximizable: false, + menu: undefined, + }); + const mainStyle = document.querySelector('#container')?.style; + if (mainStyle) { + mainStyle.width = '100%'; + mainStyle.position = 'fixed'; + mainStyle.border = 'unset'; + } +}; + + +module.exports = customTitlebarFunction; +export default customTitlebarFunction; diff --git a/providers/prompt-options.js b/providers/prompt-options.js deleted file mode 100644 index a34d3b1c..00000000 --- a/providers/prompt-options.js +++ /dev/null @@ -1,18 +0,0 @@ -const path = require("path"); -const is = require("electron-is"); -const { isEnabled } = require("../config/plugins"); - -const iconPath = path.join(__dirname, "..", "assets", "youtube-music-tray.png"); -const customTitlebarPath = path.join(__dirname, "prompt-custom-titlebar.js"); - -const promptOptions = !is.macOS() && isEnabled("in-app-menu") ? { - customStylesheet: "dark", - // The following are used for custom titlebar - frame: false, - customScript: customTitlebarPath, -} : { - customStylesheet: "dark", - icon: iconPath -}; - -module.exports = () => promptOptions; diff --git a/providers/prompt-options.ts b/providers/prompt-options.ts new file mode 100644 index 00000000..87e27f13 --- /dev/null +++ b/providers/prompt-options.ts @@ -0,0 +1,20 @@ +import path from 'node:path'; + +import is from 'electron-is'; + +import { isEnabled } from '../config/plugins'; + +const iconPath = path.join(__dirname, '..', 'assets', 'youtube-music-tray.png'); +const customTitlebarPath = path.join(__dirname, 'prompt-custom-titlebar.js'); + +const promptOptions = !is.macOS() && isEnabled('in-app-menu') ? { + customStylesheet: 'dark', + // The following are used for custom titlebar + frame: false, + customScript: customTitlebarPath, +} : { + customStylesheet: 'dark', + icon: iconPath, +}; + +export default () => promptOptions; diff --git a/providers/protocol-handler.js b/providers/protocol-handler.js deleted file mode 100644 index 6b0d36e1..00000000 --- a/providers/protocol-handler.js +++ /dev/null @@ -1,44 +0,0 @@ -const { app } = require("electron"); -const path = require("path"); -const getSongControls = require("./song-controls"); - -const APP_PROTOCOL = "youtubemusic"; - -let protocolHandler; - -function setupProtocolHandler(win) { - if (process.defaultApp && process.argv.length >= 2) { - app.setAsDefaultProtocolClient( - APP_PROTOCOL, - process.execPath, - [path.resolve(process.argv[1])] - ); - } else { - app.setAsDefaultProtocolClient(APP_PROTOCOL) - } - - const songControls = getSongControls(win); - - protocolHandler = (cmd) => { - if (Object.keys(songControls).includes(cmd)) { - songControls[cmd](); - } - } -} - -function handleProtocol(cmd) { - protocolHandler(cmd); -} - -function changeProtocolHandler(f) { - protocolHandler = f; -} - -module.exports = { - APP_PROTOCOL, - setupProtocolHandler, - handleProtocol, - changeProtocolHandler, -}; - - diff --git a/providers/protocol-handler.ts b/providers/protocol-handler.ts new file mode 100644 index 00000000..49dd88b2 --- /dev/null +++ b/providers/protocol-handler.ts @@ -0,0 +1,45 @@ +import path from 'node:path'; + +import { app, BrowserWindow } from 'electron'; + +import getSongControls from './song-controls'; + +export const APP_PROTOCOL = 'youtubemusic'; + +let protocolHandler: ((cmd: string) => void) | undefined; + +export function setupProtocolHandler(win: BrowserWindow) { + if (process.defaultApp && process.argv.length >= 2) { + app.setAsDefaultProtocolClient( + APP_PROTOCOL, + process.execPath, + [path.resolve(process.argv[1])], + ); + } else { + app.setAsDefaultProtocolClient(APP_PROTOCOL); + } + + const songControls = getSongControls(win); + + protocolHandler = ((cmd: keyof typeof songControls) => { + if (Object.keys(songControls).includes(cmd)) { + songControls[cmd](); + } + }) as (cmd: string) => void; +} + +export function handleProtocol(cmd: string) { + protocolHandler?.(cmd); +} + +export function changeProtocolHandler(f: (cmd: string) => void) { + protocolHandler = f; +} + +export default { + APP_PROTOCOL, + setupProtocolHandler, + handleProtocol, + changeProtocolHandler, +}; + diff --git a/providers/song-controls-front.js b/providers/song-controls-front.js deleted file mode 100644 index 4bc33274..00000000 --- a/providers/song-controls-front.js +++ /dev/null @@ -1,8 +0,0 @@ -const { ipcRenderer } = require("electron"); - -module.exports.setupSongControls = () => { - document.addEventListener('apiLoaded', e => { - ipcRenderer.on("seekTo", (_, t) => e.detail.seekTo(t)); - ipcRenderer.on("seekBy", (_, t) => e.detail.seekBy(t)); - }, { once: true, passive: true }) -}; diff --git a/providers/song-controls-front.ts b/providers/song-controls-front.ts new file mode 100644 index 00000000..012a75b4 --- /dev/null +++ b/providers/song-controls-front.ts @@ -0,0 +1,8 @@ +import { ipcRenderer } from 'electron'; + +export const setupSongControls = () => { + document.addEventListener('apiLoaded', (event) => { + ipcRenderer.on('seekTo', (_, t: number) => event.detail.seekTo(t)); + ipcRenderer.on('seekBy', (_, t: number) => event.detail.seekBy(t)); + }, { once: true, passive: true }); +}; diff --git a/providers/song-controls.js b/providers/song-controls.js deleted file mode 100644 index 93f352d1..00000000 --- a/providers/song-controls.js +++ /dev/null @@ -1,57 +0,0 @@ -// This is used for to control the songs -const pressKey = (window, key, modifiers = []) => { - window.webContents.sendInputEvent({ - type: "keydown", - modifiers, - keyCode: key, - }); -}; - -module.exports = (win) => { - const commands = { - // Playback - previous: () => pressKey(win, "k"), - next: () => pressKey(win, "j"), - playPause: () => pressKey(win, ";"), - like: () => pressKey(win, "+"), - dislike: () => pressKey(win, "_"), - go10sBack: () => pressKey(win, "h"), - go10sForward: () => pressKey(win, "l"), - go1sBack: () => pressKey(win, "h", ["shift"]), - go1sForward: () => pressKey(win, "l", ["shift"]), - shuffle: () => pressKey(win, "s"), - switchRepeat: (n = 1) => { - for (let i = 0; i < n; i++) pressKey(win, "r"); - }, - // General - volumeMinus10: () => pressKey(win, "-"), - volumePlus10: () => pressKey(win, "="), - fullscreen: () => pressKey(win, "f"), - muteUnmute: () => pressKey(win, "m"), - maximizeMinimisePlayer: () => pressKey(win, "q"), - // Navigation - goToHome: () => { - pressKey(win, "g"); - pressKey(win, "h"); - }, - goToLibrary: () => { - pressKey(win, "g"); - pressKey(win, "l"); - }, - goToSettings: () => { - pressKey(win, "g"); - pressKey(win, ","); - }, - goToExplore: () => { - pressKey(win, "g"); - pressKey(win, "e"); - }, - search: () => pressKey(win, "/"), - showShortcuts: () => pressKey(win, "/", ["shift"]), - }; - return { - ...commands, - play: commands.playPause, - pause: commands.playPause - }; -}; diff --git a/providers/song-controls.ts b/providers/song-controls.ts new file mode 100644 index 00000000..eae0fd60 --- /dev/null +++ b/providers/song-controls.ts @@ -0,0 +1,62 @@ +// This is used for to control the songs +import { BrowserWindow } from 'electron'; + +type Modifiers = (Electron.MouseInputEvent | Electron.MouseWheelInputEvent | Electron.KeyboardInputEvent)['modifiers']; +export const pressKey = (window: BrowserWindow, key: string, modifiers: Modifiers = []) => { + window.webContents.sendInputEvent({ + type: 'keyDown', + modifiers, + keyCode: key, + }); +}; + +export default (win: BrowserWindow) => { + const commands = { + // Playback + previous: () => pressKey(win, 'k'), + next: () => pressKey(win, 'j'), + playPause: () => pressKey(win, ';'), + like: () => pressKey(win, '+'), + dislike: () => pressKey(win, '_'), + go10sBack: () => pressKey(win, 'h'), + go10sForward: () => pressKey(win, 'l'), + go1sBack: () => pressKey(win, 'h', ['shift']), + go1sForward: () => pressKey(win, 'l', ['shift']), + shuffle: () => pressKey(win, 's'), + switchRepeat(n = 1) { + for (let i = 0; i < n; i++) { + pressKey(win, 'r'); + } + }, + // General + volumeMinus10: () => pressKey(win, '-'), + volumePlus10: () => pressKey(win, '='), + fullscreen: () => pressKey(win, 'f'), + muteUnmute: () => pressKey(win, 'm'), + maximizeMinimisePlayer: () => pressKey(win, 'q'), + // Navigation + goToHome() { + pressKey(win, 'g'); + pressKey(win, 'h'); + }, + goToLibrary() { + pressKey(win, 'g'); + pressKey(win, 'l'); + }, + goToSettings() { + pressKey(win, 'g'); + pressKey(win, ','); + }, + goToExplore() { + pressKey(win, 'g'); + pressKey(win, 'e'); + }, + search: () => pressKey(win, '/'), + showShortcuts: () => pressKey(win, '/', ['shift']), + }; + return { + ...commands, + play: commands.playPause, + pause: commands.playPause, + }; +}; diff --git a/providers/song-info-front.js b/providers/song-info-front.js deleted file mode 100644 index 32349ad9..00000000 --- a/providers/song-info-front.js +++ /dev/null @@ -1,100 +0,0 @@ -const { ipcRenderer } = require("electron"); -const { getImage } = require("./song-info"); -const { singleton } = require("../providers/decorators"); - -global.songInfo = {}; - -const $ = s => document.querySelector(s); -const $$ = s => Array.from(document.querySelectorAll(s)); - -ipcRenderer.on("update-song-info", async (_, extractedSongInfo) => { - global.songInfo = JSON.parse(extractedSongInfo); - global.songInfo.image = await getImage(global.songInfo.imageSrc); -}); - -// used because 'loadeddata' or 'loadedmetadata' weren't firing on song start for some users (https://github.com/th-ch/youtube-music/issues/473) -const srcChangedEvent = new CustomEvent('srcChanged'); - -module.exports.setupSeekedListener = singleton(() => { - $('video')?.addEventListener('seeked', v => ipcRenderer.send('seeked', v.target.currentTime)); -}); - -module.exports.setupTimeChangedListener = singleton(() => { - const progressObserver = new MutationObserver(mutations => { - ipcRenderer.send('timeChanged', mutations[0].target.value); - global.songInfo.elapsedSeconds = mutations[0].target.value; - }); - progressObserver.observe($('#progress-bar'), { attributeFilter: ["value"] }); -}); - -module.exports.setupRepeatChangedListener = singleton(() => { - const repeatObserver = new MutationObserver(mutations => { - ipcRenderer.send('repeatChanged', mutations[0].target.__dataHost.getState().queue.repeatMode); - }); - repeatObserver.observe($('#right-controls .repeat'), { attributeFilter: ["title"] }); - - // Emit the initial value as well; as it's persistent between launches. - ipcRenderer.send('repeatChanged', $('ytmusic-player-bar').getState().queue.repeatMode); -}); - -module.exports.setupVolumeChangedListener = singleton((api) => { - $('video').addEventListener('volumechange', (_) => { - ipcRenderer.send('volumeChanged', api.getVolume()); - }); - // Emit the initial value as well; as it's persistent between launches. - ipcRenderer.send('volumeChanged', api.getVolume()); -}); - -module.exports = () => { - document.addEventListener('apiLoaded', apiEvent => { - ipcRenderer.on("setupTimeChangedListener", async () => { - this.setupTimeChangedListener(); - }); - - ipcRenderer.on("setupRepeatChangedListener", async () => { - this.setupRepeatChangedListener(); - }); - - ipcRenderer.on("setupVolumeChangedListener", async () => { - this.setupVolumeChangedListener(apiEvent.detail); - }); - - ipcRenderer.on("setupSeekedListener", async () => { - this.setupSeekedListener(); - }); - - const video = $('video'); - // name = "dataloaded" and abit later "dataupdated" - apiEvent.detail.addEventListener('videodatachange', (name, _dataEvent) => { - if (name !== 'dataloaded') return; - video.dispatchEvent(srcChangedEvent); - setTimeout(sendSongInfo, 200); - }) - - for (const status of ['playing', 'pause']) { - video.addEventListener(status, e => { - if (Math.round(e.target.currentTime) > 0) { - ipcRenderer.send("playPaused", { - isPaused: status === 'pause', - elapsedSeconds: Math.floor(e.target.currentTime) - }); - } - }); - } - - function sendSongInfo() { - const data = apiEvent.detail.getPlayerResponse(); - - data.videoDetails.album = $$( - ".byline.ytmusic-player-bar > .yt-simple-endpoint" - ).find(e => - e.href?.includes("browse/FEmusic_library_privately_owned_release") - || e.href?.includes("browse/MPREb") - )?.textContent; - - data.videoDetails.elapsedSeconds = 0; - data.videoDetails.isPaused = false; - ipcRenderer.send("video-src-changed", JSON.stringify(data)); - } - }, { once: true, passive: true }); -}; diff --git a/providers/song-info-front.ts b/providers/song-info-front.ts new file mode 100644 index 00000000..f5607869 --- /dev/null +++ b/providers/song-info-front.ts @@ -0,0 +1,144 @@ +import { ipcRenderer } from 'electron'; + +import { singleton } from './decorators'; +import { getImage, SongInfo } from './song-info'; + +import { YoutubePlayer } from '../types/youtube-player'; +import { GetState } from '../types/datahost-get-state'; + +let songInfo: SongInfo = {} as SongInfo; +export const getSongInfo = () => songInfo; + +const $ = (s: string): E | null => document.querySelector(s); +const $$ = (s: string): NodeListOf => document.querySelectorAll(s); + +ipcRenderer.on('update-song-info', async (_, extractedSongInfo: SongInfo) => { + songInfo = extractedSongInfo; + if (songInfo.imageSrc) songInfo.image = await getImage(songInfo.imageSrc); +}); + +// Used because 'loadeddata' or 'loadedmetadata' weren't firing on song start for some users (https://github.com/th-ch/youtube-music/issues/473) +const srcChangedEvent = new CustomEvent('srcChanged'); + +export const setupSeekedListener = singleton(() => { + $('video')?.addEventListener('seeked', (v) => { + if (v.target instanceof HTMLVideoElement) { + ipcRenderer.send('seeked', v.target.currentTime); + } + }); +}); + +export const setupTimeChangedListener = singleton(() => { + const progressObserver = new MutationObserver((mutations) => { + for (const mutation of mutations) { + const target = mutation.target as Node & { value: string }; + ipcRenderer.send('timeChanged', target.value); + songInfo.elapsedSeconds = Number(target.value); + } + }); + const progressBar = $('#progress-bar'); + if (progressBar) { + progressObserver.observe(progressBar, { attributeFilter: ['value'] }); + } +}); + +export const setupRepeatChangedListener = singleton(() => { + const repeatObserver = new MutationObserver((mutations) => { + + // provided by YouTube Music + ipcRenderer.send( + 'repeatChanged', + (mutations[0].target as Node & { + __dataHost: { + getState: () => GetState; + } + }).__dataHost.getState().queue.repeatMode, + ); + }); + repeatObserver.observe($('#right-controls .repeat')!, { attributeFilter: ['title'] }); + + // Emit the initial value as well; as it's persistent between launches. + // provided by YouTube Music + ipcRenderer.send( + 'repeatChanged', + $ GetState; + }>('ytmusic-player-bar')?.GetState().queue.repeatMode, + ); +}); + +export const setupVolumeChangedListener = singleton((api: YoutubePlayer) => { + $('video')?.addEventListener('volumechange', () => { + ipcRenderer.send('volumeChanged', api.getVolume()); + }); + // Emit the initial value as well; as it's persistent between launches. + ipcRenderer.send('volumeChanged', api.getVolume()); +}); + +export default () => { + document.addEventListener('apiLoaded', (apiEvent) => { + ipcRenderer.on('setupTimeChangedListener', () => { + setupTimeChangedListener(); + }); + + ipcRenderer.on('setupRepeatChangedListener', () => { + setupRepeatChangedListener(); + }); + + ipcRenderer.on('setupVolumeChangedListener', () => { + setupVolumeChangedListener(apiEvent.detail); + }); + + ipcRenderer.on('setupSeekedListener', () => { + setupSeekedListener(); + }); + + const playPausedHandler = (e: Event, status: string) => { + if (e.target instanceof HTMLVideoElement && Math.round(e.target.currentTime) > 0) { + ipcRenderer.send('playPaused', { + isPaused: status === 'pause', + elapsedSeconds: Math.floor(e.target.currentTime), + }); + } + }; + + const playPausedHandlers = { + playing: (e: Event) => playPausedHandler(e, 'playing'), + pause: (e: Event) => playPausedHandler(e, 'pause'), + }; + + // Name = "dataloaded" and abit later "dataupdated" + apiEvent.detail.addEventListener('videodatachange', (name: string) => { + if (name !== 'dataloaded') { + return; + } + const video = $('video'); + video?.dispatchEvent(srcChangedEvent); + + for (const status of ['playing', 'pause'] as const) { // for fix issue that pause event not fired + video?.addEventListener(status, playPausedHandlers[status]); + } + setTimeout(sendSongInfo, 200); + }); + + const video = $('video')!; + for (const status of ['playing', 'pause'] as const) { + video.addEventListener(status, playPausedHandlers[status]); + } + + function sendSongInfo() { + const data = apiEvent.detail.getPlayerResponse(); + + for (const e of $$('.byline.ytmusic-player-bar > .yt-simple-endpoint')) { + if (e.href?.includes('browse/FEmusic_library_privately_owned_release') || e.href?.includes('browse/MPREb')) { + data.videoDetails.album = e.textContent; + break; + } + } + + data.videoDetails.elapsedSeconds = 0; + data.videoDetails.isPaused = false; + ipcRenderer.send('video-src-changed', data); + } + }, { once: true, passive: true }); +}; diff --git a/providers/song-info.js b/providers/song-info.js deleted file mode 100644 index d63bddf0..00000000 --- a/providers/song-info.js +++ /dev/null @@ -1,138 +0,0 @@ -const { ipcMain, nativeImage } = require("electron"); - -const fetch = require("node-fetch"); - -const config = require("../config"); - -const { cache } = require("../providers/decorators") - -// Fill songInfo with empty values -/** - * @typedef {songInfo} SongInfo - */ -const songInfo = { - title: "", - artist: "", - views: 0, - uploadDate: "", - imageSrc: "", - image: null, - isPaused: undefined, - songDuration: 0, - elapsedSeconds: 0, - url: "", - album: undefined, - videoId: "", - playlistId: "", -}; - -// Grab the native image using the src -const getImage = cache( - /** - * @returns {Promise} - */ - async (src) => { - const result = await fetch(src); - const buffer = await result.buffer(); - const output = nativeImage.createFromBuffer(buffer); - if (output.isEmpty() && !src.endsWith(".jpg") && src.includes(".jpg")) { // fix hidden webp files (https://github.com/th-ch/youtube-music/issues/315) - return getImage(src.slice(0, src.lastIndexOf(".jpg") + 4)); - } else { - return output; - } - } -); - -const handleData = async (responseText, win) => { - const data = JSON.parse(responseText); - if (!data) return; - - const microformat = data.microformat?.microformatDataRenderer; - if (microformat) { - songInfo.uploadDate = microformat.uploadDate; - songInfo.url = microformat.urlCanonical?.split("&")[0]; - songInfo.playlistId = new URL(microformat.urlCanonical).searchParams.get("list"); - // used for options.resumeOnStart - config.set("url", microformat.urlCanonical); - } - - const videoDetails = data.videoDetails; - if (videoDetails) { - songInfo.title = cleanupName(videoDetails.title); - songInfo.artist = cleanupName(videoDetails.author); - songInfo.views = videoDetails.viewCount; - songInfo.songDuration = videoDetails.lengthSeconds; - songInfo.elapsedSeconds = videoDetails.elapsedSeconds; - songInfo.isPaused = videoDetails.isPaused; - songInfo.videoId = videoDetails.videoId; - songInfo.album = data?.videoDetails?.album; // Will be undefined if video exist - - const thumbnails = videoDetails.thumbnail?.thumbnails; - songInfo.imageSrc = thumbnails[thumbnails.length - 1]?.url.split("?")[0]; - songInfo.image = await getImage(songInfo.imageSrc); - - win.webContents.send("update-song-info", JSON.stringify(songInfo)); - } -}; - -// This variable will be filled with the callbacks once they register -const callbacks = []; - -// This function will allow plugins to register callback that will be triggered when data changes -/** - * @callback songInfoCallback - * @param {songInfo} songInfo - * @returns {void} - */ -/** - * @param {songInfoCallback} callback - */ -const registerCallback = (callback) => { - callbacks.push(callback); -}; - -let handlingData = false; - -const registerProvider = (win) => { - // This will be called when the song-info-front finds a new request with song data - ipcMain.on("video-src-changed", async (_, responseText) => { - handlingData = true; - await handleData(responseText, win); - handlingData = false; - callbacks.forEach((c) => { - c(songInfo, "video-src-changed"); - }); - }); - ipcMain.on("playPaused", (_, { isPaused, elapsedSeconds }) => { - songInfo.isPaused = isPaused; - songInfo.elapsedSeconds = elapsedSeconds; - if (handlingData) return; - callbacks.forEach((c) => { - c(songInfo, "playPaused"); - }); - }) -}; - -const suffixesToRemove = [ - " - topic", - "vevo", - " (performance video)", - " (clip officiel)", -]; - -function cleanupName(name) { - if (!name) return name; - name = name.replace(/\((?:official)?[ ]?(?:music)?[ ]?(?:lyric[s]?)?[ ]?(?:video)?\)$/i, '') - const lowCaseName = name.toLowerCase(); - for (const suffix of suffixesToRemove) { - if (lowCaseName.endsWith(suffix)) { - return name.slice(0, -suffix.length); - } - } - return name; -} - -module.exports = registerCallback; -module.exports.setupSongInfo = registerProvider; -module.exports.getImage = getImage; -module.exports.cleanupName = cleanupName; diff --git a/providers/song-info.ts b/providers/song-info.ts new file mode 100644 index 00000000..83cfa6ca --- /dev/null +++ b/providers/song-info.ts @@ -0,0 +1,148 @@ +import { BrowserWindow, ipcMain, nativeImage, net } from 'electron'; + +import { cache } from './decorators'; + +import config from '../config'; + +import type { GetPlayerResponse } from '../types/get-player-response'; + +export interface SongInfo { + title: string; + artist: string; + views: number; + uploadDate?: string; + imageSrc?: string | null; + image?: Electron.NativeImage | null; + isPaused?: boolean; + songDuration: number; + elapsedSeconds?: number; + url?: string; + album?: string | null; + videoId: string; + playlistId?: string; +} + +// Fill songInfo with empty values +export const songInfo: SongInfo = { + title: '', + artist: '', + views: 0, + uploadDate: '', + imageSrc: '', + image: null, + isPaused: undefined, + songDuration: 0, + elapsedSeconds: 0, + url: '', + album: undefined, + videoId: '', + playlistId: '', +}; + +// Grab the native image using the src +export const getImage = cache( + async (src: string): Promise => { + + const result = await net.fetch(src); + const buffer = await result.arrayBuffer(); + const output = nativeImage.createFromBuffer(Buffer.from(buffer)); + if (output.isEmpty() && !src.endsWith('.jpg') && src.includes('.jpg')) { // Fix hidden webp files (https://github.com/th-ch/youtube-music/issues/315) + return getImage(src.slice(0, src.lastIndexOf('.jpg') + 4)); + } + + return output; + }, +); + +const handleData = async (data: GetPlayerResponse, win: Electron.BrowserWindow) => { + if (!data) { + return; + } + + const microformat = data.microformat?.microformatDataRenderer; + if (microformat) { + songInfo.uploadDate = microformat.uploadDate; + songInfo.url = microformat.urlCanonical?.split('&')[0]; + songInfo.playlistId = new URL(microformat.urlCanonical).searchParams.get('list') ?? ''; + // Used for options.resumeOnStart + config.set('url', microformat.urlCanonical); + } + + const { videoDetails } = data; + if (videoDetails) { + songInfo.title = cleanupName(videoDetails.title); + songInfo.artist = cleanupName(videoDetails.author); + songInfo.views = Number(videoDetails.viewCount); + songInfo.songDuration = Number(videoDetails.lengthSeconds); + songInfo.elapsedSeconds = videoDetails.elapsedSeconds; + songInfo.isPaused = videoDetails.isPaused; + songInfo.videoId = videoDetails.videoId; + songInfo.album = data?.videoDetails?.album; // Will be undefined if video exist + + const thumbnails = videoDetails.thumbnail?.thumbnails; + songInfo.imageSrc = thumbnails.at(-1)?.url.split('?')[0]; + if (songInfo.imageSrc) songInfo.image = await getImage(songInfo.imageSrc); + + win.webContents.send('update-song-info', songInfo); + } +}; + +// This variable will be filled with the callbacks once they register +export type SongInfoCallback = (songInfo: SongInfo, event?: string) => void; +const callbacks: SongInfoCallback[] = []; + +// This function will allow plugins to register callback that will be triggered when data changes +const registerCallback = (callback: SongInfoCallback) => { + callbacks.push(callback); +}; + +let handlingData = false; + +const registerProvider = (win: BrowserWindow) => { + // This will be called when the song-info-front finds a new request with song data + ipcMain.on('video-src-changed', async (_, data: GetPlayerResponse) => { + handlingData = true; + await handleData(data, win); + handlingData = false; + for (const c of callbacks) { + c(songInfo, 'video-src-changed'); + } + }); + ipcMain.on('playPaused', (_, { isPaused, elapsedSeconds }: { isPaused: boolean, elapsedSeconds: number }) => { + songInfo.isPaused = isPaused; + songInfo.elapsedSeconds = elapsedSeconds; + if (handlingData) { + return; + } + + for (const c of callbacks) { + c(songInfo, 'playPaused'); + } + }); +}; + +const suffixesToRemove = [ + ' - topic', + 'vevo', + ' (performance video)', + ' (clip officiel)', +]; + +export function cleanupName(name: string): string { + if (!name) { + return name; + } + + name = name.replace(/\((?:official)? ?(?:music)? ?(?:lyrics?)? ?(?:video)?\)$/i, ''); + const lowCaseName = name.toLowerCase(); + for (const suffix of suffixesToRemove) { + if (lowCaseName.endsWith(suffix)) { + return name.slice(0, -suffix.length); + } + } + + return name; +} + +export default registerCallback; +export const setupSongInfo = registerProvider; diff --git a/readme.md b/readme.md index 587204f3..cc17bd3e 100644 --- a/readme.md +++ b/readme.md @@ -4,7 +4,7 @@ [![GitHub release](https://img.shields.io/github/release/th-ch/youtube-music.svg?style=for-the-badge&logo=youtube-music)](https://github.com/th-ch/youtube-music/releases/) [![GitHub license](https://img.shields.io/github/license/th-ch/youtube-music.svg?style=for-the-badge)](https://github.com/th-ch/youtube-music/blob/master/LICENSE) -[![XO code style](https://img.shields.io/badge/code_style-XO-5ed9c7.svg?style=for-the-badge)](https://github.com/sindresorhus/xo) +[![eslint code style](https://img.shields.io/badge/code_style-eslint-5ed9c7.svg?style=for-the-badge)](https://github.com/th-ch/youtube-music/blob/master/.eslintrc.js) [![Build status](https://img.shields.io/github/actions/workflow/status/th-ch/youtube-music/build.yml?branch=master&style=for-the-badge&logo=youtube-music)](https://GitHub.com/th-ch/youtube-music/releases/) [![Known Vulnerabilities](https://img.shields.io/snyk/vulnerabilities/github/th-ch/youtube-music?style=for-the-badge)](https://snyk.io/test/github/th-ch/youtube-music) [![GitHub All Releases](https://img.shields.io/github/downloads/th-ch/youtube-music/total?style=for-the-badge&logo=youtube-music)](https://GitHub.com/th-ch/youtube-music/releases/) @@ -23,35 +23,43 @@ **Electron wrapper around YouTube Music featuring:** - Native look & feel, aims at keeping the original interface -- Framework for custom plugins: change YouTube Music to your needs (style, content, features), enable/disable plugins in one click +- Framework for custom plugins: change YouTube Music to your needs (style, content, features), enable/disable plugins in + one click ## Download -You can check out the [latest release](https://github.com/th-ch/youtube-music/releases/latest) to quickly find the latest version. +You can check out the [latest release](https://github.com/th-ch/youtube-music/releases/latest) to quickly find the +latest version. ### Arch Linux -Install the `youtube-music-bin` package from the AUR. For AUR installation instructions, take a look at this [wiki page](https://wiki.archlinux.org/index.php/Arch_User_Repository#Installing_packages). +Install the `youtube-music-bin` package from the AUR. For AUR installation instructions, take a look at +this [wiki page](https://wiki.archlinux.org/index.php/Arch_User_Repository#Installing_packages). ### MacOS If you get an error "is damaged and can’t be opened." when launching the app, run the following in the Terminal: + ``` xattr -cr /Applications/YouTube\ Music.app ``` ### Windows -You can use the [Scoop package manager](https://scoop.sh) to install the `youtube-music` package from the [`extras` bucket](https://github.com/ScoopInstaller/Extras). +You can use the [Scoop package manager](https://scoop.sh) to install the `youtube-music` package from +the [`extras` bucket](https://github.com/ScoopInstaller/Extras). ``` scoop bucket add extras scoop install extras/youtube-music ``` -Alternately you can use [Winget](https://learn.microsoft.com/en-us/windows/package-manager/winget/), Windows 11s official CLI package manager to install the `th-ch.YouTubeMusic` package. +Alternately you can use [Winget](https://learn.microsoft.com/en-us/windows/package-manager/winget/), Windows 11s +official CLI package manager to install the `th-ch.YouTubeMusic` package. -*Note: Microsoft Defender SmartScreen might block the installation since it is from an "unknown publisher". This is also true for the manual installation when trying to run the executable(.exe) after a manual download here on github (same file).* +*Note: Microsoft Defender SmartScreen might block the installation since it is from an "unknown publisher". This is also +true for the manual installation when trying to run the executable(.exe) after a manual download here on github (same +file).* ``` winget install th-ch.YouTubeMusic @@ -61,7 +69,8 @@ winget install th-ch.YouTubeMusic - **Ad Blocker**: Block all ads and tracking out of the box -- **Audio Compressor**: Apply compression to audio (lowers the volume of the loudest parts of the signal and raises the volume of the softest parts) +- **Audio Compressor**: Apply compression to audio (lowers the volume of the loudest parts of the signal and raises the + volume of the softest parts) - **Blur Nav Bar**: makes navigation bar transparent and blurry @@ -75,15 +84,21 @@ winget install th-ch.YouTubeMusic - **Disable Autoplay**: Makes every song start in "paused" mode -- [**Discord**](https://discord.com/): Show your friends what you listen to with [Rich Presence](https://user-images.githubusercontent.com/28219076/104362104-a7a0b980-5513-11eb-9744-bb89eabe0016.png) +- [**Discord**](https://discord.com/): Show your friends what you listen to + with [Rich Presence](https://user-images.githubusercontent.com/28219076/104362104-a7a0b980-5513-11eb-9744-bb89eabe0016.png) -- **Downloader**: downloads MP3 [directly from the interface](https://user-images.githubusercontent.com/61631665/129977677-83a7d067-c192-45e1-98ae-b5a4927393be.png) [(youtube-dl)](https://github.com/ytdl-org/youtube-dl) +- **Downloader**: downloads + MP3 [directly from the interface](https://user-images.githubusercontent.com/61631665/129977677-83a7d067-c192-45e1-98ae-b5a4927393be.png) [(youtube-dl)](https://github.com/ytdl-org/youtube-dl) -- **Exponential Volume**: Makes the volume slider [exponential](https://greasyfork.org/en/scripts/397686-youtube-music-fix-volume-ratio/) so it's easier to select lower volumes. +- **Exponential Volume**: Makes the volume + slider [exponential](https://greasyfork.org/en/scripts/397686-youtube-music-fix-volume-ratio/) so it's easier to + select lower volumes. -- **In-App Menu**: [gives bars a fancy, dark look](https://user-images.githubusercontent.com/78568641/112215894-923dbf00-8c29-11eb-95c3-3ce15db27eca.png) +- **In-App Menu + **: [gives bars a fancy, dark look](https://user-images.githubusercontent.com/78568641/112215894-923dbf00-8c29-11eb-95c3-3ce15db27eca.png) - > (see [this post](https://github.com/th-ch/youtube-music/issues/410#issuecomment-952060709) if you have problem accessing the menu after enabling this plugin and hide-menu option) + > (see [this post](https://github.com/th-ch/youtube-music/issues/410#issuecomment-952060709) if you have problem + accessing the menu after enabling this plugin and hide-menu option) - [**Last.fm**](https://www.last.fm/): Scrobbles support @@ -93,37 +108,55 @@ winget install th-ch.YouTubeMusic - **No Google Login**: Remove Google login buttons and links from the interface -- **Notifications**: Display a notification when a song starts playing ([interactive notifications](https://user-images.githubusercontent.com/78568641/114102651-63ce0e00-98d0-11eb-9dfe-c5a02bb54f9c.png) are available on windows) +- **Notifications**: Display a notification when a song starts + playing ([interactive notifications](https://user-images.githubusercontent.com/78568641/114102651-63ce0e00-98d0-11eb-9dfe-c5a02bb54f9c.png) + are available on windows) - **Picture in picture**: allows to switch the app to picture-in-picture mode -- **Playback Speed**: Listen fast, listen slow! [Adds a slider that controls song speed](https://user-images.githubusercontent.com/61631665/129976003-e55db5ba-bf42-448c-a059-26a009775e68.png) +- **Playback Speed**: Listen fast, listen + slow! [Adds a slider that controls song speed](https://user-images.githubusercontent.com/61631665/129976003-e55db5ba-bf42-448c-a059-26a009775e68.png) -- **Precise Volume**: Control the volume precisely using mousewheel/hotkeys, with a custom hud and customizable volume steps +- **Precise Volume**: Control the volume precisely using mousewheel/hotkeys, with a custom hud and customizable volume + steps -- **Quality Changer**: Allows changing the video quality with a [button](https://user-images.githubusercontent.com/78568641/138574366-70324a5e-2d64-4f6a-acdd-dc2a2b9cecc5.png) on the video overlay +- **Quality Changer**: Allows changing the video quality with + a [button](https://user-images.githubusercontent.com/78568641/138574366-70324a5e-2d64-4f6a-acdd-dc2a2b9cecc5.png) on + the video overlay -- **Shortcuts**: Allows setting global hotkeys for playback (play/pause/next/previous) + disable [media osd](https://user-images.githubusercontent.com/84923831/128601225-afa38c1f-dea8-4209-9f72-0f84c1dd8b54.png) by overriding media keys + enable Ctrl/CMD + F to search + enable linux mpris support for mediakeys + [custom hotkeys](https://github.com/Araxeus/youtube-music/blob/1e591d6a3df98449bcda6e63baab249b28026148/providers/song-controls.js#L13-L50) for [advanced users](https://github.com/th-ch/youtube-music/issues/106#issuecomment-952156902) +- **Shortcuts**: Allows setting global hotkeys for playback (play/pause/next/previous) + + disable [media osd](https://user-images.githubusercontent.com/84923831/128601225-afa38c1f-dea8-4209-9f72-0f84c1dd8b54.png) + by overriding media keys + enable Ctrl/CMD + F to search + enable linux mpris support for + mediakeys + [custom hotkeys](https://github.com/Araxeus/youtube-music/blob/1e591d6a3df98449bcda6e63baab249b28026148/providers/song-controls.js#L13-L50) + for [advanced users](https://github.com/th-ch/youtube-music/issues/106#issuecomment-952156902) - **Skip-Silences** - Automatically skip silenced sections -- [**SponsorBlock**](https://github.com/ajayyy/SponsorBlock): Automatically Skips non-music parts like intro/outro or parts of music videos where the song isn't playing +- [**SponsorBlock**](https://github.com/ajayyy/SponsorBlock): Automatically Skips non-music parts like intro/outro or + parts of music videos where the song isn't playing -- **Taskbar Media Control**: Control playback from your [Windows taskbar](https://user-images.githubusercontent.com/78568641/111916130-24a35e80-8a82-11eb-80c8-5021c1aa27f4.png) +- **Taskbar Media Control**: Control playback from + your [Windows taskbar](https://user-images.githubusercontent.com/78568641/111916130-24a35e80-8a82-11eb-80c8-5021c1aa27f4.png) - **Touchbar**: Custom TouchBar layout for macOS -- **Tuna-OBS**: Integration with [OBS](https://obsproject.com/)'s plugin [Tuna](https://obsproject.com/forum/resources/tuna.843/) +- **Tuna-OBS**: Integration with [OBS](https://obsproject.com/)'s + plugin [Tuna](https://obsproject.com/forum/resources/tuna.843/) -- **Video Toggle**: Adds a [button](https://user-images.githubusercontent.com/28893833/173663950-63e6610e-a532-49b7-9afa-54cb57ddfc15.png) to switch between Video/Song mode. can also optionally remove the whole video tab +- **Video Toggle**: Adds + a [button](https://user-images.githubusercontent.com/28893833/173663950-63e6610e-a532-49b7-9afa-54cb57ddfc15.png) to + switch between Video/Song mode. can also optionally remove the whole video tab - **Visualizer**: Different music visualizers --- -- **Auto confirm when paused** (Always Enabled): disable the ["Continue Watching?"](https://user-images.githubusercontent.com/61631665/129977894-01c60740-7ec6-4bf0-9a2c-25da24491b0e.png) popup that pause music after a certain time +- **Auto confirm when paused** (Always Enabled): disable + the ["Continue Watching?"](https://user-images.githubusercontent.com/61631665/129977894-01c60740-7ec6-4bf0-9a2c-25da24491b0e.png) + popup that pause music after a certain time -> If `Hide Menu` option is on - you can show the menu with the alt key (or \` [backtick] if using the in-app-menu plugin) +> If `Hide Menu` option is on - you can show the menu with the alt key (or \` [backtick] if using +> the in-app-menu plugin) ## Themes @@ -136,8 +169,8 @@ Some predefined themes are available in https://github.com/kerichdev/themes-for- ```sh git clone https://github.com/th-ch/youtube-music cd youtube-music -yarn -yarn start +npm +npm run start ``` ## Build your own plugins @@ -155,7 +188,7 @@ Create a folder in `plugins/YOUR-PLUGIN-NAME`: ```node module.exports = win => { - // win is the BrowserWindow object + // win is the BrowserWindow object }; ``` @@ -163,8 +196,8 @@ module.exports = win => { ```node module.exports = () => { - // This function will be called as a preload script - // So you can use front features like `document.querySelector` + // This function will be called as a preload script + // So you can use front features like `document.querySelector` }; ``` @@ -174,11 +207,11 @@ module.exports = () => { ```node const path = require("path"); -const { injectCSS } = require("../utils"); +const {injectCSS} = require("../utils"); // back.js module.exports = win => { - injectCSS(win.webContents, path.join(__dirname, "style.css")); + injectCSS(win.webContents, path.join(__dirname, "style.css")); }; ``` @@ -187,28 +220,31 @@ module.exports = win => { ```node // front.js module.exports = () => { - // Remove the login button - document.querySelector(".sign-in-link.ytmusic-nav-bar").remove(); + // Remove the login button + document.querySelector(".sign-in-link.ytmusic-nav-bar").remove(); }; ``` -- communicating between the front and back: can be done using the ipcMain module from electron. See `utils.js` file and example in `navigation` plugin. +- communicating between the front and back: can be done using the ipcMain module from electron. See `utils.js` file and + example in `navigation` plugin. ## Build 1. Clone the repo -2. Run `yarn` to install dependencies -3. Run `yarn build:OS` - - `yarn build:win` - Windows - - `yarn build:linux` - Linux - - `yarn build:mac` - MacOS +2. Run `npm i` to install dependencies +3. Run `npm run build:OS` -Builds the app for macOS, Linux, and Windows, using [electron-builder](https://github.com/electron-userland/electron-builder). +- `npm run build:win` - Windows +- `npm run build:linux` - Linux +- `npm run build:mac` - MacOS + +Builds the app for macOS, Linux, and Windows, +using [electron-builder](https://github.com/electron-userland/electron-builder). ## Tests ```sh -yarn test +npm run test ``` Uses [Playwright](https://playwright.dev/) to test the app. diff --git a/reset.d.ts b/reset.d.ts new file mode 100644 index 00000000..b3b3d290 --- /dev/null +++ b/reset.d.ts @@ -0,0 +1,34 @@ +import '@total-typescript/ts-reset'; +import { YoutubePlayer } from './types/youtube-player'; + +declare global { + interface Compressor { + audioSource: MediaElementAudioSourceNode; + audioContext: AudioContext; + } + + interface DocumentEventMap { + 'apiLoaded': CustomEvent; + 'audioCanPlay': CustomEvent; + } + + interface Window { + /** + * YouTube Music internal variable (Last interaction time) + */ + _lact: number; + navigation: Navigation; + } +} + + // import { Howl as _Howl } from 'howler'; +declare module 'howler' { + interface Howl { + _sounds: { + _paused: boolean; + _ended: boolean; + _id: string; + _node: HTMLMediaElement; + }[]; + } +} diff --git a/tests/index.test.js b/tests/index.test.js index 162583aa..a08da6dc 100644 --- a/tests/index.test.js +++ b/tests/index.test.js @@ -1,38 +1,38 @@ -const path = require("path"); +const path = require('node:path'); -const { _electron: electron } = require("playwright"); -const { test, expect } = require("@playwright/test"); +const { _electron: electron } = require('playwright'); +const { test, expect } = require('@playwright/test'); -process.env.NODE_ENV = "test"; +process.env.NODE_ENV = 'test'; -const appPath = path.resolve(__dirname, ".."); +const appPath = path.resolve(__dirname, '..'); -test("YouTube Music App - With default settings, app is launched and visible", async () => { - const app = await electron.launch({ - cwd: appPath, - args: [ - appPath, - "--no-sandbox", - "--disable-gpu", - "--whitelisted-ips=", - "--disable-dev-shm-usage", - ], - }); +test('YouTube Music App - With default settings, app is launched and visible', async () => { + const app = await electron.launch({ + cwd: appPath, + args: [ + appPath, + '--no-sandbox', + '--disable-gpu', + '--whitelisted-ips=', + '--disable-dev-shm-usage', + ], + }); - const window = await app.firstWindow(); + const window = await app.firstWindow(); - const consentForm = await window.$( - "form[action='https://consent.youtube.com/save']" - ); - if (consentForm) { - await consentForm.click("button"); - } + const consentForm = await window.$( + "form[action='https://consent.youtube.com/save']", + ); + if (consentForm) { + await consentForm.click('button'); + } - const title = await window.title(); - expect(title.replace(/\s/g, " ")).toEqual("YouTube Music"); + const title = await window.title(); + expect(title.replaceAll(/\s/g, ' ')).toEqual('YouTube Music'); - const url = window.url(); - expect(url.startsWith("https://music.youtube.com")).toBe(true); + const url = window.url(); + expect(url.startsWith('https://music.youtube.com')).toBe(true); - await app.close(); + await app.close(); }); diff --git a/tray.js b/tray.js deleted file mode 100644 index 46b76f83..00000000 --- a/tray.js +++ /dev/null @@ -1,97 +0,0 @@ -const path = require("path"); - -const { Menu, nativeImage, Tray } = require("electron"); - -const { restart } = require("./providers/app-controls"); -const config = require("./config"); -const getSongControls = require("./providers/song-controls"); - -// Prevent tray being garbage collected - -/** @type {Electron.Tray} */ -let tray; - -module.exports.setTrayOnClick = (fn) => { - if (!tray) return; - tray.removeAllListeners('click'); - tray.on("click", fn); -}; - -// wont do anything on macos since its disabled -module.exports.setTrayOnDoubleClick = (fn) => { - if (!tray) return; - tray.removeAllListeners('double-click'); - tray.on("double-click", fn); -}; - -module.exports.setUpTray = (app, win) => { - if (!config.get("options.tray")) { - tray = undefined; - return; - } - - const { playPause, next, previous } = getSongControls(win); - const iconPath = path.join(__dirname, "assets", "youtube-music-tray.png"); - - let trayIcon = nativeImage.createFromPath(iconPath).resize({ - width: 16, - height: 16, - }); - - tray = new Tray(trayIcon); - - tray.setToolTip("YouTube Music"); - - // macOS only - tray.setIgnoreDoubleClickEvents(true); - - tray.on("click", () => { - if (config.get("options.trayClickPlayPause")) { - playPause(); - } else { - if (win.isVisible()) { - win.hide(); - app.dock?.hide(); - } else { - win.show(); - app.dock?.show(); - } - } - }); - - let template = [ - { - label: "Play/Pause", - click: () => { - playPause(); - }, - }, - { - label: "Next", - click: () => { - next(); - }, - }, - { - label: "Previous", - click: () => { - previous(); - }, - }, - { - label: "Show", - click: () => { - win.show(); - app.dock?.show(); - }, - }, - { - label: "Restart App", - click: restart - }, - { role: "quit" }, - ]; - - const trayMenu = Menu.buildFromTemplate(template); - tray.setContextMenu(trayMenu); -}; diff --git a/tray.ts b/tray.ts new file mode 100644 index 00000000..f7537057 --- /dev/null +++ b/tray.ts @@ -0,0 +1,103 @@ +import path from 'node:path'; + +import { Menu, nativeImage, Tray } from 'electron'; + +import { restart } from './providers/app-controls'; +import config from './config'; +import getSongControls from './providers/song-controls'; + +import type { MenuTemplate } from './menu'; + +// Prevent tray being garbage collected +let tray: Electron.Tray | undefined; + +type TrayEvent = (event: Electron.KeyboardEvent, bounds: Electron.Rectangle) => void; + +export const setTrayOnClick = (fn: TrayEvent) => { + if (!tray) { + return; + } + + tray.removeAllListeners('click'); + tray.on('click', fn); +}; + +// Won't do anything on macOS since its disabled +export const setTrayOnDoubleClick = (fn: TrayEvent) => { + if (!tray) { + return; + } + + tray.removeAllListeners('double-click'); + tray.on('double-click', fn); +}; + +export const setUpTray = (app: Electron.App, win: Electron.BrowserWindow) => { + if (!config.get('options.tray')) { + tray = undefined; + return; + } + + const { playPause, next, previous } = getSongControls(win); + const iconPath = path.join(__dirname, 'assets', 'youtube-music-tray.png'); + + const trayIcon = nativeImage.createFromPath(iconPath).resize({ + width: 16, + height: 16, + }); + + tray = new Tray(trayIcon); + + tray.setToolTip('YouTube Music'); + + // MacOS only + tray.setIgnoreDoubleClickEvents(true); + + tray.on('click', () => { + if (config.get('options.trayClickPlayPause')) { + playPause(); + } else if (win.isVisible()) { + win.hide(); + app.dock?.hide(); + } else { + win.show(); + app.dock?.show(); + } + }); + + const template: MenuTemplate = [ + { + label: 'Play/Pause', + click() { + playPause(); + }, + }, + { + label: 'Next', + click() { + next(); + }, + }, + { + label: 'Previous', + click() { + previous(); + }, + }, + { + label: 'Show', + click() { + win.show(); + app.dock?.show(); + }, + }, + { + label: 'Restart App', + click: restart, + }, + { role: 'quit' }, + ]; + + const trayMenu = Menu.buildFromTemplate(template); + tray.setContextMenu(trayMenu); +}; diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 00000000..a53e985a --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,24 @@ +{ + "compilerOptions": { + "target": "ESNext", + "lib": ["dom", "dom.iterable", "es2022"], + "module": "CommonJS", + "allowSyntheticDefaultImports": true, + "esModuleInterop": true, + "resolveJsonModule": true, + "moduleResolution": "node", + "baseUrl": ".", + "outDir": "./dist", + "strict": true, + "noImplicitAny": true, + "strictFunctionTypes": true, + "skipLibCheck": true + }, + "exclude": [ + "*.config.ts", + "./dist" + ], + "paths": { + "*": ["*.d.ts"] + } +} diff --git a/types/datahost-get-state.ts b/types/datahost-get-state.ts new file mode 100644 index 00000000..3f796f05 --- /dev/null +++ b/types/datahost-get-state.ts @@ -0,0 +1,1823 @@ +export interface GetState { + castStatus: CastStatus; + entities: Entities; + download: Download; + likeStatus: LikeStatus; + multiSelect: MultiSelect; + navigation: Navigation; + player: Player; + playerPage: PlayerPage; + queue: Queue; + subscribeStatus: SubscribeStatus; + toggleStates: ToggleStates; + ui: UI; + uploads: Uploads; +} + +export interface CastStatus { + castAvailable: boolean; + castConnectionData: CastConnectionData; + remoteWatchEndpoint: null; +} + +export interface CastConnectionData { + castConnectionState: string; + castReceiverName: string; +} + +export interface Download { + isLeaderTab: boolean; +} + +export interface Entities { +} + +export interface LikeStatus { + videos: Videos; + playlists: Entities; +} + +export interface Videos { + tNVTuUEeWP0: Kqp1PyPRBzA; + KQP1PyPrBzA: Kqp1PyPRBzA; + 'o1iz4L-5zkQ': Kqp1PyPRBzA; +} + +export enum Kqp1PyPRBzA { + Dislike = 'DISLIKE', + Indifferent = 'INDIFFERENT', + Like = 'LIKE', +} + +export interface MultiSelect { + multiSelectedItems: Entities; + latestMultiSelectIndex: number; + multiSelectParams: string; +} + +export interface Navigation { + artistDiscographyBrowseCommand: null; + isLoadingIndicatorShowing: boolean; + libraryTabBrowseCommand: null; + mainContent: MainContent; + playerUiState: string; + playerPageInfo: PlayerPageInfo; +} + +export interface MainContent { + endpoint: MainContentEndpoint; + response: Response; +} + +export interface MainContentEndpoint { + data: Data; + clickTrackingVe: TriggerElement; + createScreenConfig: null; + JSC$8515_innertubePath: string; +} + +export interface TriggerElement { + veData: VeData; + csn: string; +} + +export interface VeData { + veType: number; + veCounter: number; +} + +export interface Data { + query: string; + suggestStats: SuggestStats; +} + +export interface SuggestStats { + validationStatus: string; + parameterValidationStatus: string; + clientName: string; + searchMethod: string; + inputMethods: string[]; + originalQuery: string; + availableSuggestions: unknown[]; + zeroPrefixEnabled: boolean; + firstEditTimeMsec: number; + lastEditTimeMsec: number; +} + +export interface Response { + responseContext: ResponseResponseContext; + contents: ResponseContents; + trackingParams: string; +} + +export interface ResponseContents { + tabbedSearchResultsRenderer: TabbedSearchResultsRenderer; +} + +export interface TabbedSearchResultsRenderer { + tabs: TabbedSearchResultsRendererTab[]; +} + +export interface TabbedSearchResultsRendererTab { + tabRenderer: PurpleTabRenderer; +} + +export interface PurpleTabRenderer { + title: string; + selected?: boolean; + content: PurpleContent; + tabIdentifier: string; + trackingParams: string; + endpoint?: BottomEndpointClass; +} + +export interface PurpleContent { + sectionListRenderer: SectionListRenderer; +} + +export interface SectionListRenderer { + contents?: SectionListRendererContent[]; + trackingParams: string; + header?: SectionListRendererHeader; + continuations?: Continuation[]; +} + +export interface SectionListRendererContent { + musicCardShelfRenderer?: MusicCardShelfRenderer; + musicShelfRenderer?: MusicShelfRenderer; +} + +export interface MusicCardShelfRenderer { + trackingParams: string; + thumbnail: MusicResponsiveListItemRendererThumbnail; + title: Title; + subtitle: LongBylineText; + contents: MusicCardShelfRendererContent[]; + buttons: MusicCardShelfRendererButton[]; + menu: MusicCardShelfRendererMenu; + onTap: OnTap; + header: MusicCardShelfRendererHeader; + thumbnailOverlay: ThumbnailOverlayClass; +} + +export interface MusicCardShelfRendererButton { + buttonRenderer: ButtonButtonRenderer; +} + +export interface ButtonButtonRenderer { + style: string; + size?: string; + isDisabled?: boolean; + text: Subtitle; + icon: DefaultIconClass; + accessibility: AccessibilityDataAccessibility; + trackingParams: string; + accessibilityData: AccessibilityPauseDataClass; + command: ButtonRendererCommand; +} + +export interface AccessibilityDataAccessibility { + label: string; +} + +export interface AccessibilityPauseDataClass { + accessibilityData: AccessibilityDataAccessibility; +} + +export interface ButtonRendererCommand { + clickTrackingParams: string; + watchEndpoint?: CommandWatchEndpoint; + addToPlaylistEndpoint?: Target; +} + +export interface Target { + videoId: string; +} + +export interface CommandWatchEndpoint { + videoId: string; + params: PurpleParams; + watchEndpointMusicSupportedConfigs: PurpleWatchEndpointMusicSupportedConfigs; +} + +export enum PurpleParams { + WAEB = 'wAEB', +} + +export interface PurpleWatchEndpointMusicSupportedConfigs { + watchEndpointMusicConfig: PurpleWatchEndpointMusicConfig; +} + +export interface PurpleWatchEndpointMusicConfig { + musicVideoType: MusicVideoType; +} + +export enum MusicVideoType { + MusicVideoTypeAtv = 'MUSIC_VIDEO_TYPE_ATV', + MusicVideoTypeOmv = 'MUSIC_VIDEO_TYPE_OMV', + MusicVideoTypeUgc = 'MUSIC_VIDEO_TYPE_UGC', +} + +export interface DefaultIconClass { + iconType: IconType; +} + +export enum IconType { + AddToPlaylist = 'ADD_TO_PLAYLIST', + AddToRemoteQueue = 'ADD_TO_REMOTE_QUEUE', + Album = 'ALBUM', + Artist = 'ARTIST', + Favorite = 'FAVORITE', + Flag = 'FLAG', + LibraryAdd = 'LIBRARY_ADD', + LibrarySaved = 'LIBRARY_SAVED', + Mix = 'MIX', + MusicShuffle = 'MUSIC_SHUFFLE', + Pause = 'PAUSE', + PlayArrow = 'PLAY_ARROW', + PlaylistAdd = 'PLAYLIST_ADD', + QueuePlayNext = 'QUEUE_PLAY_NEXT', + Remove = 'REMOVE', + Share = 'SHARE', + Unfavorite = 'UNFAVORITE', + VolumeUp = 'VOLUME_UP', +} + +export interface Subtitle { + runs: ShortBylineTextRun[]; +} + +export interface ShortBylineTextRun { + text: string; +} + +export interface MusicCardShelfRendererContent { + messageRenderer?: MessageRenderer; + musicResponsiveListItemRenderer?: PurpleMusicResponsiveListItemRenderer; +} + +export interface MessageRenderer { + text: Subtitle; + trackingParams: string; + style: MessageRendererStyle; +} + +export interface MessageRendererStyle { + value: string; +} + +export interface PurpleMusicResponsiveListItemRenderer { + trackingParams: string; + thumbnail: MusicResponsiveListItemRendererThumbnail; + overlay: ThumbnailOverlayClass; + flexColumns: FlexColumn[]; + menu: PurpleMenu; + playlistItemData: Target; + flexColumnDisplayStyle: string; + itemHeight: string; +} + +export interface FlexColumn { + musicResponsiveListItemFlexColumnRenderer: MusicResponsiveListItemFlexColumnRenderer; +} + +export interface MusicResponsiveListItemFlexColumnRenderer { + text: Text; + displayPriority: DisplayPriority; +} + +export enum DisplayPriority { + MusicResponsiveListItemColumnDisplayPriorityHigh = 'MUSIC_RESPONSIVE_LIST_ITEM_COLUMN_DISPLAY_PRIORITY_HIGH', +} + +export interface Text { + runs: PurpleRun[]; +} + +export interface PurpleRun { + text: string; + navigationEndpoint?: PurpleNavigationEndpoint; +} + +export interface PurpleNavigationEndpoint { + clickTrackingParams: string; + watchEndpoint?: OnTapWatchEndpoint; + browseEndpoint?: PurpleBrowseEndpoint; +} + +export interface PurpleBrowseEndpoint { + browseId: string; + browseEndpointContextSupportedConfigs: BrowseEndpointContextSupportedConfigs; +} + +export interface BrowseEndpointContextSupportedConfigs { + browseEndpointContextMusicConfig: BrowseEndpointContextMusicConfig; +} + +export interface BrowseEndpointContextMusicConfig { + pageType: PageType; +} + +export enum PageType { + MusicPageTypeAlbum = 'MUSIC_PAGE_TYPE_ALBUM', + MusicPageTypeArtist = 'MUSIC_PAGE_TYPE_ARTIST', + MusicPageTypePlaylist = 'MUSIC_PAGE_TYPE_PLAYLIST', + MusicPageTypeTrackLyrics = 'MUSIC_PAGE_TYPE_TRACK_LYRICS', + MusicPageTypeTrackRelated = 'MUSIC_PAGE_TYPE_TRACK_RELATED', + MusicPageTypeUserChannel = 'MUSIC_PAGE_TYPE_USER_CHANNEL', +} + +export interface OnTapWatchEndpoint { + videoId: string; + watchEndpointMusicSupportedConfigs: PurpleWatchEndpointMusicSupportedConfigs; +} + +export interface PurpleMenu { + menuRenderer: PurpleMenuRenderer; +} + +export interface PurpleMenuRenderer { + items: PurpleItem[]; + trackingParams: string; + accessibility: AccessibilityPauseDataClass; +} + +export interface PurpleItem { + menuNavigationItemRenderer?: MenuItemRenderer; + menuServiceItemRenderer?: MenuItemRenderer; + toggleMenuServiceItemRenderer?: PurpleToggleMenuServiceItemRenderer; +} + +export interface MenuItemRenderer { + text: Subtitle; + icon: DefaultIconClass; + navigationEndpoint?: MenuNavigationItemRendererNavigationEndpoint; + trackingParams: string; + serviceEndpoint?: MenuNavigationItemRendererServiceEndpoint; +} + +export interface MenuNavigationItemRendererNavigationEndpoint { + clickTrackingParams: string; + watchEndpoint?: PurpleWatchEndpoint; + addToPlaylistEndpoint?: AddToPlaylistEndpoint; + browseEndpoint?: PurpleBrowseEndpoint; + shareEntityEndpoint?: ShareEntityEndpoint; + watchPlaylistEndpoint?: WatchPlaylistEndpoint; +} + +export interface AddToPlaylistEndpoint { + videoId?: string; + playlistId?: string; +} + +export interface ShareEntityEndpoint { + serializedShareEntity: string; + sharePanelType: SharePanelType; +} + +export enum SharePanelType { + SharePanelTypeUnifiedSharePanel = 'SHARE_PANEL_TYPE_UNIFIED_SHARE_PANEL', +} + +export interface PurpleWatchEndpoint { + videoId: string; + playlistId: string; + params: PurpleParams; + loggingContext: LoggingContext; + watchEndpointMusicSupportedConfigs: PurpleWatchEndpointMusicSupportedConfigs; +} + +export interface LoggingContext { + vssLoggingContext: VssLoggingContext; +} + +export interface VssLoggingContext { + serializedContextData: string; +} + +export interface WatchPlaylistEndpoint { + playlistId: string; + params: string; +} + +export interface MenuNavigationItemRendererServiceEndpoint { + clickTrackingParams: string; + queueAddEndpoint?: QueueAddEndpoint; + removeFromQueueEndpoint?: RemoveFromQueueEndpoint; + getReportFormEndpoint?: GetReportFormEndpoint; +} + +export interface GetReportFormEndpoint { + params: string; +} + +export interface QueueAddEndpoint { + queueTarget: AddToPlaylistEndpoint; + queueInsertPosition: QueueInsertPosition; + commands: CommandElement[]; +} + +export interface CommandElement { + clickTrackingParams: string; + addToToastAction: AddToToastAction; +} + +export interface AddToToastAction { + item: AddToToastActionItem; +} + +export interface AddToToastActionItem { + notificationTextRenderer: NotificationTextRenderer; +} + +export interface NotificationTextRenderer { + successResponseText: Subtitle; + trackingParams: string; +} + +export enum QueueInsertPosition { + InsertAfterCurrentVideo = 'INSERT_AFTER_CURRENT_VIDEO', + InsertAtEnd = 'INSERT_AT_END', +} + +export interface RemoveFromQueueEndpoint { + videoId: string; + commands: CommandElement[]; + itemId: string; +} + +export interface PurpleToggleMenuServiceItemRenderer { + defaultText: Subtitle; + defaultIcon: DefaultIconClass; + defaultServiceEndpoint: PurpleDefaultServiceEndpoint; + toggledText: Subtitle; + toggledIcon: DefaultIconClass; + toggledServiceEndpoint: PurpleToggledServiceEndpoint; + trackingParams: string; +} + +export interface PurpleDefaultServiceEndpoint { + clickTrackingParams: string; + feedbackEndpoint?: FeedbackEndpoint; + likeEndpoint?: PurpleLikeEndpoint; +} + +export interface FeedbackEndpoint { + feedbackToken: string; +} + +export interface PurpleLikeEndpoint { + status: Kqp1PyPRBzA; + target: Target; + actions?: LikeEndpointAction[]; +} + +export interface LikeEndpointAction { + clickTrackingParams: string; + musicLibraryStatusUpdateCommand: MusicLibraryStatusUpdateCommand; +} + +export interface MusicLibraryStatusUpdateCommand { + libraryStatus: string; + addToLibraryFeedbackToken: string; +} + +export interface PurpleToggledServiceEndpoint { + clickTrackingParams: string; + feedbackEndpoint?: FeedbackEndpoint; + likeEndpoint?: FluffyLikeEndpoint; +} + +export interface FluffyLikeEndpoint { + status: Kqp1PyPRBzA; + target: Target; +} + +export interface ThumbnailOverlayClass { + musicItemThumbnailOverlayRenderer: ThumbnailOverlayMusicItemThumbnailOverlayRenderer; +} + +export interface ThumbnailOverlayMusicItemThumbnailOverlayRenderer { + background: Background; + content: FluffyContent; + contentPosition: string; + displayStyle: string; +} + +export interface Background { + verticalGradient: VerticalGradient; +} + +export interface VerticalGradient { + gradientLayerColors: string[]; +} + +export interface FluffyContent { + musicPlayButtonRenderer: PurpleMusicPlayButtonRenderer; +} + +export interface PurpleMusicPlayButtonRenderer { + playNavigationEndpoint: OnTap; + trackingParams: string; + playIcon: DefaultIconClass; + pauseIcon: DefaultIconClass; + iconColor: number; + backgroundColor: number; + activeBackgroundColor: number; + loadingIndicatorColor: number; + playingIcon: DefaultIconClass; + iconLoadingColor: number; + activeScaleFactor: number; + buttonSize: string; + rippleTarget: string; + accessibilityPlayData: AccessibilityPauseDataClass; + accessibilityPauseData: AccessibilityPauseDataClass; +} + +export interface OnTap { + clickTrackingParams: string; + watchEndpoint: OnTapWatchEndpoint; +} + +export interface MusicResponsiveListItemRendererThumbnail { + musicThumbnailRenderer: MusicThumbnailRenderer; +} + +export interface MusicThumbnailRenderer { + thumbnail: ThumbnailDetailsClass; + thumbnailCrop: string; + thumbnailScale: string; + trackingParams: string; +} + +export interface ThumbnailDetailsClass { + thumbnails: ThumbnailElement[]; +} + +export interface ThumbnailElement { + url: string; + width: number; + height: number; +} + +export interface MusicCardShelfRendererHeader { + musicCardShelfHeaderBasicRenderer: MusicCardShelfHeaderBasicRenderer; +} + +export interface MusicCardShelfHeaderBasicRenderer { + title: Subtitle; + trackingParams: string; +} + +export interface MusicCardShelfRendererMenu { + menuRenderer: FluffyMenuRenderer; +} + +export interface FluffyMenuRenderer { + items: FluffyItem[]; + trackingParams: string; + accessibility: AccessibilityPauseDataClass; +} + +export interface FluffyItem { + menuNavigationItemRenderer?: MenuItemRenderer; + menuServiceItemRenderer?: MenuItemRenderer; + toggleMenuServiceItemRenderer?: FluffyToggleMenuServiceItemRenderer; +} + +export interface FluffyToggleMenuServiceItemRenderer { + defaultText: Subtitle; + defaultIcon: DefaultIconClass; + defaultServiceEndpoint: PurpleServiceEndpoint; + toggledText: Subtitle; + toggledIcon: DefaultIconClass; + toggledServiceEndpoint: PurpleServiceEndpoint; + trackingParams: string; +} + +export interface PurpleServiceEndpoint { + clickTrackingParams: string; + likeEndpoint: FluffyLikeEndpoint; +} + +export interface LongBylineText { + runs: LongBylineTextRun[]; +} + +export interface LongBylineTextRun { + text: string; + navigationEndpoint?: RunEndpoint; +} + +export interface RunEndpoint { + clickTrackingParams: string; + browseEndpoint: PurpleBrowseEndpoint; +} + +export interface Title { + runs: FluffyRun[]; +} + +export interface FluffyRun { + text: string; + navigationEndpoint: OnTap; +} + +export interface MusicShelfRenderer { + title: Subtitle; + contents: MusicShelfRendererContent[]; + trackingParams: string; + bottomText: Subtitle; + bottomEndpoint: BottomEndpointClass; + shelfDivider: ShelfDivider; +} + +export interface BottomEndpointClass { + clickTrackingParams: string; + searchEndpoint: SearchEndpoint; +} + +export interface SearchEndpoint { + query: string; + params: string; +} + +export interface MusicShelfRendererContent { + musicResponsiveListItemRenderer: FluffyMusicResponsiveListItemRenderer; +} + +export interface FluffyMusicResponsiveListItemRenderer { + trackingParams: string; + thumbnail: MusicResponsiveListItemRendererThumbnail; + overlay: PurpleOverlay; + flexColumns: FlexColumn[]; + menu: FluffyMenu; + playlistItemData?: Target; + flexColumnDisplayStyle: string; + itemHeight: string; + navigationEndpoint?: RunEndpoint; +} + +export interface FluffyMenu { + menuRenderer: TentacledMenuRenderer; +} + +export interface TentacledMenuRenderer { + items: TentacledItem[]; + trackingParams: string; + accessibility: AccessibilityPauseDataClass; +} + +export interface TentacledItem { + menuNavigationItemRenderer?: MenuItemRenderer; + menuServiceItemRenderer?: MenuItemRenderer; + toggleMenuServiceItemRenderer?: TentacledToggleMenuServiceItemRenderer; +} + +export interface TentacledToggleMenuServiceItemRenderer { + defaultText: Subtitle; + defaultIcon: DefaultIconClass; + defaultServiceEndpoint: FluffyDefaultServiceEndpoint; + toggledText: Subtitle; + toggledIcon: DefaultIconClass; + toggledServiceEndpoint: FluffyToggledServiceEndpoint; + trackingParams: string; +} + +export interface FluffyDefaultServiceEndpoint { + clickTrackingParams: string; + feedbackEndpoint?: FeedbackEndpoint; + likeEndpoint?: TentacledLikeEndpoint; +} + +export interface TentacledLikeEndpoint { + status: Kqp1PyPRBzA; + target: AddToPlaylistEndpoint; + actions?: LikeEndpointAction[]; +} + +export interface FluffyToggledServiceEndpoint { + clickTrackingParams: string; + feedbackEndpoint?: FeedbackEndpoint; + likeEndpoint?: StickyLikeEndpoint; +} + +export interface StickyLikeEndpoint { + status: Kqp1PyPRBzA; + target: AddToPlaylistEndpoint; +} + +export interface PurpleOverlay { + musicItemThumbnailOverlayRenderer: PurpleMusicItemThumbnailOverlayRenderer; +} + +export interface PurpleMusicItemThumbnailOverlayRenderer { + background: Background; + content: TentacledContent; + contentPosition: string; + displayStyle: string; +} + +export interface TentacledContent { + musicPlayButtonRenderer: FluffyMusicPlayButtonRenderer; +} + +export interface FluffyMusicPlayButtonRenderer { + playNavigationEndpoint: PlayNavigationEndpoint; + trackingParams: string; + playIcon: DefaultIconClass; + pauseIcon: DefaultIconClass; + iconColor: number; + backgroundColor: number; + activeBackgroundColor: number; + loadingIndicatorColor: number; + playingIcon: DefaultIconClass; + iconLoadingColor: number; + activeScaleFactor: number; + buttonSize: string; + rippleTarget: string; + accessibilityPlayData: AccessibilityPauseDataClass; + accessibilityPauseData: AccessibilityPauseDataClass; +} + +export interface PlayNavigationEndpoint { + clickTrackingParams: string; + watchEndpoint?: OnTapWatchEndpoint; + watchPlaylistEndpoint?: WatchPlaylistEndpoint; +} + +export interface ShelfDivider { + musicShelfDividerRenderer: MusicShelfDividerRenderer; +} + +export interface MusicShelfDividerRenderer { + hidden: boolean; +} + +export interface Continuation { + reloadContinuationData: ReloadContinuationData; +} + +export interface ReloadContinuationData { + continuation: string; + clickTrackingParams: string; +} + +export interface SectionListRendererHeader { + chipCloudRenderer: ChipCloudRenderer; +} + +export interface ChipCloudRenderer { + chips: ChipCloudRendererChip[]; + collapsedRowCount: number; + trackingParams: string; + horizontalScrollable: boolean; +} + +export interface ChipCloudRendererChip { + chipCloudChipRenderer: PurpleChipCloudChipRenderer; +} + +export interface PurpleChipCloudChipRenderer { + style: ChipCloudChipRendererStyle; + text: Subtitle; + navigationEndpoint: BottomEndpointClass; + trackingParams: string; + accessibilityData: AccessibilityPauseDataClass; + isSelected: boolean; + uniqueId: string; +} + +export interface ChipCloudChipRendererStyle { + styleType: string; +} + +export interface ResponseResponseContext { + serviceTrackingParams: ServiceTrackingParam[]; + maxAgeSeconds: number; +} + +export interface ServiceTrackingParam { + service: string; + params: Param[]; +} + +export interface Param { + key: string; + value: string; +} + +export interface PlayerPageInfo { + open: boolean; + triggerElement: TriggerElement; +} + +export interface Player { + adPlaying: boolean; + captionsAvailable: boolean; + captionsVisible: boolean; + fullscreened: boolean; + miniPlayerEnabled: boolean; + muted: boolean; + nerdStatsVisible: boolean; + playerResponse: PlayerResponse; + playerTriggerInfo: PlayerTriggerInfo; + preloadedEndpoint_: null; + volume: number; + playbackRate: number; +} + +export interface PlayerResponse { + responseContext: ResponseResponseContext; + playabilityStatus: PlayabilityStatus; + streamingData: StreamingData; + heartbeatParams: HeartbeatParams; + playbackTracking: PlaybackTracking; + captions: Captions; + videoDetails: PlayerResponseVideoDetails; + annotations: Annotation[]; + playerConfig: PlayerConfig; + storyboards: Storyboards; + microformat: Microformat; + trackingParams: string; + attestation: Attestation; + endscreen: Endscreen; + adBreakHeartbeatParams: string; +} + +export interface Annotation { + playerAnnotationsExpandedRenderer: PlayerAnnotationsExpandedRenderer; +} + +export interface PlayerAnnotationsExpandedRenderer { + featuredChannel: FeaturedChannel; + allowSwipeDismiss: boolean; +} + +export interface FeaturedChannel { + startTimeMs: string; + endTimeMs: string; + watermark: ThumbnailDetailsClass; + trackingParams: string; + navigationEndpoint: FeaturedChannelNavigationEndpoint; + channelName: string; + subscribeButton: SubscribeButtonClass; +} + +export interface FeaturedChannelNavigationEndpoint { + clickTrackingParams: string; + browseEndpoint: FluffyBrowseEndpoint; +} + +export interface FluffyBrowseEndpoint { + browseId: string; +} + +export interface SubscribeButtonClass { + subscribeButtonRenderer: SubscribeButtonRenderer; +} + +export interface SubscribeButtonRenderer { + buttonText: Subtitle; + subscribed: boolean; + enabled: boolean; + type: string; + channelId: string; + showPreferences: boolean; + subscribedButtonText: Subtitle; + unsubscribedButtonText: Subtitle; + trackingParams: string; + unsubscribeButtonText: Subtitle; + serviceEndpoints: SubscribeButtonRendererServiceEndpoint[]; +} + +export interface SubscribeButtonRendererServiceEndpoint { + clickTrackingParams: string; + subscribeEndpoint?: SubscribeEndpoint; + signalServiceEndpoint?: SignalServiceEndpoint; +} + +export interface SignalServiceEndpoint { + signal: string; + actions: SignalServiceEndpointAction[]; +} + +export interface SignalServiceEndpointAction { + clickTrackingParams: string; + openPopupAction: OpenPopupAction; +} + +export interface OpenPopupAction { + popup: Popup; + popupType: string; +} + +export interface Popup { + confirmDialogRenderer: ConfirmDialogRenderer; +} + +export interface ConfirmDialogRenderer { + trackingParams: string; + dialogMessages: Subtitle[]; + confirmButton: CancelButtonClass; + cancelButton: CancelButtonClass; +} + +export interface CancelButtonClass { + buttonRenderer: CancelButtonButtonRenderer; +} + +export interface CancelButtonButtonRenderer { + style: string; + isDisabled: boolean; + text: Subtitle; + accessibility?: AccessibilityDataAccessibility; + trackingParams: string; + serviceEndpoint?: UnsubscribeCommand; +} + +export interface UnsubscribeCommand { + clickTrackingParams: string; + unsubscribeEndpoint: SubscribeEndpoint; +} + +export interface SubscribeEndpoint { + channelIds: string[]; + params: string; +} + +export interface Attestation { + playerAttestationRenderer: PlayerAttestationRenderer; +} + +export interface PlayerAttestationRenderer { + challenge: string; + botguardData: BotguardData; +} + +export interface BotguardData { + program: string; + interpreterSafeUrl: InterpreterSafeURL; + serverEnvironment: number; +} + +export interface InterpreterSafeURL { + privateDoNotAccessOrElseTrustedResourceUrlWrappedValue: string; +} + +export interface Captions { + playerCaptionsTracklistRenderer: PlayerCaptionsTracklistRenderer; +} + +export interface PlayerCaptionsTracklistRenderer { + captionTracks: CaptionTrack[]; + audioTracks: AudioTrack[]; + translationLanguages: TranslationLanguage[]; + defaultAudioTrackIndex: number; +} + +export interface AudioTrack { + captionTrackIndices: number[]; + defaultCaptionTrackIndex: number; + visibility: string; + hasDefaultTrack: boolean; + captionsInitialState: string; +} + +export interface CaptionTrack { + baseUrl: string; + name: Subtitle; + vssId: string; + languageCode: string; + kind?: string; + isTranslatable: boolean; +} + +export interface TranslationLanguage { + languageCode: string; + languageName: Subtitle; +} + +export interface Endscreen { + endscreenRenderer: EndscreenRenderer; +} + +export interface EndscreenRenderer { + elements: Element[]; + startMs: string; + trackingParams: string; +} + +export interface Element { + endscreenElementRenderer: EndscreenElementRenderer; +} + +export interface EndscreenElementRenderer { + style: string; + image: ThumbnailDetailsClass; + icon?: EndscreenElementRendererIcon; + left: number; + width: number; + top: number; + aspectRatio: number; + startMs: string; + endMs: string; + title: LengthText; + metadata: Subtitle; + callToAction?: Subtitle; + dismiss?: Subtitle; + endpoint: EndscreenElementRendererEndpoint; + hovercardButton?: SubscribeButtonClass; + trackingParams: string; + isSubscribe?: boolean; + useClassicSubscribeButton?: boolean; + id: string; + thumbnailOverlays?: ThumbnailOverlay[]; +} + +export interface EndscreenElementRendererEndpoint { + clickTrackingParams: string; + browseEndpoint?: FluffyBrowseEndpoint; + commandMetadata?: Entities; + watchEndpoint?: Target; +} + +export interface EndscreenElementRendererIcon { + thumbnails: URLEndpoint[]; +} + +export interface URLEndpoint { + url: string; +} + +export interface ThumbnailOverlay { + thumbnailOverlayTimeStatusRenderer: ThumbnailOverlayTimeStatusRenderer; +} + +export interface ThumbnailOverlayTimeStatusRenderer { + text: LengthText; + style: string; +} + +export interface LengthText { + runs: ShortBylineTextRun[]; + accessibility: AccessibilityPauseDataClass; +} + +export interface HeartbeatParams { + heartbeatToken: string; + intervalMilliseconds: string; + maxRetries: string; + drmSessionId: string; + softFailOnError: boolean; + heartbeatServerData: string; +} + +export interface Microformat { + microformatDataRenderer: MicroformatDataRenderer; +} + +export interface MicroformatDataRenderer { + urlCanonical: string; + title: string; + description: string; + thumbnail: ThumbnailDetailsClass; + siteName: string; + appName: string; + androidPackage: string; + iosAppStoreId: string; + iosAppArguments: string; + ogType: string; + urlApplinksIos: string; + urlApplinksAndroid: string; + urlTwitterIos: string; + urlTwitterAndroid: string; + twitterCardType: string; + twitterSiteHandle: string; + schemaDotOrgType: string; + noindex: boolean; + unlisted: boolean; + paid: boolean; + familySafe: boolean; + tags: string[]; + availableCountries: string[]; + pageOwnerDetails: PageOwnerDetails; + videoDetails: MicroformatDataRendererVideoDetails; + linkAlternates: LinkAlternate[]; + viewCount: string; + publishDate: Date; + category: string; + uploadDate: Date; +} + +export interface LinkAlternate { + hrefUrl: string; + title?: string; + alternateType?: string; +} + +export interface PageOwnerDetails { + name: string; + externalChannelId: string; + youtubeProfileUrl: string; +} + +export interface MicroformatDataRendererVideoDetails { + externalVideoId: string; + durationSeconds: string; + durationIso8601: string; +} + +export interface PlayabilityStatus { + status: string; + playableInEmbed: boolean; + audioOnlyPlayability: AudioOnlyPlayability; + miniplayer: Miniplayer; + contextParams: string; +} + +export interface AudioOnlyPlayability { + audioOnlyPlayabilityRenderer: AudioOnlyPlayabilityRenderer; +} + +export interface AudioOnlyPlayabilityRenderer { + trackingParams: string; + audioOnlyAvailability: string; +} + +export interface Miniplayer { + miniplayerRenderer: MiniplayerRenderer; +} + +export interface MiniplayerRenderer { + playbackMode: string; +} + +export interface PlaybackTracking { + videostatsPlaybackUrl: PtrackingURLClass; + videostatsDelayplayUrl: AtrURLClass; + videostatsWatchtimeUrl: PtrackingURLClass; + ptrackingUrl: PtrackingURLClass; + qoeUrl: PtrackingURLClass; + atrUrl: AtrURLClass; + videostatsScheduledFlushWalltimeSeconds: number[]; + videostatsDefaultFlushIntervalSeconds: number; + googleRemarketingUrl: AtrURLClass; +} + +export interface AtrURLClass { + baseUrl: string; + elapsedMediaTimeSeconds: number; + headers: HeaderElement[]; +} + +export interface HeaderElement { + headerType: HeaderType; +} + +export enum HeaderType { + PlusPageID = 'PLUS_PAGE_ID', + UserAuth = 'USER_AUTH', + VisitorID = 'VISITOR_ID', +} + +export interface PtrackingURLClass { + baseUrl: string; + headers: HeaderElement[]; +} + +export interface PlayerConfig { + audioConfig: AudioConfig; + streamSelectionConfig: StreamSelectionConfig; + mediaCommonConfig: MediaCommonConfig; + webPlayerConfig: WebPlayerConfig; +} + +export interface AudioConfig { + loudnessDb: number; + perceptualLoudnessDb: number; + enablePerFormatLoudness: boolean; +} + +export interface MediaCommonConfig { + dynamicReadaheadConfig: DynamicReadaheadConfig; +} + +export interface DynamicReadaheadConfig { + maxReadAheadMediaTimeMs: number; + minReadAheadMediaTimeMs: number; + readAheadGrowthRateMs: number; +} + +export interface StreamSelectionConfig { + maxBitrate: string; +} + +export interface WebPlayerConfig { + useCobaltTvosDash: boolean; + webPlayerActionsPorting: WebPlayerActionsPorting; + gatewayExperimentGroup: string; +} + +export interface WebPlayerActionsPorting { + subscribeCommand: SubscribeCommand; + unsubscribeCommand: UnsubscribeCommand; + addToWatchLaterCommand: AddToWatchLaterCommand; + removeFromWatchLaterCommand: RemoveFromWatchLaterCommand; +} + +export interface AddToWatchLaterCommand { + clickTrackingParams: string; + playlistEditEndpoint: AddToWatchLaterCommandPlaylistEditEndpoint; +} + +export interface AddToWatchLaterCommandPlaylistEditEndpoint { + playlistId: string; + actions: PurpleAction[]; +} + +export interface PurpleAction { + addedVideoId: string; + action: string; +} + +export interface RemoveFromWatchLaterCommand { + clickTrackingParams: string; + playlistEditEndpoint: RemoveFromWatchLaterCommandPlaylistEditEndpoint; +} + +export interface RemoveFromWatchLaterCommandPlaylistEditEndpoint { + playlistId: string; + actions: FluffyAction[]; +} + +export interface FluffyAction { + action: string; + removedVideoId: string; +} + +export interface SubscribeCommand { + clickTrackingParams: string; + subscribeEndpoint: SubscribeEndpoint; +} + +export interface Storyboards { + playerStoryboardSpecRenderer: PlayerStoryboardSpecRenderer; +} + +export interface PlayerStoryboardSpecRenderer { + spec: string; + recommendedLevel: number; +} + +export interface StreamingData { + expiresInSeconds: string; + formats: Format[]; + adaptiveFormats: AdaptiveFormat[]; + probeUrl: string; +} + +export interface AdaptiveFormat { + itag: number; + mimeType: string; + bitrate: number; + width?: number; + height?: number; + initRange: Range; + indexRange: Range; + lastModified: string; + contentLength: string; + quality: string; + fps?: number; + qualityLabel?: string; + projectionType: ProjectionType; + averageBitrate: number; + approxDurationMs: string; + signatureCipher: string; + colorInfo?: ColorInfo; + highReplication?: boolean; + audioQuality?: string; + audioSampleRate?: string; + audioChannels?: number; + loudnessDb?: number; +} + +export interface ColorInfo { + primaries: string; + transferCharacteristics: string; + matrixCoefficients: string; +} + +export interface Range { + start: string; + end: string; +} + +export enum ProjectionType { + Rectangular = 'RECTANGULAR', +} + +export interface Format { + itag: number; + mimeType: string; + bitrate: number; + width: number; + height: number; + lastModified: string; + quality: string; + fps: number; + qualityLabel: string; + projectionType: ProjectionType; + audioQuality: string; + approxDurationMs: string; + audioSampleRate: string; + audioChannels: number; + signatureCipher: string; +} + +export interface PlayerResponseVideoDetails { + videoId: string; + title: string; + lengthSeconds: string; + channelId: string; + isOwnerViewing: boolean; + isCrawlable: boolean; + thumbnail: ThumbnailDetailsClass; + allowRatings: boolean; + viewCount: string; + author: string; + isPrivate: boolean; + isUnpluggedCorpus: boolean; + musicVideoType: MusicVideoType; + isLiveContent: boolean; + elapsedSeconds: number; + isPaused: boolean; +} + +export interface PlayerTriggerInfo { + screenLayer: number; +} + +export interface PlayerPage { + playerOverlay: PlayerOverlay; + playerPageTabs: PlayerPageTabElement[]; + playerPageTabsContent: Entities; + playerPageTabSelectedIndex: number; + playerPageWatchNextAutomixParams: string; + playerPageWatchNextContinuationParams: string; + playerPageWatchNextMetadata: null; + playerPageWatchNextResponse: PlayerPageWatchNextResponse; + watchNextOverlay: null; +} + +export interface PlayerOverlay { + playerOverlayRenderer: PlayerOverlayRenderer; +} + +export interface PlayerOverlayRenderer { + actions: PlayerOverlayRendererAction[]; + browserMediaSession: BrowserMediaSession; +} + +export interface PlayerOverlayRendererAction { + likeButtonRenderer: LikeButtonRenderer; +} + +export interface LikeButtonRenderer { + target: Target; + likeStatus: Kqp1PyPRBzA; + trackingParams: string; + likesAllowed: boolean; + serviceEndpoints: ServiceEndpoint[]; +} + +export interface ServiceEndpoint { + clickTrackingParams: string; + likeEndpoint: ServiceEndpointLikeEndpoint; +} + +export interface ServiceEndpointLikeEndpoint { + status: Kqp1PyPRBzA; + target: Target; + likeParams?: LikeParams; + dislikeParams?: LikeParams; + removeLikeParams?: LikeParams; +} + +export enum LikeParams { + Oai3D = 'OAI%3D', +} + +export interface BrowserMediaSession { + browserMediaSessionRenderer: BrowserMediaSessionRenderer; +} + +export interface BrowserMediaSessionRenderer { + thumbnailDetails: ThumbnailDetailsClass; +} + +export interface PlayerPageTabElement { + tabRenderer: PlayerPageTabTabRenderer; +} + +export interface PlayerPageTabTabRenderer { + title: string; + content?: StickyContent; + trackingParams: string; + endpoint?: RunEndpoint; + unselectable?: boolean; +} + +export interface StickyContent { + musicQueueRenderer: MusicQueueRenderer; +} + +export interface MusicQueueRenderer { + hack: boolean; +} + +export interface PlayerPageWatchNextResponse { + responseContext: PlayerPageWatchNextResponseResponseContext; + contents: PlayerPageWatchNextResponseContents; + currentVideoEndpoint: CurrentVideoEndpoint; + trackingParams: string; + playerOverlays: PlayerOverlay; + videoReporting: VideoReporting; +} + +export interface PlayerPageWatchNextResponseContents { + singleColumnMusicWatchNextResultsRenderer: SingleColumnMusicWatchNextResultsRenderer; +} + +export interface SingleColumnMusicWatchNextResultsRenderer { + tabbedRenderer: TabbedRenderer; +} + +export interface TabbedRenderer { + watchNextTabbedResultsRenderer: WatchNextTabbedResultsRenderer; +} + +export interface WatchNextTabbedResultsRenderer { + tabs: PlayerPageTabElement[]; +} + +export interface CurrentVideoEndpoint { + clickTrackingParams: string; + watchEndpoint: CurrentVideoEndpointWatchEndpoint; +} + +export interface CurrentVideoEndpointWatchEndpoint { + videoId: string; + playlistId: PlaylistID; + index: number; + playlistSetVideoId: string; + loggingContext: LoggingContext; +} + +export enum PlaylistID { + RDAMVMrkaNKAvksDE = 'RDAMVMrkaNKAvksDE', +} + +export interface PlayerPageWatchNextResponseResponseContext { + serviceTrackingParams: ServiceTrackingParam[]; +} + +export interface VideoReporting { + reportFormModalRenderer: ReportFormModalRenderer; +} + +export interface ReportFormModalRenderer { + optionsSupportedRenderers: OptionsSupportedRenderers; + trackingParams: string; + title: Subtitle; + submitButton: CancelButtonClass; + cancelButton: CancelButtonClass; + footer: Footer; +} + +export interface Footer { + runs: FooterRun[]; +} + +export interface FooterRun { + text: string; + navigationEndpoint?: FluffyNavigationEndpoint; +} + +export interface FluffyNavigationEndpoint { + clickTrackingParams: string; + urlEndpoint: URLEndpoint; +} + +export interface OptionsSupportedRenderers { + optionsRenderer: OptionsRenderer; +} + +export interface OptionsRenderer { + items: OptionsRendererItem[]; + trackingParams: string; +} + +export interface OptionsRendererItem { + optionSelectableItemRenderer: OptionSelectableItemRenderer; +} + +export interface OptionSelectableItemRenderer { + text: Subtitle; + trackingParams: string; + submitEndpoint: SubmitEndpoint; +} + +export interface SubmitEndpoint { + clickTrackingParams: string; + flagEndpoint: FlagEndpoint; +} + +export interface FlagEndpoint { + flagAction: string; +} + +export interface Queue { + automixItems: unknown[]; + autoplay: boolean; + hasShownAutoplay: boolean; + hasUserChangedDefaultAutoplayMode: boolean; + header: QueueHeader; + impressedVideoIds: Entities; + isFetchingChipSteer: boolean; + isGenerating: boolean; + isInfinite: boolean; + isPrefetchingContinuations: boolean; + isRaarEnabled: boolean; + isRaarSkip: boolean; + items: QueueItem[]; + nextQueueItemId: number; + playbackContentMode: string; + queueContextParams: string; + repeatMode: string; + responsiveSignals: ResponsiveSignals; + selectedItemIndex: number; + shuffleEnabled: boolean; + shuffleEndpoints: null; + steeringChips: SteeringChips; + watchNextType: null; +} + +export interface QueueHeader { + title: Subtitle; + subtitle: Subtitle; + buttons: HeaderButton[]; + trackingParams: string; +} + +export interface HeaderButton { + chipCloudChipRenderer: ButtonChipCloudChipRenderer; +} + +export interface ButtonChipCloudChipRenderer { + style: ChipCloudChipRendererStyle; + text: Subtitle; + navigationEndpoint: TentacledNavigationEndpoint; + trackingParams: string; + icon: DefaultIconClass; + accessibilityData: AccessibilityPauseDataClass; + isSelected: boolean; + uniqueId: string; +} + +export interface TentacledNavigationEndpoint { + clickTrackingParams: string; + saveQueueToPlaylistCommand: Entities; +} + +export interface QueueItem { + playlistPanelVideoWrapperRenderer?: PlaylistPanelVideoWrapperRenderer; + playlistPanelVideoRenderer?: ItemPlaylistPanelVideoRenderer; +} + +export interface ItemPlaylistPanelVideoRenderer { + title: Subtitle; + longBylineText: LongBylineText; + thumbnail: ThumbnailDetailsClass; + lengthText: LengthText; + selected: boolean; + navigationEndpoint: PlaylistPanelVideoRendererNavigationEndpoint; + videoId: string; + shortBylineText: Subtitle; + trackingParams: string; + menu: TentacledMenu; + playlistSetVideoId?: string; + canReorder: boolean; +} + +export interface TentacledMenu { + menuRenderer: StickyMenuRenderer; +} + +export interface StickyMenuRenderer { + items: StickyItem[]; + trackingParams: string; + accessibility: AccessibilityPauseDataClass; +} + +export interface StickyItem { + menuNavigationItemRenderer?: MenuItemRenderer; + menuServiceItemRenderer?: MenuItemRenderer; + toggleMenuServiceItemRenderer?: StickyToggleMenuServiceItemRenderer; +} + +export interface StickyToggleMenuServiceItemRenderer { + defaultText: Subtitle; + defaultIcon: DefaultIconClass; + defaultServiceEndpoint: ServiceEndpoint; + toggledText: Subtitle; + toggledIcon: DefaultIconClass; + toggledServiceEndpoint: ServiceEndpoint; + trackingParams: string; +} + +export interface PlaylistPanelVideoRendererNavigationEndpoint { + clickTrackingParams: string; + watchEndpoint: FluffyWatchEndpoint; +} + +export interface FluffyWatchEndpoint { + videoId: string; + playlistId?: PlaylistID; + index: number; + params: FluffyParams; + playerParams?: PlayerParams; + playlistSetVideoId?: string; + loggingContext?: LoggingContext; + watchEndpointMusicSupportedConfigs: FluffyWatchEndpointMusicSupportedConfigs; +} + +export enum FluffyParams { + OAHyAQIIAQ3D3D = 'OAHyAQIIAQ%3D%3D', +} + +export enum PlayerParams { + The8Aub = '8AUB', +} + +export interface FluffyWatchEndpointMusicSupportedConfigs { + watchEndpointMusicConfig: FluffyWatchEndpointMusicConfig; +} + +export interface FluffyWatchEndpointMusicConfig { + hasPersistentPlaylistPanel: boolean; + musicVideoType: MusicVideoType; +} + +export interface PlaylistPanelVideoWrapperRenderer { + primaryRenderer: PrimaryRenderer; + counterpart: Counterpart[]; +} + +export interface Counterpart { + counterpartRenderer: CounterpartRenderer; + segmentMap: SegmentMap; +} + +export interface CounterpartRenderer { + playlistPanelVideoRenderer: CounterpartRendererPlaylistPanelVideoRenderer; +} + +export interface CounterpartRendererPlaylistPanelVideoRenderer { + title: Subtitle; + longBylineText: LongBylineText; + thumbnail: ThumbnailDetailsClass; + lengthText: LengthText; + selected: boolean; + navigationEndpoint: PlaylistPanelVideoRendererNavigationEndpoint; + videoId: string; + shortBylineText: Subtitle; + trackingParams: string; + menu: StickyMenu; + playlistSetVideoId?: string; + canReorder: boolean; +} + +export interface StickyMenu { + menuRenderer: IndigoMenuRenderer; +} + +export interface IndigoMenuRenderer { + items: IndigoItem[]; + trackingParams: string; + accessibility: AccessibilityPauseDataClass; +} + +export interface IndigoItem { + menuNavigationItemRenderer?: MenuItemRenderer; + menuServiceItemRenderer?: MenuItemRenderer; + toggleMenuServiceItemRenderer?: IndigoToggleMenuServiceItemRenderer; +} + +export interface IndigoToggleMenuServiceItemRenderer { + defaultText: Subtitle; + defaultIcon: DefaultIconClass; + defaultServiceEndpoint: FluffyServiceEndpoint; + toggledText: Subtitle; + toggledIcon: DefaultIconClass; + toggledServiceEndpoint: FluffyServiceEndpoint; + trackingParams: string; +} + +export interface FluffyServiceEndpoint { + clickTrackingParams: string; + likeEndpoint?: ServiceEndpointLikeEndpoint; + feedbackEndpoint?: FeedbackEndpoint; +} + +export interface SegmentMap { + segment: Segment[]; +} + +export interface Segment { + primaryVideoStartTimeMilliseconds: string; + counterpartVideoStartTimeMilliseconds: string; + durationMilliseconds: string; +} + +export interface PrimaryRenderer { + playlistPanelVideoRenderer: ItemPlaylistPanelVideoRenderer; +} + +export interface ResponsiveSignals { + videoInteraction: VideoInteraction[]; +} + +export interface VideoInteraction { + queueImpress?: Entities; + videoId: string; + queueIndex: number; + playbackSkip?: Entities; +} + +export interface SteeringChips { + chips: SteeringChipsChip[]; + trackingParams: string; +} + +export interface SteeringChipsChip { + chipCloudChipRenderer: FluffyChipCloudChipRenderer; +} + +export interface FluffyChipCloudChipRenderer { + text: Subtitle; + navigationEndpoint: StickyNavigationEndpoint; + trackingParams: string; + accessibilityData: AccessibilityPauseDataClass; + isSelected: boolean; + uniqueId: string; +} + +export interface StickyNavigationEndpoint { + clickTrackingParams: string; + queueUpdateCommand: QueueUpdateCommand; +} + +export interface QueueUpdateCommand { + queueUpdateSection: QueueUpdateSection; + fetchContentsCommand: FetchContentsCommand; + dedupeAgainstLocalQueue: boolean; +} + +export interface FetchContentsCommand { + clickTrackingParams: string; + watchEndpoint: FetchContentsCommandWatchEndpoint; +} + +export interface FetchContentsCommandWatchEndpoint { + playlistId: string; + params: string; + loggingContext: LoggingContext; + index: number; +} + +export enum QueueUpdateSection { + QueueUpdateSectionQueue = 'QUEUE_UPDATE_SECTION_QUEUE', +} + +export interface SubscribeStatus { + subscribeStatusByChannelId: Entities; +} + +export interface ToggleStates { + feedbackToggleStates: Entities; +} + +export interface UI { + viewportInfo: ViewportInfo; + isGuideCollapsed: boolean; +} + +export interface ViewportInfo { + size: number; + fluid: boolean; +} + +export interface Uploads { + fileUploads: unknown[]; +} diff --git a/types/get-player-response.ts b/types/get-player-response.ts new file mode 100644 index 00000000..3a195500 --- /dev/null +++ b/types/get-player-response.ts @@ -0,0 +1,464 @@ +export interface GetPlayerResponse { + responseContext: ResponseContext; + playabilityStatus: PlayabilityStatus; + streamingData: StreamingData; + heartbeatParams: HeartbeatParams; + playbackTracking: PlaybackTracking; + captions: Captions; + videoDetails: GetPlayerResponseVideoDetails; + playerConfig: PlayerConfig; + storyboards: Storyboards; + microformat: Microformat; + trackingParams: string; + attestation: Attestation; + endscreen: Endscreen; + adBreakHeartbeatParams: string; +} + +export interface Attestation { + playerAttestationRenderer: PlayerAttestationRenderer; +} + +export interface PlayerAttestationRenderer { + challenge: string; + botguardData: BotguardData; +} + +export interface BotguardData { + program: string; + interpreterSafeUrl: InterpreterSafeURL; + serverEnvironment: number; +} + +export interface InterpreterSafeURL { + privateDoNotAccessOrElseTrustedResourceUrlWrappedValue: string; +} + +export interface Captions { + playerCaptionsTracklistRenderer: PlayerCaptionsTracklistRenderer; +} + +export interface PlayerCaptionsTracklistRenderer { + captionTracks: CaptionTrack[]; + audioTracks: AudioTrack[]; + translationLanguages: TranslationLanguage[]; + defaultAudioTrackIndex: number; +} + +export interface AudioTrack { + captionTrackIndices: number[]; +} + +export interface CaptionTrack { + baseUrl: string; + name: Name; + vssId: string; + languageCode: string; + kind: string; + isTranslatable: boolean; +} + +export interface Name { + runs: Run[]; +} + +export interface Run { + text: string; +} + +export interface TranslationLanguage { + languageCode: string; + languageName: Name; +} + +export interface Endscreen { + endscreenRenderer: EndscreenRenderer; +} + +export interface EndscreenRenderer { + elements: Element[]; + startMs: string; + trackingParams: string; +} + +export interface Element { + endscreenElementRenderer: EndscreenElementRenderer; +} + +export interface EndscreenElementRenderer { + style: string; + image: ImageClass; + left: number; + width: number; + top: number; + aspectRatio: number; + startMs: string; + endMs: string; + title: Title; + metadata: Name; + endpoint: Endpoint; + trackingParams: string; + id: string; + thumbnailOverlays: ThumbnailOverlay[]; +} + +export interface Endpoint { + clickTrackingParams: string; + commandMetadata: CommandMetadata; + watchEndpoint: WatchEndpoint; +} + +export interface CommandMetadata { +} + +export interface WatchEndpoint { + videoId: string; +} + +export interface ImageClass { + thumbnails: ThumbnailElement[]; +} + +export interface ThumbnailElement { + url: string; + width: number; + height: number; +} + +export interface ThumbnailOverlay { + thumbnailOverlayTimeStatusRenderer: ThumbnailOverlayTimeStatusRenderer; +} + +export interface ThumbnailOverlayTimeStatusRenderer { + text: Title; + style: string; +} + +export interface Title { + runs: Run[]; + accessibility: Accessibility; +} + +export interface Accessibility { + accessibilityData: AccessibilityData; +} + +export interface AccessibilityData { + label: string; +} + +export interface HeartbeatParams { + heartbeatToken: string; + intervalMilliseconds: string; + maxRetries: string; + drmSessionId: string; + softFailOnError: boolean; + heartbeatServerData: string; +} + +export interface Microformat { + microformatDataRenderer: MicroformatDataRenderer; +} + +export interface MicroformatDataRenderer { + urlCanonical: string; + title: string; + description: string; + thumbnail: ImageClass; + siteName: string; + appName: string; + androidPackage: string; + iosAppStoreId: string; + iosAppArguments: string; + ogType: string; + urlApplinksIos: string; + urlApplinksAndroid: string; + urlTwitterIos: string; + urlTwitterAndroid: string; + twitterCardType: string; + twitterSiteHandle: string; + schemaDotOrgType: string; + noindex: boolean; + unlisted: boolean; + paid: boolean; + familySafe: boolean; + tags: string[]; + availableCountries: string[]; + pageOwnerDetails: PageOwnerDetails; + videoDetails: MicroformatDataRendererVideoDetails; + linkAlternates: LinkAlternate[]; + viewCount: string; + publishDate: string; + category: string; + uploadDate: string; +} + +export interface LinkAlternate { + hrefUrl: string; + title?: string; + alternateType?: string; +} + +export interface PageOwnerDetails { + name: string; + externalChannelId: string; + youtubeProfileUrl: string; +} + +export interface MicroformatDataRendererVideoDetails { + externalVideoId: string; + durationSeconds: string; + durationIso8601: string; +} + +export interface PlayabilityStatus { + status: string; + playableInEmbed: boolean; + audioOnlyPlayability: AudioOnlyPlayability; + miniplayer: Miniplayer; + contextParams: string; +} + +export interface AudioOnlyPlayability { + audioOnlyPlayabilityRenderer: AudioOnlyPlayabilityRenderer; +} + +export interface AudioOnlyPlayabilityRenderer { + trackingParams: string; + audioOnlyAvailability: string; +} + +export interface Miniplayer { + miniplayerRenderer: MiniplayerRenderer; +} + +export interface MiniplayerRenderer { + playbackMode: string; +} + +export interface PlaybackTracking { + videostatsPlaybackUrl: PtrackingURLClass; + videostatsDelayplayUrl: AtrURLClass; + videostatsWatchtimeUrl: PtrackingURLClass; + ptrackingUrl: PtrackingURLClass; + qoeUrl: PtrackingURLClass; + atrUrl: AtrURLClass; + videostatsScheduledFlushWalltimeSeconds: number[]; + videostatsDefaultFlushIntervalSeconds: number; + googleRemarketingUrl: AtrURLClass; +} + +export interface AtrURLClass { + baseUrl: string; + elapsedMediaTimeSeconds: number; + headers: Header[]; +} + +export interface Header { + headerType: HeaderType; +} + +export enum HeaderType { + PlusPageID = 'PLUS_PAGE_ID', + UserAuth = 'USER_AUTH', + VisitorID = 'VISITOR_ID', +} + +export interface PtrackingURLClass { + baseUrl: string; + headers: Header[]; +} + +export interface PlayerConfig { + audioConfig: AudioConfig; + streamSelectionConfig: StreamSelectionConfig; + mediaCommonConfig: MediaCommonConfig; + webPlayerConfig: WebPlayerConfig; +} + +export interface AudioConfig { + loudnessDb: number; + perceptualLoudnessDb: number; + enablePerFormatLoudness: boolean; +} + +export interface MediaCommonConfig { + dynamicReadaheadConfig: DynamicReadaheadConfig; +} + +export interface DynamicReadaheadConfig { + maxReadAheadMediaTimeMs: number; + minReadAheadMediaTimeMs: number; + readAheadGrowthRateMs: number; +} + +export interface StreamSelectionConfig { + maxBitrate: string; +} + +export interface WebPlayerConfig { + useCobaltTvosDash: boolean; + webPlayerActionsPorting: WebPlayerActionsPorting; + gatewayExperimentGroup: string; +} + +export interface WebPlayerActionsPorting { + subscribeCommand: SubscribeCommand; + unsubscribeCommand: UnsubscribeCommand; + addToWatchLaterCommand: AddToWatchLaterCommand; + removeFromWatchLaterCommand: RemoveFromWatchLaterCommand; +} + +export interface AddToWatchLaterCommand { + clickTrackingParams: string; + playlistEditEndpoint: AddToWatchLaterCommandPlaylistEditEndpoint; +} + +export interface AddToWatchLaterCommandPlaylistEditEndpoint { + playlistId: string; + actions: PurpleAction[]; +} + +export interface PurpleAction { + addedVideoId: string; + action: string; +} + +export interface RemoveFromWatchLaterCommand { + clickTrackingParams: string; + playlistEditEndpoint: RemoveFromWatchLaterCommandPlaylistEditEndpoint; +} + +export interface RemoveFromWatchLaterCommandPlaylistEditEndpoint { + playlistId: string; + actions: FluffyAction[]; +} + +export interface FluffyAction { + action: string; + removedVideoId: string; +} + +export interface SubscribeCommand { + clickTrackingParams: string; + subscribeEndpoint: SubscribeEndpoint; +} + +export interface SubscribeEndpoint { + channelIds: string[]; + params: string; +} + +export interface UnsubscribeCommand { + clickTrackingParams: string; + unsubscribeEndpoint: SubscribeEndpoint; +} + +export interface ResponseContext { + serviceTrackingParams: ServiceTrackingParam[]; + maxAgeSeconds: number; +} + +export interface ServiceTrackingParam { + service: string; + params: Param[]; +} + +export interface Param { + key: string; + value: string; +} + +export interface Storyboards { + playerStoryboardSpecRenderer: PlayerStoryboardSpecRenderer; +} + +export interface PlayerStoryboardSpecRenderer { + spec: string; + recommendedLevel: number; +} + +export interface StreamingData { + expiresInSeconds: string; + formats: Format[]; + adaptiveFormats: AdaptiveFormat[]; +} + +export interface AdaptiveFormat { + itag: number; + mimeType: string; + bitrate: number; + width?: number; + height?: number; + initRange: Range; + indexRange: Range; + lastModified: string; + contentLength: string; + quality: string; + fps?: number; + qualityLabel?: string; + projectionType: ProjectionType; + averageBitrate: number; + approxDurationMs: string; + signatureCipher: string; + colorInfo?: ColorInfo; + highReplication?: boolean; + audioQuality?: string; + audioSampleRate?: string; + audioChannels?: number; + loudnessDb?: number; +} + +export interface ColorInfo { + primaries: string; + transferCharacteristics: string; +} + +export interface Range { + start: string; + end: string; +} + +export enum ProjectionType { + Rectangular = 'RECTANGULAR', +} + +export interface Format { + itag: number; + mimeType: string; + bitrate: number; + width: number; + height: number; + lastModified: string; + quality: string; + fps: number; + qualityLabel: string; + projectionType: ProjectionType; + audioQuality: string; + approxDurationMs: string; + audioSampleRate: string; + audioChannels: number; + signatureCipher: string; +} + +export interface GetPlayerResponseVideoDetails { + videoId: string; + title: string; + lengthSeconds: string; + channelId: string; + isOwnerViewing: boolean; + isCrawlable: boolean; + thumbnail: ImageClass; + allowRatings: boolean; + viewCount: string; + author: string; + isPrivate: boolean; + isUnpluggedCorpus: boolean; + musicVideoType: string; + isLiveContent: boolean; + elapsedSeconds: number; + isPaused: boolean; + + // youtube-music only + album?: string | null; +} diff --git a/types/player-api-events.ts b/types/player-api-events.ts new file mode 100644 index 00000000..af05c82b --- /dev/null +++ b/types/player-api-events.ts @@ -0,0 +1,15 @@ +export interface PlayerAPIEvents { + videodatachange: { + value: Record & { + videoId: string + title: string + author: string + + playlistId: string + isUpcoming: boolean + loading: boolean + + lengthSeconds: number + } + } & ({ name: 'dataloaded' } | { name: 'dataupdated ' }) +} diff --git a/types/video-details.ts b/types/video-details.ts new file mode 100644 index 00000000..97ab3fc3 --- /dev/null +++ b/types/video-details.ts @@ -0,0 +1,25 @@ +export interface VideoDetails { + video_id: string; + author: string; + title: string; + isPlayable: boolean; + errorCode: null; + video_quality: string; + video_quality_features: unknown[]; + list: string; + backgroundable: boolean; + eventId: string; + cpn: string; + isLive: boolean; + isWindowedLive: boolean; + isManifestless: boolean; + allowLiveDvr: boolean; + isListed: boolean; + isMultiChannelAudio: boolean; + hasProgressBarBoundaries: boolean; + isPremiere: boolean; + itct: string; + progressBarStartPositionUtcTimeMillis: number | null; + progressBarEndPositionUtcTimeMillis: number | null; + paidContentOverlayDurationMs: number; +} diff --git a/types/youtube-player.ts b/types/youtube-player.ts new file mode 100644 index 00000000..c5ee1173 --- /dev/null +++ b/types/youtube-player.ts @@ -0,0 +1,225 @@ +// TODO: fully type definitions for youtube-player + +import { VideoDetails } from './video-details'; +import { GetPlayerResponse } from './get-player-response'; +import { PlayerAPIEvents } from './player-api-events'; + +export interface YoutubePlayer { + getInternalApiInterface: (...params: Parameters) => Return; + getApiInterface: (...params: Parameters) => Return; + cueVideoByPlayerVars: () => void; + loadVideoByPlayerVars: () => void; + preloadVideoByPlayerVars: (...params: Parameters) => Return; + getAdState: (...params: Parameters) => Return; + sendAbandonmentPing: (...params: Parameters) => Return; + setLoopRange: (...params: Parameters) => Return; + getLoopRange: (...params: Parameters) => Return; + setAutonavState: (...params: Parameters) => Return; + seekToLiveHead: (...params: Parameters) => Return; + requestSeekToWallTimeSeconds: (...params: Parameters) => Return; + seekToStreamTime: (...params: Parameters) => Return; + startSeekCsiAction: (...params: Parameters) => Return; + getStreamTimeOffset: (...params: Parameters) => Return; + getVideoData: () => VideoDetails; + setInlinePreview: (...params: Parameters) => Return; + updateDownloadState: (...params: Parameters) => Return; + queueOfflineAction: (...params: Parameters) => Return; + pauseVideoDownload: (...params: Parameters) => Return; + resumeVideoDownload: (...params: Parameters) => Return; + refreshAllStaleEntities: (...params: Parameters) => Return; + isOrchestrationLeader: (...params: Parameters) => Return; + getAppState: (...params: Parameters) => Return; + updateLastActiveTime: (...params: Parameters) => Return; + setBlackout: (...params: Parameters) => Return; + setUserEngagement: (...params: Parameters) => Return; + updateSubtitlesUserSettings: (...params: Parameters) => Return; + getPresentingPlayerType: (...params: Parameters) => Return; + canPlayType: (...params: Parameters) => Return; + updatePlaylist: (...params: Parameters) => Return; + updateVideoData: (...params: Parameters) => Return; + updateEnvironmentData: (...params: Parameters) => Return; + sendVideoStatsEngageEvent: (...params: Parameters) => Return; + productsInVideoVisibilityUpdated: (...params: Parameters) => Return; + setSafetyMode: (...params: Parameters) => Return; + isAtLiveHead: (...params: Parameters) => Return; + getVideoAspectRatio: (...params: Parameters) => Return; + getPreferredQuality: (...params: Parameters) => Return; + getPlaybackQualityLabel: (...params: Parameters) => Return; + setPlaybackQualityRange: (quality: string) => void; + onAdUxClicked: (...params: Parameters) => Return; + getFeedbackProductData: (...params: Parameters) => Return; + getStoryboardFrame: (...params: Parameters) => Return; + getStoryboardFrameIndex: (...params: Parameters) => Return; + getStoryboardLevel: (...params: Parameters) => Return; + getNumberOfStoryboardLevels: (...params: Parameters) => Return; + getCaptionWindowContainerId: (...params: Parameters) => Return; + getAvailableQualityLabels: () => string[]; + addUtcCueRange: (...params: Parameters) => Return; + showAirplayPicker: (...params: Parameters) => Return; + dispatchReduxAction: (...params: Parameters) => Return; + getPlayerResponse: () => GetPlayerResponse; + getHeartbeatResponse: (...params: Parameters) => Return; + changeMarkerVisibility: (...params: Parameters) => Return; + setAutonav: (...params: Parameters) => Return; + isNotServable: (...params: Parameters) => Return; + channelSubscribed: (...params: Parameters) => Return; + channelUnsubscribed: (...params: Parameters) => Return; + togglePictureInPicture: (...params: Parameters) => Return; + supportsGaplessAudio: () => boolean; + supportsGaplessShorts: () => boolean; + enqueueVideoByPlayerVars: (...params: Parameters) => Return; + clearQueue: (...params: Parameters) => Return; + getAudioTrack: (...params: Parameters) => Return; + setAudioTrack: (...params: Parameters) => Return; + getAvailableAudioTracks: (...params: Parameters) => Return; + getMaxPlaybackQuality: (...params: Parameters) => Return; + getUserPlaybackQualityPreference: (...params: Parameters) => Return; + getSubtitlesUserSettings: (...params: Parameters) => Return; + resetSubtitlesUserSettings: (...params: Parameters) => Return; + setMinimized: (...params: Parameters) => Return; + setOverlayVisibility: (...params: Parameters) => Return; + confirmYpcRental: (...params: Parameters) => Return; + toggleSubtitlesOn: (...params: Parameters) => Return; + isSubtitlesOn: (...params: Parameters) => Return; + queueNextVideo: (...params: Parameters) => Return; + handleExternalCall: (...params: Parameters) => Return; + logApiCall: (...params: Parameters) => Return; + isExternalMethodAvailable: (...params: Parameters) => Return; + setScreenLayer: (...params: Parameters) => Return; + getCurrentPlaylistSequence: (...params: Parameters) => Return; + getPlaylistSequenceForTime: (...params: Parameters) => Return; + shouldSendVisibilityState: (...params: Parameters) => Return; + syncVolume: (...params: Parameters) => Return; + highlightSettingsMenuItem: (...params: Parameters) => Return; + openSettingsMenuItem: (...params: Parameters) => Return; + getVisibilityState: (...params: Parameters) => Return; + isMutedByMutedAutoplay: (...params: Parameters) => Return; + setGlobalCrop: (...params: Parameters) => Return; + setInternalSize: (...params: Parameters) => Return; + seekBy: (seconds: number) => void; + showControls: () => void; + hideControls: () => void; + cancelPlayback: () => void; + getProgressState: () => Return; + isInline: () => boolean; + setInline: (isInline: boolean) => void; + setLoopVideo: (value: boolean) => void; + getLoopVideo: () => boolean; + getVideoContentRect: () => Return; + getVideoStats: () => Return; + getStoryboardFormat: () => Return; + toggleFullscreen: () => Return; + isFullscreen: () => boolean; + getPlayerSize: () => Return; + toggleSubtitles: () => void; + setCenterCrop: (param: Parameter) => void; + setFauxFullscreen: (param: Parameter) => void; + setSizeStyle: (params: Parameter) => void; + handleGlobalKeyDown: () => void; + handleGlobalKeyUp: () => void; + wakeUpControls: () => void; + cueVideoById: (videoId: string) => void; + loadVideoById: (videoId: string) => void; + cueVideoByUrl: (...params: Parameters) => Return; + loadVideoByUrl: (...params: Parameters) => Return; + /** + * Note: This doesn't resume playback, it plays from the start. + */ + playVideo: () => void; + pauseVideo: () => void; + stopVideo: () => void; + clearVideo: () => void; + getVideoBytesLoaded: () => number; + getVideoBytesTotal: () => number; + getVideoLoadedFraction: () => number; + getVideoStartBytes: () => number; + cuePlaylist: () => void; + loadPlaylist: () => void; + nextVideo: () => void; + previousVideo: () => void; + playVideoAt: () => void; + setShuffle: (param: Parameter) => void; + setLoop: (param: Parameter) => void; + getPlaylist: () => Return; + getPlaylistIndex: () => number; + getPlaylistId: () => string | undefined; + loadModule: (moduleName: string) => void; + unloadModule: (moduleName: string) => void; + setOption: (optionName: string, key: string, value: T) => void; + getOption: (optionName: string, key: string) => T | null | undefined; + getOptions: () => string[]; + mute: () => void; + unMute: () => void; + isMuted: () => boolean; + /** + * @param volume 0-100 + */ + setVolume: (volume: number) => void; + getVolume: () => number; + seekTo: (seconds: number) => void; + getPlayerMode: () => Return; + getPlayerState: () => number; + getAvailablePlaybackRates: () => number[]; + getPlaybackQuality: () => string; + setPlaybackQuality: (quality: string) => void; + getAvailableQualityLevels: () => string[]; + /** + * @return float between start and end in seconds + */ + getCurrentTime: () => number; + /** + * @return int song duration in seconds + */ + getDuration: () => number; + addEventListener: ( + type: K, + listener: ( + this: Document, + name: PlayerAPIEvents[K]['name'], + data: PlayerAPIEvents[K]['value'] + ) => void, + options?: boolean | AddEventListenerOptions | undefined, + ) => void; + removeEventListener: ( + type: K, + listener: ( + this: Document, + name: PlayerAPIEvents[K]['name'], + data: PlayerAPIEvents[K]['value'] + ) => void, + options?: boolean | EventListenerOptions | undefined, + ) => void; + getDebugText: () => string; + addCueRange: (...params: Parameters) => Return; + removeCueRange: (...params: Parameters) => Return; + setSize: (size: { width: number; height: number }) => void; + destroy: (...params: Parameters) => Return; + getSphericalProperties: () => Return; + setSphericalProperties: (param: Parameter) => void; + mutedAutoplay: () => void; + /** + * @return string HTMLIFrameElement + */ + getVideoEmbedCode: () => string; + /** + * @return string full URL of the video (include playlist id) + */ + getVideoUrl: () => string; + getMediaReferenceTime: () => number; + getSize: () => { width: number; height: number }; + logImaAdEvent: (...params: Parameters) => Return; + preloadVideoById: (...params: Parameters) => Return; + setAccountLinkState: (...params: Parameters) => Return; + updateAccountLinkingConfig: (...params: Parameters) => Return; + getAvailableQualityData: (...params: Parameters) => Return; + setCompositeParam: (...params: Parameters) => Return; + getStatsForNerds: (...params: Parameters) => Return; + showVideoInfo: () => void; + hideVideoInfo: () => void; + isVideoInfoVisible: () => boolean; + getPlaybackRate: () => number; + setPlaybackRate: (playbackRate: number) => void; + updateFullerscreenEduButtonSubtleModeState: (...params: Parameters) => Return; + updateFullerscreenEduButtonVisibility: (...params: Parameters) => Return; + addEmbedsConversionTrackingParams: (...params: Parameters) => Return; +} diff --git a/utils/generate-package-json.js b/utils/generate-package-json.js index bcda791f..7c424d69 100755 --- a/utils/generate-package-json.js +++ b/utils/generate-package-json.js @@ -1,42 +1,42 @@ #!/usr/bin/env node -const { existsSync, writeFile } = require("fs"); -const { join } = require("path"); -const { promisify } = require("util"); +const { existsSync, writeFile } = require('node:fs'); +const { join } = require('node:path'); +const { promisify } = require('node:util'); /** * Generates a fake package.json for given packages that don't have any. * Allows electron-builder to resolve them */ -const generatePackageJson = async packageName => { - const packageFolder = join("node_modules", packageName) - if (!existsSync(packageFolder )) { - console.log( - `${packageName} module not found, exiting…` - ); - return - } +const generatePackageJson = async (packageName) => { + const packageFolder = join('node_modules', packageName); + if (!existsSync(packageFolder)) { + console.log( + `${packageName} module not found, exiting…`, + ); + return; + } - const filepath = join(packageFolder, "package.json"); - if (!existsSync(filepath)) { - console.log( - `No package.json found for ${packageName} module, generating one…` - ); - pkg = { - name: packageName, - version: "0.0.0", - description: "-", - repository: { type: "git", url: "-" }, - readme: "-" - }; - const writeFileAsync = promisify(writeFile); - await writeFileAsync(filepath, JSON.stringify(pkg, null, 2)); - } + const filepath = join(packageFolder, 'package.json'); + if (!existsSync(filepath)) { + console.log( + `No package.json found for ${packageName} module, generating one…`, + ); + let pkg = { + name: packageName, + version: '0.0.0', + description: '-', + repository: { type: 'git', url: '-' }, + readme: '-', + }; + const writeFileAsync = promisify(writeFile); + await writeFileAsync(filepath, JSON.stringify(pkg, null, 2)); + } }; if (require.main === module) { - process.argv.slice(2).forEach(async packageName => { - await generatePackageJson(packageName); - }); + process.argv.slice(2).forEach(async (packageName) => { + await generatePackageJson(packageName); + }); } diff --git a/utils/testing.js b/utils/testing.js deleted file mode 100644 index 4e7037a9..00000000 --- a/utils/testing.js +++ /dev/null @@ -1,3 +0,0 @@ -const isTesting = () => process.env.NODE_ENV === "test"; - -module.exports = { isTesting }; diff --git a/utils/testing.ts b/utils/testing.ts new file mode 100644 index 00000000..42c31f28 --- /dev/null +++ b/utils/testing.ts @@ -0,0 +1,3 @@ +export const isTesting = () => process.env.NODE_ENV === 'test'; + +export default { isTesting }; diff --git a/utils/type-utils.ts b/utils/type-utils.ts new file mode 100644 index 00000000..36f281b4 --- /dev/null +++ b/utils/type-utils.ts @@ -0,0 +1,5 @@ +export type Entries = { + [K in keyof T]: [K, T[K]]; +}[keyof T][]; + +export type ValueOf = T[keyof T]; diff --git a/web/youtube-music.svg b/web/youtube-music.svg index 1e6ea723..a4d00070 100644 --- a/web/youtube-music.svg +++ b/web/youtube-music.svg @@ -1,379 +1,381 @@ - -
- -
-
-

YouTube Music Desktop App

-

With built-in ad blocker

-

And built-in downloader

-

Cross-platform

-

- Free, - Open source -

- - Download - -
-
-
-
+ color: #cc0000; + text-shadow: 0px 0px 1px #fff; + transform: scale(1); + } + 100% { + opacity: 0; + text-shadow: 0px 0px 50px #fff; + transform: scale(0); + } + } + @keyframes blurFadeIn { + 0% { + opacity: 0; + color: #cc0000; + text-shadow: 0px 0px 40px #fff; + transform: scale(1.3); + } + 50% { + opacity: 0.5; + color: #cc0000; + text-shadow: 0px 0px 10px #fff; + transform: scale(1.1); + } + 100% { + opacity: 1; + text-shadow: 0px 0px 1px #fff; + transform: scale(1); + } + } + @keyframes fadeInBack { + 0% { + opacity: 0; + transform: scale(0); + } + 50% { + opacity: 0.4; + transform: scale(2); + } + 100% { + opacity: 0.2; + transform: scale(5); + } + } + @keyframes fadeInRotate { + 0% { + opacity: 0; + transform: scale(0) rotate(360deg); + } + 100% { + opacity: 1; + transform: scale(1) rotate(0deg); + } + } + +
+
+

YouTube Music Desktop App

+

With built-in ad blocker

+

And built-in downloader

+

Cross-platform

+

+ Free, + Open source +

+ + Download + +
+
+ + diff --git a/yarn.lock b/yarn.lock deleted file mode 100644 index f41f2856..00000000 --- a/yarn.lock +++ /dev/null @@ -1,7389 +0,0 @@ -# This file is generated by running "yarn install" inside your project. -# Manual changes might be lost - proceed with caution! - -__metadata: - version: 6 - cacheKey: 8 - -"7zip-bin@npm:~5.1.1": - version: 5.1.1 - resolution: "7zip-bin@npm:5.1.1" - checksum: 1e58ba3742ac86daa84d2e60c46fd545f235c9f60a00cd36a87a70bf824cc0c821fdc418994f1745081b17e7bc83d155e1e82bd44b06996e7cab0a491ce644c1 - languageName: node - linkType: hard - -"@babel/code-frame@npm:^7.0.0": - version: 7.21.4 - resolution: "@babel/code-frame@npm:7.21.4" - dependencies: - "@babel/highlight": ^7.18.6 - checksum: e5390e6ec1ac58dcef01d4f18eaf1fd2f1325528661ff6d4a5de8979588b9f5a8e852a54a91b923846f7a5c681b217f0a45c2524eb9560553160cd963b7d592c - languageName: node - linkType: hard - -"@babel/helper-validator-identifier@npm:^7.18.6, @babel/helper-validator-identifier@npm:^7.19.1": - version: 7.19.1 - resolution: "@babel/helper-validator-identifier@npm:7.19.1" - checksum: 0eca5e86a729162af569b46c6c41a63e18b43dbe09fda1d2a3c8924f7d617116af39cac5e4cd5d431bb760b4dca3c0970e0c444789b1db42bcf1fa41fbad0a3a - languageName: node - linkType: hard - -"@babel/highlight@npm:^7.18.6": - version: 7.18.6 - resolution: "@babel/highlight@npm:7.18.6" - dependencies: - "@babel/helper-validator-identifier": ^7.18.6 - chalk: ^2.0.0 - js-tokens: ^4.0.0 - checksum: 92d8ee61549de5ff5120e945e774728e5ccd57fd3b2ed6eace020ec744823d4a98e242be1453d21764a30a14769ecd62170fba28539b211799bbaf232bbb2789 - languageName: node - linkType: hard - -"@babel/runtime@npm:^7.0.0": - version: 7.21.0 - resolution: "@babel/runtime@npm:7.21.0" - dependencies: - regenerator-runtime: ^0.13.11 - checksum: 7b33e25bfa9e0e1b9e8828bb61b2d32bdd46b41b07ba7cb43319ad08efc6fda8eb89445193e67d6541814627df0ca59122c0ea795e412b99c5183a0540d338ab - languageName: node - linkType: hard - -"@cliqz/adblocker-content@npm:^1.26.5": - version: 1.26.5 - resolution: "@cliqz/adblocker-content@npm:1.26.5" - dependencies: - "@cliqz/adblocker-extended-selectors": ^1.26.5 - checksum: 8d95320ee0ddbc52a2580fa20ee71b4b5f41c40455c06a00fc2e396000f508ee5484e5ccded7d615aec482941ee1838361abfd977d9d4d566b58edff7ccde664 - languageName: node - linkType: hard - -"@cliqz/adblocker-electron-preload@npm:^1.26.5": - version: 1.26.5 - resolution: "@cliqz/adblocker-electron-preload@npm:1.26.5" - dependencies: - "@cliqz/adblocker-content": ^1.26.5 - peerDependencies: - electron: ">11" - checksum: 932798b8078f8cc7546f331f99902ee5152a0732542e5ce18397e4aa4e3c88f8d2fb42532b90fffe48c896682069928746cbcfb37560c9f57ac4c4bd935bc2bd - languageName: node - linkType: hard - -"@cliqz/adblocker-electron@npm:^1.26.5": - version: 1.26.5 - resolution: "@cliqz/adblocker-electron@npm:1.26.5" - dependencies: - "@cliqz/adblocker": ^1.26.5 - "@cliqz/adblocker-electron-preload": ^1.26.5 - tldts-experimental: ^5.6.21 - peerDependencies: - electron: ">11" - checksum: 666f562a5745cf0e54b26253d6c9506a049c9a84a8a1002d3027a951bf195f094f7d506997872e0774dc4b6bc5b7b1a02db0c1aa9c44219ead283e0b90394d3c - languageName: node - linkType: hard - -"@cliqz/adblocker-extended-selectors@npm:^1.26.5": - version: 1.26.5 - resolution: "@cliqz/adblocker-extended-selectors@npm:1.26.5" - checksum: 8c48e2fc52c20e9411298035b2a51de5a03fea09dec650e54f7471a4034f36841ab03caa0e762805e4c8c389c98b8b398d6b948569424cb0b1a540f738c80d99 - languageName: node - linkType: hard - -"@cliqz/adblocker@npm:^1.26.5": - version: 1.26.5 - resolution: "@cliqz/adblocker@npm:1.26.5" - dependencies: - "@cliqz/adblocker-content": ^1.26.5 - "@cliqz/adblocker-extended-selectors": ^1.26.5 - "@remusao/guess-url-type": ^1.1.2 - "@remusao/small": ^1.1.2 - "@remusao/smaz": ^1.7.1 - "@types/chrome": ^0.0.225 - "@types/firefox-webext-browser": ^111.0.0 - tldts-experimental: ^5.6.21 - checksum: 2c1ef4a0947fb137edcbefd219d28f86515968884280939986aafecf4ebc926a43bb52099994935336349fc9a80a22f5477919ed46350820f4d0fb914b769f23 - languageName: node - linkType: hard - -"@develar/schema-utils@npm:~2.6.5": - version: 2.6.5 - resolution: "@develar/schema-utils@npm:2.6.5" - dependencies: - ajv: ^6.12.0 - ajv-keywords: ^3.4.1 - checksum: e1c3771af7fb934a0a985c31b901ece41a3015ef352b58e8e1c4bce691fe5792ebb65712e43ec70fa91a8fa0c929ccacf6b52c8f8de0fd83681db2cbeb62d143 - languageName: node - linkType: hard - -"@electron/asar@npm:^3.2.1": - version: 3.2.4 - resolution: "@electron/asar@npm:3.2.4" - dependencies: - chromium-pickle-js: ^0.2.0 - commander: ^5.0.0 - glob: ^7.1.6 - minimatch: ^3.0.4 - bin: - asar: bin/asar.js - checksum: 06e3e8fe7c894f7e7727410af5a9957ec77088f775b22441acf4ef718a9e6642a4dc1672f77ee1ce325fc367c8d59ac1e02f7db07869c8ced8a00132a3b54643 - languageName: node - linkType: hard - -"@electron/get@npm:^2.0.0": - version: 2.0.2 - resolution: "@electron/get@npm:2.0.2" - dependencies: - debug: ^4.1.1 - env-paths: ^2.2.0 - fs-extra: ^8.1.0 - global-agent: ^3.0.0 - got: ^11.8.5 - progress: ^2.0.3 - semver: ^6.2.0 - sumchecker: ^3.0.1 - dependenciesMeta: - global-agent: - optional: true - checksum: 900845cc0b31b54761fc9b0ada2dea1e999e59aacc48999d53903bcb7c9a0a7356b5fe736cf610b2a56c5a21f5a3c0e083b2ed2b7e52c36a4d0f420d4b5ec268 - languageName: node - linkType: hard - -"@electron/universal@npm:^1.3.4": - version: 1.3.4 - resolution: "@electron/universal@npm:1.3.4" - dependencies: - "@electron/asar": ^3.2.1 - "@malept/cross-spawn-promise": ^1.1.0 - debug: ^4.3.1 - dir-compare: ^3.0.0 - fs-extra: ^9.0.1 - minimatch: ^3.0.4 - plist: ^3.0.4 - checksum: 2abc051d9ad3faa87406a72829817dc8d432018ad19cde021b265947e2733190ef7024d50e80690f2bfbcde363332dc3ff6c366ecc6d30e63a826e4c2cf6728a - languageName: node - linkType: hard - -"@eslint-community/eslint-utils@npm:^4.2.0": - version: 4.4.0 - resolution: "@eslint-community/eslint-utils@npm:4.4.0" - dependencies: - eslint-visitor-keys: ^3.3.0 - peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 - checksum: cdfe3ae42b4f572cbfb46d20edafe6f36fc5fb52bf2d90875c58aefe226892b9677fef60820e2832caf864a326fe4fc225714c46e8389ccca04d5f9288aabd22 - languageName: node - linkType: hard - -"@eslint-community/regexpp@npm:^4.4.0": - version: 4.5.0 - resolution: "@eslint-community/regexpp@npm:4.5.0" - checksum: 99c01335947dbd7f2129e954413067e217ccaa4e219fe0917b7d2bd96135789384b8fedbfb8eb09584d5130b27a7b876a7150ab7376f51b3a0c377d5ce026a10 - languageName: node - linkType: hard - -"@eslint/eslintrc@npm:^1.3.3": - version: 1.4.1 - resolution: "@eslint/eslintrc@npm:1.4.1" - dependencies: - ajv: ^6.12.4 - debug: ^4.3.2 - espree: ^9.4.0 - globals: ^13.19.0 - ignore: ^5.2.0 - import-fresh: ^3.2.1 - js-yaml: ^4.1.0 - minimatch: ^3.1.2 - strip-json-comments: ^3.1.1 - checksum: cd3e5a8683db604739938b1c1c8b77927dc04fce3e28e0c88e7f2cd4900b89466baf83dfbad76b2b9e4d2746abdd00dd3f9da544d3e311633d8693f327d04cd7 - languageName: node - linkType: hard - -"@eslint/eslintrc@npm:^2.0.2": - version: 2.0.2 - resolution: "@eslint/eslintrc@npm:2.0.2" - dependencies: - ajv: ^6.12.4 - debug: ^4.3.2 - espree: ^9.5.1 - globals: ^13.19.0 - ignore: ^5.2.0 - import-fresh: ^3.2.1 - js-yaml: ^4.1.0 - minimatch: ^3.1.2 - strip-json-comments: ^3.1.1 - checksum: cfcf5e12c7b2c4476482e7f12434e76eae16fcd163ee627309adb10b761e5caa4a4e52ed7be464423320ff3d11eca5b50de5bf8be3e25834222470835dd5c801 - languageName: node - linkType: hard - -"@eslint/js@npm:8.38.0": - version: 8.38.0 - resolution: "@eslint/js@npm:8.38.0" - checksum: 1f28987aa8c9cd93e23384e16c7220863b39b5dc4b66e46d7cdbccce868040f455a98d24cd8b567a884f26545a0555b761f7328d4a00c051e7ef689cbea5fce1 - languageName: node - linkType: hard - -"@ffmpeg/core@npm:^0.11.0": - version: 0.11.0 - resolution: "@ffmpeg/core@npm:0.11.0" - checksum: 79c9431ad15d847dc1e8d70ddffec00a16fdb0d2027523ceef212ffcb115b3de766d2209dde74aaa381f1e2a3b60acd0062ac966957321acc195460b8342d7dd - languageName: node - linkType: hard - -"@ffmpeg/ffmpeg@npm:^0.11.6": - version: 0.11.6 - resolution: "@ffmpeg/ffmpeg@npm:0.11.6" - dependencies: - is-url: ^1.2.4 - node-fetch: ^2.6.1 - regenerator-runtime: ^0.13.7 - resolve-url: ^0.2.1 - checksum: 496950c148dd16154f127106ddb533c4c84252abba875bc00c8cb1dabfaa21ba030b4fda954b7ec583b1af17fc362216d7a0c8a8ab5d346f871425cfaf392dfd - languageName: node - linkType: hard - -"@foobar404/wave@npm:^2.0.4": - version: 2.0.4 - resolution: "@foobar404/wave@npm:2.0.4" - checksum: f20c774db383af2a8acae1f3928c3a0e0f3b5e80268a73eb9b7b72b02ab726f1e9db1a407257fc28c4771f969c6784b6cba9f60acd344a3f3a8d0f389657b6fc - languageName: node - linkType: hard - -"@gar/promisify@npm:^1.1.3": - version: 1.1.3 - resolution: "@gar/promisify@npm:1.1.3" - checksum: 4059f790e2d07bf3c3ff3e0fec0daa8144fe35c1f6e0111c9921bd32106adaa97a4ab096ad7dab1e28ee6a9060083c4d1a4ada42a7f5f3f7a96b8812e2b757c1 - languageName: node - linkType: hard - -"@humanwhocodes/config-array@npm:^0.11.8": - version: 0.11.8 - resolution: "@humanwhocodes/config-array@npm:0.11.8" - dependencies: - "@humanwhocodes/object-schema": ^1.2.1 - debug: ^4.1.1 - minimatch: ^3.0.5 - checksum: 0fd6b3c54f1674ce0a224df09b9c2f9846d20b9e54fabae1281ecfc04f2e6ad69bf19e1d6af6a28f88e8aa3990168b6cb9e1ef755868c3256a630605ec2cb1d3 - languageName: node - linkType: hard - -"@humanwhocodes/module-importer@npm:^1.0.1": - version: 1.0.1 - resolution: "@humanwhocodes/module-importer@npm:1.0.1" - checksum: 0fd22007db8034a2cdf2c764b140d37d9020bbfce8a49d3ec5c05290e77d4b0263b1b972b752df8c89e5eaa94073408f2b7d977aed131faf6cf396ebb5d7fb61 - languageName: node - linkType: hard - -"@humanwhocodes/object-schema@npm:^1.2.1": - version: 1.2.1 - resolution: "@humanwhocodes/object-schema@npm:1.2.1" - checksum: a824a1ec31591231e4bad5787641f59e9633827d0a2eaae131a288d33c9ef0290bd16fda8da6f7c0fcb014147865d12118df10db57f27f41e20da92369fcb3f1 - languageName: node - linkType: hard - -"@malept/cross-spawn-promise@npm:^1.1.0": - version: 1.1.1 - resolution: "@malept/cross-spawn-promise@npm:1.1.1" - dependencies: - cross-spawn: ^7.0.1 - checksum: 1aa468f9ff3aa59dbaa720731ddf9c1928228b6844358d8821b86628953e0608420e88c6366d85af35acad73b1addaa472026a1836ad3fec34813eb38b2bd25a - languageName: node - linkType: hard - -"@malept/flatpak-bundler@npm:^0.4.0": - version: 0.4.0 - resolution: "@malept/flatpak-bundler@npm:0.4.0" - dependencies: - debug: ^4.1.1 - fs-extra: ^9.0.0 - lodash: ^4.17.15 - tmp-promise: ^3.0.2 - checksum: 12527e42c2865504eb2a91cc419e52dd7a68c1eda1138c0713a1520a5413ef9dabfa9d21b7908d211998b75c60035d1d5ae87c00fe8ff5be8fa8449525235dd5 - languageName: node - linkType: hard - -"@nodelib/fs.scandir@npm:2.1.5": - version: 2.1.5 - resolution: "@nodelib/fs.scandir@npm:2.1.5" - dependencies: - "@nodelib/fs.stat": 2.0.5 - run-parallel: ^1.1.9 - checksum: a970d595bd23c66c880e0ef1817791432dbb7acbb8d44b7e7d0e7a22f4521260d4a83f7f9fd61d44fda4610105577f8f58a60718105fb38352baed612fd79e59 - languageName: node - linkType: hard - -"@nodelib/fs.stat@npm:2.0.5, @nodelib/fs.stat@npm:^2.0.2": - version: 2.0.5 - resolution: "@nodelib/fs.stat@npm:2.0.5" - checksum: 012480b5ca9d97bff9261571dbbec7bbc6033f69cc92908bc1ecfad0792361a5a1994bc48674b9ef76419d056a03efadfce5a6cf6dbc0a36559571a7a483f6f0 - languageName: node - linkType: hard - -"@nodelib/fs.walk@npm:^1.2.3, @nodelib/fs.walk@npm:^1.2.8": - version: 1.2.8 - resolution: "@nodelib/fs.walk@npm:1.2.8" - dependencies: - "@nodelib/fs.scandir": 2.1.5 - fastq: ^1.6.0 - checksum: 190c643f156d8f8f277bf2a6078af1ffde1fd43f498f187c2db24d35b4b4b5785c02c7dc52e356497b9a1b65b13edc996de08de0b961c32844364da02986dc53 - languageName: node - linkType: hard - -"@nornagon/put@npm:0.0.8": - version: 0.0.8 - resolution: "@nornagon/put@npm:0.0.8" - checksum: 6391a5da488fa86e2fd588205b32f7049a672d75bb040d4d1f544412b3ea53a3f928ee4f1a99b7c55126e0d7e8a37b5857c8d8792b64b71cdd6e18206ca8ec69 - languageName: node - linkType: hard - -"@npmcli/fs@npm:^2.1.0": - version: 2.1.2 - resolution: "@npmcli/fs@npm:2.1.2" - dependencies: - "@gar/promisify": ^1.1.3 - semver: ^7.3.5 - checksum: 405074965e72d4c9d728931b64d2d38e6ea12066d4fad651ac253d175e413c06fe4350970c783db0d749181da8fe49c42d3880bd1cbc12cd68e3a7964d820225 - languageName: node - linkType: hard - -"@npmcli/move-file@npm:^2.0.0": - version: 2.0.1 - resolution: "@npmcli/move-file@npm:2.0.1" - dependencies: - mkdirp: ^1.0.4 - rimraf: ^3.0.2 - checksum: 52dc02259d98da517fae4cb3a0a3850227bdae4939dda1980b788a7670636ca2b4a01b58df03dd5f65c1e3cb70c50fa8ce5762b582b3f499ec30ee5ce1fd9380 - languageName: node - linkType: hard - -"@playwright/test@npm:^1.29.2": - version: 1.32.3 - resolution: "@playwright/test@npm:1.32.3" - dependencies: - "@types/node": "*" - fsevents: 2.3.2 - playwright-core: 1.32.3 - dependenciesMeta: - fsevents: - optional: true - bin: - playwright: cli.js - checksum: f248e5851d04183954ec6f3a5f2c8e3b0ea0085a83e0e695068c5c2eb6acd4dddb16829a429829a4eb9fe0a4518f6a5594890cf9bf4259255c9e07a5964be625 - languageName: node - linkType: hard - -"@remusao/guess-url-type@npm:^1.1.2": - version: 1.2.1 - resolution: "@remusao/guess-url-type@npm:1.2.1" - checksum: 37a5142c970b6fb0c217c87a554add83b370dabd7f9f191e61747ba0979d8ceede5bea74cd00896641eab1ef3f23f37398d050a2e0de2adb719c556087cd623a - languageName: node - linkType: hard - -"@remusao/small@npm:^1.1.2": - version: 1.2.1 - resolution: "@remusao/small@npm:1.2.1" - checksum: e9c6a6d117754a86064c6a65f256ec7d0a0a73e0096ef522ea036d702477c5d4ace3349a5236ebcc2809dc887a60bf627eed0e45fd3416f3a6051e3a3436c712 - languageName: node - linkType: hard - -"@remusao/smaz-compress@npm:^1.9.1": - version: 1.9.1 - resolution: "@remusao/smaz-compress@npm:1.9.1" - dependencies: - "@remusao/trie": ^1.4.1 - checksum: e01875f4bb2508316f234c2bf662d8aab3ecaddd5cea516a6822954533e4305ff6d5f90e9e53f5bcababf203d515e9b99da9e7f6e58007aabcb90f5e4c5c9669 - languageName: node - linkType: hard - -"@remusao/smaz-decompress@npm:^1.9.1": - version: 1.9.1 - resolution: "@remusao/smaz-decompress@npm:1.9.1" - checksum: 6abc127dd3ff79b63bb469ae265ab568d1b9a4234f759cbff8c7688a4adf78141c0913255eb281fee03fc9250bc3ee36494999f01a7950c3a86bb5b9e7ab4dcc - languageName: node - linkType: hard - -"@remusao/smaz@npm:^1.7.1": - version: 1.9.1 - resolution: "@remusao/smaz@npm:1.9.1" - dependencies: - "@remusao/smaz-compress": ^1.9.1 - "@remusao/smaz-decompress": ^1.9.1 - checksum: 0a7607daccd751b21a2baf43eff5b82948bfe666353612510c3c34bc3a864a40ffd8cfa5f4c29ae240426d400e95e0816bb581b3233be78ed05a315b53d65df1 - languageName: node - linkType: hard - -"@remusao/trie@npm:^1.4.1": - version: 1.4.1 - resolution: "@remusao/trie@npm:1.4.1" - checksum: 0df106a649fd1b33cfa78712518e59b9c4b00c06dbdd0cda17f0ae8a6e661996a3b84161139eacb9578e8ee0a03564a860875537414b906c1dddf39a05db7570 - languageName: node - linkType: hard - -"@selderee/plugin-htmlparser2@npm:^0.11.0": - version: 0.11.0 - resolution: "@selderee/plugin-htmlparser2@npm:0.11.0" - dependencies: - domhandler: ^5.0.3 - selderee: ^0.11.0 - checksum: 6deafedd153e492359f8f0407d20903d82f2ef4950e420f4b2ee6ffbb955753524631aac7d6a5fe61dc7c7893e6928b4d8409e886157ad64a60ab37bc08b17c4 - languageName: node - linkType: hard - -"@sindresorhus/is@npm:^4.0.0": - version: 4.6.0 - resolution: "@sindresorhus/is@npm:4.6.0" - checksum: 83839f13da2c29d55c97abc3bc2c55b250d33a0447554997a85c539e058e57b8da092da396e252b11ec24a0279a0bed1f537fa26302209327060643e327f81d2 - languageName: node - linkType: hard - -"@szmarczak/http-timer@npm:^4.0.5": - version: 4.0.6 - resolution: "@szmarczak/http-timer@npm:4.0.6" - dependencies: - defer-to-connect: ^2.0.0 - checksum: c29df3bcec6fc3bdec2b17981d89d9c9fc9bd7d0c9bcfe92821dc533f4440bc890ccde79971838b4ceed1921d456973c4180d7175ee1d0023ad0562240a58d95 - languageName: node - linkType: hard - -"@tootallnate/once@npm:2": - version: 2.0.0 - resolution: "@tootallnate/once@npm:2.0.0" - checksum: ad87447820dd3f24825d2d947ebc03072b20a42bfc96cbafec16bff8bbda6c1a81fcb0be56d5b21968560c5359a0af4038a68ba150c3e1694fe4c109a063bed8 - languageName: node - linkType: hard - -"@types/cacheable-request@npm:^6.0.1": - version: 6.0.3 - resolution: "@types/cacheable-request@npm:6.0.3" - dependencies: - "@types/http-cache-semantics": "*" - "@types/keyv": ^3.1.4 - "@types/node": "*" - "@types/responselike": ^1.0.0 - checksum: d9b26403fe65ce6b0cb3720b7030104c352bcb37e4fac2a7089a25a97de59c355fa08940658751f2f347a8512aa9d18fdb66ab3ade835975b2f454f2d5befbd9 - languageName: node - linkType: hard - -"@types/chrome@npm:^0.0.225": - version: 0.0.225 - resolution: "@types/chrome@npm:0.0.225" - dependencies: - "@types/filesystem": "*" - "@types/har-format": "*" - checksum: e507ab091b52b27cf49fbb33d5bb5730325928bcebab39f8ac888599ccef4c66115a7280f56a9e00eb48718cf95a2564159c7303f814041e2b62fe33c6c7bc99 - languageName: node - linkType: hard - -"@types/debug@npm:^4.1.6": - version: 4.1.7 - resolution: "@types/debug@npm:4.1.7" - dependencies: - "@types/ms": "*" - checksum: 0a7b89d8ed72526858f0b61c6fd81f477853e8c4415bb97f48b1b5545248d2ae389931680b94b393b993a7cfe893537a200647d93defe6d87159b96812305adc - languageName: node - linkType: hard - -"@types/eslint@npm:^7.2.13": - version: 7.29.0 - resolution: "@types/eslint@npm:7.29.0" - dependencies: - "@types/estree": "*" - "@types/json-schema": "*" - checksum: df13991c554954353ce8f3bb03e19da6cc71916889443d68d178d4f858b561ba4cc4a4f291c6eb9eebb7f864b12b9b9313051b3a8dfea3e513dadf3188a77bdf - languageName: node - linkType: hard - -"@types/estree@npm:*": - version: 1.0.0 - resolution: "@types/estree@npm:1.0.0" - checksum: 910d97fb7092c6738d30a7430ae4786a38542023c6302b95d46f49420b797f21619cdde11fa92b338366268795884111c2eb10356e4bd2c8ad5b92941e9e6443 - languageName: node - linkType: hard - -"@types/filesystem@npm:*": - version: 0.0.32 - resolution: "@types/filesystem@npm:0.0.32" - dependencies: - "@types/filewriter": "*" - checksum: 4b9079d200a3b241722b90e1c5806c4b32c4dac87d42a1c7ef76a2c0dafdbe7d5f1a379b873ad5de73622b44de6599e1522908f67b938d54e785bd1c36e302a0 - languageName: node - linkType: hard - -"@types/filewriter@npm:*": - version: 0.0.29 - resolution: "@types/filewriter@npm:0.0.29" - checksum: 0c58aa875c2c245be7dbc42b20212f3203e13d11ec013a4a5cd0febf0e8b87214be5882c05ff9d7bdf0398f145a4fdbc24b7e6cf7b094e134a3b4c7a0598502f - languageName: node - linkType: hard - -"@types/firefox-webext-browser@npm:^111.0.0": - version: 111.0.1 - resolution: "@types/firefox-webext-browser@npm:111.0.1" - checksum: 1730c2e303cb502dd3e85aeb6ac645e3526c1583da0ae02ea1203ac002485ba5bf045f7183840b6bde4055f43818b366db6dd112e0d611ec1d82c86c74a4589b - languageName: node - linkType: hard - -"@types/fs-extra@npm:^9.0.11": - version: 9.0.13 - resolution: "@types/fs-extra@npm:9.0.13" - dependencies: - "@types/node": "*" - checksum: add79e212acd5ac76b97b9045834e03a7996aef60a814185e0459088fd290519a3c1620865d588fa36c4498bf614210d2a703af5cf80aa1dbc125db78f6edac3 - languageName: node - linkType: hard - -"@types/har-format@npm:*": - version: 1.2.10 - resolution: "@types/har-format@npm:1.2.10" - checksum: 14c0118d809e77a0bac9deec0a87159c28beab21105cfce3aa291b51e28d4c07142851c4e6b93b7ecb4ea237fe07d39ba98a42bb2de2f5891144733411ac76b7 - languageName: node - linkType: hard - -"@types/http-cache-semantics@npm:*": - version: 4.0.1 - resolution: "@types/http-cache-semantics@npm:4.0.1" - checksum: 1048aacf627829f0d5f00184e16548205cd9f964bf0841c29b36bc504509230c40bc57c39778703a1c965a6f5b416ae2cbf4c1d4589c889d2838dd9dbfccf6e9 - languageName: node - linkType: hard - -"@types/json-schema@npm:*, @types/json-schema@npm:^7.0.9": - version: 7.0.11 - resolution: "@types/json-schema@npm:7.0.11" - checksum: 527bddfe62db9012fccd7627794bd4c71beb77601861055d87e3ee464f2217c85fca7a4b56ae677478367bbd248dbde13553312b7d4dbc702a2f2bbf60c4018d - languageName: node - linkType: hard - -"@types/json5@npm:^0.0.29": - version: 0.0.29 - resolution: "@types/json5@npm:0.0.29" - checksum: e60b153664572116dfea673c5bda7778dbff150498f44f998e34b5886d8afc47f16799280e4b6e241c0472aef1bc36add771c569c68fc5125fc2ae519a3eb9ac - languageName: node - linkType: hard - -"@types/keyv@npm:^3.1.4": - version: 3.1.4 - resolution: "@types/keyv@npm:3.1.4" - dependencies: - "@types/node": "*" - checksum: e009a2bfb50e90ca9b7c6e8f648f8464067271fd99116f881073fa6fa76dc8d0133181dd65e6614d5fb1220d671d67b0124aef7d97dc02d7e342ab143a47779d - languageName: node - linkType: hard - -"@types/minimist@npm:^1.2.2": - version: 1.2.2 - resolution: "@types/minimist@npm:1.2.2" - checksum: b8da83c66eb4aac0440e64674b19564d9d86c80ae273144db9681e5eeff66f238ade9515f5006ffbfa955ceff8b89ad2bd8ec577d7caee74ba101431fb07045d - languageName: node - linkType: hard - -"@types/ms@npm:*": - version: 0.7.31 - resolution: "@types/ms@npm:0.7.31" - checksum: daadd354aedde024cce6f5aa873fefe7b71b22cd0e28632a69e8b677aeb48ae8caa1c60e5919bb781df040d116b01cb4316335167a3fc0ef6a63fa3614c0f6da - languageName: node - linkType: hard - -"@types/node@npm:*": - version: 18.15.11 - resolution: "@types/node@npm:18.15.11" - checksum: 977b4ad04708897ff0eb049ecf82246d210939c82461922d20f7d2dcfd81bbc661582ba3af28869210f7e8b1934529dcd46bff7d448551400f9d48b9d3bddec3 - languageName: node - linkType: hard - -"@types/node@npm:^16.11.26": - version: 16.18.23 - resolution: "@types/node@npm:16.18.23" - checksum: 00e51db28fc7a182747f37215b3f25400b1c7a8525e09fa14e55be5798891a118ebf636a49d3197335a3580fcb8222fd4ecc20c2ccff69f1c0d233fc5697465d - languageName: node - linkType: hard - -"@types/normalize-package-data@npm:^2.4.0, @types/normalize-package-data@npm:^2.4.1": - version: 2.4.1 - resolution: "@types/normalize-package-data@npm:2.4.1" - checksum: e87bccbf11f95035c89a132b52b79ce69a1e3652fe55962363063c9c0dae0fe2477ebc585e03a9652adc6f381d24ba5589cc5e51849df4ced3d3e004a7d40ed5 - languageName: node - linkType: hard - -"@types/parse-json@npm:^4.0.0": - version: 4.0.0 - resolution: "@types/parse-json@npm:4.0.0" - checksum: fd6bce2b674b6efc3db4c7c3d336bd70c90838e8439de639b909ce22f3720d21344f52427f1d9e57b265fcb7f6c018699b99e5e0c208a1a4823014269a6bf35b - languageName: node - linkType: hard - -"@types/plist@npm:^3.0.1": - version: 3.0.2 - resolution: "@types/plist@npm:3.0.2" - dependencies: - "@types/node": "*" - xmlbuilder: ">=11.0.1" - checksum: b8f9e6b21fb41a7e8ea5250717da972cde40b120109d5d2ed79e0a25406a9f6793abcba048d9b8ecc3df4b25735d9e4223b4d8a56dff893665c4a8c8573b77ad - languageName: node - linkType: hard - -"@types/responselike@npm:^1.0.0": - version: 1.0.0 - resolution: "@types/responselike@npm:1.0.0" - dependencies: - "@types/node": "*" - checksum: e99fc7cc6265407987b30deda54c1c24bb1478803faf6037557a774b2f034c5b097ffd65847daa87e82a61a250d919f35c3588654b0fdaa816906650f596d1b0 - languageName: node - linkType: hard - -"@types/semver@npm:^7.3.12, @types/semver@npm:^7.3.6": - version: 7.3.13 - resolution: "@types/semver@npm:7.3.13" - checksum: 00c0724d54757c2f4bc60b5032fe91cda6410e48689633d5f35ece8a0a66445e3e57fa1d6e07eb780f792e82ac542948ec4d0b76eb3484297b79bd18b8cf1cb0 - languageName: node - linkType: hard - -"@types/verror@npm:^1.10.3": - version: 1.10.6 - resolution: "@types/verror@npm:1.10.6" - checksum: 650620b851d42cda6e5f6fa84f4d89c259b3f85f7443ee1c85f4f9a9e1ce7b472640c833ef483d0803f8100d6228a82fb9776f53d5539cfe1d8f06adfb04e10c - languageName: node - linkType: hard - -"@types/yargs-parser@npm:*": - version: 21.0.0 - resolution: "@types/yargs-parser@npm:21.0.0" - checksum: b2f4c8d12ac18a567440379909127cf2cec393daffb73f246d0a25df36ea983b93b7e9e824251f959e9f928cbc7c1aab6728d0a0ff15d6145f66cec2be67d9a2 - languageName: node - linkType: hard - -"@types/yargs@npm:^17.0.1": - version: 17.0.24 - resolution: "@types/yargs@npm:17.0.24" - dependencies: - "@types/yargs-parser": "*" - checksum: 5f3ac4dc4f6e211c1627340160fbe2fd247ceba002190da6cf9155af1798450501d628c9165a183f30a224fc68fa5e700490d740ff4c73e2cdef95bc4e8ba7bf - languageName: node - linkType: hard - -"@types/yauzl@npm:^2.9.1": - version: 2.10.0 - resolution: "@types/yauzl@npm:2.10.0" - dependencies: - "@types/node": "*" - checksum: 55d27ae5d346ea260e40121675c24e112ef0247649073848e5d4e03182713ae4ec8142b98f61a1c6cbe7d3b72fa99bbadb65d8b01873e5e605cdc30f1ff70ef2 - languageName: node - linkType: hard - -"@typescript-eslint/eslint-plugin@npm:^5.43.0": - version: 5.58.0 - resolution: "@typescript-eslint/eslint-plugin@npm:5.58.0" - dependencies: - "@eslint-community/regexpp": ^4.4.0 - "@typescript-eslint/scope-manager": 5.58.0 - "@typescript-eslint/type-utils": 5.58.0 - "@typescript-eslint/utils": 5.58.0 - debug: ^4.3.4 - grapheme-splitter: ^1.0.4 - ignore: ^5.2.0 - natural-compare-lite: ^1.4.0 - semver: ^7.3.7 - tsutils: ^3.21.0 - peerDependencies: - "@typescript-eslint/parser": ^5.0.0 - eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 - peerDependenciesMeta: - typescript: - optional: true - checksum: e5d76d43c466ebd4b552e3307eff72ab5ae8a0c09a1d35fa13b62769ac3336df94d9281728ab5aafd2c14a0a644133583edcd708fce60a9a82df1db3ca3b8e14 - languageName: node - linkType: hard - -"@typescript-eslint/parser@npm:^5.43.0": - version: 5.58.0 - resolution: "@typescript-eslint/parser@npm:5.58.0" - dependencies: - "@typescript-eslint/scope-manager": 5.58.0 - "@typescript-eslint/types": 5.58.0 - "@typescript-eslint/typescript-estree": 5.58.0 - debug: ^4.3.4 - peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 - peerDependenciesMeta: - typescript: - optional: true - checksum: 38681da48a40132c0538579c818ceef9ba2793ab8f79236c3f64980ba1649bb87cb367cd79d37bf2982b8bfbc28f91846b8676f9bd333e8b691c9befffd8874a - languageName: node - linkType: hard - -"@typescript-eslint/scope-manager@npm:5.58.0": - version: 5.58.0 - resolution: "@typescript-eslint/scope-manager@npm:5.58.0" - dependencies: - "@typescript-eslint/types": 5.58.0 - "@typescript-eslint/visitor-keys": 5.58.0 - checksum: f0d3df5cc3c461fe63ef89ad886b53c239cc7c1d9061d83d8a9d9c8e087e5501eac84bebff8a954728c17ccea191f235686373d54d2b8b6370af2bcf2b18e062 - languageName: node - linkType: hard - -"@typescript-eslint/type-utils@npm:5.58.0": - version: 5.58.0 - resolution: "@typescript-eslint/type-utils@npm:5.58.0" - dependencies: - "@typescript-eslint/typescript-estree": 5.58.0 - "@typescript-eslint/utils": 5.58.0 - debug: ^4.3.4 - tsutils: ^3.21.0 - peerDependencies: - eslint: "*" - peerDependenciesMeta: - typescript: - optional: true - checksum: 803f24daed185152bf86952d4acebb5ea18ff03db5f28750368edf76fdea46b4b0f8803ae0b61c0282b47181c9977113457b16e33d5d2cb33b13855f55c5e5b2 - languageName: node - linkType: hard - -"@typescript-eslint/types@npm:5.58.0": - version: 5.58.0 - resolution: "@typescript-eslint/types@npm:5.58.0" - checksum: 8622a73d73220c4a7111537825f488c0271272032a1d4e129dc722bc6e8b3ec84f64469b2ca3b8dae7da3a9c18953ce1449af51f5f757dad60835eb579ad1d2c - languageName: node - linkType: hard - -"@typescript-eslint/typescript-estree@npm:5.58.0": - version: 5.58.0 - resolution: "@typescript-eslint/typescript-estree@npm:5.58.0" - dependencies: - "@typescript-eslint/types": 5.58.0 - "@typescript-eslint/visitor-keys": 5.58.0 - debug: ^4.3.4 - globby: ^11.1.0 - is-glob: ^4.0.3 - semver: ^7.3.7 - tsutils: ^3.21.0 - peerDependenciesMeta: - typescript: - optional: true - checksum: 51b668ec858db0c040a71dff526273945cee4ba5a9b240528d503d02526685882d900cf071c6636a4d9061ed3fd4a7274f7f1a23fba55c4b48b143344b4009c7 - languageName: node - linkType: hard - -"@typescript-eslint/utils@npm:5.58.0": - version: 5.58.0 - resolution: "@typescript-eslint/utils@npm:5.58.0" - dependencies: - "@eslint-community/eslint-utils": ^4.2.0 - "@types/json-schema": ^7.0.9 - "@types/semver": ^7.3.12 - "@typescript-eslint/scope-manager": 5.58.0 - "@typescript-eslint/types": 5.58.0 - "@typescript-eslint/typescript-estree": 5.58.0 - eslint-scope: ^5.1.1 - semver: ^7.3.7 - peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 - checksum: c618ae67963ecf96b1492c09afaeb363f542f0d6780bcac4af3c26034e3b20034666b2d523aa94821df813aafb57a0b150a7d5c2224fe8257452ad1de2237a58 - languageName: node - linkType: hard - -"@typescript-eslint/visitor-keys@npm:5.58.0": - version: 5.58.0 - resolution: "@typescript-eslint/visitor-keys@npm:5.58.0" - dependencies: - "@typescript-eslint/types": 5.58.0 - eslint-visitor-keys: ^3.3.0 - checksum: ab2d1f37660559954c840429ef78bbf71834063557e3e68e435005b4987970b9356fdf217ead53f7a57f66f5488dc478062c5c44bf17053a8bf041733539b98f - languageName: node - linkType: hard - -"@xhayper/discord-rpc@npm:^1.0.16": - version: 1.0.16 - resolution: "@xhayper/discord-rpc@npm:1.0.16" - dependencies: - axios: ^1.3.5 - discord-api-types: ^0.37.37 - ws: ^8.13.0 - checksum: 19851eb56ab51c2a6425a7fbf7b2df029d356513b761c718e6059c8066230023caf91d1352adb6d3af8a503a0c6995f465929e0d0c3592636d94a8e1b09b84b2 - languageName: node - linkType: hard - -"abbrev@npm:^1.0.0": - version: 1.1.1 - resolution: "abbrev@npm:1.1.1" - checksum: a4a97ec07d7ea112c517036882b2ac22f3109b7b19077dc656316d07d308438aac28e4d9746dc4d84bf6b1e75b4a7b0a5f3cb30592419f128ca9a8cee3bcfa17 - languageName: node - linkType: hard - -"abstract-socket@npm:^2.0.0": - version: 2.1.1 - resolution: "abstract-socket@npm:2.1.1" - dependencies: - bindings: ^1.2.1 - nan: ^2.12.1 - node-gyp: latest - conditions: os=linux - languageName: node - linkType: hard - -"acorn-jsx@npm:^5.3.2": - version: 5.3.2 - resolution: "acorn-jsx@npm:5.3.2" - peerDependencies: - acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 - checksum: c3d3b2a89c9a056b205b69530a37b972b404ee46ec8e5b341666f9513d3163e2a4f214a71f4dfc7370f5a9c07472d2fd1c11c91c3f03d093e37637d95da98950 - languageName: node - linkType: hard - -"acorn@npm:^8.8.0": - version: 8.8.2 - resolution: "acorn@npm:8.8.2" - bin: - acorn: bin/acorn - checksum: f790b99a1bf63ef160c967e23c46feea7787e531292bb827126334612c234ed489a0dc2c7ba33156416f0ffa8d25bf2b0fdb7f35c2ba60eb3e960572bece4001 - languageName: node - linkType: hard - -"agent-base@npm:6, agent-base@npm:^6.0.2": - version: 6.0.2 - resolution: "agent-base@npm:6.0.2" - dependencies: - debug: 4 - checksum: f52b6872cc96fd5f622071b71ef200e01c7c4c454ee68bc9accca90c98cfb39f2810e3e9aa330435835eedc8c23f4f8a15267f67c6e245d2b33757575bdac49d - languageName: node - linkType: hard - -"agentkeepalive@npm:^4.2.1": - version: 4.3.0 - resolution: "agentkeepalive@npm:4.3.0" - dependencies: - debug: ^4.1.0 - depd: ^2.0.0 - humanize-ms: ^1.2.1 - checksum: 982453aa44c11a06826c836025e5162c846e1200adb56f2d075400da7d32d87021b3b0a58768d949d824811f5654223d5a8a3dad120921a2439625eb847c6260 - languageName: node - linkType: hard - -"aggregate-error@npm:^3.0.0": - version: 3.1.0 - resolution: "aggregate-error@npm:3.1.0" - dependencies: - clean-stack: ^2.0.0 - indent-string: ^4.0.0 - checksum: 1101a33f21baa27a2fa8e04b698271e64616b886795fd43c31068c07533c7b3facfcaf4e9e0cab3624bd88f729a592f1c901a1a229c9e490eafce411a8644b79 - languageName: node - linkType: hard - -"aggregate-error@npm:^4.0.0": - version: 4.0.1 - resolution: "aggregate-error@npm:4.0.1" - dependencies: - clean-stack: ^4.0.0 - indent-string: ^5.0.0 - checksum: bb3ffdfd13447800fff237c2cba752c59868ee669104bb995dfbbe0b8320e967d679e683dabb640feb32e4882d60258165cde0baafc4cd467cc7d275a13ad6b5 - languageName: node - linkType: hard - -"ajv-formats@npm:^2.1.1": - version: 2.1.1 - resolution: "ajv-formats@npm:2.1.1" - dependencies: - ajv: ^8.0.0 - peerDependencies: - ajv: ^8.0.0 - peerDependenciesMeta: - ajv: - optional: true - checksum: 4a287d937f1ebaad4683249a4c40c0fa3beed30d9ddc0adba04859026a622da0d317851316ea64b3680dc60f5c3c708105ddd5d5db8fe595d9d0207fd19f90b7 - languageName: node - linkType: hard - -"ajv-keywords@npm:^3.4.1": - version: 3.5.2 - resolution: "ajv-keywords@npm:3.5.2" - peerDependencies: - ajv: ^6.9.1 - checksum: 7dc5e5931677a680589050f79dcbe1fefbb8fea38a955af03724229139175b433c63c68f7ae5f86cf8f65d55eb7c25f75a046723e2e58296707617ca690feae9 - languageName: node - linkType: hard - -"ajv@npm:^6.10.0, ajv@npm:^6.12.0, ajv@npm:^6.12.4": - version: 6.12.6 - resolution: "ajv@npm:6.12.6" - dependencies: - fast-deep-equal: ^3.1.1 - fast-json-stable-stringify: ^2.0.0 - json-schema-traverse: ^0.4.1 - uri-js: ^4.2.2 - checksum: 874972efe5c4202ab0a68379481fbd3d1b5d0a7bd6d3cc21d40d3536ebff3352a2a1fabb632d4fd2cc7fe4cbdcd5ed6782084c9bbf7f32a1536d18f9da5007d4 - languageName: node - linkType: hard - -"ajv@npm:^8.0.0, ajv@npm:^8.6.3": - version: 8.12.0 - resolution: "ajv@npm:8.12.0" - dependencies: - fast-deep-equal: ^3.1.1 - json-schema-traverse: ^1.0.0 - require-from-string: ^2.0.2 - uri-js: ^4.2.2 - checksum: 4dc13714e316e67537c8b31bc063f99a1d9d9a497eb4bbd55191ac0dcd5e4985bbb71570352ad6f1e76684fb6d790928f96ba3b2d4fd6e10024be9612fe3f001 - languageName: node - linkType: hard - -"ansi-escapes@npm:^4.2.1": - version: 4.3.2 - resolution: "ansi-escapes@npm:4.3.2" - dependencies: - type-fest: ^0.21.3 - checksum: 93111c42189c0a6bed9cdb4d7f2829548e943827ee8479c74d6e0b22ee127b2a21d3f8b5ca57723b8ef78ce011fbfc2784350eb2bde3ccfccf2f575fa8489815 - languageName: node - linkType: hard - -"ansi-regex@npm:^5.0.1": - version: 5.0.1 - resolution: "ansi-regex@npm:5.0.1" - checksum: 2aa4bb54caf2d622f1afdad09441695af2a83aa3fe8b8afa581d205e57ed4261c183c4d3877cee25794443fde5876417d859c108078ab788d6af7e4fe52eb66b - languageName: node - linkType: hard - -"ansi-styles@npm:^3.2.1": - version: 3.2.1 - resolution: "ansi-styles@npm:3.2.1" - dependencies: - color-convert: ^1.9.0 - checksum: d85ade01c10e5dd77b6c89f34ed7531da5830d2cb5882c645f330079975b716438cd7ebb81d0d6e6b4f9c577f19ae41ab55f07f19786b02f9dfd9e0377395665 - languageName: node - linkType: hard - -"ansi-styles@npm:^4.0.0, ansi-styles@npm:^4.1.0": - version: 4.3.0 - resolution: "ansi-styles@npm:4.3.0" - dependencies: - color-convert: ^2.0.1 - checksum: 513b44c3b2105dd14cc42a19271e80f386466c4be574bccf60b627432f9198571ebf4ab1e4c3ba17347658f4ee1711c163d574248c0c1cdc2d5917a0ad582ec4 - languageName: node - linkType: hard - -"app-builder-bin@npm:4.0.0": - version: 4.0.0 - resolution: "app-builder-bin@npm:4.0.0" - checksum: c3c8fd85c371b7a396c1bb1160ab2e3231ba4309abea5b36a5b366e42511e347c65a33ff50d56f4960b337833d539c263137b0ba131e2fa268c32edeb6c9f683 - languageName: node - linkType: hard - -"app-builder-lib@npm:23.6.0": - version: 23.6.0 - resolution: "app-builder-lib@npm:23.6.0" - dependencies: - 7zip-bin: ~5.1.1 - "@develar/schema-utils": ~2.6.5 - "@electron/universal": 1.2.1 - "@malept/flatpak-bundler": ^0.4.0 - async-exit-hook: ^2.0.1 - bluebird-lst: ^1.0.9 - builder-util: 23.6.0 - builder-util-runtime: 9.1.1 - chromium-pickle-js: ^0.2.0 - debug: ^4.3.4 - ejs: ^3.1.7 - electron-osx-sign: ^0.6.0 - electron-publish: 23.6.0 - form-data: ^4.0.0 - fs-extra: ^10.1.0 - hosted-git-info: ^4.1.0 - is-ci: ^3.0.0 - isbinaryfile: ^4.0.10 - js-yaml: ^4.1.0 - lazy-val: ^1.0.5 - minimatch: ^3.1.2 - read-config-file: 6.2.0 - sanitize-filename: ^1.6.3 - semver: ^7.3.7 - tar: ^6.1.11 - temp-file: ^3.4.0 - checksum: da3cc9f24e127add651197076c5fa2f68bc7979bcd6a441df7f69629e96bf3aca3118d61c63a85d382a824748f8056a7639464f07b1ded09db53ff1c4b3101be - languageName: node - linkType: hard - -"aproba@npm:^1.0.3 || ^2.0.0": - version: 2.0.0 - resolution: "aproba@npm:2.0.0" - checksum: 5615cadcfb45289eea63f8afd064ab656006361020e1735112e346593856f87435e02d8dcc7ff0d11928bc7d425f27bc7c2a84f6c0b35ab0ff659c814c138a24 - languageName: node - linkType: hard - -"are-we-there-yet@npm:^3.0.0": - version: 3.0.1 - resolution: "are-we-there-yet@npm:3.0.1" - dependencies: - delegates: ^1.0.0 - readable-stream: ^3.6.0 - checksum: 52590c24860fa7173bedeb69a4c05fb573473e860197f618b9a28432ee4379049336727ae3a1f9c4cb083114601c1140cee578376164d0e651217a9843f9fe83 - languageName: node - linkType: hard - -"argparse@npm:^2.0.1": - version: 2.0.1 - resolution: "argparse@npm:2.0.1" - checksum: 83644b56493e89a254bae05702abf3a1101b4fa4d0ca31df1c9985275a5a5bd47b3c27b7fa0b71098d41114d8ca000e6ed90cad764b306f8a503665e4d517ced - languageName: node - linkType: hard - -"array-buffer-byte-length@npm:^1.0.0": - version: 1.0.0 - resolution: "array-buffer-byte-length@npm:1.0.0" - dependencies: - call-bind: ^1.0.2 - is-array-buffer: ^3.0.1 - checksum: 044e101ce150f4804ad19c51d6c4d4cfa505c5b2577bd179256e4aa3f3f6a0a5e9874c78cd428ee566ac574c8a04d7ce21af9fe52e844abfdccb82b33035a7c3 - languageName: node - linkType: hard - -"array-find@npm:^1.0.0": - version: 1.0.0 - resolution: "array-find@npm:1.0.0" - checksum: 6588ebfd15841296923f7c8c70f9f4cfd0e803c9f66cf53382431e5d5c763f1a866120181ba80aba7ebed73b27c5756fdb2202054e7ef475290239839185544b - languageName: node - linkType: hard - -"array-includes@npm:^3.1.6": - version: 3.1.6 - resolution: "array-includes@npm:3.1.6" - dependencies: - call-bind: ^1.0.2 - define-properties: ^1.1.4 - es-abstract: ^1.20.4 - get-intrinsic: ^1.1.3 - is-string: ^1.0.7 - checksum: f22f8cd8ba8a6448d91eebdc69f04e4e55085d09232b5216ee2d476dab3ef59984e8d1889e662c6a0ed939dcb1b57fd05b2c0209c3370942fc41b752c82a2ca5 - languageName: node - linkType: hard - -"array-union@npm:^2.1.0": - version: 2.1.0 - resolution: "array-union@npm:2.1.0" - checksum: 5bee12395cba82da674931df6d0fea23c4aa4660cb3b338ced9f828782a65caa232573e6bf3968f23e0c5eb301764a382cef2f128b170a9dc59de0e36c39f98d - languageName: node - linkType: hard - -"array.prototype.flat@npm:^1.3.1": - version: 1.3.1 - resolution: "array.prototype.flat@npm:1.3.1" - dependencies: - call-bind: ^1.0.2 - define-properties: ^1.1.4 - es-abstract: ^1.20.4 - es-shim-unscopables: ^1.0.0 - checksum: 5a8415949df79bf6e01afd7e8839bbde5a3581300e8ad5d8449dea52639e9e59b26a467665622783697917b43bf39940a6e621877c7dd9b3d1c1f97484b9b88b - languageName: node - linkType: hard - -"array.prototype.flatmap@npm:^1.3.1": - version: 1.3.1 - resolution: "array.prototype.flatmap@npm:1.3.1" - dependencies: - call-bind: ^1.0.2 - define-properties: ^1.1.4 - es-abstract: ^1.20.4 - es-shim-unscopables: ^1.0.0 - checksum: 8c1c43a4995f12cf12523436da28515184c753807b3f0bc2ca6c075f71c470b099e2090cc67dba8e5280958fea401c1d0c59e1db0143272aef6cd1103921a987 - languageName: node - linkType: hard - -"arrify@npm:^1.0.1": - version: 1.0.1 - resolution: "arrify@npm:1.0.1" - checksum: 745075dd4a4624ff0225c331dacb99be501a515d39bcb7c84d24660314a6ec28e68131b137e6f7e16318170842ce97538cd298fc4cd6b2cc798e0b957f2747e7 - languageName: node - linkType: hard - -"arrify@npm:^3.0.0": - version: 3.0.0 - resolution: "arrify@npm:3.0.0" - checksum: d6c6f3dad9571234f320e130d57fddb2cc283c87f2ac7df6c7005dffc5161b7bb9376f4be655ed257050330336e84afc4f3020d77696ad231ff580a94ae5aba6 - languageName: node - linkType: hard - -"assert-plus@npm:^1.0.0": - version: 1.0.0 - resolution: "assert-plus@npm:1.0.0" - checksum: 19b4340cb8f0e6a981c07225eacac0e9d52c2644c080198765d63398f0075f83bbc0c8e95474d54224e297555ad0d631c1dcd058adb1ddc2437b41a6b424ac64 - languageName: node - linkType: hard - -"astral-regex@npm:^2.0.0": - version: 2.0.0 - resolution: "astral-regex@npm:2.0.0" - checksum: 876231688c66400473ba505731df37ea436e574dd524520294cc3bbc54ea40334865e01fa0d074d74d036ee874ee7e62f486ea38bc421ee8e6a871c06f011766 - languageName: node - linkType: hard - -"async-exit-hook@npm:^2.0.1": - version: 2.0.1 - resolution: "async-exit-hook@npm:2.0.1" - checksum: b72cbdd19ea90fa33a3a57b0dbff83e4bf2f4e4acd70b2b3847a588f9f16a45d38590ee13f285375dd919c224f60fa58dc3d315a87678d3aa24ff686d1c0200a - languageName: node - linkType: hard - -"async-mutex@npm:^0.4.0": - version: 0.4.0 - resolution: "async-mutex@npm:0.4.0" - dependencies: - tslib: ^2.4.0 - checksum: 813a71728b35a4fbfd64dba719f04726d9133c67b577fcd951b7028c4a675a13ee34e69beb82d621f87bf81f5d4f135c4c44be0448550c7db728547244ef71fc - languageName: node - linkType: hard - -"async@npm:^3.2.3": - version: 3.2.4 - resolution: "async@npm:3.2.4" - checksum: 43d07459a4e1d09b84a20772414aa684ff4de085cbcaec6eea3c7a8f8150e8c62aa6cd4e699fe8ee93c3a5b324e777d34642531875a0817a35697522c1b02e89 - languageName: node - linkType: hard - -"asynckit@npm:^0.4.0": - version: 0.4.0 - resolution: "asynckit@npm:0.4.0" - checksum: 7b78c451df768adba04e2d02e63e2d0bf3b07adcd6e42b4cf665cb7ce899bedd344c69a1dcbce355b5f972d597b25aaa1c1742b52cffd9caccb22f348114f6be - languageName: node - linkType: hard - -"at-least-node@npm:^1.0.0": - version: 1.0.0 - resolution: "at-least-node@npm:1.0.0" - checksum: 463e2f8e43384f1afb54bc68485c436d7622acec08b6fad269b421cb1d29cebb5af751426793d0961ed243146fe4dc983402f6d5a51b720b277818dbf6f2e49e - languageName: node - linkType: hard - -"atomically@npm:^1.7.0": - version: 1.7.0 - resolution: "atomically@npm:1.7.0" - checksum: 991153b17334597f93b58e831bea9851e57ed9cd41d8f33991be063f170b5cc8ec7ff8605f3eb95c1d389c2ad651039e9eb8f2b795e24833c2ceb944f347373a - languageName: node - linkType: hard - -"auto-changelog@npm:^2.4.0": - version: 2.4.0 - resolution: "auto-changelog@npm:2.4.0" - dependencies: - commander: ^7.2.0 - handlebars: ^4.7.7 - node-fetch: ^2.6.1 - parse-github-url: ^1.0.2 - semver: ^7.3.5 - bin: - auto-changelog: src/index.js - checksum: 554270a24b4bd2c7485d8529f1f66db9b11bcaada959b06c4af57b135eff197dfb393d8009c1f609d46d33e413d25fb50bc264c376d346cdf41486a8b675768b - languageName: node - linkType: hard - -"available-typed-arrays@npm:^1.0.5": - version: 1.0.5 - resolution: "available-typed-arrays@npm:1.0.5" - checksum: 20eb47b3cefd7db027b9bbb993c658abd36d4edd3fe1060e83699a03ee275b0c9b216cc076ff3f2db29073225fb70e7613987af14269ac1fe2a19803ccc97f1a - languageName: node - linkType: hard - -"axios@npm:^1.3.5": - version: 1.3.5 - resolution: "axios@npm:1.3.5" - dependencies: - follow-redirects: ^1.15.0 - form-data: ^4.0.0 - proxy-from-env: ^1.1.0 - checksum: 4d6bcf933b1cdff86d4993752aaeeeedc4a7f7a4b1c942847f6884bb13fc6106610ff826b076acf0b08d8ced55dee9344bb9a11f3624c3e70ab1da1a40bb5506 - languageName: node - linkType: hard - -"babel-runtime@npm:^6.26.0": - version: 6.26.0 - resolution: "babel-runtime@npm:6.26.0" - dependencies: - core-js: ^2.4.0 - regenerator-runtime: ^0.11.0 - checksum: 8aeade94665e67a73c1ccc10f6fd42ba0c689b980032b70929de7a6d9a12eb87ef51902733f8fefede35afea7a5c3ef7e916a64d503446c1eedc9e3284bd3d50 - languageName: node - linkType: hard - -"balanced-match@npm:^1.0.0": - version: 1.0.2 - resolution: "balanced-match@npm:1.0.2" - checksum: 9706c088a283058a8a99e0bf91b0a2f75497f185980d9ffa8b304de1d9e58ebda7c72c07ebf01dadedaac5b2907b2c6f566f660d62bd336c3468e960403b9d65 - languageName: node - linkType: hard - -"base64-js@npm:^1.3.1, base64-js@npm:^1.5.1": - version: 1.5.1 - resolution: "base64-js@npm:1.5.1" - checksum: 669632eb3745404c2f822a18fc3a0122d2f9a7a13f7fb8b5823ee19d1d2ff9ee5b52c53367176ea4ad093c332fd5ab4bd0ebae5a8e27917a4105a4cfc86b1005 - languageName: node - linkType: hard - -"bindings@npm:^1.2.1": - version: 1.5.0 - resolution: "bindings@npm:1.5.0" - dependencies: - file-uri-to-path: 1.0.0 - checksum: 65b6b48095717c2e6105a021a7da4ea435aa8d3d3cd085cb9e85bcb6e5773cf318c4745c3f7c504412855940b585bdf9b918236612a1c7a7942491de176f1ae7 - languageName: node - linkType: hard - -"bluebird-lst@npm:^1.0.9": - version: 1.0.9 - resolution: "bluebird-lst@npm:1.0.9" - dependencies: - bluebird: ^3.5.5 - checksum: 5662542d7303cfc2dcd63e87e153cd0cc6adb2d8b383d08cb11582625ba5f0116b2eb725ea471feaea74e993482634c4c5bcb39b0b6efd42fc2fc749f5c6e0da - languageName: node - linkType: hard - -"bluebird@npm:^3.5.0, bluebird@npm:^3.5.5": - version: 3.7.2 - resolution: "bluebird@npm:3.7.2" - checksum: 869417503c722e7dc54ca46715f70e15f4d9c602a423a02c825570862d12935be59ed9c7ba34a9b31f186c017c23cac6b54e35446f8353059c101da73eac22ef - languageName: node - linkType: hard - -"boolbase@npm:^1.0.0": - version: 1.0.0 - resolution: "boolbase@npm:1.0.0" - checksum: 3e25c80ef626c3a3487c73dbfc70ac322ec830666c9ad915d11b701142fab25ec1e63eff2c450c74347acfd2de854ccde865cd79ef4db1683f7c7b046ea43bb0 - languageName: node - linkType: hard - -"boolean@npm:^3.0.1": - version: 3.2.0 - resolution: "boolean@npm:3.2.0" - checksum: fb29535b8bf710ef45279677a86d14f5185d604557204abd2ca5fa3fb2a5c80e04d695c8dbf13ab269991977a79bb6c04b048220a6b2a3849853faa94f4a7d77 - languageName: node - linkType: hard - -"brace-expansion@npm:^1.1.7": - version: 1.1.11 - resolution: "brace-expansion@npm:1.1.11" - dependencies: - balanced-match: ^1.0.0 - concat-map: 0.0.1 - checksum: faf34a7bb0c3fcf4b59c7808bc5d2a96a40988addf2e7e09dfbb67a2251800e0d14cd2bfc1aa79174f2f5095c54ff27f46fb1289fe2d77dac755b5eb3434cc07 - languageName: node - linkType: hard - -"brace-expansion@npm:^2.0.1": - version: 2.0.1 - resolution: "brace-expansion@npm:2.0.1" - dependencies: - balanced-match: ^1.0.0 - checksum: a61e7cd2e8a8505e9f0036b3b6108ba5e926b4b55089eeb5550cd04a471fe216c96d4fe7e4c7f995c728c554ae20ddfc4244cad10aef255e72b62930afd233d1 - languageName: node - linkType: hard - -"braces@npm:^3.0.2": - version: 3.0.2 - resolution: "braces@npm:3.0.2" - dependencies: - fill-range: ^7.0.1 - checksum: e2a8e769a863f3d4ee887b5fe21f63193a891c68b612ddb4b68d82d1b5f3ff9073af066c343e9867a393fe4c2555dcb33e89b937195feb9c1613d259edfcd459 - languageName: node - linkType: hard - -"browser-id3-writer@npm:^5.0.0": - version: 5.0.0 - resolution: "browser-id3-writer@npm:5.0.0" - checksum: 6f775572fb8b06b9c66cabf178c10630f50461c36897214737b9cc21e64f5db3ceea2f10462f7203b7180e4e915f11993f0544fa69d4df96c0586ad26418b543 - languageName: node - linkType: hard - -"buffer-alloc-unsafe@npm:^1.1.0": - version: 1.1.0 - resolution: "buffer-alloc-unsafe@npm:1.1.0" - checksum: c5e18bf51f67754ec843c9af3d4c005051aac5008a3992938dda1344e5cfec77c4b02b4ca303644d1e9a6e281765155ce6356d85c6f5ccc5cd21afc868def396 - languageName: node - linkType: hard - -"buffer-alloc@npm:^1.2.0": - version: 1.2.0 - resolution: "buffer-alloc@npm:1.2.0" - dependencies: - buffer-alloc-unsafe: ^1.1.0 - buffer-fill: ^1.0.0 - checksum: 560cd27f3cbe73c614867da373407d4506309c62fe18de45a1ce191f3785ec6ca2488d802ff82065798542422980ca25f903db078c57822218182c37c3576df5 - languageName: node - linkType: hard - -"buffer-crc32@npm:~0.2.3": - version: 0.2.13 - resolution: "buffer-crc32@npm:0.2.13" - checksum: 06252347ae6daca3453b94e4b2f1d3754a3b146a111d81c68924c22d91889a40623264e95e67955b1cb4a68cbedf317abeabb5140a9766ed248973096db5ce1c - languageName: node - linkType: hard - -"buffer-equal@npm:^1.0.0": - version: 1.0.1 - resolution: "buffer-equal@npm:1.0.1" - checksum: 6ead0f976726c4e2fb6f2e82419983f4a99cbf2cca1f1e107e16c23c4d91d9046c732dd29b63fc6ac194354f74fa107e8e94946ef2527812d83cde1d5a006309 - languageName: node - linkType: hard - -"buffer-fill@npm:^1.0.0": - version: 1.0.0 - resolution: "buffer-fill@npm:1.0.0" - checksum: c29b4723ddeab01e74b5d3b982a0c6828f2ded49cef049ddca3dac661c874ecdbcecb5dd8380cf0f4adbeb8cff90a7de724126750a1f1e5ebd4eb6c59a1315b1 - languageName: node - linkType: hard - -"buffer-from@npm:^1.0.0": - version: 1.1.2 - resolution: "buffer-from@npm:1.1.2" - checksum: 0448524a562b37d4d7ed9efd91685a5b77a50672c556ea254ac9a6d30e3403a517d8981f10e565db24e8339413b43c97ca2951f10e399c6125a0d8911f5679bb - languageName: node - linkType: hard - -"buffer@npm:^5.1.0": - version: 5.7.1 - resolution: "buffer@npm:5.7.1" - dependencies: - base64-js: ^1.3.1 - ieee754: ^1.1.13 - checksum: e2cf8429e1c4c7b8cbd30834ac09bd61da46ce35f5c22a78e6c2f04497d6d25541b16881e30a019c6fd3154150650ccee27a308eff3e26229d788bbdeb08ab84 - languageName: node - linkType: hard - -"builder-util-runtime@npm:9.1.1": - version: 9.1.1 - resolution: "builder-util-runtime@npm:9.1.1" - dependencies: - debug: ^4.3.4 - sax: ^1.2.4 - checksum: 3458f9c8accad6e934c841cffa93f5d4b342c22b10b9c1a2eb3fd44ca96ea2c662b1048f9a075da9b8a4fada17206887b7e92ebdca331b1071520916e013e245 - languageName: node - linkType: hard - -"builder-util@npm:23.6.0": - version: 23.6.0 - resolution: "builder-util@npm:23.6.0" - dependencies: - 7zip-bin: ~5.1.1 - "@types/debug": ^4.1.6 - "@types/fs-extra": ^9.0.11 - app-builder-bin: 4.0.0 - bluebird-lst: ^1.0.9 - builder-util-runtime: 9.1.1 - chalk: ^4.1.1 - cross-spawn: ^7.0.3 - debug: ^4.3.4 - fs-extra: ^10.0.0 - http-proxy-agent: ^5.0.0 - https-proxy-agent: ^5.0.0 - is-ci: ^3.0.0 - js-yaml: ^4.1.0 - source-map-support: ^0.5.19 - stat-mode: ^1.0.0 - temp-file: ^3.4.0 - checksum: 138fb9abed01ea2e5ac895e6a6ed75310ca6c89e0050483c81801b052f61b42ae5a042f457088b6e205ec8b4403b1ff3a325955f110255afb4da2310e3cf14ad - languageName: node - linkType: hard - -"builtin-modules@npm:^3.3.0": - version: 3.3.0 - resolution: "builtin-modules@npm:3.3.0" - checksum: db021755d7ed8be048f25668fe2117620861ef6703ea2c65ed2779c9e3636d5c3b82325bd912244293959ff3ae303afa3471f6a15bf5060c103e4cc3a839749d - languageName: node - linkType: hard - -"builtins@npm:^5.0.1": - version: 5.0.1 - resolution: "builtins@npm:5.0.1" - dependencies: - semver: ^7.0.0 - checksum: 66d204657fe36522822a95b288943ad11b58f5eaede235b11d8c4edaa28ce4800087d44a2681524c340494aadb120a0068011acabe99d30e8f11a7d826d83515 - languageName: node - linkType: hard - -"busboy@npm:^1.6.0": - version: 1.6.0 - resolution: "busboy@npm:1.6.0" - dependencies: - streamsearch: ^1.1.0 - checksum: 32801e2c0164e12106bf236291a00795c3c4e4b709ae02132883fe8478ba2ae23743b11c5735a0aae8afe65ac4b6ca4568b91f0d9fed1fdbc32ede824a73746e - languageName: node - linkType: hard - -"butterchurn-presets@npm:^2.4.7": - version: 2.4.7 - resolution: "butterchurn-presets@npm:2.4.7" - dependencies: - babel-runtime: ^6.26.0 - ecma-proposal-math-extensions: 0.0.2 - lodash: ^4.17.4 - checksum: ae5f657eb0ef571996c4799be846c7875ef0ce6905eccddc28b25c12ffdabe1ee87e140dfca054ed4db9e644e83054472919b8d232c7055b43ed2da6a3018439 - languageName: node - linkType: hard - -"butterchurn@npm:^2.6.7": - version: 2.6.7 - resolution: "butterchurn@npm:2.6.7" - dependencies: - "@babel/runtime": ^7.0.0 - ecma-proposal-math-extensions: 0.0.2 - checksum: f780ec2195c79bee8f0c3e425d8721f3e439e750d4259e5784b5ef5a35410ded5dbf94c03189ffd16e031b00bba29305d1600a6aea72d35a470c834c50429bd3 - languageName: node - linkType: hard - -"cacache@npm:^16.1.0": - version: 16.1.3 - resolution: "cacache@npm:16.1.3" - dependencies: - "@npmcli/fs": ^2.1.0 - "@npmcli/move-file": ^2.0.0 - chownr: ^2.0.0 - fs-minipass: ^2.1.0 - glob: ^8.0.1 - infer-owner: ^1.0.4 - lru-cache: ^7.7.1 - minipass: ^3.1.6 - minipass-collect: ^1.0.2 - minipass-flush: ^1.0.5 - minipass-pipeline: ^1.2.4 - mkdirp: ^1.0.4 - p-map: ^4.0.0 - promise-inflight: ^1.0.1 - rimraf: ^3.0.2 - ssri: ^9.0.0 - tar: ^6.1.11 - unique-filename: ^2.0.0 - checksum: d91409e6e57d7d9a3a25e5dcc589c84e75b178ae8ea7de05cbf6b783f77a5fae938f6e8fda6f5257ed70000be27a681e1e44829251bfffe4c10216002f8f14e6 - languageName: node - linkType: hard - -"cacheable-lookup@npm:^5.0.3": - version: 5.0.4 - resolution: "cacheable-lookup@npm:5.0.4" - checksum: 763e02cf9196bc9afccacd8c418d942fc2677f22261969a4c2c2e760fa44a2351a81557bd908291c3921fe9beb10b976ba8fa50c5ca837c5a0dd945f16468f2d - languageName: node - linkType: hard - -"cacheable-request@npm:^7.0.2": - version: 7.0.2 - resolution: "cacheable-request@npm:7.0.2" - dependencies: - clone-response: ^1.0.2 - get-stream: ^5.1.0 - http-cache-semantics: ^4.0.0 - keyv: ^4.0.0 - lowercase-keys: ^2.0.0 - normalize-url: ^6.0.1 - responselike: ^2.0.0 - checksum: 6152813982945a5c9989cb457a6c499f12edcc7ade323d2fbfd759abc860bdbd1306e08096916bb413c3c47e812f8e4c0a0cc1e112c8ce94381a960f115bc77f - languageName: node - linkType: hard - -"call-bind@npm:^1.0.0, call-bind@npm:^1.0.2": - version: 1.0.2 - resolution: "call-bind@npm:1.0.2" - dependencies: - function-bind: ^1.1.1 - get-intrinsic: ^1.0.2 - checksum: f8e31de9d19988a4b80f3e704788c4a2d6b6f3d17cfec4f57dc29ced450c53a49270dc66bf0fbd693329ee948dd33e6c90a329519aef17474a4d961e8d6426b0 - languageName: node - linkType: hard - -"callsites@npm:^3.0.0": - version: 3.1.0 - resolution: "callsites@npm:3.1.0" - checksum: 072d17b6abb459c2ba96598918b55868af677154bec7e73d222ef95a8fdb9bbf7dae96a8421085cdad8cd190d86653b5b6dc55a4484f2e5b2e27d5e0c3fc15b3 - languageName: node - linkType: hard - -"camelcase-keys@npm:^7.0.0": - version: 7.0.2 - resolution: "camelcase-keys@npm:7.0.2" - dependencies: - camelcase: ^6.3.0 - map-obj: ^4.1.0 - quick-lru: ^5.1.1 - type-fest: ^1.2.1 - checksum: b5821cc48dd00e8398a30c5d6547f06837ab44de123f1b3a603d0a03399722b2fc67a485a7e47106eb02ef543c3b50c5ebaabc1242cde4b63a267c3258d2365b - languageName: node - linkType: hard - -"camelcase-keys@npm:^8.0.2": - version: 8.0.2 - resolution: "camelcase-keys@npm:8.0.2" - dependencies: - camelcase: ^7.0.0 - map-obj: ^4.3.0 - quick-lru: ^6.1.1 - type-fest: ^2.13.0 - checksum: 878fdaffa55737486101845232b2bc017fec95e06711d8a4133461cabf2432b55a59b20ff6afafce9b48a5629f25181bac3ecb10023032d3eb7cf3247c6e34f6 - languageName: node - linkType: hard - -"camelcase@npm:^6.3.0": - version: 6.3.0 - resolution: "camelcase@npm:6.3.0" - checksum: 8c96818a9076434998511251dcb2761a94817ea17dbdc37f47ac080bd088fc62c7369429a19e2178b993497132c8cbcf5cc1f44ba963e76782ba469c0474938d - languageName: node - linkType: hard - -"camelcase@npm:^7.0.0": - version: 7.0.1 - resolution: "camelcase@npm:7.0.1" - checksum: 86ab8f3ebf08bcdbe605a211a242f00ed30d8bfb77dab4ebb744dd36efbc84432d1c4adb28975ba87a1b8be40a80fbd1e60e2f06565315918fa7350011a26d3d - languageName: node - linkType: hard - -"chalk@npm:^2.0.0": - version: 2.4.2 - resolution: "chalk@npm:2.4.2" - dependencies: - ansi-styles: ^3.2.1 - escape-string-regexp: ^1.0.5 - supports-color: ^5.3.0 - checksum: ec3661d38fe77f681200f878edbd9448821924e0f93a9cefc0e26a33b145f1027a2084bf19967160d11e1f03bfe4eaffcabf5493b89098b2782c3fe0b03d80c2 - languageName: node - linkType: hard - -"chalk@npm:^4.0.0, chalk@npm:^4.0.2, chalk@npm:^4.1.0, chalk@npm:^4.1.1": - version: 4.1.2 - resolution: "chalk@npm:4.1.2" - dependencies: - ansi-styles: ^4.1.0 - supports-color: ^7.1.0 - checksum: fe75c9d5c76a7a98d45495b91b2172fa3b7a09e0cc9370e5c8feb1c567b85c4288e2b3fded7cfdd7359ac28d6b3844feb8b82b8686842e93d23c827c417e83fc - languageName: node - linkType: hard - -"charenc@npm:0.0.2": - version: 0.0.2 - resolution: "charenc@npm:0.0.2" - checksum: 81dcadbe57e861d527faf6dd3855dc857395a1c4d6781f4847288ab23cffb7b3ee80d57c15bba7252ffe3e5e8019db767757ee7975663ad2ca0939bb8fcaf2e5 - languageName: node - linkType: hard - -"chownr@npm:^2.0.0": - version: 2.0.0 - resolution: "chownr@npm:2.0.0" - checksum: c57cf9dd0791e2f18a5ee9c1a299ae6e801ff58fee96dc8bfd0dcb4738a6ce58dd252a3605b1c93c6418fe4f9d5093b28ffbf4d66648cb2a9c67eaef9679be2f - languageName: node - linkType: hard - -"chromium-pickle-js@npm:^0.2.0": - version: 0.2.0 - resolution: "chromium-pickle-js@npm:0.2.0" - checksum: 5ccacc538b0a1ecf3484c8fb3327eae129ceee858db0f64eb0a5ff87bda096a418d0d3e6f6e0967c6334d336a2c7463f7b683ec0e1cafbe736907fa2ee2f58ca - languageName: node - linkType: hard - -"ci-info@npm:^3.2.0, ci-info@npm:^3.4.0": - version: 3.8.0 - resolution: "ci-info@npm:3.8.0" - checksum: d0a4d3160497cae54294974a7246202244fff031b0a6ea20dd57b10ec510aa17399c41a1b0982142c105f3255aff2173e5c0dd7302ee1b2f28ba3debda375098 - languageName: node - linkType: hard - -"clean-regexp@npm:^1.0.0": - version: 1.0.0 - resolution: "clean-regexp@npm:1.0.0" - dependencies: - escape-string-regexp: ^1.0.5 - checksum: 0b1ce281b07da2463c6882ea2e8409119b6cabbd9f687cdbdcee942c45b2b9049a2084f7b5f228c63ef9f21e722963ae0bfe56a735dbdbdd92512867625a7e40 - languageName: node - linkType: hard - -"clean-stack@npm:^2.0.0, clean-stack@npm:^2.1.0": - version: 2.2.0 - resolution: "clean-stack@npm:2.2.0" - checksum: 2ac8cd2b2f5ec986a3c743935ec85b07bc174d5421a5efc8017e1f146a1cf5f781ae962618f416352103b32c9cd7e203276e8c28241bbe946160cab16149fb68 - languageName: node - linkType: hard - -"clean-stack@npm:^4.0.0": - version: 4.2.0 - resolution: "clean-stack@npm:4.2.0" - dependencies: - escape-string-regexp: 5.0.0 - checksum: 373f656a31face5c615c0839213b9b542a0a48057abfb1df66900eab4dc2a5c6097628e4a0b5aa559cdfc4e66f8a14ea47be9681773165a44470ef5fb8ccc172 - languageName: node - linkType: hard - -"cli-truncate@npm:^2.1.0": - version: 2.1.0 - resolution: "cli-truncate@npm:2.1.0" - dependencies: - slice-ansi: ^3.0.0 - string-width: ^4.2.0 - checksum: bf1e4e6195392dc718bf9cd71f317b6300dc4a9191d052f31046b8773230ece4fa09458813bf0e3455a5e68c0690d2ea2c197d14a8b85a7b5e01c97f4b5feb5d - languageName: node - linkType: hard - -"cliui@npm:^8.0.1": - version: 8.0.1 - resolution: "cliui@npm:8.0.1" - dependencies: - string-width: ^4.2.0 - strip-ansi: ^6.0.1 - wrap-ansi: ^7.0.0 - checksum: 79648b3b0045f2e285b76fb2e24e207c6db44323581e421c3acbd0e86454cba1b37aea976ab50195a49e7384b871e6dfb2247ad7dec53c02454ac6497394cb56 - languageName: node - linkType: hard - -"clone-response@npm:^1.0.2": - version: 1.0.3 - resolution: "clone-response@npm:1.0.3" - dependencies: - mimic-response: ^1.0.0 - checksum: 4e671cac39b11c60aa8ba0a450657194a5d6504df51bca3fac5b3bd0145c4f8e8464898f87c8406b83232e3bc5cca555f51c1f9c8ac023969ebfbf7f6bdabb2e - languageName: node - linkType: hard - -"color-convert@npm:^1.9.0": - version: 1.9.3 - resolution: "color-convert@npm:1.9.3" - dependencies: - color-name: 1.1.3 - checksum: fd7a64a17cde98fb923b1dd05c5f2e6f7aefda1b60d67e8d449f9328b4e53b228a428fd38bfeaeb2db2ff6b6503a776a996150b80cdf224062af08a5c8a3a203 - languageName: node - linkType: hard - -"color-convert@npm:^2.0.1": - version: 2.0.1 - resolution: "color-convert@npm:2.0.1" - dependencies: - color-name: ~1.1.4 - checksum: 79e6bdb9fd479a205c71d89574fccfb22bd9053bd98c6c4d870d65c132e5e904e6034978e55b43d69fcaa7433af2016ee203ce76eeba9cfa554b373e7f7db336 - languageName: node - linkType: hard - -"color-name@npm:1.1.3": - version: 1.1.3 - resolution: "color-name@npm:1.1.3" - checksum: 09c5d3e33d2105850153b14466501f2bfb30324a2f76568a408763a3b7433b0e50e5b4ab1947868e65cb101bb7cb75029553f2c333b6d4b8138a73fcc133d69d - languageName: node - linkType: hard - -"color-name@npm:~1.1.4": - version: 1.1.4 - resolution: "color-name@npm:1.1.4" - checksum: b0445859521eb4021cd0fb0cc1a75cecf67fceecae89b63f62b201cca8d345baf8b952c966862a9d9a2632987d4f6581f0ec8d957dfacece86f0a7919316f610 - languageName: node - linkType: hard - -"color-support@npm:^1.1.3": - version: 1.1.3 - resolution: "color-support@npm:1.1.3" - bin: - color-support: bin.js - checksum: 9b7356817670b9a13a26ca5af1c21615463b500783b739b7634a0c2047c16cef4b2865d7576875c31c3cddf9dd621fa19285e628f20198b233a5cfdda6d0793b - languageName: node - linkType: hard - -"combined-stream@npm:^1.0.8": - version: 1.0.8 - resolution: "combined-stream@npm:1.0.8" - dependencies: - delayed-stream: ~1.0.0 - checksum: 49fa4aeb4916567e33ea81d088f6584749fc90c7abec76fd516bf1c5aa5c79f3584b5ba3de6b86d26ddd64bae5329c4c7479343250cfe71c75bb366eae53bb7c - languageName: node - linkType: hard - -"commander@npm:^5.0.0": - version: 5.1.0 - resolution: "commander@npm:5.1.0" - checksum: 0b7fec1712fbcc6230fcb161d8d73b4730fa91a21dc089515489402ad78810547683f058e2a9835929c212fead1d6a6ade70db28bbb03edbc2829a9ab7d69447 - languageName: node - linkType: hard - -"commander@npm:^7.2.0": - version: 7.2.0 - resolution: "commander@npm:7.2.0" - checksum: 53501cbeee61d5157546c0bef0fedb6cdfc763a882136284bed9a07225f09a14b82d2a84e7637edfd1a679fb35ed9502fd58ef1d091e6287f60d790147f68ddc - languageName: node - linkType: hard - -"common-path-prefix@npm:^3.0.0": - version: 3.0.0 - resolution: "common-path-prefix@npm:3.0.0" - checksum: fdb3c4f54e51e70d417ccd950c07f757582de800c0678ca388aedefefc84982039f346f9fd9a1252d08d2da9e9ef4019f580a1d1d3a10da031e4bb3c924c5818 - languageName: node - linkType: hard - -"compare-version@npm:^0.1.2": - version: 0.1.2 - resolution: "compare-version@npm:0.1.2" - checksum: 0ceaf50b5f912c8eb8eeca19375e617209d200abebd771e9306510166462e6f91ad764f33f210a3058ee27c83f2f001a7a4ca32f509da2d207d0143a3438a020 - languageName: node - linkType: hard - -"concat-map@npm:0.0.1": - version: 0.0.1 - resolution: "concat-map@npm:0.0.1" - checksum: 902a9f5d8967a3e2faf138d5cb784b9979bad2e6db5357c5b21c568df4ebe62bcb15108af1b2253744844eb964fc023fbd9afbbbb6ddd0bcc204c6fb5b7bf3af - languageName: node - linkType: hard - -"conf@npm:^10.2.0": - version: 10.2.0 - resolution: "conf@npm:10.2.0" - dependencies: - ajv: ^8.6.3 - ajv-formats: ^2.1.1 - atomically: ^1.7.0 - debounce-fn: ^4.0.0 - dot-prop: ^6.0.1 - env-paths: ^2.2.1 - json-schema-typed: ^7.0.3 - onetime: ^5.1.2 - pkg-up: ^3.1.0 - semver: ^7.3.5 - checksum: 27066f38a25411c1e72e81a5219e2c7ed675cd39d8aa2a2f1797bb2c9255725e92e335d639334177a23d488b22b1290bbe0708e9a005574e5d83d5432df72bd3 - languageName: node - linkType: hard - -"confusing-browser-globals@npm:1.0.11": - version: 1.0.11 - resolution: "confusing-browser-globals@npm:1.0.11" - checksum: 3afc635abd37e566477f610e7978b15753f0e84025c25d49236f1f14d480117185516bdd40d2a2167e6bed8048641a9854964b9c067e3dcdfa6b5d0ad3c3a5ef - languageName: node - linkType: hard - -"console-control-strings@npm:^1.1.0": - version: 1.1.0 - resolution: "console-control-strings@npm:1.1.0" - checksum: 8755d76787f94e6cf79ce4666f0c5519906d7f5b02d4b884cf41e11dcd759ed69c57da0670afd9236d229a46e0f9cf519db0cd829c6dca820bb5a5c3def584ed - languageName: node - linkType: hard - -"core-js@npm:^2.4.0": - version: 2.6.12 - resolution: "core-js@npm:2.6.12" - checksum: 44fa9934a85f8c78d61e0c8b7b22436330471ffe59ec5076fe7f324d6e8cf7f824b14b1c81ca73608b13bdb0fef035bd820989bf059767ad6fa13123bb8bd016 - languageName: node - linkType: hard - -"core-util-is@npm:1.0.2": - version: 1.0.2 - resolution: "core-util-is@npm:1.0.2" - checksum: 7a4c925b497a2c91421e25bf76d6d8190f0b2359a9200dbeed136e63b2931d6294d3b1893eda378883ed363cd950f44a12a401384c609839ea616befb7927dab - languageName: node - linkType: hard - -"core-util-is@npm:~1.0.0": - version: 1.0.3 - resolution: "core-util-is@npm:1.0.3" - checksum: 9de8597363a8e9b9952491ebe18167e3b36e7707569eed0ebf14f8bba773611376466ae34575bca8cfe3c767890c859c74056084738f09d4e4a6f902b2ad7d99 - languageName: node - linkType: hard - -"cosmiconfig@npm:^7.1.0": - version: 7.1.0 - resolution: "cosmiconfig@npm:7.1.0" - dependencies: - "@types/parse-json": ^4.0.0 - import-fresh: ^3.2.1 - parse-json: ^5.0.0 - path-type: ^4.0.0 - yaml: ^1.10.0 - checksum: c53bf7befc1591b2651a22414a5e786cd5f2eeaa87f3678a3d49d6069835a9d8d1aef223728e98aa8fec9a95bf831120d245096db12abe019fecb51f5696c96f - languageName: node - linkType: hard - -"crc@npm:^3.8.0": - version: 3.8.0 - resolution: "crc@npm:3.8.0" - dependencies: - buffer: ^5.1.0 - checksum: dabbc4eba223b206068b92ca82bb471d583eb6be2384a87f5c3712730cfd6ba4b13a45e8ba3ef62174d5a781a2c5ac5c20bf36cf37bba73926899bd0aa19186f - languageName: node - linkType: hard - -"cross-spawn@npm:^7.0.1, cross-spawn@npm:^7.0.2, cross-spawn@npm:^7.0.3": - version: 7.0.3 - resolution: "cross-spawn@npm:7.0.3" - dependencies: - path-key: ^3.1.0 - shebang-command: ^2.0.0 - which: ^2.0.1 - checksum: 671cc7c7288c3a8406f3c69a3ae2fc85555c04169e9d611def9a675635472614f1c0ed0ef80955d5b6d4e724f6ced67f0ad1bb006c2ea643488fcfef994d7f52 - languageName: node - linkType: hard - -"crypt@npm:0.0.2": - version: 0.0.2 - resolution: "crypt@npm:0.0.2" - checksum: baf4c7bbe05df656ec230018af8cf7dbe8c14b36b98726939cef008d473f6fe7a4fad906cfea4062c93af516f1550a3f43ceb4d6615329612c6511378ed9fe34 - languageName: node - linkType: hard - -"css-select@npm:^5.1.0": - version: 5.1.0 - resolution: "css-select@npm:5.1.0" - dependencies: - boolbase: ^1.0.0 - css-what: ^6.1.0 - domhandler: ^5.0.2 - domutils: ^3.0.1 - nth-check: ^2.0.1 - checksum: 2772c049b188d3b8a8159907192e926e11824aea525b8282981f72ba3f349cf9ecd523fdf7734875ee2cb772246c22117fc062da105b6d59afe8dcd5c99c9bda - languageName: node - linkType: hard - -"css-what@npm:^6.1.0": - version: 6.1.0 - resolution: "css-what@npm:6.1.0" - checksum: b975e547e1e90b79625918f84e67db5d33d896e6de846c9b584094e529f0c63e2ab85ee33b9daffd05bff3a146a1916bec664e18bb76dd5f66cbff9fc13b2bbe - languageName: node - linkType: hard - -"cssom@npm:^0.5.0": - version: 0.5.0 - resolution: "cssom@npm:0.5.0" - checksum: 823471aa30091c59e0a305927c30e7768939b6af70405808f8d2ce1ca778cddcb24722717392438329d1691f9a87cb0183b64b8d779b56a961546d54854fde01 - languageName: node - linkType: hard - -"custom-electron-prompt@npm:^1.5.7": - version: 1.5.7 - resolution: "custom-electron-prompt@npm:1.5.7" - peerDependencies: - electron: ">=10.0.0" - checksum: 7dd7b2fb6e0acdee35474893d0e98b5e701c411c76be716cc02c5c9ac42db4fdaa7d526e22fd8c7047c2f143559d185bed8731bd455a1d11982404512d5f5021 - languageName: node - linkType: hard - -"custom-electron-titlebar@npm:^4.1.6": - version: 4.1.6 - resolution: "custom-electron-titlebar@npm:4.1.6" - peerDependencies: - electron: ">20" - checksum: e08db7ef87bf8eb3685ca97bb966239d5b3083bc11704087f03c8c6f25143094844fbf2eea7b809ec9612f1b4e28b37a2688547a6cc88e2ab50e2087241c29d3 - languageName: node - linkType: hard - -"dbus-next@npm:^0.9.2": - version: 0.9.2 - resolution: "dbus-next@npm:0.9.2" - dependencies: - "@nornagon/put": 0.0.8 - abstract-socket: ^2.0.0 - event-stream: 3.3.4 - hexy: ^0.2.10 - jsbi: ^2.0.5 - long: ^4.0.0 - safe-buffer: ^5.1.1 - xml2js: ^0.4.17 - dependenciesMeta: - abstract-socket: - optional: true - checksum: 71a87451f7fcd574066162d1e91dc0a6ba456fe0e8fb23319b23ee8bfcd24987151bf99538ecaf69b5c5143486a20c6ed1fb48e4184fa14aad0b7c50f189fd6e - languageName: node - linkType: hard - -"debounce-fn@npm:^4.0.0": - version: 4.0.0 - resolution: "debounce-fn@npm:4.0.0" - dependencies: - mimic-fn: ^3.0.0 - checksum: 7bf8d142b46a88453bbd6eda083f303049b4c8554af5114bdadfc2da56031030664360e81211ae08b708775e6904db7e6d72a421c4ff473344f4521c2c5e4a22 - languageName: node - linkType: hard - -"debug@npm:4, debug@npm:^4.0.1, debug@npm:^4.1.0, debug@npm:^4.1.1, debug@npm:^4.3.1, debug@npm:^4.3.2, debug@npm:^4.3.3, debug@npm:^4.3.4": - version: 4.3.4 - resolution: "debug@npm:4.3.4" - dependencies: - ms: 2.1.2 - peerDependenciesMeta: - supports-color: - optional: true - checksum: 3dbad3f94ea64f34431a9cbf0bafb61853eda57bff2880036153438f50fb5a84f27683ba0d8e5426bf41a8c6ff03879488120cf5b3a761e77953169c0600a708 - languageName: node - linkType: hard - -"debug@npm:^2.6.8": - version: 2.6.9 - resolution: "debug@npm:2.6.9" - dependencies: - ms: 2.0.0 - checksum: d2f51589ca66df60bf36e1fa6e4386b318c3f1e06772280eea5b1ae9fd3d05e9c2b7fd8a7d862457d00853c75b00451aa2d7459b924629ee385287a650f58fe6 - languageName: node - linkType: hard - -"debug@npm:^3.2.7": - version: 3.2.7 - resolution: "debug@npm:3.2.7" - dependencies: - ms: ^2.1.1 - checksum: b3d8c5940799914d30314b7c3304a43305fd0715581a919dacb8b3176d024a782062368405b47491516d2091d6462d4d11f2f4974a405048094f8bfebfa3071c - languageName: node - linkType: hard - -"decamelize-keys@npm:^1.1.0": - version: 1.1.1 - resolution: "decamelize-keys@npm:1.1.1" - dependencies: - decamelize: ^1.1.0 - map-obj: ^1.0.0 - checksum: fc645fe20b7bda2680bbf9481a3477257a7f9304b1691036092b97ab04c0ab53e3bf9fcc2d2ae382536568e402ec41fb11e1d4c3836a9abe2d813dd9ef4311e0 - languageName: node - linkType: hard - -"decamelize@npm:^1.1.0": - version: 1.2.0 - resolution: "decamelize@npm:1.2.0" - checksum: ad8c51a7e7e0720c70ec2eeb1163b66da03e7616d7b98c9ef43cce2416395e84c1e9548dd94f5f6ffecfee9f8b94251fc57121a8b021f2ff2469b2bae247b8aa - languageName: node - linkType: hard - -"decamelize@npm:^5.0.0": - version: 5.0.1 - resolution: "decamelize@npm:5.0.1" - checksum: 7c3b1ed4b3e60e7fbc00a35fb248298527c1cdfe603e41dfcf05e6c4a8cb9efbee60630deb677ed428908fb4e74e322966c687a094d1478ddc9c3a74e9dc7140 - languageName: node - linkType: hard - -"decamelize@npm:^6.0.0": - version: 6.0.0 - resolution: "decamelize@npm:6.0.0" - checksum: 0066bc30798ec11e01adf0c19ad975caef86545d4bb6f70cfb90b7eb8e3cbf7974cf774ac2e6ea2586e4e07b1f654bfecc4e772c42128a79a89f8584fc546753 - languageName: node - linkType: hard - -"decompress-response@npm:^6.0.0": - version: 6.0.0 - resolution: "decompress-response@npm:6.0.0" - dependencies: - mimic-response: ^3.1.0 - checksum: d377cf47e02d805e283866c3f50d3d21578b779731e8c5072d6ce8c13cc31493db1c2f6784da9d1d5250822120cefa44f1deab112d5981015f2e17444b763812 - languageName: node - linkType: hard - -"deep-equal@npm:^1.0.1": - version: 1.1.1 - resolution: "deep-equal@npm:1.1.1" - dependencies: - is-arguments: ^1.0.4 - is-date-object: ^1.0.1 - is-regex: ^1.0.4 - object-is: ^1.0.1 - object-keys: ^1.1.1 - regexp.prototype.flags: ^1.2.0 - checksum: f92686f2c5bcdf714a75a5fa7a9e47cb374a8ec9307e717b8d1ce61f56a75aaebf5619c2a12b8087a705b5a2f60d0292c35f8b58cb1f72e3268a3a15cab9f78d - languageName: node - linkType: hard - -"deep-is@npm:^0.1.3": - version: 0.1.4 - resolution: "deep-is@npm:0.1.4" - checksum: edb65dd0d7d1b9c40b2f50219aef30e116cedd6fc79290e740972c132c09106d2e80aa0bc8826673dd5a00222d4179c84b36a790eef63a4c4bca75a37ef90804 - languageName: node - linkType: hard - -"deepmerge@npm:^4.3.1": - version: 4.3.1 - resolution: "deepmerge@npm:4.3.1" - checksum: 2024c6a980a1b7128084170c4cf56b0fd58a63f2da1660dcfe977415f27b17dbe5888668b59d0b063753f3220719d5e400b7f113609489c90160bb9a5518d052 - languageName: node - linkType: hard - -"defer-to-connect@npm:^2.0.0": - version: 2.0.1 - resolution: "defer-to-connect@npm:2.0.1" - checksum: 8a9b50d2f25446c0bfefb55a48e90afd58f85b21bcf78e9207cd7b804354f6409032a1705c2491686e202e64fc05f147aa5aa45f9aa82627563f045937f5791b - languageName: node - linkType: hard - -"define-lazy-prop@npm:^2.0.0": - version: 2.0.0 - resolution: "define-lazy-prop@npm:2.0.0" - checksum: 0115fdb065e0490918ba271d7339c42453d209d4cb619dfe635870d906731eff3e1ade8028bb461ea27ce8264ec5e22c6980612d332895977e89c1bbc80fcee2 - languageName: node - linkType: hard - -"define-lazy-prop@npm:^3.0.0": - version: 3.0.0 - resolution: "define-lazy-prop@npm:3.0.0" - checksum: 54884f94caac0791bf6395a3ec530ce901cf71c47b0196b8754f3fd17edb6c0e80149c1214429d851873bb0d689dbe08dcedbb2306dc45c8534a5934723851b6 - languageName: node - linkType: hard - -"define-properties@npm:^1.1.3, define-properties@npm:^1.1.4": - version: 1.2.0 - resolution: "define-properties@npm:1.2.0" - dependencies: - has-property-descriptors: ^1.0.0 - object-keys: ^1.1.1 - checksum: e60aee6a19b102df4e2b1f301816804e81ab48bb91f00d0d935f269bf4b3f79c88b39e4f89eaa132890d23267335fd1140dfcd8d5ccd61031a0a2c41a54e33a6 - languageName: node - linkType: hard - -"del-cli@npm:^5.0.0": - version: 5.0.0 - resolution: "del-cli@npm:5.0.0" - dependencies: - del: ^7.0.0 - meow: ^10.1.3 - bin: - del: cli.js - del-cli: cli.js - checksum: 1f21bbdf3ad3d6a2e61ac3041a072b5a0c36b5e02154d62c0b130fa879b0b6b07d6e85889ce7cd9e333b294d57a9fa8866b243be9da49a6d5050e1d917389672 - languageName: node - linkType: hard - -"del@npm:^7.0.0": - version: 7.0.0 - resolution: "del@npm:7.0.0" - dependencies: - globby: ^13.1.2 - graceful-fs: ^4.2.10 - is-glob: ^4.0.3 - is-path-cwd: ^3.0.0 - is-path-inside: ^4.0.0 - p-map: ^5.5.0 - rimraf: ^3.0.2 - slash: ^4.0.0 - checksum: 33e5077f18b5dfbe81971d1f8a2cd8bf676dd5ede491bab85ec17a4a1d59001bd3ec47fd38e9a4ae01a3c98c07b98c7b3dc56190b86d88926798802d7858d827 - languageName: node - linkType: hard - -"delayed-stream@npm:~1.0.0": - version: 1.0.0 - resolution: "delayed-stream@npm:1.0.0" - checksum: 46fe6e83e2cb1d85ba50bd52803c68be9bd953282fa7096f51fc29edd5d67ff84ff753c51966061e5ba7cb5e47ef6d36a91924eddb7f3f3483b1c560f77a0020 - languageName: node - linkType: hard - -"delegates@npm:^1.0.0": - version: 1.0.0 - resolution: "delegates@npm:1.0.0" - checksum: a51744d9b53c164ba9c0492471a1a2ffa0b6727451bdc89e31627fdf4adda9d51277cfcbfb20f0a6f08ccb3c436f341df3e92631a3440226d93a8971724771fd - languageName: node - linkType: hard - -"depd@npm:^2.0.0": - version: 2.0.0 - resolution: "depd@npm:2.0.0" - checksum: abbe19c768c97ee2eed6282d8ce3031126662252c58d711f646921c9623f9052e3e1906443066beec1095832f534e57c523b7333f8e7e0d93051ab6baef5ab3a - languageName: node - linkType: hard - -"detect-node@npm:^2.0.4": - version: 2.1.0 - resolution: "detect-node@npm:2.1.0" - checksum: 832184ec458353e41533ac9c622f16c19f7c02d8b10c303dfd3a756f56be93e903616c0bb2d4226183c9351c15fc0b3dba41a17a2308262afabcfa3776e6ae6e - languageName: node - linkType: hard - -"dir-compare@npm:^3.0.0": - version: 3.3.0 - resolution: "dir-compare@npm:3.3.0" - dependencies: - buffer-equal: ^1.0.0 - minimatch: ^3.0.4 - checksum: 05e7381509b17cb4e6791bd9569c12ce4267f44b1ee36594946ed895ed7ad24da9285130dc42af3a60707d58c76307bb3a1cbae2acd0a9cce8c74664e6a26828 - languageName: node - linkType: hard - -"dir-glob@npm:^3.0.1": - version: 3.0.1 - resolution: "dir-glob@npm:3.0.1" - dependencies: - path-type: ^4.0.0 - checksum: fa05e18324510d7283f55862f3161c6759a3f2f8dbce491a2fc14c8324c498286c54282c1f0e933cb930da8419b30679389499b919122952a4f8592362ef4615 - languageName: node - linkType: hard - -"discord-api-types@npm:^0.37.37": - version: 0.37.38 - resolution: "discord-api-types@npm:0.37.38" - checksum: 58972778639234307ae6c0ce5b841a8a3a29c38116aa9f96051e65a88f6bbc4f1df671c5a985712d816764507308f8ebc97b1c98dad8de7bf756e05819db84ca - languageName: node - linkType: hard - -"dmg-builder@npm:23.6.0": - version: 23.6.0 - resolution: "dmg-builder@npm:23.6.0" - dependencies: - app-builder-lib: 23.6.0 - builder-util: 23.6.0 - builder-util-runtime: 9.1.1 - dmg-license: ^1.0.11 - fs-extra: ^10.0.0 - iconv-lite: ^0.6.2 - js-yaml: ^4.1.0 - dependenciesMeta: - dmg-license: - optional: true - checksum: 3e37a4b191cf40c9c7b97d07408c2bf58e7632d78de0dc49a142fb7c68670fd2a7123f31ee8803b3cd100f38feea7b785c28698dfaace508254659d81ecc0b80 - languageName: node - linkType: hard - -"dmg-license@npm:^1.0.11": - version: 1.0.11 - resolution: "dmg-license@npm:1.0.11" - dependencies: - "@types/plist": ^3.0.1 - "@types/verror": ^1.10.3 - ajv: ^6.10.0 - crc: ^3.8.0 - iconv-corefoundation: ^1.1.7 - plist: ^3.0.4 - smart-buffer: ^4.0.2 - verror: ^1.10.0 - bin: - dmg-license: bin/dmg-license.js - conditions: os=darwin - languageName: node - linkType: hard - -"doctrine@npm:^2.1.0": - version: 2.1.0 - resolution: "doctrine@npm:2.1.0" - dependencies: - esutils: ^2.0.2 - checksum: a45e277f7feaed309fe658ace1ff286c6e2002ac515af0aaf37145b8baa96e49899638c7cd47dccf84c3d32abfc113246625b3ac8f552d1046072adee13b0dc8 - languageName: node - linkType: hard - -"doctrine@npm:^3.0.0": - version: 3.0.0 - resolution: "doctrine@npm:3.0.0" - dependencies: - esutils: ^2.0.2 - checksum: fd7673ca77fe26cd5cba38d816bc72d641f500f1f9b25b83e8ce28827fe2da7ad583a8da26ab6af85f834138cf8dae9f69b0cd6ab925f52ddab1754db44d99ce - languageName: node - linkType: hard - -"dom-serializer@npm:^2.0.0": - version: 2.0.0 - resolution: "dom-serializer@npm:2.0.0" - dependencies: - domelementtype: ^2.3.0 - domhandler: ^5.0.2 - entities: ^4.2.0 - checksum: cd1810544fd8cdfbd51fa2c0c1128ec3a13ba92f14e61b7650b5de421b88205fd2e3f0cc6ace82f13334114addb90ed1c2f23074a51770a8e9c1273acbc7f3e6 - languageName: node - linkType: hard - -"domelementtype@npm:^2.3.0": - version: 2.3.0 - resolution: "domelementtype@npm:2.3.0" - checksum: ee837a318ff702622f383409d1f5b25dd1024b692ef64d3096ff702e26339f8e345820f29a68bcdcea8cfee3531776b3382651232fbeae95612d6f0a75efb4f6 - languageName: node - linkType: hard - -"domhandler@npm:^5.0.1, domhandler@npm:^5.0.2, domhandler@npm:^5.0.3": - version: 5.0.3 - resolution: "domhandler@npm:5.0.3" - dependencies: - domelementtype: ^2.3.0 - checksum: 0f58f4a6af63e6f3a4320aa446d28b5790a009018707bce2859dcb1d21144c7876482b5188395a188dfa974238c019e0a1e610d2fc269a12b2c192ea2b0b131c - languageName: node - linkType: hard - -"domutils@npm:^3.0.1": - version: 3.0.1 - resolution: "domutils@npm:3.0.1" - dependencies: - dom-serializer: ^2.0.0 - domelementtype: ^2.3.0 - domhandler: ^5.0.1 - checksum: 23aa7a840572d395220e173cb6263b0d028596e3950100520870a125af33ff819e6f609e1606d6f7d73bd9e7feb03bb404286e57a39063b5384c62b724d987b3 - languageName: node - linkType: hard - -"dot-prop@npm:^6.0.1": - version: 6.0.1 - resolution: "dot-prop@npm:6.0.1" - dependencies: - is-obj: ^2.0.0 - checksum: 0f47600a4b93e1dc37261da4e6909652c008832a5d3684b5bf9a9a0d3f4c67ea949a86dceed9b72f5733ed8e8e6383cc5958df3bbd0799ee317fd181f2ece700 - languageName: node - linkType: hard - -"dotenv-expand@npm:^5.1.0": - version: 5.1.0 - resolution: "dotenv-expand@npm:5.1.0" - checksum: 8017675b7f254384915d55f9eb6388e577cf0a1231a28d54b0ca03b782be9501b0ac90ac57338636d395fa59051e6209e9b44b8ddf169ce6076dffb5dea227d3 - languageName: node - linkType: hard - -"dotenv@npm:^9.0.2": - version: 9.0.2 - resolution: "dotenv@npm:9.0.2" - checksum: 6b7980330a653089bc9b83362248547791151ee74f9881eb223ac2f4d641b174b708f77315d88708b551d45b4177afd3ba71bca4832f8807e003f71c2a0f83e7 - languageName: node - linkType: hard - -"duplexer@npm:~0.1.1": - version: 0.1.2 - resolution: "duplexer@npm:0.1.2" - checksum: 62ba61a830c56801db28ff6305c7d289b6dc9f859054e8c982abd8ee0b0a14d2e9a8e7d086ffee12e868d43e2bbe8a964be55ddbd8c8957714c87373c7a4f9b0 - languageName: node - linkType: hard - -"ecma-proposal-math-extensions@npm:0.0.2": - version: 0.0.2 - resolution: "ecma-proposal-math-extensions@npm:0.0.2" - checksum: e897547688b5b2f99a0aaec440bcddeb323a82ade961686dc25628e70c636dd8112f940358664f1b2bd0013cf0ff753b0497afaf654bedd94f628fa143b72c53 - languageName: node - linkType: hard - -"ejs@npm:^3.1.7": - version: 3.1.9 - resolution: "ejs@npm:3.1.9" - dependencies: - jake: ^10.8.5 - bin: - ejs: bin/cli.js - checksum: af6f10eb815885ff8a8cfacc42c6b6cf87daf97a4884f87a30e0c3271fedd85d76a3a297d9c33a70e735b97ee632887f85e32854b9cdd3a2d97edf931519a35f - languageName: node - linkType: hard - -"electron-better-web-request@npm:^1.0.1": - version: 1.0.1 - resolution: "electron-better-web-request@npm:1.0.1" - dependencies: - url-match-patterns: ^0.2.0 - uuid: ^3.3.2 - checksum: 3f424e66004af466e2ff6aad49783e2601727a5e8259edb2588cee5f04e82f2c3818ccadb415e67d567dd0484c40cbb676ce89a10444df38fec254a0346f362b - languageName: node - linkType: hard - -"electron-builder@npm:^23.6.0": - version: 23.6.0 - resolution: "electron-builder@npm:23.6.0" - dependencies: - "@types/yargs": ^17.0.1 - app-builder-lib: 23.6.0 - builder-util: 23.6.0 - builder-util-runtime: 9.1.1 - chalk: ^4.1.1 - dmg-builder: 23.6.0 - fs-extra: ^10.0.0 - is-ci: ^3.0.0 - lazy-val: ^1.0.5 - read-config-file: 6.2.0 - simple-update-notifier: ^1.0.7 - yargs: ^17.5.1 - bin: - electron-builder: cli.js - install-app-deps: install-app-deps.js - checksum: 227f8fb9c9bb11a11d999f2ade6a5cd1afb720d6ff5053c88b4be62d1265b6268c8f6b4b3b8ad6d0a7261d57ea5acd6619ef301b843865f260b616c474cf8cbd - languageName: node - linkType: hard - -"electron-debug@npm:^3.2.0": - version: 3.2.0 - resolution: "electron-debug@npm:3.2.0" - dependencies: - electron-is-dev: ^1.1.0 - electron-localshortcut: ^3.1.0 - checksum: 40b1669ff7abbbd3ce483f3bbb9620bbc7cffd8073110a53a9a3083249efdcdea2913bf1ae5f6b74f49e4dad761eec872c31cab1b4569b34356ea41f334ce4f2 - languageName: node - linkType: hard - -"electron-devtools-installer@npm:^3.2.0": - version: 3.2.0 - resolution: "electron-devtools-installer@npm:3.2.0" - dependencies: - rimraf: ^3.0.2 - semver: ^7.2.1 - tslib: ^2.1.0 - unzip-crx-3: ^0.2.0 - checksum: e87d4c9283f84ac610e9ee37d72677f18feed05174e9d5bf0415a56c3daac717e3f34a5a763499aff7fc2e565660d2ad66beb95d960e8176ed148acf1c3a416b - languageName: node - linkType: hard - -"electron-is-accelerator@npm:^0.1.0": - version: 0.1.2 - resolution: "electron-is-accelerator@npm:0.1.2" - checksum: 2bc05a0acf9c252d636b48c716ad0a8c2f29875559b87c666852575310c17fc8350907a6f09412d6cbcc71da42f0228a0869fb68c3ead15e8211d5f13fcdbd17 - languageName: node - linkType: hard - -"electron-is-dev@npm:2.0.0": - version: 2.0.0 - resolution: "electron-is-dev@npm:2.0.0" - checksum: 7393f46f06153d70a427ea904c60a092e50fbf1015c26c342cebb8324ada8c9e0c0f1f02867af56d9cc76f47be17da8cb311ea6bdc83343e7ebd2323ec4014c8 - languageName: node - linkType: hard - -"electron-is-dev@patch:electron-is-dev@npm%3A2.0.0#./.yarn/patches/electron-is-dev-npm-2.0.0-9d41637d91.patch::locator=youtube-music%40workspace%3A.": - version: 2.0.0 - resolution: "electron-is-dev@patch:electron-is-dev@npm%3A2.0.0#./.yarn/patches/electron-is-dev-npm-2.0.0-9d41637d91.patch::version=2.0.0&hash=64e927&locator=youtube-music%40workspace%3A." - checksum: 9a0c03b4d89c1ef474bff03f331fb72a0edc58c9a5ad0d0fc31a55625a2f2650e6e4934839668cfb4200bc3c83b299f421183f9476e6ebccb6df51f0b8b6d27e - languageName: node - linkType: hard - -"electron-is@npm:^3.0.0": - version: 3.0.0 - resolution: "electron-is@npm:3.0.0" - dependencies: - electron-is-dev: ^0.3.0 - semver: ^5.5.0 - checksum: 1a0236e07caed9743dad4a4fa9d271da655b5a444c65483a5d6ddd1bd9a173ab9b992cdaeaeca866dcc9b1d2764c4eb64f9d81266bf187494ae0fcb02c66d9ac - languageName: node - linkType: hard - -"electron-localshortcut@npm:^3.1.0, electron-localshortcut@npm:^3.2.1": - version: 3.2.1 - resolution: "electron-localshortcut@npm:3.2.1" - dependencies: - debug: ^4.0.1 - electron-is-accelerator: ^0.1.0 - keyboardevent-from-electron-accelerator: ^2.0.0 - keyboardevents-areequal: ^0.2.1 - checksum: a733b1dea82ebf4e4414ac85383e4fd162e7f37ffefac8fc8974a98b5580387bc429e7e7ade03d89522922c60d336dc139adc18bcc89b8d123dba047efec1a36 - languageName: node - linkType: hard - -"electron-osx-sign@npm:^0.6.0": - version: 0.6.0 - resolution: "electron-osx-sign@npm:0.6.0" - dependencies: - bluebird: ^3.5.0 - compare-version: ^0.1.2 - debug: ^2.6.8 - isbinaryfile: ^3.0.2 - minimist: ^1.2.0 - plist: ^3.0.1 - bin: - electron-osx-flat: bin/electron-osx-flat.js - electron-osx-sign: bin/electron-osx-sign.js - checksum: b688f9efb013670b4226cff7c38101e7b1384ea44e1ab203259995f1eefc019c63aa18e936217a76d33b5a5a452b987ab3d86a56a961294582ce42acbb950de6 - languageName: node - linkType: hard - -"electron-publish@npm:23.6.0": - version: 23.6.0 - resolution: "electron-publish@npm:23.6.0" - dependencies: - "@types/fs-extra": ^9.0.11 - builder-util: 23.6.0 - builder-util-runtime: 9.1.1 - chalk: ^4.1.1 - fs-extra: ^10.0.0 - lazy-val: ^1.0.5 - mime: ^2.5.2 - checksum: 70473d800f0607b5ffc32473e87004079fe3e5f133242bb498dcff0be89bfaa4ce967860809e12b97ce216b1e907649a8a916b7483daf7a00ea28db3d665878e - languageName: node - linkType: hard - -"electron-store@npm:^8.1.0": - version: 8.1.0 - resolution: "electron-store@npm:8.1.0" - dependencies: - conf: ^10.2.0 - type-fest: ^2.17.0 - checksum: 7036f6d91cdcf6e08b10e24df9b144b9a04fe6cb1d7a7cc009277c1f6ad206d96cfbc3ada8ead47206fc5dadec0d34ff1beb8345bb3696e200f071f66b0abd8e - languageName: node - linkType: hard - -"electron-unhandled@npm:^4.0.1": - version: 4.0.1 - resolution: "electron-unhandled@npm:4.0.1" - dependencies: - clean-stack: ^2.1.0 - electron-is-dev: ^2.0.0 - ensure-error: ^2.0.0 - lodash.debounce: ^4.0.8 - serialize-error: ^8.1.0 - checksum: 64874ef2f2a681a7a4c2f98be7bf0365c02d31ebf0adaef03f5a68a22bff6db3a22be66aef7a21b85c949f8c05647dd31b15d92fb73c0ff22e2e845c5a2a9db9 - languageName: node - linkType: hard - -"electron-updater@npm:^5.3.0": - version: 5.3.0 - resolution: "electron-updater@npm:5.3.0" - dependencies: - "@types/semver": ^7.3.6 - builder-util-runtime: 9.1.1 - fs-extra: ^10.0.0 - js-yaml: ^4.1.0 - lazy-val: ^1.0.5 - lodash.escaperegexp: ^4.1.2 - lodash.isequal: ^4.5.0 - semver: ^7.3.5 - typed-emitter: ^2.1.0 - checksum: 975381ffb0d9e17686f7f0b90739320922ca52d06ee548e89ceeb3b56bfc23180c20e7049e5c33ef789b228eb4c960c9886986e1332577866dca2437c315ed4e - languageName: node - linkType: hard - -"electron@npm:^22.3.6": - version: 22.3.6 - resolution: "electron@npm:22.3.6" - dependencies: - "@electron/get": ^2.0.0 - "@types/node": ^16.11.26 - extract-zip: ^2.0.1 - bin: - electron: cli.js - checksum: 99ff77eac6c1a05f731d563fadf106852859c7ac3d38ba4bae8379a0fd7b299d14a8d1151ba1354a0a9a108d7f886cde7d43370eb6166c7cd0fab367532d9fde - languageName: node - linkType: hard - -"emoji-regex@npm:^8.0.0": - version: 8.0.0 - resolution: "emoji-regex@npm:8.0.0" - checksum: d4c5c39d5a9868b5fa152f00cada8a936868fd3367f33f71be515ecee4c803132d11b31a6222b2571b1e5f7e13890156a94880345594d0ce7e3c9895f560f192 - languageName: node - linkType: hard - -"encoding@npm:^0.1.13": - version: 0.1.13 - resolution: "encoding@npm:0.1.13" - dependencies: - iconv-lite: ^0.6.2 - checksum: bb98632f8ffa823996e508ce6a58ffcf5856330fde839ae42c9e1f436cc3b5cc651d4aeae72222916545428e54fd0f6aa8862fd8d25bdbcc4589f1e3f3715e7f - languageName: node - linkType: hard - -"end-of-stream@npm:^1.1.0": - version: 1.4.4 - resolution: "end-of-stream@npm:1.4.4" - dependencies: - once: ^1.4.0 - checksum: 530a5a5a1e517e962854a31693dbb5c0b2fc40b46dad2a56a2deec656ca040631124f4795823acc68238147805f8b021abbe221f4afed5ef3c8e8efc2024908b - languageName: node - linkType: hard - -"enhance-visitors@npm:^1.0.0": - version: 1.0.0 - resolution: "enhance-visitors@npm:1.0.0" - dependencies: - lodash: ^4.13.1 - checksum: d01d41297eb2c726fcbc42b602b3480290b8c301fd2628a64e640480f72d237bafbe31f4c99e80b752b65292948b77be21f51b98a9b120227faecb74972ff3cf - languageName: node - linkType: hard - -"enhanced-resolve@npm:^0.9.1": - version: 0.9.1 - resolution: "enhanced-resolve@npm:0.9.1" - dependencies: - graceful-fs: ^4.1.2 - memory-fs: ^0.2.0 - tapable: ^0.1.8 - checksum: 397106771257d12177a3f07fd86db33b6dd6881a087ef2d43054d82b5e1fb8c1ce9add36f1f0c57e226e5d40e5764c44127f4adeb76bcd7fe0bd0a194c24f98c - languageName: node - linkType: hard - -"ensure-error@npm:^2.0.0": - version: 2.1.0 - resolution: "ensure-error@npm:2.1.0" - checksum: a24852103e9f39cb20ccd5b014d2657425fb786356da3ddc19a4842354430002847f1efeafd14c798e9ee62f644be1986b2b60c9eb1c73f335d1a6dea5bda71a - languageName: node - linkType: hard - -"entities@npm:^4.2.0, entities@npm:^4.4.0": - version: 4.5.0 - resolution: "entities@npm:4.5.0" - checksum: 853f8ebd5b425d350bffa97dd6958143179a5938352ccae092c62d1267c4e392a039be1bae7d51b6e4ffad25f51f9617531fedf5237f15df302ccfb452cbf2d7 - languageName: node - linkType: hard - -"env-editor@npm:^1.0.0": - version: 1.1.0 - resolution: "env-editor@npm:1.1.0" - checksum: f1693c23c530240f13aec866b5d8d8d4729f3b281093e3b69585d820c1aa7ad0e5ebca6e49ce103d94c202a34837d5c0c2c8eedd9278a0a5c4943ddeb94f0fc7 - languageName: node - linkType: hard - -"env-paths@npm:^2.2.0, env-paths@npm:^2.2.1": - version: 2.2.1 - resolution: "env-paths@npm:2.2.1" - checksum: 65b5df55a8bab92229ab2b40dad3b387fad24613263d103a97f91c9fe43ceb21965cd3392b1ccb5d77088021e525c4e0481adb309625d0cb94ade1d1fb8dc17e - languageName: node - linkType: hard - -"err-code@npm:^2.0.2": - version: 2.0.3 - resolution: "err-code@npm:2.0.3" - checksum: 8b7b1be20d2de12d2255c0bc2ca638b7af5171142693299416e6a9339bd7d88fc8d7707d913d78e0993176005405a236b066b45666b27b797252c771156ace54 - languageName: node - linkType: hard - -"error-ex@npm:^1.3.1": - version: 1.3.2 - resolution: "error-ex@npm:1.3.2" - dependencies: - is-arrayish: ^0.2.1 - checksum: c1c2b8b65f9c91b0f9d75f0debaa7ec5b35c266c2cac5de412c1a6de86d4cbae04ae44e510378cb14d032d0645a36925d0186f8bb7367bcc629db256b743a001 - languageName: node - linkType: hard - -"es-abstract@npm:^1.19.0, es-abstract@npm:^1.20.4": - version: 1.21.2 - resolution: "es-abstract@npm:1.21.2" - dependencies: - array-buffer-byte-length: ^1.0.0 - available-typed-arrays: ^1.0.5 - call-bind: ^1.0.2 - es-set-tostringtag: ^2.0.1 - es-to-primitive: ^1.2.1 - function.prototype.name: ^1.1.5 - get-intrinsic: ^1.2.0 - get-symbol-description: ^1.0.0 - globalthis: ^1.0.3 - gopd: ^1.0.1 - has: ^1.0.3 - has-property-descriptors: ^1.0.0 - has-proto: ^1.0.1 - has-symbols: ^1.0.3 - internal-slot: ^1.0.5 - is-array-buffer: ^3.0.2 - is-callable: ^1.2.7 - is-negative-zero: ^2.0.2 - is-regex: ^1.1.4 - is-shared-array-buffer: ^1.0.2 - is-string: ^1.0.7 - is-typed-array: ^1.1.10 - is-weakref: ^1.0.2 - object-inspect: ^1.12.3 - object-keys: ^1.1.1 - object.assign: ^4.1.4 - regexp.prototype.flags: ^1.4.3 - safe-regex-test: ^1.0.0 - string.prototype.trim: ^1.2.7 - string.prototype.trimend: ^1.0.6 - string.prototype.trimstart: ^1.0.6 - typed-array-length: ^1.0.4 - unbox-primitive: ^1.0.2 - which-typed-array: ^1.1.9 - checksum: 037f55ee5e1cdf2e5edbab5524095a4f97144d95b94ea29e3611b77d852fd8c8a40e7ae7101fa6a759a9b9b1405f188c3c70928f2d3cd88d543a07fc0d5ad41a - languageName: node - linkType: hard - -"es-set-tostringtag@npm:^2.0.1": - version: 2.0.1 - resolution: "es-set-tostringtag@npm:2.0.1" - dependencies: - get-intrinsic: ^1.1.3 - has: ^1.0.3 - has-tostringtag: ^1.0.0 - checksum: ec416a12948cefb4b2a5932e62093a7cf36ddc3efd58d6c58ca7ae7064475ace556434b869b0bbeb0c365f1032a8ccd577211101234b69837ad83ad204fff884 - languageName: node - linkType: hard - -"es-shim-unscopables@npm:^1.0.0": - version: 1.0.0 - resolution: "es-shim-unscopables@npm:1.0.0" - dependencies: - has: ^1.0.3 - checksum: 83e95cadbb6ee44d3644dfad60dcad7929edbc42c85e66c3e99aefd68a3a5c5665f2686885cddb47dfeabfd77bd5ea5a7060f2092a955a729bbd8834f0d86fa1 - languageName: node - linkType: hard - -"es-to-primitive@npm:^1.2.1": - version: 1.2.1 - resolution: "es-to-primitive@npm:1.2.1" - dependencies: - is-callable: ^1.1.4 - is-date-object: ^1.0.1 - is-symbol: ^1.0.2 - checksum: 4ead6671a2c1402619bdd77f3503991232ca15e17e46222b0a41a5d81aebc8740a77822f5b3c965008e631153e9ef0580540007744521e72de8e33599fca2eed - languageName: node - linkType: hard - -"es6-error@npm:^4.1.1": - version: 4.1.1 - resolution: "es6-error@npm:4.1.1" - checksum: ae41332a51ec1323da6bbc5d75b7803ccdeddfae17c41b6166ebbafc8e8beb7a7b80b884b7fab1cc80df485860ac3c59d78605e860bb4f8cd816b3d6ade0d010 - languageName: node - linkType: hard - -"escalade@npm:^3.1.1": - version: 3.1.1 - resolution: "escalade@npm:3.1.1" - checksum: a3e2a99f07acb74b3ad4989c48ca0c3140f69f923e56d0cba0526240ee470b91010f9d39001f2a4a313841d237ede70a729e92125191ba5d21e74b106800b133 - languageName: node - linkType: hard - -"escape-string-regexp@npm:5.0.0": - version: 5.0.0 - resolution: "escape-string-regexp@npm:5.0.0" - checksum: 20daabe197f3cb198ec28546deebcf24b3dbb1a5a269184381b3116d12f0532e06007f4bc8da25669d6a7f8efb68db0758df4cd981f57bc5b57f521a3e12c59e - languageName: node - linkType: hard - -"escape-string-regexp@npm:^1.0.2, escape-string-regexp@npm:^1.0.5": - version: 1.0.5 - resolution: "escape-string-regexp@npm:1.0.5" - checksum: 6092fda75c63b110c706b6a9bfde8a612ad595b628f0bd2147eea1d3406723020810e591effc7db1da91d80a71a737a313567c5abb3813e8d9c71f4aa595b410 - languageName: node - linkType: hard - -"escape-string-regexp@npm:^4.0.0": - version: 4.0.0 - resolution: "escape-string-regexp@npm:4.0.0" - checksum: 98b48897d93060f2322108bf29db0feba7dd774be96cd069458d1453347b25ce8682ecc39859d4bca2203cc0ab19c237bcc71755eff49a0f8d90beadeeba5cc5 - languageName: node - linkType: hard - -"eslint-config-prettier@npm:^8.5.0": - version: 8.8.0 - resolution: "eslint-config-prettier@npm:8.8.0" - peerDependencies: - eslint: ">=7.0.0" - bin: - eslint-config-prettier: bin/cli.js - checksum: 1e94c3882c4d5e41e1dcfa2c368dbccbfe3134f6ac7d40101644d3bfbe3eb2f2ffac757f3145910b5eacf20c0e85e02b91293d3126d770cbf3dc390b3564681c - languageName: node - linkType: hard - -"eslint-config-xo-typescript@npm:^0.55.0": - version: 0.55.1 - resolution: "eslint-config-xo-typescript@npm:0.55.1" - peerDependencies: - "@typescript-eslint/eslint-plugin": ">=5.43.0" - "@typescript-eslint/parser": ">=5.43.0" - eslint: ">=8.0.0" - typescript: ">=4.4" - checksum: d3d26d2348594d0b7f22995fba7b8d9681be150a0607026397db27b529e225c4cdfa982b05107a9d4a4b8b32063b0ac9d35742ec28d9a4e6719891c6209f367e - languageName: node - linkType: hard - -"eslint-config-xo@npm:^0.43.1": - version: 0.43.1 - resolution: "eslint-config-xo@npm:0.43.1" - dependencies: - confusing-browser-globals: 1.0.11 - peerDependencies: - eslint: ">=8.27.0" - checksum: 66c69c83ec8bd39fb8bb0a92fed2590a13ba7542c94047503eb5db368adf6576f0db5fe1579aa535e111d50c366bc6c7f1f535d694e67f3343c7fcf16b6aa23c - languageName: node - linkType: hard - -"eslint-formatter-pretty@npm:^4.1.0": - version: 4.1.0 - resolution: "eslint-formatter-pretty@npm:4.1.0" - dependencies: - "@types/eslint": ^7.2.13 - ansi-escapes: ^4.2.1 - chalk: ^4.1.0 - eslint-rule-docs: ^1.1.5 - log-symbols: ^4.0.0 - plur: ^4.0.0 - string-width: ^4.2.0 - supports-hyperlinks: ^2.0.0 - checksum: e8e0cd3843513fff32a70b036dd349fdab81d73b5e522f23685181c907a1faf2b2ebcae1688dc71d0fc026184011792f7e39b833d349df18fe2baea00d017901 - languageName: node - linkType: hard - -"eslint-import-resolver-node@npm:^0.3.7": - version: 0.3.7 - resolution: "eslint-import-resolver-node@npm:0.3.7" - dependencies: - debug: ^3.2.7 - is-core-module: ^2.11.0 - resolve: ^1.22.1 - checksum: 3379aacf1d2c6952c1b9666c6fa5982c3023df695430b0d391c0029f6403a7775414873d90f397e98ba6245372b6c8960e16e74d9e4a3b0c0a4582f3bdbe3d6e - languageName: node - linkType: hard - -"eslint-import-resolver-webpack@npm:^0.13.2": - version: 0.13.2 - resolution: "eslint-import-resolver-webpack@npm:0.13.2" - dependencies: - array-find: ^1.0.0 - debug: ^3.2.7 - enhanced-resolve: ^0.9.1 - find-root: ^1.1.0 - has: ^1.0.3 - interpret: ^1.4.0 - is-core-module: ^2.7.0 - is-regex: ^1.1.4 - lodash: ^4.17.21 - resolve: ^1.20.0 - semver: ^5.7.1 - peerDependencies: - eslint-plugin-import: ">=1.4.0" - webpack: ">=1.11.0" - checksum: 6c40164747bf894a0e34cbc9626566193471062e8809cef7aa8be74e0346c962d03aa7b8f3579a3d348245269860c1f241eba5379ec04acc89daffa4fb6b5f17 - languageName: node - linkType: hard - -"eslint-module-utils@npm:^2.7.4": - version: 2.8.0 - resolution: "eslint-module-utils@npm:2.8.0" - dependencies: - debug: ^3.2.7 - peerDependenciesMeta: - eslint: - optional: true - checksum: 74c6dfea7641ebcfe174be61168541a11a14aa8d72e515f5f09af55cd0d0862686104b0524aa4b8e0ce66418a44aa38a94d2588743db5fd07a6b49ffd16921d2 - languageName: node - linkType: hard - -"eslint-plugin-ava@npm:^13.2.0": - version: 13.2.0 - resolution: "eslint-plugin-ava@npm:13.2.0" - dependencies: - enhance-visitors: ^1.0.0 - eslint-utils: ^3.0.0 - espree: ^9.0.0 - espurify: ^2.1.1 - import-modules: ^2.1.0 - micro-spelling-correcter: ^1.1.1 - pkg-dir: ^5.0.0 - resolve-from: ^5.0.0 - peerDependencies: - eslint: ">=7.22.0" - checksum: e7e3077d5695c9293aa1b32cd76a2190110f0c73e90d175f2fe80c052e9dd8a621e7537c75142047889d503d83df9662ed9e60ce761166e5d493917060b47959 - languageName: node - linkType: hard - -"eslint-plugin-es@npm:^4.1.0": - version: 4.1.0 - resolution: "eslint-plugin-es@npm:4.1.0" - dependencies: - eslint-utils: ^2.0.0 - regexpp: ^3.0.0 - peerDependencies: - eslint: ">=4.19.1" - checksum: 26b87a216d3625612b1d3ca8653ac8a1d261046d2a973bb0eb2759070267d2bfb0509051facdeb5ae03dc8dfb51a434be23aff7309a752ca901d637da535677f - languageName: node - linkType: hard - -"eslint-plugin-eslint-comments@npm:^3.2.0": - version: 3.2.0 - resolution: "eslint-plugin-eslint-comments@npm:3.2.0" - dependencies: - escape-string-regexp: ^1.0.5 - ignore: ^5.0.5 - peerDependencies: - eslint: ">=4.19.1" - checksum: c9fe273dd56699abdf7e416cfad0344eb50aa01564a5a9133e72d982defb89310bc2e9b0b148ce19c5190d7ff641223b0ba9e667a194bc48467c3dd0d471e657 - languageName: node - linkType: hard - -"eslint-plugin-import@npm:^2.26.0": - version: 2.27.5 - resolution: "eslint-plugin-import@npm:2.27.5" - dependencies: - array-includes: ^3.1.6 - array.prototype.flat: ^1.3.1 - array.prototype.flatmap: ^1.3.1 - debug: ^3.2.7 - doctrine: ^2.1.0 - eslint-import-resolver-node: ^0.3.7 - eslint-module-utils: ^2.7.4 - has: ^1.0.3 - is-core-module: ^2.11.0 - is-glob: ^4.0.3 - minimatch: ^3.1.2 - object.values: ^1.1.6 - resolve: ^1.22.1 - semver: ^6.3.0 - tsconfig-paths: ^3.14.1 - peerDependencies: - eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 - checksum: f500571a380167e25d72a4d925ef9a7aae8899eada57653e5f3051ec3d3c16d08271fcefe41a30a9a2f4fefc232f066253673ee4ea77b30dba65ae173dade85d - languageName: node - linkType: hard - -"eslint-plugin-n@npm:^15.5.1": - version: 15.7.0 - resolution: "eslint-plugin-n@npm:15.7.0" - dependencies: - builtins: ^5.0.1 - eslint-plugin-es: ^4.1.0 - eslint-utils: ^3.0.0 - ignore: ^5.1.1 - is-core-module: ^2.11.0 - minimatch: ^3.1.2 - resolve: ^1.22.1 - semver: ^7.3.8 - peerDependencies: - eslint: ">=7.0.0" - checksum: cfbcc67e62adf27712afdeadf13223cb9717f95d4af8442056d9d4c97a8b88af76b7969f75deaac26fa98481023d6b7c9e43a28909e7f0468f40b3024b7bcfae - languageName: node - linkType: hard - -"eslint-plugin-no-use-extend-native@npm:^0.5.0": - version: 0.5.0 - resolution: "eslint-plugin-no-use-extend-native@npm:0.5.0" - dependencies: - is-get-set-prop: ^1.0.0 - is-js-type: ^2.0.0 - is-obj-prop: ^1.0.0 - is-proto-prop: ^2.0.0 - checksum: addc83c73aa7137b057e009ce34aa549ba1441bf732d643c8b945328bff13b1f7ed1c07194d8ca48c5ba645c4d1358588e1d947e525abdc595b85acde02a0dd5 - languageName: node - linkType: hard - -"eslint-plugin-prettier@npm:^4.2.1": - version: 4.2.1 - resolution: "eslint-plugin-prettier@npm:4.2.1" - dependencies: - prettier-linter-helpers: ^1.0.0 - peerDependencies: - eslint: ">=7.28.0" - prettier: ">=2.0.0" - peerDependenciesMeta: - eslint-config-prettier: - optional: true - checksum: b9e839d2334ad8ec7a5589c5cb0f219bded260839a857d7a486997f9870e95106aa59b8756ff3f37202085ebab658de382b0267cae44c3a7f0eb0bcc03a4f6d6 - languageName: node - linkType: hard - -"eslint-plugin-unicorn@npm:^44.0.2": - version: 44.0.2 - resolution: "eslint-plugin-unicorn@npm:44.0.2" - dependencies: - "@babel/helper-validator-identifier": ^7.19.1 - ci-info: ^3.4.0 - clean-regexp: ^1.0.0 - eslint-utils: ^3.0.0 - esquery: ^1.4.0 - indent-string: ^4.0.0 - is-builtin-module: ^3.2.0 - lodash: ^4.17.21 - pluralize: ^8.0.0 - read-pkg-up: ^7.0.1 - regexp-tree: ^0.1.24 - safe-regex: ^2.1.1 - semver: ^7.3.7 - strip-indent: ^3.0.0 - peerDependencies: - eslint: ">=8.23.1" - checksum: b0ed6b3a60e36efab5b19a0e2a1ea4e4faba79ef315aa1eff9bdebaf28b70ada059837a0a4cdf20e0b678d8eee6155afc2c6300d0ff7d51b68eced4f0bcb56e0 - languageName: node - linkType: hard - -"eslint-rule-docs@npm:^1.1.5": - version: 1.1.235 - resolution: "eslint-rule-docs@npm:1.1.235" - checksum: b163596f9a05568e287b2c78f51a280092122a2e43c45fa2c200f0bd3f61877af186c641dab97620978bec96d9e2cfb621e51728044d9efe42ddc24f5a594b26 - languageName: node - linkType: hard - -"eslint-scope@npm:^5.1.1": - version: 5.1.1 - resolution: "eslint-scope@npm:5.1.1" - dependencies: - esrecurse: ^4.3.0 - estraverse: ^4.1.1 - checksum: 47e4b6a3f0cc29c7feedee6c67b225a2da7e155802c6ea13bbef4ac6b9e10c66cd2dcb987867ef176292bf4e64eccc680a49e35e9e9c669f4a02bac17e86abdb - languageName: node - linkType: hard - -"eslint-scope@npm:^7.1.1": - version: 7.2.0 - resolution: "eslint-scope@npm:7.2.0" - dependencies: - esrecurse: ^4.3.0 - estraverse: ^5.2.0 - checksum: 64591a2d8b244ade9c690b59ef238a11d5c721a98bcee9e9f445454f442d03d3e04eda88e95a4daec558220a99fa384309d9faae3d459bd40e7a81b4063980ae - languageName: node - linkType: hard - -"eslint-utils@npm:^2.0.0": - version: 2.1.0 - resolution: "eslint-utils@npm:2.1.0" - dependencies: - eslint-visitor-keys: ^1.1.0 - checksum: 27500938f348da42100d9e6ad03ae29b3de19ba757ae1a7f4a087bdcf83ac60949bbb54286492ca61fac1f5f3ac8692dd21537ce6214240bf95ad0122f24d71d - languageName: node - linkType: hard - -"eslint-utils@npm:^3.0.0": - version: 3.0.0 - resolution: "eslint-utils@npm:3.0.0" - dependencies: - eslint-visitor-keys: ^2.0.0 - peerDependencies: - eslint: ">=5" - checksum: 0668fe02f5adab2e5a367eee5089f4c39033af20499df88fe4e6aba2015c20720404d8c3d6349b6f716b08fdf91b9da4e5d5481f265049278099c4c836ccb619 - languageName: node - linkType: hard - -"eslint-visitor-keys@npm:^1.1.0": - version: 1.3.0 - resolution: "eslint-visitor-keys@npm:1.3.0" - checksum: 37a19b712f42f4c9027e8ba98c2b06031c17e0c0a4c696cd429bd9ee04eb43889c446f2cd545e1ff51bef9593fcec94ecd2c2ef89129fcbbf3adadbef520376a - languageName: node - linkType: hard - -"eslint-visitor-keys@npm:^2.0.0": - version: 2.1.0 - resolution: "eslint-visitor-keys@npm:2.1.0" - checksum: e3081d7dd2611a35f0388bbdc2f5da60b3a3c5b8b6e928daffff7391146b434d691577aa95064c8b7faad0b8a680266bcda0a42439c18c717b80e6718d7e267d - languageName: node - linkType: hard - -"eslint-visitor-keys@npm:^3.3.0, eslint-visitor-keys@npm:^3.4.0": - version: 3.4.0 - resolution: "eslint-visitor-keys@npm:3.4.0" - checksum: 33159169462d3989321a1ec1e9aaaf6a24cc403d5d347e9886d1b5bfe18ffa1be73bdc6203143a28a606b142b1af49787f33cff0d6d0813eb5f2e8d2e1a6043c - languageName: node - linkType: hard - -"eslint@npm:^8.27.0": - version: 8.38.0 - resolution: "eslint@npm:8.38.0" - dependencies: - "@eslint-community/eslint-utils": ^4.2.0 - "@eslint-community/regexpp": ^4.4.0 - "@eslint/eslintrc": ^2.0.2 - "@eslint/js": 8.38.0 - "@humanwhocodes/config-array": ^0.11.8 - "@humanwhocodes/module-importer": ^1.0.1 - "@nodelib/fs.walk": ^1.2.8 - ajv: ^6.10.0 - chalk: ^4.0.0 - cross-spawn: ^7.0.2 - debug: ^4.3.2 - doctrine: ^3.0.0 - escape-string-regexp: ^4.0.0 - eslint-scope: ^7.1.1 - eslint-visitor-keys: ^3.4.0 - espree: ^9.5.1 - esquery: ^1.4.2 - esutils: ^2.0.2 - fast-deep-equal: ^3.1.3 - file-entry-cache: ^6.0.1 - find-up: ^5.0.0 - glob-parent: ^6.0.2 - globals: ^13.19.0 - grapheme-splitter: ^1.0.4 - ignore: ^5.2.0 - import-fresh: ^3.0.0 - imurmurhash: ^0.1.4 - is-glob: ^4.0.0 - is-path-inside: ^3.0.3 - js-sdsl: ^4.1.4 - js-yaml: ^4.1.0 - json-stable-stringify-without-jsonify: ^1.0.1 - levn: ^0.4.1 - lodash.merge: ^4.6.2 - minimatch: ^3.1.2 - natural-compare: ^1.4.0 - optionator: ^0.9.1 - strip-ansi: ^6.0.1 - strip-json-comments: ^3.1.0 - text-table: ^0.2.0 - bin: - eslint: bin/eslint.js - checksum: 73b6d9b650d0434aa7c07d0a1802f099b086ee70a8d8ba7be730439a26572a5eb71def12125c82942be2ec8ee5be38a6f1b42a13e40d4b67f11a148ec9e263eb - languageName: node - linkType: hard - -"esm-utils@npm:^4.1.0": - version: 4.1.2 - resolution: "esm-utils@npm:4.1.2" - dependencies: - import-meta-resolve: 2.2.2 - url-or-path: 2.1.0 - checksum: a78f977d18cf3e07f352ce465fd3b083a7e33942980430eb4769c79d67fc5679a272b3e11666405c2dc9eeaebf2de949ffdf7f49976974b4d5683688f5c1708c - languageName: node - linkType: hard - -"espree@npm:^9.0.0, espree@npm:^9.4.0, espree@npm:^9.5.1": - version: 9.5.1 - resolution: "espree@npm:9.5.1" - dependencies: - acorn: ^8.8.0 - acorn-jsx: ^5.3.2 - eslint-visitor-keys: ^3.4.0 - checksum: cdf6e43540433d917c4f2ee087c6e987b2063baa85a1d9cdaf51533d78275ebd5910c42154e7baf8e3e89804b386da0a2f7fad2264d8f04420e7506bf87b3b88 - languageName: node - linkType: hard - -"espurify@npm:^2.1.1": - version: 2.1.1 - resolution: "espurify@npm:2.1.1" - checksum: 7d92a7670e3d4833bd6e6ff29759bd2c30aaedfeb93330d8fcf78c1760b535ae0cc5f3aa84d2d49b065cad9ba14a0c4c04b21002e0a7b62580e58dfdfc6a67cf - languageName: node - linkType: hard - -"esquery@npm:^1.4.0, esquery@npm:^1.4.2": - version: 1.5.0 - resolution: "esquery@npm:1.5.0" - dependencies: - estraverse: ^5.1.0 - checksum: aefb0d2596c230118656cd4ec7532d447333a410a48834d80ea648b1e7b5c9bc9ed8b5e33a89cb04e487b60d622f44cf5713bf4abed7c97343edefdc84a35900 - languageName: node - linkType: hard - -"esrecurse@npm:^4.3.0": - version: 4.3.0 - resolution: "esrecurse@npm:4.3.0" - dependencies: - estraverse: ^5.2.0 - checksum: ebc17b1a33c51cef46fdc28b958994b1dc43cd2e86237515cbc3b4e5d2be6a811b2315d0a1a4d9d340b6d2308b15322f5c8291059521cc5f4802f65e7ec32837 - languageName: node - linkType: hard - -"estraverse@npm:^4.1.1": - version: 4.3.0 - resolution: "estraverse@npm:4.3.0" - checksum: a6299491f9940bb246124a8d44b7b7a413a8336f5436f9837aaa9330209bd9ee8af7e91a654a3545aee9c54b3308e78ee360cef1d777d37cfef77d2fa33b5827 - languageName: node - linkType: hard - -"estraverse@npm:^5.1.0, estraverse@npm:^5.2.0": - version: 5.3.0 - resolution: "estraverse@npm:5.3.0" - checksum: 072780882dc8416ad144f8fe199628d2b3e7bbc9989d9ed43795d2c90309a2047e6bc5979d7e2322a341163d22cfad9e21f4110597fe487519697389497e4e2b - languageName: node - linkType: hard - -"esutils@npm:^2.0.2": - version: 2.0.3 - resolution: "esutils@npm:2.0.3" - checksum: 22b5b08f74737379a840b8ed2036a5fb35826c709ab000683b092d9054e5c2a82c27818f12604bfc2a9a76b90b6834ef081edbc1c7ae30d1627012e067c6ec87 - languageName: node - linkType: hard - -"event-stream@npm:3.3.4": - version: 3.3.4 - resolution: "event-stream@npm:3.3.4" - dependencies: - duplexer: ~0.1.1 - from: ~0 - map-stream: ~0.1.0 - pause-stream: 0.0.11 - split: 0.3 - stream-combiner: ~0.0.4 - through: ~2.3.1 - checksum: 80b467820b6daf824d9fb4345d2daf115a056e5c104463f2e98534e92d196a27f2df5ea2aa085624db26f4c45698905499e881d13bc7c01f7a13eac85be72a22 - languageName: node - linkType: hard - -"execa@npm:^5.1.1": - version: 5.1.1 - resolution: "execa@npm:5.1.1" - dependencies: - cross-spawn: ^7.0.3 - get-stream: ^6.0.0 - human-signals: ^2.1.0 - is-stream: ^2.0.0 - merge-stream: ^2.0.0 - npm-run-path: ^4.0.1 - onetime: ^5.1.2 - signal-exit: ^3.0.3 - strip-final-newline: ^2.0.0 - checksum: fba9022c8c8c15ed862847e94c252b3d946036d7547af310e344a527e59021fd8b6bb0723883ea87044dc4f0201f949046993124a42ccb0855cae5bf8c786343 - languageName: node - linkType: hard - -"extract-zip@npm:^2.0.1": - version: 2.0.1 - resolution: "extract-zip@npm:2.0.1" - dependencies: - "@types/yauzl": ^2.9.1 - debug: ^4.1.1 - get-stream: ^5.1.0 - yauzl: ^2.10.0 - dependenciesMeta: - "@types/yauzl": - optional: true - bin: - extract-zip: cli.js - checksum: 8cbda9debdd6d6980819cc69734d874ddd71051c9fe5bde1ef307ebcedfe949ba57b004894b585f758b7c9eeeea0e3d87f2dda89b7d25320459c2c9643ebb635 - languageName: node - linkType: hard - -"extsprintf@npm:^1.2.0": - version: 1.4.1 - resolution: "extsprintf@npm:1.4.1" - checksum: a2f29b241914a8d2bad64363de684821b6b1609d06ae68d5b539e4de6b28659715b5bea94a7265201603713b7027d35399d10b0548f09071c5513e65e8323d33 - languageName: node - linkType: hard - -"fast-deep-equal@npm:^3.1.1, fast-deep-equal@npm:^3.1.3": - version: 3.1.3 - resolution: "fast-deep-equal@npm:3.1.3" - checksum: e21a9d8d84f53493b6aa15efc9cfd53dd5b714a1f23f67fb5dc8f574af80df889b3bce25dc081887c6d25457cce704e636395333abad896ccdec03abaf1f3f9d - languageName: node - linkType: hard - -"fast-diff@npm:^1.1.2": - version: 1.2.0 - resolution: "fast-diff@npm:1.2.0" - checksum: 1b5306eaa9e826564d9e5ffcd6ebd881eb5f770b3f977fcbf38f05c824e42172b53c79920e8429c54eb742ce15a0caf268b0fdd5b38f6de52234c4a8368131ae - languageName: node - linkType: hard - -"fast-glob@npm:^3.2.11, fast-glob@npm:^3.2.9": - version: 3.2.12 - resolution: "fast-glob@npm:3.2.12" - dependencies: - "@nodelib/fs.stat": ^2.0.2 - "@nodelib/fs.walk": ^1.2.3 - glob-parent: ^5.1.2 - merge2: ^1.3.0 - micromatch: ^4.0.4 - checksum: 0b1990f6ce831c7e28c4d505edcdaad8e27e88ab9fa65eedadb730438cfc7cde4910d6c975d6b7b8dc8a73da4773702ebcfcd6e3518e73938bb1383badfe01c2 - languageName: node - linkType: hard - -"fast-json-stable-stringify@npm:^2.0.0": - version: 2.1.0 - resolution: "fast-json-stable-stringify@npm:2.1.0" - checksum: b191531e36c607977e5b1c47811158733c34ccb3bfde92c44798929e9b4154884378536d26ad90dfecd32e1ffc09c545d23535ad91b3161a27ddbb8ebe0cbecb - languageName: node - linkType: hard - -"fast-levenshtein@npm:^2.0.6": - version: 2.0.6 - resolution: "fast-levenshtein@npm:2.0.6" - checksum: 92cfec0a8dfafd9c7a15fba8f2cc29cd0b62b85f056d99ce448bbcd9f708e18ab2764bda4dd5158364f4145a7c72788538994f0d1787b956ef0d1062b0f7c24c - languageName: node - linkType: hard - -"fastq@npm:^1.6.0": - version: 1.15.0 - resolution: "fastq@npm:1.15.0" - dependencies: - reusify: ^1.0.4 - checksum: 0170e6bfcd5d57a70412440b8ef600da6de3b2a6c5966aeaf0a852d542daff506a0ee92d6de7679d1de82e644bce69d7a574a6c93f0b03964b5337eed75ada1a - languageName: node - linkType: hard - -"fd-slicer@npm:~1.1.0": - version: 1.1.0 - resolution: "fd-slicer@npm:1.1.0" - dependencies: - pend: ~1.2.0 - checksum: c8585fd5713f4476eb8261150900d2cb7f6ff2d87f8feb306ccc8a1122efd152f1783bdb2b8dc891395744583436bfd8081d8e63ece0ec8687eeefea394d4ff2 - languageName: node - linkType: hard - -"file-entry-cache@npm:^6.0.1": - version: 6.0.1 - resolution: "file-entry-cache@npm:6.0.1" - dependencies: - flat-cache: ^3.0.4 - checksum: f49701feaa6314c8127c3c2f6173cfefff17612f5ed2daaafc6da13b5c91fd43e3b2a58fd0d63f9f94478a501b167615931e7200e31485e320f74a33885a9c74 - languageName: node - linkType: hard - -"file-uri-to-path@npm:1.0.0": - version: 1.0.0 - resolution: "file-uri-to-path@npm:1.0.0" - checksum: b648580bdd893a008c92c7ecc96c3ee57a5e7b6c4c18a9a09b44fb5d36d79146f8e442578bc0e173dc027adf3987e254ba1dfd6e3ec998b7c282873010502144 - languageName: node - linkType: hard - -"filelist@npm:^1.0.1": - version: 1.0.4 - resolution: "filelist@npm:1.0.4" - dependencies: - minimatch: ^5.0.1 - checksum: a303573b0821e17f2d5e9783688ab6fbfce5d52aaac842790ae85e704a6f5e4e3538660a63183d6453834dedf1e0f19a9dadcebfa3e926c72397694ea11f5160 - languageName: node - linkType: hard - -"filename-reserved-regex@npm:^2.0.0": - version: 2.0.0 - resolution: "filename-reserved-regex@npm:2.0.0" - checksum: 323a0020fd7f243238ffccab9d728cbc5f3a13c84b2c10e01efb09b8324561d7a51776be76f36603c734d4f69145c39a5d12492bf6142a28b50d7f90bd6190bc - languageName: node - linkType: hard - -"filenamify@npm:^4.3.0": - version: 4.3.0 - resolution: "filenamify@npm:4.3.0" - dependencies: - filename-reserved-regex: ^2.0.0 - strip-outer: ^1.0.1 - trim-repeated: ^1.0.0 - checksum: 5b71a7ff8e958c8621957e6fbf7872024126d3b5da50f59b1634af3343ba1a69d4cc15cfe4ca4bbfa7c959ad4d98614ee51e6f1d9fa7326eef8ceda2da8cd74e - languageName: node - linkType: hard - -"fill-range@npm:^7.0.1": - version: 7.0.1 - resolution: "fill-range@npm:7.0.1" - dependencies: - to-regex-range: ^5.0.1 - checksum: cc283f4e65b504259e64fd969bcf4def4eb08d85565e906b7d36516e87819db52029a76b6363d0f02d0d532f0033c9603b9e2d943d56ee3b0d4f7ad3328ff917 - languageName: node - linkType: hard - -"find-cache-dir@npm:^4.0.0": - version: 4.0.0 - resolution: "find-cache-dir@npm:4.0.0" - dependencies: - common-path-prefix: ^3.0.0 - pkg-dir: ^7.0.0 - checksum: 52a456a80deeb27daa3af6e06059b63bdb9cc4af4d845fc6d6229887e505ba913cd56000349caa60bc3aa59dacdb5b4c37903d4ba34c75102d83cab330b70d2f - languageName: node - linkType: hard - -"find-root@npm:^1.1.0": - version: 1.1.0 - resolution: "find-root@npm:1.1.0" - checksum: b2a59fe4b6c932eef36c45a048ae8f93c85640212ebe8363164814990ee20f154197505965f3f4f102efc33bfb1cbc26fd17c4a2fc739ebc51b886b137cbefaf - languageName: node - linkType: hard - -"find-up@npm:^3.0.0": - version: 3.0.0 - resolution: "find-up@npm:3.0.0" - dependencies: - locate-path: ^3.0.0 - checksum: 38eba3fe7a66e4bc7f0f5a1366dc25508b7cfc349f852640e3678d26ad9a6d7e2c43eff0a472287de4a9753ef58f066a0ea892a256fa3636ad51b3fe1e17fae9 - languageName: node - linkType: hard - -"find-up@npm:^4.1.0": - version: 4.1.0 - resolution: "find-up@npm:4.1.0" - dependencies: - locate-path: ^5.0.0 - path-exists: ^4.0.0 - checksum: 4c172680e8f8c1f78839486e14a43ef82e9decd0e74145f40707cc42e7420506d5ec92d9a11c22bd2c48fb0c384ea05dd30e10dd152fefeec6f2f75282a8b844 - languageName: node - linkType: hard - -"find-up@npm:^5.0.0": - version: 5.0.0 - resolution: "find-up@npm:5.0.0" - dependencies: - locate-path: ^6.0.0 - path-exists: ^4.0.0 - checksum: 07955e357348f34660bde7920783204ff5a26ac2cafcaa28bace494027158a97b9f56faaf2d89a6106211a8174db650dd9f503f9c0d526b1202d5554a00b9095 - languageName: node - linkType: hard - -"find-up@npm:^6.3.0": - version: 6.3.0 - resolution: "find-up@npm:6.3.0" - dependencies: - locate-path: ^7.1.0 - path-exists: ^5.0.0 - checksum: 9a21b7f9244a420e54c6df95b4f6fc3941efd3c3e5476f8274eb452f6a85706e7a6a90de71353ee4f091fcb4593271a6f92810a324ec542650398f928783c280 - languageName: node - linkType: hard - -"flat-cache@npm:^3.0.4": - version: 3.0.4 - resolution: "flat-cache@npm:3.0.4" - dependencies: - flatted: ^3.1.0 - rimraf: ^3.0.2 - checksum: 4fdd10ecbcbf7d520f9040dd1340eb5dfe951e6f0ecf2252edeec03ee68d989ec8b9a20f4434270e71bcfd57800dc09b3344fca3966b2eb8f613072c7d9a2365 - languageName: node - linkType: hard - -"flatted@npm:^3.1.0": - version: 3.2.7 - resolution: "flatted@npm:3.2.7" - checksum: 427633049d55bdb80201c68f7eb1cbd533e03eac541f97d3aecab8c5526f12a20ccecaeede08b57503e772c769e7f8680b37e8d482d1e5f8d7e2194687f9ea35 - languageName: node - linkType: hard - -"follow-redirects@npm:^1.15.0": - version: 1.15.2 - resolution: "follow-redirects@npm:1.15.2" - peerDependenciesMeta: - debug: - optional: true - checksum: faa66059b66358ba65c234c2f2a37fcec029dc22775f35d9ad6abac56003268baf41e55f9ee645957b32c7d9f62baf1f0b906e68267276f54ec4b4c597c2b190 - languageName: node - linkType: hard - -"for-each@npm:^0.3.3": - version: 0.3.3 - resolution: "for-each@npm:0.3.3" - dependencies: - is-callable: ^1.1.3 - checksum: 6c48ff2bc63362319c65e2edca4a8e1e3483a2fabc72fbe7feaf8c73db94fc7861bd53bc02c8a66a0c1dd709da6b04eec42e0abdd6b40ce47305ae92a25e5d28 - languageName: node - linkType: hard - -"form-data@npm:^4.0.0": - version: 4.0.0 - resolution: "form-data@npm:4.0.0" - dependencies: - asynckit: ^0.4.0 - combined-stream: ^1.0.8 - mime-types: ^2.1.12 - checksum: 01135bf8675f9d5c61ff18e2e2932f719ca4de964e3be90ef4c36aacfc7b9cb2fceb5eca0b7e0190e3383fe51c5b37f4cb80b62ca06a99aaabfcfd6ac7c9328c - languageName: node - linkType: hard - -"from@npm:~0": - version: 0.1.7 - resolution: "from@npm:0.1.7" - checksum: b85125b7890489656eb2e4f208f7654a93ec26e3aefaf3bbbcc0d496fc1941e4405834fcc9fe7333192aa2187905510ace70417bbf9ac6f6f4784a731d986939 - languageName: node - linkType: hard - -"fs-extra@npm:^10.0.0, fs-extra@npm:^10.1.0": - version: 10.1.0 - resolution: "fs-extra@npm:10.1.0" - dependencies: - graceful-fs: ^4.2.0 - jsonfile: ^6.0.1 - universalify: ^2.0.0 - checksum: dc94ab37096f813cc3ca12f0f1b5ad6744dfed9ed21e953d72530d103cea193c2f81584a39e9dee1bea36de5ee66805678c0dddc048e8af1427ac19c00fffc50 - languageName: node - linkType: hard - -"fs-extra@npm:^8.1.0": - version: 8.1.0 - resolution: "fs-extra@npm:8.1.0" - dependencies: - graceful-fs: ^4.2.0 - jsonfile: ^4.0.0 - universalify: ^0.1.0 - checksum: bf44f0e6cea59d5ce071bba4c43ca76d216f89e402dc6285c128abc0902e9b8525135aa808adad72c9d5d218e9f4bcc63962815529ff2f684ad532172a284880 - languageName: node - linkType: hard - -"fs-extra@npm:^9.0.0, fs-extra@npm:^9.0.1": - version: 9.1.0 - resolution: "fs-extra@npm:9.1.0" - dependencies: - at-least-node: ^1.0.0 - graceful-fs: ^4.2.0 - jsonfile: ^6.0.1 - universalify: ^2.0.0 - checksum: ba71ba32e0faa74ab931b7a0031d1523c66a73e225de7426e275e238e312d07313d2da2d33e34a52aa406c8763ade5712eb3ec9ba4d9edce652bcacdc29e6b20 - languageName: node - linkType: hard - -"fs-minipass@npm:^2.0.0, fs-minipass@npm:^2.1.0": - version: 2.1.0 - resolution: "fs-minipass@npm:2.1.0" - dependencies: - minipass: ^3.0.0 - checksum: 1b8d128dae2ac6cc94230cc5ead341ba3e0efaef82dab46a33d171c044caaa6ca001364178d42069b2809c35a1c3c35079a32107c770e9ffab3901b59af8c8b1 - languageName: node - linkType: hard - -"fs.realpath@npm:^1.0.0": - version: 1.0.0 - resolution: "fs.realpath@npm:1.0.0" - checksum: 99ddea01a7e75aa276c250a04eedeffe5662bce66c65c07164ad6264f9de18fb21be9433ead460e54cff20e31721c811f4fb5d70591799df5f85dce6d6746fd0 - languageName: node - linkType: hard - -"fsevents@npm:2.3.2": - version: 2.3.2 - resolution: "fsevents@npm:2.3.2" - dependencies: - node-gyp: latest - checksum: 97ade64e75091afee5265e6956cb72ba34db7819b4c3e94c431d4be2b19b8bb7a2d4116da417950c3425f17c8fe693d25e20212cac583ac1521ad066b77ae31f - conditions: os=darwin - languageName: node - linkType: hard - -"fsevents@patch:fsevents@2.3.2#~builtin": - version: 2.3.2 - resolution: "fsevents@patch:fsevents@npm%3A2.3.2#~builtin::version=2.3.2&hash=df0bf1" - dependencies: - node-gyp: latest - conditions: os=darwin - languageName: node - linkType: hard - -"function-bind@npm:^1.1.1": - version: 1.1.1 - resolution: "function-bind@npm:1.1.1" - checksum: b32fbaebb3f8ec4969f033073b43f5c8befbb58f1a79e12f1d7490358150359ebd92f49e72ff0144f65f2c48ea2a605bff2d07965f548f6474fd8efd95bf361a - languageName: node - linkType: hard - -"function.prototype.name@npm:^1.1.5": - version: 1.1.5 - resolution: "function.prototype.name@npm:1.1.5" - dependencies: - call-bind: ^1.0.2 - define-properties: ^1.1.3 - es-abstract: ^1.19.0 - functions-have-names: ^1.2.2 - checksum: acd21d733a9b649c2c442f067567743214af5fa248dbeee69d8278ce7df3329ea5abac572be9f7470b4ec1cd4d8f1040e3c5caccf98ebf2bf861a0deab735c27 - languageName: node - linkType: hard - -"functions-have-names@npm:^1.2.2": - version: 1.2.3 - resolution: "functions-have-names@npm:1.2.3" - checksum: c3f1f5ba20f4e962efb71344ce0a40722163e85bee2101ce25f88214e78182d2d2476aa85ef37950c579eb6cf6ee811c17b3101bb84004bb75655f3e33f3fdb5 - languageName: node - linkType: hard - -"gauge@npm:^4.0.3": - version: 4.0.4 - resolution: "gauge@npm:4.0.4" - dependencies: - aproba: ^1.0.3 || ^2.0.0 - color-support: ^1.1.3 - console-control-strings: ^1.1.0 - has-unicode: ^2.0.1 - signal-exit: ^3.0.7 - string-width: ^4.2.3 - strip-ansi: ^6.0.1 - wide-align: ^1.1.5 - checksum: 788b6bfe52f1dd8e263cda800c26ac0ca2ff6de0b6eee2fe0d9e3abf15e149b651bd27bf5226be10e6e3edb5c4e5d5985a5a1a98137e7a892f75eff76467ad2d - languageName: node - linkType: hard - -"get-caller-file@npm:^2.0.5": - version: 2.0.5 - resolution: "get-caller-file@npm:2.0.5" - checksum: b9769a836d2a98c3ee734a88ba712e62703f1df31b94b784762c433c27a386dd6029ff55c2a920c392e33657d80191edbf18c61487e198844844516f843496b9 - languageName: node - linkType: hard - -"get-intrinsic@npm:^1.0.2, get-intrinsic@npm:^1.1.1, get-intrinsic@npm:^1.1.3, get-intrinsic@npm:^1.2.0": - version: 1.2.0 - resolution: "get-intrinsic@npm:1.2.0" - dependencies: - function-bind: ^1.1.1 - has: ^1.0.3 - has-symbols: ^1.0.3 - checksum: 78fc0487b783f5c58cf2dccafc3ae656ee8d2d8062a8831ce4a95e7057af4587a1d4882246c033aca0a7b4965276f4802b45cc300338d1b77a73d3e3e3f4877d - languageName: node - linkType: hard - -"get-set-props@npm:^0.1.0": - version: 0.1.0 - resolution: "get-set-props@npm:0.1.0" - checksum: 738ab6b7df3655bcc533e8c66c512b6643e241b969c14240e489d650cecb7a9646d78c4fef648f032b7ccb7b1e5ed6a79a59e1d3a1b760dd75d70fee0a656ea8 - languageName: node - linkType: hard - -"get-stdin@npm:^9.0.0": - version: 9.0.0 - resolution: "get-stdin@npm:9.0.0" - checksum: 5972bc34d05932b45512c8e2d67b040f1c1ca8afb95c56cbc480985f2d761b7e37fe90dc8abd22527f062cc5639a6930ff346e9952ae4c11a2d4275869459594 - languageName: node - linkType: hard - -"get-stream@npm:^5.1.0": - version: 5.2.0 - resolution: "get-stream@npm:5.2.0" - dependencies: - pump: ^3.0.0 - checksum: 8bc1a23174a06b2b4ce600df38d6c98d2ef6d84e020c1ddad632ad75bac4e092eeb40e4c09e0761c35fc2dbc5e7fff5dab5e763a383582c4a167dd69a905bd12 - languageName: node - linkType: hard - -"get-stream@npm:^6.0.0": - version: 6.0.1 - resolution: "get-stream@npm:6.0.1" - checksum: e04ecece32c92eebf5b8c940f51468cd53554dcbb0ea725b2748be583c9523d00128137966afce410b9b051eb2ef16d657cd2b120ca8edafcf5a65e81af63cad - languageName: node - linkType: hard - -"get-symbol-description@npm:^1.0.0": - version: 1.0.0 - resolution: "get-symbol-description@npm:1.0.0" - dependencies: - call-bind: ^1.0.2 - get-intrinsic: ^1.1.1 - checksum: 9ceff8fe968f9270a37a1f73bf3f1f7bda69ca80f4f80850670e0e7b9444ff99323f7ac52f96567f8b5f5fbe7ac717a0d81d3407c7313e82810c6199446a5247 - languageName: node - linkType: hard - -"glob-parent@npm:^5.1.2": - version: 5.1.2 - resolution: "glob-parent@npm:5.1.2" - dependencies: - is-glob: ^4.0.1 - checksum: f4f2bfe2425296e8a47e36864e4f42be38a996db40420fe434565e4480e3322f18eb37589617a98640c5dc8fdec1a387007ee18dbb1f3f5553409c34d17f425e - languageName: node - linkType: hard - -"glob-parent@npm:^6.0.2": - version: 6.0.2 - resolution: "glob-parent@npm:6.0.2" - dependencies: - is-glob: ^4.0.3 - checksum: c13ee97978bef4f55106b71e66428eb1512e71a7466ba49025fc2aec59a5bfb0954d5abd58fc5ee6c9b076eef4e1f6d3375c2e964b88466ca390da4419a786a8 - languageName: node - linkType: hard - -"glob@npm:^7.1.3, glob@npm:^7.1.4, glob@npm:^7.1.6": - version: 7.2.3 - resolution: "glob@npm:7.2.3" - dependencies: - fs.realpath: ^1.0.0 - inflight: ^1.0.4 - inherits: 2 - minimatch: ^3.1.1 - once: ^1.3.0 - path-is-absolute: ^1.0.0 - checksum: 29452e97b38fa704dabb1d1045350fb2467cf0277e155aa9ff7077e90ad81d1ea9d53d3ee63bd37c05b09a065e90f16aec4a65f5b8de401d1dac40bc5605d133 - languageName: node - linkType: hard - -"glob@npm:^8.0.1": - version: 8.1.0 - resolution: "glob@npm:8.1.0" - dependencies: - fs.realpath: ^1.0.0 - inflight: ^1.0.4 - inherits: 2 - minimatch: ^5.0.1 - once: ^1.3.0 - checksum: 92fbea3221a7d12075f26f0227abac435de868dd0736a17170663783296d0dd8d3d532a5672b4488a439bf5d7fb85cdd07c11185d6cd39184f0385cbdfb86a47 - languageName: node - linkType: hard - -"global-agent@npm:^3.0.0": - version: 3.0.0 - resolution: "global-agent@npm:3.0.0" - dependencies: - boolean: ^3.0.1 - es6-error: ^4.1.1 - matcher: ^3.0.0 - roarr: ^2.15.3 - semver: ^7.3.2 - serialize-error: ^7.0.1 - checksum: 75074d80733b4bd5386c47f5df028e798018025beac0ab310e9908c72bf5639e408203e7bca0130d5ee01b5f4abc6d34385d96a9f950ea5fe1979bb431c808f7 - languageName: node - linkType: hard - -"globals@npm:^13.19.0": - version: 13.20.0 - resolution: "globals@npm:13.20.0" - dependencies: - type-fest: ^0.20.2 - checksum: ad1ecf914bd051325faad281d02ea2c0b1df5d01bd94d368dcc5513340eac41d14b3c61af325768e3c7f8d44576e72780ec0b6f2d366121f8eec6e03c3a3b97a - languageName: node - linkType: hard - -"globalthis@npm:^1.0.1, globalthis@npm:^1.0.3": - version: 1.0.3 - resolution: "globalthis@npm:1.0.3" - dependencies: - define-properties: ^1.1.3 - checksum: fbd7d760dc464c886d0196166d92e5ffb4c84d0730846d6621a39fbbc068aeeb9c8d1421ad330e94b7bca4bb4ea092f5f21f3d36077812af5d098b4dc006c998 - languageName: node - linkType: hard - -"globby@npm:^11.1.0": - version: 11.1.0 - resolution: "globby@npm:11.1.0" - dependencies: - array-union: ^2.1.0 - dir-glob: ^3.0.1 - fast-glob: ^3.2.9 - ignore: ^5.2.0 - merge2: ^1.4.1 - slash: ^3.0.0 - checksum: b4be8885e0cfa018fc783792942d53926c35c50b3aefd3fdcfb9d22c627639dc26bd2327a40a0b74b074100ce95bb7187bfeae2f236856aa3de183af7a02aea6 - languageName: node - linkType: hard - -"globby@npm:^13.1.2": - version: 13.1.4 - resolution: "globby@npm:13.1.4" - dependencies: - dir-glob: ^3.0.1 - fast-glob: ^3.2.11 - ignore: ^5.2.0 - merge2: ^1.4.1 - slash: ^4.0.0 - checksum: e8bc13879972082d590cd1b0e27080d90d2e12fff7eeb2cee9329c29115ace14cc5b9f899e3d6beb136ba826307a727016658919a6f383e1511d698acee81741 - languageName: node - linkType: hard - -"gopd@npm:^1.0.1": - version: 1.0.1 - resolution: "gopd@npm:1.0.1" - dependencies: - get-intrinsic: ^1.1.3 - checksum: a5ccfb8806e0917a94e0b3de2af2ea4979c1da920bc381667c260e00e7cafdbe844e2cb9c5bcfef4e5412e8bf73bab837285bc35c7ba73aaaf0134d4583393a6 - languageName: node - linkType: hard - -"got@npm:^11.8.5": - version: 11.8.6 - resolution: "got@npm:11.8.6" - dependencies: - "@sindresorhus/is": ^4.0.0 - "@szmarczak/http-timer": ^4.0.5 - "@types/cacheable-request": ^6.0.1 - "@types/responselike": ^1.0.0 - cacheable-lookup: ^5.0.3 - cacheable-request: ^7.0.2 - decompress-response: ^6.0.0 - http2-wrapper: ^1.0.0-beta.5.2 - lowercase-keys: ^2.0.0 - p-cancelable: ^2.0.0 - responselike: ^2.0.0 - checksum: bbc783578a8d5030c8164ef7f57ce41b5ad7db2ed13371e1944bef157eeca5a7475530e07c0aaa71610d7085474d0d96222c9f4268d41db333a17e39b463f45d - languageName: node - linkType: hard - -"graceful-fs@npm:^4.1.2, graceful-fs@npm:^4.1.6, graceful-fs@npm:^4.2.0, graceful-fs@npm:^4.2.10, graceful-fs@npm:^4.2.6": - version: 4.2.11 - resolution: "graceful-fs@npm:4.2.11" - checksum: ac85f94da92d8eb6b7f5a8b20ce65e43d66761c55ce85ac96df6865308390da45a8d3f0296dd3a663de65d30ba497bd46c696cc1e248c72b13d6d567138a4fc7 - languageName: node - linkType: hard - -"grapheme-splitter@npm:^1.0.4": - version: 1.0.4 - resolution: "grapheme-splitter@npm:1.0.4" - checksum: 0c22ec54dee1b05cd480f78cf14f732cb5b108edc073572c4ec205df4cd63f30f8db8025afc5debc8835a8ddeacf648a1c7992fe3dcd6ad38f9a476d84906620 - languageName: node - linkType: hard - -"handlebars@npm:^4.7.7": - version: 4.7.7 - resolution: "handlebars@npm:4.7.7" - dependencies: - minimist: ^1.2.5 - neo-async: ^2.6.0 - source-map: ^0.6.1 - uglify-js: ^3.1.4 - wordwrap: ^1.0.0 - dependenciesMeta: - uglify-js: - optional: true - bin: - handlebars: bin/handlebars - checksum: 1e79a43f5e18d15742977cb987923eab3e2a8f44f2d9d340982bcb69e1735ed049226e534d7c1074eaddaf37e4fb4f471a8adb71cddd5bc8cf3f894241df5cee - languageName: node - linkType: hard - -"hard-rejection@npm:^2.1.0": - version: 2.1.0 - resolution: "hard-rejection@npm:2.1.0" - checksum: 7baaf80a0c7fff4ca79687b4060113f1529589852152fa935e6787a2bc96211e784ad4588fb3048136ff8ffc9dfcf3ae385314a5b24db32de20bea0d1597f9dc - languageName: node - linkType: hard - -"has-bigints@npm:^1.0.1, has-bigints@npm:^1.0.2": - version: 1.0.2 - resolution: "has-bigints@npm:1.0.2" - checksum: 390e31e7be7e5c6fe68b81babb73dfc35d413604d7ee5f56da101417027a4b4ce6a27e46eff97ad040c835b5d228676eae99a9b5c3bc0e23c8e81a49241ff45b - languageName: node - linkType: hard - -"has-flag@npm:^3.0.0": - version: 3.0.0 - resolution: "has-flag@npm:3.0.0" - checksum: 4a15638b454bf086c8148979aae044dd6e39d63904cd452d970374fa6a87623423da485dfb814e7be882e05c096a7ccf1ebd48e7e7501d0208d8384ff4dea73b - languageName: node - linkType: hard - -"has-flag@npm:^4.0.0": - version: 4.0.0 - resolution: "has-flag@npm:4.0.0" - checksum: 261a1357037ead75e338156b1f9452c016a37dcd3283a972a30d9e4a87441ba372c8b81f818cd0fbcd9c0354b4ae7e18b9e1afa1971164aef6d18c2b6095a8ad - languageName: node - linkType: hard - -"has-property-descriptors@npm:^1.0.0": - version: 1.0.0 - resolution: "has-property-descriptors@npm:1.0.0" - dependencies: - get-intrinsic: ^1.1.1 - checksum: a6d3f0a266d0294d972e354782e872e2fe1b6495b321e6ef678c9b7a06a40408a6891817350c62e752adced73a94ac903c54734fee05bf65b1905ee1368194bb - languageName: node - linkType: hard - -"has-proto@npm:^1.0.1": - version: 1.0.1 - resolution: "has-proto@npm:1.0.1" - checksum: febc5b5b531de8022806ad7407935e2135f1cc9e64636c3916c6842bd7995994ca3b29871ecd7954bd35f9e2986c17b3b227880484d22259e2f8e6ce63fd383e - languageName: node - linkType: hard - -"has-symbols@npm:^1.0.2, has-symbols@npm:^1.0.3": - version: 1.0.3 - resolution: "has-symbols@npm:1.0.3" - checksum: a054c40c631c0d5741a8285010a0777ea0c068f99ed43e5d6eb12972da223f8af553a455132fdb0801bdcfa0e0f443c0c03a68d8555aa529b3144b446c3f2410 - languageName: node - linkType: hard - -"has-tostringtag@npm:^1.0.0": - version: 1.0.0 - resolution: "has-tostringtag@npm:1.0.0" - dependencies: - has-symbols: ^1.0.2 - checksum: cc12eb28cb6ae22369ebaad3a8ab0799ed61270991be88f208d508076a1e99abe4198c965935ce85ea90b60c94ddda73693b0920b58e7ead048b4a391b502c1c - languageName: node - linkType: hard - -"has-unicode@npm:^2.0.1": - version: 2.0.1 - resolution: "has-unicode@npm:2.0.1" - checksum: 1eab07a7436512db0be40a710b29b5dc21fa04880b7f63c9980b706683127e3c1b57cb80ea96d47991bdae2dfe479604f6a1ba410106ee1046a41d1bd0814400 - languageName: node - linkType: hard - -"has@npm:^1.0.3": - version: 1.0.3 - resolution: "has@npm:1.0.3" - dependencies: - function-bind: ^1.1.1 - checksum: b9ad53d53be4af90ce5d1c38331e712522417d017d5ef1ebd0507e07c2fbad8686fffb8e12ddecd4c39ca9b9b47431afbb975b8abf7f3c3b82c98e9aad052792 - languageName: node - linkType: hard - -"hexy@npm:^0.2.10": - version: 0.2.11 - resolution: "hexy@npm:0.2.11" - bin: - hexy: ./bin/hexy_cmd.js - checksum: 0bd59c95a3ceb9d34b68062b6a48dc70a33f20dbc2d7f01c57c397590cb5044d823b0f5ce1759e4423f307614149a27e996ab9877a81565c8c6a0dad9c070eda - languageName: node - linkType: hard - -"hosted-git-info@npm:^2.1.4": - version: 2.8.9 - resolution: "hosted-git-info@npm:2.8.9" - checksum: c955394bdab888a1e9bb10eb33029e0f7ce5a2ac7b3f158099dc8c486c99e73809dca609f5694b223920ca2174db33d32b12f9a2a47141dc59607c29da5a62dd - languageName: node - linkType: hard - -"hosted-git-info@npm:^4.0.1, hosted-git-info@npm:^4.1.0": - version: 4.1.0 - resolution: "hosted-git-info@npm:4.1.0" - dependencies: - lru-cache: ^6.0.0 - checksum: c3f87b3c2f7eb8c2748c8f49c0c2517c9a95f35d26f4bf54b2a8cba05d2e668f3753548b6ea366b18ec8dadb4e12066e19fa382a01496b0ffa0497eb23cbe461 - languageName: node - linkType: hard - -"hosted-git-info@npm:^5.0.0": - version: 5.2.1 - resolution: "hosted-git-info@npm:5.2.1" - dependencies: - lru-cache: ^7.5.1 - checksum: fa35df185224adfd69141f3b2f8cc31f50e705a5ebb415ccfbfd055c5b94bd08d3e658edf1edad9e2ac7d81831ac7cf261f5d219b3adc8d744fb8cdacaaf2ead - languageName: node - linkType: hard - -"howler@npm:^2.2.3": - version: 2.2.3 - resolution: "howler@npm:2.2.3" - checksum: c04ce19411f4d86f8508d411a93aea943f128c2686b3df3c61383fd4ed8f5551232c4389aba3a8d4c8b0eeb34ae51df5a9c3ccd9ba48583ac53e9bf9fcbd1ecf - languageName: node - linkType: hard - -"html-escaper@npm:^3.0.3": - version: 3.0.3 - resolution: "html-escaper@npm:3.0.3" - checksum: a2678be42c15d2ef6e629775dac0925a729f4615c6593db8358b9262c7565c4627134987c00f548eb4eb76cbc3b3392f78475cd02b022f8ae7aeb9a88280831b - languageName: node - linkType: hard - -"html-to-text@npm:^9.0.5": - version: 9.0.5 - resolution: "html-to-text@npm:9.0.5" - dependencies: - "@selderee/plugin-htmlparser2": ^0.11.0 - deepmerge: ^4.3.1 - dom-serializer: ^2.0.0 - htmlparser2: ^8.0.2 - selderee: ^0.11.0 - checksum: 205e0faa9b9aa281b369122acdffc5f348848e400f4037fde1fb12d68a6baa11644d2b64c3cc6821a79d3bc7316d89e85cc733d86f7f709858cb5c5b72faac65 - languageName: node - linkType: hard - -"htmlparser2@npm:^8.0.1, htmlparser2@npm:^8.0.2": - version: 8.0.2 - resolution: "htmlparser2@npm:8.0.2" - dependencies: - domelementtype: ^2.3.0 - domhandler: ^5.0.3 - domutils: ^3.0.1 - entities: ^4.4.0 - checksum: 29167a0f9282f181da8a6d0311b76820c8a59bc9e3c87009e21968264c2987d2723d6fde5a964d4b7b6cba663fca96ffb373c06d8223a85f52a6089ced942700 - languageName: node - linkType: hard - -"http-cache-semantics@npm:^4.0.0, http-cache-semantics@npm:^4.1.0": - version: 4.1.1 - resolution: "http-cache-semantics@npm:4.1.1" - checksum: 83ac0bc60b17a3a36f9953e7be55e5c8f41acc61b22583060e8dedc9dd5e3607c823a88d0926f9150e571f90946835c7fe150732801010845c72cd8bbff1a236 - languageName: node - linkType: hard - -"http-proxy-agent@npm:^5.0.0": - version: 5.0.0 - resolution: "http-proxy-agent@npm:5.0.0" - dependencies: - "@tootallnate/once": 2 - agent-base: 6 - debug: 4 - checksum: e2ee1ff1656a131953839b2a19cd1f3a52d97c25ba87bd2559af6ae87114abf60971e498021f9b73f9fd78aea8876d1fb0d4656aac8a03c6caa9fc175f22b786 - languageName: node - linkType: hard - -"http2-wrapper@npm:^1.0.0-beta.5.2": - version: 1.0.3 - resolution: "http2-wrapper@npm:1.0.3" - dependencies: - quick-lru: ^5.1.1 - resolve-alpn: ^1.0.0 - checksum: 74160b862ec699e3f859739101ff592d52ce1cb207b7950295bf7962e4aa1597ef709b4292c673bece9c9b300efad0559fc86c71b1409c7a1e02b7229456003e - languageName: node - linkType: hard - -"https-proxy-agent@npm:^5.0.0": - version: 5.0.1 - resolution: "https-proxy-agent@npm:5.0.1" - dependencies: - agent-base: 6 - debug: 4 - checksum: 571fccdf38184f05943e12d37d6ce38197becdd69e58d03f43637f7fa1269cf303a7d228aa27e5b27bbd3af8f09fd938e1c91dcfefff2df7ba77c20ed8dfc765 - languageName: node - linkType: hard - -"human-signals@npm:^2.1.0": - version: 2.1.0 - resolution: "human-signals@npm:2.1.0" - checksum: b87fd89fce72391625271454e70f67fe405277415b48bcc0117ca73d31fa23a4241787afdc8d67f5a116cf37258c052f59ea82daffa72364d61351423848e3b8 - languageName: node - linkType: hard - -"humanize-ms@npm:^1.2.1": - version: 1.2.1 - resolution: "humanize-ms@npm:1.2.1" - dependencies: - ms: ^2.0.0 - checksum: 9c7a74a2827f9294c009266c82031030eae811ca87b0da3dceb8d6071b9bde22c9f3daef0469c3c533cc67a97d8a167cd9fc0389350e5f415f61a79b171ded16 - languageName: node - linkType: hard - -"iconv-corefoundation@npm:^1.1.7": - version: 1.1.7 - resolution: "iconv-corefoundation@npm:1.1.7" - dependencies: - cli-truncate: ^2.1.0 - node-addon-api: ^1.6.3 - conditions: os=darwin - languageName: node - linkType: hard - -"iconv-lite@npm:^0.6.2": - version: 0.6.3 - resolution: "iconv-lite@npm:0.6.3" - dependencies: - safer-buffer: ">= 2.1.2 < 3.0.0" - checksum: 3f60d47a5c8fc3313317edfd29a00a692cc87a19cac0159e2ce711d0ebc9019064108323b5e493625e25594f11c6236647d8e256fbe7a58f4a3b33b89e6d30bf - languageName: node - linkType: hard - -"ieee754@npm:^1.1.13": - version: 1.2.1 - resolution: "ieee754@npm:1.2.1" - checksum: 5144c0c9815e54ada181d80a0b810221a253562422e7c6c3a60b1901154184f49326ec239d618c416c1c5945a2e197107aee8d986a3dd836b53dffefd99b5e7e - languageName: node - linkType: hard - -"ignore@npm:^5.0.5, ignore@npm:^5.1.1, ignore@npm:^5.2.0": - version: 5.2.4 - resolution: "ignore@npm:5.2.4" - checksum: 3d4c309c6006e2621659311783eaea7ebcd41fe4ca1d78c91c473157ad6666a57a2df790fe0d07a12300d9aac2888204d7be8d59f9aaf665b1c7fcdb432517ef - languageName: node - linkType: hard - -"immediate@npm:~3.0.5": - version: 3.0.6 - resolution: "immediate@npm:3.0.6" - checksum: f9b3486477555997657f70318cc8d3416159f208bec4cca3ff3442fd266bc23f50f0c9bd8547e1371a6b5e82b821ec9a7044a4f7b944798b25aa3cc6d5e63e62 - languageName: node - linkType: hard - -"import-fresh@npm:^3.0.0, import-fresh@npm:^3.2.1": - version: 3.3.0 - resolution: "import-fresh@npm:3.3.0" - dependencies: - parent-module: ^1.0.0 - resolve-from: ^4.0.0 - checksum: 2cacfad06e652b1edc50be650f7ec3be08c5e5a6f6d12d035c440a42a8cc028e60a5b99ca08a77ab4d6b1346da7d971915828f33cdab730d3d42f08242d09baa - languageName: node - linkType: hard - -"import-meta-resolve@npm:2.2.2": - version: 2.2.2 - resolution: "import-meta-resolve@npm:2.2.2" - checksum: 3a5910a6f914b5f06b307d7d1c25710bc56f12e21e923d5b2180dd0d53c6c2d51e7b55df26f168b63f5670babcaca9422b7a9429e877bbb8c1997d79bd65882b - languageName: node - linkType: hard - -"import-modules@npm:^2.1.0": - version: 2.1.0 - resolution: "import-modules@npm:2.1.0" - checksum: d9ac33dfea5a301c0cdc51455d875c373b2c04eb673488cb6d706474612575763f8ea6353d0b4a5bfffb2a9a06cbf4ecba90d8d9db4aa5f736fa957acbbc851c - languageName: node - linkType: hard - -"imurmurhash@npm:^0.1.4": - version: 0.1.4 - resolution: "imurmurhash@npm:0.1.4" - checksum: 7cae75c8cd9a50f57dadd77482359f659eaebac0319dd9368bcd1714f55e65badd6929ca58569da2b6494ef13fdd5598cd700b1eba23f8b79c5f19d195a3ecf7 - languageName: node - linkType: hard - -"indent-string@npm:^4.0.0": - version: 4.0.0 - resolution: "indent-string@npm:4.0.0" - checksum: 824cfb9929d031dabf059bebfe08cf3137365e112019086ed3dcff6a0a7b698cb80cf67ccccde0e25b9e2d7527aa6cc1fed1ac490c752162496caba3e6699612 - languageName: node - linkType: hard - -"indent-string@npm:^5.0.0": - version: 5.0.0 - resolution: "indent-string@npm:5.0.0" - checksum: e466c27b6373440e6d84fbc19e750219ce25865cb82d578e41a6053d727e5520dc5725217d6eb1cc76005a1bb1696a0f106d84ce7ebda3033b963a38583fb3b3 - languageName: node - linkType: hard - -"infer-owner@npm:^1.0.4": - version: 1.0.4 - resolution: "infer-owner@npm:1.0.4" - checksum: 181e732764e4a0611576466b4b87dac338972b839920b2a8cde43642e4ed6bd54dc1fb0b40874728f2a2df9a1b097b8ff83b56d5f8f8e3927f837fdcb47d8a89 - languageName: node - linkType: hard - -"inflight@npm:^1.0.4": - version: 1.0.6 - resolution: "inflight@npm:1.0.6" - dependencies: - once: ^1.3.0 - wrappy: 1 - checksum: f4f76aa072ce19fae87ce1ef7d221e709afb59d445e05d47fba710e85470923a75de35bfae47da6de1b18afc3ce83d70facf44cfb0aff89f0a3f45c0a0244dfd - languageName: node - linkType: hard - -"inherits@npm:2, inherits@npm:^2.0.3, inherits@npm:~2.0.3": - version: 2.0.4 - resolution: "inherits@npm:2.0.4" - checksum: 4a48a733847879d6cf6691860a6b1e3f0f4754176e4d71494c41f3475553768b10f84b5ce1d40fbd0e34e6bfbb864ee35858ad4dd2cf31e02fc4a154b724d7f1 - languageName: node - linkType: hard - -"internal-slot@npm:^1.0.5": - version: 1.0.5 - resolution: "internal-slot@npm:1.0.5" - dependencies: - get-intrinsic: ^1.2.0 - has: ^1.0.3 - side-channel: ^1.0.4 - checksum: 97e84046bf9e7574d0956bd98d7162313ce7057883b6db6c5c7b5e5f05688864b0978ba07610c726d15d66544ffe4b1050107d93f8a39ebc59b15d8b429b497a - languageName: node - linkType: hard - -"interpret@npm:^1.4.0": - version: 1.4.0 - resolution: "interpret@npm:1.4.0" - checksum: 2e5f51268b5941e4a17e4ef0575bc91ed0ab5f8515e3cf77486f7c14d13f3010df9c0959f37063dcc96e78d12dc6b0bb1b9e111cdfe69771f4656d2993d36155 - languageName: node - linkType: hard - -"ip@npm:^2.0.0": - version: 2.0.0 - resolution: "ip@npm:2.0.0" - checksum: cfcfac6b873b701996d71ec82a7dd27ba92450afdb421e356f44044ed688df04567344c36cbacea7d01b1c39a4c732dc012570ebe9bebfb06f27314bca625349 - languageName: node - linkType: hard - -"irregular-plurals@npm:^3.2.0": - version: 3.5.0 - resolution: "irregular-plurals@npm:3.5.0" - checksum: 5b663091dc89155df7b2e9d053e8fb11941a0c4be95c4b6549ed3ea020489fdf4f75ea586c915b5b543704252679a5a6e8c6c3587da5ac3fc57b12da90a9aee7 - languageName: node - linkType: hard - -"is-absolute@npm:^1.0.0": - version: 1.0.0 - resolution: "is-absolute@npm:1.0.0" - dependencies: - is-relative: ^1.0.0 - is-windows: ^1.0.1 - checksum: 9d16b2605eda3f3ce755410f1d423e327ad3a898bcb86c9354cf63970ed3f91ba85e9828aa56f5d6a952b9fae43d0477770f78d37409ae8ecc31e59ebc279b27 - languageName: node - linkType: hard - -"is-arguments@npm:^1.0.4": - version: 1.1.1 - resolution: "is-arguments@npm:1.1.1" - dependencies: - call-bind: ^1.0.2 - has-tostringtag: ^1.0.0 - checksum: 7f02700ec2171b691ef3e4d0e3e6c0ba408e8434368504bb593d0d7c891c0dbfda6d19d30808b904a6cb1929bca648c061ba438c39f296c2a8ca083229c49f27 - languageName: node - linkType: hard - -"is-array-buffer@npm:^3.0.1, is-array-buffer@npm:^3.0.2": - version: 3.0.2 - resolution: "is-array-buffer@npm:3.0.2" - dependencies: - call-bind: ^1.0.2 - get-intrinsic: ^1.2.0 - is-typed-array: ^1.1.10 - checksum: dcac9dda66ff17df9cabdc58214172bf41082f956eab30bb0d86bc0fab1e44b690fc8e1f855cf2481245caf4e8a5a006a982a71ddccec84032ed41f9d8da8c14 - languageName: node - linkType: hard - -"is-arrayish@npm:^0.2.1": - version: 0.2.1 - resolution: "is-arrayish@npm:0.2.1" - checksum: eef4417e3c10e60e2c810b6084942b3ead455af16c4509959a27e490e7aee87cfb3f38e01bbde92220b528a0ee1a18d52b787e1458ee86174d8c7f0e58cd488f - languageName: node - linkType: hard - -"is-bigint@npm:^1.0.1": - version: 1.0.4 - resolution: "is-bigint@npm:1.0.4" - dependencies: - has-bigints: ^1.0.1 - checksum: c56edfe09b1154f8668e53ebe8252b6f185ee852a50f9b41e8d921cb2bed425652049fbe438723f6cb48a63ca1aa051e948e7e401e093477c99c84eba244f666 - languageName: node - linkType: hard - -"is-boolean-object@npm:^1.1.0": - version: 1.1.2 - resolution: "is-boolean-object@npm:1.1.2" - dependencies: - call-bind: ^1.0.2 - has-tostringtag: ^1.0.0 - checksum: c03b23dbaacadc18940defb12c1c0e3aaece7553ef58b162a0f6bba0c2a7e1551b59f365b91e00d2dbac0522392d576ef322628cb1d036a0fe51eb466db67222 - languageName: node - linkType: hard - -"is-buffer@npm:~1.1.6": - version: 1.1.6 - resolution: "is-buffer@npm:1.1.6" - checksum: 4a186d995d8bbf9153b4bd9ff9fd04ae75068fe695d29025d25e592d9488911eeece84eefbd8fa41b8ddcc0711058a71d4c466dcf6f1f6e1d83830052d8ca707 - languageName: node - linkType: hard - -"is-builtin-module@npm:^3.2.0": - version: 3.2.1 - resolution: "is-builtin-module@npm:3.2.1" - dependencies: - builtin-modules: ^3.3.0 - checksum: e8f0ffc19a98240bda9c7ada84d846486365af88d14616e737d280d378695c8c448a621dcafc8332dbf0fcd0a17b0763b845400709963fa9151ddffece90ae88 - languageName: node - linkType: hard - -"is-callable@npm:^1.1.3, is-callable@npm:^1.1.4, is-callable@npm:^1.2.7": - version: 1.2.7 - resolution: "is-callable@npm:1.2.7" - checksum: 61fd57d03b0d984e2ed3720fb1c7a897827ea174bd44402878e059542ea8c4aeedee0ea0985998aa5cc2736b2fa6e271c08587addb5b3959ac52cf665173d1ac - languageName: node - linkType: hard - -"is-ci@npm:^3.0.0": - version: 3.0.1 - resolution: "is-ci@npm:3.0.1" - dependencies: - ci-info: ^3.2.0 - bin: - is-ci: bin.js - checksum: 192c66dc7826d58f803ecae624860dccf1899fc1f3ac5505284c0a5cf5f889046ffeb958fa651e5725d5705c5bcb14f055b79150ea5fcad7456a9569de60260e - languageName: node - linkType: hard - -"is-core-module@npm:^2.11.0, is-core-module@npm:^2.12.0, is-core-module@npm:^2.5.0, is-core-module@npm:^2.7.0, is-core-module@npm:^2.8.1": - version: 2.12.0 - resolution: "is-core-module@npm:2.12.0" - dependencies: - has: ^1.0.3 - checksum: f7f7eb2ab71fd769ee9fb2385c095d503aa4b5ce0028c04557de03f1e67a87c85e5bac1f215945fc3c955867a139a415a3ec4c4234a0bffdf715232660f440a6 - languageName: node - linkType: hard - -"is-date-object@npm:^1.0.1": - version: 1.0.5 - resolution: "is-date-object@npm:1.0.5" - dependencies: - has-tostringtag: ^1.0.0 - checksum: baa9077cdf15eb7b58c79398604ca57379b2fc4cf9aa7a9b9e295278648f628c9b201400c01c5e0f7afae56507d741185730307cbe7cad3b9f90a77e5ee342fc - languageName: node - linkType: hard - -"is-docker@npm:^2.0.0, is-docker@npm:^2.1.1": - version: 2.2.1 - resolution: "is-docker@npm:2.2.1" - bin: - is-docker: cli.js - checksum: 3fef7ddbf0be25958e8991ad941901bf5922ab2753c46980b60b05c1bf9c9c2402d35e6dc32e4380b980ef5e1970a5d9d5e5aa2e02d77727c3b6b5e918474c56 - languageName: node - linkType: hard - -"is-extglob@npm:^2.1.1": - version: 2.1.1 - resolution: "is-extglob@npm:2.1.1" - checksum: df033653d06d0eb567461e58a7a8c9f940bd8c22274b94bf7671ab36df5719791aae15eef6d83bbb5e23283967f2f984b8914559d4449efda578c775c4be6f85 - languageName: node - linkType: hard - -"is-fullwidth-code-point@npm:^3.0.0": - version: 3.0.0 - resolution: "is-fullwidth-code-point@npm:3.0.0" - checksum: 44a30c29457c7fb8f00297bce733f0a64cd22eca270f83e58c105e0d015e45c019491a4ab2faef91ab51d4738c670daff901c799f6a700e27f7314029e99e348 - languageName: node - linkType: hard - -"is-get-set-prop@npm:^1.0.0": - version: 1.0.0 - resolution: "is-get-set-prop@npm:1.0.0" - dependencies: - get-set-props: ^0.1.0 - lowercase-keys: ^1.0.0 - checksum: c606ba16bda0185d0f6c0c85c7ef2c4ad4e0c85381bdbee2f0fa92fc4601f6a8d0bf42164f25c6744153059916cae5d9206fead63390d9b1f948d3abe9780408 - languageName: node - linkType: hard - -"is-glob@npm:^4.0.0, is-glob@npm:^4.0.1, is-glob@npm:^4.0.3": - version: 4.0.3 - resolution: "is-glob@npm:4.0.3" - dependencies: - is-extglob: ^2.1.1 - checksum: d381c1319fcb69d341cc6e6c7cd588e17cd94722d9a32dbd60660b993c4fb7d0f19438674e68dfec686d09b7c73139c9166b47597f846af387450224a8101ab4 - languageName: node - linkType: hard - -"is-js-type@npm:^2.0.0": - version: 2.0.0 - resolution: "is-js-type@npm:2.0.0" - dependencies: - js-types: ^1.0.0 - checksum: 94a1ff44201e0ee6540ed292484a2a6530efd66ac277c9fcfae62086a1838e6b66ed58d7666bfd228fbf99a5f3cc50fd0768e7fc112fc026e122d2fd3f7c4c59 - languageName: node - linkType: hard - -"is-lambda@npm:^1.0.1": - version: 1.0.1 - resolution: "is-lambda@npm:1.0.1" - checksum: 93a32f01940220532e5948538699ad610d5924ac86093fcee83022252b363eb0cc99ba53ab084a04e4fb62bf7b5731f55496257a4c38adf87af9c4d352c71c35 - languageName: node - linkType: hard - -"is-negated-glob@npm:^1.0.0": - version: 1.0.0 - resolution: "is-negated-glob@npm:1.0.0" - checksum: 2a767da06435b492daa98d3049480f0b7032abd5bfd3930ac01dbe9d6fcae04f2b3d883c6dca6b9c0c3f8a703952643c78540151c3eb1a2fe90fec543d61d241 - languageName: node - linkType: hard - -"is-negative-zero@npm:^2.0.2": - version: 2.0.2 - resolution: "is-negative-zero@npm:2.0.2" - checksum: f3232194c47a549da60c3d509c9a09be442507616b69454716692e37ae9f37c4dea264fb208ad0c9f3efd15a796a46b79df07c7e53c6227c32170608b809149a - languageName: node - linkType: hard - -"is-number-object@npm:^1.0.4": - version: 1.0.7 - resolution: "is-number-object@npm:1.0.7" - dependencies: - has-tostringtag: ^1.0.0 - checksum: d1e8d01bb0a7134c74649c4e62da0c6118a0bfc6771ea3c560914d52a627873e6920dd0fd0ebc0e12ad2ff4687eac4c308f7e80320b973b2c8a2c8f97a7524f7 - languageName: node - linkType: hard - -"is-number@npm:^7.0.0": - version: 7.0.0 - resolution: "is-number@npm:7.0.0" - checksum: 456ac6f8e0f3111ed34668a624e45315201dff921e5ac181f8ec24923b99e9f32ca1a194912dc79d539c97d33dba17dc635202ff0b2cf98326f608323276d27a - languageName: node - linkType: hard - -"is-obj-prop@npm:^1.0.0": - version: 1.0.0 - resolution: "is-obj-prop@npm:1.0.0" - dependencies: - lowercase-keys: ^1.0.0 - obj-props: ^1.0.0 - checksum: 887f8397e0652544c0a42596976bde32e0f9453486fbe04fe0d4e1ee09b4e5f59682e23c4ec15017015fe9b5b478fb61c16aaca4226a9211f8516690b0b2515e - languageName: node - linkType: hard - -"is-obj@npm:^2.0.0": - version: 2.0.0 - resolution: "is-obj@npm:2.0.0" - checksum: c9916ac8f4621962a42f5e80e7ffdb1d79a3fab7456ceaeea394cd9e0858d04f985a9ace45be44433bf605673c8be8810540fe4cc7f4266fc7526ced95af5a08 - languageName: node - linkType: hard - -"is-path-cwd@npm:^3.0.0": - version: 3.0.0 - resolution: "is-path-cwd@npm:3.0.0" - checksum: bc34d13b6a03dfca4a3ab6a8a5ba78ae4b24f4f1db4b2b031d2760c60d0913bd16a4b980dcb4e590adfc906649d5f5132684079a3972bd219da49deebb9adea8 - languageName: node - linkType: hard - -"is-path-inside@npm:^3.0.3": - version: 3.0.3 - resolution: "is-path-inside@npm:3.0.3" - checksum: abd50f06186a052b349c15e55b182326f1936c89a78bf6c8f2b707412517c097ce04bc49a0ca221787bc44e1049f51f09a2ffb63d22899051988d3a618ba13e9 - languageName: node - linkType: hard - -"is-path-inside@npm:^4.0.0": - version: 4.0.0 - resolution: "is-path-inside@npm:4.0.0" - checksum: 8810fa11c58e6360b82c3e0d6cd7d9c7d0392d3ac9eb10f980b81f9839f40ac6d1d6d6f05d069db0d227759801228f0b072e1b6c343e4469b065ab5fe0b68fe5 - languageName: node - linkType: hard - -"is-plain-obj@npm:^1.1.0": - version: 1.1.0 - resolution: "is-plain-obj@npm:1.1.0" - checksum: 0ee04807797aad50859652a7467481816cbb57e5cc97d813a7dcd8915da8195dc68c436010bf39d195226cde6a2d352f4b815f16f26b7bf486a5754290629931 - languageName: node - linkType: hard - -"is-proto-prop@npm:^2.0.0": - version: 2.0.0 - resolution: "is-proto-prop@npm:2.0.0" - dependencies: - lowercase-keys: ^1.0.0 - proto-props: ^2.0.0 - checksum: 66dbc1996d802de3b1f4c30b1113d9943e1de6d1c7c3372be9974a12671a82d568f3c1f406c6e2529b44757358a0c56336bb8ba2a86b0ff24b5177edd2266898 - languageName: node - linkType: hard - -"is-regex@npm:^1.0.4, is-regex@npm:^1.1.4": - version: 1.1.4 - resolution: "is-regex@npm:1.1.4" - dependencies: - call-bind: ^1.0.2 - has-tostringtag: ^1.0.0 - checksum: 362399b33535bc8f386d96c45c9feb04cf7f8b41c182f54174c1a45c9abbbe5e31290bbad09a458583ff6bf3b2048672cdb1881b13289569a7c548370856a652 - languageName: node - linkType: hard - -"is-relative@npm:^1.0.0": - version: 1.0.0 - resolution: "is-relative@npm:1.0.0" - dependencies: - is-unc-path: ^1.0.0 - checksum: 3271a0df109302ef5e14a29dcd5d23d9788e15ade91a40b942b035827ffbb59f7ce9ff82d036ea798541a52913cbf9d2d0b66456340887b51f3542d57b5a4c05 - languageName: node - linkType: hard - -"is-shared-array-buffer@npm:^1.0.2": - version: 1.0.2 - resolution: "is-shared-array-buffer@npm:1.0.2" - dependencies: - call-bind: ^1.0.2 - checksum: 9508929cf14fdc1afc9d61d723c6e8d34f5e117f0bffda4d97e7a5d88c3a8681f633a74f8e3ad1fe92d5113f9b921dc5ca44356492079612f9a247efbce7032a - languageName: node - linkType: hard - -"is-stream@npm:^2.0.0": - version: 2.0.1 - resolution: "is-stream@npm:2.0.1" - checksum: b8e05ccdf96ac330ea83c12450304d4a591f9958c11fd17bed240af8d5ffe08aedafa4c0f4cfccd4d28dc9d4d129daca1023633d5c11601a6cbc77521f6fae66 - languageName: node - linkType: hard - -"is-string@npm:^1.0.5, is-string@npm:^1.0.7": - version: 1.0.7 - resolution: "is-string@npm:1.0.7" - dependencies: - has-tostringtag: ^1.0.0 - checksum: 323b3d04622f78d45077cf89aab783b2f49d24dc641aa89b5ad1a72114cfeff2585efc8c12ef42466dff32bde93d839ad321b26884cf75e5a7892a938b089989 - languageName: node - linkType: hard - -"is-symbol@npm:^1.0.2, is-symbol@npm:^1.0.3": - version: 1.0.4 - resolution: "is-symbol@npm:1.0.4" - dependencies: - has-symbols: ^1.0.2 - checksum: 92805812ef590738d9de49d677cd17dfd486794773fb6fa0032d16452af46e9b91bb43ffe82c983570f015b37136f4b53b28b8523bfb10b0ece7a66c31a54510 - languageName: node - linkType: hard - -"is-typed-array@npm:^1.1.10, is-typed-array@npm:^1.1.9": - version: 1.1.10 - resolution: "is-typed-array@npm:1.1.10" - dependencies: - available-typed-arrays: ^1.0.5 - call-bind: ^1.0.2 - for-each: ^0.3.3 - gopd: ^1.0.1 - has-tostringtag: ^1.0.0 - checksum: aac6ecb59d4c56a1cdeb69b1f129154ef462bbffe434cb8a8235ca89b42f258b7ae94073c41b3cb7bce37f6a1733ad4499f07882d5d5093a7ba84dfc4ebb8017 - languageName: node - linkType: hard - -"is-unc-path@npm:^1.0.0": - version: 1.0.0 - resolution: "is-unc-path@npm:1.0.0" - dependencies: - unc-path-regex: ^0.1.2 - checksum: e8abfde203f7409f5b03a5f1f8636e3a41e78b983702ef49d9343eb608cdfe691429398e8815157519b987b739bcfbc73ae7cf4c8582b0ab66add5171088eab6 - languageName: node - linkType: hard - -"is-unicode-supported@npm:^0.1.0": - version: 0.1.0 - resolution: "is-unicode-supported@npm:0.1.0" - checksum: a2aab86ee7712f5c2f999180daaba5f361bdad1efadc9610ff5b8ab5495b86e4f627839d085c6530363c6d6d4ecbde340fb8e54bdb83da4ba8e0865ed5513c52 - languageName: node - linkType: hard - -"is-url@npm:^1.2.4": - version: 1.2.4 - resolution: "is-url@npm:1.2.4" - checksum: 100e74b3b1feab87a43ef7653736e88d997eb7bd32e71fd3ebc413e58c1cbe56269699c776aaea84244b0567f2a7d68dfaa512a062293ed2f9fdecb394148432 - languageName: node - linkType: hard - -"is-weakref@npm:^1.0.2": - version: 1.0.2 - resolution: "is-weakref@npm:1.0.2" - dependencies: - call-bind: ^1.0.2 - checksum: 95bd9a57cdcb58c63b1c401c60a474b0f45b94719c30f548c891860f051bc2231575c290a6b420c6bc6e7ed99459d424c652bd5bf9a1d5259505dc35b4bf83de - languageName: node - linkType: hard - -"is-windows@npm:^1.0.1": - version: 1.0.2 - resolution: "is-windows@npm:1.0.2" - checksum: 438b7e52656fe3b9b293b180defb4e448088e7023a523ec21a91a80b9ff8cdb3377ddb5b6e60f7c7de4fa8b63ab56e121b6705fe081b3cf1b828b0a380009ad7 - languageName: node - linkType: hard - -"is-wsl@npm:^2.2.0": - version: 2.2.0 - resolution: "is-wsl@npm:2.2.0" - dependencies: - is-docker: ^2.0.0 - checksum: 20849846ae414997d290b75e16868e5261e86ff5047f104027026fd61d8b5a9b0b3ade16239f35e1a067b3c7cc02f70183cb661010ed16f4b6c7c93dad1b19d8 - languageName: node - linkType: hard - -"isarray@npm:~1.0.0": - version: 1.0.0 - resolution: "isarray@npm:1.0.0" - checksum: f032df8e02dce8ec565cf2eb605ea939bdccea528dbcf565cdf92bfa2da9110461159d86a537388ef1acef8815a330642d7885b29010e8f7eac967c9993b65ab - languageName: node - linkType: hard - -"isbinaryfile@npm:^3.0.2": - version: 3.0.3 - resolution: "isbinaryfile@npm:3.0.3" - dependencies: - buffer-alloc: ^1.2.0 - checksum: 9a555786857c66fe36024d15a54e0ca371c02275622b007356d6afca2b3bca179cb0bd97e1adf5d3922b3325c0fe22813645c7f7eafb4c4bdab1da9d635133c2 - languageName: node - linkType: hard - -"isbinaryfile@npm:^4.0.10": - version: 4.0.10 - resolution: "isbinaryfile@npm:4.0.10" - checksum: a6b28db7e23ac7a77d3707567cac81356ea18bd602a4f21f424f862a31d0e7ab4f250759c98a559ece35ffe4d99f0d339f1ab884ffa9795172f632ab8f88e686 - languageName: node - linkType: hard - -"isexe@npm:^2.0.0": - version: 2.0.0 - resolution: "isexe@npm:2.0.0" - checksum: 26bf6c5480dda5161c820c5b5c751ae1e766c587b1f951ea3fcfc973bafb7831ae5b54a31a69bd670220e42e99ec154475025a468eae58ea262f813fdc8d1c62 - languageName: node - linkType: hard - -"jake@npm:^10.8.5": - version: 10.8.5 - resolution: "jake@npm:10.8.5" - dependencies: - async: ^3.2.3 - chalk: ^4.0.2 - filelist: ^1.0.1 - minimatch: ^3.0.4 - bin: - jake: ./bin/cli.js - checksum: 56c913ecf5a8d74325d0af9bc17a233bad50977438d44864d925bb6c45c946e0fee8c4c1f5fe2225471ef40df5222e943047982717ebff0d624770564d3c46ba - languageName: node - linkType: hard - -"jintr@npm:^1.0.0": - version: 1.0.0 - resolution: "jintr@npm:1.0.0" - dependencies: - acorn: ^8.8.0 - checksum: e5cb3e8d3fefc2c3e089aa1a534715dd76925cf9586d2f1c6feb7489402441fb171e7bf617f0fa0297e170382a7f1d85a35eacfc79cc84d1d6c5dd5761fb35a8 - languageName: node - linkType: hard - -"js-sdsl@npm:^4.1.4": - version: 4.4.0 - resolution: "js-sdsl@npm:4.4.0" - checksum: 7bb08a2d746ab7ff742720339aa006c631afe05e77d11eda988c1c35fae8e03e492e4e347e883e786e3ce6170685d4780c125619111f0730c11fdb41b04059c7 - languageName: node - linkType: hard - -"js-tokens@npm:^4.0.0": - version: 4.0.0 - resolution: "js-tokens@npm:4.0.0" - checksum: 8a95213a5a77deb6cbe94d86340e8d9ace2b93bc367790b260101d2f36a2eaf4e4e22d9fa9cf459b38af3a32fb4190e638024cf82ec95ef708680e405ea7cc78 - languageName: node - linkType: hard - -"js-types@npm:^1.0.0": - version: 1.0.0 - resolution: "js-types@npm:1.0.0" - checksum: 22540fa780ec48633c3f83f016bde1c5934a62b07e9d8f8187c7c5f12e64a8ea498cb60177b6438c550e91ab7f039c4a8ce832a1bee651e04ddde1efc78be22b - languageName: node - linkType: hard - -"js-yaml@npm:^4.1.0": - version: 4.1.0 - resolution: "js-yaml@npm:4.1.0" - dependencies: - argparse: ^2.0.1 - bin: - js-yaml: bin/js-yaml.js - checksum: c7830dfd456c3ef2c6e355cc5a92e6700ceafa1d14bba54497b34a99f0376cecbb3e9ac14d3e5849b426d5a5140709a66237a8c991c675431271c4ce5504151a - languageName: node - linkType: hard - -"jsbi@npm:^2.0.5": - version: 2.0.5 - resolution: "jsbi@npm:2.0.5" - checksum: dc9c44516ec5ff59c416f248c51e8af68f8ab24240c7f32ec10af42eb8e2efdab656ab9d48c1a84d6c4b5a6ad069e48972ea0a80481ca6b3cd4b6c655efe91d2 - languageName: node - linkType: hard - -"json-buffer@npm:3.0.1": - version: 3.0.1 - resolution: "json-buffer@npm:3.0.1" - checksum: 9026b03edc2847eefa2e37646c579300a1f3a4586cfb62bf857832b60c852042d0d6ae55d1afb8926163fa54c2b01d83ae24705f34990348bdac6273a29d4581 - languageName: node - linkType: hard - -"json-parse-even-better-errors@npm:^2.3.0": - version: 2.3.1 - resolution: "json-parse-even-better-errors@npm:2.3.1" - checksum: 798ed4cf3354a2d9ccd78e86d2169515a0097a5c133337807cdf7f1fc32e1391d207ccfc276518cc1d7d8d4db93288b8a50ba4293d212ad1336e52a8ec0a941f - languageName: node - linkType: hard - -"json-schema-traverse@npm:^0.4.1": - version: 0.4.1 - resolution: "json-schema-traverse@npm:0.4.1" - checksum: 7486074d3ba247769fda17d5181b345c9fb7d12e0da98b22d1d71a5db9698d8b4bd900a3ec1a4ffdd60846fc2556274a5c894d0c48795f14cb03aeae7b55260b - languageName: node - linkType: hard - -"json-schema-traverse@npm:^1.0.0": - version: 1.0.0 - resolution: "json-schema-traverse@npm:1.0.0" - checksum: 02f2f466cdb0362558b2f1fd5e15cce82ef55d60cd7f8fa828cf35ba74330f8d767fcae5c5c2adb7851fa811766c694b9405810879bc4e1ddd78a7c0e03658ad - languageName: node - linkType: hard - -"json-schema-typed@npm:^7.0.3": - version: 7.0.3 - resolution: "json-schema-typed@npm:7.0.3" - checksum: e861b19e97e3cc2b29a429147890157827eeda16ab639a0765b935cf3e22aeb6abbba108e23aef442da806bb1f402bdff21da9c5cb30015f8007594565e110b5 - languageName: node - linkType: hard - -"json-stable-stringify-without-jsonify@npm:^1.0.1": - version: 1.0.1 - resolution: "json-stable-stringify-without-jsonify@npm:1.0.1" - checksum: cff44156ddce9c67c44386ad5cddf91925fe06b1d217f2da9c4910d01f358c6e3989c4d5a02683c7a5667f9727ff05831f7aa8ae66c8ff691c556f0884d49215 - languageName: node - linkType: hard - -"json-stringify-safe@npm:^5.0.1": - version: 5.0.1 - resolution: "json-stringify-safe@npm:5.0.1" - checksum: 48ec0adad5280b8a96bb93f4563aa1667fd7a36334f79149abd42446d0989f2ddc58274b479f4819f1f00617957e6344c886c55d05a4e15ebb4ab931e4a6a8ee - languageName: node - linkType: hard - -"json5@npm:^1.0.2": - version: 1.0.2 - resolution: "json5@npm:1.0.2" - dependencies: - minimist: ^1.2.0 - bin: - json5: lib/cli.js - checksum: 866458a8c58a95a49bef3adba929c625e82532bcff1fe93f01d29cb02cac7c3fe1f4b79951b7792c2da9de0b32871a8401a6e3c5b36778ad852bf5b8a61165d7 - languageName: node - linkType: hard - -"json5@npm:^2.2.0, json5@npm:^2.2.1": - version: 2.2.3 - resolution: "json5@npm:2.2.3" - bin: - json5: lib/cli.js - checksum: 2a7436a93393830bce797d4626275152e37e877b265e94ca69c99e3d20c2b9dab021279146a39cdb700e71b2dd32a4cebd1514cd57cee102b1af906ce5040349 - languageName: node - linkType: hard - -"jsonfile@npm:^4.0.0": - version: 4.0.0 - resolution: "jsonfile@npm:4.0.0" - dependencies: - graceful-fs: ^4.1.6 - dependenciesMeta: - graceful-fs: - optional: true - checksum: 6447d6224f0d31623eef9b51185af03ac328a7553efcee30fa423d98a9e276ca08db87d71e17f2310b0263fd3ffa6c2a90a6308367f661dc21580f9469897c9e - languageName: node - linkType: hard - -"jsonfile@npm:^6.0.1": - version: 6.1.0 - resolution: "jsonfile@npm:6.1.0" - dependencies: - graceful-fs: ^4.1.6 - universalify: ^2.0.0 - dependenciesMeta: - graceful-fs: - optional: true - checksum: 7af3b8e1ac8fe7f1eccc6263c6ca14e1966fcbc74b618d3c78a0a2075579487547b94f72b7a1114e844a1e15bb00d440e5d1720bfc4612d790a6f285d5ea8354 - languageName: node - linkType: hard - -"jszip@npm:^3.1.0": - version: 3.10.1 - resolution: "jszip@npm:3.10.1" - dependencies: - lie: ~3.3.0 - pako: ~1.0.2 - readable-stream: ~2.3.6 - setimmediate: ^1.0.5 - checksum: abc77bfbe33e691d4d1ac9c74c8851b5761fba6a6986630864f98d876f3fcc2d36817dfc183779f32c00157b5d53a016796677298272a714ae096dfe6b1c8b60 - languageName: node - linkType: hard - -"keyboardevent-from-electron-accelerator@npm:^2.0.0": - version: 2.0.0 - resolution: "keyboardevent-from-electron-accelerator@npm:2.0.0" - checksum: 25fb2de48cda8857fad49fc8ba7191055089adb4899ec76021af2d97eae1ff0f0ba398f8e490121a270e1848eac96089aa3bace0f79f691583112bb9c45d13d3 - languageName: node - linkType: hard - -"keyboardevents-areequal@npm:^0.2.1, keyboardevents-areequal@npm:^0.2.2": - version: 0.2.2 - resolution: "keyboardevents-areequal@npm:0.2.2" - checksum: 05d846f75170238bbb9ed45d13ca9c6cd3e68ea8ba6b7727971790fa55b44c3386ec8b9c321ae72dae0d0944678d0dc2b922148fe67d3f9720bf30a23999dd65 - languageName: node - linkType: hard - -"keyv@npm:^4.0.0": - version: 4.5.2 - resolution: "keyv@npm:4.5.2" - dependencies: - json-buffer: 3.0.1 - checksum: 13ad58303acd2261c0d4831b4658451603fd159e61daea2121fcb15feb623e75ee328cded0572da9ca76b7b3ceaf8e614f1806c6b3af5db73c9c35a345259651 - languageName: node - linkType: hard - -"kind-of@npm:^6.0.3": - version: 6.0.3 - resolution: "kind-of@npm:6.0.3" - checksum: 3ab01e7b1d440b22fe4c31f23d8d38b4d9b91d9f291df683476576493d5dfd2e03848a8b05813dd0c3f0e835bc63f433007ddeceb71f05cb25c45ae1b19c6d3b - languageName: node - linkType: hard - -"lazy-val@npm:^1.0.4, lazy-val@npm:^1.0.5": - version: 1.0.5 - resolution: "lazy-val@npm:1.0.5" - checksum: 31e12e0b118826dfae74f8f3ff8ebcddfe4200ff88d0d448db175c7265ee537e0ba55488d411728246337f3ed3c9ec68416f10889f632a2ce28fb7a970909fb5 - languageName: node - linkType: hard - -"leac@npm:^0.6.0": - version: 0.6.0 - resolution: "leac@npm:0.6.0" - checksum: a7a722cfc2ddfd6fb2620e5dee3ac8e9b0af4eb04325f3c8286a820de78becba3010a4d7026ff5189bb159eb7a851c3a1ac73e076eb0d54fcee0adaf695291ba - languageName: node - linkType: hard - -"levn@npm:^0.4.1": - version: 0.4.1 - resolution: "levn@npm:0.4.1" - dependencies: - prelude-ls: ^1.2.1 - type-check: ~0.4.0 - checksum: 12c5021c859bd0f5248561bf139121f0358285ec545ebf48bb3d346820d5c61a4309535c7f387ed7d84361cf821e124ce346c6b7cef8ee09a67c1473b46d0fc4 - languageName: node - linkType: hard - -"lie@npm:~3.3.0": - version: 3.3.0 - resolution: "lie@npm:3.3.0" - dependencies: - immediate: ~3.0.5 - checksum: 33102302cf19766f97919a6a98d481e01393288b17a6aa1f030a3542031df42736edde8dab29ffdbf90bebeffc48c761eb1d064dc77592ca3ba3556f9fe6d2a8 - languageName: node - linkType: hard - -"line-column-path@npm:^3.0.0": - version: 3.0.0 - resolution: "line-column-path@npm:3.0.0" - dependencies: - type-fest: ^2.0.0 - checksum: 124564d302e45a5c2ce7d05588ead253aca254a064db8875fa9c31e7e00d9ae5b5d7caf7f1c45ff3615739cc0960ec0490d1ac0903a978a904f2aa114641f152 - languageName: node - linkType: hard - -"lines-and-columns@npm:^1.1.6": - version: 1.2.4 - resolution: "lines-and-columns@npm:1.2.4" - checksum: 0c37f9f7fa212b38912b7145e1cd16a5f3cd34d782441c3e6ca653485d326f58b3caccda66efce1c5812bde4961bbde3374fae4b0d11bf1226152337f3894aa5 - languageName: node - linkType: hard - -"linkedom@npm:^0.14.12": - version: 0.14.25 - resolution: "linkedom@npm:0.14.25" - dependencies: - css-select: ^5.1.0 - cssom: ^0.5.0 - html-escaper: ^3.0.3 - htmlparser2: ^8.0.1 - uhyphen: ^0.2.0 - checksum: ab0caf795257f1bdaa8306af0a2c2664176e98e6c74171e8dd7c0718626357316dac53c9bbed37b929eb8cfda9b364f0aa1f75f92afce138a420bced003afdfa - languageName: node - linkType: hard - -"locate-path@npm:^3.0.0": - version: 3.0.0 - resolution: "locate-path@npm:3.0.0" - dependencies: - p-locate: ^3.0.0 - path-exists: ^3.0.0 - checksum: 53db3996672f21f8b0bf2a2c645ae2c13ffdae1eeecfcd399a583bce8516c0b88dcb4222ca6efbbbeb6949df7e46860895be2c02e8d3219abd373ace3bfb4e11 - languageName: node - linkType: hard - -"locate-path@npm:^5.0.0": - version: 5.0.0 - resolution: "locate-path@npm:5.0.0" - dependencies: - p-locate: ^4.1.0 - checksum: 83e51725e67517287d73e1ded92b28602e3ae5580b301fe54bfb76c0c723e3f285b19252e375712316774cf52006cb236aed5704692c32db0d5d089b69696e30 - languageName: node - linkType: hard - -"locate-path@npm:^6.0.0": - version: 6.0.0 - resolution: "locate-path@npm:6.0.0" - dependencies: - p-locate: ^5.0.0 - checksum: 72eb661788a0368c099a184c59d2fee760b3831c9c1c33955e8a19ae4a21b4116e53fa736dc086cdeb9fce9f7cc508f2f92d2d3aae516f133e16a2bb59a39f5a - languageName: node - linkType: hard - -"locate-path@npm:^7.1.0": - version: 7.2.0 - resolution: "locate-path@npm:7.2.0" - dependencies: - p-locate: ^6.0.0 - checksum: c1b653bdf29beaecb3d307dfb7c44d98a2a98a02ebe353c9ad055d1ac45d6ed4e1142563d222df9b9efebc2bcb7d4c792b507fad9e7150a04c29530b7db570f8 - languageName: node - linkType: hard - -"lodash-es@npm:^4.17.21": - version: 4.17.21 - resolution: "lodash-es@npm:4.17.21" - checksum: 05cbffad6e2adbb331a4e16fbd826e7faee403a1a04873b82b42c0f22090f280839f85b95393f487c1303c8a3d2a010048bf06151a6cbe03eee4d388fb0a12d2 - languageName: node - linkType: hard - -"lodash.debounce@npm:^4.0.8": - version: 4.0.8 - resolution: "lodash.debounce@npm:4.0.8" - checksum: a3f527d22c548f43ae31c861ada88b2637eb48ac6aa3eb56e82d44917971b8aa96fbb37aa60efea674dc4ee8c42074f90f7b1f772e9db375435f6c83a19b3bc6 - languageName: node - linkType: hard - -"lodash.escaperegexp@npm:^4.1.2": - version: 4.1.2 - resolution: "lodash.escaperegexp@npm:4.1.2" - checksum: 6d99452b1cfd6073175a9b741a9b09ece159eac463f86f02ea3bee2e2092923fce812c8d2bf446309cc52d1d61bf9af51c8118b0d7421388e6cead7bd3798f0f - languageName: node - linkType: hard - -"lodash.isequal@npm:^4.5.0": - version: 4.5.0 - resolution: "lodash.isequal@npm:4.5.0" - checksum: da27515dc5230eb1140ba65ff8de3613649620e8656b19a6270afe4866b7bd461d9ba2ac8a48dcc57f7adac4ee80e1de9f965d89d4d81a0ad52bb3eec2609644 - languageName: node - linkType: hard - -"lodash.merge@npm:^4.6.2": - version: 4.6.2 - resolution: "lodash.merge@npm:4.6.2" - checksum: ad580b4bdbb7ca1f7abf7e1bce63a9a0b98e370cf40194b03380a46b4ed799c9573029599caebc1b14e3f24b111aef72b96674a56cfa105e0f5ac70546cdc005 - languageName: node - linkType: hard - -"lodash@npm:^4.13.1, lodash@npm:^4.17.15, lodash@npm:^4.17.21, lodash@npm:^4.17.4, lodash@npm:^4.3.0": - version: 4.17.21 - resolution: "lodash@npm:4.17.21" - checksum: eb835a2e51d381e561e508ce932ea50a8e5a68f4ebdd771ea240d3048244a8d13658acbd502cd4829768c56f2e16bdd4340b9ea141297d472517b83868e677f7 - languageName: node - linkType: hard - -"log-symbols@npm:^4.0.0": - version: 4.1.0 - resolution: "log-symbols@npm:4.1.0" - dependencies: - chalk: ^4.1.0 - is-unicode-supported: ^0.1.0 - checksum: fce1497b3135a0198803f9f07464165e9eb83ed02ceb2273930a6f8a508951178d8cf4f0378e9d28300a2ed2bc49050995d2bd5f53ab716bb15ac84d58c6ef74 - languageName: node - linkType: hard - -"long@npm:^4.0.0": - version: 4.0.0 - resolution: "long@npm:4.0.0" - checksum: 16afbe8f749c7c849db1f4de4e2e6a31ac6e617cead3bdc4f9605cb703cd20e1e9fc1a7baba674ffcca57d660a6e5b53a9e236d7b25a295d3855cca79cc06744 - languageName: node - linkType: hard - -"lowercase-keys@npm:^1.0.0": - version: 1.0.1 - resolution: "lowercase-keys@npm:1.0.1" - checksum: 4d045026595936e09953e3867722e309415ff2c80d7701d067546d75ef698dac218a4f53c6d1d0e7368b47e45fd7529df47e6cb56fbb90523ba599f898b3d147 - languageName: node - linkType: hard - -"lowercase-keys@npm:^2.0.0": - version: 2.0.0 - resolution: "lowercase-keys@npm:2.0.0" - checksum: 24d7ebd56ccdf15ff529ca9e08863f3c54b0b9d1edb97a3ae1af34940ae666c01a1e6d200707bce730a8ef76cb57cc10e65f245ecaaf7e6bc8639f2fb460ac23 - languageName: node - linkType: hard - -"lru-cache@npm:^6.0.0": - version: 6.0.0 - resolution: "lru-cache@npm:6.0.0" - dependencies: - yallist: ^4.0.0 - checksum: f97f499f898f23e4585742138a22f22526254fdba6d75d41a1c2526b3b6cc5747ef59c5612ba7375f42aca4f8461950e925ba08c991ead0651b4918b7c978297 - languageName: node - linkType: hard - -"lru-cache@npm:^7.5.1, lru-cache@npm:^7.7.1": - version: 7.18.3 - resolution: "lru-cache@npm:7.18.3" - checksum: e550d772384709deea3f141af34b6d4fa392e2e418c1498c078de0ee63670f1f46f5eee746e8ef7e69e1c895af0d4224e62ee33e66a543a14763b0f2e74c1356 - languageName: node - linkType: hard - -"make-fetch-happen@npm:^10.0.3": - version: 10.2.1 - resolution: "make-fetch-happen@npm:10.2.1" - dependencies: - agentkeepalive: ^4.2.1 - cacache: ^16.1.0 - http-cache-semantics: ^4.1.0 - http-proxy-agent: ^5.0.0 - https-proxy-agent: ^5.0.0 - is-lambda: ^1.0.1 - lru-cache: ^7.7.1 - minipass: ^3.1.6 - minipass-collect: ^1.0.2 - minipass-fetch: ^2.0.3 - minipass-flush: ^1.0.5 - minipass-pipeline: ^1.2.4 - negotiator: ^0.6.3 - promise-retry: ^2.0.1 - socks-proxy-agent: ^7.0.0 - ssri: ^9.0.0 - checksum: 2332eb9a8ec96f1ffeeea56ccefabcb4193693597b132cd110734d50f2928842e22b84cfa1508e921b8385cdfd06dda9ad68645fed62b50fff629a580f5fb72c - languageName: node - linkType: hard - -"map-obj@npm:^1.0.0": - version: 1.0.1 - resolution: "map-obj@npm:1.0.1" - checksum: 9949e7baec2a336e63b8d4dc71018c117c3ce6e39d2451ccbfd3b8350c547c4f6af331a4cbe1c83193d7c6b786082b6256bde843db90cb7da2a21e8fcc28afed - languageName: node - linkType: hard - -"map-obj@npm:^4.1.0, map-obj@npm:^4.3.0": - version: 4.3.0 - resolution: "map-obj@npm:4.3.0" - checksum: fbc554934d1a27a1910e842bc87b177b1a556609dd803747c85ece420692380827c6ae94a95cce4407c054fa0964be3bf8226f7f2cb2e9eeee432c7c1985684e - languageName: node - linkType: hard - -"map-stream@npm:~0.1.0": - version: 0.1.0 - resolution: "map-stream@npm:0.1.0" - checksum: 38abbe4eb883888031e6b2fc0630bc583c99396be16b8ace5794b937b682a8a081f03e8b15bfd4914d1bc88318f0e9ac73ba3512ae65955cd449f63256ddb31d - languageName: node - linkType: hard - -"matcher@npm:^3.0.0": - version: 3.0.0 - resolution: "matcher@npm:3.0.0" - dependencies: - escape-string-regexp: ^4.0.0 - checksum: 8bee1a7ab7609c2c21d9c9254b6785fa708eadf289032b556d57a34e98fcd4c537659a004dafee6ce80ab157099e645c199dc52678dff1e7fb0a6684e0da4dbe - languageName: node - linkType: hard - -"md5@npm:^2.3.0": - version: 2.3.0 - resolution: "md5@npm:2.3.0" - dependencies: - charenc: 0.0.2 - crypt: 0.0.2 - is-buffer: ~1.1.6 - checksum: a63cacf4018dc9dee08c36e6f924a64ced735b37826116c905717c41cebeb41a522f7a526ba6ad578f9c80f02cb365033ccd67fe186ffbcc1a1faeb75daa9b6e - languageName: node - linkType: hard - -"memory-fs@npm:^0.2.0": - version: 0.2.0 - resolution: "memory-fs@npm:0.2.0" - checksum: 7a8268eab60ff7214ab25d9248ac0b9c51124193e4999f18a4190e64a997d9a5302704c0e5ba9e2e365acb8ab59c9f49139c9eff9bf6e9c5eca783442437b1d6 - languageName: node - linkType: hard - -"meow@npm:^10.1.3": - version: 10.1.5 - resolution: "meow@npm:10.1.5" - dependencies: - "@types/minimist": ^1.2.2 - camelcase-keys: ^7.0.0 - decamelize: ^5.0.0 - decamelize-keys: ^1.1.0 - hard-rejection: ^2.1.0 - minimist-options: 4.1.0 - normalize-package-data: ^3.0.2 - read-pkg-up: ^8.0.0 - redent: ^4.0.0 - trim-newlines: ^4.0.2 - type-fest: ^1.2.2 - yargs-parser: ^20.2.9 - checksum: dd5f0caa4af18517813547dc66741dcbf52c4c23def5062578d39b11189fd9457aee5c1f2263a5cd6592a465023df8357e8ac876b685b64dbcf545e3f66c23a7 - languageName: node - linkType: hard - -"meow@npm:^11.0.0": - version: 11.0.0 - resolution: "meow@npm:11.0.0" - dependencies: - "@types/minimist": ^1.2.2 - camelcase-keys: ^8.0.2 - decamelize: ^6.0.0 - decamelize-keys: ^1.1.0 - hard-rejection: ^2.1.0 - minimist-options: 4.1.0 - normalize-package-data: ^4.0.1 - read-pkg-up: ^9.1.0 - redent: ^4.0.0 - trim-newlines: ^4.0.2 - type-fest: ^3.1.0 - yargs-parser: ^21.1.1 - checksum: 2e815b8d2acc6cda0ea10e0a6dcd6fbdcc2fb8b24412c3c70acd77220642ca0dc727c6fccd79d64b7ca811d099e8a9ad62ea261a8f39d4b61fcdcaf551c5c788 - languageName: node - linkType: hard - -"merge-stream@npm:^2.0.0": - version: 2.0.0 - resolution: "merge-stream@npm:2.0.0" - checksum: 6fa4dcc8d86629705cea944a4b88ef4cb0e07656ebf223fa287443256414283dd25d91c1cd84c77987f2aec5927af1a9db6085757cb43d90eb170ebf4b47f4f4 - languageName: node - linkType: hard - -"merge2@npm:^1.3.0, merge2@npm:^1.4.1": - version: 1.4.1 - resolution: "merge2@npm:1.4.1" - checksum: 7268db63ed5169466540b6fb947aec313200bcf6d40c5ab722c22e242f651994619bcd85601602972d3c85bd2cc45a358a4c61937e9f11a061919a1da569b0c2 - languageName: node - linkType: hard - -"micro-spelling-correcter@npm:^1.1.1": - version: 1.1.1 - resolution: "micro-spelling-correcter@npm:1.1.1" - checksum: dd5cae78f437a2b17b701e1f195ab68f69ec1a6ed751345ca6654e8b76cb48d47060f2c1fdcfa87db8da0105c1199dc5b5f71e7499904207c0e9a5fe261f44d4 - languageName: node - linkType: hard - -"micromatch@npm:^4.0.4, micromatch@npm:^4.0.5": - version: 4.0.5 - resolution: "micromatch@npm:4.0.5" - dependencies: - braces: ^3.0.2 - picomatch: ^2.3.1 - checksum: 02a17b671c06e8fefeeb6ef996119c1e597c942e632a21ef589154f23898c9c6a9858526246abb14f8bca6e77734aa9dcf65476fca47cedfb80d9577d52843fc - languageName: node - linkType: hard - -"mime-db@npm:1.52.0": - version: 1.52.0 - resolution: "mime-db@npm:1.52.0" - checksum: 0d99a03585f8b39d68182803b12ac601d9c01abfa28ec56204fa330bc9f3d1c5e14beb049bafadb3dbdf646dfb94b87e24d4ec7b31b7279ef906a8ea9b6a513f - languageName: node - linkType: hard - -"mime-types@npm:^2.1.12": - version: 2.1.35 - resolution: "mime-types@npm:2.1.35" - dependencies: - mime-db: 1.52.0 - checksum: 89a5b7f1def9f3af5dad6496c5ed50191ae4331cc5389d7c521c8ad28d5fdad2d06fd81baf38fed813dc4e46bb55c8145bb0ff406330818c9cf712fb2e9b3836 - languageName: node - linkType: hard - -"mime@npm:^2.5.2": - version: 2.6.0 - resolution: "mime@npm:2.6.0" - bin: - mime: cli.js - checksum: 1497ba7b9f6960694268a557eae24b743fd2923da46ec392b042469f4b901721ba0adcf8b0d3c2677839d0e243b209d76e5edcbd09cfdeffa2dfb6bb4df4b862 - languageName: node - linkType: hard - -"mimic-fn@npm:^2.1.0": - version: 2.1.0 - resolution: "mimic-fn@npm:2.1.0" - checksum: d2421a3444848ce7f84bd49115ddacff29c15745db73f54041edc906c14b131a38d05298dae3081667627a59b2eb1ca4b436ff2e1b80f69679522410418b478a - languageName: node - linkType: hard - -"mimic-fn@npm:^3.0.0": - version: 3.1.0 - resolution: "mimic-fn@npm:3.1.0" - checksum: f7b167f9115b8bbdf2c3ee55dce9149d14be9e54b237259c4bc1d8d0512ea60f25a1b323f814eb1fe8f5a541662804bcfcfff3202ca58df143edb986849d58db - languageName: node - linkType: hard - -"mimic-response@npm:^1.0.0": - version: 1.0.1 - resolution: "mimic-response@npm:1.0.1" - checksum: 034c78753b0e622bc03c983663b1cdf66d03861050e0c8606563d149bc2b02d63f62ce4d32be4ab50d0553ae0ffe647fc34d1f5281184c6e1e8cf4d85e8d9823 - languageName: node - linkType: hard - -"mimic-response@npm:^3.1.0": - version: 3.1.0 - resolution: "mimic-response@npm:3.1.0" - checksum: 25739fee32c17f433626bf19f016df9036b75b3d84a3046c7d156e72ec963dd29d7fc8a302f55a3d6c5a4ff24259676b15d915aad6480815a969ff2ec0836867 - languageName: node - linkType: hard - -"min-indent@npm:^1.0.0, min-indent@npm:^1.0.1": - version: 1.0.1 - resolution: "min-indent@npm:1.0.1" - checksum: bfc6dd03c5eaf623a4963ebd94d087f6f4bbbfd8c41329a7f09706b0cb66969c4ddd336abeb587bc44bc6f08e13bf90f0b374f9d71f9f01e04adc2cd6f083ef1 - languageName: node - linkType: hard - -"miniget@npm:^4.2.2": - version: 4.2.2 - resolution: "miniget@npm:4.2.2" - checksum: 577a7826cbf521b8ecb31906b3dce55c61b35398318a461f3484681572287208b7ec5a40de7b0bf0b7738f21630d015cc39ba3edcfb69146565f1528ff957612 - languageName: node - linkType: hard - -"minimatch@npm:^3.0.4, minimatch@npm:^3.0.5, minimatch@npm:^3.1.1, minimatch@npm:^3.1.2": - version: 3.1.2 - resolution: "minimatch@npm:3.1.2" - dependencies: - brace-expansion: ^1.1.7 - checksum: c154e566406683e7bcb746e000b84d74465b3a832c45d59912b9b55cd50dee66e5c4b1e5566dba26154040e51672f9aa450a9aef0c97cfc7336b78b7afb9540a - languageName: node - linkType: hard - -"minimatch@npm:^5.0.1": - version: 5.1.6 - resolution: "minimatch@npm:5.1.6" - dependencies: - brace-expansion: ^2.0.1 - checksum: 7564208ef81d7065a370f788d337cd80a689e981042cb9a1d0e6580b6c6a8c9279eba80010516e258835a988363f99f54a6f711a315089b8b42694f5da9d0d77 - languageName: node - linkType: hard - -"minimist-options@npm:4.1.0": - version: 4.1.0 - resolution: "minimist-options@npm:4.1.0" - dependencies: - arrify: ^1.0.1 - is-plain-obj: ^1.1.0 - kind-of: ^6.0.3 - checksum: 8c040b3068811e79de1140ca2b708d3e203c8003eb9a414c1ab3cd467fc5f17c9ca02a5aef23bedc51a7f8bfbe77f87e9a7e31ec81fba304cda675b019496f4e - languageName: node - linkType: hard - -"minimist@npm:^1.2.0, minimist@npm:^1.2.5, minimist@npm:^1.2.6": - version: 1.2.8 - resolution: "minimist@npm:1.2.8" - checksum: 75a6d645fb122dad29c06a7597bddea977258957ed88d7a6df59b5cd3fe4a527e253e9bbf2e783e4b73657f9098b96a5fe96ab8a113655d4109108577ecf85b0 - languageName: node - linkType: hard - -"minipass-collect@npm:^1.0.2": - version: 1.0.2 - resolution: "minipass-collect@npm:1.0.2" - dependencies: - minipass: ^3.0.0 - checksum: 14df761028f3e47293aee72888f2657695ec66bd7d09cae7ad558da30415fdc4752bbfee66287dcc6fd5e6a2fa3466d6c484dc1cbd986525d9393b9523d97f10 - languageName: node - linkType: hard - -"minipass-fetch@npm:^2.0.3": - version: 2.1.2 - resolution: "minipass-fetch@npm:2.1.2" - dependencies: - encoding: ^0.1.13 - minipass: ^3.1.6 - minipass-sized: ^1.0.3 - minizlib: ^2.1.2 - dependenciesMeta: - encoding: - optional: true - checksum: 3f216be79164e915fc91210cea1850e488793c740534985da017a4cbc7a5ff50506956d0f73bb0cb60e4fe91be08b6b61ef35101706d3ef5da2c8709b5f08f91 - languageName: node - linkType: hard - -"minipass-flush@npm:^1.0.5": - version: 1.0.5 - resolution: "minipass-flush@npm:1.0.5" - dependencies: - minipass: ^3.0.0 - checksum: 56269a0b22bad756a08a94b1ffc36b7c9c5de0735a4dd1ab2b06c066d795cfd1f0ac44a0fcae13eece5589b908ecddc867f04c745c7009be0b566421ea0944cf - languageName: node - linkType: hard - -"minipass-pipeline@npm:^1.2.4": - version: 1.2.4 - resolution: "minipass-pipeline@npm:1.2.4" - dependencies: - minipass: ^3.0.0 - checksum: b14240dac0d29823c3d5911c286069e36d0b81173d7bdf07a7e4a91ecdef92cdff4baaf31ea3746f1c61e0957f652e641223970870e2353593f382112257971b - languageName: node - linkType: hard - -"minipass-sized@npm:^1.0.3": - version: 1.0.3 - resolution: "minipass-sized@npm:1.0.3" - dependencies: - minipass: ^3.0.0 - checksum: 79076749fcacf21b5d16dd596d32c3b6bf4d6e62abb43868fac21674078505c8b15eaca4e47ed844985a4514854f917d78f588fcd029693709417d8f98b2bd60 - languageName: node - linkType: hard - -"minipass@npm:^3.0.0, minipass@npm:^3.1.1, minipass@npm:^3.1.6": - version: 3.3.6 - resolution: "minipass@npm:3.3.6" - dependencies: - yallist: ^4.0.0 - checksum: a30d083c8054cee83cdcdc97f97e4641a3f58ae743970457b1489ce38ee1167b3aaf7d815cd39ec7a99b9c40397fd4f686e83750e73e652b21cb516f6d845e48 - languageName: node - linkType: hard - -"minipass@npm:^4.0.0": - version: 4.2.8 - resolution: "minipass@npm:4.2.8" - checksum: 7f4914d5295a9a30807cae5227a37a926e6d910c03f315930fde52332cf0575dfbc20295318f91f0baf0e6bb11a6f668e30cde8027dea7a11b9d159867a3c830 - languageName: node - linkType: hard - -"minizlib@npm:^2.1.1, minizlib@npm:^2.1.2": - version: 2.1.2 - resolution: "minizlib@npm:2.1.2" - dependencies: - minipass: ^3.0.0 - yallist: ^4.0.0 - checksum: f1fdeac0b07cf8f30fcf12f4b586795b97be856edea22b5e9072707be51fc95d41487faec3f265b42973a304fe3a64acd91a44a3826a963e37b37bafde0212c3 - languageName: node - linkType: hard - -"mkdirp@npm:^0.5.1": - version: 0.5.6 - resolution: "mkdirp@npm:0.5.6" - dependencies: - minimist: ^1.2.6 - bin: - mkdirp: bin/cmd.js - checksum: 0c91b721bb12c3f9af4b77ebf73604baf350e64d80df91754dc509491ae93bf238581e59c7188360cec7cb62fc4100959245a42cfe01834efedc5e9d068376c2 - languageName: node - linkType: hard - -"mkdirp@npm:^1.0.3, mkdirp@npm:^1.0.4": - version: 1.0.4 - resolution: "mkdirp@npm:1.0.4" - bin: - mkdirp: bin/cmd.js - checksum: a96865108c6c3b1b8e1d5e9f11843de1e077e57737602de1b82030815f311be11f96f09cce59bd5b903d0b29834733e5313f9301e3ed6d6f6fba2eae0df4298f - languageName: node - linkType: hard - -"mpris-service@npm:^2.1.2": - version: 2.1.2 - resolution: "mpris-service@npm:2.1.2" - dependencies: - dbus-next: ^0.9.2 - deep-equal: ^1.0.1 - source-map-support: ^0.5.11 - checksum: 53857988ee65a2a7eb6d216c0799ad61b1ff4b836bea52f21008e46025c03a8e980b15f6fbbf29e3880243c697713559809a5424ae2f9803e06cbf705f68a9d2 - languageName: node - linkType: hard - -"ms@npm:2.0.0": - version: 2.0.0 - resolution: "ms@npm:2.0.0" - checksum: 0e6a22b8b746d2e0b65a430519934fefd41b6db0682e3477c10f60c76e947c4c0ad06f63ffdf1d78d335f83edee8c0aa928aa66a36c7cd95b69b26f468d527f4 - languageName: node - linkType: hard - -"ms@npm:2.1.2": - version: 2.1.2 - resolution: "ms@npm:2.1.2" - checksum: 673cdb2c3133eb050c745908d8ce632ed2c02d85640e2edb3ace856a2266a813b30c613569bf3354fdf4ea7d1a1494add3bfa95e2713baa27d0c2c71fc44f58f - languageName: node - linkType: hard - -"ms@npm:^2.0.0, ms@npm:^2.1.1": - version: 2.1.3 - resolution: "ms@npm:2.1.3" - checksum: aa92de608021b242401676e35cfa5aa42dd70cbdc082b916da7fb925c542173e36bce97ea3e804923fe92c0ad991434e4a38327e15a1b5b5f945d66df615ae6d - languageName: node - linkType: hard - -"nan@npm:^2.12.1": - version: 2.17.0 - resolution: "nan@npm:2.17.0" - dependencies: - node-gyp: latest - checksum: ec609aeaf7e68b76592a3ba96b372aa7f5df5b056c1e37410b0f1deefbab5a57a922061e2c5b369bae9c7c6b5e6eecf4ad2dac8833a1a7d3a751e0a7c7f849ed - languageName: node - linkType: hard - -"natural-compare-lite@npm:^1.4.0": - version: 1.4.0 - resolution: "natural-compare-lite@npm:1.4.0" - checksum: 5222ac3986a2b78dd6069ac62cbb52a7bf8ffc90d972ab76dfe7b01892485d229530ed20d0c62e79a6b363a663b273db3bde195a1358ce9e5f779d4453887225 - languageName: node - linkType: hard - -"natural-compare@npm:^1.4.0": - version: 1.4.0 - resolution: "natural-compare@npm:1.4.0" - checksum: 23ad088b08f898fc9b53011d7bb78ec48e79de7627e01ab5518e806033861bef68d5b0cd0e2205c2f36690ac9571ff6bcb05eb777ced2eeda8d4ac5b44592c3d - languageName: node - linkType: hard - -"negotiator@npm:^0.6.3": - version: 0.6.3 - resolution: "negotiator@npm:0.6.3" - checksum: b8ffeb1e262eff7968fc90a2b6767b04cfd9842582a9d0ece0af7049537266e7b2506dfb1d107a32f06dd849ab2aea834d5830f7f4d0e5cb7d36e1ae55d021d9 - languageName: node - linkType: hard - -"neo-async@npm:^2.6.0": - version: 2.6.2 - resolution: "neo-async@npm:2.6.2" - checksum: deac9f8d00eda7b2e5cd1b2549e26e10a0faa70adaa6fdadca701cc55f49ee9018e427f424bac0c790b7c7e2d3068db97f3093f1093975f2acb8f8818b936ed9 - languageName: node - linkType: hard - -"node-addon-api@npm:^1.6.3": - version: 1.7.2 - resolution: "node-addon-api@npm:1.7.2" - dependencies: - node-gyp: latest - checksum: 938922b3d7cb34ee137c5ec39df6289a3965e8cab9061c6848863324c21a778a81ae3bc955554c56b6b86962f6ccab2043dd5fa3f33deab633636bd28039333f - languageName: node - linkType: hard - -"node-fetch@npm:^2.6.1, node-fetch@npm:^2.6.9": - version: 2.6.9 - resolution: "node-fetch@npm:2.6.9" - dependencies: - whatwg-url: ^5.0.0 - peerDependencies: - encoding: ^0.1.0 - peerDependenciesMeta: - encoding: - optional: true - checksum: acb04f9ce7224965b2b59e71b33c639794d8991efd73855b0b250921382b38331ffc9d61bce502571f6cc6e11a8905ca9b1b6d4aeb586ab093e2756a1fd190d0 - languageName: node - linkType: hard - -"node-gyp@npm:^9.3.1, node-gyp@npm:latest": - version: 9.3.1 - resolution: "node-gyp@npm:9.3.1" - dependencies: - env-paths: ^2.2.0 - glob: ^7.1.4 - graceful-fs: ^4.2.6 - make-fetch-happen: ^10.0.3 - nopt: ^6.0.0 - npmlog: ^6.0.0 - rimraf: ^3.0.2 - semver: ^7.3.5 - tar: ^6.1.2 - which: ^2.0.2 - bin: - node-gyp: bin/node-gyp.js - checksum: b860e9976fa645ca0789c69e25387401b4396b93c8375489b5151a6c55cf2640a3b6183c212b38625ef7c508994930b72198338e3d09b9d7ade5acc4aaf51ea7 - languageName: node - linkType: hard - -"nopt@npm:^6.0.0": - version: 6.0.0 - resolution: "nopt@npm:6.0.0" - dependencies: - abbrev: ^1.0.0 - bin: - nopt: bin/nopt.js - checksum: 82149371f8be0c4b9ec2f863cc6509a7fd0fa729929c009f3a58e4eb0c9e4cae9920e8f1f8eb46e7d032fec8fb01bede7f0f41a67eb3553b7b8e14fa53de1dac - languageName: node - linkType: hard - -"normalize-package-data@npm:^2.5.0": - version: 2.5.0 - resolution: "normalize-package-data@npm:2.5.0" - dependencies: - hosted-git-info: ^2.1.4 - resolve: ^1.10.0 - semver: 2 || 3 || 4 || 5 - validate-npm-package-license: ^3.0.1 - checksum: 7999112efc35a6259bc22db460540cae06564aa65d0271e3bdfa86876d08b0e578b7b5b0028ee61b23f1cae9fc0e7847e4edc0948d3068a39a2a82853efc8499 - languageName: node - linkType: hard - -"normalize-package-data@npm:^3.0.2": - version: 3.0.3 - resolution: "normalize-package-data@npm:3.0.3" - dependencies: - hosted-git-info: ^4.0.1 - is-core-module: ^2.5.0 - semver: ^7.3.4 - validate-npm-package-license: ^3.0.1 - checksum: bbcee00339e7c26fdbc760f9b66d429258e2ceca41a5df41f5df06cc7652de8d82e8679ff188ca095cad8eff2b6118d7d866af2b68400f74602fbcbce39c160a - languageName: node - linkType: hard - -"normalize-package-data@npm:^4.0.1": - version: 4.0.1 - resolution: "normalize-package-data@npm:4.0.1" - dependencies: - hosted-git-info: ^5.0.0 - is-core-module: ^2.8.1 - semver: ^7.3.5 - validate-npm-package-license: ^3.0.4 - checksum: 292e0aa740e73d62f84bbd9d55d4bfc078155f32d5d7572c32c9807f96d543af0f43ff7e5c80bfa6238667123fd68bd83cd412eae9b27b85b271fb041f624528 - languageName: node - linkType: hard - -"normalize-url@npm:^6.0.1": - version: 6.1.0 - resolution: "normalize-url@npm:6.1.0" - checksum: 4a4944631173e7d521d6b80e4c85ccaeceb2870f315584fa30121f505a6dfd86439c5e3fdd8cd9e0e291290c41d0c3599f0cb12ab356722ed242584c30348e50 - languageName: node - linkType: hard - -"npm-run-path@npm:^4.0.1": - version: 4.0.1 - resolution: "npm-run-path@npm:4.0.1" - dependencies: - path-key: ^3.0.0 - checksum: 5374c0cea4b0bbfdfae62da7bbdf1e1558d338335f4cacf2515c282ff358ff27b2ecb91ffa5330a8b14390ac66a1e146e10700440c1ab868208430f56b5f4d23 - languageName: node - linkType: hard - -"npmlog@npm:^6.0.0": - version: 6.0.2 - resolution: "npmlog@npm:6.0.2" - dependencies: - are-we-there-yet: ^3.0.0 - console-control-strings: ^1.1.0 - gauge: ^4.0.3 - set-blocking: ^2.0.0 - checksum: ae238cd264a1c3f22091cdd9e2b106f684297d3c184f1146984ecbe18aaa86343953f26b9520dedd1b1372bc0316905b736c1932d778dbeb1fcf5a1001390e2a - languageName: node - linkType: hard - -"nth-check@npm:^2.0.1": - version: 2.1.1 - resolution: "nth-check@npm:2.1.1" - dependencies: - boolbase: ^1.0.0 - checksum: 5afc3dafcd1573b08877ca8e6148c52abd565f1d06b1eb08caf982e3fa289a82f2cae697ffb55b5021e146d60443f1590a5d6b944844e944714a5b549675bcd3 - languageName: node - linkType: hard - -"obj-props@npm:^1.0.0": - version: 1.4.0 - resolution: "obj-props@npm:1.4.0" - checksum: 6cdeb383dcca731063a9129e6fc6178d1238bededa31b565067b7ecf9963e2580567f50f620d007cc446e57cdade567edff68ecb49c0289382990ed9a42c5544 - languageName: node - linkType: hard - -"object-inspect@npm:^1.12.3, object-inspect@npm:^1.9.0": - version: 1.12.3 - resolution: "object-inspect@npm:1.12.3" - checksum: dabfd824d97a5f407e6d5d24810d888859f6be394d8b733a77442b277e0808860555176719c5905e765e3743a7cada6b8b0a3b85e5331c530fd418cc8ae991db - languageName: node - linkType: hard - -"object-is@npm:^1.0.1": - version: 1.1.5 - resolution: "object-is@npm:1.1.5" - dependencies: - call-bind: ^1.0.2 - define-properties: ^1.1.3 - checksum: 989b18c4cba258a6b74dc1d74a41805c1a1425bce29f6cabb50dcb1a6a651ea9104a1b07046739a49a5bb1bc49727bcb00efd5c55f932f6ea04ec8927a7901fe - languageName: node - linkType: hard - -"object-keys@npm:^1.1.1": - version: 1.1.1 - resolution: "object-keys@npm:1.1.1" - checksum: b363c5e7644b1e1b04aa507e88dcb8e3a2f52b6ffd0ea801e4c7a62d5aa559affe21c55a07fd4b1fd55fc03a33c610d73426664b20032405d7b92a1414c34d6a - languageName: node - linkType: hard - -"object.assign@npm:^4.1.4": - version: 4.1.4 - resolution: "object.assign@npm:4.1.4" - dependencies: - call-bind: ^1.0.2 - define-properties: ^1.1.4 - has-symbols: ^1.0.3 - object-keys: ^1.1.1 - checksum: 76cab513a5999acbfe0ff355f15a6a125e71805fcf53de4e9d4e082e1989bdb81d1e329291e1e4e0ae7719f0e4ef80e88fb2d367ae60500d79d25a6224ac8864 - languageName: node - linkType: hard - -"object.values@npm:^1.1.6": - version: 1.1.6 - resolution: "object.values@npm:1.1.6" - dependencies: - call-bind: ^1.0.2 - define-properties: ^1.1.4 - es-abstract: ^1.20.4 - checksum: f6fff9fd817c24cfd8107f50fb33061d81cd11bacc4e3dbb3852e9ff7692fde4dbce823d4333ea27cd9637ef1b6690df5fbb61f1ed314fa2959598dc3ae23d8e - languageName: node - linkType: hard - -"once@npm:^1.3.0, once@npm:^1.3.1, once@npm:^1.4.0": - version: 1.4.0 - resolution: "once@npm:1.4.0" - dependencies: - wrappy: 1 - checksum: cd0a88501333edd640d95f0d2700fbde6bff20b3d4d9bdc521bdd31af0656b5706570d6c6afe532045a20bb8dc0849f8332d6f2a416e0ba6d3d3b98806c7db68 - languageName: node - linkType: hard - -"onetime@npm:^5.1.2": - version: 5.1.2 - resolution: "onetime@npm:5.1.2" - dependencies: - mimic-fn: ^2.1.0 - checksum: 2478859ef817fc5d4e9c2f9e5728512ddd1dbc9fb7829ad263765bb6d3b91ce699d6e2332eef6b7dff183c2f490bd3349f1666427eaba4469fba0ac38dfd0d34 - languageName: node - linkType: hard - -"open-editor@npm:^4.0.0": - version: 4.0.0 - resolution: "open-editor@npm:4.0.0" - dependencies: - env-editor: ^1.0.0 - execa: ^5.1.1 - line-column-path: ^3.0.0 - open: ^8.4.0 - checksum: b3af8d0303cda1a0ae3d0a866094a35e4b0e0f646ab27389cd56cc9f4875f6ddc9e8249babbf7ffcfa1c162f8799dc5e5e7e8f6e528c02fbc17241d3ed88b706 - languageName: node - linkType: hard - -"open@npm:^8.4.0": - version: 8.4.2 - resolution: "open@npm:8.4.2" - dependencies: - define-lazy-prop: ^2.0.0 - is-docker: ^2.1.1 - is-wsl: ^2.2.0 - checksum: 6388bfff21b40cb9bd8f913f9130d107f2ed4724ea81a8fd29798ee322b361ca31fa2cdfb491a5c31e43a3996cfe9566741238c7a741ada8d7af1cb78d85cf26 - languageName: node - linkType: hard - -"optionator@npm:^0.9.1": - version: 0.9.1 - resolution: "optionator@npm:0.9.1" - dependencies: - deep-is: ^0.1.3 - fast-levenshtein: ^2.0.6 - levn: ^0.4.1 - prelude-ls: ^1.2.1 - type-check: ^0.4.0 - word-wrap: ^1.2.3 - checksum: dbc6fa065604b24ea57d734261914e697bd73b69eff7f18e967e8912aa2a40a19a9f599a507fa805be6c13c24c4eae8c71306c239d517d42d4c041c942f508a0 - languageName: node - linkType: hard - -"p-cancelable@npm:^2.0.0": - version: 2.1.1 - resolution: "p-cancelable@npm:2.1.1" - checksum: 3dba12b4fb4a1e3e34524535c7858fc82381bbbd0f247cc32dedc4018592a3950ce66b106d0880b4ec4c2d8d6576f98ca885dc1d7d0f274d1370be20e9523ddf - languageName: node - linkType: hard - -"p-limit@npm:^2.0.0, p-limit@npm:^2.2.0": - version: 2.3.0 - resolution: "p-limit@npm:2.3.0" - dependencies: - p-try: ^2.0.0 - checksum: 84ff17f1a38126c3314e91ecfe56aecbf36430940e2873dadaa773ffe072dc23b7af8e46d4b6485d302a11673fe94c6b67ca2cfbb60c989848b02100d0594ac1 - languageName: node - linkType: hard - -"p-limit@npm:^3.0.2": - version: 3.1.0 - resolution: "p-limit@npm:3.1.0" - dependencies: - yocto-queue: ^0.1.0 - checksum: 7c3690c4dbf62ef625671e20b7bdf1cbc9534e83352a2780f165b0d3ceba21907e77ad63401708145ca4e25bfc51636588d89a8c0aeb715e6c37d1c066430360 - languageName: node - linkType: hard - -"p-limit@npm:^4.0.0": - version: 4.0.0 - resolution: "p-limit@npm:4.0.0" - dependencies: - yocto-queue: ^1.0.0 - checksum: 01d9d70695187788f984226e16c903475ec6a947ee7b21948d6f597bed788e3112cc7ec2e171c1d37125057a5f45f3da21d8653e04a3a793589e12e9e80e756b - languageName: node - linkType: hard - -"p-locate@npm:^3.0.0": - version: 3.0.0 - resolution: "p-locate@npm:3.0.0" - dependencies: - p-limit: ^2.0.0 - checksum: 83991734a9854a05fe9dbb29f707ea8a0599391f52daac32b86f08e21415e857ffa60f0e120bfe7ce0cc4faf9274a50239c7895fc0d0579d08411e513b83a4ae - languageName: node - linkType: hard - -"p-locate@npm:^4.1.0": - version: 4.1.0 - resolution: "p-locate@npm:4.1.0" - dependencies: - p-limit: ^2.2.0 - checksum: 513bd14a455f5da4ebfcb819ef706c54adb09097703de6aeaa5d26fe5ea16df92b48d1ac45e01e3944ce1e6aa2a66f7f8894742b8c9d6e276e16cd2049a2b870 - languageName: node - linkType: hard - -"p-locate@npm:^5.0.0": - version: 5.0.0 - resolution: "p-locate@npm:5.0.0" - dependencies: - p-limit: ^3.0.2 - checksum: 1623088f36cf1cbca58e9b61c4e62bf0c60a07af5ae1ca99a720837356b5b6c5ba3eb1b2127e47a06865fee59dd0453cad7cc844cda9d5a62ac1a5a51b7c86d3 - languageName: node - linkType: hard - -"p-locate@npm:^6.0.0": - version: 6.0.0 - resolution: "p-locate@npm:6.0.0" - dependencies: - p-limit: ^4.0.0 - checksum: 2bfe5234efa5e7a4e74b30a5479a193fdd9236f8f6b4d2f3f69e3d286d9a7d7ab0c118a2a50142efcf4e41625def635bd9332d6cbf9cc65d85eb0718c579ab38 - languageName: node - linkType: hard - -"p-map@npm:^4.0.0": - version: 4.0.0 - resolution: "p-map@npm:4.0.0" - dependencies: - aggregate-error: ^3.0.0 - checksum: cb0ab21ec0f32ddffd31dfc250e3afa61e103ef43d957cc45497afe37513634589316de4eb88abdfd969fe6410c22c0b93ab24328833b8eb1ccc087fc0442a1c - languageName: node - linkType: hard - -"p-map@npm:^5.5.0": - version: 5.5.0 - resolution: "p-map@npm:5.5.0" - dependencies: - aggregate-error: ^4.0.0 - checksum: 065cb6fca6b78afbd070dd9224ff160dc23eea96e57863c09a0c8ea7ce921043f76854be7ee0abc295cff1ac9adcf700e79a1fbe3b80b625081087be58e7effb - languageName: node - linkType: hard - -"p-try@npm:^2.0.0": - version: 2.2.0 - resolution: "p-try@npm:2.2.0" - checksum: f8a8e9a7693659383f06aec604ad5ead237c7a261c18048a6e1b5b85a5f8a067e469aa24f5bc009b991ea3b058a87f5065ef4176793a200d4917349881216cae - languageName: node - linkType: hard - -"pako@npm:~1.0.2": - version: 1.0.11 - resolution: "pako@npm:1.0.11" - checksum: 1be2bfa1f807608c7538afa15d6f25baa523c30ec870a3228a89579e474a4d992f4293859524e46d5d87fd30fa17c5edf34dbef0671251d9749820b488660b16 - languageName: node - linkType: hard - -"parent-module@npm:^1.0.0": - version: 1.0.1 - resolution: "parent-module@npm:1.0.1" - dependencies: - callsites: ^3.0.0 - checksum: 6ba8b255145cae9470cf5551eb74be2d22281587af787a2626683a6c20fbb464978784661478dd2a3f1dad74d1e802d403e1b03c1a31fab310259eec8ac560ff - languageName: node - linkType: hard - -"parse-github-url@npm:^1.0.2": - version: 1.0.2 - resolution: "parse-github-url@npm:1.0.2" - bin: - parse-github-url: ./cli.js - checksum: a19b8bc6f8908a24cb63a10ff90cd39cec0745615a272ec686803684653be34eb3e638e31a66c8ee3a9568082ff686eaf010181688000a6274c86a23e9220f2f - languageName: node - linkType: hard - -"parse-json@npm:^5.0.0, parse-json@npm:^5.2.0": - version: 5.2.0 - resolution: "parse-json@npm:5.2.0" - dependencies: - "@babel/code-frame": ^7.0.0 - error-ex: ^1.3.1 - json-parse-even-better-errors: ^2.3.0 - lines-and-columns: ^1.1.6 - checksum: 62085b17d64da57f40f6afc2ac1f4d95def18c4323577e1eced571db75d9ab59b297d1d10582920f84b15985cbfc6b6d450ccbf317644cfa176f3ed982ad87e2 - languageName: node - linkType: hard - -"parseley@npm:^0.12.0": - version: 0.12.0 - resolution: "parseley@npm:0.12.0" - dependencies: - leac: ^0.6.0 - peberminta: ^0.9.0 - checksum: 3eaad074dfa914f55f16a2d2c45335fd8b3e84f968b40be4b784a5655f6984d652aaaaeba975ee1100541cd2bdda280f978a1b0cbfe4d961e0e45fb4439977f6 - languageName: node - linkType: hard - -"path-exists@npm:^3.0.0": - version: 3.0.0 - resolution: "path-exists@npm:3.0.0" - checksum: 96e92643aa34b4b28d0de1cd2eba52a1c5313a90c6542d03f62750d82480e20bfa62bc865d5cfc6165f5fcd5aeb0851043c40a39be5989646f223300021bae0a - languageName: node - linkType: hard - -"path-exists@npm:^4.0.0": - version: 4.0.0 - resolution: "path-exists@npm:4.0.0" - checksum: 505807199dfb7c50737b057dd8d351b82c033029ab94cb10a657609e00c1bc53b951cfdbccab8de04c5584d5eff31128ce6afd3db79281874a5ef2adbba55ed1 - languageName: node - linkType: hard - -"path-exists@npm:^5.0.0": - version: 5.0.0 - resolution: "path-exists@npm:5.0.0" - checksum: 8ca842868cab09423994596eb2c5ec2a971c17d1a3cb36dbf060592c730c725cd524b9067d7d2a1e031fef9ba7bd2ac6dc5ec9fb92aa693265f7be3987045254 - languageName: node - linkType: hard - -"path-is-absolute@npm:^1.0.0": - version: 1.0.1 - resolution: "path-is-absolute@npm:1.0.1" - checksum: 060840f92cf8effa293bcc1bea81281bd7d363731d214cbe5c227df207c34cd727430f70c6037b5159c8a870b9157cba65e775446b0ab06fd5ecc7e54615a3b8 - languageName: node - linkType: hard - -"path-key@npm:^3.0.0, path-key@npm:^3.1.0": - version: 3.1.1 - resolution: "path-key@npm:3.1.1" - checksum: 55cd7a9dd4b343412a8386a743f9c746ef196e57c823d90ca3ab917f90ab9f13dd0ded27252ba49dbdfcab2b091d998bc446f6220cd3cea65db407502a740020 - languageName: node - linkType: hard - -"path-parse@npm:^1.0.7": - version: 1.0.7 - resolution: "path-parse@npm:1.0.7" - checksum: 49abf3d81115642938a8700ec580da6e830dde670be21893c62f4e10bd7dd4c3742ddc603fe24f898cba7eb0c6bc1777f8d9ac14185d34540c6d4d80cd9cae8a - languageName: node - linkType: hard - -"path-type@npm:^4.0.0": - version: 4.0.0 - resolution: "path-type@npm:4.0.0" - checksum: 5b1e2daa247062061325b8fdbfd1fb56dde0a448fb1455453276ea18c60685bdad23a445dc148cf87bc216be1573357509b7d4060494a6fd768c7efad833ee45 - languageName: node - linkType: hard - -"pause-stream@npm:0.0.11": - version: 0.0.11 - resolution: "pause-stream@npm:0.0.11" - dependencies: - through: ~2.3 - checksum: 3c4a14052a638b92e0c96eb00c0d7977df7f79ea28395250c525d197f1fc02d34ce1165d5362e2e6ebbb251524b94a76f3f0d4abc39ab8b016d97449fe15583c - languageName: node - linkType: hard - -"peberminta@npm:^0.9.0": - version: 0.9.0 - resolution: "peberminta@npm:0.9.0" - checksum: b983b68077269ca8a3327520a0a3f027fa930faa9fb3cb53bed1cb3847ebc0ed55db936d70b1745a756149911f5f450e898e87e25ab207f1b8b892bed48fb540 - languageName: node - linkType: hard - -"pend@npm:~1.2.0": - version: 1.2.0 - resolution: "pend@npm:1.2.0" - checksum: 6c72f5243303d9c60bd98e6446ba7d30ae29e3d56fdb6fae8767e8ba6386f33ee284c97efe3230a0d0217e2b1723b8ab490b1bbf34fcbb2180dbc8a9de47850d - languageName: node - linkType: hard - -"picomatch@npm:^2.3.1": - version: 2.3.1 - resolution: "picomatch@npm:2.3.1" - checksum: 050c865ce81119c4822c45d3c84f1ced46f93a0126febae20737bd05ca20589c564d6e9226977df859ed5e03dc73f02584a2b0faad36e896936238238b0446cf - languageName: node - linkType: hard - -"pkg-dir@npm:^5.0.0": - version: 5.0.0 - resolution: "pkg-dir@npm:5.0.0" - dependencies: - find-up: ^5.0.0 - checksum: b167bb8dac7bbf22b1d5e30ec223e6b064b84b63010c9d49384619a36734caf95ed23ad23d4f9bd975e8e8082b60a83395f43a89bb192df53a7c25a38ecb57d9 - languageName: node - linkType: hard - -"pkg-dir@npm:^7.0.0": - version: 7.0.0 - resolution: "pkg-dir@npm:7.0.0" - dependencies: - find-up: ^6.3.0 - checksum: 94298b20a446bfbbd66604474de8a0cdd3b8d251225170970f15d9646f633e056c80520dd5b4c1d1050c9fed8f6a9e5054b141c93806439452efe72e57562c03 - languageName: node - linkType: hard - -"pkg-up@npm:^3.1.0": - version: 3.1.0 - resolution: "pkg-up@npm:3.1.0" - dependencies: - find-up: ^3.0.0 - checksum: 5bac346b7c7c903613c057ae3ab722f320716199d753f4a7d053d38f2b5955460f3e6ab73b4762c62fd3e947f58e04f1343e92089e7bb6091c90877406fcd8c8 - languageName: node - linkType: hard - -"playwright-core@npm:1.32.3": - version: 1.32.3 - resolution: "playwright-core@npm:1.32.3" - bin: - playwright: cli.js - checksum: 7ea091c41a7d1bb97b445bc541a85b123ffcf167bcc00fb7e13e9079f06c92f59fd27caf9d1c1d7e0054f2b5765d1a16d198833c2be7266cebb9dbb916cd90f4 - languageName: node - linkType: hard - -"playwright@npm:^1.29.2": - version: 1.32.3 - resolution: "playwright@npm:1.32.3" - dependencies: - playwright-core: 1.32.3 - bin: - playwright: cli.js - checksum: 9627771a131ab96a26d702757e89dcf09a228f0038c43a14f982cc59a2eca672cb27c9d92c324ddc2c44457b82d77c30b3562b386601969e0456b52dba5df176 - languageName: node - linkType: hard - -"plist@npm:^3.0.1, plist@npm:^3.0.4": - version: 3.0.6 - resolution: "plist@npm:3.0.6" - dependencies: - base64-js: ^1.5.1 - xmlbuilder: ^15.1.1 - checksum: e21390fab8a3c388f8f51b76c0aa187242a40537119ce865d8637630e7d7df79b21f841ec6a4668e7c68d409a6f584d696619099a6125d28011561639c0823b8 - languageName: node - linkType: hard - -"plur@npm:^4.0.0": - version: 4.0.0 - resolution: "plur@npm:4.0.0" - dependencies: - irregular-plurals: ^3.2.0 - checksum: fea2e903efca67cc5c7a8952fca3db46ae8d9e9353373b406714977e601a5d3b628bcb043c3ad2126c6ff0e73d8020bf43af30a72dd087eff1ec240eb13b90e1 - languageName: node - linkType: hard - -"pluralize@npm:^8.0.0": - version: 8.0.0 - resolution: "pluralize@npm:8.0.0" - checksum: 08931d4a6a4a5561a7f94f67a31c17e6632cb21e459ab3ff4f6f629d9a822984cf8afef2311d2005fbea5d7ef26016ebb090db008e2d8bce39d0a9a9d218736e - languageName: node - linkType: hard - -"prelude-ls@npm:^1.2.1": - version: 1.2.1 - resolution: "prelude-ls@npm:1.2.1" - checksum: cd192ec0d0a8e4c6da3bb80e4f62afe336df3f76271ac6deb0e6a36187133b6073a19e9727a1ff108cd8b9982e4768850d413baa71214dd80c7979617dca827a - languageName: node - linkType: hard - -"prettier-linter-helpers@npm:^1.0.0": - version: 1.0.0 - resolution: "prettier-linter-helpers@npm:1.0.0" - dependencies: - fast-diff: ^1.1.2 - checksum: 00ce8011cf6430158d27f9c92cfea0a7699405633f7f1d4a45f07e21bf78e99895911cbcdc3853db3a824201a7c745bd49bfea8abd5fb9883e765a90f74f8392 - languageName: node - linkType: hard - -"prettier@npm:^2.7.1": - version: 2.8.7 - resolution: "prettier@npm:2.8.7" - bin: - prettier: bin-prettier.js - checksum: fdc8f2616f099f5f0d685907f4449a70595a0fc1d081a88919604375989e0d5e9168d6121d8cc6861f21990b31665828e00472544d785d5940ea08a17660c3a6 - languageName: node - linkType: hard - -"process-nextick-args@npm:~2.0.0": - version: 2.0.1 - resolution: "process-nextick-args@npm:2.0.1" - checksum: 1d38588e520dab7cea67cbbe2efdd86a10cc7a074c09657635e34f035277b59fbb57d09d8638346bf7090f8e8ebc070c96fa5fd183b777fff4f5edff5e9466cf - languageName: node - linkType: hard - -"progress@npm:^2.0.3": - version: 2.0.3 - resolution: "progress@npm:2.0.3" - checksum: f67403fe7b34912148d9252cb7481266a354bd99ce82c835f79070643bb3c6583d10dbcfda4d41e04bbc1d8437e9af0fb1e1f2135727878f5308682a579429b7 - languageName: node - linkType: hard - -"promise-inflight@npm:^1.0.1": - version: 1.0.1 - resolution: "promise-inflight@npm:1.0.1" - checksum: 22749483091d2c594261517f4f80e05226d4d5ecc1fc917e1886929da56e22b5718b7f2a75f3807e7a7d471bc3be2907fe92e6e8f373ddf5c64bae35b5af3981 - languageName: node - linkType: hard - -"promise-retry@npm:^2.0.1": - version: 2.0.1 - resolution: "promise-retry@npm:2.0.1" - dependencies: - err-code: ^2.0.2 - retry: ^0.12.0 - checksum: f96a3f6d90b92b568a26f71e966cbbc0f63ab85ea6ff6c81284dc869b41510e6cdef99b6b65f9030f0db422bf7c96652a3fff9f2e8fb4a0f069d8f4430359429 - languageName: node - linkType: hard - -"proto-props@npm:^2.0.0": - version: 2.0.0 - resolution: "proto-props@npm:2.0.0" - checksum: 124dd7bc0e8ee5fae2f1c19446f17d58f71d15f4f81fb4aad4c6f2f379b50e2a6a04ff91387399ef71517dd411be1935d9b14d1c4894645f961912436f0a298a - languageName: node - linkType: hard - -"proxy-from-env@npm:^1.1.0": - version: 1.1.0 - resolution: "proxy-from-env@npm:1.1.0" - checksum: ed7fcc2ba0a33404958e34d95d18638249a68c430e30fcb6c478497d72739ba64ce9810a24f53a7d921d0c065e5b78e3822759800698167256b04659366ca4d4 - languageName: node - linkType: hard - -"pump@npm:^3.0.0": - version: 3.0.0 - resolution: "pump@npm:3.0.0" - dependencies: - end-of-stream: ^1.1.0 - once: ^1.3.1 - checksum: e42e9229fba14732593a718b04cb5e1cfef8254544870997e0ecd9732b189a48e1256e4e5478148ecb47c8511dca2b09eae56b4d0aad8009e6fac8072923cfc9 - languageName: node - linkType: hard - -"punycode@npm:^2.1.0": - version: 2.3.0 - resolution: "punycode@npm:2.3.0" - checksum: 39f760e09a2a3bbfe8f5287cf733ecdad69d6af2fe6f97ca95f24b8921858b91e9ea3c9eeec6e08cede96181b3bb33f95c6ffd8c77e63986508aa2e8159fa200 - languageName: node - linkType: hard - -"queue-microtask@npm:^1.2.2": - version: 1.2.3 - resolution: "queue-microtask@npm:1.2.3" - checksum: b676f8c040cdc5b12723ad2f91414d267605b26419d5c821ff03befa817ddd10e238d22b25d604920340fd73efd8ba795465a0377c4adf45a4a41e4234e42dc4 - languageName: node - linkType: hard - -"quick-lru@npm:^5.1.1": - version: 5.1.1 - resolution: "quick-lru@npm:5.1.1" - checksum: a516faa25574be7947969883e6068dbe4aa19e8ef8e8e0fd96cddd6d36485e9106d85c0041a27153286b0770b381328f4072aa40d3b18a19f5f7d2b78b94b5ed - languageName: node - linkType: hard - -"quick-lru@npm:^6.1.1": - version: 6.1.1 - resolution: "quick-lru@npm:6.1.1" - checksum: a9c75bf1d208c1d207590e10403a75d037f9faf7857f2e0d38c294d92b40d8b400776bcb5d4dd516baa84e6f5e3baf2a16cf405e6fedc18107922f46aeae83ee - languageName: node - linkType: hard - -"read-config-file@npm:6.2.0": - version: 6.2.0 - resolution: "read-config-file@npm:6.2.0" - dependencies: - dotenv: ^9.0.2 - dotenv-expand: ^5.1.0 - js-yaml: ^4.1.0 - json5: ^2.2.0 - lazy-val: ^1.0.4 - checksum: 51e30db82244b8ceea19143207a52c5210fa17f5282ec43e9485cf7da87ac4ee3a0fb961cccc5c7af319b06d004baa0154349e09ca8ca7235ae7e5ac7c14c3f3 - languageName: node - linkType: hard - -"read-pkg-up@npm:^7.0.1": - version: 7.0.1 - resolution: "read-pkg-up@npm:7.0.1" - dependencies: - find-up: ^4.1.0 - read-pkg: ^5.2.0 - type-fest: ^0.8.1 - checksum: e4e93ce70e5905b490ca8f883eb9e48b5d3cebc6cd4527c25a0d8f3ae2903bd4121c5ab9c5a3e217ada0141098eeb661313c86fa008524b089b8ed0b7f165e44 - languageName: node - linkType: hard - -"read-pkg-up@npm:^8.0.0": - version: 8.0.0 - resolution: "read-pkg-up@npm:8.0.0" - dependencies: - find-up: ^5.0.0 - read-pkg: ^6.0.0 - type-fest: ^1.0.1 - checksum: fe4c80401656b40b408884457fffb5a8015c03b1018cfd8e48f8d82a5e9023e24963603aeb2755608d964593e046c15b34d29b07d35af9c7aa478be81805209c - languageName: node - linkType: hard - -"read-pkg-up@npm:^9.1.0": - version: 9.1.0 - resolution: "read-pkg-up@npm:9.1.0" - dependencies: - find-up: ^6.3.0 - read-pkg: ^7.1.0 - type-fest: ^2.5.0 - checksum: 41b8ba4bdb7c1e914aa6ce2d36a7c1651e9086938977fa12f058f6fca51ee15315634af648ca4ef70dd074e575e854616b39032ad0b376e9e97d61a9d0867afe - languageName: node - linkType: hard - -"read-pkg@npm:^5.2.0": - version: 5.2.0 - resolution: "read-pkg@npm:5.2.0" - dependencies: - "@types/normalize-package-data": ^2.4.0 - normalize-package-data: ^2.5.0 - parse-json: ^5.0.0 - type-fest: ^0.6.0 - checksum: eb696e60528b29aebe10e499ba93f44991908c57d70f2d26f369e46b8b9afc208ef11b4ba64f67630f31df8b6872129e0a8933c8c53b7b4daf0eace536901222 - languageName: node - linkType: hard - -"read-pkg@npm:^6.0.0": - version: 6.0.0 - resolution: "read-pkg@npm:6.0.0" - dependencies: - "@types/normalize-package-data": ^2.4.0 - normalize-package-data: ^3.0.2 - parse-json: ^5.2.0 - type-fest: ^1.0.1 - checksum: 0cebdff381128e923815c643074a87011070e5fc352bee575d327d6485da3317fab6d802a7b03deeb0be7be8d3ad1640397b3d5d2f044452caf4e8d1736bf94f - languageName: node - linkType: hard - -"read-pkg@npm:^7.1.0": - version: 7.1.0 - resolution: "read-pkg@npm:7.1.0" - dependencies: - "@types/normalize-package-data": ^2.4.1 - normalize-package-data: ^3.0.2 - parse-json: ^5.2.0 - type-fest: ^2.0.0 - checksum: 20d11c59be3ae1fc79d4b9c8594dabeaec58105f9dfd710570ef9690ec2ac929247006e79ca114257683228663199735d60f149948dbc5f34fcd2d28883ab5f7 - languageName: node - linkType: hard - -"readable-stream@npm:^3.6.0": - version: 3.6.2 - resolution: "readable-stream@npm:3.6.2" - dependencies: - inherits: ^2.0.3 - string_decoder: ^1.1.1 - util-deprecate: ^1.0.1 - checksum: bdcbe6c22e846b6af075e32cf8f4751c2576238c5043169a1c221c92ee2878458a816a4ea33f4c67623c0b6827c8a400409bfb3cf0bf3381392d0b1dfb52ac8d - languageName: node - linkType: hard - -"readable-stream@npm:~2.3.6": - version: 2.3.8 - resolution: "readable-stream@npm:2.3.8" - dependencies: - core-util-is: ~1.0.0 - inherits: ~2.0.3 - isarray: ~1.0.0 - process-nextick-args: ~2.0.0 - safe-buffer: ~5.1.1 - string_decoder: ~1.1.1 - util-deprecate: ~1.0.1 - checksum: 65645467038704f0c8aaf026a72fbb588a9e2ef7a75cd57a01702ee9db1c4a1e4b03aaad36861a6a0926546a74d174149c8c207527963e0c2d3eee2f37678a42 - languageName: node - linkType: hard - -"redent@npm:^4.0.0": - version: 4.0.0 - resolution: "redent@npm:4.0.0" - dependencies: - indent-string: ^5.0.0 - strip-indent: ^4.0.0 - checksum: 6944e7b1d8f3fd28c2515f5c605b9f7f0ea0f4edddf41890bbbdd4d9ee35abb7540c3b278f03ff827bd278bb6ff4a5bd8692ca406b748c5c1c3ce7355e9fbf8f - languageName: node - linkType: hard - -"regenerator-runtime@npm:^0.11.0": - version: 0.11.1 - resolution: "regenerator-runtime@npm:0.11.1" - checksum: 3c97bd2c7b2b3247e6f8e2147a002eb78c995323732dad5dc70fac8d8d0b758d0295e7015b90d3d444446ae77cbd24b9f9123ec3a77018e81d8999818301b4f4 - languageName: node - linkType: hard - -"regenerator-runtime@npm:^0.13.11, regenerator-runtime@npm:^0.13.7": - version: 0.13.11 - resolution: "regenerator-runtime@npm:0.13.11" - checksum: 27481628d22a1c4e3ff551096a683b424242a216fee44685467307f14d58020af1e19660bf2e26064de946bad7eff28950eae9f8209d55723e2d9351e632bbb4 - languageName: node - linkType: hard - -"regexp-tree@npm:^0.1.24, regexp-tree@npm:~0.1.1": - version: 0.1.24 - resolution: "regexp-tree@npm:0.1.24" - bin: - regexp-tree: bin/regexp-tree - checksum: 5807013289d9205288d665e0f8d8cff94843dfd55fdedd1833eb9d9bbd07188a37dfa02942ec5cdc671180037f715148fac1ba6f18fd6be4268e5a8feb49d340 - languageName: node - linkType: hard - -"regexp.prototype.flags@npm:^1.2.0, regexp.prototype.flags@npm:^1.4.3": - version: 1.4.3 - resolution: "regexp.prototype.flags@npm:1.4.3" - dependencies: - call-bind: ^1.0.2 - define-properties: ^1.1.3 - functions-have-names: ^1.2.2 - checksum: 51228bae732592adb3ededd5e15426be25f289e9c4ef15212f4da73f4ec3919b6140806374b8894036a86020d054a8d2657d3fee6bb9b4d35d8939c20030b7a6 - languageName: node - linkType: hard - -"regexpp@npm:^3.0.0": - version: 3.2.0 - resolution: "regexpp@npm:3.2.0" - checksum: a78dc5c7158ad9ddcfe01aa9144f46e192ddbfa7b263895a70a5c6c73edd9ce85faf7c0430e59ac38839e1734e275b9c3de5c57ee3ab6edc0e0b1bdebefccef8 - languageName: node - linkType: hard - -"require-directory@npm:^2.1.1": - version: 2.1.1 - resolution: "require-directory@npm:2.1.1" - checksum: fb47e70bf0001fdeabdc0429d431863e9475e7e43ea5f94ad86503d918423c1543361cc5166d713eaa7029dd7a3d34775af04764bebff99ef413111a5af18c80 - languageName: node - linkType: hard - -"require-from-string@npm:^2.0.2": - version: 2.0.2 - resolution: "require-from-string@npm:2.0.2" - checksum: a03ef6895445f33a4015300c426699bc66b2b044ba7b670aa238610381b56d3f07c686251740d575e22f4c87531ba662d06937508f0f3c0f1ddc04db3130560b - languageName: node - linkType: hard - -"resolve-alpn@npm:^1.0.0": - version: 1.2.1 - resolution: "resolve-alpn@npm:1.2.1" - checksum: f558071fcb2c60b04054c99aebd572a2af97ef64128d59bef7ab73bd50d896a222a056de40ffc545b633d99b304c259ea9d0c06830d5c867c34f0bfa60b8eae0 - languageName: node - linkType: hard - -"resolve-from@npm:^4.0.0": - version: 4.0.0 - resolution: "resolve-from@npm:4.0.0" - checksum: f4ba0b8494846a5066328ad33ef8ac173801a51739eb4d63408c847da9a2e1c1de1e6cbbf72699211f3d13f8fc1325648b169bd15eb7da35688e30a5fb0e4a7f - languageName: node - linkType: hard - -"resolve-from@npm:^5.0.0": - version: 5.0.0 - resolution: "resolve-from@npm:5.0.0" - checksum: 4ceeb9113e1b1372d0cd969f3468fa042daa1dd9527b1b6bb88acb6ab55d8b9cd65dbf18819f9f9ddf0db804990901dcdaade80a215e7b2c23daae38e64f5bdf - languageName: node - linkType: hard - -"resolve-url@npm:^0.2.1": - version: 0.2.1 - resolution: "resolve-url@npm:0.2.1" - checksum: 7b7035b9ed6e7bc7d289e90aef1eab5a43834539695dac6416ca6e91f1a94132ae4796bbd173cdacfdc2ade90b5f38a3fb6186bebc1b221cd157777a23b9ad14 - languageName: node - linkType: hard - -"resolve@npm:^1.10.0, resolve@npm:^1.20.0, resolve@npm:^1.22.1": - version: 1.22.3 - resolution: "resolve@npm:1.22.3" - dependencies: - is-core-module: ^2.12.0 - path-parse: ^1.0.7 - supports-preserve-symlinks-flag: ^1.0.0 - bin: - resolve: bin/resolve - checksum: fb834b81348428cb545ff1b828a72ea28feb5a97c026a1cf40aa1008352c72811ff4d4e71f2035273dc536dcfcae20c13604ba6283c612d70fa0b6e44519c374 - languageName: node - linkType: hard - -"resolve@patch:resolve@^1.10.0#~builtin, resolve@patch:resolve@^1.20.0#~builtin, resolve@patch:resolve@^1.22.1#~builtin": - version: 1.22.3 - resolution: "resolve@patch:resolve@npm%3A1.22.3#~builtin::version=1.22.3&hash=c3c19d" - dependencies: - is-core-module: ^2.12.0 - path-parse: ^1.0.7 - supports-preserve-symlinks-flag: ^1.0.0 - bin: - resolve: bin/resolve - checksum: ad59734723b596d0891321c951592ed9015a77ce84907f89c9d9307dd0c06e11a67906a3e628c4cae143d3e44898603478af0ddeb2bba3f229a9373efe342665 - languageName: node - linkType: hard - -"responselike@npm:^2.0.0": - version: 2.0.1 - resolution: "responselike@npm:2.0.1" - dependencies: - lowercase-keys: ^2.0.0 - checksum: b122535466e9c97b55e69c7f18e2be0ce3823c5d47ee8de0d9c0b114aa55741c6db8bfbfce3766a94d1272e61bfb1ebf0a15e9310ac5629fbb7446a861b4fd3a - languageName: node - linkType: hard - -"retry@npm:^0.12.0": - version: 0.12.0 - resolution: "retry@npm:0.12.0" - checksum: 623bd7d2e5119467ba66202d733ec3c2e2e26568074923bc0585b6b99db14f357e79bdedb63cab56cec47491c4a0da7e6021a7465ca6dc4f481d3898fdd3158c - languageName: node - linkType: hard - -"reusify@npm:^1.0.4": - version: 1.0.4 - resolution: "reusify@npm:1.0.4" - checksum: c3076ebcc22a6bc252cb0b9c77561795256c22b757f40c0d8110b1300723f15ec0fc8685e8d4ea6d7666f36c79ccc793b1939c748bf36f18f542744a4e379fcc - languageName: node - linkType: hard - -"rimraf@npm:^3.0.0, rimraf@npm:^3.0.2": - version: 3.0.2 - resolution: "rimraf@npm:3.0.2" - dependencies: - glob: ^7.1.3 - bin: - rimraf: bin.js - checksum: 87f4164e396f0171b0a3386cc1877a817f572148ee13a7e113b238e48e8a9f2f31d009a92ec38a591ff1567d9662c6b67fd8818a2dbbaed74bc26a87a2a4a9a0 - languageName: node - linkType: hard - -"roarr@npm:^2.15.3": - version: 2.15.4 - resolution: "roarr@npm:2.15.4" - dependencies: - boolean: ^3.0.1 - detect-node: ^2.0.4 - globalthis: ^1.0.1 - json-stringify-safe: ^5.0.1 - semver-compare: ^1.0.0 - sprintf-js: ^1.1.2 - checksum: 682e28d5491e3ae99728a35ba188f4f0ccb6347dbd492f95dc9f4bfdfe8ee63d8203ad234766ee2db88c8d7a300714304976eb095ce5c9366fe586c03a21586c - languageName: node - linkType: hard - -"run-parallel@npm:^1.1.9": - version: 1.2.0 - resolution: "run-parallel@npm:1.2.0" - dependencies: - queue-microtask: ^1.2.2 - checksum: cb4f97ad25a75ebc11a8ef4e33bb962f8af8516bb2001082ceabd8902e15b98f4b84b4f8a9b222e5d57fc3bd1379c483886ed4619367a7680dad65316993021d - languageName: node - linkType: hard - -"rxjs@npm:*": - version: 7.8.0 - resolution: "rxjs@npm:7.8.0" - dependencies: - tslib: ^2.1.0 - checksum: 61b4d4fd323c1043d8d6ceb91f24183b28bcf5def4f01ca111511d5c6b66755bc5578587fe714ef5d67cf4c9f2e26f4490d4e1d8cabf9bd5967687835e9866a2 - languageName: node - linkType: hard - -"safe-buffer@npm:^5.1.1, safe-buffer@npm:~5.2.0": - version: 5.2.1 - resolution: "safe-buffer@npm:5.2.1" - checksum: b99c4b41fdd67a6aaf280fcd05e9ffb0813654894223afb78a31f14a19ad220bba8aba1cb14eddce1fcfb037155fe6de4e861784eb434f7d11ed58d1e70dd491 - languageName: node - linkType: hard - -"safe-buffer@npm:~5.1.0, safe-buffer@npm:~5.1.1": - version: 5.1.2 - resolution: "safe-buffer@npm:5.1.2" - checksum: f2f1f7943ca44a594893a852894055cf619c1fbcb611237fc39e461ae751187e7baf4dc391a72125e0ac4fb2d8c5c0b3c71529622e6a58f46b960211e704903c - languageName: node - linkType: hard - -"safe-regex-test@npm:^1.0.0": - version: 1.0.0 - resolution: "safe-regex-test@npm:1.0.0" - dependencies: - call-bind: ^1.0.2 - get-intrinsic: ^1.1.3 - is-regex: ^1.1.4 - checksum: bc566d8beb8b43c01b94e67de3f070fd2781685e835959bbbaaec91cc53381145ca91f69bd837ce6ec244817afa0a5e974fc4e40a2957f0aca68ac3add1ddd34 - languageName: node - linkType: hard - -"safe-regex@npm:^2.1.1": - version: 2.1.1 - resolution: "safe-regex@npm:2.1.1" - dependencies: - regexp-tree: ~0.1.1 - checksum: 5d734e2193c63ef0cb00f60c0244e0f8a30ecb31923633cd34636808d6a7c4c206d650017953ae1db8bc33967c2f06af33488dea6f038f4e38212beb7bed77b4 - languageName: node - linkType: hard - -"safer-buffer@npm:>= 2.1.2 < 3.0.0": - version: 2.1.2 - resolution: "safer-buffer@npm:2.1.2" - checksum: cab8f25ae6f1434abee8d80023d7e72b598cf1327164ddab31003c51215526801e40b66c5e65d658a0af1e9d6478cadcb4c745f4bd6751f97d8644786c0978b0 - languageName: node - linkType: hard - -"sanitize-filename@npm:^1.6.3": - version: 1.6.3 - resolution: "sanitize-filename@npm:1.6.3" - dependencies: - truncate-utf8-bytes: ^1.0.0 - checksum: aa733c012b7823cf65730603cf3b503c641cee6b239771d3164ca482f22d81a50e434a713938d994071db18e4202625669cc56bccc9d13d818b4c983b5f47fde - languageName: node - linkType: hard - -"sax@npm:>=0.6.0, sax@npm:^1.2.4": - version: 1.2.4 - resolution: "sax@npm:1.2.4" - checksum: d3df7d32b897a2c2f28e941f732c71ba90e27c24f62ee918bd4d9a8cfb3553f2f81e5493c7f0be94a11c1911b643a9108f231dd6f60df3fa9586b5d2e3e9e1fe - languageName: node - linkType: hard - -"selderee@npm:^0.11.0": - version: 0.11.0 - resolution: "selderee@npm:0.11.0" - dependencies: - parseley: ^0.12.0 - checksum: af8a68c1f4cde858152943b6fc9f2b7164c8fb1a1c9f01b44350dffd1f79783930d77a0ae33548a036816d17c8130eeb9d15f1db65c9262ca368ad3a0d750f66 - languageName: node - linkType: hard - -"semver-compare@npm:^1.0.0": - version: 1.0.0 - resolution: "semver-compare@npm:1.0.0" - checksum: dd1d7e2909744cf2cf71864ac718efc990297f9de2913b68e41a214319e70174b1d1793ac16e31183b128c2b9812541300cb324db8168e6cf6b570703b171c68 - languageName: node - linkType: hard - -"semver@npm:2 || 3 || 4 || 5, semver@npm:^5.5.0, semver@npm:^5.7.1": - version: 5.7.1 - resolution: "semver@npm:5.7.1" - bin: - semver: ./bin/semver - checksum: 57fd0acfd0bac382ee87cd52cd0aaa5af086a7dc8d60379dfe65fea491fb2489b6016400813930ecd61fd0952dae75c115287a1b16c234b1550887117744dfaf - languageName: node - linkType: hard - -"semver@npm:^6.2.0, semver@npm:^6.3.0": - version: 6.3.0 - resolution: "semver@npm:6.3.0" - bin: - semver: ./bin/semver.js - checksum: 1b26ecf6db9e8292dd90df4e781d91875c0dcc1b1909e70f5d12959a23c7eebb8f01ea581c00783bbee72ceeaad9505797c381756326073850dc36ed284b21b9 - languageName: node - linkType: hard - -"semver@npm:^7.0.0, semver@npm:^7.2.1, semver@npm:^7.3.2, semver@npm:^7.3.4, semver@npm:^7.3.5, semver@npm:^7.3.7, semver@npm:^7.3.8": - version: 7.4.0 - resolution: "semver@npm:7.4.0" - dependencies: - lru-cache: ^6.0.0 - bin: - semver: bin/semver.js - checksum: debf7f4d6fa36fdc5ef82bd7fc3603b6412165c8a3963a30be0c45a587be1a49e7681e80aa109da1875765741af24edc6e021cee1ba16ae96f649d06c5df296d - languageName: node - linkType: hard - -"semver@npm:~7.0.0": - version: 7.0.0 - resolution: "semver@npm:7.0.0" - bin: - semver: bin/semver.js - checksum: 272c11bf8d083274ef79fe40a81c55c184dff84dd58e3c325299d0927ba48cece1f020793d138382b85f89bab5002a35a5ba59a3a68a7eebbb597eb733838778 - languageName: node - linkType: hard - -"serialize-error@npm:^7.0.1": - version: 7.0.1 - resolution: "serialize-error@npm:7.0.1" - dependencies: - type-fest: ^0.13.1 - checksum: e0aba4dca2fc9fe74ae1baf38dbd99190e1945445a241ba646290f2176cdb2032281a76443b02ccf0caf30da5657d510746506368889a593b9835a497fc0732e - languageName: node - linkType: hard - -"serialize-error@npm:^8.1.0": - version: 8.1.0 - resolution: "serialize-error@npm:8.1.0" - dependencies: - type-fest: ^0.20.2 - checksum: 2eef236d50edd2d7926e602c14fb500dc3a125ee52e9f08f67033181b8e0be5d1122498bdf7c23c80683cddcad083a27974e9e7111ce23165f4d3bcdd6d65102 - languageName: node - linkType: hard - -"set-blocking@npm:^2.0.0": - version: 2.0.0 - resolution: "set-blocking@npm:2.0.0" - checksum: 6e65a05f7cf7ebdf8b7c75b101e18c0b7e3dff4940d480efed8aad3a36a4005140b660fa1d804cb8bce911cac290441dc728084a30504d3516ac2ff7ad607b02 - languageName: node - linkType: hard - -"setimmediate@npm:^1.0.5": - version: 1.0.5 - resolution: "setimmediate@npm:1.0.5" - checksum: c9a6f2c5b51a2dabdc0247db9c46460152ffc62ee139f3157440bd48e7c59425093f42719ac1d7931f054f153e2d26cf37dfeb8da17a794a58198a2705e527fd - languageName: node - linkType: hard - -"shebang-command@npm:^2.0.0": - version: 2.0.0 - resolution: "shebang-command@npm:2.0.0" - dependencies: - shebang-regex: ^3.0.0 - checksum: 6b52fe87271c12968f6a054e60f6bde5f0f3d2db483a1e5c3e12d657c488a15474121a1d55cd958f6df026a54374ec38a4a963988c213b7570e1d51575cea7fa - languageName: node - linkType: hard - -"shebang-regex@npm:^3.0.0": - version: 3.0.0 - resolution: "shebang-regex@npm:3.0.0" - checksum: 1a2bcae50de99034fcd92ad4212d8e01eedf52c7ec7830eedcf886622804fe36884278f2be8be0ea5fde3fd1c23911643a4e0f726c8685b61871c8908af01222 - languageName: node - linkType: hard - -"side-channel@npm:^1.0.4": - version: 1.0.4 - resolution: "side-channel@npm:1.0.4" - dependencies: - call-bind: ^1.0.0 - get-intrinsic: ^1.0.2 - object-inspect: ^1.9.0 - checksum: 351e41b947079c10bd0858364f32bb3a7379514c399edb64ab3dce683933483fc63fb5e4efe0a15a2e8a7e3c436b6a91736ddb8d8c6591b0460a24bb4a1ee245 - languageName: node - linkType: hard - -"signal-exit@npm:^3.0.3, signal-exit@npm:^3.0.7": - version: 3.0.7 - resolution: "signal-exit@npm:3.0.7" - checksum: a2f098f247adc367dffc27845853e9959b9e88b01cb301658cfe4194352d8d2bb32e18467c786a7fe15f1d44b233ea35633d076d5e737870b7139949d1ab6318 - languageName: node - linkType: hard - -"simple-update-notifier@npm:^1.0.7": - version: 1.1.0 - resolution: "simple-update-notifier@npm:1.1.0" - dependencies: - semver: ~7.0.0 - checksum: 1012e9b6c504e559a948078177b3eedbb9d7e4d15878e2bda56314d08db609ca5da485be4ac9f838759faae8057935ee0246fcdf63f1233c86bd9fecb2a5544b - languageName: node - linkType: hard - -"simple-youtube-age-restriction-bypass@https://gitpkg.now.sh/api/pkg.tgz?url=MiepHD/Simple-YouTube-Age-Restriction-Bypass&commit=v2.5.5": - version: 2.5.9 - resolution: "simple-youtube-age-restriction-bypass@https://gitpkg.now.sh/api/pkg.tgz?url=MiepHD/Simple-YouTube-Age-Restriction-Bypass&commit=v2.5.5" - checksum: 6871673051c50c9fa4d17ad2e1a75b0d8988de5c633bc00bd911647d91b377dc8945ee9aac4ee607e1d2ffd92128ca55aa8841d9716a108999cf925654fd4b05 - languageName: node - linkType: hard - -"slash@npm:^3.0.0": - version: 3.0.0 - resolution: "slash@npm:3.0.0" - checksum: 94a93fff615f25a999ad4b83c9d5e257a7280c90a32a7cb8b4a87996e4babf322e469c42b7f649fd5796edd8687652f3fb452a86dc97a816f01113183393f11c - languageName: node - linkType: hard - -"slash@npm:^4.0.0": - version: 4.0.0 - resolution: "slash@npm:4.0.0" - checksum: da8e4af73712253acd21b7853b7e0dbba776b786e82b010a5bfc8b5051a1db38ed8aba8e1e8f400dd2c9f373be91eb1c42b66e91abb407ff42b10feece5e1d2d - languageName: node - linkType: hard - -"slash@npm:^5.0.0": - version: 5.0.0 - resolution: "slash@npm:5.0.0" - checksum: 1fa799ee165f7eacf0122ea4252bcf44290db402eb9d3058624ff1d421b8dfe262100dffb0b2cc23f36858666bf661476e2a4c40ebaf3e7b61107cad55a1de88 - languageName: node - linkType: hard - -"slice-ansi@npm:^3.0.0": - version: 3.0.0 - resolution: "slice-ansi@npm:3.0.0" - dependencies: - ansi-styles: ^4.0.0 - astral-regex: ^2.0.0 - is-fullwidth-code-point: ^3.0.0 - checksum: 5ec6d022d12e016347e9e3e98a7eb2a592213a43a65f1b61b74d2c78288da0aded781f665807a9f3876b9daa9ad94f64f77d7633a0458876c3a4fdc4eb223f24 - languageName: node - linkType: hard - -"smart-buffer@npm:^4.0.2, smart-buffer@npm:^4.2.0": - version: 4.2.0 - resolution: "smart-buffer@npm:4.2.0" - checksum: b5167a7142c1da704c0e3af85c402002b597081dd9575031a90b4f229ca5678e9a36e8a374f1814c8156a725d17008ae3bde63b92f9cfd132526379e580bec8b - languageName: node - linkType: hard - -"socks-proxy-agent@npm:^7.0.0": - version: 7.0.0 - resolution: "socks-proxy-agent@npm:7.0.0" - dependencies: - agent-base: ^6.0.2 - debug: ^4.3.3 - socks: ^2.6.2 - checksum: 720554370154cbc979e2e9ce6a6ec6ced205d02757d8f5d93fe95adae454fc187a5cbfc6b022afab850a5ce9b4c7d73e0f98e381879cf45f66317a4895953846 - languageName: node - linkType: hard - -"socks@npm:^2.6.2": - version: 2.7.1 - resolution: "socks@npm:2.7.1" - dependencies: - ip: ^2.0.0 - smart-buffer: ^4.2.0 - checksum: 259d9e3e8e1c9809a7f5c32238c3d4d2a36b39b83851d0f573bfde5f21c4b1288417ce1af06af1452569cd1eb0841169afd4998f0e04ba04656f6b7f0e46d748 - languageName: node - linkType: hard - -"source-map-support@npm:^0.5.11, source-map-support@npm:^0.5.19": - version: 0.5.21 - resolution: "source-map-support@npm:0.5.21" - dependencies: - buffer-from: ^1.0.0 - source-map: ^0.6.0 - checksum: 43e98d700d79af1d36f859bdb7318e601dfc918c7ba2e98456118ebc4c4872b327773e5a1df09b0524e9e5063bb18f0934538eace60cca2710d1fa687645d137 - languageName: node - linkType: hard - -"source-map@npm:^0.6.0, source-map@npm:^0.6.1": - version: 0.6.1 - resolution: "source-map@npm:0.6.1" - checksum: 59ce8640cf3f3124f64ac289012c2b8bd377c238e316fb323ea22fbfe83da07d81e000071d7242cad7a23cd91c7de98e4df8830ec3f133cb6133a5f6e9f67bc2 - languageName: node - linkType: hard - -"spdx-correct@npm:^3.0.0": - version: 3.2.0 - resolution: "spdx-correct@npm:3.2.0" - dependencies: - spdx-expression-parse: ^3.0.0 - spdx-license-ids: ^3.0.0 - checksum: e9ae98d22f69c88e7aff5b8778dc01c361ef635580e82d29e5c60a6533cc8f4d820803e67d7432581af0cc4fb49973125076ee3b90df191d153e223c004193b2 - languageName: node - linkType: hard - -"spdx-exceptions@npm:^2.1.0": - version: 2.3.0 - resolution: "spdx-exceptions@npm:2.3.0" - checksum: cb69a26fa3b46305637123cd37c85f75610e8c477b6476fa7354eb67c08128d159f1d36715f19be6f9daf4b680337deb8c65acdcae7f2608ba51931540687ac0 - languageName: node - linkType: hard - -"spdx-expression-parse@npm:^3.0.0": - version: 3.0.1 - resolution: "spdx-expression-parse@npm:3.0.1" - dependencies: - spdx-exceptions: ^2.1.0 - spdx-license-ids: ^3.0.0 - checksum: a1c6e104a2cbada7a593eaa9f430bd5e148ef5290d4c0409899855ce8b1c39652bcc88a725259491a82601159d6dc790bedefc9016c7472f7de8de7361f8ccde - languageName: node - linkType: hard - -"spdx-license-ids@npm:^3.0.0": - version: 3.0.13 - resolution: "spdx-license-ids@npm:3.0.13" - checksum: 3469d85c65f3245a279fa11afc250c3dca96e9e847f2f79d57f466940c5bb8495da08a542646086d499b7f24a74b8d0b42f3fc0f95d50ff99af1f599f6360ad7 - languageName: node - linkType: hard - -"split@npm:0.3": - version: 0.3.3 - resolution: "split@npm:0.3.3" - dependencies: - through: 2 - checksum: 2e076634c9637cfdc54ab4387b6a243b8c33b360874a25adf6f327a5647f07cb3bf1c755d515248eb3afee4e382278d01f62c62d87263c118f28065b86f74f02 - languageName: node - linkType: hard - -"sprintf-js@npm:^1.1.2": - version: 1.1.2 - resolution: "sprintf-js@npm:1.1.2" - checksum: d4bb46464632b335e5faed381bd331157e0af64915a98ede833452663bc672823db49d7531c32d58798e85236581fb7342fd0270531ffc8f914e186187bf1c90 - languageName: node - linkType: hard - -"ssri@npm:^9.0.0": - version: 9.0.1 - resolution: "ssri@npm:9.0.1" - dependencies: - minipass: ^3.1.1 - checksum: fb58f5e46b6923ae67b87ad5ef1c5ab6d427a17db0bead84570c2df3cd50b4ceb880ebdba2d60726588272890bae842a744e1ecce5bd2a2a582fccd5068309eb - languageName: node - linkType: hard - -"stat-mode@npm:^1.0.0": - version: 1.0.0 - resolution: "stat-mode@npm:1.0.0" - checksum: f9daea2dba41e1dffae5543a8af087ec8b56ff6ae1c729b5373b4f528e214f53260108dab522d2660cca2215dc3e61f164920a82136ad142dab50b3faa6f6090 - languageName: node - linkType: hard - -"stream-combiner@npm:~0.0.4": - version: 0.0.4 - resolution: "stream-combiner@npm:0.0.4" - dependencies: - duplexer: ~0.1.1 - checksum: 844b622cfe8b9de45a6007404f613b60aaf85200ab9862299066204242f89a7c8033b1c356c998aa6cfc630f6cd9eba119ec1c6dc1f93e245982be4a847aee7d - languageName: node - linkType: hard - -"streamsearch@npm:^1.1.0": - version: 1.1.0 - resolution: "streamsearch@npm:1.1.0" - checksum: 1cce16cea8405d7a233d32ca5e00a00169cc0e19fbc02aa839959985f267335d435c07f96e5e0edd0eadc6d39c98d5435fb5bbbdefc62c41834eadc5622ad942 - languageName: node - linkType: hard - -"string-width@npm:^1.0.2 || 2 || 3 || 4, string-width@npm:^4.1.0, string-width@npm:^4.2.0, string-width@npm:^4.2.3": - version: 4.2.3 - resolution: "string-width@npm:4.2.3" - dependencies: - emoji-regex: ^8.0.0 - is-fullwidth-code-point: ^3.0.0 - strip-ansi: ^6.0.1 - checksum: e52c10dc3fbfcd6c3a15f159f54a90024241d0f149cf8aed2982a2d801d2e64df0bf1dc351cf8e95c3319323f9f220c16e740b06faecd53e2462df1d2b5443fb - languageName: node - linkType: hard - -"string.prototype.trim@npm:^1.2.7": - version: 1.2.7 - resolution: "string.prototype.trim@npm:1.2.7" - dependencies: - call-bind: ^1.0.2 - define-properties: ^1.1.4 - es-abstract: ^1.20.4 - checksum: 05b7b2d6af63648e70e44c4a8d10d8cc457536df78b55b9d6230918bde75c5987f6b8604438c4c8652eb55e4fc9725d2912789eb4ec457d6995f3495af190c09 - languageName: node - linkType: hard - -"string.prototype.trimend@npm:^1.0.6": - version: 1.0.6 - resolution: "string.prototype.trimend@npm:1.0.6" - dependencies: - call-bind: ^1.0.2 - define-properties: ^1.1.4 - es-abstract: ^1.20.4 - checksum: 0fdc34645a639bd35179b5a08227a353b88dc089adf438f46be8a7c197fc3f22f8514c1c9be4629b3cd29c281582730a8cbbad6466c60f76b5f99cf2addb132e - languageName: node - linkType: hard - -"string.prototype.trimstart@npm:^1.0.6": - version: 1.0.6 - resolution: "string.prototype.trimstart@npm:1.0.6" - dependencies: - call-bind: ^1.0.2 - define-properties: ^1.1.4 - es-abstract: ^1.20.4 - checksum: 89080feef416621e6ef1279588994305477a7a91648d9436490d56010a1f7adc39167cddac7ce0b9884b8cdbef086987c4dcb2960209f2af8bac0d23ceff4f41 - languageName: node - linkType: hard - -"string_decoder@npm:^1.1.1": - version: 1.3.0 - resolution: "string_decoder@npm:1.3.0" - dependencies: - safe-buffer: ~5.2.0 - checksum: 8417646695a66e73aefc4420eb3b84cc9ffd89572861fe004e6aeb13c7bc00e2f616247505d2dbbef24247c372f70268f594af7126f43548565c68c117bdeb56 - languageName: node - linkType: hard - -"string_decoder@npm:~1.1.1": - version: 1.1.1 - resolution: "string_decoder@npm:1.1.1" - dependencies: - safe-buffer: ~5.1.0 - checksum: 9ab7e56f9d60a28f2be697419917c50cac19f3e8e6c28ef26ed5f4852289fe0de5d6997d29becf59028556f2c62983790c1d9ba1e2a3cc401768ca12d5183a5b - languageName: node - linkType: hard - -"strip-ansi@npm:^6.0.0, strip-ansi@npm:^6.0.1": - version: 6.0.1 - resolution: "strip-ansi@npm:6.0.1" - dependencies: - ansi-regex: ^5.0.1 - checksum: f3cd25890aef3ba6e1a74e20896c21a46f482e93df4a06567cebf2b57edabb15133f1f94e57434e0a958d61186087b1008e89c94875d019910a213181a14fc8c - languageName: node - linkType: hard - -"strip-bom@npm:^3.0.0": - version: 3.0.0 - resolution: "strip-bom@npm:3.0.0" - checksum: 8d50ff27b7ebe5ecc78f1fe1e00fcdff7af014e73cf724b46fb81ef889eeb1015fc5184b64e81a2efe002180f3ba431bdd77e300da5c6685d702780fbf0c8d5b - languageName: node - linkType: hard - -"strip-final-newline@npm:^2.0.0": - version: 2.0.0 - resolution: "strip-final-newline@npm:2.0.0" - checksum: 69412b5e25731e1938184b5d489c32e340605bb611d6140344abc3421b7f3c6f9984b21dff296dfcf056681b82caa3bb4cc996a965ce37bcfad663e92eae9c64 - languageName: node - linkType: hard - -"strip-indent@npm:^3.0.0": - version: 3.0.0 - resolution: "strip-indent@npm:3.0.0" - dependencies: - min-indent: ^1.0.0 - checksum: 18f045d57d9d0d90cd16f72b2313d6364fd2cb4bf85b9f593523ad431c8720011a4d5f08b6591c9d580f446e78855c5334a30fb91aa1560f5d9f95ed1b4a0530 - languageName: node - linkType: hard - -"strip-indent@npm:^4.0.0": - version: 4.0.0 - resolution: "strip-indent@npm:4.0.0" - dependencies: - min-indent: ^1.0.1 - checksum: 06cbcd93da721c46bc13caeb1c00af93a9b18146a1c95927672d2decab6a25ad83662772417cea9317a2507fb143253ecc23c4415b64f5828cef9b638a744598 - languageName: node - linkType: hard - -"strip-json-comments@npm:^3.1.0, strip-json-comments@npm:^3.1.1": - version: 3.1.1 - resolution: "strip-json-comments@npm:3.1.1" - checksum: 492f73e27268f9b1c122733f28ecb0e7e8d8a531a6662efbd08e22cccb3f9475e90a1b82cab06a392f6afae6d2de636f977e231296400d0ec5304ba70f166443 - languageName: node - linkType: hard - -"strip-outer@npm:^1.0.1": - version: 1.0.1 - resolution: "strip-outer@npm:1.0.1" - dependencies: - escape-string-regexp: ^1.0.2 - checksum: f8d65d33ca2b49aabc66bb41d689dda7b8b9959d320e3a40a2ef4d7079ff2f67ffb72db43f179f48dbf9495c2e33742863feab7a584d180fa62505439162c191 - languageName: node - linkType: hard - -"sumchecker@npm:^3.0.1": - version: 3.0.1 - resolution: "sumchecker@npm:3.0.1" - dependencies: - debug: ^4.1.0 - checksum: 31ba7a62c889236b5b07f75b5c250d481158a1ca061b8f234fca0457bdbe48a20e5011c12c715343dc577e111463dc3d9e721b98015a445a2a88c35e0c9f0f91 - languageName: node - linkType: hard - -"supports-color@npm:^5.3.0": - version: 5.5.0 - resolution: "supports-color@npm:5.5.0" - dependencies: - has-flag: ^3.0.0 - checksum: 95f6f4ba5afdf92f495b5a912d4abee8dcba766ae719b975c56c084f5004845f6f5a5f7769f52d53f40e21952a6d87411bafe34af4a01e65f9926002e38e1dac - languageName: node - linkType: hard - -"supports-color@npm:^7.0.0, supports-color@npm:^7.1.0": - version: 7.2.0 - resolution: "supports-color@npm:7.2.0" - dependencies: - has-flag: ^4.0.0 - checksum: 3dda818de06ebbe5b9653e07842d9479f3555ebc77e9a0280caf5a14fb877ffee9ed57007c3b78f5a6324b8dbeec648d9e97a24e2ed9fdb81ddc69ea07100f4a - languageName: node - linkType: hard - -"supports-hyperlinks@npm:^2.0.0": - version: 2.3.0 - resolution: "supports-hyperlinks@npm:2.3.0" - dependencies: - has-flag: ^4.0.0 - supports-color: ^7.0.0 - checksum: 9ee0de3c8ce919d453511b2b1588a8205bd429d98af94a01df87411391010fe22ca463f268c84b2ce2abad019dfff8452aa02806eeb5c905a8d7ad5c4f4c52b8 - languageName: node - linkType: hard - -"supports-preserve-symlinks-flag@npm:^1.0.0": - version: 1.0.0 - resolution: "supports-preserve-symlinks-flag@npm:1.0.0" - checksum: 53b1e247e68e05db7b3808b99b892bd36fb096e6fba213a06da7fab22045e97597db425c724f2bbd6c99a3c295e1e73f3e4de78592289f38431049e1277ca0ae - languageName: node - linkType: hard - -"tapable@npm:^0.1.8": - version: 0.1.10 - resolution: "tapable@npm:0.1.10" - checksum: fe02f5f4ce696b44c0c2d1176e41427a2fa54c2d59e80a2d16d9c8bab308c2603c3c78327a58b71e5a57abd427ddc54698736201039cc4f3d5d8b9c37b7940bb - languageName: node - linkType: hard - -"tar@npm:^6.1.11, tar@npm:^6.1.2": - version: 6.1.13 - resolution: "tar@npm:6.1.13" - dependencies: - chownr: ^2.0.0 - fs-minipass: ^2.0.0 - minipass: ^4.0.0 - minizlib: ^2.1.1 - mkdirp: ^1.0.3 - yallist: ^4.0.0 - checksum: 8a278bed123aa9f53549b256a36b719e317c8b96fe86a63406f3c62887f78267cea9b22dc6f7007009738509800d4a4dccc444abd71d762287c90f35b002eb1c - languageName: node - linkType: hard - -"temp-file@npm:^3.4.0": - version: 3.4.0 - resolution: "temp-file@npm:3.4.0" - dependencies: - async-exit-hook: ^2.0.1 - fs-extra: ^10.0.0 - checksum: 8e2b90321c9d865ad3e9e613cc524c9a9e22cd7820d3c8378840a01ab720116f4de4d340bbca6a50a9562b37f8ce614451fdb02dc2f993b4f9866cf81840b3cb - languageName: node - linkType: hard - -"text-table@npm:^0.2.0": - version: 0.2.0 - resolution: "text-table@npm:0.2.0" - checksum: b6937a38c80c7f84d9c11dd75e49d5c44f71d95e810a3250bd1f1797fc7117c57698204adf676b71497acc205d769d65c16ae8fa10afad832ae1322630aef10a - languageName: node - linkType: hard - -"through@npm:2, through@npm:~2.3, through@npm:~2.3.1": - version: 2.3.8 - resolution: "through@npm:2.3.8" - checksum: a38c3e059853c494af95d50c072b83f8b676a9ba2818dcc5b108ef252230735c54e0185437618596c790bbba8fcdaef5b290405981ffa09dce67b1f1bf190cbd - languageName: node - linkType: hard - -"tldts-core@npm:^5.7.112": - version: 5.7.112 - resolution: "tldts-core@npm:5.7.112" - checksum: e86b1dd29a5fdb18b33b3fb49fc11778c11229adf83cc73d360ef0481d52309b91c8daa9aa6e5cf56540391a49b13c02326eb5311e869bdc66bb952e86b1e2be - languageName: node - linkType: hard - -"tldts-experimental@npm:^5.6.21": - version: 5.7.112 - resolution: "tldts-experimental@npm:5.7.112" - dependencies: - tldts-core: ^5.7.112 - checksum: efc006303ff57ebeb7e1203e26e69d3595fe971401089d1158c4a7885ec660f7f44e8f7396eaedf43e70f0c8d818bc6e1f069d946ec790546fa2719ac59df6ed - languageName: node - linkType: hard - -"tmp-promise@npm:^3.0.2": - version: 3.0.3 - resolution: "tmp-promise@npm:3.0.3" - dependencies: - tmp: ^0.2.0 - checksum: f854f5307dcee6455927ec3da9398f139897faf715c5c6dcee6d9471ae85136983ea06662eba2edf2533bdcb0fca66d16648e79e14381e30c7fb20be9c1aa62c - languageName: node - linkType: hard - -"tmp@npm:^0.2.0": - version: 0.2.1 - resolution: "tmp@npm:0.2.1" - dependencies: - rimraf: ^3.0.0 - checksum: 8b1214654182575124498c87ca986ac53dc76ff36e8f0e0b67139a8d221eaecfdec108c0e6ec54d76f49f1f72ab9325500b246f562b926f85bcdfca8bf35df9e - languageName: node - linkType: hard - -"to-absolute-glob@npm:^2.0.2": - version: 2.0.2 - resolution: "to-absolute-glob@npm:2.0.2" - dependencies: - is-absolute: ^1.0.0 - is-negated-glob: ^1.0.0 - checksum: 0a8bef172909e43d711bfd33792643f2eec35b9109bde927dabfd231e6ad643b7a657f306c93c6e7b89f71d3de74ac94060fe9637bca8c37b036523993664323 - languageName: node - linkType: hard - -"to-regex-range@npm:^5.0.1": - version: 5.0.1 - resolution: "to-regex-range@npm:5.0.1" - dependencies: - is-number: ^7.0.0 - checksum: f76fa01b3d5be85db6a2a143e24df9f60dd047d151062d0ba3df62953f2f697b16fe5dad9b0ac6191c7efc7b1d9dcaa4b768174b7b29da89d4428e64bc0a20ed - languageName: node - linkType: hard - -"tr46@npm:~0.0.3": - version: 0.0.3 - resolution: "tr46@npm:0.0.3" - checksum: 726321c5eaf41b5002e17ffbd1fb7245999a073e8979085dacd47c4b4e8068ff5777142fc6726d6ca1fd2ff16921b48788b87225cbc57c72636f6efa8efbffe3 - languageName: node - linkType: hard - -"trim-newlines@npm:^4.0.2": - version: 4.1.1 - resolution: "trim-newlines@npm:4.1.1" - checksum: 5b09f8e329e8f33c1111ef26906332ba7ba7248cde3e26fc054bb3d69f2858bf5feedca9559c572ff91f33e52977c28e0d41c387df6a02a633cbb8c2d8238627 - languageName: node - linkType: hard - -"trim-repeated@npm:^1.0.0": - version: 1.0.0 - resolution: "trim-repeated@npm:1.0.0" - dependencies: - escape-string-regexp: ^1.0.2 - checksum: e25c235305b82c43f1d64a67a71226c406b00281755e4c2c4f3b1d0b09c687a535dd3c4483327f949f28bb89dc400a0bc5e5b749054f4b99f49ebfe48ba36496 - languageName: node - linkType: hard - -"truncate-utf8-bytes@npm:^1.0.0": - version: 1.0.2 - resolution: "truncate-utf8-bytes@npm:1.0.2" - dependencies: - utf8-byte-length: ^1.0.1 - checksum: ad097314709ea98444ad9c80c03aac8da805b894f37ceb5685c49ad297483afe3a5ec9572ebcaff699dda72b6cd447a2ba2a3fd10e96c2628cd16d94abeb328a - languageName: node - linkType: hard - -"tsconfig-paths@npm:^3.14.1": - version: 3.14.2 - resolution: "tsconfig-paths@npm:3.14.2" - dependencies: - "@types/json5": ^0.0.29 - json5: ^1.0.2 - minimist: ^1.2.6 - strip-bom: ^3.0.0 - checksum: a6162eaa1aed680537f93621b82399c7856afd10ec299867b13a0675e981acac4e0ec00896860480efc59fc10fd0b16fdc928c0b885865b52be62cadac692447 - languageName: node - linkType: hard - -"tslib@npm:^1.8.1": - version: 1.14.1 - resolution: "tslib@npm:1.14.1" - checksum: dbe628ef87f66691d5d2959b3e41b9ca0045c3ee3c7c7b906cc1e328b39f199bb1ad9e671c39025bd56122ac57dfbf7385a94843b1cc07c60a4db74795829acd - languageName: node - linkType: hard - -"tslib@npm:^2.1.0, tslib@npm:^2.4.0, tslib@npm:^2.5.0": - version: 2.5.0 - resolution: "tslib@npm:2.5.0" - checksum: ae3ed5f9ce29932d049908ebfdf21b3a003a85653a9a140d614da6b767a93ef94f460e52c3d787f0e4f383546981713f165037dc2274df212ea9f8a4541004e1 - languageName: node - linkType: hard - -"tsutils@npm:^3.21.0": - version: 3.21.0 - resolution: "tsutils@npm:3.21.0" - dependencies: - tslib: ^1.8.1 - peerDependencies: - typescript: ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" - checksum: 1843f4c1b2e0f975e08c4c21caa4af4f7f65a12ac1b81b3b8489366826259323feb3fc7a243123453d2d1a02314205a7634e048d4a8009921da19f99755cdc48 - languageName: node - linkType: hard - -"type-check@npm:^0.4.0, type-check@npm:~0.4.0": - version: 0.4.0 - resolution: "type-check@npm:0.4.0" - dependencies: - prelude-ls: ^1.2.1 - checksum: ec688ebfc9c45d0c30412e41ca9c0cdbd704580eb3a9ccf07b9b576094d7b86a012baebc95681999dd38f4f444afd28504cb3a89f2ef16b31d4ab61a0739025a - languageName: node - linkType: hard - -"type-fest@npm:^0.13.1": - version: 0.13.1 - resolution: "type-fest@npm:0.13.1" - checksum: e6bf2e3c449f27d4ef5d56faf8b86feafbc3aec3025fc9a5fbe2db0a2587c44714521f9c30d8516a833c8c506d6263f5cc11267522b10c6ccdb6cc55b0a9d1c4 - languageName: node - linkType: hard - -"type-fest@npm:^0.20.2": - version: 0.20.2 - resolution: "type-fest@npm:0.20.2" - checksum: 4fb3272df21ad1c552486f8a2f8e115c09a521ad7a8db3d56d53718d0c907b62c6e9141ba5f584af3f6830d0872c521357e512381f24f7c44acae583ad517d73 - languageName: node - linkType: hard - -"type-fest@npm:^0.21.3": - version: 0.21.3 - resolution: "type-fest@npm:0.21.3" - checksum: e6b32a3b3877f04339bae01c193b273c62ba7bfc9e325b8703c4ee1b32dc8fe4ef5dfa54bf78265e069f7667d058e360ae0f37be5af9f153b22382cd55a9afe0 - languageName: node - linkType: hard - -"type-fest@npm:^0.6.0": - version: 0.6.0 - resolution: "type-fest@npm:0.6.0" - checksum: b2188e6e4b21557f6e92960ec496d28a51d68658018cba8b597bd3ef757721d1db309f120ae987abeeda874511d14b776157ff809f23c6d1ce8f83b9b2b7d60f - languageName: node - linkType: hard - -"type-fest@npm:^0.8.1": - version: 0.8.1 - resolution: "type-fest@npm:0.8.1" - checksum: d61c4b2eba24009033ae4500d7d818a94fd6d1b481a8111612ee141400d5f1db46f199c014766b9fa9b31a6a7374d96fc748c6d688a78a3ce5a33123839becb7 - languageName: node - linkType: hard - -"type-fest@npm:^1.0.1, type-fest@npm:^1.2.1, type-fest@npm:^1.2.2": - version: 1.4.0 - resolution: "type-fest@npm:1.4.0" - checksum: b011c3388665b097ae6a109a437a04d6f61d81b7357f74cbcb02246f2f5bd72b888ae33631b99871388122ba0a87f4ff1c94078e7119ff22c70e52c0ff828201 - languageName: node - linkType: hard - -"type-fest@npm:^2.0.0, type-fest@npm:^2.13.0, type-fest@npm:^2.17.0, type-fest@npm:^2.5.0": - version: 2.19.0 - resolution: "type-fest@npm:2.19.0" - checksum: a4ef07ece297c9fba78fc1bd6d85dff4472fe043ede98bd4710d2615d15776902b595abf62bd78339ed6278f021235fb28a96361f8be86ed754f778973a0d278 - languageName: node - linkType: hard - -"type-fest@npm:^3.1.0": - version: 3.8.0 - resolution: "type-fest@npm:3.8.0" - checksum: f9a9ef00378dddd6af2be5cbb67ce4c3a61f6696c5f3ae88815c98266865766118343d928faec8a0efc012efe1d080f59bf62d8fdc382bf285f45d02dbc8fb66 - languageName: node - linkType: hard - -"typed-array-length@npm:^1.0.4": - version: 1.0.4 - resolution: "typed-array-length@npm:1.0.4" - dependencies: - call-bind: ^1.0.2 - for-each: ^0.3.3 - is-typed-array: ^1.1.9 - checksum: 2228febc93c7feff142b8c96a58d4a0d7623ecde6c7a24b2b98eb3170e99f7c7eff8c114f9b283085cd59dcd2bd43aadf20e25bba4b034a53c5bb292f71f8956 - languageName: node - linkType: hard - -"typed-emitter@npm:^2.1.0": - version: 2.1.0 - resolution: "typed-emitter@npm:2.1.0" - dependencies: - rxjs: "*" - dependenciesMeta: - rxjs: - optional: true - checksum: 95821a9e05784b972cc9d152891fd12a56cb4b1a7c57e768c02bea6a8984da7aff8f19404a7b69eea11fae2a3b6c0c510a4c510f575f50162c759ae9059f2520 - languageName: node - linkType: hard - -"typescript@npm:^4.9.3": - version: 4.9.5 - resolution: "typescript@npm:4.9.5" - bin: - tsc: bin/tsc - tsserver: bin/tsserver - checksum: ee000bc26848147ad423b581bd250075662a354d84f0e06eb76d3b892328d8d4440b7487b5a83e851b12b255f55d71835b008a66cbf8f255a11e4400159237db - languageName: node - linkType: hard - -"typescript@patch:typescript@^4.9.3#~builtin": - version: 4.9.5 - resolution: "typescript@patch:typescript@npm%3A4.9.5#~builtin::version=4.9.5&hash=23ec76" - bin: - tsc: bin/tsc - tsserver: bin/tsserver - checksum: ab417a2f398380c90a6cf5a5f74badd17866adf57f1165617d6a551f059c3ba0a3e4da0d147b3ac5681db9ac76a303c5876394b13b3de75fdd5b1eaa06181c9d - languageName: node - linkType: hard - -"uglify-js@npm:^3.1.4": - version: 3.17.4 - resolution: "uglify-js@npm:3.17.4" - bin: - uglifyjs: bin/uglifyjs - checksum: 7b3897df38b6fc7d7d9f4dcd658599d81aa2b1fb0d074829dd4e5290f7318dbca1f4af2f45acb833b95b1fe0ed4698662ab61b87e94328eb4c0a0d3435baf924 - languageName: node - linkType: hard - -"uhyphen@npm:^0.2.0": - version: 0.2.0 - resolution: "uhyphen@npm:0.2.0" - checksum: b946e2c17989f50412d7cc07521a199a1edc52e0320813c06ef5eee21570cd46bbfeb98e82288f21150144a3ef9d4e99395533ab1c918030e5224f3e247cbe57 - languageName: node - linkType: hard - -"unbox-primitive@npm:^1.0.2": - version: 1.0.2 - resolution: "unbox-primitive@npm:1.0.2" - dependencies: - call-bind: ^1.0.2 - has-bigints: ^1.0.2 - has-symbols: ^1.0.3 - which-boxed-primitive: ^1.0.2 - checksum: b7a1cf5862b5e4b5deb091672ffa579aa274f648410009c81cca63fed3b62b610c4f3b773f912ce545bb4e31edc3138975b5bc777fc6e4817dca51affb6380e9 - languageName: node - linkType: hard - -"unc-path-regex@npm:^0.1.2": - version: 0.1.2 - resolution: "unc-path-regex@npm:0.1.2" - checksum: a05fa2006bf4606051c10fc7968f08ce7b28fa646befafa282813aeb1ac1a56f65cb1b577ca7851af2726198d59475bb49b11776036257b843eaacee2860a4ec - languageName: node - linkType: hard - -"undici@npm:^5.19.1": - version: 5.21.2 - resolution: "undici@npm:5.21.2" - dependencies: - busboy: ^1.6.0 - checksum: baceaa9e610966631e86ad2869b657556dd465438eed55e8079cec2a306ecbeecfde2d6e37e43baf96a4c59588ebef50476131e96e018dcc0a7f5db7e6a06c85 - languageName: node - linkType: hard - -"unique-filename@npm:^2.0.0": - version: 2.0.1 - resolution: "unique-filename@npm:2.0.1" - dependencies: - unique-slug: ^3.0.0 - checksum: 807acf3381aff319086b64dc7125a9a37c09c44af7620bd4f7f3247fcd5565660ac12d8b80534dcbfd067e6fe88a67e621386dd796a8af828d1337a8420a255f - languageName: node - linkType: hard - -"unique-slug@npm:^3.0.0": - version: 3.0.0 - resolution: "unique-slug@npm:3.0.0" - dependencies: - imurmurhash: ^0.1.4 - checksum: 49f8d915ba7f0101801b922062ee46b7953256c93ceca74303bd8e6413ae10aa7e8216556b54dc5382895e8221d04f1efaf75f945c2e4a515b4139f77aa6640c - languageName: node - linkType: hard - -"universalify@npm:^0.1.0": - version: 0.1.2 - resolution: "universalify@npm:0.1.2" - checksum: 40cdc60f6e61070fe658ca36016a8f4ec216b29bf04a55dce14e3710cc84c7448538ef4dad3728d0bfe29975ccd7bfb5f414c45e7b78883567fb31b246f02dff - languageName: node - linkType: hard - -"universalify@npm:^2.0.0": - version: 2.0.0 - resolution: "universalify@npm:2.0.0" - checksum: 2406a4edf4a8830aa6813278bab1f953a8e40f2f63a37873ffa9a3bc8f9745d06cc8e88f3572cb899b7e509013f7f6fcc3e37e8a6d914167a5381d8440518c44 - languageName: node - linkType: hard - -"unzip-crx-3@npm:^0.2.0": - version: 0.2.0 - resolution: "unzip-crx-3@npm:0.2.0" - dependencies: - jszip: ^3.1.0 - mkdirp: ^0.5.1 - yaku: ^0.16.6 - checksum: 3988dd19feac161953862835ad7df2c0c155dd9aad6e48c36abc093e810036dd1877d81ad6b7825e788c1d05f4eabf99e2874c9104b95613ead500abb9664b40 - languageName: node - linkType: hard - -"uri-js@npm:^4.2.2": - version: 4.4.1 - resolution: "uri-js@npm:4.4.1" - dependencies: - punycode: ^2.1.0 - checksum: 7167432de6817fe8e9e0c9684f1d2de2bb688c94388f7569f7dbdb1587c9f4ca2a77962f134ec90be0cc4d004c939ff0d05acc9f34a0db39a3c797dada262633 - languageName: node - linkType: hard - -"url-match-patterns@npm:^0.2.0": - version: 0.2.0 - resolution: "url-match-patterns@npm:0.2.0" - dependencies: - lodash: ^4.3.0 - checksum: 198d06724d052562232953335b8f61c2405993f422725ffd08ccd00d9f38e22637491bc746bd81e8ab2354e1ae7bbe8b13430017658050a984afabcf39562d47 - languageName: node - linkType: hard - -"url-or-path@npm:2.1.0": - version: 2.1.0 - resolution: "url-or-path@npm:2.1.0" - checksum: 8bbc00439fe7bc4ce8c3cb92d80a5b8b4925d4709a210116c6996cf17135e361b97233f7abbd7dd09ea00684fc0043c8ae9abfd62fc20b648419bc2cd01bc219 - languageName: node - linkType: hard - -"utf8-byte-length@npm:^1.0.1": - version: 1.0.4 - resolution: "utf8-byte-length@npm:1.0.4" - checksum: f188ca076ec094d58e7009fcc32623c5830c7f0f3e15802bfa4fdd1e759454a481fc4ac05e0fa83b7736e77af628a9ee0e57dcc89683d688fde3811473e42143 - languageName: node - linkType: hard - -"util-deprecate@npm:^1.0.1, util-deprecate@npm:~1.0.1": - version: 1.0.2 - resolution: "util-deprecate@npm:1.0.2" - checksum: 474acf1146cb2701fe3b074892217553dfcf9a031280919ba1b8d651a068c9b15d863b7303cb15bd00a862b498e6cf4ad7b4a08fb134edd5a6f7641681cb54a2 - languageName: node - linkType: hard - -"uuid@npm:^3.3.2": - version: 3.4.0 - resolution: "uuid@npm:3.4.0" - bin: - uuid: ./bin/uuid - checksum: 58de2feed61c59060b40f8203c0e4ed7fd6f99d42534a499f1741218a1dd0c129f4aa1de797bcf822c8ea5da7e4137aa3673431a96dae729047f7aca7b27866f - languageName: node - linkType: hard - -"validate-npm-package-license@npm:^3.0.1, validate-npm-package-license@npm:^3.0.4": - version: 3.0.4 - resolution: "validate-npm-package-license@npm:3.0.4" - dependencies: - spdx-correct: ^3.0.0 - spdx-expression-parse: ^3.0.0 - checksum: 35703ac889d419cf2aceef63daeadbe4e77227c39ab6287eeb6c1b36a746b364f50ba22e88591f5d017bc54685d8137bc2d328d0a896e4d3fd22093c0f32a9ad - languageName: node - linkType: hard - -"verror@npm:^1.10.0": - version: 1.10.1 - resolution: "verror@npm:1.10.1" - dependencies: - assert-plus: ^1.0.0 - core-util-is: 1.0.2 - extsprintf: ^1.2.0 - checksum: 690a8d6ad5a4001672290e9719e3107c86269bc45fe19f844758eecf502e59f8aa9631b19b839f6d3dea562334884d22d1eb95ae7c863032075a9212c889e116 - languageName: node - linkType: hard - -"vudio@npm:^2.1.1": - version: 2.1.1 - resolution: "vudio@npm:2.1.1" - checksum: f9d7ad1f575838cfdc2d5df44014e96216eeba3c18a58ba7af4a866531364a95de8a85ed9660f6690fa3981b0710630717f7686dbff1f9d72053d5af1d22383e - languageName: node - linkType: hard - -"webidl-conversions@npm:^3.0.0": - version: 3.0.1 - resolution: "webidl-conversions@npm:3.0.1" - checksum: c92a0a6ab95314bde9c32e1d0a6dfac83b578f8fa5f21e675bc2706ed6981bc26b7eb7e6a1fab158e5ce4adf9caa4a0aee49a52505d4d13c7be545f15021b17c - languageName: node - linkType: hard - -"whatwg-url@npm:^5.0.0": - version: 5.0.0 - resolution: "whatwg-url@npm:5.0.0" - dependencies: - tr46: ~0.0.3 - webidl-conversions: ^3.0.0 - checksum: b8daed4ad3356cc4899048a15b2c143a9aed0dfae1f611ebd55073310c7b910f522ad75d727346ad64203d7e6c79ef25eafd465f4d12775ca44b90fa82ed9e2c - languageName: node - linkType: hard - -"which-boxed-primitive@npm:^1.0.2": - version: 1.0.2 - resolution: "which-boxed-primitive@npm:1.0.2" - dependencies: - is-bigint: ^1.0.1 - is-boolean-object: ^1.1.0 - is-number-object: ^1.0.4 - is-string: ^1.0.5 - is-symbol: ^1.0.3 - checksum: 53ce774c7379071729533922adcca47220228405e1895f26673bbd71bdf7fb09bee38c1d6399395927c6289476b5ae0629863427fd151491b71c4b6cb04f3a5e - languageName: node - linkType: hard - -"which-typed-array@npm:^1.1.9": - version: 1.1.9 - resolution: "which-typed-array@npm:1.1.9" - dependencies: - available-typed-arrays: ^1.0.5 - call-bind: ^1.0.2 - for-each: ^0.3.3 - gopd: ^1.0.1 - has-tostringtag: ^1.0.0 - is-typed-array: ^1.1.10 - checksum: fe0178ca44c57699ca2c0e657b64eaa8d2db2372a4e2851184f568f98c478ae3dc3fdb5f7e46c384487046b0cf9e23241423242b277e03e8ba3dabc7c84c98ef - languageName: node - linkType: hard - -"which@npm:^2.0.1, which@npm:^2.0.2": - version: 2.0.2 - resolution: "which@npm:2.0.2" - dependencies: - isexe: ^2.0.0 - bin: - node-which: ./bin/node-which - checksum: 1a5c563d3c1b52d5f893c8b61afe11abc3bab4afac492e8da5bde69d550de701cf9806235f20a47b5c8fa8a1d6a9135841de2596535e998027a54589000e66d1 - languageName: node - linkType: hard - -"wide-align@npm:^1.1.5": - version: 1.1.5 - resolution: "wide-align@npm:1.1.5" - dependencies: - string-width: ^1.0.2 || 2 || 3 || 4 - checksum: d5fc37cd561f9daee3c80e03b92ed3e84d80dde3365a8767263d03dacfc8fa06b065ffe1df00d8c2a09f731482fcacae745abfbb478d4af36d0a891fad4834d3 - languageName: node - linkType: hard - -"word-wrap@npm:^1.2.3": - version: 1.2.3 - resolution: "word-wrap@npm:1.2.3" - checksum: 30b48f91fcf12106ed3186ae4fa86a6a1842416df425be7b60485de14bec665a54a68e4b5156647dec3a70f25e84d270ca8bc8cd23182ed095f5c7206a938c1f - languageName: node - linkType: hard - -"wordwrap@npm:^1.0.0": - version: 1.0.0 - resolution: "wordwrap@npm:1.0.0" - checksum: 2a44b2788165d0a3de71fd517d4880a8e20ea3a82c080ce46e294f0b68b69a2e49cff5f99c600e275c698a90d12c5ea32aff06c311f0db2eb3f1201f3e7b2a04 - languageName: node - linkType: hard - -"wrap-ansi@npm:^7.0.0": - version: 7.0.0 - resolution: "wrap-ansi@npm:7.0.0" - dependencies: - ansi-styles: ^4.0.0 - string-width: ^4.1.0 - strip-ansi: ^6.0.0 - checksum: a790b846fd4505de962ba728a21aaeda189b8ee1c7568ca5e817d85930e06ef8d1689d49dbf0e881e8ef84436af3a88bc49115c2e2788d841ff1b8b5b51a608b - languageName: node - linkType: hard - -"wrappy@npm:1": - version: 1.0.2 - resolution: "wrappy@npm:1.0.2" - checksum: 159da4805f7e84a3d003d8841557196034155008f817172d4e986bd591f74aa82aa7db55929a54222309e01079a65a92a9e6414da5a6aa4b01ee44a511ac3ee5 - languageName: node - linkType: hard - -"ws@npm:^8.13.0": - version: 8.13.0 - resolution: "ws@npm:8.13.0" - peerDependencies: - bufferutil: ^4.0.1 - utf-8-validate: ">=5.0.2" - peerDependenciesMeta: - bufferutil: - optional: true - utf-8-validate: - optional: true - checksum: 53e991bbf928faf5dc6efac9b8eb9ab6497c69feeb94f963d648b7a3530a720b19ec2e0ec037344257e05a4f35bd9ad04d9de6f289615ffb133282031b18c61c - languageName: node - linkType: hard - -"xml2js@npm:^0.5.0": - version: 0.5.0 - resolution: "xml2js@npm:0.5.0" - dependencies: - sax: ">=0.6.0" - xmlbuilder: ~11.0.0 - checksum: 1aa71d62e5bc2d89138e3929b9ea46459157727759cbc62ef99484b778641c0cd21fb637696c052d901a22f82d092a3e740a16b4ce218e81ac59b933535124ea - languageName: node - linkType: hard - -"xmlbuilder@npm:>=11.0.1, xmlbuilder@npm:^15.1.1": - version: 15.1.1 - resolution: "xmlbuilder@npm:15.1.1" - checksum: 14f7302402e28d1f32823583d121594a9dca36408d40320b33f598bd589ca5163a352d076489c9c64d2dc1da19a790926a07bf4191275330d4de2b0d85bb1843 - languageName: node - linkType: hard - -"xmlbuilder@npm:~11.0.0": - version: 11.0.1 - resolution: "xmlbuilder@npm:11.0.1" - checksum: 7152695e16f1a9976658215abab27e55d08b1b97bca901d58b048d2b6e106b5af31efccbdecf9b07af37c8377d8e7e821b494af10b3a68b0ff4ae60331b415b0 - languageName: node - linkType: hard - -"xo@npm:^0.53.1": - version: 0.53.1 - resolution: "xo@npm:0.53.1" - dependencies: - "@eslint/eslintrc": ^1.3.3 - "@typescript-eslint/eslint-plugin": ^5.43.0 - "@typescript-eslint/parser": ^5.43.0 - arrify: ^3.0.0 - cosmiconfig: ^7.1.0 - define-lazy-prop: ^3.0.0 - eslint: ^8.27.0 - eslint-config-prettier: ^8.5.0 - eslint-config-xo: ^0.43.1 - eslint-config-xo-typescript: ^0.55.0 - eslint-formatter-pretty: ^4.1.0 - eslint-import-resolver-webpack: ^0.13.2 - eslint-plugin-ava: ^13.2.0 - eslint-plugin-eslint-comments: ^3.2.0 - eslint-plugin-import: ^2.26.0 - eslint-plugin-n: ^15.5.1 - eslint-plugin-no-use-extend-native: ^0.5.0 - eslint-plugin-prettier: ^4.2.1 - eslint-plugin-unicorn: ^44.0.2 - esm-utils: ^4.1.0 - find-cache-dir: ^4.0.0 - find-up: ^6.3.0 - get-stdin: ^9.0.0 - globby: ^13.1.2 - imurmurhash: ^0.1.4 - json-stable-stringify-without-jsonify: ^1.0.1 - json5: ^2.2.1 - lodash-es: ^4.17.21 - meow: ^11.0.0 - micromatch: ^4.0.5 - open-editor: ^4.0.0 - prettier: ^2.7.1 - semver: ^7.3.8 - slash: ^5.0.0 - to-absolute-glob: ^2.0.2 - typescript: ^4.9.3 - bin: - xo: cli.js - checksum: 48aa8cdcbb2210f3d786a573484db986e3d4d8b096d46dd5414942fe149f8c426e9bcdb400c48b60a8fc96f747f1e073670bb49b24ea5c3e46d973f7f8ce294a - languageName: node - linkType: hard - -"y18n@npm:^5.0.5": - version: 5.0.8 - resolution: "y18n@npm:5.0.8" - checksum: 54f0fb95621ee60898a38c572c515659e51cc9d9f787fb109cef6fde4befbe1c4602dc999d30110feee37456ad0f1660fa2edcfde6a9a740f86a290999550d30 - languageName: node - linkType: hard - -"yaku@npm:^0.16.6": - version: 0.16.7 - resolution: "yaku@npm:0.16.7" - checksum: 000cf744ead4cc72ef7d04faf09a2d18b63efab83cede2ed0f2911a86fd5da8638a4fbae9f359956c1ed9c1179fe012404b1ec104972e4c204f6550ff1a1454b - languageName: node - linkType: hard - -"yallist@npm:^4.0.0": - version: 4.0.0 - resolution: "yallist@npm:4.0.0" - checksum: 343617202af32df2a15a3be36a5a8c0c8545208f3d3dfbc6bb7c3e3b7e8c6f8e7485432e4f3b88da3031a6e20afa7c711eded32ddfb122896ac5d914e75848d5 - languageName: node - linkType: hard - -"yaml@npm:^1.10.0": - version: 1.10.2 - resolution: "yaml@npm:1.10.2" - checksum: ce4ada136e8a78a0b08dc10b4b900936912d15de59905b2bf415b4d33c63df1d555d23acb2a41b23cf9fb5da41c256441afca3d6509de7247daa062fd2c5ea5f - languageName: node - linkType: hard - -"yargs-parser@npm:^20.2.9": - version: 20.2.9 - resolution: "yargs-parser@npm:20.2.9" - checksum: 8bb69015f2b0ff9e17b2c8e6bfe224ab463dd00ca211eece72a4cd8a906224d2703fb8a326d36fdd0e68701e201b2a60ed7cf81ce0fd9b3799f9fe7745977ae3 - languageName: node - linkType: hard - -"yargs-parser@npm:^21.1.1": - version: 21.1.1 - resolution: "yargs-parser@npm:21.1.1" - checksum: ed2d96a616a9e3e1cc7d204c62ecc61f7aaab633dcbfab2c6df50f7f87b393993fe6640d017759fe112d0cb1e0119f2b4150a87305cc873fd90831c6a58ccf1c - languageName: node - linkType: hard - -"yargs@npm:^17.5.1": - version: 17.7.1 - resolution: "yargs@npm:17.7.1" - dependencies: - cliui: ^8.0.1 - escalade: ^3.1.1 - get-caller-file: ^2.0.5 - require-directory: ^2.1.1 - string-width: ^4.2.3 - y18n: ^5.0.5 - yargs-parser: ^21.1.1 - checksum: 3d8a43c336a4942bc68080768664aca85c7bd406f018bad362fd255c41c8f4e650277f42fd65d543fce99e084124ddafee7bbfc1a5c6a8fda4cec78609dcf8d4 - languageName: node - linkType: hard - -"yauzl@npm:^2.10.0": - version: 2.10.0 - resolution: "yauzl@npm:2.10.0" - dependencies: - buffer-crc32: ~0.2.3 - fd-slicer: ~1.1.0 - checksum: 7f21fe0bbad6e2cb130044a5d1d0d5a0e5bf3d8d4f8c4e6ee12163ce798fee3de7388d22a7a0907f563ac5f9d40f8699a223d3d5c1718da90b0156da6904022b - languageName: node - linkType: hard - -"yocto-queue@npm:^0.1.0": - version: 0.1.0 - resolution: "yocto-queue@npm:0.1.0" - checksum: f77b3d8d00310def622123df93d4ee654fc6a0096182af8bd60679ddcdfb3474c56c6c7190817c84a2785648cdee9d721c0154eb45698c62176c322fb46fc700 - languageName: node - linkType: hard - -"yocto-queue@npm:^1.0.0": - version: 1.0.0 - resolution: "yocto-queue@npm:1.0.0" - checksum: 2cac84540f65c64ccc1683c267edce396b26b1e931aa429660aefac8fbe0188167b7aee815a3c22fa59a28a58d898d1a2b1825048f834d8d629f4c2a5d443801 - languageName: node - linkType: hard - -"youtube-music@workspace:.": - version: 0.0.0-use.local - resolution: "youtube-music@workspace:." - dependencies: - "@cliqz/adblocker-electron": ^1.26.5 - "@ffmpeg/core": ^0.11.0 - "@ffmpeg/ffmpeg": ^0.11.6 - "@foobar404/wave": ^2.0.4 - "@playwright/test": ^1.29.2 - "@xhayper/discord-rpc": ^1.0.16 - async-mutex: ^0.4.0 - auto-changelog: ^2.4.0 - browser-id3-writer: ^5.0.0 - butterchurn: ^2.6.7 - butterchurn-presets: ^2.4.7 - custom-electron-prompt: ^1.5.7 - custom-electron-titlebar: ^4.1.6 - del-cli: ^5.0.0 - electron: ^22.3.6 - electron-better-web-request: ^1.0.1 - electron-builder: ^23.6.0 - electron-debug: ^3.2.0 - electron-devtools-installer: ^3.2.0 - electron-is: ^3.0.0 - electron-localshortcut: ^3.2.1 - electron-store: ^8.1.0 - electron-unhandled: ^4.0.1 - electron-updater: ^5.3.0 - filenamify: ^4.3.0 - howler: ^2.2.3 - html-to-text: ^9.0.5 - keyboardevent-from-electron-accelerator: ^2.0.0 - keyboardevents-areequal: ^0.2.2 - md5: ^2.3.0 - mpris-service: ^2.1.2 - node-fetch: ^2.6.9 - node-gyp: ^9.3.1 - playwright: ^1.29.2 - simple-youtube-age-restriction-bypass: "https://gitpkg.now.sh/api/pkg.tgz?url=MiepHD/Simple-YouTube-Age-Restriction-Bypass&commit=v2.5.5" - vudio: ^2.1.1 - xo: ^0.53.1 - youtubei.js: ^4.3.0 - ytpl: ^2.3.0 - languageName: unknown - linkType: soft - -"youtubei.js@npm:^4.3.0": - version: 4.3.0 - resolution: "youtubei.js@npm:4.3.0" - dependencies: - jintr: ^1.0.0 - linkedom: ^0.14.12 - tslib: ^2.5.0 - undici: ^5.19.1 - checksum: c4fe9d01b46cf57fe8ef9ab71e43b77f3d1cffe303f2a5aa302305db7ba15bd3f511f60a9ee6e473e6429a0e529843bb19e2d456929eb6923cf04b62a83063bf - languageName: node - linkType: hard - -"ytpl@npm:^2.3.0": - version: 2.3.0 - resolution: "ytpl@npm:2.3.0" - dependencies: - miniget: ^4.2.2 - checksum: cec072c4e4b5e19930d498b0e4e69726538e95a452dc0686d4d7c865583f9ed14c33e526bbf1d54a75b7470490b4860eac814a697a98b3b89115ed1a0ea77a39 - languageName: node - linkType: hard diff --git a/youtube-music.css b/youtube-music.css index 79983bb7..686feb4f 100644 --- a/youtube-music.css +++ b/youtube-music.css @@ -4,53 +4,53 @@ /* Allow window dragging */ .center-content.ytmusic-nav-bar { - -webkit-user-select: none; - -webkit-app-region: drag; + -webkit-user-select: none; + -webkit-app-region: drag; } -.center-content.ytmusic-nav-bar > ytmusic-search-box{ - -webkit-app-region: no-drag; +.center-content.ytmusic-nav-bar > ytmusic-search-box { + -webkit-app-region: no-drag; } iron-icon, ytmusic-pivot-bar-item-renderer, .tab-title, a { - -webkit-app-region: no-drag; + -webkit-app-region: no-drag; } /* custom style for navbar */ ytmusic-app-layout { - --ytmusic-nav-bar-height: 90px; + --ytmusic-nav-bar-height: 90px; } ytmusic-search-box.ytmusic-nav-bar { - margin-top: 15px; + margin-top: 15px; } /* Blocking annoying elements */ ytmusic-mealbar-promo-renderer { - display: none !important; + display: none !important; } /* Disable Image Selection */ img { - -webkit-user-select: none; - user-select: none; + -webkit-user-select: none; + user-select: none; } /* Hide cast button which doesn't work */ ytmusic-cast-button { - display: none !important; + display: none !important; } /* Remove useless inaccessible button on top-right corner of the video player */ .ytp-chrome-top-buttons { - display: none !important; + display: none !important; } /* Make youtube-music logo un-draggable */ -ytmusic-nav-bar>div.left-content>a, -ytmusic-nav-bar>div.left-content>a>picture>img { - -webkit-user-drag: none; +ytmusic-nav-bar > div.left-content > a, +ytmusic-nav-bar > div.left-content > a > picture > img { + -webkit-user-drag: none; }