diff --git a/.eslintrc.js b/.eslintrc.js deleted file mode 100644 index eaf98f7..0000000 --- a/.eslintrc.js +++ /dev/null @@ -1,38 +0,0 @@ -module.exports = { - root: true, - env: { - node: true - }, - extends: [ - "plugin:vue/vue3-essential", - "eslint:recommended", - "@vue/typescript/recommended" - ], - parserOptions: { - ecmaVersion: 2020 - }, - rules: { - "no-console": process.env.NODE_ENV === "production" ? "warn" : "off", - "no-debugger": process.env.NODE_ENV === "production" ? "warn" : "off", - "no-unused-vars": "off", - "@typescript-eslint/no-unused-vars": [ - "error", - { "argsIgnorePattern": "^_" } - ] - }, - overrides: [ - { - files: [ - "**/__tests__/*.{j,t}s?(x)", - "**/tests/unit/**/*.spec.{j,t}s?(x)", - "*.js" - ], - rules: { - "@typescript-eslint/no-var-requires": "off", - }, - env: { - jest: true - } - } - ] -}; diff --git a/.gitignore b/.gitignore index 20128fc..75d5ca4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,5 @@ .DS_Store -node_modules +/node_modules /dist /crate/target/* /.log @@ -28,10 +28,3 @@ pnpm-debug.log* #Electron-builder output /dist_electron - -#Electron-builder config -electron-builder.yml - -#Window and session states -session.json -window.json diff --git a/.npmrc b/.npmrc new file mode 100644 index 0000000..936e781 --- /dev/null +++ b/.npmrc @@ -0,0 +1,2 @@ +@crimata:registry=https://gitlab.com/api/v4/projects/28849281/packages/npm/ +//gitlab.com/api/v4/projects/28849281/packages/npm/:_authToken=${NPM_TOKEN} \ No newline at end of file diff --git a/babel.config.js b/babel.config.js deleted file mode 100644 index e955840..0000000 --- a/babel.config.js +++ /dev/null @@ -1,5 +0,0 @@ -module.exports = { - presets: [ - '@vue/cli-plugin-babel/preset' - ] -} diff --git a/jest.config.js b/jest.config.js deleted file mode 100644 index d7f13cc..0000000 --- a/jest.config.js +++ /dev/null @@ -1,6 +0,0 @@ -module.exports = { - preset: '@vue/cli-plugin-unit-jest/presets/typescript-and-babel', - transform: { - '^.+\\.vue$': 'vue-jest' - } -} diff --git a/jsconfig.json b/jsconfig.json deleted file mode 100644 index 5df65d0..0000000 --- a/jsconfig.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "typeAcquisition": { - - "enable": true - } -} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..82bd044 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,2213 @@ +{ + "name": "Crimata", + "version": "1.0.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "Crimata", + "version": "1.0.0", + "dependencies": { + "@crimata/nodeaudio": "^0.0.0", + "axios": "^0.21.1", + "base64-arraybuffer": "^1.0.1", + "electron-store": "^8.0.0", + "ws": "^7.3.1" + }, + "devDependencies": { + "electron": "^13.2.3" + } + }, + "node_modules/@crimata/nodeaudio": { + "version": "0.0.0", + "resolved": "https://gitlab.com/api/v4/projects/28849281/packages/npm/@crimata/nodeaudio/-/@crimata/nodeaudio-0.0.0.tgz", + "integrity": "sha1-KTpDGuL8j3x72BLNb4Iyg8zgARo=", + "hasInstallScript": true, + "dependencies": { + "bindings": "~1.2.1", + "sleep": "^6.3.0" + } + }, + "node_modules/@electron/get": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/@electron/get/-/get-1.13.0.tgz", + "integrity": "sha512-+SjZhRuRo+STTO1Fdhzqnv9D2ZhjxXP6egsJ9kiO8dtP68cDx7dFCwWi64dlMQV7sWcfW1OYCW4wviEBzmRsfQ==", + "dev": true, + "dependencies": { + "debug": "^4.1.1", + "env-paths": "^2.2.0", + "fs-extra": "^8.1.0", + "got": "^9.6.0", + "progress": "^2.0.3", + "semver": "^6.2.0", + "sumchecker": "^3.0.1" + }, + "engines": { + "node": ">=8.6" + }, + "optionalDependencies": { + "global-agent": "^2.0.2", + "global-tunnel-ng": "^2.7.1" + } + }, + "node_modules/@electron/get/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==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/@electron/get/node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "dev": true, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/@electron/get/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@electron/get/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==", + "dev": true, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/@sindresorhus/is": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", + "integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/@szmarczak/http-timer": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz", + "integrity": "sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==", + "dev": true, + "dependencies": { + "defer-to-connect": "^1.0.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@types/node": { + "version": "14.17.12", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.17.12.tgz", + "integrity": "sha512-vhUqgjJR1qxwTWV5Ps5txuy2XMdf7Fw+OrdChRboy8BmWUPkckOhphaohzFG6b8DW7CrxaBMdrdJ47SYFq1okw==", + "dev": true + }, + "node_modules/ajv": { + "version": "8.6.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.6.2.tgz", + "integrity": "sha512-9807RlWAgT564wT+DjeyU5OFMPjmzxVobvDFmNAhY+5zD6A2ly3jDp6sgnfyDtlIQ+7H97oc/DGCzzfu9rjw9w==", + "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": { + "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/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/axios": { + "version": "0.21.1", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz", + "integrity": "sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==", + "dependencies": { + "follow-redirects": "^1.10.0" + } + }, + "node_modules/base64-arraybuffer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-1.0.1.tgz", + "integrity": "sha512-vFIUq7FdLtjZMhATwDul5RZWv2jpXQ09Pd6jcVEOvIsqCWTRFD/ONHNfyOS8dA/Ippi5dsIgpyKWKZaAKZltbA==", + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/bindings": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.2.1.tgz", + "integrity": "sha1-FK1hE4EtLTfXLme0ystLtyZQXxE=" + }, + "node_modules/boolean": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/boolean/-/boolean-3.1.4.tgz", + "integrity": "sha512-3hx0kwU3uzG6ReQ3pnaFQPSktpBw6RHN3/ivDKEuU8g1XSfafowyvDnadjv1xp8IZqhtSukxlwv9bF6FhX8m0w==", + "dev": true, + "optional": true + }, + "node_modules/buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=", + "dev": true, + "engines": { + "node": "*" + } + }, + "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==", + "dev": true + }, + "node_modules/cacheable-request": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-6.1.0.tgz", + "integrity": "sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==", + "dev": true, + "dependencies": { + "clone-response": "^1.0.2", + "get-stream": "^5.1.0", + "http-cache-semantics": "^4.0.0", + "keyv": "^3.0.0", + "lowercase-keys": "^2.0.0", + "normalize-url": "^4.1.0", + "responselike": "^1.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cacheable-request/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==", + "dev": true, + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cacheable-request/node_modules/lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/clone-response": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz", + "integrity": "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=", + "dev": true, + "dependencies": { + "mimic-response": "^1.0.0" + } + }, + "node_modules/concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "dev": true, + "engines": [ + "node >= 0.8" + ], + "dependencies": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, + "node_modules/conf": { + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/conf/-/conf-10.0.2.tgz", + "integrity": "sha512-iyy4ArqyQ/yrzNASNBN+jaylu53JRuq0ztvL6KAWYHj4iN56BVuhy2SrzEEHBodNbacZr2Pd/4nWhoAwc66T1g==", + "dependencies": { + "ajv": "^8.1.0", + "ajv-formats": "^2.0.2", + "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/config-chain": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz", + "integrity": "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==", + "dev": true, + "optional": true, + "dependencies": { + "ini": "^1.3.4", + "proto-list": "~1.2.1" + } + }, + "node_modules/core-js": { + "version": "3.16.3", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.16.3.tgz", + "integrity": "sha512-lM3GftxzHNtPNUJg0v4pC2RC6puwMd6VZA7vXUczi+SKmCWSf4JwO89VJGMqbzmB7jlK7B5hr3S64PqwFL49cA==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "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": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "dev": true + }, + "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/debug": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", + "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decompress-response": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", + "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=", + "dev": true, + "dependencies": { + "mimic-response": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/defer-to-connect": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.3.tgz", + "integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==", + "dev": true + }, + "node_modules/define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "dev": true, + "optional": true, + "dependencies": { + "object-keys": "^1.0.12" + }, + "engines": { + "node": ">= 0.4" + } + }, + "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==", + "dev": true, + "optional": true + }, + "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/duplexer3": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", + "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=", + "dev": true + }, + "node_modules/electron": { + "version": "13.2.3", + "resolved": "https://registry.npmjs.org/electron/-/electron-13.2.3.tgz", + "integrity": "sha512-FzWhbKHjq7ZTpPQFaYiLPL64erC8/BOsu5NlNN9nQ6f7rIP8ygKlNAlQit3vbOcksQAwItDUCIw4sW0mcaRpCA==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "@electron/get": "^1.0.1", + "@types/node": "^14.6.2", + "extract-zip": "^1.0.3" + }, + "bin": { + "electron": "cli.js" + }, + "engines": { + "node": ">= 8.6" + } + }, + "node_modules/electron-store": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/electron-store/-/electron-store-8.0.0.tgz", + "integrity": "sha512-ZgRPUZkfrrjWSqxZeaxu7lEvmYf6tgl49dLMqxXGnEmliSiwv3u4rJPG+mH3fBQP9PBqgSh4TCuxHZImMMUgWg==", + "dependencies": { + "conf": "^10.0.0", + "type-fest": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", + "dev": true, + "optional": true, + "engines": { + "node": ">= 0.8" + } + }, + "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==", + "dev": true, + "dependencies": { + "once": "^1.4.0" + } + }, + "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/es6-error": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", + "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", + "dev": true, + "optional": true + }, + "node_modules/extract-zip": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-1.7.0.tgz", + "integrity": "sha512-xoh5G1W/PB0/27lXgMQyIhP5DSY/LhoCsOyZgb+6iMmRtCwVBo55uKaMoEYrDCKQhWvqEip5ZPKAc6eFNyf/MA==", + "dev": true, + "dependencies": { + "concat-stream": "^1.6.2", + "debug": "^2.6.9", + "mkdirp": "^0.5.4", + "yauzl": "^2.10.0" + }, + "bin": { + "extract-zip": "cli.js" + } + }, + "node_modules/extract-zip/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/extract-zip/node_modules/mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "dev": true, + "dependencies": { + "minimist": "^1.2.5" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/extract-zip/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": 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/fd-slicer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=", + "dev": true, + "dependencies": { + "pend": "~1.2.0" + } + }, + "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/follow-redirects": { + "version": "1.14.2", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.2.tgz", + "integrity": "sha512-yLR6WaE2lbF0x4K2qE2p9PEXKLDjUjnR/xmjS3wHAYxtlsI9MLLBJUZirAHKzUZDGLxje7w/cXR49WOUo4rbsA==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dev": true, + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/global-agent": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/global-agent/-/global-agent-2.2.0.tgz", + "integrity": "sha512-+20KpaW6DDLqhG7JDiJpD1JvNvb8ts+TNl7BPOYcURqCrXqnN1Vf+XVOrkKJAFPqfX+oEhsdzOj1hLWkBTdNJg==", + "dev": true, + "optional": true, + "dependencies": { + "boolean": "^3.0.1", + "core-js": "^3.6.5", + "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-tunnel-ng": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/global-tunnel-ng/-/global-tunnel-ng-2.7.1.tgz", + "integrity": "sha512-4s+DyciWBV0eK148wqXxcmVAbFVPqtc3sEtUE/GTQfuU80rySLcMhUmHKSHI7/LDj8q0gDYI1lIhRRB7ieRAqg==", + "dev": true, + "optional": true, + "dependencies": { + "encodeurl": "^1.0.2", + "lodash": "^4.17.10", + "npm-conf": "^1.1.3", + "tunnel": "^0.0.6" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/globalthis": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.2.tgz", + "integrity": "sha512-ZQnSFO1la8P7auIOQECnm0sSuoMeaSq0EEdXMBFF2QJO4uNcwbyhSgG3MruWNbFTqCLmxVwGOl7LZ9kASvHdeQ==", + "dev": true, + "optional": true, + "dependencies": { + "define-properties": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/got": { + "version": "9.6.0", + "resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz", + "integrity": "sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==", + "dev": true, + "dependencies": { + "@sindresorhus/is": "^0.14.0", + "@szmarczak/http-timer": "^1.1.2", + "cacheable-request": "^6.0.0", + "decompress-response": "^3.3.0", + "duplexer3": "^0.1.4", + "get-stream": "^4.1.0", + "lowercase-keys": "^1.0.1", + "mimic-response": "^1.0.1", + "p-cancelable": "^1.0.0", + "to-readable-stream": "^1.0.0", + "url-parse-lax": "^3.0.0" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz", + "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==", + "dev": true + }, + "node_modules/http-cache-semantics": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", + "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==", + "dev": true + }, + "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/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true, + "optional": true + }, + "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/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "node_modules/json-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", + "integrity": "sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=", + "dev": true + }, + "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/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-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", + "dev": true, + "optional": true + }, + "node_modules/keyv": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", + "integrity": "sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==", + "dev": true, + "dependencies": { + "json-buffer": "3.0.0" + } + }, + "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/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true, + "optional": true + }, + "node_modules/lowercase-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", + "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "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/matcher": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/matcher/-/matcher-3.0.0.tgz", + "integrity": "sha512-OkeDaAZ/bQCxeFAozM55PKcKU0yJMPGifLwV4Qgjitu+5MoAfSQN4lsLJeXZ1b8w0x+/Emda6MZgXS1jvsapng==", + "dev": true, + "optional": true, + "dependencies": { + "escape-string-regexp": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/matcher/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==", + "dev": true, + "optional": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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/mimic-response": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "dev": true + }, + "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==", + "dev": true + }, + "node_modules/nan": { + "version": "2.15.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.15.0.tgz", + "integrity": "sha512-8ZtvEnA2c5aYCZYd1cvgdnU6cqwixRoYg70xPLWUws5ORTa/lnw+u4amixRS/Ac5U5mQVgp9pnlSUnbNWFaWZQ==" + }, + "node_modules/normalize-url": { + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.1.tgz", + "integrity": "sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm-conf": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/npm-conf/-/npm-conf-1.1.3.tgz", + "integrity": "sha512-Yic4bZHJOt9RCFbRP3GgpqhScOY4HH3V2P8yBj6CeYq118Qr+BLXqT2JvpJ00mryLESpgOxf5XlFv4ZjXxLScw==", + "dev": true, + "optional": true, + "dependencies": { + "config-chain": "^1.1.11", + "pify": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "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==", + "dev": true, + "optional": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "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/p-cancelable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz", + "integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "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/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/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/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "engines": { + "node": ">=4" + } + }, + "node_modules/pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=", + "dev": true + }, + "node_modules/pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true, + "optional": true, + "engines": { + "node": ">=4" + } + }, + "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/prepend-http": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", + "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "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==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/proto-list": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", + "integrity": "sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk=", + "dev": true, + "optional": true + }, + "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==", + "dev": true, + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "engines": { + "node": ">=6" + } + }, + "node_modules/readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "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/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/responselike": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", + "integrity": "sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec=", + "dev": true, + "dependencies": { + "lowercase-keys": "^1.0.0" + } + }, + "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==", + "dev": true, + "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/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/semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "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": "sha1-De4hahyUGrN+nvsXiPavxf9VN/w=", + "dev": true, + "optional": true + }, + "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==", + "dev": true, + "optional": true, + "dependencies": { + "type-fest": "^0.13.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/serialize-error/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==", + "dev": true, + "optional": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/sleep": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/sleep/-/sleep-6.3.0.tgz", + "integrity": "sha512-+WgYl951qdUlb1iS97UvQ01pkauoBK9ML9I/CMPg41v0Ze4EyMlTgFTDDo32iYj98IYqxIjDMRd+L71lawFfpQ==", + "hasInstallScript": true, + "dependencies": { + "nan": "^2.14.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "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==", + "dev": true, + "optional": true + }, + "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/sumchecker": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/sumchecker/-/sumchecker-3.0.1.tgz", + "integrity": "sha512-MvjXzkz/BOfyVDkG0oFOtBxHX2u3gKbMHIF/dXblZsgD3BWOFLmHovIpZY7BykJdAjcqRCBi1WYBNdEC9yI7vg==", + "dev": true, + "dependencies": { + "debug": "^4.1.0" + }, + "engines": { + "node": ">= 8.0" + } + }, + "node_modules/to-readable-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-1.0.0.tgz", + "integrity": "sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/tunnel": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", + "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==", + "dev": true, + "optional": true, + "engines": { + "node": ">=0.6.11 <=0.7.0 || >=0.7.3" + } + }, + "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==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", + "dev": true + }, + "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-parse-lax": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", + "integrity": "sha1-FrXK/Afb42dsGxmZF3gj1lA6yww=", + "dev": true, + "dependencies": { + "prepend-http": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "node_modules/ws": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.4.tgz", + "integrity": "sha512-zP9z6GXm6zC27YtspwH99T3qTG7bBFv2VIkeHstMLrLlDJuzA7tQ5ls3OJ1hOGGCzTQPniNJoHXIAOS0Jljohg==", + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": 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/yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=", + "dev": true, + "dependencies": { + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" + } + } + }, + "dependencies": { + "@crimata/nodeaudio": { + "version": "0.0.0", + "resolved": "https://gitlab.com/api/v4/projects/28849281/packages/npm/@crimata/nodeaudio/-/@crimata/nodeaudio-0.0.0.tgz", + "integrity": "sha1-KTpDGuL8j3x72BLNb4Iyg8zgARo=", + "requires": { + "bindings": "~1.2.1", + "sleep": "^6.3.0" + } + }, + "@electron/get": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/@electron/get/-/get-1.13.0.tgz", + "integrity": "sha512-+SjZhRuRo+STTO1Fdhzqnv9D2ZhjxXP6egsJ9kiO8dtP68cDx7dFCwWi64dlMQV7sWcfW1OYCW4wviEBzmRsfQ==", + "dev": true, + "requires": { + "debug": "^4.1.1", + "env-paths": "^2.2.0", + "fs-extra": "^8.1.0", + "global-agent": "^2.0.2", + "global-tunnel-ng": "^2.7.1", + "got": "^9.6.0", + "progress": "^2.0.3", + "semver": "^6.2.0", + "sumchecker": "^3.0.1" + }, + "dependencies": { + "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==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6" + } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + }, + "universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true + } + } + }, + "@sindresorhus/is": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", + "integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==", + "dev": true + }, + "@szmarczak/http-timer": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz", + "integrity": "sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==", + "dev": true, + "requires": { + "defer-to-connect": "^1.0.1" + } + }, + "@types/node": { + "version": "14.17.12", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.17.12.tgz", + "integrity": "sha512-vhUqgjJR1qxwTWV5Ps5txuy2XMdf7Fw+OrdChRboy8BmWUPkckOhphaohzFG6b8DW7CrxaBMdrdJ47SYFq1okw==", + "dev": true + }, + "ajv": { + "version": "8.6.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.6.2.tgz", + "integrity": "sha512-9807RlWAgT564wT+DjeyU5OFMPjmzxVobvDFmNAhY+5zD6A2ly3jDp6sgnfyDtlIQ+7H97oc/DGCzzfu9rjw9w==", + "requires": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + } + }, + "ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "requires": { + "ajv": "^8.0.0" + } + }, + "atomically": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/atomically/-/atomically-1.7.0.tgz", + "integrity": "sha512-Xcz9l0z7y9yQ9rdDaxlmaI4uJHf/T8g9hOEzJcsEqX2SjCj4J20uK7+ldkDHMbpJDK76wF7xEIgxc/vSlsfw5w==" + }, + "axios": { + "version": "0.21.1", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz", + "integrity": "sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==", + "requires": { + "follow-redirects": "^1.10.0" + } + }, + "base64-arraybuffer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-1.0.1.tgz", + "integrity": "sha512-vFIUq7FdLtjZMhATwDul5RZWv2jpXQ09Pd6jcVEOvIsqCWTRFD/ONHNfyOS8dA/Ippi5dsIgpyKWKZaAKZltbA==" + }, + "bindings": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.2.1.tgz", + "integrity": "sha1-FK1hE4EtLTfXLme0ystLtyZQXxE=" + }, + "boolean": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/boolean/-/boolean-3.1.4.tgz", + "integrity": "sha512-3hx0kwU3uzG6ReQ3pnaFQPSktpBw6RHN3/ivDKEuU8g1XSfafowyvDnadjv1xp8IZqhtSukxlwv9bF6FhX8m0w==", + "dev": true, + "optional": true + }, + "buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=", + "dev": true + }, + "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==", + "dev": true + }, + "cacheable-request": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-6.1.0.tgz", + "integrity": "sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==", + "dev": true, + "requires": { + "clone-response": "^1.0.2", + "get-stream": "^5.1.0", + "http-cache-semantics": "^4.0.0", + "keyv": "^3.0.0", + "lowercase-keys": "^2.0.0", + "normalize-url": "^4.1.0", + "responselike": "^1.0.2" + }, + "dependencies": { + "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==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, + "lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", + "dev": true + } + } + }, + "clone-response": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz", + "integrity": "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=", + "dev": true, + "requires": { + "mimic-response": "^1.0.0" + } + }, + "concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, + "conf": { + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/conf/-/conf-10.0.2.tgz", + "integrity": "sha512-iyy4ArqyQ/yrzNASNBN+jaylu53JRuq0ztvL6KAWYHj4iN56BVuhy2SrzEEHBodNbacZr2Pd/4nWhoAwc66T1g==", + "requires": { + "ajv": "^8.1.0", + "ajv-formats": "^2.0.2", + "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" + } + }, + "config-chain": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz", + "integrity": "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==", + "dev": true, + "optional": true, + "requires": { + "ini": "^1.3.4", + "proto-list": "~1.2.1" + } + }, + "core-js": { + "version": "3.16.3", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.16.3.tgz", + "integrity": "sha512-lM3GftxzHNtPNUJg0v4pC2RC6puwMd6VZA7vXUczi+SKmCWSf4JwO89VJGMqbzmB7jlK7B5hr3S64PqwFL49cA==", + "dev": true, + "optional": true + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "dev": true + }, + "debounce-fn": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/debounce-fn/-/debounce-fn-4.0.0.tgz", + "integrity": "sha512-8pYCQiL9Xdcg0UPSD3d+0KMlOjp+KGU5EPwYddgzQ7DATsg4fuUDjQtsYLmWjnk2obnNHgV3vE2Y4jejSOJVBQ==", + "requires": { + "mimic-fn": "^3.0.0" + } + }, + "debug": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", + "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "decompress-response": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", + "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=", + "dev": true, + "requires": { + "mimic-response": "^1.0.0" + } + }, + "defer-to-connect": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.3.tgz", + "integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==", + "dev": true + }, + "define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "dev": true, + "optional": true, + "requires": { + "object-keys": "^1.0.12" + } + }, + "detect-node": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", + "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", + "dev": true, + "optional": true + }, + "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==", + "requires": { + "is-obj": "^2.0.0" + } + }, + "duplexer3": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", + "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=", + "dev": true + }, + "electron": { + "version": "13.2.3", + "resolved": "https://registry.npmjs.org/electron/-/electron-13.2.3.tgz", + "integrity": "sha512-FzWhbKHjq7ZTpPQFaYiLPL64erC8/BOsu5NlNN9nQ6f7rIP8ygKlNAlQit3vbOcksQAwItDUCIw4sW0mcaRpCA==", + "dev": true, + "requires": { + "@electron/get": "^1.0.1", + "@types/node": "^14.6.2", + "extract-zip": "^1.0.3" + } + }, + "electron-store": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/electron-store/-/electron-store-8.0.0.tgz", + "integrity": "sha512-ZgRPUZkfrrjWSqxZeaxu7lEvmYf6tgl49dLMqxXGnEmliSiwv3u4rJPG+mH3fBQP9PBqgSh4TCuxHZImMMUgWg==", + "requires": { + "conf": "^10.0.0", + "type-fest": "^1.0.2" + } + }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", + "dev": true, + "optional": true + }, + "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==", + "dev": true, + "requires": { + "once": "^1.4.0" + } + }, + "env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==" + }, + "es6-error": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", + "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", + "dev": true, + "optional": true + }, + "extract-zip": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-1.7.0.tgz", + "integrity": "sha512-xoh5G1W/PB0/27lXgMQyIhP5DSY/LhoCsOyZgb+6iMmRtCwVBo55uKaMoEYrDCKQhWvqEip5ZPKAc6eFNyf/MA==", + "dev": true, + "requires": { + "concat-stream": "^1.6.2", + "debug": "^2.6.9", + "mkdirp": "^0.5.4", + "yauzl": "^2.10.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "dev": true, + "requires": { + "minimist": "^1.2.5" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "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==" + }, + "fd-slicer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=", + "dev": true, + "requires": { + "pend": "~1.2.0" + } + }, + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "requires": { + "locate-path": "^3.0.0" + } + }, + "follow-redirects": { + "version": "1.14.2", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.2.tgz", + "integrity": "sha512-yLR6WaE2lbF0x4K2qE2p9PEXKLDjUjnR/xmjS3wHAYxtlsI9MLLBJUZirAHKzUZDGLxje7w/cXR49WOUo4rbsA==" + }, + "get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, + "global-agent": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/global-agent/-/global-agent-2.2.0.tgz", + "integrity": "sha512-+20KpaW6DDLqhG7JDiJpD1JvNvb8ts+TNl7BPOYcURqCrXqnN1Vf+XVOrkKJAFPqfX+oEhsdzOj1hLWkBTdNJg==", + "dev": true, + "optional": true, + "requires": { + "boolean": "^3.0.1", + "core-js": "^3.6.5", + "es6-error": "^4.1.1", + "matcher": "^3.0.0", + "roarr": "^2.15.3", + "semver": "^7.3.2", + "serialize-error": "^7.0.1" + } + }, + "global-tunnel-ng": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/global-tunnel-ng/-/global-tunnel-ng-2.7.1.tgz", + "integrity": "sha512-4s+DyciWBV0eK148wqXxcmVAbFVPqtc3sEtUE/GTQfuU80rySLcMhUmHKSHI7/LDj8q0gDYI1lIhRRB7ieRAqg==", + "dev": true, + "optional": true, + "requires": { + "encodeurl": "^1.0.2", + "lodash": "^4.17.10", + "npm-conf": "^1.1.3", + "tunnel": "^0.0.6" + } + }, + "globalthis": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.2.tgz", + "integrity": "sha512-ZQnSFO1la8P7auIOQECnm0sSuoMeaSq0EEdXMBFF2QJO4uNcwbyhSgG3MruWNbFTqCLmxVwGOl7LZ9kASvHdeQ==", + "dev": true, + "optional": true, + "requires": { + "define-properties": "^1.1.3" + } + }, + "got": { + "version": "9.6.0", + "resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz", + "integrity": "sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==", + "dev": true, + "requires": { + "@sindresorhus/is": "^0.14.0", + "@szmarczak/http-timer": "^1.1.2", + "cacheable-request": "^6.0.0", + "decompress-response": "^3.3.0", + "duplexer3": "^0.1.4", + "get-stream": "^4.1.0", + "lowercase-keys": "^1.0.1", + "mimic-response": "^1.0.1", + "p-cancelable": "^1.0.0", + "to-readable-stream": "^1.0.0", + "url-parse-lax": "^3.0.0" + } + }, + "graceful-fs": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz", + "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==", + "dev": true + }, + "http-cache-semantics": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", + "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==", + "dev": true + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true, + "optional": true + }, + "is-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==" + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "json-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", + "integrity": "sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=", + "dev": true + }, + "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==" + }, + "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==" + }, + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", + "dev": true, + "optional": true + }, + "keyv": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", + "integrity": "sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==", + "dev": true, + "requires": { + "json-buffer": "3.0.0" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true, + "optional": true + }, + "lowercase-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", + "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", + "dev": true + }, + "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==", + "requires": { + "yallist": "^4.0.0" + } + }, + "matcher": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/matcher/-/matcher-3.0.0.tgz", + "integrity": "sha512-OkeDaAZ/bQCxeFAozM55PKcKU0yJMPGifLwV4Qgjitu+5MoAfSQN4lsLJeXZ1b8w0x+/Emda6MZgXS1jvsapng==", + "dev": true, + "optional": true, + "requires": { + "escape-string-regexp": "^4.0.0" + }, + "dependencies": { + "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==", + "dev": true, + "optional": true + } + } + }, + "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==" + }, + "mimic-response": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", + "dev": true + }, + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "dev": true + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "nan": { + "version": "2.15.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.15.0.tgz", + "integrity": "sha512-8ZtvEnA2c5aYCZYd1cvgdnU6cqwixRoYg70xPLWUws5ORTa/lnw+u4amixRS/Ac5U5mQVgp9pnlSUnbNWFaWZQ==" + }, + "normalize-url": { + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.1.tgz", + "integrity": "sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA==", + "dev": true + }, + "npm-conf": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/npm-conf/-/npm-conf-1.1.3.tgz", + "integrity": "sha512-Yic4bZHJOt9RCFbRP3GgpqhScOY4HH3V2P8yBj6CeYq118Qr+BLXqT2JvpJ00mryLESpgOxf5XlFv4ZjXxLScw==", + "dev": true, + "optional": true, + "requires": { + "config-chain": "^1.1.11", + "pify": "^3.0.0" + } + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, + "optional": true + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "requires": { + "mimic-fn": "^2.1.0" + }, + "dependencies": { + "mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==" + } + } + }, + "p-cancelable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz", + "integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==", + "dev": true + }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "requires": { + "p-try": "^2.0.0" + } + }, + "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==", + "requires": { + "p-limit": "^2.0.0" + } + }, + "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==" + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=" + }, + "pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=", + "dev": true + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true, + "optional": true + }, + "pkg-up": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-3.1.0.tgz", + "integrity": "sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA==", + "requires": { + "find-up": "^3.0.0" + } + }, + "prepend-http": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", + "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=", + "dev": true + }, + "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 + }, + "progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true + }, + "proto-list": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", + "integrity": "sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk=", + "dev": true, + "optional": true + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "requires": { + "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" + } + }, + "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==" + }, + "responselike": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", + "integrity": "sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec=", + "dev": true, + "requires": { + "lowercase-keys": "^1.0.0" + } + }, + "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==", + "dev": true, + "optional": true, + "requires": { + "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" + } + }, + "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 + }, + "semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "requires": { + "lru-cache": "^6.0.0" + } + }, + "semver-compare": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz", + "integrity": "sha1-De4hahyUGrN+nvsXiPavxf9VN/w=", + "dev": true, + "optional": true + }, + "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==", + "dev": true, + "optional": true, + "requires": { + "type-fest": "^0.13.1" + }, + "dependencies": { + "type-fest": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.13.1.tgz", + "integrity": "sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==", + "dev": true, + "optional": true + } + } + }, + "sleep": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/sleep/-/sleep-6.3.0.tgz", + "integrity": "sha512-+WgYl951qdUlb1iS97UvQ01pkauoBK9ML9I/CMPg41v0Ze4EyMlTgFTDDo32iYj98IYqxIjDMRd+L71lawFfpQ==", + "requires": { + "nan": "^2.14.1" + } + }, + "sprintf-js": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.2.tgz", + "integrity": "sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==", + "dev": true, + "optional": true + }, + "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, + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "sumchecker": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/sumchecker/-/sumchecker-3.0.1.tgz", + "integrity": "sha512-MvjXzkz/BOfyVDkG0oFOtBxHX2u3gKbMHIF/dXblZsgD3BWOFLmHovIpZY7BykJdAjcqRCBi1WYBNdEC9yI7vg==", + "dev": true, + "requires": { + "debug": "^4.1.0" + } + }, + "to-readable-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-1.0.0.tgz", + "integrity": "sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==", + "dev": true + }, + "tunnel": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", + "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==", + "dev": true, + "optional": true + }, + "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==" + }, + "typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", + "dev": true + }, + "uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "requires": { + "punycode": "^2.1.0" + } + }, + "url-parse-lax": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", + "integrity": "sha1-FrXK/Afb42dsGxmZF3gj1lA6yww=", + "dev": true, + "requires": { + "prepend-http": "^2.0.0" + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "ws": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.4.tgz", + "integrity": "sha512-zP9z6GXm6zC27YtspwH99T3qTG7bBFv2VIkeHstMLrLlDJuzA7tQ5ls3OJ1hOGGCzTQPniNJoHXIAOS0Jljohg==", + "requires": {} + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=", + "dev": true, + "requires": { + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" + } + } + } +} diff --git a/package.json b/package.json index 24d13b1..31bd08d 100644 --- a/package.json +++ b/package.json @@ -1,104 +1,24 @@ { "name": "Crimata", - "version": "0.9.9", + "productName": "crimata-messenger", + "version": "1.0.0", "private": true, - "description": "Cross-platform messenger application built with electron, vue3, and TS.", + "description": "Cross-platform messenger app (Electron, Vue3, and TS)", "author": { - "name": "Enrique Hernandez" + "name": "Andrew Gundersen" }, + "main": "src/main.js", "scripts": { - "build": "vue-cli-service electron:build", - "dev": "vue-cli-service electron:serve", - "postinstall": "electron-builder install-app-deps", - "postuninstall": "electron-builder install-app-deps" + "start": "electron ." }, - "main": "init.js", "dependencies": { - "@google-cloud/speech": "^4.2.0", - "@types/animejs": "^3.1.2", - "@types/bindings": "^1.3.0", - "@types/dom-mediacapture-record": "^1.0.7", - "@types/node": "^14.14.25", - "@types/uuid": "^8.3.0", - "@types/ws": "^7.2.7", - "animejs": "^3.2.0", + "@crimata/nodeaudio": "^0.0.0", "axios": "^0.21.1", - "core-js": "^3.6.5", - "electron-is-dev": "^2.0.0", + "base64-arraybuffer": "^1.0.1", "electron-store": "^8.0.0", - "electron-updater": "^4.3.8", - "mitt": "^2.1.0", - "naudiodon": "^2.3.2", - "node-record-lpcm16": "^1.0.1", - "update-electron-app": "^2.0.1", - "uuid": "^8.3.2", - "vue": "^3.0.0-0", - "vue-router": "^4.0.0-0", - "vuex": "^4.0.0-0", "ws": "^7.3.1" }, "devDependencies": { - "@types/axios": "^0.14.0", - "@types/electron-devtools-installer": "^2.2.0", - "@types/jest": "^24.0.19", - "@typescript-eslint/eslint-plugin": "^2.33.0", - "@typescript-eslint/parser": "^2.33.0", - "@vue/cli-plugin-babel": "~4.5.0", - "@vue/cli-plugin-eslint": "~4.5.0", - "@vue/cli-plugin-router": "~4.5.0", - "@vue/cli-plugin-typescript": "~4.5.0", - "@vue/cli-plugin-unit-jest": "~4.5.0", - "@vue/cli-plugin-vuex": "~4.5.0", - "@vue/cli-service": "~4.5.0", - "@vue/compiler-sfc": "^3.0.0-0", - "@vue/eslint-config-typescript": "^5.0.2", - "@vue/test-utils": "^2.0.0-0", - "@wasm-tool/wasm-pack-plugin": "^1.3.1", - "electron": "^9.0.0", - "electron-devtools-installer": "^3.1.0", - "electron-log": "^4.3.4", - "eslint": "^6.7.2", - "eslint-plugin-vue": "^7.0.0-0", - "lint-staged": "^9.5.0", - "node-sass": "^4.12.0", - "optimize-wasm-webpack-plugin": "^1.0.12", - "sass-loader": "^8.0.2", - "spectron": "11.0.0", - "typescript": "~3.9.3", - "vue-cli-plugin-electron-builder": "~2.0.0-rc.6", - "vue-jest": "^5.0.0-0" - }, - "vue": { - "lintOnSave": false, - "pluginOptions": { - "electronBuilder": { - "mainProcessFile": "./src/init.ts", - "rendererProcessFile": "./src/render/main.ts", - "preload": "./src/render/preload.ts", - "builderOptions": { - "appId": "com.crimata.ElectronUpdaterApp", - "artifactName": "${productName}-${version}.${ext}", - "publish": { - "provider": "generic", - "url": "https://gitlab.com/api/v4/projects/25637892/jobs/artifacts/main/raw/dist_electron?job=build" - } - } - } - } - }, - "gitHooks": { - "pre-commit": "lint-staged" - }, - "lint-staged": { - "*.{js,jsx,vue,ts,tsx}": [ - "vue-cli-service lint", - "git add" - ] - }, - "productName": "crimata-messenger", - "repository": { - "type": "git", - "url": "https://gitlab.com/crimata/electron-app.git", - "release": "latest" + "electron": "^13.2.3" } } diff --git a/public/index.html b/public/index.html deleted file mode 100644 index 8f79d27..0000000 --- a/public/index.html +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - <%= htmlWebpackPlugin.options.title %> - - - -
- - - diff --git a/src/account.js b/src/account.js new file mode 100644 index 0000000..239d89d --- /dev/null +++ b/src/account.js @@ -0,0 +1,44 @@ +const { ipcMain } = require("electron"); + +const store = require("./utils/store"); +const { postLogin } = require("./api"); +const { ipcEmit } = require("./utils/emitter"); +const { launchSession, endSession } = require("./session"); + +// store.set("account", "smith12@gmail.com"); +store.set("account", "adgundersen@gmail.com"); + +async function login(_e, email, password) +{ + const res = await postLogin(email, password); + if (res) + { + const account = res.crimataId; + store.set("account", account); + ipcEmit("set-account", account); + launchSession(account); + return true; + } + else + { + return false; + } +}; + +function logout() +{ + store.delete("account"); + ipcEmit("set-account", false); + endSession(); +}; + +function initAccount() +{ + ipcMain.handle("login", login); + ipcMain.on("logout", logout); + + const account = store.get("account"); + if (account) launchSession(account); +} + +exports.initAccount = initAccount; diff --git a/src/account.ts b/src/account.ts deleted file mode 100644 index 581da0e..0000000 --- a/src/account.ts +++ /dev/null @@ -1,95 +0,0 @@ - -import { postAuth, postLogin, postLogout } from "@/api/account"; -import { endSession, launchSession } from "@/session"; -import { getToken, setToken, setProfile, getProfile, clearStore } from "./store"; -import { parseAuthRes } from "./auth"; -import { ipcEmit } from "@/composables/useEmitter"; - -export const accountAuth = async (): Promise => { - - /* attempt to get a login token from the store */ - const token = getToken(); - - /* try to login with it, returns platform secret and new token on success */ - if (token) { - try { - - const res = await postAuth(token); - - const parsed = parseAuthRes(res); - - setToken(parsed.token) - setProfile(parsed.profile); - - return { - profile: parsed.profile, - token: parsed.token - }; - - } catch(e) { - console.log('[ACCOUNT]', e); - clearStore(); - throw(new Error('Failed to authenticate.')); - - } - } else { - throw(new Error('Unable to authenticate.')); - } -}; - -export const accountLogin: IpcHandlerCallback = async (payload) => { - const account = payload as AccountCredentials; - try { - - // attempt login with email password - const res = await postLogin(account.email, account.password); - const parsed = parseAuthRes(res); - - // save jwt token and profile - setToken(parsed.token); - setProfile(parsed.profile); - - // launch session - launchSession(parsed.token); - - // return profile to renderer - return parsed.profile; - - } catch(e) { - clearStore(); - throw e; - } -} - - -export const accountLogout = async (): Promise => { - - try { - // post logout to backend - await postLogout(); - - // remove key and crimataId - clearStore(); - - // kill crimata platform session - endSession(); - - return; - - } catch(e) { - console.log('[ACCOUNT]', e); - return (new Error('Failed to logout. Please try again.')); - } - -} - -export const updateAppState = (): void => { - - const profile = getProfile(); - - ipcEmit("set-profile", profile); - - // ipcEmit('messages') etc - -} - diff --git a/src/api.js b/src/api.js new file mode 100644 index 0000000..89d617e --- /dev/null +++ b/src/api.js @@ -0,0 +1,19 @@ +const axios = require('axios').default; + +const config = require("./config"); + +const baseUrl = config.BUSINESS_URL + config.BUSINESS_PREFIX; + +async function postLogin(email, password) +{ + try { + const res = await axios.post(baseUrl + "/account/login", { + email: email, password: password + }); + return res.data; + } catch (e) { + return false; + } +} + +exports.postLogin = postLogin; \ No newline at end of file diff --git a/src/api/account.ts b/src/api/account.ts deleted file mode 100644 index 45baca2..0000000 --- a/src/api/account.ts +++ /dev/null @@ -1,31 +0,0 @@ - -import useHttp from "@/composables/useHttp"; -import axios from "axios"; -import {config} from "@/config"; - -const { post } = useHttp(); - -export const postAuth = async (token: string) => ( - await axios({ - url: config.BUSINESS_URL + config.BUSINESS_PREFIX + '/account/authenticate', - headers: { - Cookie: `crimataCookie=${token}` - }, - method: 'POST', - }) -); - - -export const postLogin = async (email: string, password: string) => ( - await post('/account/login', { email, password }) -); - - -export const postLogout = - async (): Promise => (await post('/account/logout')); - - - - - - diff --git a/src/assets/icon.icns b/src/assets/icon.icns new file mode 100644 index 0000000..b173533 Binary files /dev/null and b/src/assets/icon.icns differ diff --git a/src/assets/tray/000.png b/src/assets/tray/000.png new file mode 100644 index 0000000..e6d5d32 Binary files /dev/null and b/src/assets/tray/000.png differ diff --git a/src/assets/tray/000@2x.png b/src/assets/tray/000@2x.png new file mode 100644 index 0000000..6d61d7f Binary files /dev/null and b/src/assets/tray/000@2x.png differ diff --git a/src/assets/tray/001.png b/src/assets/tray/001.png new file mode 100644 index 0000000..8d65b38 Binary files /dev/null and b/src/assets/tray/001.png differ diff --git a/src/assets/tray/001@2x.png b/src/assets/tray/001@2x.png new file mode 100644 index 0000000..b7f0e2c Binary files /dev/null and b/src/assets/tray/001@2x.png differ diff --git a/src/assets/tray/010.png b/src/assets/tray/010.png new file mode 100644 index 0000000..bc5718c Binary files /dev/null and b/src/assets/tray/010.png differ diff --git a/src/assets/tray/010@2x.png b/src/assets/tray/010@2x.png new file mode 100644 index 0000000..6b97193 Binary files /dev/null and b/src/assets/tray/010@2x.png differ diff --git a/src/assets/tray/011.png b/src/assets/tray/011.png new file mode 100644 index 0000000..c2f8612 Binary files /dev/null and b/src/assets/tray/011.png differ diff --git a/src/assets/tray/011@2x.png b/src/assets/tray/011@2x.png new file mode 100644 index 0000000..befcd5f Binary files /dev/null and b/src/assets/tray/011@2x.png differ diff --git a/src/assets/tray/100.png b/src/assets/tray/100.png new file mode 100644 index 0000000..99df7df Binary files /dev/null and b/src/assets/tray/100.png differ diff --git a/src/assets/tray/100@2x.png b/src/assets/tray/100@2x.png new file mode 100644 index 0000000..2d26144 Binary files /dev/null and b/src/assets/tray/100@2x.png differ diff --git a/src/assets/tray/101.png b/src/assets/tray/101.png new file mode 100644 index 0000000..523bc93 Binary files /dev/null and b/src/assets/tray/101.png differ diff --git a/src/assets/tray/101@2x.png b/src/assets/tray/101@2x.png new file mode 100644 index 0000000..91a15be Binary files /dev/null and b/src/assets/tray/101@2x.png differ diff --git a/src/assets/tray/110.png b/src/assets/tray/110.png new file mode 100644 index 0000000..ddd2524 Binary files /dev/null and b/src/assets/tray/110.png differ diff --git a/src/assets/tray/110@2x.png b/src/assets/tray/110@2x.png new file mode 100644 index 0000000..fd073dd Binary files /dev/null and b/src/assets/tray/110@2x.png differ diff --git a/src/assets/tray/111.png b/src/assets/tray/111.png new file mode 100644 index 0000000..d2dd686 Binary files /dev/null and b/src/assets/tray/111.png differ diff --git a/src/assets/tray/111@2x.png b/src/assets/tray/111@2x.png new file mode 100644 index 0000000..2bc77fd Binary files /dev/null and b/src/assets/tray/111@2x.png differ diff --git a/src/audio.js b/src/audio.js new file mode 100644 index 0000000..3736ee9 --- /dev/null +++ b/src/audio.js @@ -0,0 +1,137 @@ +const nodeAudio = require("@crimata/nodeaudio"); +const { globalShortcut, ipcMain } = require("electron"); + +const { sendMessage } = require("./io"); +const { updateTray } = require("./tray"); +const { encode, decode } = require("./codec"); +const { backgroundMitt, ipcEmit } = require("./utils/emitter"); + +let inputDevice; +let outputDevice; + +let setWriteId; +let setStreamsId; + +let autoStopId; /* keep track of recording time */ + +let playbackId; /* UID of the message being played */ + +const streamState = { rec: false, pb: false }; + +const /** @type {Int16Array[]} */ chunks = []; + +backgroundMitt.on("data", (int16Arr) => { + if (streamState.rec) chunks.push(int16Arr); +}); + +backgroundMitt.on("write", (int16Arr) => { + clearTimeout(setWriteId); + setWriteId = setTimeout(setPlaybackStatus.prototype.bind(null, false), 500); +}); + +function setStreams() +{ + const defaultInput = nodeAudio.core.GetDefaultInputDevice(); + const defaultOutput = nodeAudio.core.GetDefaultOutputDevice(); + + if (inputDevice !== defaultInput) + { + inputDevice = defaultInput; + nodeAudio.core.CloseInputStream(inputDevice); + nodeAudio.core.OpenInputStream(inputDevice); + } + + if (outputDevice !== defaultOutput) + { + outputDevice = defaultOutput; + nodeAudio.core.CloseOutputStream(outputDevice); + nodeAudio.core.OpenOutputStream(outputDevice); + } +} + +function startRecording() +{ + setRecordingStatus(true); + + /* 15s recording time limit */ + autoStopId = setTimeout(stopRecording, 15000); +} + +function stopRecording() +{ + if (autoStopId) + { + clearTimeout(autoStopId); + } + + setRecordingStatus(false); + + sendMessage({ + category: "audio/L16", + text: null, + blob: encode(nodeAudio.utils.mergeChunks(chunks).buffer) + }); + + chunks.length = 0; +} + +function initAudio() +{ + nodeAudio.core.Initialize(backgroundMitt.emit.bind(backgroundMitt)); + setStreamsId = setInterval(setStreams, 2000); + + const res = globalShortcut.register('CommandOrControl+Return', () => { + streamState.rec ? stopRecording() : startRecording(); + }); + + if (!res) throw new Error("Failed to register recording shortcut"); +} + +function playback(base64String, id) +{ + /* terminate any current playback */ + nodeAudio.core.CancelPlayback(); + ipcEmit("playback", playbackId, false); + + playbackId = id; + setPlaybackStatus(true); + nodeAudio.core.WriteToOutputStream(decode(base64String)); +} + +function terminateAudio() +{ + globalShortcut.unregisterAll(); + + /* Only terminate PA if initialized */ + if (setStreamsId) + { + clearInterval(setStreamsId); + nodeAudio.core.Terminate(); + } +} + +function setRecordingStatus(status) +{ + streamState.rec = status; + ipcEmit("record", status); + updateTray("recording", streamState.rec); +} + +function setPlaybackStatus(status) +{ + console.log("Setting playback status: ", status); + + streamState.pb = status; + ipcEmit("playback", playbackId, status); + updateTray("playback", status); +} + +exports.initAudio = initAudio; +exports.terminateAudio = terminateAudio; +exports.playback = playback; +exports.streamState = streamState; + + +// setWriteId = setTimeout(() => { +// setPlaybackStatus(false); +// }, 500); diff --git a/src/audio.ts b/src/audio.ts deleted file mode 100644 index 7ae2562..0000000 --- a/src/audio.ts +++ /dev/null @@ -1,187 +0,0 @@ -/* eslint @typescript-eslint/no-var-requires: "off" */ - -"use strict"; - -// where the audio goes -let buffer: ArrayBuffer[] = []; - -// place audio data in buffer -export const collect: IpcListenerCallback = (chunk) => { - if (chunk) buffer.push(chunk); -} - -// return audio and clear buffer -export const flush = async () => { - const bufferCopy = buffer; - buffer = []; - return bufferCopy; -} - -// import { backgroundMitt } from '@/modules/emitter'; -// const portAudio = require('naudiodon'); - -// // Audio in and out stream objects. -// let ai: typeof portAudio.AudioIO | boolean = false; -// let ao: typeof portAudio.AudioIO | boolean = false; - -// // Whether activly recording. -// let record = false; - -// const audioContainer = { -// input: '', -// } - -// const audioOptions = { -// channelCount: 1, -// sampleFormat: 16, -// sampleRate: 16000, -// deviceId: -1, -// closeOnError: false, -// } - -// export const toggleRecord = (): void => { record = !record }; - - -// export const fetchAudioInput = (): Promise => ( - -// new Promise((resolve, reject) => { - -// try { -// resolve(audioContainer.input); -// toggleRecord(); -// } catch (e) { -// reject(new Error('Failed to fetch the audio.')) -// } - -// }) -// ) - - -// // Main audio function run by run.ts module. -// export function initAudioIO(): void { -// console.log("AUDIO:Starting io streams.") - -// if (!ai) { - -// // Initialize and start input stream. -// ai = new portAudio.AudioIO({ inOptions: audioOptions }); -// ai.setEncoding("hex"); -// ai.start(); - -// // On each data chunk... -// ai.on('data', (chunk: string) => { - -// // If recording, we capture the data. -// if (record) { -// console.log('AUDIO:Recording...') -// audioContainer.input += chunk; -// } - -// // Else, we don't capture and also clear audioContainer. -// else { -// if (audioContainer.input.length) { -// audioContainer.input = ""; -// } -// } - -// }); -// } - -// if (!ao) { - -// // Initialize and start input stream. -// ao = new portAudio.AudioIO({ outOptions: audioOptions }); -// ao.start(); - -// } -// } - - -// // ---Audio playback-------------------------------------------- - -// // Split Buffer into an array of len-sized Buffers. -// function bufSplit(buf: Buffer, len: number): Array { -// const chunks = []; -// let i = 0; -// let L = len; - -// while(i < buf.byteLength) { -// chunks.push(buf.slice(i, L)); -// i = L; -// L += len; -// } - -// return chunks; -// } - -// // Audio playback. -// export function play(input: string): void { - -// // Format the audio. -// const audio = bufSplit( -// Buffer.from(input as string, 'hex'), -// 8192 -// ); - -// // Called on end of write. -// const callback = () => { - -// // We stop audio playback anim. -// backgroundMitt.emit('ipc-renderer', { -// endpoint: 'stop-playback-anim' -// }); - -// } - -// write(); - -// // Iterate through audio array and write buffers to portAudio writable. -// function write() { -// let chunk: Buffer; -// let ok = true; -// let i = 0; - -// do { -// chunk = audio[i]; -// if (i === audio.length - 1) { -// // write last chunk. -// ao.write(chunk, null, callback); -// } else { -// // check for backpreassure. -// ok = ao.write(chunk, null); -// } -// i++; -// } while (i < audio.length && ok); - -// if (i < audio.length) { -// // Had to stop early! -// // Write some more once it drains. -// ao.once('drain', write); -// } -// } -// } - -// // ------------------------------------------------------------- - -// // Get's called on window close. -// export async function stopStream() { -// console.log("AUDIO:Stopping audio stream.") -// if (ai) { -// try { -// await ai.quit() -// } catch(e){ -// console.log('AUDIO: Failed to shutdown audio input.'); -// throw e; -// } -// } -// if (ao) { -// try { -// await ao.quit() -// } catch(e){ -// console.log('AUDIO: Failed to shutdown audio output.'); -// throw e; -// } -// } -// } - - diff --git a/src/auth.ts b/src/auth.ts deleted file mode 100644 index 14ed36a..0000000 --- a/src/auth.ts +++ /dev/null @@ -1,13 +0,0 @@ - -export const parseAuthRes = (authRes: any) => { - const token = authRes.headers['set-cookie'][0].split(";")[0].split("=")[1] as string; - const profile = authRes.data as Profile; - return { - token, - profile - } -}; - - - - diff --git a/src/codec.js b/src/codec.js new file mode 100644 index 0000000..3a9a8bf --- /dev/null +++ b/src/codec.js @@ -0,0 +1,13 @@ +const { ipcMain } = require("electron"); +const { encode, decode } = require("base64-arraybuffer"); + +ipcMain.handle("encode", (_e, arrayBuffer) => { + return encode(arrayBuffer); +}); + +ipcMain.handle("decode", (_e, b64string) => { + return decode(b64string); +}); + +exports.encode = encode; +exports.decode = decode; \ No newline at end of file diff --git a/src/composables/autoUpdate.ts b/src/composables/autoUpdate.ts deleted file mode 100644 index 1a6b780..0000000 --- a/src/composables/autoUpdate.ts +++ /dev/null @@ -1,31 +0,0 @@ -const { autoUpdater } = require('electron-updater'); - -let win: boolean; - -// Listen for window creation. -backgroundMitt.on('window-active', (state: boolean) => { - win = state; -}); - -// Auto updating. -autoUpdater.requestHeaders = { 'PRIVATE-TOKEN': 'mvvgWYwWnot4bisiQMh_' } - -autoUpdater.on('update-available', (info: any) => { - console.log(`Update available: ${info.version}`) -}) - -autoUpdater.on('update-downloaded', (info: any) => { - - const updateDialog = { - type: 'info', - buttons: ['Restart', 'Later'], - title: 'Application Update', - message: info.version, - detail: 'A new version has been downloaded. Restart the application to apply the updates.' - } - - dialog.showMessageBox(updateDialog).then((returnValue) => { - if (returnValue.response === 0) autoUpdater.quitAndInstall() - }) - -}) \ No newline at end of file diff --git a/src/composables/useEmitter.ts b/src/composables/useEmitter.ts deleted file mode 100644 index f95f328..0000000 --- a/src/composables/useEmitter.ts +++ /dev/null @@ -1,16 +0,0 @@ - -// Backend emitter -// -const EventEmitter = require('events'); -class BackgroundMitt extends EventEmitter { } - -export const backgroundMitt = new BackgroundMitt(); - -export const ipcEmit = (channel: string, payload: T) => { - backgroundMitt.emit('ipc-renderer', { - channel, - payload - }); -}; - - diff --git a/src/composables/useHttp.ts b/src/composables/useHttp.ts deleted file mode 100644 index 6b9ee56..0000000 --- a/src/composables/useHttp.ts +++ /dev/null @@ -1,51 +0,0 @@ - -import axios, { AxiosRequestConfig } from 'axios'; -import {config} from "@/config"; - -const baseURL = config.BUSINESS_URL + config.BUSINESS_PREFIX; - -interface Request { - endpoint: string; - query?: Record; - config?: Record; -} - -const makeQuery = (reqQuery: Record) => { - - let result = ''; - - result = '?' + Object.entries(reqQuery) - .map(([ key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`) - .join('&') - - return result; -}; - - -export default function useHttp() { - - const api = axios.create({ - baseURL, - withCredentials: true, - }); - - - const post = async (endpoint: string, payload?: Record): Promise => ( - await api.post(endpoint, payload) - ) - - - const get = async (req: Request) => { - - if (req.query) { - req.endpoint += makeQuery(req.query); - } - - const res = await api.get(req.endpoint, req.config); - return res; - }; - - return { - get, post - } -} diff --git a/src/composables/useIpcMain.ts b/src/composables/useIpcMain.ts deleted file mode 100644 index ebfc4bc..0000000 --- a/src/composables/useIpcMain.ts +++ /dev/null @@ -1,82 +0,0 @@ - -import { ipcMain, IpcMainInvokeEvent, IpcMainEvent } from "electron"; - -export class IpcHandler implements IIpcHandler { - - readonly channel: string; - - readonly _handlerCallback: IpcHandlerCallback; - - constructor(options: { - channel: string; - handlerCallback: IpcHandlerCallback; - }) { - this.channel = options.channel; - this._handlerCallback = options.handlerCallback; - } - - handle() { - this.remove(); - ipcMain.handle(this.channel, this._onInvoke); - } - - remove() { - ipcMain.removeHandler(this.channel); - } - - private _onInvoke = (_e: IpcMainInvokeEvent, payload?: string | null): Promise => { - - return new Promise(async (resolve, reject) => { - - console.log(`[IPC] Handle:${this.channel}`); - - try { - - const params = payload ? JSON.parse(payload) : null; - - const res = await this._handlerCallback(params); - - resolve(res as unknown as ReturnType); - - } catch(e) { - console.log(`[IPC] Error:${this.channel}`); - reject(e); - } - }); - } - -} - - -export class IpcListener implements IIpcListener { - - readonly channel: string; - - readonly _listenerCallback: IpcListenerCallback; - - constructor(options: { - channel: string; - listenerCallback: IpcListenerCallback; - }) { - this.channel = options.channel; - this._listenerCallback = options.listenerCallback; - } - - listen() { - this.remove(); - ipcMain.on(this.channel, this._onPost); - } - - remove() { - ipcMain.removeAllListeners(this.channel); - } - - private _onPost = (_e: IpcMainEvent, payload?: string | null): void => { - - console.log(`[IPC] Post: ${this.channel}`); - - const params = payload ? JSON.parse(payload) : null; - this._listenerCallback(params); - } - -} diff --git a/src/composables/useMessageCanvas.ts b/src/composables/useMessageCanvas.ts deleted file mode 100644 index c85f7ed..0000000 --- a/src/composables/useMessageCanvas.ts +++ /dev/null @@ -1,36 +0,0 @@ - - - -export default class Canvas { - - messages: Message[]; - - /* seed canvas with messages on init */ - constructor(messages: Message[]) { - this.messages = messages; - ipcEmit("seed-view", this.messages); - } - - /* add a new message to the canvas */ - add(message: Message) { - this.messages.push(message); - ipcEmit("update-view", message); - } - - /* update an existing message */ - update(message: Message) { - - /* get the target message */ - let target_message = this.messages.filter((m: Message) => { - return m.uid = message.uid; - })[0]; - - /* replace the target message */ - if (target_message) { - target_message = message; - ipcEmit("update-view", message); - } - - } - -} diff --git a/src/composables/useSaveToJSON.ts b/src/composables/useSaveToJSON.ts deleted file mode 100644 index 06ab4b9..0000000 --- a/src/composables/useSaveToJSON.ts +++ /dev/null @@ -1,13 +0,0 @@ - -import {config} from "@/config"; -import fs from 'fs'; - -export const saveToJson = (fileName: string, data: any) => { - - fs.writeFile(config.configPath + fileName, JSON.stringify(data), (err) => { - if (err) { - console.log("Error when saving to json.") - } - }) - -} diff --git a/src/composables/useWebsockets.ts b/src/composables/useWebsockets.ts deleted file mode 100644 index d1cfc02..0000000 --- a/src/composables/useWebsockets.ts +++ /dev/null @@ -1,89 +0,0 @@ - -"use strict"; - -import WebSocket from 'ws'; - - -const _connectionCheckTimeout = 4000; -const _reconnectTimeout = 1000; -let _connectionCheckInterval: ReturnType; - - -export default function useWebSockets( - messageCallback: (message: string) => void, - connectionStatusCallback: (alive: boolean) => void, -) { - - let socket: WebSocket; - - const send = async (data: Record): Promise => { - return new Promise((resolve, reject) => { - if (socket) { - if (socket.readyState === WebSocket.OPEN) { - socket.send(JSON.stringify(data)); - resolve(true); - } - } - reject(false); - }); - } - - const connect = (socketUrl: string, secret: string) => { - - // avoid setting multiple interval; - if (_connectionCheckInterval) clearInterval(_connectionCheckInterval); - - /* create a new socket */ - socket = new WebSocket(socketUrl); - - /* add event listeners */ - socket.on("open", () => { - - socket.send(JSON.stringify({key: secret})); - - // ping server - _connectionCheckInterval = setInterval(() => { - - socket.ping(null, true, (e: Error) => { - if (e) { - socket.close(); - connectionStatusCallback(false); - setTimeout(() => connect(socketUrl, secret), _reconnectTimeout); - } - }); - - }, _connectionCheckTimeout); - - }); - - socket.on("message", (event: WebSocket.MessageEvent) => { - console.log("message received", event); - messageCallback(event.toString()) - }); - - socket.on("close", (event: WebSocket.CloseEvent) => { - connectionStatusCallback(false); - clearInterval(_connectionCheckInterval); - if (!event.wasClean) { - setTimeout(() => connect(socketUrl, secret), _reconnectTimeout); - } - - }); - - socket.on("pong", () => connectionStatusCallback(true)); - - } - - const close = () => { - if (socket) { - socket.close(); - } - } - - return { - connect, - send, - close - }; - -} diff --git a/src/config.ts b/src/config.js similarity index 79% rename from src/config.ts rename to src/config.js index 855b1b2..adf5e22 100644 --- a/src/config.ts +++ b/src/config.js @@ -1,5 +1,4 @@ - -import { app } from "electron"; +const { app } = require("electron"); const env = process.env; @@ -9,9 +8,9 @@ const PLATFORM_IP = env.PLATFORM_IP || 'http://127.0.0.1'; const BUSINESS_PORT = env.BUSINESS_PORT || 3000; const BUSINESS_IP = env.BUSINESS_IP || 'http://127.0.0.1'; -export const config = { +module.exports = { PLATFORM_URL: `${PLATFORM_IP}:${PLATFORM_PORT}`, BUSINESS_URL: `${BUSINESS_IP}:${BUSINESS_PORT}`, BUSINESS_PREFIX: '/api', - configPath: app.getPath('userData') -} + configPath: app.getPath('userData'), +} \ No newline at end of file diff --git a/src/init.ts b/src/init.ts deleted file mode 100644 index 9a0fdf6..0000000 --- a/src/init.ts +++ /dev/null @@ -1,52 +0,0 @@ -/** - * Entry point for Crimata electron app. - * "Look on my Works, ye Mighty, and despair!" - */ - -"use strict"; - -import { app, protocol } from "electron"; -import createWindow from "./window"; -import main from "./main"; -import { backgroundMitt } from '@/composables/useEmitter'; - -console.log('Starting Crimata electron app.'); - -// Scheme must be registered before the app is ready -protocol.registerSchemesAsPrivileged([ - { scheme: "app", privileges: { secure: true, standard: true } } -]); - -const isDev = require('electron-is-dev'); - -let win: boolean; - -// Listen for window creation. -backgroundMitt.on('window-active', (state: boolean) => { - win = state; -}); - -/* Start main process on ready */ -app.on("ready", async () => { - await main(); -}); - -// Must keep to ensure app doesn't quit on close. -app.on("before-quit", async () => { -}); - -// Must keep to ensure app doesn't quit on close. -app.on("window-all-closed", () => { -}); - -// When user clicks app icon (re-open) -app.on("activate", () => { - if (!win) createWindow(); -}); - -// Exit cleanly on request from parent process in development mode. -if (isDev) { - process.on("SIGTERM", () => { - app.quit(); - }); -} diff --git a/src/io.js b/src/io.js new file mode 100644 index 0000000..a269d49 --- /dev/null +++ b/src/io.js @@ -0,0 +1,80 @@ +const WebSocket = require("ws"); +const { ipcMain } = require("electron"); + +const config = require("./config"); +const { updateTray } = require("./tray"); +const { backgroundMitt, ipcEmit } = require("./utils/emitter"); + +let connection = null; + +let pingId; +let reconnectId; + +function connectToPlatform(account) +{ + if (pingId) clearInterval(pingId); + + connection = new WebSocket(`${config.PLATFORM_URL}/${account}`) + + .on("open", () => pingId = setInterval(() => connection.ping(null, true), 1000)) + + .on("pong", () => setConnectionStatus(0)) + + .on("error", () => {}) /** keep silent on error */ + + .on("message", (payload) => backgroundMitt.emit("message", JSON.parse(payload))) + + .on("close", (code, reason) => { + setConnectionStatus(1); + if (reason !== "logout") { + reconnectId = setTimeout(() => connectToPlatform(account), 500); + } + }); +} + +function sendMessage(message) +{ + if (connection.readyState === WebSocket.OPEN) { + connection.send(JSON.stringify(message)); + } else console.log("Failed to send message"); +} + +function disconnectFromPlatform() +{ + clearTimeout(reconnectId); + connection.close(1000, "logout"); +} + +function setConnectionStatus(status) +{ + updateTray("disconnect", status); + ipcEmit("ws-status", status); +} + +ipcMain.on("message", (_e, message) => sendMessage(message)); + +exports.connectToPlatform = connectToPlatform; +exports.sendMessage = sendMessage; +exports.disconnectFromPlatform = disconnectFromPlatform; + + + +/* ------------- Test Messages------------- */ + + + +setTimeout(() => { + + // sendMessage({ + // category: "text/plain", + // text: "show contacts", + // blob: null + // }) + + sendMessage({ + category: "text/plain", + text: "add contact John Smith, john.smith97@gmail.com", + blob: null + }) + +}, 2000); diff --git a/src/ipc/handlers.ts b/src/ipc/handlers.ts deleted file mode 100644 index 5529662..0000000 --- a/src/ipc/handlers.ts +++ /dev/null @@ -1,28 +0,0 @@ - -"use strict"; - -import { accountLogin, accountLogout, accountProfile } from "@/account"; -import { IpcHandler } from "@/composables/useIpcMain"; -import { flush } from "@/audio"; - - -const LOGIN_CHANNEL = "invoke-account-login"; -const LOGOUT_CHANNEL = "invoke-account-logout"; -const GET_AUDIO_CHANNEL = "invoke-audio-flush"; - -export const loginHandler = new IpcHandler({ - channel: LOGIN_CHANNEL, - handlerCallback: accountLogin -}); - -export const logoutHandler = new IpcHandler({ - channel: LOGOUT_CHANNEL, - handlerCallback: accountLogout -}); - -export const getAudioHandler = new IpcHandler({ - channel: GET_AUDIO_CHANNEL, - handlerCallback: flush -}); - - diff --git a/src/ipc/index.ts b/src/ipc/index.ts deleted file mode 100644 index e6eb90a..0000000 --- a/src/ipc/index.ts +++ /dev/null @@ -1,33 +0,0 @@ - -"use strict"; - -import * as handlers from "./handlers"; -import * as listeners from "./listeners"; - -const ipcHandlers: IPCHandlers = {}; -const ipcListeners: IPCListeners = {}; - -const _initHandlers = (): void => { - for (const [key, handler] of Object.entries(handlers)) { - if (!(key in ipcHandlers)) { - ipcHandlers[key] = handler; - handler.handle(); - } - } -}; - -const _initListeners = (): void => { - for (const [key, listener] of Object.entries(listeners)) { - if (!(key in ipcListeners)) { - ipcListeners[key] = listener; - listener.listen(); - } - } -}; - -export default function initIpcMain(): void { - _initHandlers(); - _initListeners(); -} - - diff --git a/src/ipc/listeners.ts b/src/ipc/listeners.ts deleted file mode 100644 index 8ef5d45..0000000 --- a/src/ipc/listeners.ts +++ /dev/null @@ -1,24 +0,0 @@ - -import { IpcListener } from "@/composables/useIpcMain" -import { sendMessage } from '@/session'; -import { collect } from "@/audio"; -import { updateAppState } from "@/account"; - -const CLIENT_MESSAGE_CHANNEL = "post-session-send" -const GET_AUDIO_CHANNEL = "post-audio-collect"; -const APP_MOUNT_CHANNEL = "post-app-mount"; - -export const messageListener = new IpcListener({ - channel: CLIENT_MESSAGE_CHANNEL, - listenerCallback: sendMessage -}); - -export const audioChunkListener = new IpcListener({ - channel: GET_AUDIO_CHANNEL, - listenerCallback: collect -}); - -export const appMountListener = new IpcListener({ - channel: APP_MOUNT_CHANNEL, - listenerCallback: updateAppState -}); diff --git a/src/main.js b/src/main.js new file mode 100644 index 0000000..841579e --- /dev/null +++ b/src/main.js @@ -0,0 +1,29 @@ +const { app, protocol, ipcMain, nativeTheme } = require("electron"); + +const store = require("./utils/store"); + +const { initTray } = require("./tray"); +const { postLogin } = require("./api"); +const { createWin } = require("./window"); +const { initAccount } = require("./account"); +const { terminateAudio } = require("./audio"); + +// Assert a light theme +nativeTheme.themeSource = "light"; + +app.on("ready", () => +{ + initTray(); + + createWin(); + + initAccount(); +}); + +// app.on("will-quit", terminateAudio); + +// When user clicks app icon (re-open) +app.on("activate", createWin); + +// Prevents app from quitting on window close event +app.on('window-all-closed', (e) => e.preventDefault()); \ No newline at end of file diff --git a/src/main.ts b/src/main.ts deleted file mode 100644 index a360835..0000000 --- a/src/main.ts +++ /dev/null @@ -1,39 +0,0 @@ -/** - * Where the background logic really begins, gets called by app.onReady(). - * - * Handles authentication. If profile is set, we launch a session, which consis - * of opening a connection with the platform, initializing the audio streams. - * - * The session is primarily an interface between the frontend and the platform, - * relaying messages from one to the other. - * - */ - -import initIpcMain from "@/ipc/index"; -import { accountAuth, updateAppState } from "./account"; -import { launchSession } from "./session"; -import createWindow from "./window"; - -let authState: AuthState | null; - -export default async function main() { - - /* initiate controls for frontend to use when needed */ - initIpcMain(); - - /* launch browser window */ - await createWindow(); - - try { - authState = await accountAuth() as AuthState; - } catch(e) { - console.log('AUTH:', e); - authState = null; - } finally { - if (authState) { - launchSession(authState.token as string); - } - updateAppState(); - } - -} diff --git a/src/preview.html b/src/preview.html new file mode 100644 index 0000000..8c8fc48 --- /dev/null +++ b/src/preview.html @@ -0,0 +1,52 @@ + + + + + + + + + + +
+ + + + + diff --git a/src/render/App.vue b/src/render/App.vue deleted file mode 100644 index 686591b..0000000 --- a/src/render/App.vue +++ /dev/null @@ -1,76 +0,0 @@ - - - - - diff --git a/src/render/assets/connectLogo.svg b/src/render/assets/connectLogo.svg new file mode 100644 index 0000000..7a390a4 --- /dev/null +++ b/src/render/assets/connectLogo.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/src/render/assets/settingsIcon.svg b/src/render/assets/settingsIcon.svg new file mode 100644 index 0000000..25399f5 --- /dev/null +++ b/src/render/assets/settingsIcon.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/src/render/components/app.js b/src/render/components/app.js new file mode 100644 index 0000000..08909a6 --- /dev/null +++ b/src/render/components/app.js @@ -0,0 +1,42 @@ +import Splash from "./splash.js"; +import Messenger from "./messenger.js"; +import Login from "./login.js"; + +const account = Vue.ref(null); + +const App = +{ + components: { + Splash, + Messenger, + Login + }, + + setup() + { + return { account }; + }, + + template: ` +
+ +
+ + ` +} + +window.mainApi.on("set-account", (account_) => { + console.log("setting-account"); + account.value = account_; +}); + +export default App; +export { account }; + +// Is called when window is about to close or reload +window.onbeforeunload = () => console.log("beforeUnload"); \ No newline at end of file diff --git a/src/render/components/bubble.js b/src/render/components/bubble.js new file mode 100644 index 0000000..16f7983 --- /dev/null +++ b/src/render/components/bubble.js @@ -0,0 +1,36 @@ +const Bubble = +{ + props: ["category", "text", "blob", "modifier", "child"], + + setup(props) + { + const getUrl = () => { + return `data:${props.category};base64,${props.blob}`; + } + + Vue.onMounted(() => { + document.getElementById("messenger").dispatchEvent(new CustomEvent('adjust-scroll')); + }); + + return { getUrl }; + }, + + template: ` +
+ +

{{ text }}

+ +

{{ text }}

+ +
+ + + + {{ text }} + +
` +}; + +export default Bubble; + +// TODO: should include other styling/actions for audio bubbles \ No newline at end of file diff --git a/src/render/components/bubble.vue b/src/render/components/bubble.vue deleted file mode 100644 index 982cef3..0000000 --- a/src/render/components/bubble.vue +++ /dev/null @@ -1,331 +0,0 @@ - - - - - - - diff --git a/src/render/components/context.js b/src/render/components/context.js new file mode 100644 index 0000000..b6879ae --- /dev/null +++ b/src/render/components/context.js @@ -0,0 +1,38 @@ + +const Context = +{ + props: ["modifier", "context", "avatar", "id"], + + setup(props) { + const playback = Vue.ref(false); + + Vue.onMounted(() => { + window.mainApi.on("playback", (id, status) => { + if (id === props.id) { + playback.value = status; + } + }); + }); + + return { playback }; + }, + + template: ` + + +
+ + + +
+ + {{ context }} + +
` +} + +export default Context; diff --git a/src/render/components/control/draggify.js b/src/render/components/control/draggify.js new file mode 100644 index 0000000..f85b930 --- /dev/null +++ b/src/render/components/control/draggify.js @@ -0,0 +1,198 @@ +const saveLocation = "input_item_position"; +const defaultPosition = { x: 15, y: window.innerHeight - 300 }; + +//---Dragabble Helper Funcs-------------------------------------- + +// Calculate distance to nearest side. +function calcSideProximity (elementX, elementLength, winW) { + + // Calc right short. + let short = winW - elementX - elementLength; + + // See if it's left short. + if (elementX + 20 < winW / 2) { + short = elementX + } + + return short +} + +// Update elementX or elementY value on window resize +function calcPosition (elementPosition, elementLength, percent, short, win) { + + // Is it close to the right/bottom side? + if (percent > 0.75) { + elementPosition = win - short - elementLength; + } + + // Is it not close to a side? + if (percent < 0.75 && percent > 0.25) { + elementPosition = win * percent + } + + return elementPosition +} + +function draggify(elementId, margin) { + + let element; + + /* only compatible with elements having equal width and height */ + let elementLength; + + // Cords of inputItem. + const elementX = Vue.ref(); + const elementY = Vue.ref(); + + // Position of inputItem on terms of percentage of window. + let percentX; + let percentY; + + // How close inputItem is to closest X or Y side. + let xShort; + let yShort; + + // Keep track of window size; + let winW = window.innerWidth; + let winH = window.innerHeight; + + //---Reposition Anime----------------------------------------------- + + // Move element to target smoothly. + const repositionAnime = (xChange, yChange) => { + const xStep = xChange / 6000; + const yStep = yChange / 6000; + + for (let i = 1; i <= 6000; i++) { + + setTimeout(() => { + elementX.value += xStep; + elementY.value += yStep; + }, 16) // 60fps + + } + } + + //---Event Handlers----------------------------------------------- + + // Update the position of inputItem on mouse dragging. + const onMouseMove = (e) => { + e.preventDefault(); + + const inputItemRect = element.getBoundingClientRect(); + elementX.value = inputItemRect.left + e.movementX; + elementY.value = inputItemRect.top + e.movementY; + } + + // Add an event listener for dragging. + const onMouseDown = (e) => { + e.preventDefault(); + window.addEventListener('mousemove', onMouseMove); + window.addEventListener('mouseup', onMouseUp); + } + + // Update position references when user is done moving targetEl. + const onMouseUp = (e) => { + e.preventDefault(); + + window.removeEventListener('mousemove', onMouseMove); + window.removeEventListener('mouseup', onMouseUp); + + // See if and calculate reposition. + let x = 0; // vector change + let y = 0; + + if (elementX.value < 0) { + x = (elementX.value - margin)*-1 + } + + if (elementX.value > winW - elementLength) { + const b = winW - elementLength - margin; + x = (elementX.value - b)*-1 + } + + // Reposition y + if (elementY.value < 0) { + y = (elementY.value - margin)*-1 + } + + if (elementY.value > winH - elementLength) { + const d = winH - elementLength - margin; + y = (elementY.value - d)*-1 + } + + // Reposition if needed. + if (x !== 0 || y !== 0) repositionAnime(x, y); + + xShort = calcSideProximity(elementX.value, elementLength, winW); + yShort = calcSideProximity(elementY.value, elementLength, winH); + + // Update percentages. + percentX = elementX.value / winW; + percentY = elementY.value / winH; + + // Save position. + savePosition(); + } + + // Update position of targetEl on windowResize. + const onWindowResize = (_e) => { + + // Update window dimensions. + winW = window.innerWidth; + winH = window.innerHeight; + + elementX.value = calcPosition(elementX.value, elementLength, percentX, xShort, winW); + elementY.value = calcPosition(elementY.value, elementLength, percentY, yShort, winH); + + savePosition(); + } + + const savePosition = () => { + window.localStorage.setItem(saveLocation, JSON.stringify({ + x: elementX.value, + y: elementY.value + })); + } + + //--------------------------------------------------------------- + + Vue.onMounted(() => { + + element = document.getElementById(elementId); + + elementLength = element.offsetWidth; + + // Initialize the positional references. + percentX = elementX.value / window.innerWidth; + percentY = elementY.value / window.innerHeight; + + xShort = calcSideProximity(elementX.value, elementLength, window.innerWidth); + yShort = calcSideProximity(elementX.value, elementLength, window.innerHeight); + + // Then, we can listen for window resize (and mousedown). + element.addEventListener("mousedown", onMouseDown); + window.addEventListener('resize', onWindowResize) + }); + + // remove event listeners on component dismount. + Vue.onUnmounted(() => { + element.removeEventListener('mousedown', onMouseDown); + window.removeEventListener('resize', onWindowResize) + window.removeEventListener('mouseup', onMouseUp) + window.removeEventListener('mousemove', onMouseMove); + }); + + // Try loading initPosition, otherwise set default values + let initPosition; + const rawData = window.localStorage.getItem("saveLocation") + rawData ? initPosition = JSON.parse(rawData) : initPosition = defaultPosition; + + elementX.value = initPosition.x; + elementY.value = initPosition.y; + + return { elementX, elementY }; + +} + +export default draggify; diff --git a/src/render/components/control/scroll.js b/src/render/components/control/scroll.js new file mode 100644 index 0000000..4666ea1 --- /dev/null +++ b/src/render/components/control/scroll.js @@ -0,0 +1,24 @@ +let el; + +const initScroll = (elementId) => { + el = document.getElementById(elementId); + el.addEventListener('adjust-scroll', adjustScroll); + window.addEventListener('resize', adjustScroll); +} + +const isBottom = () => { + if (el) { + return el.scrollHeight - el.clientHeight <= el.scrollTop + 1; + } +} + +const adjustScroll = () => { + if (el) { + el.scrollTo({ + top: el.scrollHeight - el.clientHeight, + behavior: 'smooth' + }); + } +} + +export default initScroll; \ No newline at end of file diff --git a/src/render/components/control/text.js b/src/render/components/control/text.js new file mode 100644 index 0000000..626746f --- /dev/null +++ b/src/render/components/control/text.js @@ -0,0 +1,76 @@ +const inputLength = 230; + +const metaKeys = [ + "Tab", + "CapsLock", + "Shift", + "Control", + "Alt", + "Meta", + " ", + "ArrowLeft", + "ArrowRight", + "ArrowUp", + "ArrowDown", + "Enter", + "Backspace", + "Escape" +]; + +function useText(elementId, left, typing) +{ + let el; + + const show = Vue.ref(false); + const leftSide = Vue.ref(false); + + const calcSide = () => { + window.innerWidth - left.value < inputLength ? leftSide.value = true : leftSide.value = false; + } + + /* handle user typing */ + Vue.onMounted(() => { + + el = document.getElementById(elementId); + + window.addEventListener("keydown", (e) => { + + if (!show.value && !metaKeys.includes(e.key)) + { + show.value = true; + } + else if (show.value && ((el.value.length === 1 && e.key === "Backspace") || e.key === "Escape")) + { + show.value = false; + } + + if (e.key === "Enter" && el.value) + { + window.mainApi.send("message", { + category: "text/plain", + text: el.value, + blob: null + }); + show.value = false; + } + }); + + }); + + Vue.watch(left, calcSide); + + Vue.watch(show, (c, _p) => { + if (c) { + el.focus(); + } else { + el.value = ""; + el.blur(); + } + }); + + calcSide(); + + return { leftSide, show }; +} + +export default useText; diff --git a/src/render/components/controllers/bubble.control.ts b/src/render/components/controllers/bubble.control.ts deleted file mode 100644 index e69de29..0000000 diff --git a/src/render/components/controllers/helpers.ts b/src/render/components/controllers/helpers.ts deleted file mode 100644 index 23976a8..0000000 --- a/src/render/components/controllers/helpers.ts +++ /dev/null @@ -1,102 +0,0 @@ -import { ref } from "vue"; -import anime from "animejs"; -import { v4 as uuidv4 } from 'uuid'; - - -export function animateTextInput () { - - const side = ref("right"); - - function show () { - const t1 = (side.value === "right") ? 50 : -70; - const t2 = (side.value === "right") ? 110 : -130; - - anime({ - targets: '#textInput', - opacity: [0, 1], - translateX: [t1, t2], - scale: [0.3, 1], - duration: 500, - easing: 'easeOutExpo', - }) - - } - - function hide () { - const t = (side.value === "right") ? 50 : -80; - - anime({ - targets: '#textInput', - opacity: [1, 0], - translateX: t, - scale: 0.3, - duration: 500, - easing: 'easeOutExpo', - }) - - } - - function switchSide () { - const t = (side.value === "right") ? -130 : 110; - - anime({ - targets: '#textInput', - translateX: t, - duration: 500, - easing: 'easeOutExpo', - }) - - } - - return { - side, - show, - hide, - switchSide - }; - -} - -export function animateAudioInput () { - - function show () { - anime({ - targets: '#recIcon', - opacity: [0, 0.75], - scale: [0.0, 1], - duration: 250, - easing: 'linear', - }) - } - - function hide () { - anime({ - targets: '#recIcon', - opacity: [0.75, 0], - scale: [1, 0], - duration: 250, - easing: 'linear', - }) - } - - return { - show, - hide - }; - -} - - -export function newMessage ({ - text=false, - audio=false, - context=false, - uid=uuidv4() -}) { - return { - text: text, - audio: audio, - context: context, - uid: uid - }; -} diff --git a/src/render/components/controllers/inputItem.control.audio.ts b/src/render/components/controllers/inputItem.control.audio.ts deleted file mode 100644 index facf30c..0000000 --- a/src/render/components/controllers/inputItem.control.audio.ts +++ /dev/null @@ -1,77 +0,0 @@ -import { onMounted, onUnmounted, ref, Ref } from "vue"; -import { postMessage } from "@/render/ipc"; -import { newMessage, animateAudioInput } from "./helpers"; -import { invokeReturnAudio, postAudioChunk } from "@/render/ipc"; - -export default function useAudioInputController (typing: Ref) { - - const recording = ref(false); - let mediaRecorder: MediaRecorder; - - const { show, hide } = animateAudioInput(); - - // initialize audio - const conf = {audio: true, video: false} - navigator.mediaDevices.getUserMedia(conf).then((stream: MediaStream) => { - - const options = {mimeType: 'audio/webm'}; - mediaRecorder = new MediaRecorder(stream, options); - - // post any mew audio to backend - mediaRecorder.addEventListener('dataavailable', (e: BlobEvent) => { - e.data.arrayBuffer().then((buff: ArrayBuffer) => { - postAudioChunk(buff); - }); - }); - - // get audio and post new message to backend - mediaRecorder.addEventListener('stop', (_e: Event) => { - invokeReturnAudio().then((audio: ArrayBuffer[] | Error) => { - console.log(audio); - // postMessage(newMessage({audio: audio})); - }); - }); - - }); - - // start recording on space bar - const record = () => { - console.log("INPT:Capturing audio...") - mediaRecorder.start(); - recording.value = true; - show() - } - - // stop recording and send on release - const stop = () => { - console.log("INPT:Stopping record.") - mediaRecorder.stop(); - recording.value = false; - hide(); - } - - const onKeyDown = (e: KeyboardEvent) => { - if (e.keyCode == 32 && !typing.value) record(); - } - - const onKeyUp = (e: KeyboardEvent) => { - if (e.keyCode == 32 && recording.value) stop(); - } - - //----------------------------------------------------------- - - onMounted(() => { - window.addEventListener("keydown", onKeyDown); - window.addEventListener("keyup", onKeyUp); - }); - - onUnmounted(() => { - window.removeEventListener("keydown", onKeyDown); - window.removeEventListener("keyup", onKeyUp); - }) - - return { - recording - } - -} diff --git a/src/render/components/controllers/inputItem.control.text.ts b/src/render/components/controllers/inputItem.control.text.ts deleted file mode 100644 index 941ae89..0000000 --- a/src/render/components/controllers/inputItem.control.text.ts +++ /dev/null @@ -1,134 +0,0 @@ -import { Ref, ref, watch, onMounted, onUnmounted } from "vue"; -import { postMessage } from "@/render/ipc"; -import { newMessage, animateTextInput } from "./helpers"; - - -export default function useTextInputController(elementX: Ref) { - - let textInput: HTMLInputElement | null; - - const { side, show, hide, switchSide } = animateTextInput(); - - let firstKey = true; - const typing = ref(false); - - // Prep inputItem for typing. - const prepInput = () => { - show() - typing.value = true - } - - // Clear and hide inputItem after done typing. - const clearInput = () => { - - if (textInput) { - textInput.value = ""; - textInput.blur(); - } - - hide() - firstKey = true; - typing.value = false; - } - - // Send a message and clean up after. - const sendMessage = () => { - if (textInput) { - - // Send it to the backend for processing. - const message = newMessage({ - text: false - }); - - // postMessage(message); - - clearInput() - } - } - - // Keys that are capable of opening the text input (numbers and letters). - const isHotKey = (key: number) => { - if (key >= 47 && key <= 91) { // a letter - return true - } - } - - //---Callbacks----------------------------------------------- - - const onKeyDown = (e: KeyboardEvent) => { - const key = e.keyCode; - - if (textInput) { - - // Only runs on firstKey. - if (firstKey) { - - if (!isHotKey(key)) { - return - } - - prepInput() - } - - textInput.focus(); - - // Close input when no text or on ESC. - if ((textInput.value == "") && (!firstKey) && (key === 8)) { // backspace - clearInput() - return - } - - if (key === 27) { // escape - clearInput() - return - } - - // Close and send on enter. - if (key === 13) { - if (textInput.value) { - sendMessage() - return - } - } - - if (firstKey) firstKey = false - } - } - - //----------------------------------------------------------- - - // Watch parent position and update side. - watch(elementX, (elementX, _previous) => { - const winW = window.innerWidth - - // Logic depends on the side we are on. - if (side.value === "right") { - if (winW - elementX < 230) { - switchSide() - side.value = "left" - } - } - - else { - if (winW - elementX > 230) { - switchSide() - side.value = "right" - } - } - - }); - - onMounted(() => { - textInput = document.getElementById("textInput") as HTMLInputElement; - window.addEventListener("keydown", onKeyDown); - }) - - onUnmounted(() => { - window.removeEventListener("keydown", onKeyDown); - }); - - return { - typing - } - -} diff --git a/src/render/components/controllers/messenger.control.ts b/src/render/components/controllers/messenger.control.ts deleted file mode 100644 index b9c3a96..0000000 --- a/src/render/components/controllers/messenger.control.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { ref } from 'vue'; -import useScroll from "@/render/composables/useScroll"; - -const messagesRef = ref(); - -/* seed the canvas with messages */ -const seedCanvas = (messages: Message[]) => { - messagesRef.value = messages; -} - -const addMessage = (message: Message) => { - messagesRef.value.push(message); -} - -const updateMessage = (message: Message) => { - - let target_message = messagesRef.value.filter((m: Message) => { - return m.uid = message.uid; - })[0]; - - if (target_message) { - target_message = message; - } - -} - -export default function useMessages() { - - const { updateScrollRef, adjustScroll } = useScroll("messenger"); - - return { - messagesRef, - seedCanvas, - addMessage, - updateMessage - }; - -} diff --git a/src/render/components/header.js b/src/render/components/header.js new file mode 100644 index 0000000..0851a69 --- /dev/null +++ b/src/render/components/header.js @@ -0,0 +1,23 @@ +const Header = +{ + setup() { + const onNavBar = (command) => window.mainApi.send('nav-bar', command); + return { onNavBar }; + }, + + template: ` + + + ` +} + +/** Shake a div to indicate incorrect credentials */ +const shake = (elementId) => +{ + const el = document.getElementById(elementId); + + if (el) + el.classList.remove("shake"); + + setTimeout(() => { + if (el) el.classList.add("shake"); + }, 250); +} + +export default Login; \ No newline at end of file diff --git a/src/render/components/login.vue b/src/render/components/login.vue deleted file mode 100644 index bece6ea..0000000 --- a/src/render/components/login.vue +++ /dev/null @@ -1,180 +0,0 @@ - - - - - diff --git a/src/render/components/message.js b/src/render/components/message.js new file mode 100644 index 0000000..fd1b41c --- /dev/null +++ b/src/render/components/message.js @@ -0,0 +1,60 @@ +import Bubble from "./bubble.js"; +import Context from "./context.js"; + +const Message = +{ + components: { + Bubble, + Context + }, + + props: ["modifier", "content", "context", "avatar", "id"], + + setup(props) + { + return { calcChild }; + }, + + template: ` +
+ + + + + +
` +} + +function calcChild(index, len) +{ + if (len === 1) + { + return "none-child"; + } + else if (index === 0) + { + return "first-child"; + } + else if (index === len - 1) + { + return "last-child"; + } + else + { + return "middle-child"; + } +} + +export default Message; diff --git a/src/render/components/messenger.js b/src/render/components/messenger.js new file mode 100644 index 0000000..668b505 --- /dev/null +++ b/src/render/components/messenger.js @@ -0,0 +1,102 @@ +import initScroll from "./control/scroll.js"; + +import WS from "./ws.js"; +import Input from "./input.js"; +import Settings from "./settings.js"; +import Message from "./message.js"; + +const Messenger = { + + components: { + WS, + Settings, + Message, + Input + }, + + setup() + { + const person = Vue.ref(""); + const messages = Vue.ref([{ + modifier: "ai", + content: [{ + category: "text/html", + text: `
+

About HTML Parser

+

Return the text of the most recently opened start tag. This should not normally be needed for structured processing, but may be useful in dealing with HTML “as deployed” or for re-generating input with minimal changes (whitespace between attributes can be preserved, etc.).

+
`, + blob: null + }], + context: "Email from David Spade", + avatar: null, + id: 0 + }]); + + const onDrop = async (e) => { + const file = e.dataTransfer.items[0].getAsFile(); + + const buffer = await file.arrayBuffer(); + const b64String = await window.mainApi.invoke("encode", buffer); + + window.mainApi.send("message", { + category: file.type, + text: file.name, + blob: b64String + }); + } + + Vue.onMounted(() => { + + window.mainApi.on("message", (message) => { + if (message.person) + { + person.value = message.person; + messages.value = message.messages; + } + else if (message.name) + { + person.value = message; + } + else if (message.content) + { + messages.value.push(message); + } + else + { + messages.value[messages.value.length - 1].content.push(message); + } + }); + + initScroll("messenger"); + window.mainApi.send("messenger"); + }); + + Vue.onUnmounted(() => { + messages.value = []; + }); + + return { person, messages, onDrop }; + }, + + template: ` + + + + +
+ +
` +} + +export default Messenger; diff --git a/src/render/components/messenger.vue b/src/render/components/messenger.vue deleted file mode 100644 index ee56549..0000000 --- a/src/render/components/messenger.vue +++ /dev/null @@ -1,82 +0,0 @@ - - - - - diff --git a/src/render/components/settings.js b/src/render/components/settings.js new file mode 100644 index 0000000..68d69f2 --- /dev/null +++ b/src/render/components/settings.js @@ -0,0 +1,28 @@ + +const Settings = +{ + setup() { + const active = Vue.ref(false); + + window.addEventListener("keydown", (e) => { + console.log("toggle settings"); + }) + + const logout = async () => { + await window.mainApi.send("logout"); + } + + return { active, logout }; + }, + + template: ` +
+ + + +
` +} + +export default Settings; \ No newline at end of file diff --git a/src/render/components/settings.vue b/src/render/components/settings.vue deleted file mode 100644 index cf881c3..0000000 --- a/src/render/components/settings.vue +++ /dev/null @@ -1,164 +0,0 @@ - - - - - - diff --git a/src/render/components/splash.js b/src/render/components/splash.js new file mode 100644 index 0000000..220eaad --- /dev/null +++ b/src/render/components/splash.js @@ -0,0 +1,50 @@ +const Splash = +{ + template: ` +
+ + + + + + + + + + + + + + +
+ ` +} + +export default Splash; \ No newline at end of file diff --git a/src/render/components/splash.vue b/src/render/components/splash.vue deleted file mode 100644 index 247847a..0000000 --- a/src/render/components/splash.vue +++ /dev/null @@ -1,69 +0,0 @@ - - - - - diff --git a/src/render/components/ws.js b/src/render/components/ws.js new file mode 100644 index 0000000..189b03d --- /dev/null +++ b/src/render/components/ws.js @@ -0,0 +1,35 @@ + +const WS = +{ + setup() + { + const status = Vue.ref(); + + Vue.onMounted(() => { + + window.mainApi.on("ws-status", (val) => { + status.value = val; + }); + + }); + + return { status } + }, + + template: ` +
+ + + +
+
+
+ +
` +} + +export default WS; \ No newline at end of file diff --git a/src/render/composables/useDraggify.ts b/src/render/composables/useDraggify.ts deleted file mode 100644 index f3d8978..0000000 --- a/src/render/composables/useDraggify.ts +++ /dev/null @@ -1,199 +0,0 @@ -import { onMounted, ref, onUnmounted } from "vue"; - -//---Dragabble Helper Funcs-------------------------------------- - -// Calculate distance to nearest side. -function calcSideProximity (elementX: number, winW: number) { - - // Calc right short. - let short = winW - elementX - 40; - - // See if it's left short. - if (elementX + 20 < winW / 2) { - short = elementX - } - - return short -} - -// Update elementX or elementY value on window resize -function calcPosition (elementPosition: number, percent: number, - short: number, win: number) { - - // Is it close to the right/bottom side? - if (percent > 0.75) { - elementPosition = win - short - 40; - } - - // Is it not close to a side? - if (percent < 0.75 && percent > 0.25) { - elementPosition = win * percent - } - - return elementPosition -} - -export default function draggify(elementId: string, xStart: number, - yStart: number, margin: number) { - - let element: HTMLElement | null; - - // Cords of inputItem. - const elementX = ref(0); - const elementY = ref(0); - - // Position of inputItem on terms of percentage of window. - let percentX: number; - let percentY: number; - - // How close inputItem is to closest X or Y side. - let xShort: number; - let yShort: number; - - // Keep track of window size; - let winW = window.innerWidth; - let winH = window.innerHeight; - - //---Reposition Anime----------------------------------------------- - - // Move element to target smoothly. - const repositionAnime = (xChange: number, yChange: number) => { - const xStep = xChange / 6000; - const yStep = yChange / 6000; - - for (let i = 1; i <= 6000; i++) { - - setTimeout(() => { - elementX.value += xStep; - elementY.value += yStep; - }, 16) // 60fps - - } - } - - //---Event Handlers----------------------------------------------- - - // Update the position of inputItem on mouse dragging. - const onMouseMove = (e: any) => { - e.preventDefault() - element = document.getElementById(elementId); - - if (element) { - const inputItemRect = element.getBoundingClientRect(); - elementX.value = inputItemRect.left + e.movementX; - elementY.value = inputItemRect.top + e.movementY; - } - - } - - // Add an event listener for dragging. - const onMouseDown = (_e: any) => { - _e.preventDefault() - window.addEventListener('mousemove', onMouseMove, true); - } - - // Update position references when user is done moving targetEl. - const onMouseUp = (_e: any) => { - window.removeEventListener('mousemove', onMouseMove, true); - - // See if and calculate reposition. - let x = 0; // vector change - let y = 0; - - if (elementX.value < 0) { - x = (elementX.value - margin)*-1 - } - - if (elementX.value > winW - 40) { - const b = winW - 40 - margin; - x = (elementX.value - b)*-1 - } - - // Reposition y - if (elementY.value < 0) { - y = (elementY.value - margin)*-1 - } - - if (elementY.value > winH - 40) { - const d = winH - 40 - margin; - y = (elementY.value - d)*-1 - } - - // Reposition if needed. - if (x !== 0 || y !== 0) repositionAnime(x, y); - - xShort = calcSideProximity(elementX.value, winW); - yShort = calcSideProximity(elementY.value, winH); - - // Update percentages. - percentX = elementX.value / winW; - percentY = elementY.value / winH; - - // Save position. - const position = { - x: elementX.value, - y: elementY.value - } - window.localStorage.setItem("inputItem_position", JSON.stringify(position)); - } - - // Update position of targetEl on windowResize. - const onWindowResize = (_e: any) => { - - // Update window dimensions. - winW = window.innerWidth; - winH = window.innerHeight; - - elementX.value = calcPosition(elementX.value, percentX, xShort, winW); - elementY.value = calcPosition(elementY.value, percentY, yShort, winH); - - } - - //--------------------------------------------------------------- - - onMounted(() => { - element = document.getElementById(elementId); - - if (element) { - element.addEventListener('mousedown', onMouseDown, false); - } - - window.addEventListener("mouseup", onMouseUp, false); - - // Initialize the positional references. - percentX = elementX.value / window.innerWidth; - percentY = elementY.value / window.innerHeight; - - xShort = calcSideProximity(elementX.value, window.innerWidth); - yShort = calcSideProximity(elementX.value, window.innerHeight); - - // Then, we can listen for window resize. - window.addEventListener('resize', onWindowResize, false); - }); - - // Try loading initPosition, otherwise set default values - let initPosition: any; - const rawData = window.localStorage.getItem("inputItem_position") - - if (rawData) { - initPosition = JSON.parse(rawData) - } else { - initPosition = {x: xStart, y: yStart} - } - - elementX.value = initPosition.x; - elementY.value = initPosition.y; - - // remove event listeners on component dismount. - onUnmounted(() => { - window.removeEventListener('resize', onWindowResize); - window.removeEventListener('mouseup', onMouseUp); - if (element) element.removeEventListener('mousedown', onMouseDown); - }) - - return { - elementX, - elementY - } - -} diff --git a/src/render/composables/useIpcRend.ts b/src/render/composables/useIpcRend.ts deleted file mode 100644 index 9ba7f73..0000000 --- a/src/render/composables/useIpcRend.ts +++ /dev/null @@ -1,54 +0,0 @@ - -import { IpcRendererEvent } from "electron"; - -export class IpcRendererListener implements IIpcListener { - - readonly channel: string; - - readonly _listenerCallback: IpcListenerCallback; - - constructor(options: { - channel: string; - listenerCallback: IpcListenerCallback; - }) { - this.channel = options.channel; - this._listenerCallback = options.listenerCallback; - } - - listen() { - this.remove(); - window.ipcRenderer.on(this.channel, this._onPost); - } - - remove() { - window.ipcRenderer.removeAllListeners(this.channel); - } - - private _onPost = (_e: IpcRendererEvent, payload: InputParam): void => { - console.log(`[IPC] Post: ${this.channel}`); - this._listenerCallback(payload); - } - -} - - -export default function useIpcRenderer () { - - const invoke = async (endpoint: string, payload: any) => { - try { - const res = await window.ipcRenderer.invoke(endpoint, payload); - return res; - } catch (e) { - throw e; - } - } - - const post = (endpoint: string, payload: any) => { - window.ipcRenderer.send(endpoint, payload); - }; - - return { - invoke, - post, - } -} diff --git a/src/render/composables/useMessages.ts b/src/render/composables/useMessages.ts deleted file mode 100644 index f731584..0000000 --- a/src/render/composables/useMessages.ts +++ /dev/null @@ -1,33 +0,0 @@ -// shared -import { ref, Ref } from "vue"; -import useScroll from "@/render/composables/useScroll"; - -export const messages: Ref> = ref([]); - -export const setMessages: IpcListenerCallback> = (payload) => { - messages.value = payload as Array; -} - -export const addMessage: IpcListenerCallback = (payload) => { - messages.value.push(payload as Message); -} - -export const updateMessage: IpcListenerCallback = (payload) => { - const message = payload as Message; - - let targetMessage = messages.value.filter((m: Message) => { - return m.uid = message.uid; - })[0]; - - if (targetMessage) { - targetMessage = message; - } - -} - -export default { - messages, - setMessages, - addMessage, - updateMessage -}; diff --git a/src/render/composables/useProfile.ts b/src/render/composables/useProfile.ts deleted file mode 100644 index 3575de7..0000000 --- a/src/render/composables/useProfile.ts +++ /dev/null @@ -1,27 +0,0 @@ -// shared -import { ref } from "vue"; - -export const profile = ref(); - -export const authComplete = ref(false); - -export const setProfile: IpcListenerCallback = (payload) => { - payload ? profile.value = payload : clearProfile(); - showRender(); -}; - -export const clearProfile = () => { - profile.value = null; -}; - -export const showRender = () => { - authComplete.value = true; -}; - -export default { - setProfile, - clearProfile, - profile, - showRender, - authComplete, -}; diff --git a/src/render/composables/useScroll.ts b/src/render/composables/useScroll.ts deleted file mode 100644 index 811e7fc..0000000 --- a/src/render/composables/useScroll.ts +++ /dev/null @@ -1,29 +0,0 @@ - - -export default function useScroll(element: string) { - - let isScrolledToBottom: boolean; - const view = document.getElementById(element) - - // Update isScrolledToBottom - const updateScrollRef = () => { - if (view) isScrolledToBottom = view.scrollHeight - view.clientHeight <= view.scrollTop + 1; - return isScrolledToBottom; - } - - // Adjust scroll after we add content to the messenger. - const adjustScroll = () => { - if (view) { - view.scrollTo({ - top: view.scrollHeight - view.clientHeight, - behavior: 'smooth' - }); - } - } - - return { - updateScrollRef, - adjustScroll, - }; - -} \ No newline at end of file diff --git a/src/render/index.html b/src/render/index.html new file mode 100644 index 0000000..e45bb6c --- /dev/null +++ b/src/render/index.html @@ -0,0 +1,17 @@ + + + + + + + + +
+ + + + + + + + \ No newline at end of file diff --git a/src/render/index.js b/src/render/index.js new file mode 100644 index 0000000..9757f5a --- /dev/null +++ b/src/render/index.js @@ -0,0 +1,2 @@ +import App from "./components/app.js"; +Vue.createApp(App).mount("#app"); diff --git a/src/render/ipc.ts b/src/render/ipc.ts deleted file mode 100644 index bc68049..0000000 --- a/src/render/ipc.ts +++ /dev/null @@ -1,80 +0,0 @@ - -import useIpc from "@/render/composables/useIpcRend"; -import * as rendererListeners from "./listeners"; - -const { post, invoke } = useIpc(); - -/** - * - * Account and auth related endpoints - * - */ - - -export const invokeLogin = async ( - payload: LoginPayload -): Promise => ( - await invoke('invoke-account-login', JSON.stringify(payload)) -); - -export const invokeLogout = async (): Promise => ( - await invoke("invoke-account-logout", null) -); - -/** - * - * Audio endpoints - * - */ - -export const postAudioChunk = (chunk: ArrayBuffer): void => ( - post("post-audio-collect", chunk) -); - -export const invokeReturnAudio = async (): Promise => ( - await invoke("invoke-audio-flush", null) -); - -/** - * - * Crimata Platform (session) endpoints - * - */ - -export const invokeSession = async (cid: string): Promise => ( - await invoke("messenger-init", cid) -); - -export const postMessage = (payload: Message): void => ( - post('post-session-send', payload) -); - -export const postAppMount = (): void => ( - post('post-app-mount', null) -); - - -/** - * - * Ipc Renderer Listeners - * - */ - -let ipcListeners: IPCListeners = {}; - -export const initIpcRendererListeners = () => { - for (const [key, listener] of Object.entries(rendererListeners)) { - if (!(key in ipcListeners)) { - ipcListeners[key] = listener; - listener.listen(); - } - } -}; - -export const removeListeners = () => { - for (const [key, listener] of Object.entries(rendererListeners)) { - listener.remove(); - } - ipcListeners = {}; -}; - diff --git a/src/render/listeners.ts b/src/render/listeners.ts deleted file mode 100644 index 876d206..0000000 --- a/src/render/listeners.ts +++ /dev/null @@ -1,32 +0,0 @@ - -import { IpcRendererListener } from "./composables/useIpcRend" -import { setProfile } from "./composables/useProfile"; -import { setMessages, addMessage, updateMessage } from "./composables/useMessages"; - -const SET_PROFILE_CHANNEL = "set-profile"; - -const INIT_MESSAGES_CHANNEL = "init-messages"; -const ADD_MESSAGE_CHANNEL = "add-message"; -const UPDATE_MESSAGE_CHANNEL = "update-message"; - -export const setProfileListener = new IpcRendererListener({ - channel: SET_PROFILE_CHANNEL, - listenerCallback: setProfile -}); - -export const initMessagesListener = new IpcRendererListener({ - channel: INIT_MESSAGES_CHANNEL, - listenerCallback: setMessages -}); - - -export const addMessagesListener = new IpcRendererListener({ - channel: ADD_MESSAGE_CHANNEL, - listenerCallback: addMessage -}); - -export const updateMessagesListener = new IpcRendererListener({ - channel: UPDATE_MESSAGE_CHANNEL, - listenerCallback: updateMessage -}); - diff --git a/src/render/main.css b/src/render/main.css new file mode 100644 index 0000000..f25adda --- /dev/null +++ b/src/render/main.css @@ -0,0 +1,571 @@ +html, body { + margin: 0; + padding: 0; +} + +/* The first word of the class is the component that it modifys. */ + +#splash { + width: 100vw; + height: 100vh; + display: flex; + align-items: center; + justify-content: center; +} + +#app { + font-family: "SF Pro Text"; + -webkit-font-smoothing: antialiased; + height: 100vh; + width: 100vw; + border-radius: 15px; +} + +#header-titlebar { + position: fixed; + width: 100vw; + height: 54px; + opacity: 0.75; + background-color: #EBEBEB; + -webkit-app-region: drag; + border: none; + outline: none; + z-index: 1; +} + +.contacts { + margin: 0; + padding: 0; + border-radius: inherit; + background-color: #DBDBDB; +} + +.contacts > li { + padding: 12px; + display: flex; +} + +.contacts img { + border-radius: 50%; +} + +.contacts .info { + margin-left: 10px; + margin-right: 10px; +} + +.contacts .name { + +} + +.contacts .email { + font-family: SF Compact Display; + font-weight: bold; + font-size: 12px; + color: #898989; +} + +.mail { + padding: 12px; + margin: 0px; + background-color: #D6F2FF; + border-radius: inherit; +} + +.mail h4 { + margin-top: 0px; +} + +.mail p { + margin-bottom: 0px; +} + +#header-menu { + position: fixed; + margin-left: 20px; + margin-top: 20px; + z-index: 2; +} + +.header-menu-button { + min-width: 14px; + min-height: 14px; + border-radius: 7px; +} + +.header-exit-button { + background-color: #FF6157; +} + +.header-exit-button:active { + background: #c14645; +} + +.header-min-button { + background-color: #FFC12F; + margin-left: 8px; +} + +.header-min-button:active { + background-color: #c08e38; +} + +#login { + width: 100vw; + height: 100vh; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; +} + +#login-form { + font-family: "SF Compact Display"; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + padding-bottom: 20px; +} + +.login-input-box { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + margin-bottom: 10px; +} + +.login-input { + background-color: #B9B9B9; + border: none; + outline: none; + padding: 16px; + text-decoration: none; + margin: 4px 2px; + cursor: pointer; + border-radius: 10px; +} + +.login-input-modifier { + min-width: 181px; + font-size: 12px; + font-weight: bold; + text-align: left; + margin-left: 15px; +} + +.login-submit-button { + font-family: "SF Compact Display"; + position: fixed; + margin-top: 260px; + background-color: #58C4FD; + color: white; + padding: 10px 30px; + border-radius: 20px; + font-size: 14px; + font-weight: bold; +} + +.login-submit-button:active { + background-color: #4296C3; +} + +/* generic shaking functionality */ +.shake { + animation: shake 0.82s cubic-bezier(.36,.07,.19,.97) both; + transform: translate3d(0, 0, 0); + backface-visibility: hidden; + perspective: 1000px; +} + +@keyframes shake { + 10%, 90% { + transform: translate3d(-1px, 0, 0); + } + + 20%, 80% { + transform: translate3d(2px, 0, 0); + } + + 30%, 50%, 70% { + transform: translate3d(-4px, 0, 0); + } + + 40%, 60% { + transform: translate3d(4px, 0, 0); + } +} + +#messenger { + width: 100vw; + height: 100vh; + overflow: auto; +} + +/* hide native scrollbar */ +#messenger::-webkit-scrollbar { + display: none; +} + +#ws { + position: fixed; + width: 100vw; + height: 54px; + display: flex; + align-items: center; + justify-content: center; + z-index: 1; +} + +#ws-logo { + transition: all 0.5s; +} + +#ws-logo.move { + transform: translateX(15px); +} + +#ws-dots { + opacity: 0; + transition: all 0.5s; +} + +#ws-dots.move { + opacity: 1; + transform: translateX(-15px); +} + +.ws-dot { + width: 6px; + height: 6px; + border-radius: 50%; + background-color: #48E065; + position: relative; + transform: translateX(-15px); + animation: ws-dot-flashing 1s infinite linear alternate; + animation-delay: .25s; +} + +.ws-dot::before, .ws-dot::after { + content: ''; + display: inline-block; + position: absolute; +} + +.ws-dot::before { + width: 6px; + height: 6px; + border-radius: 50%; + background-color: #48E065; + left: -9px; + animation: ws-dot-flashing 1s infinite alternate; + animation-delay: 0s; +} + +.ws-dot::after { + width: 6px; + height: 6px; + border-radius: 50%; + background-color: #48E065; + left: 9px; + animation: ws-dot-flashing 1s infinite alternate; + animation-delay: 0.5s; +} + +@keyframes ws-dot-flashing { + 0% { + background-color: #48E065; + } + 50%, + 100% { + background-color: #9B9B9B; + } +} + +#input { + position: absolute; + display: flex; + align-items: center; + justify-content: center; + padding: 0; + width: 40px; + height: 40px; + z-index: 3; + /* To prevent window drag when overlapping with titlebar. */ + -webkit-app-region: no-drag; + border-radius: 50%; + /* Set opacity here to not affect child. */ + background-color: rgba(235, 235, 235, 0.75); + cursor: pointer; + box-shadow: 0px 0px 10px 0px rgba(0,0,0,0.15); +} + +#input-text { + position: absolute; + min-width: 150px; + height: 16px; + border-radius: 18px; + padding: 10px; + outline: none; + border: none; + pointer-events: none; + background-color: white; + z-index: -1; + box-shadow: 0px 0px 10px 0px rgba(0,0,0,0.15); + transform-origin: center; + opacity: 0; + transform: translateX(70%); + transition: all 0.5s; +} + +#input-text.show { + opacity: 1; +} + +#input-text.leftSide { + transform: translateX(-70%); +} + +#settings { + position: fixed; + width: 100vw; + height: 100vh; + background-color: rgba(235, 235, 235, 0.75); + z-index: 4; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + animation-name: settings-appear; + animation-duration: 0.5s; +} + +@keyframes settings-appear { + from { + background-color: rgba(235, 235, 235, 0); + } + to { + background-color: rgba(235, 235, 235, 0.75); + } +} + +.settings-icon { + position: fixed; + right: 0; + border: none; + outline: none; + display: flex; + flex-direction: row; + padding: 5px; + margin-right: 20px; + margin-top: 19px; + z-index: 2; + background-color: Transparent; +} + +.settings-icon:hover { + cursor: pointer; +} + +.settings-account { + font-size: 12px; + font-weight: bold; + margin-bottom: 25px; +} + +.settings-logout-button { + font-family: "SF Compact Display"; + background-color: #B7B7B7; + padding: 10px 30px; + border-radius: 20px; + font-size: 14px; + font-weight: bold; +} + +.settings-logout-button:hover { + cursor: pointer; +} + +.settings-version { + position: absolute; + left: 50%; + top: 75%; + transform: translate(-50%, -50%); + font-size: 12px; + font-weight: bold; + color: #575757; +} + +.message { + width: 100vw; + display: flex; + flex-direction: column; + padding-top: 9px; + padding-bottom: 9px; + animation-name: message-init-anim; + animation-duration: 0.25s; +} + +@keyframes message-init-anim { + from { + opacity: 0; + } to { + opacity: 1; + } +} + +.message:first-child { + margin-top: 55px; +} + +.message:last-child { + margin-bottom: 6px; +} + +.client-message { + align-items: flex-end; +} + +.ai-message { + align-items: flex-start; +} + +.bubble { + position: relative; + max-width: 66vw; + font-family: "SF Pro Text"; + font-size: 14px; + border-radius: 18px; + margin-bottom: 4px; +} + +.ai-bubble { + background-color: #FFFFFF; + margin-left: 15px; +} + +.client-bubble { + color: white; + background-color: #58C4FD; + margin-right: 15px; +} + +.ai-first-child { + border-bottom-left-radius: 9px; +} + +.ai-middle-child { + border-top-left-radius: 9px; + border-bottom-left-radius: 9px; +} + +.ai-last-child { + border-top-left-radius: 9px; +} + +.client-first-child { + border-bottom-right-radius: 9px; +} + +.client-middle-child { + border-top-right-radius: 9px; + border-bottom-right-radius: 9px; +} + +.client-last-child { + border-top-right-radius: 9px; +} + +.bubble > p { + margin: 0px; + padding: 10px; +} + +.bubble > div { + border-radius: inherit; +} + +.bubble > img { + border-radius: inherit; + display: block; + max-width: inherit; +} + +.bubble a { + border-radius: inherit; + font-family: "SF Compact Rounded"; + background-color: #D9D9D9; + font-weight: bold; + padding: 12px; + color: #727272; + margin: 0px; +} + +.context { + position: relative; + min-height: 14px; + display: flex; + align-items: center; + font-family: "SF Compact Display"; + font-size: 12px; + font-weight: bold; + margin-top: 5px; +} + +.ai-context { + margin-left: 15px; +} + +.client-context { + margin-right: 15px; +} + +.context-avatar { + display: flex; + justify-content: center; + align-items: center; + width: 30px; + height: 30px; + background-color: white; + border-radius: 15px; + margin-right: 5px; +} + +.context-avatar img { + border-radius: 50%; +} + +/* ---------- shared between components ---------- */ + +.button { + border: none; + outline: none; + text-decoration: none; +} + +/*.button:hover { + cursor: pointer; +}*/ + +.audio { + animation-name: audio-anim; + animation-duration: 2s; + animation-iteration-count: infinite; +} + +@keyframes audio-anim { + 0%, + 100% { + box-shadow: 0 0 0 0.4em rgba(195, 195, 195, 0.4), 0 0 0 0.25em rgba(195, 195, 195, 0.15); + } + 25% { + box-shadow: 0 0 0 0.15em rgba(195, 195, 195, 0.15), 0 0 0 0.4em rgba(195, 195, 195, 0.3); + } + 50% { + box-shadow: 0 0 0 0.55em rgba(195, 195, 195, 0.55), 0 0 0 0.15em rgba(195, 195, 195, 0.05); + } + 75% { + box-shadow: 0 0 0 0.25em rgba(195, 195, 195, 0.25), 0 0 0 0.55em rgba(195, 195, 195, 0.45); + } +} diff --git a/src/render/main.ts b/src/render/main.ts deleted file mode 100644 index 5375889..0000000 --- a/src/render/main.ts +++ /dev/null @@ -1,21 +0,0 @@ - -// src/main.ts - -import App from "./App.vue"; - -import mitt from "mitt"; -import { createApp } from "vue"; - -import { initIpcRendererListeners } from "./ipc" - - -// Handle ipcMain events. -initIpcRendererListeners(); - -// Handle events. -const emitter = mitt(); - -const app = createApp(App); - -app.provide("mitt", emitter); -app.mount("#app"); diff --git a/src/render/preload.js b/src/render/preload.js new file mode 100644 index 0000000..9b50adf --- /dev/null +++ b/src/render/preload.js @@ -0,0 +1,53 @@ +const { contextBridge, ipcRenderer } = require("electron"); + +/** The main <-> render interface */ + +const validFromMainChannels = [ + "set-account", + "message", + "ws-status", + "record", + "playback" +]; + +const validToMain = [ + "messenger", + "message", + "login", + "logout", + "encode", + "decode" +] + +ipcRenderer.setMaxListeners(250); + +// Expose protected methods that allow the renderer process to use +// the ipcRenderer without exposing the entire object +// TODO: Implement argument filtering for added security +contextBridge.exposeInMainWorld( + "mainApi", { + invoke: async (channel, ...args) => { + if (validToMain.includes(channel)) { + try { + const res = await ipcRenderer.invoke(channel, ...args); + return res; + } catch (e) { + console.log("IPCRenderer.invoke error"); + } + } + }, + send: (channel, ...args) => { + if (validToMain.includes(channel)) { + ipcRenderer.send(channel, ...args); + } + }, + on: (channel, func) => { + if (validFromMainChannels.includes(channel)) { + ipcRenderer.on(channel, (event, ...args) => func(...args)); + } + }, + removeAllListeners: (channel) => { + ipcRenderer.removeAllListeners(channel); + } + } +); diff --git a/src/render/preload.ts b/src/render/preload.ts deleted file mode 100644 index 054f672..0000000 --- a/src/render/preload.ts +++ /dev/null @@ -1,38 +0,0 @@ -// All of the Node.js APIs are available in the preload process. -// It has the same sandbox as a Chrome extension. -import { ipcRenderer } from "electron"; - -declare global { - interface Window { - ipcRenderer: typeof ipcRenderer; - } -} - -window.ipcRenderer = ipcRenderer; - -process.once("loaded", () => { - - window.addEventListener("message", event => { - - // do something with custom event - const message = event.data; - - if (message.endpoint === "update-menu-bar") { - ipcRenderer.send("update-menu-bar", message.content); - } - - if (message.endpoint === "update-recorder") { - ipcRenderer.send("update-recorder", message.content); - } - - if (message.endpoint === "client-message") { - ipcRenderer.send("client-message", message.content); - } - - if (message.endpoint === "logout") { - ipcRenderer.send("logout", message.content); - } - - }); - -}); diff --git a/src/render/shims-vue.d.ts b/src/render/shims-vue.d.ts deleted file mode 100644 index 35a61a9..0000000 --- a/src/render/shims-vue.d.ts +++ /dev/null @@ -1,13 +0,0 @@ -declare module "*.vue" { - import { defineComponent } from "vue"; - const component: ReturnType; - export default component; -} - -declare module "anime-js" { - namespace anime { - import * as anime from "animejs/lib/anime.es.js"; - function anime(): void; - export = anime; - } -} diff --git a/src/render/vendor/vue.js b/src/render/vendor/vue.js new file mode 100644 index 0000000..6e5ee00 --- /dev/null +++ b/src/render/vendor/vue.js @@ -0,0 +1,15872 @@ +var Vue = (function (exports) { + 'use strict'; + + /** + * Make a map and return a function for checking if a key + * is in that map. + * IMPORTANT: all calls of this function must be prefixed with + * \/\*#\_\_PURE\_\_\*\/ + * So that rollup can tree-shake them if necessary. + */ + function makeMap(str, expectsLowerCase) { + const map = Object.create(null); + const list = str.split(','); + for (let i = 0; i < list.length; i++) { + map[list[i]] = true; + } + return expectsLowerCase ? val => !!map[val.toLowerCase()] : val => !!map[val]; + } + + /** + * dev only flag -> name mapping + */ + const PatchFlagNames = { + [1 /* TEXT */]: `TEXT`, + [2 /* CLASS */]: `CLASS`, + [4 /* STYLE */]: `STYLE`, + [8 /* PROPS */]: `PROPS`, + [16 /* FULL_PROPS */]: `FULL_PROPS`, + [32 /* HYDRATE_EVENTS */]: `HYDRATE_EVENTS`, + [64 /* STABLE_FRAGMENT */]: `STABLE_FRAGMENT`, + [128 /* KEYED_FRAGMENT */]: `KEYED_FRAGMENT`, + [256 /* UNKEYED_FRAGMENT */]: `UNKEYED_FRAGMENT`, + [512 /* NEED_PATCH */]: `NEED_PATCH`, + [1024 /* DYNAMIC_SLOTS */]: `DYNAMIC_SLOTS`, + [2048 /* DEV_ROOT_FRAGMENT */]: `DEV_ROOT_FRAGMENT`, + [-1 /* HOISTED */]: `HOISTED`, + [-2 /* BAIL */]: `BAIL` + }; + + /** + * Dev only + */ + const slotFlagsText = { + [1 /* STABLE */]: 'STABLE', + [2 /* DYNAMIC */]: 'DYNAMIC', + [3 /* FORWARDED */]: 'FORWARDED' + }; + + const GLOBALS_WHITE_LISTED = 'Infinity,undefined,NaN,isFinite,isNaN,parseFloat,parseInt,decodeURI,' + + 'decodeURIComponent,encodeURI,encodeURIComponent,Math,Number,Date,Array,' + + 'Object,Boolean,String,RegExp,Map,Set,JSON,Intl,BigInt'; + const isGloballyWhitelisted = /*#__PURE__*/ makeMap(GLOBALS_WHITE_LISTED); + + const range = 2; + function generateCodeFrame(source, start = 0, end = source.length) { + // Split the content into individual lines but capture the newline sequence + // that separated each line. This is important because the actual sequence is + // needed to properly take into account the full line length for offset + // comparison + let lines = source.split(/(\r?\n)/); + // Separate the lines and newline sequences into separate arrays for easier referencing + const newlineSequences = lines.filter((_, idx) => idx % 2 === 1); + lines = lines.filter((_, idx) => idx % 2 === 0); + let count = 0; + const res = []; + for (let i = 0; i < lines.length; i++) { + count += + lines[i].length + + ((newlineSequences[i] && newlineSequences[i].length) || 0); + if (count >= start) { + for (let j = i - range; j <= i + range || end > count; j++) { + if (j < 0 || j >= lines.length) + continue; + const line = j + 1; + res.push(`${line}${' '.repeat(Math.max(3 - String(line).length, 0))}| ${lines[j]}`); + const lineLength = lines[j].length; + const newLineSeqLength = (newlineSequences[j] && newlineSequences[j].length) || 0; + if (j === i) { + // push underline + const pad = start - (count - (lineLength + newLineSeqLength)); + const length = Math.max(1, end > count ? lineLength - pad : end - start); + res.push(` | ` + ' '.repeat(pad) + '^'.repeat(length)); + } + else if (j > i) { + if (end > count) { + const length = Math.max(Math.min(end - count, lineLength), 1); + res.push(` | ` + '^'.repeat(length)); + } + count += lineLength + newLineSeqLength; + } + } + break; + } + } + return res.join('\n'); + } + + /** + * On the client we only need to offer special cases for boolean attributes that + * have different names from their corresponding dom properties: + * - itemscope -> N/A + * - allowfullscreen -> allowFullscreen + * - formnovalidate -> formNoValidate + * - ismap -> isMap + * - nomodule -> noModule + * - novalidate -> noValidate + * - readonly -> readOnly + */ + const specialBooleanAttrs = `itemscope,allowfullscreen,formnovalidate,ismap,nomodule,novalidate,readonly`; + const isSpecialBooleanAttr = /*#__PURE__*/ makeMap(specialBooleanAttrs); + /** + * Boolean attributes should be included if the value is truthy or ''. + * e.g. + const forcePatchValue = (type === 'input' && dirs) || type === 'option'; + // skip props & children if this is hoisted static nodes + if (forcePatchValue || patchFlag !== -1 /* HOISTED */) { + if (dirs) { + invokeDirectiveHook(vnode, null, parentComponent, 'created'); + } + // props + if (props) { + if (forcePatchValue || + !optimized || + patchFlag & (16 /* FULL_PROPS */ | 32 /* HYDRATE_EVENTS */)) { + for (const key in props) { + if ((forcePatchValue && key.endsWith('value')) || + (isOn(key) && !isReservedProp(key))) { + patchProp(el, key, null, props[key]); + } + } + } + else if (props.onClick) { + // Fast path for click listeners (which is most often) to avoid + // iterating through props. + patchProp(el, 'onClick', null, props.onClick); + } + } + // vnode / directive hooks + let vnodeHooks; + if ((vnodeHooks = props && props.onVnodeBeforeMount)) { + invokeVNodeHook(vnodeHooks, parentComponent, vnode); + } + if (dirs) { + invokeDirectiveHook(vnode, null, parentComponent, 'beforeMount'); + } + if ((vnodeHooks = props && props.onVnodeMounted) || dirs) { + queueEffectWithSuspense(() => { + vnodeHooks && invokeVNodeHook(vnodeHooks, parentComponent, vnode); + dirs && invokeDirectiveHook(vnode, null, parentComponent, 'mounted'); + }, parentSuspense); + } + // children + if (shapeFlag & 16 /* ARRAY_CHILDREN */ && + // skip if element has innerHTML / textContent + !(props && (props.innerHTML || props.textContent))) { + let next = hydrateChildren(el.firstChild, vnode, el, parentComponent, parentSuspense, slotScopeIds, optimized); + let hasWarned = false; + while (next) { + hasMismatch = true; + if (!hasWarned) { + warn$1(`Hydration children mismatch in <${vnode.type}>: ` + + `server rendered element contains more child nodes than client vdom.`); + hasWarned = true; + } + // The SSRed DOM contains more nodes than it should. Remove them. + const cur = next; + next = next.nextSibling; + remove(cur); + } + } + else if (shapeFlag & 8 /* TEXT_CHILDREN */) { + if (el.textContent !== vnode.children) { + hasMismatch = true; + warn$1(`Hydration text content mismatch in <${vnode.type}>:\n` + + `- Client: ${el.textContent}\n` + + `- Server: ${vnode.children}`); + el.textContent = vnode.children; + } + } + } + return el.nextSibling; + }; + const hydrateChildren = (node, parentVNode, container, parentComponent, parentSuspense, slotScopeIds, optimized) => { + optimized = optimized || !!parentVNode.dynamicChildren; + const children = parentVNode.children; + const l = children.length; + let hasWarned = false; + for (let i = 0; i < l; i++) { + const vnode = optimized + ? children[i] + : (children[i] = normalizeVNode(children[i])); + if (node) { + node = hydrateNode(node, vnode, parentComponent, parentSuspense, slotScopeIds, optimized); + } + else if (vnode.type === Text && !vnode.children) { + continue; + } + else { + hasMismatch = true; + if (!hasWarned) { + warn$1(`Hydration children mismatch in <${container.tagName.toLowerCase()}>: ` + + `server rendered element contains fewer child nodes than client vdom.`); + hasWarned = true; + } + // the SSRed DOM didn't contain enough nodes. Mount the missing ones. + patch(null, vnode, container, null, parentComponent, parentSuspense, isSVGContainer(container), slotScopeIds); + } + } + return node; + }; + const hydrateFragment = (node, vnode, parentComponent, parentSuspense, slotScopeIds, optimized) => { + const { slotScopeIds: fragmentSlotScopeIds } = vnode; + if (fragmentSlotScopeIds) { + slotScopeIds = slotScopeIds + ? slotScopeIds.concat(fragmentSlotScopeIds) + : fragmentSlotScopeIds; + } + const container = parentNode(node); + const next = hydrateChildren(nextSibling(node), vnode, container, parentComponent, parentSuspense, slotScopeIds, optimized); + if (next && isComment(next) && next.data === ']') { + return nextSibling((vnode.anchor = next)); + } + else { + // fragment didn't hydrate successfully, since we didn't get a end anchor + // back. This should have led to node/children mismatch warnings. + hasMismatch = true; + // since the anchor is missing, we need to create one and insert it + insert((vnode.anchor = createComment(`]`)), container, next); + return next; + } + }; + const handleMismatch = (node, vnode, parentComponent, parentSuspense, slotScopeIds, isFragment) => { + hasMismatch = true; + warn$1(`Hydration node mismatch:\n- Client vnode:`, vnode.type, `\n- Server rendered DOM:`, node, node.nodeType === 3 /* TEXT */ + ? `(text)` + : isComment(node) && node.data === '[' + ? `(start of fragment)` + : ``); + vnode.el = null; + if (isFragment) { + // remove excessive fragment nodes + const end = locateClosingAsyncAnchor(node); + while (true) { + const next = nextSibling(node); + if (next && next !== end) { + remove(next); + } + else { + break; + } + } + } + const next = nextSibling(node); + const container = parentNode(node); + remove(node); + patch(null, vnode, container, next, parentComponent, parentSuspense, isSVGContainer(container), slotScopeIds); + return next; + }; + const locateClosingAsyncAnchor = (node) => { + let match = 0; + while (node) { + node = nextSibling(node); + if (node && isComment(node)) { + if (node.data === '[') + match++; + if (node.data === ']') { + if (match === 0) { + return nextSibling(node); + } + else { + match--; + } + } + } + } + return node; + }; + return [hydrate, hydrateNode]; + } + + let supported; + let perf; + function startMeasure(instance, type) { + if (instance.appContext.config.performance && isSupported()) { + perf.mark(`vue-${type}-${instance.uid}`); + } + { + devtoolsPerfStart(instance, type, supported ? perf.now() : Date.now()); + } + } + function endMeasure(instance, type) { + if (instance.appContext.config.performance && isSupported()) { + const startTag = `vue-${type}-${instance.uid}`; + const endTag = startTag + `:end`; + perf.mark(endTag); + perf.measure(`<${formatComponentName(instance, instance.type)}> ${type}`, startTag, endTag); + perf.clearMarks(startTag); + perf.clearMarks(endTag); + } + { + devtoolsPerfEnd(instance, type, supported ? perf.now() : Date.now()); + } + } + function isSupported() { + if (supported !== undefined) { + return supported; + } + /* eslint-disable no-restricted-globals */ + if (typeof window !== 'undefined' && window.performance) { + supported = true; + perf = window.performance; + } + else { + supported = false; + } + /* eslint-enable no-restricted-globals */ + return supported; + } + + const queuePostRenderEffect = queueEffectWithSuspense + ; + /** + * The createRenderer function accepts two generic arguments: + * HostNode and HostElement, corresponding to Node and Element types in the + * host environment. For example, for runtime-dom, HostNode would be the DOM + * `Node` interface and HostElement would be the DOM `Element` interface. + * + * Custom renderers can pass in the platform specific types like this: + * + * ``` js + * const { render, createApp } = createRenderer({ + * patchProp, + * ...nodeOps + * }) + * ``` + */ + function createRenderer(options) { + return baseCreateRenderer(options); + } + // Separate API for creating hydration-enabled renderer. + // Hydration logic is only used when calling this function, making it + // tree-shakable. + function createHydrationRenderer(options) { + return baseCreateRenderer(options, createHydrationFunctions); + } + // implementation + function baseCreateRenderer(options, createHydrationFns) { + { + const target = getGlobalThis(); + target.__VUE__ = true; + setDevtoolsHook(target.__VUE_DEVTOOLS_GLOBAL_HOOK__); + } + const { insert: hostInsert, remove: hostRemove, patchProp: hostPatchProp, createElement: hostCreateElement, createText: hostCreateText, createComment: hostCreateComment, setText: hostSetText, setElementText: hostSetElementText, parentNode: hostParentNode, nextSibling: hostNextSibling, setScopeId: hostSetScopeId = NOOP, cloneNode: hostCloneNode, insertStaticContent: hostInsertStaticContent } = options; + // Note: functions inside this closure should use `const xxx = () => {}` + // style in order to prevent being inlined by minifiers. + const patch = (n1, n2, container, anchor = null, parentComponent = null, parentSuspense = null, isSVG = false, slotScopeIds = null, optimized = isHmrUpdating ? false : !!n2.dynamicChildren) => { + if (n1 === n2) { + return; + } + // patching & not same type, unmount old tree + if (n1 && !isSameVNodeType(n1, n2)) { + anchor = getNextHostNode(n1); + unmount(n1, parentComponent, parentSuspense, true); + n1 = null; + } + if (n2.patchFlag === -2 /* BAIL */) { + optimized = false; + n2.dynamicChildren = null; + } + const { type, ref, shapeFlag } = n2; + switch (type) { + case Text: + processText(n1, n2, container, anchor); + break; + case Comment: + processCommentNode(n1, n2, container, anchor); + break; + case Static: + if (n1 == null) { + mountStaticNode(n2, container, anchor, isSVG); + } + else { + patchStaticNode(n1, n2, container, isSVG); + } + break; + case Fragment: + processFragment(n1, n2, container, anchor, parentComponent, parentSuspense, isSVG, slotScopeIds, optimized); + break; + default: + if (shapeFlag & 1 /* ELEMENT */) { + processElement(n1, n2, container, anchor, parentComponent, parentSuspense, isSVG, slotScopeIds, optimized); + } + else if (shapeFlag & 6 /* COMPONENT */) { + processComponent(n1, n2, container, anchor, parentComponent, parentSuspense, isSVG, slotScopeIds, optimized); + } + else if (shapeFlag & 64 /* TELEPORT */) { + type.process(n1, n2, container, anchor, parentComponent, parentSuspense, isSVG, slotScopeIds, optimized, internals); + } + else if (shapeFlag & 128 /* SUSPENSE */) { + type.process(n1, n2, container, anchor, parentComponent, parentSuspense, isSVG, slotScopeIds, optimized, internals); + } + else { + warn$1('Invalid VNode type:', type, `(${typeof type})`); + } + } + // set ref + if (ref != null && parentComponent) { + setRef(ref, n1 && n1.ref, parentSuspense, n2 || n1, !n2); + } + }; + const processText = (n1, n2, container, anchor) => { + if (n1 == null) { + hostInsert((n2.el = hostCreateText(n2.children)), container, anchor); + } + else { + const el = (n2.el = n1.el); + if (n2.children !== n1.children) { + hostSetText(el, n2.children); + } + } + }; + const processCommentNode = (n1, n2, container, anchor) => { + if (n1 == null) { + hostInsert((n2.el = hostCreateComment(n2.children || '')), container, anchor); + } + else { + // there's no support for dynamic comments + n2.el = n1.el; + } + }; + const mountStaticNode = (n2, container, anchor, isSVG) => { + [n2.el, n2.anchor] = hostInsertStaticContent(n2.children, container, anchor, isSVG); + }; + /** + * Dev / HMR only + */ + const patchStaticNode = (n1, n2, container, isSVG) => { + // static nodes are only patched during dev for HMR + if (n2.children !== n1.children) { + const anchor = hostNextSibling(n1.anchor); + // remove existing + removeStaticNode(n1); + [n2.el, n2.anchor] = hostInsertStaticContent(n2.children, container, anchor, isSVG); + } + else { + n2.el = n1.el; + n2.anchor = n1.anchor; + } + }; + const moveStaticNode = ({ el, anchor }, container, nextSibling) => { + let next; + while (el && el !== anchor) { + next = hostNextSibling(el); + hostInsert(el, container, nextSibling); + el = next; + } + hostInsert(anchor, container, nextSibling); + }; + const removeStaticNode = ({ el, anchor }) => { + let next; + while (el && el !== anchor) { + next = hostNextSibling(el); + hostRemove(el); + el = next; + } + hostRemove(anchor); + }; + const processElement = (n1, n2, container, anchor, parentComponent, parentSuspense, isSVG, slotScopeIds, optimized) => { + isSVG = isSVG || n2.type === 'svg'; + if (n1 == null) { + mountElement(n2, container, anchor, parentComponent, parentSuspense, isSVG, slotScopeIds, optimized); + } + else { + patchElement(n1, n2, parentComponent, parentSuspense, isSVG, slotScopeIds, optimized); + } + }; + const mountElement = (vnode, container, anchor, parentComponent, parentSuspense, isSVG, slotScopeIds, optimized) => { + let el; + let vnodeHook; + const { type, props, shapeFlag, transition, patchFlag, dirs } = vnode; + { + el = vnode.el = hostCreateElement(vnode.type, isSVG, props && props.is, props); + // mount children first, since some props may rely on child content + // being already rendered, e.g. `