From 41528e7e27791bc4d5bdab419705a3a4bc462eb4 Mon Sep 17 00:00:00 2001 From: Andrew Gundersen Date: Sat, 16 Oct 2021 09:39:10 -0500 Subject: [PATCH] production refactor --- .eslintrc.js | 38 - .gitignore | 12 +- .npmrc | 2 + .yarnrc.yml | 8 - babel.config.js | 5 - jest.config.js | 6 - jsconfig.json | 6 - package-lock.json | 2213 ++ package.json | 93 +- public/index.html | 17 - public/trayIcon/icon.png | Bin 3341 -> 0 bytes public/trayIcon/icon@2x.png | Bin 4083 -> 0 bytes src/account.js | 41 + src/account.ts | 124 - src/api.js | 19 + src/api/account.ts | 31 - {build => src/assets}/icon.icns | Bin src/assets/tray/000.png | Bin 0 -> 3347 bytes .../assets/tray/000@2x.png | Bin src/assets/tray/001.png | Bin 0 -> 3329 bytes .../assets/tray/001@2x.png | Bin src/assets/tray/010.png | Bin 0 -> 3470 bytes .../assets/tray/010@2x.png | Bin src/assets/tray/011.png | Bin 0 -> 3487 bytes .../assets/tray/011@2x.png | Bin src/assets/tray/100.png | Bin 0 -> 3423 bytes .../assets/tray/100@2x.png | Bin src/assets/tray/101.png | Bin 0 -> 3401 bytes .../assets/tray/101@2x.png | Bin src/assets/tray/110.png | Bin 0 -> 3532 bytes .../assets/tray/110@2x.png | Bin src/assets/tray/111.png | Bin 0 -> 3527 bytes .../assets/tray/111@2x.png | Bin src/audio.js | 109 + src/audio.ts | 124 - src/composables/autoUpdate.ts | 31 - src/composables/useHttp.ts | 51 - src/composables/useIpcMain.ts | 80 - src/composables/useStore.ts | 12 - src/composables/useWebsockets.ts | 99 - src/{config.ts => config.js} | 7 +- src/init.ts | 53 - src/io.js | 58 + src/io.ts | 34 - src/ipc/handlers.ts | 19 - src/ipc/index.ts | 33 - src/ipc/listeners.ts | 36 - src/main.js | 26 + src/main.ts | 20 - src/render/App.vue | 74 - src/render/assets/mailAvatar.svg | 11 + src/render/audioVisualizer.js | 81 - src/render/components/app.js | 44 + src/render/components/bubble.js | 16 + src/render/components/bubble.vue | 98 - src/render/components/connectionStatus.vue | 103 - src/render/components/context.js | 38 + src/render/components/context.vue | 83 - src/render/components/control/draggify.js | 199 + src/render/components/control/scroll.js | 24 + src/render/components/control/text.js | 73 + src/render/components/controllers/helpers.ts | 107 - .../controllers/inputItem.control.text.ts | 135 - src/render/components/header.js | 23 + src/render/components/header.vue | 90 - src/render/components/input.js | 39 + src/render/components/inputItem.vue | 141 - src/render/components/login.js | 58 + src/render/components/login.vue | 173 - src/render/components/message.js | 69 + src/render/components/message.vue | 105 - src/render/components/messenger.js | 71 + src/render/components/messenger.vue | 126 - src/render/components/settings.js | 40 + src/render/components/settings.vue | 158 - src/render/components/splash.js | 50 + src/render/components/splash.vue | 69 - src/render/components/ws.js | 36 + src/render/composables/useDraggify.ts | 199 - src/render/composables/useIpcRend.ts | 54 - src/render/composables/useScroll.ts | 25 - src/render/index.html | 17 + src/render/index.js | 2 + src/render/ipc.ts | 90 - src/render/listeners.ts | 81 - src/render/main.css | 507 + src/render/main.ts | 21 - src/render/preload.js | 53 + src/render/preload.ts | 38 - src/render/shared/account.ts | 26 - src/render/shared/audio.ts | 13 - src/render/shared/connectionStatus.ts | 65 - src/render/shared/messages.ts | 79 - src/render/shared/profile.ts | 19 - src/render/shared/version.ts | 12 - src/render/shims-vue.d.ts | 13 - src/render/vendor/vue.js | 15872 +++++++++++++ src/session.js | 81 + src/session.ts | 97 - src/tray.js | 44 + src/tray.ts | 34 - src/types.ts | 143 - src/ui.ts | 102 - .../useEmitter.ts => utils/emitter.js} | 13 +- src/utils/store.js | 5 + src/window.js | 77 + src/window.ts | 120 - tests/audio.js | 182 - tests/mockMessages.ts | 160 - tests/server.js | 36 - tests/unit/electron.spec.js | 32 - tests/unit/example.spec.ts | 12 - tests/ws.py | 59 - tsconfig.json | 46 - yarn.lock | 18656 +--------------- 115 files changed, 20719 insertions(+), 22107 deletions(-) delete mode 100644 .eslintrc.js create mode 100644 .npmrc delete mode 100644 .yarnrc.yml delete mode 100644 babel.config.js delete mode 100644 jest.config.js delete mode 100644 jsconfig.json create mode 100644 package-lock.json delete mode 100644 public/index.html delete mode 100644 public/trayIcon/icon.png delete mode 100644 public/trayIcon/icon@2x.png create mode 100644 src/account.js delete mode 100644 src/account.ts create mode 100644 src/api.js delete mode 100644 src/api/account.ts rename {build => src/assets}/icon.icns (100%) create mode 100644 src/assets/tray/000.png rename build/tray/000_16x16@2x.png => src/assets/tray/000@2x.png (100%) create mode 100644 src/assets/tray/001.png rename build/tray/001_16x16@2x.png => src/assets/tray/001@2x.png (100%) create mode 100644 src/assets/tray/010.png rename build/tray/010_16x16@2x.png => src/assets/tray/010@2x.png (100%) create mode 100644 src/assets/tray/011.png rename build/tray/011_16x16@2x.png => src/assets/tray/011@2x.png (100%) create mode 100644 src/assets/tray/100.png rename build/tray/100_16x16@2x.png => src/assets/tray/100@2x.png (100%) create mode 100644 src/assets/tray/101.png rename build/tray/101_16x16@2x.png => src/assets/tray/101@2x.png (100%) create mode 100644 src/assets/tray/110.png rename build/tray/110_16x16@2x.png => src/assets/tray/110@2x.png (100%) create mode 100644 src/assets/tray/111.png rename build/tray/111_16x16@2x.png => src/assets/tray/111@2x.png (100%) create mode 100644 src/audio.js delete mode 100644 src/audio.ts delete mode 100644 src/composables/autoUpdate.ts delete mode 100644 src/composables/useHttp.ts delete mode 100644 src/composables/useIpcMain.ts delete mode 100644 src/composables/useStore.ts delete mode 100644 src/composables/useWebsockets.ts rename src/{config.ts => config.js} (87%) delete mode 100644 src/init.ts create mode 100644 src/io.js delete mode 100644 src/io.ts delete mode 100644 src/ipc/handlers.ts delete mode 100644 src/ipc/index.ts delete mode 100644 src/ipc/listeners.ts create mode 100644 src/main.js delete mode 100644 src/main.ts delete mode 100644 src/render/App.vue create mode 100644 src/render/assets/mailAvatar.svg delete mode 100644 src/render/audioVisualizer.js create mode 100644 src/render/components/app.js create mode 100644 src/render/components/bubble.js delete mode 100644 src/render/components/bubble.vue delete mode 100644 src/render/components/connectionStatus.vue create mode 100644 src/render/components/context.js delete mode 100644 src/render/components/context.vue create mode 100644 src/render/components/control/draggify.js create mode 100644 src/render/components/control/scroll.js create mode 100644 src/render/components/control/text.js delete mode 100644 src/render/components/controllers/helpers.ts delete mode 100644 src/render/components/controllers/inputItem.control.text.ts create mode 100644 src/render/components/header.js delete mode 100644 src/render/components/header.vue create mode 100644 src/render/components/input.js delete mode 100644 src/render/components/inputItem.vue create mode 100644 src/render/components/login.js delete mode 100644 src/render/components/login.vue create mode 100644 src/render/components/message.js delete mode 100644 src/render/components/message.vue create mode 100644 src/render/components/messenger.js delete mode 100644 src/render/components/messenger.vue create mode 100644 src/render/components/settings.js delete mode 100644 src/render/components/settings.vue create mode 100644 src/render/components/splash.js delete mode 100644 src/render/components/splash.vue create mode 100644 src/render/components/ws.js delete mode 100644 src/render/composables/useDraggify.ts delete mode 100644 src/render/composables/useIpcRend.ts delete mode 100644 src/render/composables/useScroll.ts create mode 100644 src/render/index.html create mode 100644 src/render/index.js delete mode 100644 src/render/ipc.ts delete mode 100644 src/render/listeners.ts create mode 100644 src/render/main.css delete mode 100644 src/render/main.ts create mode 100644 src/render/preload.js delete mode 100644 src/render/preload.ts delete mode 100644 src/render/shared/account.ts delete mode 100644 src/render/shared/audio.ts delete mode 100644 src/render/shared/connectionStatus.ts delete mode 100644 src/render/shared/messages.ts delete mode 100644 src/render/shared/profile.ts delete mode 100644 src/render/shared/version.ts delete mode 100644 src/render/shims-vue.d.ts create mode 100644 src/render/vendor/vue.js create mode 100644 src/session.js delete mode 100644 src/session.ts create mode 100644 src/tray.js delete mode 100644 src/tray.ts delete mode 100644 src/types.ts delete mode 100644 src/ui.ts rename src/{composables/useEmitter.ts => utils/emitter.js} (51%) create mode 100644 src/utils/store.js create mode 100644 src/window.js delete mode 100644 src/window.ts delete mode 100644 tests/audio.js delete mode 100644 tests/mockMessages.ts delete mode 100644 tests/server.js delete mode 100644 tests/unit/electron.spec.js delete mode 100644 tests/unit/example.spec.ts delete mode 100644 tests/ws.py delete mode 100644 tsconfig.json 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 4340749..75d5ca4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,5 @@ .DS_Store -node_modules +/node_modules /dist /crate/target/* /.log @@ -17,9 +17,6 @@ yarn-debug.log* yarn-error.log* pnpm-debug.log* -# Yarn cache -/.yarn - # Editor directories and files .idea .vscode @@ -31,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/.yarnrc.yml b/.yarnrc.yml deleted file mode 100644 index 4325bf4..0000000 --- a/.yarnrc.yml +++ /dev/null @@ -1,8 +0,0 @@ -nodeLinker: node-modules - -npmScopes: - crimata: - npmAuthToken: "${NPM_TOKEN}" - npmRegistryServer: "https://gitlab.com/api/v4/projects/28849281/packages/npm/" - -yarnPath: ".yarn/releases/yarn-berry.cjs" \ 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 309ccc7..31bd08d 100644 --- a/package.json +++ b/package.json @@ -1,103 +1,24 @@ { "name": "Crimata", "productName": "crimata-messenger", - "version": "1.0.0-beta.0", + "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": "Andrew Gundersen" }, + "main": "src/main.js", "scripts": { - "build": "vue-cli-service electron:build", - "dev": "vue-cli-service electron:serve" + "start": "electron ." }, - "main": "background.js", "dependencies": { "@crimata/nodeaudio": "^0.0.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", "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", - "fft.js": "^4.0.4", - "mitt": "^2.1.0", - "node-gyp": "^8.2.0", - "update-electron-app": "^2.0.1", - "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": "11.4.10", - "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", - "webpack-node-externals": "^3.0.0" - }, - "gitHooks": { - "pre-commit": "lint-staged" - }, - "lint-staged": { - "*.{js,jsx,vue,ts,tsx}": [ - "vue-cli-service lint", - "git add" - ] - }, - "repository": { - "type": "git", - "url": "https://gitlab.com/crimata/electron.git", - "release": "latest" - }, - "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" - } - } - } - } - }, - "packageManager": "yarn@1.22.11" + "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/public/trayIcon/icon.png b/public/trayIcon/icon.png deleted file mode 100644 index b925c06182530d62a8b4f797b4058100bd089dd2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3341 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 XtjbNVe3~rK00000NkvXXu0mjfaynPv diff --git a/public/trayIcon/icon@2x.png b/public/trayIcon/icon@2x.png deleted file mode 100644 index 7bf880ce701d69e66b0c610863f536fce0abbaa7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4083 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 { - const token = authRes.headers['set-cookie'][0].split(";")[0].split("=")[1] as string; - const crimataId = authRes.data as string; - return {token, crimataId} -}; - -export const accountAuth = async (): Promise => { - - /* attempt to get a login token from the store */ - const token = store.get("token"); - - try { - - if (token) { - - // attempt to login with token - const res = await postAuth(token); - const parsed = parseAuthRes(res); - - // save jwt token and profile - store.set("token", parsed.token); - account = parsed.crimataId - - // launch session - LaunchSession(parsed.token); - - } else throw(new Error('Failed to authenticate (no token).')); - - } catch (e) { - console.log(e); - store.delete("token"); - - } finally { - - // push state changes to the frontend - updateAppState(); - - } - -}; - -export const accountLogin = async (payload: any): Promise => { - - const creds = payload as AccountCredentials; - - try { - - // attempt login with email password - const res = await postLogin(creds.email, creds.password); - const parsed = parseAuthRes(res); - - // save jwt token and profile - store.set("token", parsed.token); - account = parsed.crimataId; - - // launch session - LaunchSession(parsed.token); - - // push state changes to the frontend - updateAppState(); - - return; - - } catch(e) { - store.delete("token"); - throw e; - } - -} - -export const accountLogout = async (): Promise => { - - try { - // post logout to backend - await postLogout(); - - // remove key and account - store.delete("token"); - account = null; - - // push account state to browser - ipcEmit("set-account", account); - - // kill crimata platform session - EndSession(); - - return; - - } catch(e) { - console.log('[ACCOUNT]', e); - return (new Error('Failed to logout. Please try again.')); - } - -} - -// logout when auth fails on platform end -backgroundMitt.on("close-auth-fail", async (_payload: any) => { - - await accountLogout(); - -}); - -// emits state of account, version, and UI -export const updateAppState = () => { - - ipcEmit("set-account", account); - - ipcEmit("set-version", app.getVersion()); - -} - - - - 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/build/icon.icns b/src/assets/icon.icns similarity index 100% rename from build/icon.icns rename to src/assets/icon.icns diff --git a/src/assets/tray/000.png b/src/assets/tray/000.png new file mode 100644 index 0000000000000000000000000000000000000000..e6d5d328101b8a1ae0825e64ef0f27d7f56ae3d6 GIT binary patch literal 3347 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 literal 0 HcmV?d00001 diff --git a/build/tray/000_16x16@2x.png b/src/assets/tray/000@2x.png similarity index 100% rename from build/tray/000_16x16@2x.png rename to src/assets/tray/000@2x.png diff --git a/src/assets/tray/001.png b/src/assets/tray/001.png new file mode 100644 index 0000000000000000000000000000000000000000..8d65b384daf2fc1a82f8e3d263571273fe5e64ed GIT binary patch literal 3329 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 LNkvXXu0mjfqZCxb literal 0 HcmV?d00001 diff --git a/build/tray/001_16x16@2x.png b/src/assets/tray/001@2x.png similarity index 100% rename from build/tray/001_16x16@2x.png rename to src/assets/tray/001@2x.png diff --git a/src/assets/tray/010.png b/src/assets/tray/010.png new file mode 100644 index 0000000000000000000000000000000000000000..bc5718c9fddd9dbd4b1587b0ec797b1deb344e2c GIT binary patch literal 3470 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 literal 0 HcmV?d00001 diff --git a/build/tray/010_16x16@2x.png b/src/assets/tray/010@2x.png similarity index 100% rename from build/tray/010_16x16@2x.png rename to src/assets/tray/010@2x.png diff --git a/src/assets/tray/011.png b/src/assets/tray/011.png new file mode 100644 index 0000000000000000000000000000000000000000..c2f8612727f88aff1712c82435d0b93d99e81715 GIT binary patch literal 3487 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 BeK`OC literal 0 HcmV?d00001 diff --git a/build/tray/100_16x16@2x.png b/src/assets/tray/100@2x.png similarity index 100% rename from build/tray/100_16x16@2x.png rename to src/assets/tray/100@2x.png diff --git a/src/assets/tray/101.png b/src/assets/tray/101.png new file mode 100644 index 0000000000000000000000000000000000000000..523bc9340b4d96568fb9878fb432ad36e230f84e GIT binary patch literal 3401 zcmV-P4Yu-$P)4Tx07!|Imj_f+*%m5ygsN?*lTZsNcbYsHpr0e8SB9_5WZ0taaYq@4R!*J?E`^*E$yf zavDn{%7K*u$Q4S(vB7?{a}n-9^c!0wmI8o67#J^-iYEDYgw@1If(U<{WZo2`Nt2v0 z&9o_>_*j30odLj;SS&FQ0Fp0arxmbyNE}i+!uCRrK#1^WguU5(76;*8gy-bu=1uY! zge?$%5ddTpgy|W7ipl#+{0w<~7KAI!_A0Uv3a#&0L&tLPuB{xSlvxXU>B)&K# zcABBP*?D1d7G^|7&9Hzo;}6~C%R&-nm@V;7ona0uAWS|tCo+77GX+6Rc^oM-eulY{ zz_=L}=f%p`$`t!EW|$?OU00T!Ah+|mOnLl5etgml7YGs~XIPRQ7dGqTFSm&z+a(2Y^0`uEbI#6$hMtBbF_DK0ATVwPj8WT)Twg{Q7_Hf@;d-< zFF}mFSsTk3fa6aApnRCM8NZ!AD<^x|GI7DQ4L$k503uKVYCsF<17lzTY=9$h1)jhc z1cFcyg;bIP763LfLUhO*3WUO;SSSTbhj@?>l0nO$wNNQk230~e zPy_TcbR0SZU4;6ed(Z$h484Uu!zh>ptHFA(8EgmBVFnxq$HVhs9-I#s!bR{#xB{+) z55g_*8Tc}M3+{(s!lNjFQb18rhA0~p9p#UTLZzZIQDW2zR0*maRf}puwWGRGH&Fek zSEx^DESiF*p>5Ef=n!-QnvKp!uRw1=SEBc$ThLwT8|VS_2>Kg_jM2qdV>~cSOfrUt zS%fLZlwE-l!-il}uvyrp*bUg-*k)`8whudq9mU~rS~zQ* z7cL6N!bx$(xShCzxYM}nxFOs}yaL_;?}!h=r{ab9HTZJ;0sJZab^J5@I6;|UO7I{= z5jcb;giVAxLObCaVTdqJR3VxZy@>I|EaGZn1+j^Ej`)!HPC-GzNWonpMnRykN})pG zu)+m}0fkQ_Rgx9SpOi+Dkv5X*Ngbqnq<3U8*^KNS;{MvtCWu`-%%b_p{O{h zM5*MeY*0C%a#7{EDo)i*HBgnKTBN#H^{nb31w}EY_*2-FwUj!_Im(b4R?S?Esg|Wy zs&+`NM{Pu1Roz)VQGKy`mHJ8bekzJ;MrBfSsGF!qsJE$~HS{zX8eEO_8ciD4HO4e` zG<`L>nkAaenzuARYtgg?Gsp?RbELkqHnk43&kt;J1CtR>wt+j6&M zuN7?NV#T+rvbtssTf15dtan@Y&B4rZpCg=8JLirK$%bK5VAE(bU`w?Pw_Rh~YWv#G z#4goti(R+fH+vWR9Q!)^2M($Zp$=;t+8y3HS~;>Es~m4Sk)48^Rywsgy>Yg7<~r|j zzUxA9iEvrx(&_Tm)y-Ax+T=RyX5yCaw#)4fU5y@1-$1|Mj&b*MU+I3r{ga2Qht%VU z#~+?Hp4pxUJfF`spUa(FH+Rs>$cyDw+{6d*q7tG&-WR_ zl99zY$aw8%?Fh@e&LYIejg^|MI!Yad_gjB0-kWnW&VQme`Ou zmK2awmeikYm%Kdra*B3}Af+u8mztQmFLiWY;JoeghSFTpiqme-H=n25_3vw2m zT&T2=weV;8O}6swjsn!(K2l`+EhXYXLYc;&an;j|)|W*}|?o{k+9_eIjd7 zv8X@aBY%7Th&W8VPXbBiOWLGrNaJ)xW+D4dHc;SQP*w18QR1Sbi&Yj27hhRowPgL0 zXN5t9KP^QsWiRbqX1HwivVrA{hICt3%>7J@3emB`fnwil1rubrRAkxHn2Bb z`oZCciXSF6W^U}+s6OlfBsSM~1c zQrh~ChaT^2_iR7*tL?A#Ck#(iom4-$=@ju)(W!~kg{Mb5L>;fr@Xic&F6?}8Hu>z$ zu9&W#b7AK$oDVvGwwuv?`hwSm6Bj)$9=}At)Oy+Va?2H$E61+7Ts_v~+S78)?OI!} zdvAN++`d!SeXgIm5pd)DP3FzZw<2%#-A=fD_fFcK{=1yJ&+p~jdvm|w{`iAc4>1o* z9w|R6f2{ks_BYGln)_Y*PYwhOTzL}rtG_@XbkFBM-czqWr1`}S}mcVa@s60@dS0TiNeW+nh{>ydsr z1?e4-UYa;>y5F7>X!?#YMc_a2bWc7dt^m~g0+6r@fN-Qo*@LJl!X#vzY?I=B0qo=? z*MEs5)5&o<776J#F&`%;-su5=YX{(~cw%CF_r%24IwaY90CeO}_xY28MQ%T3<{COs z^wqHotH9r6`VR1?8vj0m$qbyq-^YIfy?G-Q1gjFv0000uWmrjOO-%qQ0000800D<- z00aO40096102%-Q00002paK8{000010000GpaTE|000010000G000007oAhc0005p zNkl0w85Sq#HLb{RNT!4590GA@~oZi`Iow#UCML zWsxj|ERrmm)R%xZtLB4zwvOja-aN014$Pf1XU^RF?z{Jjz*O~|!-v^yrX)7DTCG5; zMobAnNcPQJNr^_n2iVC(zGd*!tf3o6V-SS}oR;M2{e`64fN1Ib(4?SN-+7 z>&2QE`~AMw>vc~pW}x~`CAJ}h!9XgNiZmJxYsN5fz-3N@)*Il>`mO-62S0}&IG09{ zUHCuycA+!XeG`B^^U89$Gm_JenL!CL_`Aj^)X~o@0JN4d9bkhQndHa7183F=D?a&LN(KGx4bSD!PH-K6pv3H`_b)#3KZJqP(py67DPF fMHEGsNuGwkHfb8h*I^BV00000NkvXXu0mjfXcB#~ literal 0 HcmV?d00001 diff --git a/build/tray/101_16x16@2x.png b/src/assets/tray/101@2x.png similarity index 100% rename from build/tray/101_16x16@2x.png rename to src/assets/tray/101@2x.png diff --git a/src/assets/tray/110.png b/src/assets/tray/110.png new file mode 100644 index 0000000000000000000000000000000000000000..ddd25247da7419f97df431919be926f86143dbda GIT binary patch literal 3532 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 { + if (streamState.rec) chunks.push(int16Arr); +}); + +backgroundMitt.on("write", (int16Arr) => { + clearTimeout(setWriteId); + setWriteId = setTimeout(() => setPlaybackStatus(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 stopRecording() +{ + setRecordingStatus(false); + + sendMessage({ + text: false, + audio: 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() : setRecordingStatus(true); + }); + + 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(); + clearInterval(setStreamsId); + nodeAudio.core.Terminate(); +} + +function setRecordingStatus(status) +{ + streamState.rec = status; + ipcEmit("record", status); + updateTray("recording", streamState.rec); +} + +function setPlaybackStatus(status) +{ + streamState.pb = status; + ipcEmit("playback", playbackId, status); + updateTray("playback", status); +} + +exports.initAudio = initAudio; +exports.terminateAudio = terminateAudio; +exports.playback = playback; +exports.streamState = streamState; diff --git a/src/audio.ts b/src/audio.ts deleted file mode 100644 index 76d53c4..0000000 --- a/src/audio.ts +++ /dev/null @@ -1,124 +0,0 @@ -const FFT = require('fft.js'); -import { globalShortcut } from "electron"; -const nodeAudio = require('@crimata/nodeaudio'); - -import { sendMessage } from "@/io"; -import { updateTray } from "@/tray"; -import { backgroundMitt, ipcEmit } from '@/composables/useEmitter'; - -let inputDevice: number; -let outputDevice: number; - -let setWriteId: ReturnType; -let setStreamsId: ReturnType; - -let playbackId: string; - -const streamState = { rec: false, pb: false }; - -const chunks: Int16Array[] = []; - -const fft = new FFT(4); - -function calcFFT(int16Arr: Int16Array) -{ - const out = fft.createComplexArray(); - fft.realTransform(out, int16Arr); - return out; -} - -backgroundMitt.on("read", (int16Arr: Int16Array) => -{ - if (streamState.rec) - { - chunks.push(int16Arr); - ipcEmit("recording", calcFFT(int16Arr)); /* fft used for animation */ - } -} -); - -backgroundMitt.on("write", (int16Arr: Int16Array) => -{ - ipcEmit("playback", { uid: playbackId, fft: calcFFT(int16Arr) }); - streamState.pb = true; - - clearTimeout(setWriteId); - setWriteId = setTimeout(() => streamState.pb = false, 1000); -} -); - -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() -{ - streamState.rec = true; - updateTray("recording", streamState.rec); -} - -function stopRecording() -{ - streamState.rec = false; - updateTray("recording", streamState.rec); - - /* Send the data to the platform right away */ - sendMessage({ - text: false, - audio: nodeAudio.utils.mergeChunks(chunks) - } as Raw); - - chunks.length = 0; -} - -function InitAudio() -{ - nodeAudio.core.Initialize(backgroundMitt.emit.bind(backgroundMitt)); - setStreamsId = setInterval(setStreams, 2000); // sense device - - /* Toggle recording switch with global shortcut */ - globalShortcut.register('CommandOrControl+R', () => - { - if (streamState.rec) - { - stopRecording(); - } - else - { - startRecording(); - } - } - ); -} - -/* Will override an existing playback process */ -function playback(audio: Int16Array, uid: string) -{ - playbackId = uid; /* uid of message */ - // nodeAudio.core.CancelPlayback(); /* terminate any current playback */ - nodeAudio.core.WriteToOutputStream(audio.buffer); -} - -function TerminateAudio() -{ - clearInterval(setStreamsId); - nodeAudio.core.Terminate(); -} - -export { InitAudio, TerminateAudio, playback, streamState }; 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/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 4c3ba24..0000000 --- a/src/composables/useIpcMain.ts +++ /dev/null @@ -1,80 +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: InputParam): void => { - - console.log(`[IPC] Post: ${this.channel}`); - this._listenerCallback(payload); - } - -} diff --git a/src/composables/useStore.ts b/src/composables/useStore.ts deleted file mode 100644 index e876748..0000000 --- a/src/composables/useStore.ts +++ /dev/null @@ -1,12 +0,0 @@ -const Store = require('electron-store'); - -const schema = { - token: { - type: 'string', - }, -}; - -export const store = new Store({ - schema, - encryptionKey: "super user test" -}); \ No newline at end of file diff --git a/src/composables/useWebsockets.ts b/src/composables/useWebsockets.ts deleted file mode 100644 index 8991070..0000000 --- a/src/composables/useWebsockets.ts +++ /dev/null @@ -1,99 +0,0 @@ - -"use strict"; - -import WebSocket from 'ws'; - - -const _connectionCheckTimeout = 4000; -const _reconnectTimeout = 1000; -let _connectionCheckInterval: ReturnType; - -/* ws-status key: - * 0 - onMessage (connected) - * 1 - pongMessage (nominal) - * 2 - closeMessage (reconnecting) - * 3 - pingErrorMessage (connection lost) - */ - -export default function useWebSockets(emit: (eventName: string | symbol, [...args]: any) => boolean) -{ - - 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})); - - emit("ws-status", 0); - - // ping server - _connectionCheckInterval = setInterval(() => { - - socket.ping(null, true, (e: Error) => { - if (e) { - socket.close(); - emit("ws-status", 3); - setTimeout(() => connect(socketUrl, secret), _reconnectTimeout); - } - }); - - }, _connectionCheckTimeout); - - }); - - socket.on("message", (event: WebSocket.MessageEvent) => { - console.log("message received", event); - emit("ws-message", event.toString()); - }); - - socket.on("close", (code: number, reason: string) => { - emit("ws-status", 2); - clearInterval(_connectionCheckInterval); - if (code !== 1000 || reason !== 'session-logout') { - setTimeout(() => { - connect(socketUrl, secret), _reconnectTimeout - }); - } - - }); - - socket.on("pong", () => emit("ws-status", 1)); - - socket.on('error', () => {}); - - } - - const close = (code: number, reason: string) => { - if (socket) { - socket.close(code, reason); - } - }; - - return { - connect, - send, - close - }; - -} diff --git a/src/config.ts b/src/config.js similarity index 87% rename from src/config.ts rename to src/config.js index ae54af0..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'), -} +} \ No newline at end of file diff --git a/src/init.ts b/src/init.ts deleted file mode 100644 index 5d885da..0000000 --- a/src/init.ts +++ /dev/null @@ -1,53 +0,0 @@ -/** - * Entry point for Crimata electron app. - * "Look on my Works, ye Mighty, and despair!" - */ - -"use strict"; - -import { app, protocol, globalShortcut } from "electron"; - -import main from "@/main"; -import { CreateWindow, winState } from "@/window"; -import { TerminateAudio } from '@/audio'; -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'); - -/* Start main process on ready */ -app.on("ready", async () => -{ - await main(); -} -); - -app.on("will-quit", () => -{ - TerminateAudio(); - globalShortcut.unregisterAll(); -} -); - -// When user clicks app icon (re-open) -app.on("activate", () => -{ - if (!winState.open) 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..b5b2751 --- /dev/null +++ b/src/io.js @@ -0,0 +1,58 @@ +const WebSocket = require("ws"); + +const config = require("./config"); +const { ipcMain } = require("electron"); +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("ws-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; \ No newline at end of file diff --git a/src/io.ts b/src/io.ts deleted file mode 100644 index 75e2c9c..0000000 --- a/src/io.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { config } from "@/config"; -import { updateTray } from "@/tray"; -import useWebsockets from "@/composables/useWebsockets"; -import { backgroundMitt, ipcEmit } from "@/composables/useEmitter"; - -backgroundMitt.on("ws-status", (status: any) => -{ - let simpleStatus = false; - if (status == 2 || status == 3) simpleStatus = true; - - updateTray("disconnect", simpleStatus); - - ipcEmit('set-connection-status', status); -}); - -const { connect, send, close } = -useWebsockets(backgroundMitt.emit.bind(backgroundMitt)) - -function sendMessage(message: Raw | Request): void -{ - send(message); -} - -function ConnectToPlatform(platformKey: string) -{ - connect(config.PLATFORM_URL, platformKey); -} - -function DisconnectFromPlatform(code: number, reason: string) -{ - close(code, reason); -} - -export { ConnectToPlatform, DisconnectFromPlatform, sendMessage }; \ No newline at end of file diff --git a/src/ipc/handlers.ts b/src/ipc/handlers.ts deleted file mode 100644 index f35e283..0000000 --- a/src/ipc/handlers.ts +++ /dev/null @@ -1,19 +0,0 @@ - -"use strict"; - -import { accountLogin, accountLogout } from "@/account"; -import { IpcHandler } from "@/composables/useIpcMain"; - - -const LOGIN_CHANNEL = "invoke-account-login"; -const LOGOUT_CHANNEL = "invoke-account-logout"; - -export const loginHandler = new IpcHandler({ - channel: LOGIN_CHANNEL, - handlerCallback: accountLogin -}); - -export const logoutHandler = new IpcHandler({ - channel: LOGOUT_CHANNEL, - handlerCallback: accountLogout -}); 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 c9f45f8..0000000 --- a/src/ipc/listeners.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { sendMessage } from '@/io'; -import { playback } from "@/audio"; -import { winState, onNavBar } from "@/window"; -import { updateAppState } from "@/account"; -import { IpcListener } from "@/composables/useIpcMain" - -const CLIENT_MESSAGE_CHANNEL = "post-session-send" -const APP_MOUNT_CHANNEL = "post-app-mount"; -const NAV_BAR_CHANNEL = "post-nav-bar"; -const POST_WINDOW_FOCUS = 'post-window-focus'; -const PLAYBACK_CHANNEL = "post-playback;" - -export const messageListener = new IpcListener({ - channel: CLIENT_MESSAGE_CHANNEL, - listenerCallback: sendMessage -}); - -export const appMountListener = new IpcListener({ - channel: APP_MOUNT_CHANNEL, - listenerCallback: updateAppState -}); - -export const navBarListener = new IpcListener({ - channel: NAV_BAR_CHANNEL, - listenerCallback: onNavBar -}); - -export const windowFocusListener = new IpcListener({ - channel: POST_WINDOW_FOCUS, - listenerCallback: (state) => winState.focus = state -}); - -// export const playbackListener = new IpcListener({ -// channel: PLAYBACK_CHANNEL, -// listenerCallback: playback -// }); \ No newline at end of file diff --git a/src/main.js b/src/main.js new file mode 100644 index 0000000..e903e6c --- /dev/null +++ b/src/main.js @@ -0,0 +1,26 @@ +const { app, protocol, ipcMain } = 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"); + +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 ccf0846..0000000 --- a/src/main.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { initTray } from '@/tray'; -import { CreateWindow } from "@/window"; -import initIpcMain from "@/ipc/index"; -import { accountAuth } from "@/account"; - -export default async function main() { - - /* initiate render process event listeners & handlers */ - initIpcMain(); - - /* initiate tray icon in default state */ - initTray(); - - /* launch browser window */ - await CreateWindow(); - - /* try to authenticate with token */ - accountAuth(); - -} diff --git a/src/render/App.vue b/src/render/App.vue deleted file mode 100644 index 3e5cf13..0000000 --- a/src/render/App.vue +++ /dev/null @@ -1,74 +0,0 @@ - - - - - diff --git a/src/render/assets/mailAvatar.svg b/src/render/assets/mailAvatar.svg new file mode 100644 index 0000000..e9ac882 --- /dev/null +++ b/src/render/assets/mailAvatar.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/src/render/audioVisualizer.js b/src/render/audioVisualizer.js deleted file mode 100644 index 8f1fe13..0000000 --- a/src/render/audioVisualizer.js +++ /dev/null @@ -1,81 +0,0 @@ -class AudioVisualizer { - constructor( audioContext, processFrame, processError ) { - this.audioContext = audioContext; - this.processFrame = processFrame; - this.connectStream = this.connectStream.bind( this ); - navigator.mediaDevices.getUserMedia( { audio: true, video: false } ) - .then( this.connectStream ) - .catch( ( error ) => { - if ( processError ) { - processError( error ); - } - } ); - } - - connectStream( stream ) { - this.analyser = this.audioContext.createAnalyser(); - const source = this.audioContext.createMediaStreamSource( stream ); - source.connect( this.analyser ); - this.analyser.smoothingTimeConstant = 0.5; - this.analyser.fftSize = 32; - - this.initRenderLoop( this.analyser ); - } - - initRenderLoop() { - const frequencyData = new Uint8Array( this.analyser.frequencyBinCount ); - const processFrame = this.processFrame || ( () => {} ); - - const renderFrame = () => { - this.analyser.getByteFrequencyData( frequencyData ); - processFrame( frequencyData ); - - requestAnimationFrame( renderFrame ); - }; - requestAnimationFrame( renderFrame ); - } -} - -const visualMainElement = document.querySelector( 'main' ); -const visualValueCount = 16; -let visualElements; -const createDOMElements = () => { - let i; - for ( i = 0; i < visualValueCount; ++i ) { - const elm = document.createElement( 'div' ); - visualMainElement.appendChild( elm ); - } - - visualElements = document.querySelectorAll( 'main div' ); -}; -createDOMElements(); - -const init = () => { - // Creating initial DOM elements - const audioContext = new AudioContext(); - const initDOM = () => { - visualMainElement.innerHTML = ''; - createDOMElements(); - }; - initDOM(); - - // Swapping values around for a better visual effect - const dataMap = { 0: 15, 1: 10, 2: 8, 3: 9, 4: 6, 5: 5, 6: 2, 7: 1, 8: 0, 9: 4, 10: 3, 11: 7, 12: 11, 13: 12, 14: 13, 15: 14 }; - const processFrame = ( data ) => { - const values = Object.values( data ); - let i; - for ( i = 0; i < visualValueCount; ++i ) { - const value = values[ dataMap[ i ] ] / 255; - const elmStyles = visualElements[ i ].style; - elmStyles.transform = `scaleY( ${ value } )`; - elmStyles.opacity = Math.max( .25, value ); - } - }; - - const processError = () => { - visualMainElement.classList.add( 'error' ); - visualMainElement.innerText = 'Please allow access to your microphone in order to see this demo.\nNothing bad is going to happen... hopefully :P'; - } - - const a = new AudioVisualizer( audioContext, processFrame, processError ); -}; \ No newline at end of file diff --git a/src/render/components/app.js b/src/render/components/app.js new file mode 100644 index 0000000..49abb6e --- /dev/null +++ b/src/render/components/app.js @@ -0,0 +1,44 @@ +import Splash from "./splash.js"; +import Messenger from "./messenger.js"; +import Login from "./login.js"; +import Header from "./header.js"; + +const account = Vue.ref(null); + +const App = +{ + components: { + Splash, + Messenger, + Login, + Header + }, + + 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..c4949e4 --- /dev/null +++ b/src/render/components/bubble.js @@ -0,0 +1,16 @@ +const Bubble = +{ + props: ["modifier", "text", "child"], + + template: ` +
+ {{ text }} +
` +}; + +export default Bubble; + + +//
+ + diff --git a/src/render/components/bubble.vue b/src/render/components/bubble.vue deleted file mode 100644 index f1c1f15..0000000 --- a/src/render/components/bubble.vue +++ /dev/null @@ -1,98 +0,0 @@ - - - - - \ No newline at end of file diff --git a/src/render/components/connectionStatus.vue b/src/render/components/connectionStatus.vue deleted file mode 100644 index ca5f3bf..0000000 --- a/src/render/components/connectionStatus.vue +++ /dev/null @@ -1,103 +0,0 @@ - - - - - - - diff --git a/src/render/components/context.js b/src/render/components/context.js new file mode 100644 index 0000000..374c1f2 --- /dev/null +++ b/src/render/components/context.js @@ -0,0 +1,38 @@ + +const Context = +{ + props: ["modifier", "context", "avatar", "audio", "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/context.vue b/src/render/components/context.vue deleted file mode 100644 index d351462..0000000 --- a/src/render/components/context.vue +++ /dev/null @@ -1,83 +0,0 @@ - - - - - \ No newline at end of file diff --git a/src/render/components/control/draggify.js b/src/render/components/control/draggify.js new file mode 100644 index 0000000..e7545a0 --- /dev/null +++ b/src/render/components/control/draggify.js @@ -0,0 +1,199 @@ +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(); + + console.log("onMouseUp"); + 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..e1a5250 --- /dev/null +++ b/src/render/components/control/text.js @@ -0,0 +1,73 @@ +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", { + text: el.value, audio: false }); + 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; \ No newline at end of file diff --git a/src/render/components/controllers/helpers.ts b/src/render/components/controllers/helpers.ts deleted file mode 100644 index 7fff75d..0000000 --- a/src/render/components/controllers/helpers.ts +++ /dev/null @@ -1,107 +0,0 @@ -import { ref, Ref } from "vue"; -import anime from "animejs"; - - -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 - }; - -} - -// Given index and length of content, return message child status. -export function calcChild (index: number, len: number) -{ - if (len === 1) - { - return "none"; - } - else if (index === 0) - { - return "first-child"; - } - else if (index === len - 1) - { - return "last-child"; - } - else - { - return "middle-child"; - } -} \ No newline at end of file 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 51edfe0..0000000 --- a/src/render/components/controllers/inputItem.control.text.ts +++ /dev/null @@ -1,135 +0,0 @@ -import { Ref, ref, watch, onMounted, onUnmounted } from "vue"; -import { postMessage } from "@/render/ipc"; -import { 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: Raw = { - text: textInput.value, - audio: 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/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 d0756a5..0000000 --- a/src/render/components/login.vue +++ /dev/null @@ -1,173 +0,0 @@ - - - - - diff --git a/src/render/components/message.js b/src/render/components/message.js new file mode 100644 index 0000000..de822e2 --- /dev/null +++ b/src/render/components/message.js @@ -0,0 +1,69 @@ +import Bubble from "./bubble.js"; +import Context from "./context.js"; + +const Message = +{ + components: { + Bubble, + Context + }, + + props: ["modifier", "content", "context", "avatar", "audio", "id"], + + setup(props) + { + Vue.onMounted(() => { + + const messengerEl = document.getElementById("messenger"); + + if (messengerEl) { + messengerEl.dispatchEvent(new CustomEvent('adjust-scroll')); + } + + }); + + 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; \ No newline at end of file diff --git a/src/render/components/message.vue b/src/render/components/message.vue deleted file mode 100644 index 9dbd531..0000000 --- a/src/render/components/message.vue +++ /dev/null @@ -1,105 +0,0 @@ - - - - - - - diff --git a/src/render/components/messenger.js b/src/render/components/messenger.js new file mode 100644 index 0000000..5151907 --- /dev/null +++ b/src/render/components/messenger.js @@ -0,0 +1,71 @@ +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 messages = Vue.ref([]); + + Vue.onMounted(() => { + + window.mainApi.on("ui-init", (ui) => { + messages.value = ui; + }); + + window.mainApi.on("ui-update", (message) => { + console.log(message) + + let index = messages.value.findIndex(m => m.id===message.id); + if (index >= 0) + { + messages.value[index] = message; + } + else + { + messages.value.push(message); + } + + }); + + initScroll("messenger"); + window.mainApi.send("messenger"); + }); + + Vue.onUnmounted(() => { + messages.value = []; + }); + + return { messages }; + }, + + template: ` + + + + +
+ +
` +} + +export default Messenger; diff --git a/src/render/components/messenger.vue b/src/render/components/messenger.vue deleted file mode 100644 index da97ec1..0000000 --- a/src/render/components/messenger.vue +++ /dev/null @@ -1,126 +0,0 @@ - - - - - diff --git a/src/render/components/settings.js b/src/render/components/settings.js new file mode 100644 index 0000000..c1f9a81 --- /dev/null +++ b/src/render/components/settings.js @@ -0,0 +1,40 @@ + +const Settings = +{ + setup() { + const active = Vue.ref(false); + + function hideSettings(e) { + if (e.key == "Escape") { + active.value = false; + window.removeEventListener("keydown", hideSettings); + } + } + + function showSettings() { + active.value = true; + window.addEventListener("keydown", hideSettings); + } + + async function logout() { + await window.mainApi.send("logout"); + } + + return { showSettings, 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 8e2ca8b..0000000 --- a/src/render/components/settings.vue +++ /dev/null @@ -1,158 +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..fac0622 --- /dev/null +++ b/src/render/components/ws.js @@ -0,0 +1,36 @@ + +const WS = +{ + setup() + { + const status = Vue.ref(); + + Vue.onMounted(() => { + + window.mainApi.on("ws-status", (val) => { + status.value = val; + console.log(status.value); + }); + + }); + + 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 477289f..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}`, payload); - this._listenerCallback(payload); - } - -} - - -export default function useIpcRenderer () { - - const invoke = async (endpoint: string, payload: T) => { - try { - const res = await window.ipcRenderer.invoke(endpoint, payload? JSON.stringify(payload) : null); - return res; - } catch (e) { - throw e; - } - } - - const post = (endpoint: string, payload: T) => { - window.ipcRenderer.send(endpoint, payload); - }; - - return { - invoke, - post, - } -} diff --git a/src/render/composables/useScroll.ts b/src/render/composables/useScroll.ts deleted file mode 100644 index 07417f3..0000000 --- a/src/render/composables/useScroll.ts +++ /dev/null @@ -1,25 +0,0 @@ - -export default function useScroll(elementId: string) { - - const el = document.getElementById(elementId); - - 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' - }); - } - } - - if (el) - el.addEventListener('adjust-scroll', adjustScroll); - window.addEventListener('resize', adjustScroll); - -} 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 7f3eeb0..0000000 --- a/src/render/ipc.ts +++ /dev/null @@ -1,90 +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: AccountCredentials -): Promise => ( - await invoke('invoke-account-login', payload) -); - -export const invokeLogout = async (): Promise => ( - await invoke("invoke-account-logout", null) -); - -/** - * - * Audio endpoints - * - */ - -// export const postPlayback = (audio: Int16Array, uid: string): void => ( -// post('post-playback', payload) -// ); - -/** - * - * Crimata Platform (session) endpoints - * - */ - -export const postMessage = (payload: Raw | PlatformRequest): void => ( - post('post-session-send', payload) -); - -export const postAppMount = (): void => ( - post('post-app-mount', null) -); - -/** - * - * Nav bar endpoints - * - */ - -export const postNavBar = (payload: string): void => ( - post('post-nav-bar', payload) -); - -/** - * - * Window focus endpoint - * - */ - -export const postWindowFocus = (payload: boolean): void => ( - post('post-window-focus', payload) -); - -/** - * - * 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 c3aadef..0000000 --- a/src/render/listeners.ts +++ /dev/null @@ -1,81 +0,0 @@ - -import { IpcRendererListener } from "./composables/useIpcRend" -/* - * Shared state imports - * */ -import { - setMessages, - addMessage, - updateMessage, - deleteMessage, - animatePlayback -} from "./shared/messages"; -import { setAccount } from "./shared/account"; -import { setProfile } from "./shared/profile"; -import { setVersion } from "./shared/version"; -import { setConnectionStatus } from "./shared/connectionStatus"; -import { setRecording } from "./shared/audio"; - -const SET_ACCOUNT_CHANNEL = "set-account"; -const SET_PROFILE_CHANNEL = "set-profile"; -const SET_VERSION_CHANNEL = "set-version"; - -const INIT_MESSAGES_CHANNEL = "init-messages"; -const ADD_MESSAGE_CHANNEL = "add-message"; -const UPDATE_MESSAGE_CHANNEL = "update-message"; -const DELETE_MESSAGE_CHANNEL = "delete-message"; - -const CONNECTION_STATUS_CHANNEL = "set-connection-status"; - -const RECORDING_CHANNEL = "recording"; -const PLAYBACK_CHANNEL = "playback"; - -export const setAccountListener = new IpcRendererListener({ - channel: SET_ACCOUNT_CHANNEL, - listenerCallback: setAccount -}); - -export const setVersionListener = new IpcRendererListener({ - channel: SET_VERSION_CHANNEL, - listenerCallback: setVersion -}); - -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 -}); - -export const deleteMessagesListener = new IpcRendererListener({ - channel: DELETE_MESSAGE_CHANNEL, - listenerCallback: deleteMessage -}); - -export const connectionStatusListener = new IpcRendererListener({ - channel: CONNECTION_STATUS_CHANNEL, - listenerCallback: setConnectionStatus -}); - -export const recordingListener = new IpcRendererListener({ - channel: RECORDING_CHANNEL, - listenerCallback: setRecording -}); - -export const playbackListener = new IpcRendererListener({ - channel: PLAYBACK_CHANNEL, - listenerCallback: animatePlayback -}); \ No newline at end of file diff --git a/src/render/main.css b/src/render/main.css new file mode 100644 index 0000000..51e5996 --- /dev/null +++ b/src/render/main.css @@ -0,0 +1,507 @@ +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; +} + +#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; + padding: 10px; + 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-notify { + position: absolute; + width: 12px; + height: 12px; + border-radius: 50%; + background-color: #58D9FF; + top: -5px; + left: -5px; + border: 2px solid #EBEBEB; +} + +.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; +} + +/* ---------- 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..a2dded6 --- /dev/null +++ b/src/render/preload.js @@ -0,0 +1,53 @@ +const { contextBridge, ipcRenderer } = require("electron"); + +/** The main <-> render interface */ + +const validFromMainChannels = [ + "set-account", + "ui-init", + "ui-update", + "ws-status", + "record", + "playback" +]; + +const validToMain = [ + "messenger", + "message", + "nav-bar", + "login", + "logout" +] + +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); + } + } +); \ No newline at end of file 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/shared/account.ts b/src/render/shared/account.ts deleted file mode 100644 index a612867..0000000 --- a/src/render/shared/account.ts +++ /dev/null @@ -1,26 +0,0 @@ -// shared -import { ref } from "vue"; - -export const ready = ref(false); -export const account = ref(); - -export const setAccount: IpcListenerCallback = (payload) => { - payload ? account.value = payload : clearAccount(); - showRender(); -}; - -export const clearAccount = () => { - console.log("Clearing account"); - account.value = null; -} - -const showRender = () => { - ready.value = true; -} - -export default { - ready, - account, - setAccount, - clearAccount -}; diff --git a/src/render/shared/audio.ts b/src/render/shared/audio.ts deleted file mode 100644 index c040e0e..0000000 --- a/src/render/shared/audio.ts +++ /dev/null @@ -1,13 +0,0 @@ -// shared -import { ref } from "vue"; - -export const recording = ref(); - -export const setRecording: IpcListenerCallback = (payload) => { - console.log("Recording"); - // recording.value = payload; -} - -export default { - recording -} \ No newline at end of file diff --git a/src/render/shared/connectionStatus.ts b/src/render/shared/connectionStatus.ts deleted file mode 100644 index 6dd95da..0000000 --- a/src/render/shared/connectionStatus.ts +++ /dev/null @@ -1,65 +0,0 @@ -// shared -import { ref } from "vue"; -import anime from "animejs"; - -export const status = ref(""); - -export let hiddenState = true; - -let animateLogo: anime.AnimeInstance; -let animateConnect: anime.AnimeInstance; - -export function useAnim() { - - animateLogo = anime({ - targets: '#logo', - translateX: [0, 15], - duration: 500, - autoplay: false, - easing: 'easeInOutBack' - }); - - animateConnect = anime({ - targets: '#connect', - translateX: [0, -15], - opacity: [0, 1], - duration: 500, - autoplay: false, - easing: 'easeInOutBack' - }); - -} - -export function show() { - if (animateLogo && animateConnect) { - animateLogo.direction = "normal"; - animateConnect.direction = "normal"; - animateLogo.play(); - animateConnect.play(); - hiddenState = false; - } -} - -export function hide() { - if (animateLogo && animateConnect) { - animateLogo.direction = "reverse"; - animateConnect.direction = "reverse"; - animateLogo.play(); - animateConnect.play(); - hiddenState = true; - } -} - -export const setConnectionStatus: IpcListenerCallback = (payload) => { - status.value = payload; -}; - -export default { - hiddenState, - useAnim, - status, - show, - hide -}; - - diff --git a/src/render/shared/messages.ts b/src/render/shared/messages.ts deleted file mode 100644 index 446b85d..0000000 --- a/src/render/shared/messages.ts +++ /dev/null @@ -1,79 +0,0 @@ -// shared -import { ref, Ref } from "vue"; - -export const messages: Ref> = ref([]); - -export const setMessages: IpcListenerCallback> = (payload) => { - messages.value = payload; -} - -export const addMessage: IpcListenerCallback = (payload) => { - messages.value.push(payload as Message); -} - -export const updateMessage: IpcListenerCallback = (payload) => { - const annotation = payload as Annotation; - - for (const i in messages.value) { - - if (messages.value[i].uid == annotation.uid) { - - if (annotation.name == "content") { - messages.value[i].content = annotation.data as Content[]; - } - - if (annotation.name == "context") { - messages.value[i].context = annotation.data as Context; - } - - if (annotation.name == "seen") { - messages.value[i].seen = annotation.data as boolean; - } - - } - - } - -} - -let playbackId: ReturnType; - -export const animatePlayback: IpcListenerCallback = (payload) => { - console.log("animatePlayback"); - // clearTimeout(playbackId); - - // const context = payload as AnimationContext; - - // const el = document.getElementById(context.uid); - - // el.style.boxShadow = `0px 0px 0px 20px rgba(0,0,0,${payload.fft})`; - - // /* box shadow will return to 0 in 300ms if no more playback is done */ - // playbackId = setTimeout(() => { - // el.style.boxShadow = `0px 0px 0px 20px rgba(0,0,0,0)`; - // }, 300); -} - -export const deleteMessage: IpcListenerCallback = (payload) => { - const uid = payload as string; - - for (let i = 0; i < messages.value.length; i++) { - if (messages.value[i].uid === uid) { - messages.value.splice(i, 1); - break; - } - } - -} - -export const resetMessages = () => { - messages.value = []; -} - -export default { - messages, - setMessages, - addMessage, - updateMessage, - animatePlayback -}; diff --git a/src/render/shared/profile.ts b/src/render/shared/profile.ts deleted file mode 100644 index cdf39f2..0000000 --- a/src/render/shared/profile.ts +++ /dev/null @@ -1,19 +0,0 @@ -// shared -import { ref } from "vue"; - -class Profile implements Profile{ - crimata_id = ""; - name = ""; - photo = ""; -} - -export const profile = ref(new Profile()); - -export const setProfile: IpcListenerCallback = (payload) => { - profile.value = payload; -}; - -export default { - profile, - setProfile -}; \ No newline at end of file diff --git a/src/render/shared/version.ts b/src/render/shared/version.ts deleted file mode 100644 index a412cf6..0000000 --- a/src/render/shared/version.ts +++ /dev/null @@ -1,12 +0,0 @@ -// shared -import { ref } from "vue"; - -export const version = ref(); - -export const setVersion: IpcListenerCallback = (payload) => { - version.value = payload; -}; - -export default { - setVersion -} \ No newline at end of file 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. `